From 7c8a35aea9b6108bffdc39390cdb00db525be2ac Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Sun, 16 Feb 2020 21:07:54 +0800 Subject: [PATCH 01/69] use libco instead of state-thread(st), still have some bug --- trunk/3rdparty/libco/.gitignore | 1 + trunk/3rdparty/libco/CMakeLists.txt | 55 + trunk/3rdparty/libco/LICENSE.txt | Bin 0 -> 18962 bytes trunk/3rdparty/libco/Makefile | 84 + trunk/3rdparty/libco/co.mk | 85 + trunk/3rdparty/libco/co_closure.h | 96 + trunk/3rdparty/libco/co_epoll.cpp | 318 ++ trunk/3rdparty/libco/co_epoll.h | 93 + trunk/3rdparty/libco/co_hook_sys_call.cpp | 1003 ++++++ trunk/3rdparty/libco/co_routine.cpp | 1196 +++++++ trunk/3rdparty/libco/co_routine.h | 93 + trunk/3rdparty/libco/co_routine_inner.h | 111 + trunk/3rdparty/libco/co_routine_specific.h | 86 + trunk/3rdparty/libco/coctx.cpp | 132 + trunk/3rdparty/libco/coctx.h | 42 + trunk/3rdparty/libco/coctx_swap.S | 83 + trunk/3rdparty/libco/example_closure.cpp | 91 + trunk/3rdparty/libco/example_cond.cpp | 83 + trunk/3rdparty/libco/example_copystack.cpp | 61 + trunk/3rdparty/libco/example_echocli.cpp | 218 ++ trunk/3rdparty/libco/example_echosvr.cpp | 255 ++ trunk/3rdparty/libco/example_poll.cpp | 211 ++ trunk/3rdparty/libco/example_setenv.cpp | 89 + trunk/3rdparty/libco/example_specific.cpp | 61 + trunk/3rdparty/libco/example_thread.cpp | 56 + trunk/3rdparty/st-srs/.gitignore | 4 - trunk/3rdparty/st-srs/Makefile | 474 --- trunk/3rdparty/st-srs/README | 394 --- trunk/3rdparty/st-srs/README.md | 88 - trunk/3rdparty/st-srs/common.h | 479 --- trunk/3rdparty/st-srs/docs/fig.gif | Bin 5374 -> 0 bytes trunk/3rdparty/st-srs/docs/notes.html | 434 --- trunk/3rdparty/st-srs/docs/reference.html | 3120 ----------------- trunk/3rdparty/st-srs/docs/st.html | 504 --- trunk/3rdparty/st-srs/docs/timeout_heap.txt | 60 - trunk/3rdparty/st-srs/event.c | 1413 -------- trunk/3rdparty/st-srs/examples/Makefile | 115 - trunk/3rdparty/st-srs/examples/README | 98 - trunk/3rdparty/st-srs/examples/error.c | 168 - trunk/3rdparty/st-srs/examples/lookupdns.c | 103 - trunk/3rdparty/st-srs/examples/proxy.c | 541 --- trunk/3rdparty/st-srs/examples/res.c | 305 -- trunk/3rdparty/st-srs/examples/server.c | 1025 ------ trunk/3rdparty/st-srs/extensions/Makefile | 91 - trunk/3rdparty/st-srs/extensions/README | 42 - trunk/3rdparty/st-srs/extensions/common.h | 77 - trunk/3rdparty/st-srs/extensions/dnscache.c | 190 - trunk/3rdparty/st-srs/extensions/dnsres.c | 305 -- trunk/3rdparty/st-srs/extensions/lrucache.c | 343 -- .../st-srs/extensions/print_stk.patch | 367 -- trunk/3rdparty/st-srs/extensions/stx.h | 91 - trunk/3rdparty/st-srs/extensions/stx_fileio.c | 197 -- trunk/3rdparty/st-srs/extensions/stx_fileio.h | 52 - trunk/3rdparty/st-srs/extensions/testdns.c | 112 - trunk/3rdparty/st-srs/io.c | 769 ---- trunk/3rdparty/st-srs/key.c | 121 - trunk/3rdparty/st-srs/libst.def | 51 - trunk/3rdparty/st-srs/md.S | 644 ---- trunk/3rdparty/st-srs/md.h | 641 ---- trunk/3rdparty/st-srs/osguess.sh | 45 - trunk/3rdparty/st-srs/public.h | 166 - trunk/3rdparty/st-srs/sched.c | 705 ---- trunk/3rdparty/st-srs/st.pc.in | 10 - trunk/3rdparty/st-srs/st.spec | 79 - trunk/3rdparty/st-srs/stk.c | 173 - trunk/3rdparty/st-srs/sync.c | 368 -- trunk/auto/depends.sh | 31 +- trunk/configure | 34 +- trunk/research/st/Makefile | 100 - trunk/research/st/common.h | 445 --- trunk/research/st/event.c | 483 --- trunk/research/st/io.c | 792 ----- trunk/research/st/key.c | 116 - trunk/research/st/md.S | 151 - trunk/research/st/md.h | 193 - trunk/research/st/public.h | 164 - trunk/research/st/sched.c | 680 ---- trunk/research/st/srs.c | 497 --- trunk/research/st/st/init | 3 - trunk/research/st/st/st.upp | 18 - trunk/research/st/stk.c | 169 - trunk/research/st/sync.c | 352 -- trunk/src/app/srs_app_listener.cpp | 10 +- trunk/src/app/srs_app_server.cpp | 12 +- trunk/src/app/srs_app_st.cpp | 27 +- trunk/src/app/srs_app_st.hpp | 3 + trunk/src/service/srs_service_st.cpp | 260 +- trunk/src/service/srs_service_st.hpp | 2 +- 88 files changed, 4836 insertions(+), 19273 deletions(-) create mode 100644 trunk/3rdparty/libco/.gitignore create mode 100644 trunk/3rdparty/libco/CMakeLists.txt create mode 100644 trunk/3rdparty/libco/LICENSE.txt create mode 100644 trunk/3rdparty/libco/Makefile create mode 100644 trunk/3rdparty/libco/co.mk create mode 100644 trunk/3rdparty/libco/co_closure.h create mode 100644 trunk/3rdparty/libco/co_epoll.cpp create mode 100644 trunk/3rdparty/libco/co_epoll.h create mode 100644 trunk/3rdparty/libco/co_hook_sys_call.cpp create mode 100644 trunk/3rdparty/libco/co_routine.cpp create mode 100644 trunk/3rdparty/libco/co_routine.h create mode 100644 trunk/3rdparty/libco/co_routine_inner.h create mode 100644 trunk/3rdparty/libco/co_routine_specific.h create mode 100644 trunk/3rdparty/libco/coctx.cpp create mode 100644 trunk/3rdparty/libco/coctx.h create mode 100644 trunk/3rdparty/libco/coctx_swap.S create mode 100644 trunk/3rdparty/libco/example_closure.cpp create mode 100644 trunk/3rdparty/libco/example_cond.cpp create mode 100644 trunk/3rdparty/libco/example_copystack.cpp create mode 100644 trunk/3rdparty/libco/example_echocli.cpp create mode 100644 trunk/3rdparty/libco/example_echosvr.cpp create mode 100644 trunk/3rdparty/libco/example_poll.cpp create mode 100644 trunk/3rdparty/libco/example_setenv.cpp create mode 100644 trunk/3rdparty/libco/example_specific.cpp create mode 100644 trunk/3rdparty/libco/example_thread.cpp delete mode 100644 trunk/3rdparty/st-srs/.gitignore delete mode 100644 trunk/3rdparty/st-srs/Makefile delete mode 100644 trunk/3rdparty/st-srs/README delete mode 100644 trunk/3rdparty/st-srs/README.md delete mode 100644 trunk/3rdparty/st-srs/common.h delete mode 100644 trunk/3rdparty/st-srs/docs/fig.gif delete mode 100644 trunk/3rdparty/st-srs/docs/notes.html delete mode 100644 trunk/3rdparty/st-srs/docs/reference.html delete mode 100644 trunk/3rdparty/st-srs/docs/st.html delete mode 100644 trunk/3rdparty/st-srs/docs/timeout_heap.txt delete mode 100644 trunk/3rdparty/st-srs/event.c delete mode 100644 trunk/3rdparty/st-srs/examples/Makefile delete mode 100644 trunk/3rdparty/st-srs/examples/README delete mode 100644 trunk/3rdparty/st-srs/examples/error.c delete mode 100644 trunk/3rdparty/st-srs/examples/lookupdns.c delete mode 100644 trunk/3rdparty/st-srs/examples/proxy.c delete mode 100644 trunk/3rdparty/st-srs/examples/res.c delete mode 100644 trunk/3rdparty/st-srs/examples/server.c delete mode 100644 trunk/3rdparty/st-srs/extensions/Makefile delete mode 100644 trunk/3rdparty/st-srs/extensions/README delete mode 100644 trunk/3rdparty/st-srs/extensions/common.h delete mode 100644 trunk/3rdparty/st-srs/extensions/dnscache.c delete mode 100644 trunk/3rdparty/st-srs/extensions/dnsres.c delete mode 100644 trunk/3rdparty/st-srs/extensions/lrucache.c delete mode 100644 trunk/3rdparty/st-srs/extensions/print_stk.patch delete mode 100644 trunk/3rdparty/st-srs/extensions/stx.h delete mode 100644 trunk/3rdparty/st-srs/extensions/stx_fileio.c delete mode 100644 trunk/3rdparty/st-srs/extensions/stx_fileio.h delete mode 100644 trunk/3rdparty/st-srs/extensions/testdns.c delete mode 100644 trunk/3rdparty/st-srs/io.c delete mode 100644 trunk/3rdparty/st-srs/key.c delete mode 100644 trunk/3rdparty/st-srs/libst.def delete mode 100644 trunk/3rdparty/st-srs/md.S delete mode 100644 trunk/3rdparty/st-srs/md.h delete mode 100644 trunk/3rdparty/st-srs/osguess.sh delete mode 100644 trunk/3rdparty/st-srs/public.h delete mode 100644 trunk/3rdparty/st-srs/sched.c delete mode 100644 trunk/3rdparty/st-srs/st.pc.in delete mode 100644 trunk/3rdparty/st-srs/st.spec delete mode 100644 trunk/3rdparty/st-srs/stk.c delete mode 100644 trunk/3rdparty/st-srs/sync.c delete mode 100755 trunk/research/st/Makefile delete mode 100644 trunk/research/st/common.h delete mode 100644 trunk/research/st/event.c delete mode 100644 trunk/research/st/io.c delete mode 100644 trunk/research/st/key.c delete mode 100755 trunk/research/st/md.S delete mode 100644 trunk/research/st/md.h delete mode 100644 trunk/research/st/public.h delete mode 100755 trunk/research/st/sched.c delete mode 100644 trunk/research/st/srs.c delete mode 100644 trunk/research/st/st/init delete mode 100755 trunk/research/st/st/st.upp delete mode 100644 trunk/research/st/stk.c delete mode 100644 trunk/research/st/sync.c diff --git a/trunk/3rdparty/libco/.gitignore b/trunk/3rdparty/libco/.gitignore new file mode 100644 index 0000000000..42061c01a1 --- /dev/null +++ b/trunk/3rdparty/libco/.gitignore @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/trunk/3rdparty/libco/CMakeLists.txt b/trunk/3rdparty/libco/CMakeLists.txt new file mode 100644 index 0000000000..04399a55a3 --- /dev/null +++ b/trunk/3rdparty/libco/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 2.8) +project(libco) + +# This for mac osx only +set(CMAKE_MACOSX_RPATH 0) + +# Set lib version +set(LIBCO_VERSION 0.5) + +# Set cflags +set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -g -fno-strict-aliasing -O2 -Wall -export-dynamic -Wall -pipe -D_GNU_SOURCE -D_REENTRANT -fPIC -Wno-deprecated -m64) + +# Use c and asm +enable_language(C ASM) + +# Add source files +set(SOURCE_FILES + co_epoll.cpp + co_hook_sys_call.cpp + co_routine.cpp + coctx.cpp + coctx_swap.S) + +# Add static and shared library target +add_library(colib_static STATIC ${SOURCE_FILES}) +add_library(colib_shared SHARED ${SOURCE_FILES}) + +# Set library output name +set_target_properties(colib_static PROPERTIES OUTPUT_NAME colib) +set_target_properties(colib_shared PROPERTIES OUTPUT_NAME colib) + +set_target_properties(colib_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) +set_target_properties(colib_shared PROPERTIES CLEAN_DIRECT_OUTPUT 1) + +# Set shared library version, will generate libcolib.${LIBCO_VERSION}.so and a symbol link named libcolib.so +# For mac osx, the extension name will be .dylib +set_target_properties(colib_shared PROPERTIES VERSION ${LIBCO_VERSION} SOVERSION ${LIBCO_VERSION}) + + + +# Macro for add example target +macro(add_example_target EXAMPLE_TARGET) + add_executable("example_${EXAMPLE_TARGET}" "example_${EXAMPLE_TARGET}.cpp") + target_link_libraries("example_${EXAMPLE_TARGET}" colib_static pthread dl) +endmacro(add_example_target) + +add_example_target(closure) +add_example_target(cond) +add_example_target(copystack) +add_example_target(echocli) +add_example_target(echosvr) +add_example_target(poll) +add_example_target(setenv) +add_example_target(specific) +add_example_target(thread) diff --git a/trunk/3rdparty/libco/LICENSE.txt b/trunk/3rdparty/libco/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..bff49d4bc3a55637e1ed4bd7eeb9834a2b16dbd4 GIT binary patch literal 18962 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 literal 0 HcmV?d00001 diff --git a/trunk/3rdparty/libco/Makefile b/trunk/3rdparty/libco/Makefile new file mode 100644 index 0000000000..7db3749460 --- /dev/null +++ b/trunk/3rdparty/libco/Makefile @@ -0,0 +1,84 @@ +# +# Tencent is pleased to support the open source community by making Libco available. +# +# Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +COMM_MAKE = 1 +COMM_ECHO = 1 +version=0.5 +v=debug +include co.mk + +########## options ########## +CFLAGS += -g -fno-strict-aliasing -O2 -Wall -export-dynamic \ + -Wall -pipe -D_GNU_SOURCE -D_REENTRANT -fPIC -Wno-deprecated -m64 + +UNAME := $(shell uname -s) + +ifeq ($(UNAME), FreeBSD) +LINKS += -g -L./lib -lcolib -lpthread +else +LINKS += -g -L./lib -lcolib -lpthread -ldl +endif + +COLIB_OBJS=co_epoll.o co_routine.o co_hook_sys_call.o coctx_swap.o coctx.o +#co_swapcontext.o + +PROGS = colib example_poll example_echosvr example_echocli example_thread example_cond example_specific example_copystack example_closure + +all:$(PROGS) + +colib:libcolib.a libcolib.so + +libcolib.a: $(COLIB_OBJS) + $(ARSTATICLIB) +libcolib.so: $(COLIB_OBJS) + $(BUILDSHARELIB) + +example_echosvr:example_echosvr.o + $(BUILDEXE) +example_echocli:example_echocli.o + $(BUILDEXE) +example_thread:example_thread.o + $(BUILDEXE) +example_poll:example_poll.o + $(BUILDEXE) +example_exit:example_exit.o + $(BUILDEXE) +example_cond:example_cond.o + $(BUILDEXE) +example_specific:example_specific.o + $(BUILDEXE) +example_copystack:example_copystack.o + $(BUILDEXE) +example_setenv:example_setenv.o + $(BUILDEXE) +example_closure:example_closure.o + $(BUILDEXE) + +dist: clean libco-$(version).src.tar.gz + +libco-$(version).src.tar.gz: + @find . -type f | grep -v CVS | grep -v .svn | sed s:^./:libco-$(version)/: > MANIFEST + @(cd ..; ln -s libco_pub libco-$(version)) + (cd ..; tar cvf - `cat libco_pub/MANIFEST` | gzip > libco_pub/libco-$(version).src.tar.gz) + @(cd ..; rm libco-$(version)) + +clean: + $(CLEAN) *.o $(PROGS) + rm -fr MANIFEST lib solib libco-$(version).src.tar.gz libco-$(version) + diff --git a/trunk/3rdparty/libco/co.mk b/trunk/3rdparty/libco/co.mk new file mode 100644 index 0000000000..29658b5116 --- /dev/null +++ b/trunk/3rdparty/libco/co.mk @@ -0,0 +1,85 @@ +# +# Tencent is pleased to support the open source community by making Libco available. +# +# Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + + +##### Makefile Rules ########## +MAIL_ROOT=. +SRCROOT=. + +##define the compliers +CPP = $(CXX) +AR = ar -rc +RANLIB = ranlib + +CPPSHARE = $(CPP) -fPIC -shared -O2 -pipe -L$(SRCROOT)/solib/ -o +CSHARE = $(CC) -fPIC -shared -O2 -pipe -L$(SRCROOT)/solib/ -o + +ifeq ($v,release) +CFLAGS= -O2 $(INCLS) -fPIC -DLINUX -pipe -Wno-deprecated -c +else +CFLAGS= -g $(INCLS) -fPIC -DLINUX -pipe -c -fno-inline +endif + +ifneq ($v,release) +BFLAGS= -g +endif + +STATICLIBPATH=$(SRCROOT)/lib +DYNAMICLIBPATH=$(SRCROOT)/solib + +INCLS += -I$(SRCROOT) + +## default links +ifeq ($(LINKS_DYNAMIC), 1) +LINKS += -L$(DYNAMICLIBPATH) -L$(STATICLIBPATH) +else +LINKS += -L$(STATICLIBPATH) +endif + +CPPSRCS = $(wildcard *.cpp) +CSRCS = $(wildcard *.c) +CPPOBJS = $(patsubst %.cpp,%.o,$(CPPSRCS)) +COBJS = $(patsubst %.c,%.o,$(CSRCS)) + +SRCS = $(CPPSRCS) $(CSRCS) +OBJS = $(CPPOBJS) $(COBJS) + +CPPCOMPI=$(CPP) $(CFLAGS) -Wno-deprecated +CCCOMPI=$(CC) $(CFLAGS) + +BUILDEXE = $(CPP) $(BFLAGS) -o $@ $^ $(LINKS) +CLEAN = rm -f *.o + +CPPCOMPILE = $(CPPCOMPI) $< $(FLAGS) $(INCLS) $(MTOOL_INCL) -o $@ +CCCOMPILE = $(CCCOMPI) $< $(FLAGS) $(INCLS) $(MTOOL_INCL) -o $@ + +ARSTATICLIB = $(AR) $@.tmp $^ $(AR_FLAGS); \ + if [ $$? -ne 0 ]; then exit 1; fi; \ + test -d $(STATICLIBPATH) || mkdir -p $(STATICLIBPATH); \ + mv -f $@.tmp $(STATICLIBPATH)/$@; + +BUILDSHARELIB = $(CPPSHARE) $@.tmp $^ $(BS_FLAGS); \ + if [ $$? -ne 0 ]; then exit 1; fi; \ + test -d $(DYNAMICLIBPATH) || mkdir -p $(DYNAMICLIBPATH); \ + mv -f $@.tmp $(DYNAMICLIBPATH)/$@; + +.cpp.o: + $(CPPCOMPILE) +.c.o: + $(CCCOMPILE) diff --git a/trunk/3rdparty/libco/co_closure.h b/trunk/3rdparty/libco/co_closure.h new file mode 100644 index 0000000000..87d5c6891d --- /dev/null +++ b/trunk/3rdparty/libco/co_closure.h @@ -0,0 +1,96 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __CO_CLOSURE_H__ +#define __CO_CLOSURE_H__ +struct stCoClosure_t +{ +public: + virtual void exec() = 0; +}; + +//1.base +//-- 1.1 comac_argc + +#define comac_get_args_cnt( ... ) comac_arg_n( __VA_ARGS__ ) +#define comac_arg_n( _0,_1,_2,_3,_4,_5,_6,_7,N,...) N +#define comac_args_seqs() 7,6,5,4,3,2,1,0 +#define comac_join_1( x,y ) x##y + +#define comac_argc( ... ) comac_get_args_cnt( 0,##__VA_ARGS__,comac_args_seqs() ) +#define comac_join( x,y) comac_join_1( x,y ) + +//-- 1.2 repeat +#define repeat_0( fun,a,... ) +#define repeat_1( fun,a,... ) fun( 1,a,__VA_ARGS__ ) repeat_0( fun,__VA_ARGS__ ) +#define repeat_2( fun,a,... ) fun( 2,a,__VA_ARGS__ ) repeat_1( fun,__VA_ARGS__ ) +#define repeat_3( fun,a,... ) fun( 3,a,__VA_ARGS__ ) repeat_2( fun,__VA_ARGS__ ) +#define repeat_4( fun,a,... ) fun( 4,a,__VA_ARGS__ ) repeat_3( fun,__VA_ARGS__ ) +#define repeat_5( fun,a,... ) fun( 5,a,__VA_ARGS__ ) repeat_4( fun,__VA_ARGS__ ) +#define repeat_6( fun,a,... ) fun( 6,a,__VA_ARGS__ ) repeat_5( fun,__VA_ARGS__ ) + +#define repeat( n,fun,... ) comac_join( repeat_,n )( fun,__VA_ARGS__) + +//2.implement +#if __cplusplus <= 199711L +#define decl_typeof( i,a,... ) typedef typeof( a ) typeof_##a; +#else +#define decl_typeof( i,a,... ) typedef decltype( a ) typeof_##a; +#endif +#define impl_typeof( i,a,... ) typeof_##a & a; +#define impl_typeof_cpy( i,a,... ) typeof_##a a; +#define con_param_typeof( i,a,... ) typeof_##a & a##r, +#define param_init_typeof( i,a,... ) a(a##r), + + +//2.1 reference + +#define co_ref( name,... )\ +repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\ +class type_##name\ +{\ +public:\ + repeat( comac_argc(__VA_ARGS__) ,impl_typeof,__VA_ARGS__ )\ + int _member_cnt;\ + type_##name( \ + repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \ + repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__)) \ + {}\ +} name( __VA_ARGS__ ) ; + + +//2.2 function + +#define co_func(name,...)\ +repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\ +class name:public stCoClosure_t\ +{\ +public:\ + repeat( comac_argc(__VA_ARGS__) ,impl_typeof_cpy,__VA_ARGS__ )\ + int _member_cnt;\ +public:\ + name( repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \ + repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__))\ + {}\ + void exec() + +#define co_func_end } + + +#endif + diff --git a/trunk/3rdparty/libco/co_epoll.cpp b/trunk/3rdparty/libco/co_epoll.cpp new file mode 100644 index 0000000000..12726218dd --- /dev/null +++ b/trunk/3rdparty/libco/co_epoll.cpp @@ -0,0 +1,318 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "co_epoll.h" +#include +#include +#include +#include + +#if !defined( __APPLE__ ) && !defined( __FreeBSD__ ) + +int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ) +{ + return epoll_wait( epfd,events->events,maxevents,timeout ); +} +int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev ) +{ + return epoll_ctl( epfd,op,fd,ev ); +} +int co_epoll_create( int size ) +{ + return epoll_create( size ); +} + +struct co_epoll_res *co_epoll_res_alloc( int n ) +{ + struct co_epoll_res * ptr = + (struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) ); + + ptr->size = n; + ptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) ); + + return ptr; + +} +void co_epoll_res_free( struct co_epoll_res * ptr ) +{ + if( !ptr ) return; + if( ptr->events ) free( ptr->events ); + free( ptr ); +} + +#else +class clsFdMap // million of fd , 1024 * 1024 +{ +private: + static const int row_size = 1024; + static const int col_size = 1024; + + void **m_pp[ 1024 ]; +public: + clsFdMap() + { + memset( m_pp,0,sizeof(m_pp) ); + } + ~clsFdMap() + { + for(int i=0;i= sizeof(m_pp)/sizeof(m_pp[0]) ) + { + assert( __LINE__ == 0 ); + return -__LINE__; + } + if( !m_pp[ idx ] ) + { + m_pp[ idx ] = (void**)calloc( 1,sizeof(void*) * col_size ); + } + m_pp[ idx ][ fd % col_size ] = (void*)ptr; + return 0; + } + inline void *get( int fd ) + { + int idx = fd / row_size; + if( idx < 0 || idx >= sizeof(m_pp)/sizeof(m_pp[0]) ) + { + return NULL; + } + void **lp = m_pp[ idx ]; + if( !lp ) return NULL; + + return lp[ fd % col_size ]; + } +}; + +__thread clsFdMap *s_fd_map = NULL; + +static inline clsFdMap *get_fd_map() +{ + if( !s_fd_map ) + { + s_fd_map = new clsFdMap(); + } + return s_fd_map; +} + +struct kevent_pair_t +{ + int fire_idx; + int events; + uint64_t u64; +}; +int co_epoll_create( int size ) +{ + return kqueue(); +} +int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ) +{ + struct timespec t = { 0 }; + if( timeout > 0 ) + { + t.tv_sec = timeout; + } + int ret = kevent( epfd, + NULL, 0, //register null + events->eventlist, maxevents,//just retrival + ( -1 == timeout ) ? NULL : &t ); + int j = 0; + for(int i=0;ieventlist[i]; + struct kevent_pair_t *ptr = (struct kevent_pair_t*)kev.udata; + struct epoll_event *ev = events->events + i; + if( 0 == ptr->fire_idx ) + { + ptr->fire_idx = i + 1; + memset( ev,0,sizeof(*ev) ); + ++j; + } + else + { + ev = events->events + ptr->fire_idx - 1; + } + if( EVFILT_READ == kev.filter ) + { + ev->events |= EPOLLIN; + } + else if( EVFILT_WRITE == kev.filter ) + { + ev->events |= EPOLLOUT; + } + ev->data.u64 = ptr->u64; + } + for(int i=0;ieventlist[i].udata) )->fire_idx = 0; + } + return j; +} +int co_epoll_del( int epfd,int fd ) +{ + + struct timespec t = { 0 }; + struct kevent_pair_t *ptr = ( struct kevent_pair_t* )get_fd_map()->get( fd ); + if( !ptr ) return 0; + if( EPOLLIN & ptr->events ) + { + struct kevent kev = { 0 }; + kev.ident = fd; + kev.filter = EVFILT_READ; + kev.flags = EV_DELETE; + kevent( epfd,&kev,1, NULL,0,&t ); + } + if( EPOLLOUT & ptr->events ) + { + struct kevent kev = { 0 }; + kev.ident = fd; + kev.filter = EVFILT_WRITE; + kev.flags = EV_DELETE; + kevent( epfd,&kev,1, NULL,0,&t ); + } + get_fd_map()->clear( fd ); + free( ptr ); + return 0; +} +int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev ) +{ + if( EPOLL_CTL_DEL == op ) + { + return co_epoll_del( epfd,fd ); + } + + const int flags = ( EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP ); + if( ev->events & ~flags ) + { + return -1; + } + + if( EPOLL_CTL_ADD == op && get_fd_map()->get( fd ) ) + { + errno = EEXIST; + return -1; + } + else if( EPOLL_CTL_MOD == op && !get_fd_map()->get( fd ) ) + { + errno = ENOENT; + return -1; + } + + struct kevent_pair_t *ptr = (struct kevent_pair_t*)get_fd_map()->get( fd ); + if( !ptr ) + { + ptr = (kevent_pair_t*)calloc(1,sizeof(kevent_pair_t)); + get_fd_map()->set( fd,ptr ); + } + + int ret = 0; + struct timespec t = { 0 }; + + // printf("ptr->events 0x%X\n",ptr->events); + + if( EPOLL_CTL_MOD == op ) + { + //1.delete if exists + if( ptr->events & EPOLLIN ) + { + struct kevent kev = { 0 }; + EV_SET( &kev,fd,EVFILT_READ,EV_DELETE,0,0,NULL ); + kevent( epfd, &kev,1, NULL,0, &t ); + } + //1.delete if exists + if( ptr->events & EPOLLOUT ) + { + struct kevent kev = { 0 }; + EV_SET( &kev,fd,EVFILT_WRITE,EV_DELETE,0,0,NULL ); + ret = kevent( epfd, &kev,1, NULL,0, &t ); + // printf("delete write ret %d\n",ret ); + } + } + + do + { + if( ev->events & EPOLLIN ) + { + + //2.add + struct kevent kev = { 0 }; + EV_SET( &kev,fd,EVFILT_READ,EV_ADD,0,0,ptr ); + ret = kevent( epfd, &kev,1, NULL,0, &t ); + if( ret ) break; + } + if( ev->events & EPOLLOUT ) + { + //2.add + struct kevent kev = { 0 }; + EV_SET( &kev,fd,EVFILT_WRITE,EV_ADD,0,0,ptr ); + ret = kevent( epfd, &kev,1, NULL,0, &t ); + if( ret ) break; + } + } while( 0 ); + + if( ret ) + { + get_fd_map()->clear( fd ); + free( ptr ); + return ret; + } + + ptr->events = ev->events; + ptr->u64 = ev->data.u64; + + + return ret; +} + +struct co_epoll_res *co_epoll_res_alloc( int n ) +{ + struct co_epoll_res * ptr = + (struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) ); + + ptr->size = n; + ptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) ); + ptr->eventlist = (struct kevent*)calloc( 1,n * sizeof( struct kevent) ); + + return ptr; +} + +void co_epoll_res_free( struct co_epoll_res * ptr ) +{ + if( !ptr ) return; + if( ptr->events ) free( ptr->events ); + if( ptr->eventlist ) free( ptr->eventlist ); + free( ptr ); +} + +#endif + + diff --git a/trunk/3rdparty/libco/co_epoll.h b/trunk/3rdparty/libco/co_epoll.h new file mode 100644 index 0000000000..a1b0e4a7d9 --- /dev/null +++ b/trunk/3rdparty/libco/co_epoll.h @@ -0,0 +1,93 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __CO_EPOLL_H__ +#define __CO_EPOLL_H__ +#include +#include +#include +#include +#include +#include +#include + +#if !defined( __APPLE__ ) && !defined( __FreeBSD__ ) + +#include + +struct co_epoll_res +{ + int size; + struct epoll_event *events; + struct kevent *eventlist; +}; +int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ); +int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ); +int co_epoll_create( int size ); +struct co_epoll_res *co_epoll_res_alloc( int n ); +void co_epoll_res_free( struct co_epoll_res * ); + +#else + +#include +enum EPOLL_EVENTS +{ + EPOLLIN = 0X001, + EPOLLPRI = 0X002, + EPOLLOUT = 0X004, + + EPOLLERR = 0X008, + EPOLLHUP = 0X010, + + EPOLLRDNORM = 0x40, + EPOLLWRNORM = 0x004, +}; +#define EPOLL_CTL_ADD 1 +#define EPOLL_CTL_DEL 2 +#define EPOLL_CTL_MOD 3 +typedef union epoll_data +{ + void *ptr; + int fd; + uint32_t u32; + uint64_t u64; + +} epoll_data_t; + +struct epoll_event +{ + uint32_t events; + epoll_data_t data; +}; + +struct co_epoll_res +{ + int size; + struct epoll_event *events; + struct kevent *eventlist; +}; +int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ); +int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ); +int co_epoll_create( int size ); +struct co_epoll_res *co_epoll_res_alloc( int n ); +void co_epoll_res_free( struct co_epoll_res * ); + +#endif +#endif + + diff --git a/trunk/3rdparty/libco/co_hook_sys_call.cpp b/trunk/3rdparty/libco/co_hook_sys_call.cpp new file mode 100644 index 0000000000..7bb0c417b9 --- /dev/null +++ b/trunk/3rdparty/libco/co_hook_sys_call.cpp @@ -0,0 +1,1003 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "co_routine.h" +#include "co_routine_inner.h" +#include "co_routine_specific.h" + +typedef long long ll64_t; + +struct rpchook_t +{ + int user_flag; + struct sockaddr_in dest; //maybe sockaddr_un; + int domain; //AF_LOCAL , AF_INET + + struct timeval read_timeout; + struct timeval write_timeout; +}; +static inline pid_t GetPid() +{ + char **p = (char**)pthread_self(); + return p ? *(pid_t*)(p + 18) : getpid(); +} +static rpchook_t *g_rpchook_socket_fd[ 102400 ] = { 0 }; + +typedef int (*socket_pfn_t)(int domain, int type, int protocol); +typedef int (*connect_pfn_t)(int socket, const struct sockaddr *address, socklen_t address_len); +typedef int (*close_pfn_t)(int fd); + +typedef ssize_t (*read_pfn_t)(int fildes, void *buf, size_t nbyte); +typedef ssize_t (*write_pfn_t)(int fildes, const void *buf, size_t nbyte); + +typedef ssize_t (*sendto_pfn_t)(int socket, const void *message, size_t length, + int flags, const struct sockaddr *dest_addr, + socklen_t dest_len); + +typedef ssize_t (*recvfrom_pfn_t)(int socket, void *buffer, size_t length, + int flags, struct sockaddr *address, + socklen_t *address_len); + +typedef size_t (*send_pfn_t)(int socket, const void *buffer, size_t length, int flags); +typedef ssize_t (*recv_pfn_t)(int socket, void *buffer, size_t length, int flags); + +typedef int (*poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout); +typedef int (*setsockopt_pfn_t)(int socket, int level, int option_name, + const void *option_value, socklen_t option_len); + +typedef int (*fcntl_pfn_t)(int fildes, int cmd, ...); +typedef struct tm *(*localtime_r_pfn_t)( const time_t *timep, struct tm *result ); + +typedef void *(*pthread_getspecific_pfn_t)(pthread_key_t key); +typedef int (*pthread_setspecific_pfn_t)(pthread_key_t key, const void *value); + +typedef int (*setenv_pfn_t)(const char *name, const char *value, int overwrite); +typedef int (*unsetenv_pfn_t)(const char *name); +typedef char *(*getenv_pfn_t)(const char *name); +typedef hostent* (*gethostbyname_pfn_t)(const char *name); +typedef res_state (*__res_state_pfn_t)(); +typedef int (*__poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout); + +static socket_pfn_t g_sys_socket_func = (socket_pfn_t)dlsym(RTLD_NEXT,"socket"); +static connect_pfn_t g_sys_connect_func = (connect_pfn_t)dlsym(RTLD_NEXT,"connect"); +static close_pfn_t g_sys_close_func = (close_pfn_t)dlsym(RTLD_NEXT,"close"); + +static read_pfn_t g_sys_read_func = (read_pfn_t)dlsym(RTLD_NEXT,"read"); +static write_pfn_t g_sys_write_func = (write_pfn_t)dlsym(RTLD_NEXT,"write"); + +static sendto_pfn_t g_sys_sendto_func = (sendto_pfn_t)dlsym(RTLD_NEXT,"sendto"); +static recvfrom_pfn_t g_sys_recvfrom_func = (recvfrom_pfn_t)dlsym(RTLD_NEXT,"recvfrom"); + +static send_pfn_t g_sys_send_func = (send_pfn_t)dlsym(RTLD_NEXT,"send"); +static recv_pfn_t g_sys_recv_func = (recv_pfn_t)dlsym(RTLD_NEXT,"recv"); + +static poll_pfn_t g_sys_poll_func = (poll_pfn_t)dlsym(RTLD_NEXT,"poll"); + +static setsockopt_pfn_t g_sys_setsockopt_func + = (setsockopt_pfn_t)dlsym(RTLD_NEXT,"setsockopt"); +static fcntl_pfn_t g_sys_fcntl_func = (fcntl_pfn_t)dlsym(RTLD_NEXT,"fcntl"); + +static setenv_pfn_t g_sys_setenv_func = (setenv_pfn_t)dlsym(RTLD_NEXT,"setenv"); +static unsetenv_pfn_t g_sys_unsetenv_func = (unsetenv_pfn_t)dlsym(RTLD_NEXT,"unsetenv"); +static getenv_pfn_t g_sys_getenv_func = (getenv_pfn_t)dlsym(RTLD_NEXT,"getenv"); +static __res_state_pfn_t g_sys___res_state_func = (__res_state_pfn_t)dlsym(RTLD_NEXT,"__res_state"); + +static gethostbyname_pfn_t g_sys_gethostbyname_func = (gethostbyname_pfn_t)dlsym(RTLD_NEXT, "gethostbyname"); + +static __poll_pfn_t g_sys___poll_func = (__poll_pfn_t)dlsym(RTLD_NEXT, "__poll"); + + +/* +static pthread_getspecific_pfn_t g_sys_pthread_getspecific_func + = (pthread_getspecific_pfn_t)dlsym(RTLD_NEXT,"pthread_getspecific"); + +static pthread_setspecific_pfn_t g_sys_pthread_setspecific_func + = (pthread_setspecific_pfn_t)dlsym(RTLD_NEXT,"pthread_setspecific"); + +static pthread_rwlock_rdlock_pfn_t g_sys_pthread_rwlock_rdlock_func + = (pthread_rwlock_rdlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_rdlock"); + +static pthread_rwlock_wrlock_pfn_t g_sys_pthread_rwlock_wrlock_func + = (pthread_rwlock_wrlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_wrlock"); + +static pthread_rwlock_unlock_pfn_t g_sys_pthread_rwlock_unlock_func + = (pthread_rwlock_unlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_unlock"); +*/ + + + +static inline unsigned long long get_tick_count() +{ + uint32_t lo, hi; + __asm__ __volatile__ ( + "rdtscp" : "=a"(lo), "=d"(hi) + ); + return ((unsigned long long)lo) | (((unsigned long long)hi) << 32); +} + +struct rpchook_connagent_head_t +{ + unsigned char bVersion; + struct in_addr iIP; + unsigned short hPort; + unsigned int iBodyLen; + unsigned int iOssAttrID; + unsigned char bIsRespNotExist; + unsigned char sReserved[6]; +}__attribute__((packed)); + + +#define HOOK_SYS_FUNC(name) if( !g_sys_##name##_func ) { g_sys_##name##_func = (name##_pfn_t)dlsym(RTLD_NEXT,#name); } + +static inline ll64_t diff_ms(struct timeval &begin,struct timeval &end) +{ + ll64_t u = (end.tv_sec - begin.tv_sec) ; + u *= 1000 * 10; + u += ( end.tv_usec - begin.tv_usec ) / ( 100 ); + return u; +} + + + +static inline rpchook_t * get_by_fd( int fd ) +{ + if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) ) + { + return g_rpchook_socket_fd[ fd ]; + } + return NULL; +} +static inline rpchook_t * alloc_by_fd( int fd ) +{ + if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) ) + { + rpchook_t *lp = (rpchook_t*)calloc( 1,sizeof(rpchook_t) ); + lp->read_timeout.tv_sec = 1; + lp->write_timeout.tv_sec = 1; + g_rpchook_socket_fd[ fd ] = lp; + return lp; + } + return NULL; +} +static inline void free_by_fd( int fd ) +{ + if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) ) + { + rpchook_t *lp = g_rpchook_socket_fd[ fd ]; + if( lp ) + { + g_rpchook_socket_fd[ fd ] = NULL; + free(lp); + } + } + return; + +} +int socket(int domain, int type, int protocol) +{ + HOOK_SYS_FUNC( socket ); + + if( !co_is_enable_sys_hook() ) + { + return g_sys_socket_func( domain,type,protocol ); + } + int fd = g_sys_socket_func(domain,type,protocol); + if( fd < 0 ) + { + return fd; + } + + rpchook_t *lp = alloc_by_fd( fd ); + lp->domain = domain; + + fcntl( fd, F_SETFL, g_sys_fcntl_func(fd, F_GETFL,0 ) ); + + return fd; +} + +int co_accept( int fd, struct sockaddr *addr, socklen_t *len ) +{ + int cli = accept( fd,addr,len ); + if( cli < 0 ) + { + return cli; + } + alloc_by_fd( cli ); + return cli; +} +int connect(int fd, const struct sockaddr *address, socklen_t address_len) +{ + HOOK_SYS_FUNC( connect ); + + if( !co_is_enable_sys_hook() ) + { + return g_sys_connect_func(fd,address,address_len); + } + + //1.sys call + int ret = g_sys_connect_func( fd,address,address_len ); + + rpchook_t *lp = get_by_fd( fd ); + if( !lp ) return ret; + + if( sizeof(lp->dest) >= address_len ) + { + memcpy( &(lp->dest),address,(int)address_len ); + } + if( O_NONBLOCK & lp->user_flag ) + { + return ret; + } + + if (!(ret < 0 && errno == EINPROGRESS)) + { + return ret; + } + + //2.wait + int pollret = 0; + struct pollfd pf = { 0 }; + + for(int i=0;i<3;i++) //25s * 3 = 75s + { + memset( &pf,0,sizeof(pf) ); + pf.fd = fd; + pf.events = ( POLLOUT | POLLERR | POLLHUP ); + + pollret = poll( &pf,1,25000 ); + + if( 1 == pollret ) + { + break; + } + } + + if( pf.revents & POLLOUT ) //connect succ + { + // 3.check getsockopt ret + int err = 0; + socklen_t errlen = sizeof(err); + ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen); + if (ret < 0) { + return ret; + } else if (err != 0) { + errno = err; + return -1; + } + errno = 0; + return 0; + } + + errno = ETIMEDOUT; + return ret; +} + + +int close(int fd) +{ + HOOK_SYS_FUNC( close ); + + if( !co_is_enable_sys_hook() ) + { + return g_sys_close_func( fd ); + } + + free_by_fd( fd ); + int ret = g_sys_close_func(fd); + + return ret; +} +ssize_t read( int fd, void *buf, size_t nbyte ) +{ + HOOK_SYS_FUNC( read ); + + if( !co_is_enable_sys_hook() ) + { + return g_sys_read_func( fd,buf,nbyte ); + } + rpchook_t *lp = get_by_fd( fd ); + + if( !lp || ( O_NONBLOCK & lp->user_flag ) ) + { + ssize_t ret = g_sys_read_func( fd,buf,nbyte ); + return ret; + } + int timeout = ( lp->read_timeout.tv_sec * 1000 ) + + ( lp->read_timeout.tv_usec / 1000 ); + + struct pollfd pf = { 0 }; + pf.fd = fd; + pf.events = ( POLLIN | POLLERR | POLLHUP ); + + int pollret = poll( &pf,1,timeout ); + + ssize_t readret = g_sys_read_func( fd,(char*)buf ,nbyte ); + + if( readret < 0 ) + { + co_log_err("CO_ERR: read fd %d ret %ld errno %d poll ret %d timeout %d", + fd,readret,errno,pollret,timeout); + } + + return readret; + +} +ssize_t write( int fd, const void *buf, size_t nbyte ) +{ + HOOK_SYS_FUNC( write ); + + if( !co_is_enable_sys_hook() ) + { + return g_sys_write_func( fd,buf,nbyte ); + } + rpchook_t *lp = get_by_fd( fd ); + + if( !lp || ( O_NONBLOCK & lp->user_flag ) ) + { + ssize_t ret = g_sys_write_func( fd,buf,nbyte ); + return ret; + } + size_t wrotelen = 0; + int timeout = ( lp->write_timeout.tv_sec * 1000 ) + + ( lp->write_timeout.tv_usec / 1000 ); + + ssize_t writeret = g_sys_write_func( fd,(const char*)buf + wrotelen,nbyte - wrotelen ); + + if (writeret == 0) + { + return writeret; + } + + if( writeret > 0 ) + { + wrotelen += writeret; + } + while( wrotelen < nbyte ) + { + + struct pollfd pf = { 0 }; + pf.fd = fd; + pf.events = ( POLLOUT | POLLERR | POLLHUP ); + poll( &pf,1,timeout ); + + writeret = g_sys_write_func( fd,(const char*)buf + wrotelen,nbyte - wrotelen ); + + if( writeret <= 0 ) + { + break; + } + wrotelen += writeret ; + } + if (writeret <= 0 && wrotelen == 0) + { + return writeret; + } + return wrotelen; +} + +ssize_t sendto(int socket, const void *message, size_t length, + int flags, const struct sockaddr *dest_addr, + socklen_t dest_len) +{ + /* + 1.no enable sys call ? sys + 2.( !lp || lp is non block ) ? sys + 3.try + 4.wait + 5.try + */ + HOOK_SYS_FUNC( sendto ); + if( !co_is_enable_sys_hook() ) + { + return g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); + } + + rpchook_t *lp = get_by_fd( socket ); + if( !lp || ( O_NONBLOCK & lp->user_flag ) ) + { + return g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); + } + + ssize_t ret = g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); + if( ret < 0 && EAGAIN == errno ) + { + int timeout = ( lp->write_timeout.tv_sec * 1000 ) + + ( lp->write_timeout.tv_usec / 1000 ); + + + struct pollfd pf = { 0 }; + pf.fd = socket; + pf.events = ( POLLOUT | POLLERR | POLLHUP ); + poll( &pf,1,timeout ); + + ret = g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); + + } + return ret; +} + +ssize_t recvfrom(int socket, void *buffer, size_t length, + int flags, struct sockaddr *address, + socklen_t *address_len) +{ + HOOK_SYS_FUNC( recvfrom ); + if( !co_is_enable_sys_hook() ) + { + return g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len ); + } + + rpchook_t *lp = get_by_fd( socket ); + if( !lp || ( O_NONBLOCK & lp->user_flag ) ) + { + return g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len ); + } + + int timeout = ( lp->read_timeout.tv_sec * 1000 ) + + ( lp->read_timeout.tv_usec / 1000 ); + + + struct pollfd pf = { 0 }; + pf.fd = socket; + pf.events = ( POLLIN | POLLERR | POLLHUP ); + poll( &pf,1,timeout ); + + ssize_t ret = g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len ); + return ret; +} + +ssize_t send(int socket, const void *buffer, size_t length, int flags) +{ + HOOK_SYS_FUNC( send ); + + if( !co_is_enable_sys_hook() ) + { + return g_sys_send_func( socket,buffer,length,flags ); + } + rpchook_t *lp = get_by_fd( socket ); + + if( !lp || ( O_NONBLOCK & lp->user_flag ) ) + { + return g_sys_send_func( socket,buffer,length,flags ); + } + size_t wrotelen = 0; + int timeout = ( lp->write_timeout.tv_sec * 1000 ) + + ( lp->write_timeout.tv_usec / 1000 ); + + ssize_t writeret = g_sys_send_func( socket,buffer,length,flags ); + if (writeret == 0) + { + return writeret; + } + + if( writeret > 0 ) + { + wrotelen += writeret; + } + while( wrotelen < length ) + { + + struct pollfd pf = { 0 }; + pf.fd = socket; + pf.events = ( POLLOUT | POLLERR | POLLHUP ); + poll( &pf,1,timeout ); + + writeret = g_sys_send_func( socket,(const char*)buffer + wrotelen,length - wrotelen,flags ); + + if( writeret <= 0 ) + { + break; + } + wrotelen += writeret ; + } + if (writeret <= 0 && wrotelen == 0) + { + return writeret; + } + return wrotelen; +} + +ssize_t recv( int socket, void *buffer, size_t length, int flags ) +{ + HOOK_SYS_FUNC( recv ); + + if( !co_is_enable_sys_hook() ) + { + return g_sys_recv_func( socket,buffer,length,flags ); + } + rpchook_t *lp = get_by_fd( socket ); + + if( !lp || ( O_NONBLOCK & lp->user_flag ) ) + { + return g_sys_recv_func( socket,buffer,length,flags ); + } + int timeout = ( lp->read_timeout.tv_sec * 1000 ) + + ( lp->read_timeout.tv_usec / 1000 ); + + struct pollfd pf = { 0 }; + pf.fd = socket; + pf.events = ( POLLIN | POLLERR | POLLHUP ); + + int pollret = poll( &pf,1,timeout ); + + ssize_t readret = g_sys_recv_func( socket,buffer,length,flags ); + + if( readret < 0 ) + { + co_log_err("CO_ERR: read fd %d ret %ld errno %d poll ret %d timeout %d", + socket,readret,errno,pollret,timeout); + } + + return readret; + +} + +extern int co_poll_inner( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout, poll_pfn_t pollfunc); + +int poll(struct pollfd fds[], nfds_t nfds, int timeout) +{ + HOOK_SYS_FUNC( poll ); + + if (!co_is_enable_sys_hook() || timeout == 0) { + return g_sys_poll_func(fds, nfds, timeout); + } + pollfd *fds_merge = NULL; + nfds_t nfds_merge = 0; + std::map m; // fd --> idx + std::map::iterator it; + if (nfds > 1) { + fds_merge = (pollfd *)malloc(sizeof(pollfd) * nfds); + for (size_t i = 0; i < nfds; i++) { + if ((it = m.find(fds[i].fd)) == m.end()) { + fds_merge[nfds_merge] = fds[i]; + m[fds[i].fd] = nfds_merge; + nfds_merge++; + } else { + int j = it->second; + fds_merge[j].events |= fds[i].events; // merge in j slot + } + } + } + + int ret = 0; + if (nfds_merge == nfds || nfds == 1) { + ret = co_poll_inner(co_get_epoll_ct(), fds, nfds, timeout, g_sys_poll_func); + } else { + ret = co_poll_inner(co_get_epoll_ct(), fds_merge, nfds_merge, timeout, + g_sys_poll_func); + if (ret > 0) { + for (size_t i = 0; i < nfds; i++) { + it = m.find(fds[i].fd); + if (it != m.end()) { + int j = it->second; + fds[i].revents = fds_merge[j].revents & fds[i].events; + } + } + } + } + free(fds_merge); + return ret; + + +} +int setsockopt(int fd, int level, int option_name, + const void *option_value, socklen_t option_len) +{ + HOOK_SYS_FUNC( setsockopt ); + + if( !co_is_enable_sys_hook() ) + { + return g_sys_setsockopt_func( fd,level,option_name,option_value,option_len ); + } + rpchook_t *lp = get_by_fd( fd ); + + if( lp && SOL_SOCKET == level ) + { + struct timeval *val = (struct timeval*)option_value; + if( SO_RCVTIMEO == option_name ) + { + memcpy( &lp->read_timeout,val,sizeof(*val) ); + } + else if( SO_SNDTIMEO == option_name ) + { + memcpy( &lp->write_timeout,val,sizeof(*val) ); + } + } + return g_sys_setsockopt_func( fd,level,option_name,option_value,option_len ); +} + + +int fcntl(int fildes, int cmd, ...) +{ + HOOK_SYS_FUNC( fcntl ); + + if( fildes < 0 ) + { + return __LINE__; + } + + va_list arg_list; + va_start( arg_list,cmd ); + + int ret = -1; + rpchook_t *lp = get_by_fd( fildes ); + switch( cmd ) + { + case F_DUPFD: + { + int param = va_arg(arg_list,int); + ret = g_sys_fcntl_func( fildes,cmd,param ); + break; + } + case F_GETFD: + { + ret = g_sys_fcntl_func( fildes,cmd ); + if (lp && !(lp->user_flag & O_NONBLOCK)) { + ret = ret & (~O_NONBLOCK); + } + break; + } + case F_SETFD: + { + int param = va_arg(arg_list,int); + ret = g_sys_fcntl_func( fildes,cmd,param ); + break; + } + case F_GETFL: + { + ret = g_sys_fcntl_func( fildes,cmd ); + break; + } + case F_SETFL: + { + int param = va_arg(arg_list,int); + int flag = param; + if( co_is_enable_sys_hook() && lp ) + { + flag |= O_NONBLOCK; + } + ret = g_sys_fcntl_func( fildes,cmd,flag ); + if( 0 == ret && lp ) + { + lp->user_flag = param; + } + break; + } + case F_GETOWN: + { + ret = g_sys_fcntl_func( fildes,cmd ); + break; + } + case F_SETOWN: + { + int param = va_arg(arg_list,int); + ret = g_sys_fcntl_func( fildes,cmd,param ); + break; + } + case F_GETLK: + { + struct flock *param = va_arg(arg_list,struct flock *); + ret = g_sys_fcntl_func( fildes,cmd,param ); + break; + } + case F_SETLK: + { + struct flock *param = va_arg(arg_list,struct flock *); + ret = g_sys_fcntl_func( fildes,cmd,param ); + break; + } + case F_SETLKW: + { + struct flock *param = va_arg(arg_list,struct flock *); + ret = g_sys_fcntl_func( fildes,cmd,param ); + break; + } + } + + va_end( arg_list ); + + return ret; +} + +struct stCoSysEnv_t +{ + char *name; + char *value; +}; +struct stCoSysEnvArr_t +{ + stCoSysEnv_t *data; + size_t cnt; +}; +static stCoSysEnvArr_t *dup_co_sysenv_arr( stCoSysEnvArr_t * arr ) +{ + stCoSysEnvArr_t *lp = (stCoSysEnvArr_t*)calloc( sizeof(stCoSysEnvArr_t),1 ); + if( arr->cnt ) + { + lp->data = (stCoSysEnv_t*)calloc( sizeof(stCoSysEnv_t) * arr->cnt,1 ); + lp->cnt = arr->cnt; + memcpy( lp->data,arr->data,sizeof( stCoSysEnv_t ) * arr->cnt ); + } + return lp; +} + +static int co_sysenv_comp(const void *a, const void *b) +{ + return strcmp(((stCoSysEnv_t*)a)->name, ((stCoSysEnv_t*)b)->name); +} +static stCoSysEnvArr_t g_co_sysenv = { 0 }; + + + +void co_set_env_list( const char *name[],size_t cnt) +{ + if( g_co_sysenv.data ) + { + return ; + } + g_co_sysenv.data = (stCoSysEnv_t*)calloc( 1,sizeof(stCoSysEnv_t) * cnt ); + + for(size_t i=0;i 1 ) + { + qsort( g_co_sysenv.data,g_co_sysenv.cnt,sizeof(stCoSysEnv_t),co_sysenv_comp ); + stCoSysEnv_t *lp = g_co_sysenv.data; + stCoSysEnv_t *lq = g_co_sysenv.data + 1; + for(size_t i=1;iname,lq->name ) ) + { + ++lp; + if( lq != lp ) + { + *lp = *lq; + } + } + ++lq; + } + g_co_sysenv.cnt = lp - g_co_sysenv.data + 1; + } + +} + +int setenv(const char *n, const char *value, int overwrite) +{ + HOOK_SYS_FUNC( setenv ) + if( co_is_enable_sys_hook() && g_co_sysenv.data ) + { + stCoRoutine_t *self = co_self(); + if( self ) + { + if( !self->pvEnv ) + { + self->pvEnv = dup_co_sysenv_arr( &g_co_sysenv ); + } + stCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv); + + stCoSysEnv_t name = { (char*)n,0 }; + + stCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp ); + + if( e ) + { + if( overwrite || !e->value ) + { + if( e->value ) free( e->value ); + e->value = ( value ? strdup( value ) : 0 ); + } + return 0; + } + } + + } + return g_sys_setenv_func( n,value,overwrite ); +} +int unsetenv(const char *n) +{ + HOOK_SYS_FUNC( unsetenv ) + if( co_is_enable_sys_hook() && g_co_sysenv.data ) + { + stCoRoutine_t *self = co_self(); + if( self ) + { + if( !self->pvEnv ) + { + self->pvEnv = dup_co_sysenv_arr( &g_co_sysenv ); + } + stCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv); + + stCoSysEnv_t name = { (char*)n,0 }; + + stCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp ); + + if( e ) + { + if( e->value ) + { + free( e->value ); + e->value = 0; + } + return 0; + } + } + + } + return g_sys_unsetenv_func( n ); +} +char *getenv( const char *n ) +{ + HOOK_SYS_FUNC( getenv ) + if( co_is_enable_sys_hook() && g_co_sysenv.data ) + { + stCoRoutine_t *self = co_self(); + + stCoSysEnv_t name = { (char*)n,0 }; + + if( !self->pvEnv ) + { + self->pvEnv = dup_co_sysenv_arr( &g_co_sysenv ); + } + stCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv); + + stCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp ); + + if( e ) + { + return e->value; + } + + } + return g_sys_getenv_func( n ); + +} +struct hostent* co_gethostbyname(const char *name); + +struct hostent *gethostbyname(const char *name) +{ + HOOK_SYS_FUNC( gethostbyname ); + +#if defined( __APPLE__ ) || defined( __FreeBSD__ ) + return g_sys_gethostbyname_func( name ); +#else + if (!co_is_enable_sys_hook()) + { + return g_sys_gethostbyname_func(name); + } + return co_gethostbyname(name); +#endif + +} + + +struct res_state_wrap +{ + struct __res_state state; +}; +CO_ROUTINE_SPECIFIC(res_state_wrap, __co_state_wrap); + +extern "C" +{ + res_state __res_state() + { + HOOK_SYS_FUNC(__res_state); + + if (!co_is_enable_sys_hook()) + { + return g_sys___res_state_func(); + } + + return &(__co_state_wrap->state); + } + int __poll(struct pollfd fds[], nfds_t nfds, int timeout) + { + return poll(fds, nfds, timeout); + } +} + +struct hostbuf_wrap +{ + struct hostent host; + char* buffer; + size_t iBufferSize; + int host_errno; +}; + +CO_ROUTINE_SPECIFIC(hostbuf_wrap, __co_hostbuf_wrap); + +#if !defined( __APPLE__ ) && !defined( __FreeBSD__ ) +struct hostent *co_gethostbyname(const char *name) +{ + if (!name) + { + return NULL; + } + + if (__co_hostbuf_wrap->buffer && __co_hostbuf_wrap->iBufferSize > 1024) + { + free(__co_hostbuf_wrap->buffer); + __co_hostbuf_wrap->buffer = NULL; + } + if (!__co_hostbuf_wrap->buffer) + { + __co_hostbuf_wrap->buffer = (char*)malloc(1024); + __co_hostbuf_wrap->iBufferSize = 1024; + } + + struct hostent *host = &__co_hostbuf_wrap->host; + struct hostent *result = NULL; + int *h_errnop = &(__co_hostbuf_wrap->host_errno); + + int ret = -1; + while (ret = gethostbyname_r(name, host, __co_hostbuf_wrap->buffer, + __co_hostbuf_wrap->iBufferSize, &result, h_errnop) == ERANGE && + *h_errnop == NETDB_INTERNAL ) + { + free(__co_hostbuf_wrap->buffer); + __co_hostbuf_wrap->iBufferSize = __co_hostbuf_wrap->iBufferSize * 2; + __co_hostbuf_wrap->buffer = (char*)malloc(__co_hostbuf_wrap->iBufferSize); + } + + if (ret == 0 && (host == result)) + { + return host; + } + return NULL; +} +#endif + + +void co_enable_hook_sys() //这函数必须在这里,否则本文件会被忽略!!! +{ + stCoRoutine_t *co = GetCurrThreadCo(); + if( co ) + { + co->cEnableSysHook = 1; + } +} + diff --git a/trunk/3rdparty/libco/co_routine.cpp b/trunk/3rdparty/libco/co_routine.cpp new file mode 100644 index 0000000000..352ae7ea0b --- /dev/null +++ b/trunk/3rdparty/libco/co_routine.cpp @@ -0,0 +1,1196 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "co_routine.h" +#include "co_routine_inner.h" +#include "co_epoll.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +extern "C" +{ + extern void coctx_swap( coctx_t *,coctx_t* ) asm("coctx_swap"); +}; +using namespace std; +stCoRoutine_t *GetCurrCo( stCoRoutineEnv_t *env ); +struct stCoEpoll_t; + +struct stCoRoutineEnv_t +{ + stCoRoutine_t *pCallStack[ 128 ]; + int iCallStackSize; + stCoEpoll_t *pEpoll; + + //for copy stack log lastco and nextco + stCoRoutine_t* pending_co; + stCoRoutine_t* occupy_co; +}; +//int socket(int domain, int type, int protocol); +void co_log_err( const char *fmt,... ) +{ +} + + +#if defined( __LIBCO_RDTSCP__) +static unsigned long long counter(void) +{ + register uint32_t lo, hi; + register unsigned long long o; + __asm__ __volatile__ ( + "rdtscp" : "=a"(lo), "=d"(hi)::"%rcx" + ); + o = hi; + o <<= 32; + return (o | lo); + +} +static unsigned long long getCpuKhz() +{ + FILE *fp = fopen("/proc/cpuinfo","r"); + if(!fp) return 1; + char buf[4096] = {0}; + fread(buf,1,sizeof(buf),fp); + fclose(fp); + + char *lp = strstr(buf,"cpu MHz"); + if(!lp) return 1; + lp += strlen("cpu MHz"); + while(*lp == ' ' || *lp == '\t' || *lp == ':') + { + ++lp; + } + + double mhz = atof(lp); + unsigned long long u = (unsigned long long)(mhz * 1000); + return u; +} +#endif + +static unsigned long long GetTickMS() +{ +#if defined( __LIBCO_RDTSCP__) + static uint32_t khz = getCpuKhz(); + return counter() / khz; +#else + struct timeval now = { 0 }; + gettimeofday( &now,NULL ); + unsigned long long u = now.tv_sec; + u *= 1000; + u += now.tv_usec / 1000; + return u; +#endif +} + +/* no longer use +static pid_t GetPid() +{ + static __thread pid_t pid = 0; + static __thread pid_t tid = 0; + if( !pid || !tid || pid != getpid() ) + { + pid = getpid(); +#if defined( __APPLE__ ) + tid = syscall( SYS_gettid ); + if( -1 == (long)tid ) + { + tid = pid; + } +#elif defined( __FreeBSD__ ) + syscall(SYS_thr_self, &tid); + if( tid < 0 ) + { + tid = pid; + } +#else + tid = syscall( __NR_gettid ); +#endif + + } + return tid; + +} +static pid_t GetPid() +{ + char **p = (char**)pthread_self(); + return p ? *(pid_t*)(p + 18) : getpid(); +} +*/ +template +void RemoveFromLink(T *ap) +{ + TLink *lst = ap->pLink; + if(!lst) return ; + assert( lst->head && lst->tail ); + + if( ap == lst->head ) + { + lst->head = ap->pNext; + if(lst->head) + { + lst->head->pPrev = NULL; + } + } + else + { + if(ap->pPrev) + { + ap->pPrev->pNext = ap->pNext; + } + } + + if( ap == lst->tail ) + { + lst->tail = ap->pPrev; + if(lst->tail) + { + lst->tail->pNext = NULL; + } + } + else + { + ap->pNext->pPrev = ap->pPrev; + } + + ap->pPrev = ap->pNext = NULL; + ap->pLink = NULL; +} + +template +void inline AddTail(TLink*apLink,TNode *ap) +{ + if( ap->pLink ) + { + return ; + } + if(apLink->tail) + { + apLink->tail->pNext = (TNode*)ap; + ap->pNext = NULL; + ap->pPrev = apLink->tail; + apLink->tail = ap; + } + else + { + apLink->head = apLink->tail = ap; + ap->pNext = ap->pPrev = NULL; + } + ap->pLink = apLink; +} +template +void inline PopHead( TLink*apLink ) +{ + if( !apLink->head ) + { + return ; + } + TNode *lp = apLink->head; + if( apLink->head == apLink->tail ) + { + apLink->head = apLink->tail = NULL; + } + else + { + apLink->head = apLink->head->pNext; + } + + lp->pPrev = lp->pNext = NULL; + lp->pLink = NULL; + + if( apLink->head ) + { + apLink->head->pPrev = NULL; + } +} + +template +void inline Join( TLink*apLink,TLink *apOther ) +{ + //printf("apOther %p\n",apOther); + if( !apOther->head ) + { + return ; + } + TNode *lp = apOther->head; + while( lp ) + { + lp->pLink = apLink; + lp = lp->pNext; + } + lp = apOther->head; + if(apLink->tail) + { + apLink->tail->pNext = (TNode*)lp; + lp->pPrev = apLink->tail; + apLink->tail = apOther->tail; + } + else + { + apLink->head = apOther->head; + apLink->tail = apOther->tail; + } + + apOther->head = apOther->tail = NULL; +} + +/////////////////for copy stack ////////////////////////// +stStackMem_t* co_alloc_stackmem(unsigned int stack_size) +{ + stStackMem_t* stack_mem = (stStackMem_t*)malloc(sizeof(stStackMem_t)); + stack_mem->occupy_co= NULL; + stack_mem->stack_size = stack_size; + stack_mem->stack_buffer = (char*)malloc(stack_size); + stack_mem->stack_bp = stack_mem->stack_buffer + stack_size; + return stack_mem; +} + +stShareStack_t* co_alloc_sharestack(int count, int stack_size) +{ + stShareStack_t* share_stack = (stShareStack_t*)malloc(sizeof(stShareStack_t)); + share_stack->alloc_idx = 0; + share_stack->stack_size = stack_size; + + //alloc stack array + share_stack->count = count; + stStackMem_t** stack_array = (stStackMem_t**)calloc(count, sizeof(stStackMem_t*)); + for (int i = 0; i < count; i++) + { + stack_array[i] = co_alloc_stackmem(stack_size); + } + share_stack->stack_array = stack_array; + return share_stack; +} + +static stStackMem_t* co_get_stackmem(stShareStack_t* share_stack) +{ + if (!share_stack) + { + return NULL; + } + int idx = share_stack->alloc_idx % share_stack->count; + share_stack->alloc_idx++; + + return share_stack->stack_array[idx]; +} + + +// ---------------------------------------------------------------------------- +struct stTimeoutItemLink_t; +struct stTimeoutItem_t; +struct stCoEpoll_t +{ + int iEpollFd; + static const int _EPOLL_SIZE = 1024 * 10; + + struct stTimeout_t *pTimeout; + + struct stTimeoutItemLink_t *pstTimeoutList; + + struct stTimeoutItemLink_t *pstActiveList; + + co_epoll_res *result; + +}; +typedef void (*OnPreparePfn_t)( stTimeoutItem_t *,struct epoll_event &ev, stTimeoutItemLink_t *active ); +typedef void (*OnProcessPfn_t)( stTimeoutItem_t *); +struct stTimeoutItem_t +{ + + enum + { + eMaxTimeout = 40 * 1000 //40s + }; + stTimeoutItem_t *pPrev; + stTimeoutItem_t *pNext; + stTimeoutItemLink_t *pLink; + + unsigned long long ullExpireTime; + + OnPreparePfn_t pfnPrepare; + OnProcessPfn_t pfnProcess; + + void *pArg; // routine + bool bTimeout; +}; +struct stTimeoutItemLink_t +{ + stTimeoutItem_t *head; + stTimeoutItem_t *tail; + +}; +struct stTimeout_t +{ + stTimeoutItemLink_t *pItems; + int iItemSize; + + unsigned long long ullStart; + long long llStartIdx; +}; +stTimeout_t *AllocTimeout( int iSize ) +{ + stTimeout_t *lp = (stTimeout_t*)calloc( 1,sizeof(stTimeout_t) ); + + lp->iItemSize = iSize; + lp->pItems = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) * lp->iItemSize ); + + lp->ullStart = GetTickMS(); + lp->llStartIdx = 0; + + return lp; +} +void FreeTimeout( stTimeout_t *apTimeout ) +{ + free( apTimeout->pItems ); + free ( apTimeout ); +} +int AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,unsigned long long allNow ) +{ + if( apTimeout->ullStart == 0 ) + { + apTimeout->ullStart = allNow; + apTimeout->llStartIdx = 0; + } + if( allNow < apTimeout->ullStart ) + { + co_log_err("CO_ERR: AddTimeout line %d allNow %llu apTimeout->ullStart %llu", + __LINE__,allNow,apTimeout->ullStart); + + return __LINE__; + } + if( apItem->ullExpireTime < allNow ) + { + co_log_err("CO_ERR: AddTimeout line %d apItem->ullExpireTime %llu allNow %llu apTimeout->ullStart %llu", + __LINE__,apItem->ullExpireTime,allNow,apTimeout->ullStart); + + return __LINE__; + } + unsigned long long diff = apItem->ullExpireTime - apTimeout->ullStart; + + if( diff >= (unsigned long long)apTimeout->iItemSize ) + { + diff = apTimeout->iItemSize - 1; + co_log_err("CO_ERR: AddTimeout line %d diff %d", + __LINE__,diff); + + //return __LINE__; + } + AddTail( apTimeout->pItems + ( apTimeout->llStartIdx + diff ) % apTimeout->iItemSize , apItem ); + + return 0; +} +inline void TakeAllTimeout( stTimeout_t *apTimeout,unsigned long long allNow,stTimeoutItemLink_t *apResult ) +{ + if( apTimeout->ullStart == 0 ) + { + apTimeout->ullStart = allNow; + apTimeout->llStartIdx = 0; + } + + if( allNow < apTimeout->ullStart ) + { + return ; + } + int cnt = allNow - apTimeout->ullStart + 1; + if( cnt > apTimeout->iItemSize ) + { + cnt = apTimeout->iItemSize; + } + if( cnt < 0 ) + { + return; + } + for( int i = 0;illStartIdx + i) % apTimeout->iItemSize; + Join( apResult,apTimeout->pItems + idx ); + } + apTimeout->ullStart = allNow; + apTimeout->llStartIdx += cnt - 1; + + +} +static int CoRoutineFunc( stCoRoutine_t *co,void * ) +{ + if( co->pfn ) + { + co->pfn( co->arg ); + } + co->cEnd = 1; + + stCoRoutineEnv_t *env = co->env; + + co_yield_env( env ); + + return 0; +} + + + +struct stCoRoutine_t *co_create_env( stCoRoutineEnv_t * env, const stCoRoutineAttr_t* attr, + pfn_co_routine_t pfn,void *arg ) +{ + + stCoRoutineAttr_t at; + if( attr ) + { + memcpy( &at,attr,sizeof(at) ); + } + if( at.stack_size <= 0 ) + { + at.stack_size = 128 * 1024; + } + else if( at.stack_size > 1024 * 1024 * 8 ) + { + at.stack_size = 1024 * 1024 * 8; + } + + if( at.stack_size & 0xFFF ) + { + at.stack_size &= ~0xFFF; + at.stack_size += 0x1000; + } + + stCoRoutine_t *lp = (stCoRoutine_t*)malloc( sizeof(stCoRoutine_t) ); + + memset( lp,0,(long)(sizeof(stCoRoutine_t))); + + + lp->env = env; + lp->pfn = pfn; + lp->arg = arg; + + stStackMem_t* stack_mem = NULL; + if( at.share_stack ) + { + stack_mem = co_get_stackmem( at.share_stack); + at.stack_size = at.share_stack->stack_size; + } + else + { + stack_mem = co_alloc_stackmem(at.stack_size); + } + lp->stack_mem = stack_mem; + + lp->ctx.ss_sp = stack_mem->stack_buffer; + lp->ctx.ss_size = at.stack_size; + + lp->cStart = 0; + lp->cEnd = 0; + lp->cIsMain = 0; + lp->cEnableSysHook = 0; + lp->cIsShareStack = at.share_stack != NULL; + + lp->save_size = 0; + lp->save_buffer = NULL; + + return lp; +} + +int co_create( stCoRoutine_t **ppco,const stCoRoutineAttr_t *attr,pfn_co_routine_t pfn,void *arg ) +{ + if( !co_get_curr_thread_env() ) + { + co_init_curr_thread_env(); + } + stCoRoutine_t *co = co_create_env( co_get_curr_thread_env(), attr, pfn,arg ); + *ppco = co; + return 0; +} +void co_free( stCoRoutine_t *co ) +{ + if (!co->cIsShareStack) + { + free(co->stack_mem->stack_buffer); + free(co->stack_mem); + } + //walkerdu fix at 2018-01-20 + //瀛樺湪鍐呭瓨娉勬紡 + else + { + if(co->save_buffer) + free(co->save_buffer); + + if(co->stack_mem->occupy_co == co) + co->stack_mem->occupy_co = NULL; + } + + free( co ); +} +void co_release( stCoRoutine_t *co ) +{ + co_free( co ); +} + +void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co); + +void co_resume( stCoRoutine_t *co ) +{ + stCoRoutineEnv_t *env = co->env; + stCoRoutine_t *lpCurrRoutine = env->pCallStack[ env->iCallStackSize - 1 ]; + if( !co->cStart ) + { + coctx_make( &co->ctx,(coctx_pfn_t)CoRoutineFunc,co,0 ); + co->cStart = 1; + } + env->pCallStack[ env->iCallStackSize++ ] = co; + co_swap( lpCurrRoutine, co ); + + +} + + +// walkerdu 2018-01-14 +// 鐢ㄤ簬reset瓒呮椂鏃犳硶閲嶅浣跨敤鐨勫崗绋 +void co_reset(stCoRoutine_t * co) +{ + if(!co->cStart || co->cIsMain) + return; + + co->cStart = 0; + co->cEnd = 0; + + // 濡傛灉褰撳墠鍗忕▼鏈夊叡浜爤琚垏鍑虹殑buff锛岃杩涜閲婃斁 + if(co->save_buffer) + { + free(co->save_buffer); + co->save_buffer = NULL; + co->save_size = 0; + } + + // 濡傛灉鍏变韩鏍堣褰撳墠鍗忕▼鍗犵敤锛岃閲婃斁鍗犵敤鏍囧織锛屽惁鍒欒鍒囨崲锛屼細鎵цsave_stack_buffer() + if(co->stack_mem->occupy_co == co) + co->stack_mem->occupy_co = NULL; +} + +void co_yield_env( stCoRoutineEnv_t *env ) +{ + + stCoRoutine_t *last = env->pCallStack[ env->iCallStackSize - 2 ]; + stCoRoutine_t *curr = env->pCallStack[ env->iCallStackSize - 1 ]; + + env->iCallStackSize--; + + co_swap( curr, last); +} + +void co_yield_ct() +{ + + co_yield_env( co_get_curr_thread_env() ); +} +void co_yield( stCoRoutine_t *co ) +{ + co_yield_env( co->env ); +} + +void save_stack_buffer(stCoRoutine_t* occupy_co) +{ + ///copy out + stStackMem_t* stack_mem = occupy_co->stack_mem; + int len = stack_mem->stack_bp - occupy_co->stack_sp; + + if (occupy_co->save_buffer) + { + free(occupy_co->save_buffer), occupy_co->save_buffer = NULL; + } + + occupy_co->save_buffer = (char*)malloc(len); //malloc buf; + occupy_co->save_size = len; + + memcpy(occupy_co->save_buffer, occupy_co->stack_sp, len); +} + +void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co) +{ + stCoRoutineEnv_t* env = co_get_curr_thread_env(); + + //get curr stack sp + char c; + curr->stack_sp= &c; + + if (!pending_co->cIsShareStack) + { + env->pending_co = NULL; + env->occupy_co = NULL; + } + else + { + env->pending_co = pending_co; + //get last occupy co on the same stack mem + stCoRoutine_t* occupy_co = pending_co->stack_mem->occupy_co; + //set pending co to occupy thest stack mem; + pending_co->stack_mem->occupy_co = pending_co; + + env->occupy_co = occupy_co; + if (occupy_co && occupy_co != pending_co) + { + save_stack_buffer(occupy_co); + } + } + + //swap context + coctx_swap(&(curr->ctx),&(pending_co->ctx) ); + + //stack buffer may be overwrite, so get again; + stCoRoutineEnv_t* curr_env = co_get_curr_thread_env(); + stCoRoutine_t* update_occupy_co = curr_env->occupy_co; + stCoRoutine_t* update_pending_co = curr_env->pending_co; + + if (update_occupy_co && update_pending_co && update_occupy_co != update_pending_co) + { + //resume stack buffer + if (update_pending_co->save_buffer && update_pending_co->save_size > 0) + { + memcpy(update_pending_co->stack_sp, update_pending_co->save_buffer, update_pending_co->save_size); + } + } +} + + + +//int poll(struct pollfd fds[], nfds_t nfds, int timeout); +// { fd,events,revents } +struct stPollItem_t ; +struct stPoll_t : public stTimeoutItem_t +{ + struct pollfd *fds; + nfds_t nfds; // typedef unsigned long int nfds_t; + + stPollItem_t *pPollItems; + + int iAllEventDetach; + + int iEpollFd; + + int iRaiseCnt; + + +}; +struct stPollItem_t : public stTimeoutItem_t +{ + struct pollfd *pSelf; + stPoll_t *pPoll; + + struct epoll_event stEvent; +}; +/* + * EPOLLPRI POLLPRI // There is urgent data to read. + * EPOLLMSG POLLMSG + * + * POLLREMOVE + * POLLRDHUP + * POLLNVAL + * + * */ +static uint32_t PollEvent2Epoll( short events ) +{ + uint32_t e = 0; + if( events & POLLIN ) e |= EPOLLIN; + if( events & POLLOUT ) e |= EPOLLOUT; + if( events & POLLHUP ) e |= EPOLLHUP; + if( events & POLLERR ) e |= EPOLLERR; + if( events & POLLRDNORM ) e |= EPOLLRDNORM; + if( events & POLLWRNORM ) e |= EPOLLWRNORM; + return e; +} +static short EpollEvent2Poll( uint32_t events ) +{ + short e = 0; + if( events & EPOLLIN ) e |= POLLIN; + if( events & EPOLLOUT ) e |= POLLOUT; + if( events & EPOLLHUP ) e |= POLLHUP; + if( events & EPOLLERR ) e |= POLLERR; + if( events & EPOLLRDNORM ) e |= POLLRDNORM; + if( events & EPOLLWRNORM ) e |= POLLWRNORM; + return e; +} + +static __thread stCoRoutineEnv_t* gCoEnvPerThread = NULL; + +void co_init_curr_thread_env() +{ + gCoEnvPerThread = (stCoRoutineEnv_t*)calloc( 1, sizeof(stCoRoutineEnv_t) ); + stCoRoutineEnv_t *env = gCoEnvPerThread; + + env->iCallStackSize = 0; + struct stCoRoutine_t *self = co_create_env( env, NULL, NULL,NULL ); + self->cIsMain = 1; + + env->pending_co = NULL; + env->occupy_co = NULL; + + coctx_init( &self->ctx ); + + env->pCallStack[ env->iCallStackSize++ ] = self; + + stCoEpoll_t *ev = AllocEpoll(); + SetEpoll( env,ev ); +} +stCoRoutineEnv_t *co_get_curr_thread_env() +{ + return gCoEnvPerThread; +} + +void OnPollProcessEvent( stTimeoutItem_t * ap ) +{ + stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; + co_resume( co ); +} + +void OnPollPreparePfn( stTimeoutItem_t * ap,struct epoll_event &e,stTimeoutItemLink_t *active ) +{ + stPollItem_t *lp = (stPollItem_t *)ap; + lp->pSelf->revents = EpollEvent2Poll( e.events ); + + + stPoll_t *pPoll = lp->pPoll; + pPoll->iRaiseCnt++; + + if( !pPoll->iAllEventDetach ) + { + pPoll->iAllEventDetach = 1; + + RemoveFromLink( pPoll ); + + AddTail( active,pPoll ); + + } +} + + +void co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg ) +{ + if( !ctx->result ) + { + ctx->result = co_epoll_res_alloc( stCoEpoll_t::_EPOLL_SIZE ); + } + co_epoll_res *result = ctx->result; + + + for(;;) + { + int ret = co_epoll_wait( ctx->iEpollFd,result,stCoEpoll_t::_EPOLL_SIZE, 1 ); + + stTimeoutItemLink_t *active = (ctx->pstActiveList); + stTimeoutItemLink_t *timeout = (ctx->pstTimeoutList); + + memset( timeout,0,sizeof(stTimeoutItemLink_t) ); + + for(int i=0;ievents[i].data.ptr; + if( item->pfnPrepare ) + { + item->pfnPrepare( item,result->events[i],active ); + } + else + { + AddTail( active,item ); + } + } + + + unsigned long long now = GetTickMS(); + TakeAllTimeout( ctx->pTimeout,now,timeout ); + + stTimeoutItem_t *lp = timeout->head; + while( lp ) + { + //printf("raise timeout %p\n",lp); + lp->bTimeout = true; + lp = lp->pNext; + } + + Join( active,timeout ); + + lp = active->head; + while( lp ) + { + + PopHead( active ); + if (lp->bTimeout && now < lp->ullExpireTime) + { + int ret = AddTimeout(ctx->pTimeout, lp, now); + if (!ret) + { + lp->bTimeout = false; + lp = active->head; + continue; + } + } + if( lp->pfnProcess ) + { + lp->pfnProcess( lp ); + } + + lp = active->head; + } + if( pfn ) + { + if( -1 == pfn( arg ) ) + { + break; + } + } + + } +} +void OnCoroutineEvent( stTimeoutItem_t * ap ) +{ + stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; + co_resume( co ); +} + + +stCoEpoll_t *AllocEpoll() +{ + stCoEpoll_t *ctx = (stCoEpoll_t*)calloc( 1,sizeof(stCoEpoll_t) ); + + ctx->iEpollFd = co_epoll_create( stCoEpoll_t::_EPOLL_SIZE ); + ctx->pTimeout = AllocTimeout( 60 * 1000 ); + + ctx->pstActiveList = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) ); + ctx->pstTimeoutList = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) ); + + + return ctx; +} + +void FreeEpoll( stCoEpoll_t *ctx ) +{ + if( ctx ) + { + free( ctx->pstActiveList ); + free( ctx->pstTimeoutList ); + FreeTimeout( ctx->pTimeout ); + co_epoll_res_free( ctx->result ); + } + free( ctx ); +} + +stCoRoutine_t *GetCurrCo( stCoRoutineEnv_t *env ) +{ + return env->pCallStack[ env->iCallStackSize - 1 ]; +} +stCoRoutine_t *GetCurrThreadCo( ) +{ + stCoRoutineEnv_t *env = co_get_curr_thread_env(); + if( !env ) return 0; + return GetCurrCo(env); +} + + + +typedef int (*poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout); +int co_poll_inner( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout, poll_pfn_t pollfunc) +{ + if (timeout == 0) + { + return pollfunc(fds, nfds, timeout); + } + if (timeout < 0) + { + timeout = INT_MAX; + } + int epfd = ctx->iEpollFd; + stCoRoutine_t* self = co_self(); + + //1.struct change + stPoll_t& arg = *((stPoll_t*)malloc(sizeof(stPoll_t))); + memset( &arg,0,sizeof(arg) ); + + arg.iEpollFd = epfd; + arg.fds = (pollfd*)calloc(nfds, sizeof(pollfd)); + arg.nfds = nfds; + + stPollItem_t arr[2]; + if( nfds < sizeof(arr) / sizeof(arr[0]) && !self->cIsShareStack) + { + arg.pPollItems = arr; + } + else + { + arg.pPollItems = (stPollItem_t*)malloc( nfds * sizeof( stPollItem_t ) ); + } + memset( arg.pPollItems,0,nfds * sizeof(stPollItem_t) ); + + arg.pfnProcess = OnPollProcessEvent; + arg.pArg = GetCurrCo( co_get_curr_thread_env() ); + + + //2. add epoll + for(nfds_t i=0;i -1 ) + { + ev.data.ptr = arg.pPollItems + i; + ev.events = PollEvent2Epoll( fds[i].events ); + + int ret = co_epoll_ctl( epfd,EPOLL_CTL_ADD, fds[i].fd, &ev ); + if (ret < 0 && errno == EPERM && nfds == 1 && pollfunc != NULL) + { + if( arg.pPollItems != arr ) + { + free( arg.pPollItems ); + arg.pPollItems = NULL; + } + free(arg.fds); + free(&arg); + return pollfunc(fds, nfds, timeout); + } + } + //if fail,the timeout would work + } + + //3.add timeout + + unsigned long long now = GetTickMS(); + arg.ullExpireTime = now + timeout; + int ret = AddTimeout( ctx->pTimeout,&arg,now ); + int iRaiseCnt = 0; + if( ret != 0 ) + { + co_log_err("CO_ERR: AddTimeout ret %d now %lld timeout %d arg.ullExpireTime %lld", + ret,now,timeout,arg.ullExpireTime); + errno = EINVAL; + iRaiseCnt = -1; + + } + else + { + co_yield_env( co_get_curr_thread_env() ); + iRaiseCnt = arg.iRaiseCnt; + } + + { + //clear epoll status and memory + RemoveFromLink( &arg ); + for(nfds_t i = 0;i < nfds;i++) + { + int fd = fds[i].fd; + if( fd > -1 ) + { + co_epoll_ctl( epfd,EPOLL_CTL_DEL,fd,&arg.pPollItems[i].stEvent ); + } + fds[i].revents = arg.fds[i].revents; + } + + + if( arg.pPollItems != arr ) + { + free( arg.pPollItems ); + arg.pPollItems = NULL; + } + + free(arg.fds); + free(&arg); + } + + return iRaiseCnt; +} + +int co_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms ) +{ + return co_poll_inner(ctx, fds, nfds, timeout_ms, NULL); +} + +void SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev ) +{ + env->pEpoll = ev; +} +stCoEpoll_t *co_get_epoll_ct() +{ + if( !co_get_curr_thread_env() ) + { + co_init_curr_thread_env(); + } + return co_get_curr_thread_env()->pEpoll; +} +struct stHookPThreadSpec_t +{ + stCoRoutine_t *co; + void *value; + + enum + { + size = 1024 + }; +}; +void *co_getspecific(pthread_key_t key) +{ + stCoRoutine_t *co = GetCurrThreadCo(); + if( !co || co->cIsMain ) + { + return pthread_getspecific( key ); + } + return co->aSpec[ key ].value; +} +int co_setspecific(pthread_key_t key, const void *value) +{ + stCoRoutine_t *co = GetCurrThreadCo(); + if( !co || co->cIsMain ) + { + return pthread_setspecific( key,value ); + } + co->aSpec[ key ].value = (void*)value; + return 0; +} + + + +void co_disable_hook_sys() +{ + stCoRoutine_t *co = GetCurrThreadCo(); + if( co ) + { + co->cEnableSysHook = 0; + } +} +bool co_is_enable_sys_hook() +{ + stCoRoutine_t *co = GetCurrThreadCo(); + return ( co && co->cEnableSysHook ); +} + +stCoRoutine_t *co_self() +{ + return GetCurrThreadCo(); +} + +//co cond +struct stCoCond_t; +struct stCoCondItem_t +{ + stCoCondItem_t *pPrev; + stCoCondItem_t *pNext; + stCoCond_t *pLink; + + stTimeoutItem_t timeout; +}; +struct stCoCond_t +{ + stCoCondItem_t *head; + stCoCondItem_t *tail; +}; +static void OnSignalProcessEvent( stTimeoutItem_t * ap ) +{ + stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; + co_resume( co ); +} + +stCoCondItem_t *co_cond_pop( stCoCond_t *link ); +int co_cond_signal( stCoCond_t *si ) +{ + stCoCondItem_t * sp = co_cond_pop( si ); + if( !sp ) + { + return 0; + } + RemoveFromLink( &sp->timeout ); + + AddTail( co_get_curr_thread_env()->pEpoll->pstActiveList,&sp->timeout ); + + return 0; +} +int co_cond_broadcast( stCoCond_t *si ) +{ + for(;;) + { + stCoCondItem_t * sp = co_cond_pop( si ); + if( !sp ) return 0; + + RemoveFromLink( &sp->timeout ); + + AddTail( co_get_curr_thread_env()->pEpoll->pstActiveList,&sp->timeout ); + } + + return 0; +} + + +int co_cond_timedwait( stCoCond_t *link,int ms ) +{ + stCoCondItem_t* psi = (stCoCondItem_t*)calloc(1, sizeof(stCoCondItem_t)); + psi->timeout.pArg = GetCurrThreadCo(); + psi->timeout.pfnProcess = OnSignalProcessEvent; + + if( ms > 0 ) + { + unsigned long long now = GetTickMS(); + psi->timeout.ullExpireTime = now + ms; + + int ret = AddTimeout( co_get_curr_thread_env()->pEpoll->pTimeout,&psi->timeout,now ); + if( ret != 0 ) + { + free(psi); + return ret; + } + } + AddTail( link, psi); + + co_yield_ct(); + + + RemoveFromLink( psi ); + free(psi); + + return 0; +} +stCoCond_t *co_cond_alloc() +{ + return (stCoCond_t*)calloc( 1,sizeof(stCoCond_t) ); +} +int co_cond_free( stCoCond_t * cc ) +{ + free( cc ); + return 0; +} + + +stCoCondItem_t *co_cond_pop( stCoCond_t *link ) +{ + stCoCondItem_t *p = link->head; + if( p ) + { + PopHead( link ); + } + return p; +} diff --git a/trunk/3rdparty/libco/co_routine.h b/trunk/3rdparty/libco/co_routine.h new file mode 100644 index 0000000000..d6f478928a --- /dev/null +++ b/trunk/3rdparty/libco/co_routine.h @@ -0,0 +1,93 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __CO_ROUTINE_H__ +#define __CO_ROUTINE_H__ + +#include +#include +#include + +//1.struct + +struct stCoRoutine_t; +struct stShareStack_t; + +struct stCoRoutineAttr_t +{ + int stack_size; + stShareStack_t* share_stack; + stCoRoutineAttr_t() + { + stack_size = 128 * 1024; + share_stack = NULL; + } +}__attribute__ ((packed)); + +struct stCoEpoll_t; +typedef int (*pfn_co_eventloop_t)(void *); +typedef void *(*pfn_co_routine_t)( void * ); + +//2.co_routine + +int co_create( stCoRoutine_t **co,const stCoRoutineAttr_t *attr,void *(*routine)(void*),void *arg ); +void co_resume( stCoRoutine_t *co ); +void co_yield( stCoRoutine_t *co ); +void co_yield_ct(); //ct = current thread +void co_release( stCoRoutine_t *co ); +void co_reset(stCoRoutine_t * co); + +stCoRoutine_t *co_self(); + +int co_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms ); +void co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg ); + +//3.specific + +int co_setspecific( pthread_key_t key, const void *value ); +void * co_getspecific( pthread_key_t key ); + +//4.event + +stCoEpoll_t * co_get_epoll_ct(); //ct = current thread + +//5.hook syscall ( poll/read/write/recv/send/recvfrom/sendto ) + +void co_enable_hook_sys(); +void co_disable_hook_sys(); +bool co_is_enable_sys_hook(); + +//6.sync +struct stCoCond_t; + +stCoCond_t *co_cond_alloc(); +int co_cond_free( stCoCond_t * cc ); + +int co_cond_signal( stCoCond_t * ); +int co_cond_broadcast( stCoCond_t * ); +int co_cond_timedwait( stCoCond_t *,int timeout_ms ); + +//7.share stack +stShareStack_t* co_alloc_sharestack(int iCount, int iStackSize); + +//8.init envlist for hook get/set env +void co_set_env_list( const char *name[],size_t cnt); + +void co_log_err( const char *fmt,... ); +#endif + diff --git a/trunk/3rdparty/libco/co_routine_inner.h b/trunk/3rdparty/libco/co_routine_inner.h new file mode 100644 index 0000000000..9d0e092de2 --- /dev/null +++ b/trunk/3rdparty/libco/co_routine_inner.h @@ -0,0 +1,111 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +#ifndef __CO_ROUTINE_INNER_H__ + +#include "co_routine.h" +#include "coctx.h" +struct stCoRoutineEnv_t; +struct stCoSpec_t +{ + void *value; +}; + +struct stStackMem_t +{ + stCoRoutine_t* occupy_co; + int stack_size; + char* stack_bp; //stack_buffer + stack_size + char* stack_buffer; + +}; + +struct stShareStack_t +{ + unsigned int alloc_idx; + int stack_size; + int count; + stStackMem_t** stack_array; +}; + + + +struct stCoRoutine_t +{ + stCoRoutineEnv_t *env; + pfn_co_routine_t pfn; + void *arg; + coctx_t ctx; + + char cStart; + char cEnd; + char cIsMain; + char cEnableSysHook; + char cIsShareStack; + + void *pvEnv; + + //char sRunStack[ 1024 * 128 ]; + stStackMem_t* stack_mem; + + + //save satck buffer while confilct on same stack_buffer; + char* stack_sp; + unsigned int save_size; + char* save_buffer; + + stCoSpec_t aSpec[1024]; + +}; + + + +//1.env +void co_init_curr_thread_env(); +stCoRoutineEnv_t * co_get_curr_thread_env(); + +//2.coroutine +void co_free( stCoRoutine_t * co ); +void co_yield_env( stCoRoutineEnv_t *env ); + +//3.func + + + +//----------------------------------------------------------------------------------------------- + +struct stTimeout_t; +struct stTimeoutItem_t ; + +stTimeout_t *AllocTimeout( int iSize ); +void FreeTimeout( stTimeout_t *apTimeout ); +int AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,uint64_t allNow ); + +struct stCoEpoll_t; +stCoEpoll_t * AllocEpoll(); +void FreeEpoll( stCoEpoll_t *ctx ); + +stCoRoutine_t * GetCurrThreadCo(); +void SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev ); + +typedef void (*pfnCoRoutineFunc_t)(); + +#endif + +#define __CO_ROUTINE_INNER_H__ diff --git a/trunk/3rdparty/libco/co_routine_specific.h b/trunk/3rdparty/libco/co_routine_specific.h new file mode 100644 index 0000000000..1b451caa52 --- /dev/null +++ b/trunk/3rdparty/libco/co_routine_specific.h @@ -0,0 +1,86 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once +#include +#include + +/* +invoke only once in the whole program +CoRoutineSetSpecificCallBack(CoRoutineGetSpecificFunc_t pfnGet,CoRoutineSetSpecificFunc_t pfnSet) + +struct MyData_t +{ + int iValue; + char szValue[100]; +}; +CO_ROUTINE_SPECIFIC( MyData_t,__routine ); + +int main() +{ + CoRoutineSetSpecificCallBack( co_getspecific,co_setspecific ); + + __routine->iValue = 10; + strcpy( __routine->szValue,"hello world" ); + + return 0; +} +*/ +extern int co_setspecific( pthread_key_t key, const void *value ); +extern void * co_getspecific( pthread_key_t key ); + +#define CO_ROUTINE_SPECIFIC( name,y ) \ +\ +static pthread_once_t _routine_once_##name = PTHREAD_ONCE_INIT; \ +static pthread_key_t _routine_key_##name;\ +static int _routine_init_##name = 0;\ +static void _routine_make_key_##name() \ +{\ + (void) pthread_key_create(&_routine_key_##name, NULL); \ +}\ +template \ +class clsRoutineData_routine_##name\ +{\ +public:\ + inline T *operator->()\ + {\ + if( !_routine_init_##name ) \ + {\ + pthread_once( &_routine_once_##name,_routine_make_key_##name );\ + _routine_init_##name = 1;\ + }\ + T* p = (T*)co_getspecific( _routine_key_##name );\ + if( !p )\ + {\ + p = (T*)calloc(1,sizeof( T ));\ + int ret = co_setspecific( _routine_key_##name,p) ;\ + if ( ret )\ + {\ + if ( p )\ + {\ + free(p);\ + p = NULL;\ + }\ + }\ + }\ + return p;\ + }\ +};\ +\ +static clsRoutineData_routine_##name y; + diff --git a/trunk/3rdparty/libco/coctx.cpp b/trunk/3rdparty/libco/coctx.cpp new file mode 100644 index 0000000000..d5eeed1486 --- /dev/null +++ b/trunk/3rdparty/libco/coctx.cpp @@ -0,0 +1,132 @@ +/* +* Tencent is pleased to support the open source community by making Libco +available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "coctx.h" +#include +#include + +#define ESP 0 +#define EIP 1 +#define EAX 2 +#define ECX 3 +// ----------- +#define RSP 0 +#define RIP 1 +#define RBX 2 +#define RDI 3 +#define RSI 4 + +#define RBP 5 +#define R12 6 +#define R13 7 +#define R14 8 +#define R15 9 +#define RDX 10 +#define RCX 11 +#define R8 12 +#define R9 13 + +//----- -------- +// 32 bit +// | regs[0]: ret | +// | regs[1]: ebx | +// | regs[2]: ecx | +// | regs[3]: edx | +// | regs[4]: edi | +// | regs[5]: esi | +// | regs[6]: ebp | +// | regs[7]: eax | = esp +enum { + kEIP = 0, + kEBP = 6, + kESP = 7, +}; + +//------------- +// 64 bit +// low | regs[0]: r15 | +// | regs[1]: r14 | +// | regs[2]: r13 | +// | regs[3]: r12 | +// | regs[4]: r9 | +// | regs[5]: r8 | +// | regs[6]: rbp | +// | regs[7]: rdi | +// | regs[8]: rsi | +// | regs[9]: ret | //ret func addr +// | regs[10]: rdx | +// | regs[11]: rcx | +// | regs[12]: rbx | +// hig | regs[13]: rsp | +enum { + kRDI = 7, + kRSI = 8, + kRETAddr = 9, + kRSP = 13, +}; + +// 64 bit +extern "C" { +extern void coctx_swap(coctx_t*, coctx_t*) asm("coctx_swap"); +}; +#if defined(__i386__) +int coctx_init(coctx_t* ctx) { + memset(ctx, 0, sizeof(*ctx)); + return 0; +} +int coctx_make(coctx_t* ctx, coctx_pfn_t pfn, const void* s, const void* s1) { + // make room for coctx_param + char* sp = ctx->ss_sp + ctx->ss_size - sizeof(coctx_param_t); + sp = (char*)((unsigned long)sp & -16L); + + coctx_param_t* param = (coctx_param_t*)sp; + void** ret_addr = (void**)(sp - sizeof(void*) * 2); + *ret_addr = (void*)pfn; + param->s1 = s; + param->s2 = s1; + + memset(ctx->regs, 0, sizeof(ctx->regs)); + + ctx->regs[kESP] = (char*)(sp) - sizeof(void*) * 2; + return 0; +} +#elif defined(__x86_64__) +int coctx_make(coctx_t* ctx, coctx_pfn_t pfn, const void* s, const void* s1) { + char* sp = ctx->ss_sp + ctx->ss_size - sizeof(void*); + sp = (char*)((unsigned long)sp & -16LL); + + memset(ctx->regs, 0, sizeof(ctx->regs)); + void** ret_addr = (void**)(sp); + *ret_addr = (void*)pfn; + + ctx->regs[kRSP] = sp; + + ctx->regs[kRETAddr] = (char*)pfn; + + ctx->regs[kRDI] = (char*)s; + ctx->regs[kRSI] = (char*)s1; + return 0; +} + +int coctx_init(coctx_t* ctx) { + memset(ctx, 0, sizeof(*ctx)); + return 0; +} + +#endif diff --git a/trunk/3rdparty/libco/coctx.h b/trunk/3rdparty/libco/coctx.h new file mode 100644 index 0000000000..c1fdfa9da9 --- /dev/null +++ b/trunk/3rdparty/libco/coctx.h @@ -0,0 +1,42 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __CO_CTX_H__ +#define __CO_CTX_H__ +#include +typedef void* (*coctx_pfn_t)( void* s, void* s2 ); +struct coctx_param_t +{ + const void *s1; + const void *s2; +}; +struct coctx_t +{ +#if defined(__i386__) + void *regs[ 8 ]; +#else + void *regs[ 14 ]; +#endif + size_t ss_size; + char *ss_sp; + +}; + +int coctx_init( coctx_t *ctx ); +int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 ); +#endif diff --git a/trunk/3rdparty/libco/coctx_swap.S b/trunk/3rdparty/libco/coctx_swap.S new file mode 100644 index 0000000000..0e4ce1c92b --- /dev/null +++ b/trunk/3rdparty/libco/coctx_swap.S @@ -0,0 +1,83 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +.globl coctx_swap +#if !defined( __APPLE__ ) +.type coctx_swap, @function +#endif +coctx_swap: + +#if defined(__i386__) + movl 4(%esp), %eax + movl %esp, 28(%eax) + movl %ebp, 24(%eax) + movl %esi, 20(%eax) + movl %edi, 16(%eax) + movl %edx, 12(%eax) + movl %ecx, 8(%eax) + movl %ebx, 4(%eax) + + + movl 8(%esp), %eax + movl 4(%eax), %ebx + movl 8(%eax), %ecx + movl 12(%eax), %edx + movl 16(%eax), %edi + movl 20(%eax), %esi + movl 24(%eax), %ebp + movl 28(%eax), %esp + + ret + +#elif defined(__x86_64__) + leaq (%rsp),%rax + movq %rax, 104(%rdi) + movq %rbx, 96(%rdi) + movq %rcx, 88(%rdi) + movq %rdx, 80(%rdi) + movq 0(%rax), %rax + movq %rax, 72(%rdi) + movq %rsi, 64(%rdi) + movq %rdi, 56(%rdi) + movq %rbp, 48(%rdi) + movq %r8, 40(%rdi) + movq %r9, 32(%rdi) + movq %r12, 24(%rdi) + movq %r13, 16(%rdi) + movq %r14, 8(%rdi) + movq %r15, (%rdi) + xorq %rax, %rax + + movq 48(%rsi), %rbp + movq 104(%rsi), %rsp + movq (%rsi), %r15 + movq 8(%rsi), %r14 + movq 16(%rsi), %r13 + movq 24(%rsi), %r12 + movq 32(%rsi), %r9 + movq 40(%rsi), %r8 + movq 56(%rsi), %rdi + movq 80(%rsi), %rdx + movq 88(%rsi), %rcx + movq 96(%rsi), %rbx + leaq 8(%rsp), %rsp + pushq 72(%rsi) + + movq 64(%rsi), %rsi + ret +#endif diff --git a/trunk/3rdparty/libco/example_closure.cpp b/trunk/3rdparty/libco/example_closure.cpp new file mode 100644 index 0000000000..c5bae1cc4b --- /dev/null +++ b/trunk/3rdparty/libco/example_closure.cpp @@ -0,0 +1,91 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "co_closure.h" +#include +#include +#include +#include +#include +using namespace std; + +static void *thread_func( void * arg ) +{ + stCoClosure_t *p = (stCoClosure_t*) arg; + p->exec(); + return 0; +} +static void batch_exec( vector &v ) +{ + vector ths; + for( size_t i=0;i v; + + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + + int total = 100; + vector v2; + co_ref( ref,total,v2,m); + for(int i=0;i<10;i++) + { + co_func( f,ref,i ) + { + printf("ref.total %d i %d\n",ref.total,i ); + //lock + pthread_mutex_lock(&ref.m); + ref.v2.push_back( i ); + pthread_mutex_unlock(&ref.m); + //unlock + } + co_func_end; + v.push_back( new f( ref,i ) ); + } + for(int i=0;i<2;i++) + { + co_func( f2,i ) + { + printf("i: %d\n",i); + for(int j=0;j<2;j++) + { + usleep( 1000 ); + printf("i %d j %d\n",i,j); + } + } + co_func_end; + v.push_back( new f2( i ) ); + } + + batch_exec( v ); + printf("done\n"); + + return 0; +} + + diff --git a/trunk/3rdparty/libco/example_cond.cpp b/trunk/3rdparty/libco/example_cond.cpp new file mode 100644 index 0000000000..5262568074 --- /dev/null +++ b/trunk/3rdparty/libco/example_cond.cpp @@ -0,0 +1,83 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include +#include "co_routine.h" +using namespace std; +struct stTask_t +{ + int id; +}; +struct stEnv_t +{ + stCoCond_t* cond; + queue task_queue; +}; +void* Producer(void* args) +{ + co_enable_hook_sys(); + stEnv_t* env= (stEnv_t*)args; + int id = 0; + while (true) + { + stTask_t* task = (stTask_t*)calloc(1, sizeof(stTask_t)); + task->id = id++; + env->task_queue.push(task); + printf("%s:%d produce task %d\n", __func__, __LINE__, task->id); + co_cond_signal(env->cond); + poll(NULL, 0, 1000); + } + return NULL; +} +void* Consumer(void* args) +{ + co_enable_hook_sys(); + stEnv_t* env = (stEnv_t*)args; + while (true) + { + if (env->task_queue.empty()) + { + co_cond_timedwait(env->cond, -1); + continue; + } + stTask_t* task = env->task_queue.front(); + env->task_queue.pop(); + printf("%s:%d consume task %d\n", __func__, __LINE__, task->id); + free(task); + } + return NULL; +} +int main() +{ + stEnv_t* env = new stEnv_t; + env->cond = co_cond_alloc(); + + stCoRoutine_t* consumer_routine; + co_create(&consumer_routine, NULL, Consumer, env); + co_resume(consumer_routine); + + stCoRoutine_t* producer_routine; + co_create(&producer_routine, NULL, Producer, env); + co_resume(producer_routine); + + co_eventloop(co_get_epoll_ct(), NULL, NULL); + return 0; +} diff --git a/trunk/3rdparty/libco/example_copystack.cpp b/trunk/3rdparty/libco/example_copystack.cpp new file mode 100644 index 0000000000..92062a6ea4 --- /dev/null +++ b/trunk/3rdparty/libco/example_copystack.cpp @@ -0,0 +1,61 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include +#include "coctx.h" +#include "co_routine.h" +#include "co_routine_inner.h" + +void* RoutineFunc(void* args) +{ + co_enable_hook_sys(); + int* routineid = (int*)args; + while (true) + { + char sBuff[128]; + sprintf(sBuff, "from routineid %d stack addr %p\n", *routineid, sBuff); + + printf("%s", sBuff); + poll(NULL, 0, 1000); //sleep 1s + } + return NULL; +} + +int main() +{ + stShareStack_t* share_stack= co_alloc_sharestack(1, 1024 * 128); + stCoRoutineAttr_t attr; + attr.stack_size = 0; + attr.share_stack = share_stack; + + stCoRoutine_t* co[2]; + int routineid[2]; + for (int i = 0; i < 2; i++) + { + routineid[i] = i; + co_create(&co[i], &attr, RoutineFunc, routineid + i); + co_resume(co[i]); + } + co_eventloop(co_get_epoll_ct(), NULL, NULL); + return 0; +} diff --git a/trunk/3rdparty/libco/example_echocli.cpp b/trunk/3rdparty/libco/example_echocli.cpp new file mode 100644 index 0000000000..083c1e7009 --- /dev/null +++ b/trunk/3rdparty/libco/example_echocli.cpp @@ -0,0 +1,218 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "co_routine.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +struct stEndPoint +{ + char *ip; + unsigned short int port; +}; + +static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr) +{ + bzero(&addr,sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(shPort); + int nIP = 0; + if( !pszIP || '\0' == *pszIP + || 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0") + || 0 == strcmp(pszIP,"*") + ) + { + nIP = htonl(INADDR_ANY); + } + else + { + nIP = inet_addr(pszIP); + } + addr.sin_addr.s_addr = nIP; + +} + +static int iSuccCnt = 0; +static int iFailCnt = 0; +static int iTime = 0; + +void AddSuccCnt() +{ + int now = time(NULL); + if (now >iTime) + { + printf("time %d Succ Cnt %d Fail Cnt %d\n", iTime, iSuccCnt, iFailCnt); + iTime = now; + iSuccCnt = 0; + iFailCnt = 0; + } + else + { + iSuccCnt++; + } +} +void AddFailCnt() +{ + int now = time(NULL); + if (now >iTime) + { + printf("time %d Succ Cnt %d Fail Cnt %d\n", iTime, iSuccCnt, iFailCnt); + iTime = now; + iSuccCnt = 0; + iFailCnt = 0; + } + else + { + iFailCnt++; + } +} + +static void *readwrite_routine( void *arg ) +{ + + co_enable_hook_sys(); + + stEndPoint *endpoint = (stEndPoint *)arg; + char str[8]="sarlmol"; + char buf[ 1024 * 16 ]; + int fd = -1; + int ret = 0; + for(;;) + { + if ( fd < 0 ) + { + fd = socket(PF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr; + SetAddr(endpoint->ip, endpoint->port, addr); + ret = connect(fd,(struct sockaddr*)&addr,sizeof(addr)); + + if ( errno == EALREADY || errno == EINPROGRESS ) + { + struct pollfd pf = { 0 }; + pf.fd = fd; + pf.events = (POLLOUT|POLLERR|POLLHUP); + co_poll( co_get_epoll_ct(),&pf,1,200); + //check connect + int error = 0; + uint32_t socklen = sizeof(error); + errno = 0; + ret = getsockopt(fd, SOL_SOCKET, SO_ERROR,(void *)&error, &socklen); + if ( ret == -1 ) + { + //printf("getsockopt ERROR ret %d %d:%s\n", ret, errno, strerror(errno)); + close(fd); + fd = -1; + AddFailCnt(); + continue; + } + if ( error ) + { + errno = error; + //printf("connect ERROR ret %d %d:%s\n", error, errno, strerror(errno)); + close(fd); + fd = -1; + AddFailCnt(); + continue; + } + } + + } + + ret = write( fd,str, 8); + if ( ret > 0 ) + { + ret = read( fd,buf, sizeof(buf) ); + if ( ret <= 0 ) + { + //printf("co %p read ret %d errno %d (%s)\n", + // co_self(), ret,errno,strerror(errno)); + close(fd); + fd = -1; + AddFailCnt(); + } + else + { + //printf("echo %s fd %d\n", buf,fd); + AddSuccCnt(); + } + } + else + { + //printf("co %p write ret %d errno %d (%s)\n", + // co_self(), ret,errno,strerror(errno)); + close(fd); + fd = -1; + AddFailCnt(); + } + } + return 0; +} + +int main(int argc,char *argv[]) +{ + stEndPoint endpoint; + endpoint.ip = argv[1]; + endpoint.port = atoi(argv[2]); + int cnt = atoi( argv[3] ); + int proccnt = atoi( argv[4] ); + + struct sigaction sa; + sa.sa_handler = SIG_IGN; + sigaction( SIGPIPE, &sa, NULL ); + + for(int k=0;k 0 ) + { + continue; + } + else if( pid < 0 ) + { + break; + } + for(int i=0;i +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __FreeBSD__ +#include +#include +#include +#endif + +using namespace std; +struct task_t +{ + stCoRoutine_t *co; + int fd; +}; + +static stack g_readwrite; +static int g_listen_fd = -1; +static int SetNonBlock(int iSock) +{ + int iFlags; + + iFlags = fcntl(iSock, F_GETFL, 0); + iFlags |= O_NONBLOCK; + iFlags |= O_NDELAY; + int ret = fcntl(iSock, F_SETFL, iFlags); + return ret; +} + +static void *readwrite_routine( void *arg ) +{ + + co_enable_hook_sys(); + + task_t *co = (task_t*)arg; + char buf[ 1024 * 16 ]; + for(;;) + { + if( -1 == co->fd ) + { + g_readwrite.push( co ); + co_yield_ct(); + continue; + } + + int fd = co->fd; + co->fd = -1; + + for(;;) + { + struct pollfd pf = { 0 }; + pf.fd = fd; + pf.events = (POLLIN|POLLERR|POLLHUP); + co_poll( co_get_epoll_ct(),&pf,1,1000); + + int ret = read( fd,buf,sizeof(buf) ); + if( ret > 0 ) + { + ret = write( fd,buf,ret ); + } + if( ret > 0 || ( -1 == ret && EAGAIN == errno ) ) + { + continue; + } + close( fd ); + break; + } + + } + return 0; +} +int co_accept(int fd, struct sockaddr *addr, socklen_t *len ); +static void *accept_routine( void * ) +{ + co_enable_hook_sys(); + printf("accept_routine\n"); + fflush(stdout); + for(;;) + { + //printf("pid %ld g_readwrite.size %ld\n",getpid(),g_readwrite.size()); + if( g_readwrite.empty() ) + { + printf("empty\n"); //sleep + struct pollfd pf = { 0 }; + pf.fd = -1; + poll( &pf,1,1000); + + continue; + + } + struct sockaddr_in addr; //maybe sockaddr_un; + memset( &addr,0,sizeof(addr) ); + socklen_t len = sizeof(addr); + + int fd = co_accept(g_listen_fd, (struct sockaddr *)&addr, &len); + if( fd < 0 ) + { + struct pollfd pf = { 0 }; + pf.fd = g_listen_fd; + pf.events = (POLLIN|POLLERR|POLLHUP); + co_poll( co_get_epoll_ct(),&pf,1,1000 ); + continue; + } + if( g_readwrite.empty() ) + { + close( fd ); + continue; + } + SetNonBlock( fd ); + task_t *co = g_readwrite.top(); + co->fd = fd; + g_readwrite.pop(); + co_resume( co->co ); + } + return 0; +} + +static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr) +{ + bzero(&addr,sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(shPort); + int nIP = 0; + if( !pszIP || '\0' == *pszIP + || 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0") + || 0 == strcmp(pszIP,"*") + ) + { + nIP = htonl(INADDR_ANY); + } + else + { + nIP = inet_addr(pszIP); + } + addr.sin_addr.s_addr = nIP; + +} + +static int CreateTcpSocket(const unsigned short shPort /* = 0 */,const char *pszIP /* = "*" */,bool bReuse /* = false */) +{ + int fd = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP); + if( fd >= 0 ) + { + if(shPort != 0) + { + if(bReuse) + { + int nReuseAddr = 1; + setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&nReuseAddr,sizeof(nReuseAddr)); + } + struct sockaddr_in addr ; + SetAddr(pszIP,shPort,addr); + int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr)); + if( ret != 0) + { + close(fd); + return -1; + } + } + } + return fd; +} + + +int main(int argc,char *argv[]) +{ + if(argc<5){ + printf("Usage:\n" + "example_echosvr [IP] [PORT] [TASK_COUNT] [PROCESS_COUNT]\n" + "example_echosvr [IP] [PORT] [TASK_COUNT] [PROCESS_COUNT] -d # daemonize mode\n"); + return -1; + } + const char *ip = argv[1]; + int port = atoi( argv[2] ); + int cnt = atoi( argv[3] ); + int proccnt = atoi( argv[4] ); + bool deamonize = argc >= 6 && strcmp(argv[5], "-d") == 0; + + g_listen_fd = CreateTcpSocket( port,ip,true ); + listen( g_listen_fd,1024 ); + if(g_listen_fd==-1){ + printf("Port %d is in use\n", port); + return -1; + } + printf("listen %d %s:%d\n",g_listen_fd,ip,port); + + SetNonBlock( g_listen_fd ); + + for(int k=0;k 0 ) + { + continue; + } + else if( pid < 0 ) + { + break; + } + for(int i=0;ifd = -1; + + co_create( &(task->co),NULL,readwrite_routine,task ); + co_resume( task->co ); + + } + stCoRoutine_t *accept_co = NULL; + co_create( &accept_co,NULL,accept_routine,0 ); + co_resume( accept_co ); + + co_eventloop( co_get_epoll_ct(),0,0 ); + + exit(0); + } + if(!deamonize) wait(NULL); + return 0; +} + diff --git a/trunk/3rdparty/libco/example_poll.cpp b/trunk/3rdparty/libco/example_poll.cpp new file mode 100644 index 0000000000..eb92f219e7 --- /dev/null +++ b/trunk/3rdparty/libco/example_poll.cpp @@ -0,0 +1,211 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "co_routine.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __FreeBSD__ +#include +#endif + +using namespace std; + +struct task_t +{ + stCoRoutine_t *co; + int fd; + struct sockaddr_in addr; +}; + +static int SetNonBlock(int iSock) +{ + int iFlags; + + iFlags = fcntl(iSock, F_GETFL, 0); + iFlags |= O_NONBLOCK; + iFlags |= O_NDELAY; + int ret = fcntl(iSock, F_SETFL, iFlags); + return ret; +} + + + +static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr) +{ + bzero(&addr,sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(shPort); + int nIP = 0; + if( !pszIP || '\0' == *pszIP + || 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0") + || 0 == strcmp(pszIP,"*") + ) + { + nIP = htonl(INADDR_ANY); + } + else + { + nIP = inet_addr(pszIP); + } + addr.sin_addr.s_addr = nIP; + +} + +static int CreateTcpSocket(const unsigned short shPort = 0 ,const char *pszIP = "*" ,bool bReuse = false ) +{ + int fd = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP); + if( fd >= 0 ) + { + if(shPort != 0) + { + if(bReuse) + { + int nReuseAddr = 1; + setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&nReuseAddr,sizeof(nReuseAddr)); + } + struct sockaddr_in addr ; + SetAddr(pszIP,shPort,addr); + int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr)); + if( ret != 0) + { + close(fd); + return -1; + } + } + } + return fd; +} + +static void *poll_routine( void *arg ) +{ + co_enable_hook_sys(); + + vector &v = *(vector*)arg; + for(size_t i=0;i setRaiseFds; + size_t iWaitCnt = v.size(); + for(;;) + { + int ret = poll( pf,iWaitCnt,1000 ); + printf("co %p poll wait %ld ret %d\n", + co_self(),iWaitCnt,ret); + for(int i=0;i<(int)iWaitCnt;i++) + { + printf("co %p fire fd %d revents 0x%X POLLOUT 0x%X POLLERR 0x%X POLLHUP 0x%X\n", + co_self(), + pf[i].fd, + pf[i].revents, + POLLOUT, + POLLERR, + POLLHUP + ); + setRaiseFds.insert( pf[i].fd ); + } + if( setRaiseFds.size() == v.size()) + { + break; + } + if( ret <= 0 ) + { + break; + } + + iWaitCnt = 0; + for(size_t i=0;i v; + for(int i=1;i v2 = v; + poll_routine( &v2 ); + printf("--------------------- routine -------------------\n"); + + for(int i=0;i<10;i++) + { + stCoRoutine_t *co = 0; + vector *v2 = new vector(); + *v2 = v; + co_create( &co,NULL,poll_routine,v2 ); + printf("routine i %d\n",i); + co_resume( co ); + } + + co_eventloop( co_get_epoll_ct(),0,0 ); + + return 0; +} +//./example_poll 127.0.0.1 12365 127.0.0.1 12222 192.168.1.1 1000 192.168.1.2 1111 + diff --git a/trunk/3rdparty/libco/example_setenv.cpp b/trunk/3rdparty/libco/example_setenv.cpp new file mode 100644 index 0000000000..520cfb6333 --- /dev/null +++ b/trunk/3rdparty/libco/example_setenv.cpp @@ -0,0 +1,89 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include +#include "co_routine.h" + +const char* CGI_ENV_HOOK_LIST [] = +{ + "CGINAME", +}; +struct stRoutineArgs_t +{ + int iRoutineID; +}; +void SetAndGetEnv(int iRoutineID) +{ + printf("routineid %d begin\n", iRoutineID); + + //use poll as sleep + poll(NULL, 0, 500); + + char sBuf[128]; + sprintf(sBuf, "cgi_routine_%d", iRoutineID); + int ret = setenv("CGINAME", sBuf, 1); + if (ret) + { + printf("%s:%d set env err ret %d errno %d %s\n", __func__, __LINE__, + ret, errno, strerror(errno)); + return; + } + printf("routineid %d set env CGINAME %s\n", iRoutineID, sBuf); + + poll(NULL, 0, 500); + + char* env = getenv("CGINAME"); + if (!env) + { + printf("%s:%d get env err errno %d %s\n", __func__, __LINE__, + errno, strerror(errno)); + return; + } + printf("routineid %d get env CGINAME %s\n", iRoutineID, env); +} + +void* RoutineFunc(void* args) +{ + co_enable_hook_sys(); + + stRoutineArgs_t* g = (stRoutineArgs_t*)args; + + SetAndGetEnv(g->iRoutineID); + return NULL; +} + +int main(int argc, char* argv[]) +{ + co_set_env_list(CGI_ENV_HOOK_LIST, sizeof(CGI_ENV_HOOK_LIST) / sizeof(char*)); + stRoutineArgs_t args[3]; + for (int i = 0; i < 3; i++) + { + stCoRoutine_t* co = NULL; + args[i].iRoutineID = i; + co_create(&co, NULL, RoutineFunc, &args[i]); + co_resume(co); + } + co_eventloop(co_get_epoll_ct(), NULL, NULL); + return 0; +} + diff --git a/trunk/3rdparty/libco/example_specific.cpp b/trunk/3rdparty/libco/example_specific.cpp new file mode 100644 index 0000000000..5d20a8b1a8 --- /dev/null +++ b/trunk/3rdparty/libco/example_specific.cpp @@ -0,0 +1,61 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "co_routine_specific.h" +#include "co_routine.h" +#include +#include +#include +#include +using namespace std; +struct stRoutineArgs_t +{ + stCoRoutine_t* co; + int routine_id; +}; +struct stRoutineSpecificData_t +{ + int idx; +}; + +CO_ROUTINE_SPECIFIC(stRoutineSpecificData_t, __routine); + +void* RoutineFunc(void* args) +{ + co_enable_hook_sys(); + stRoutineArgs_t* routine_args = (stRoutineArgs_t*)args; + __routine->idx = routine_args->routine_id; + while (true) + { + printf("%s:%d routine specific data idx %d\n", __func__, __LINE__, __routine->idx); + poll(NULL, 0, 1000); + } + return NULL; +} +int main() +{ + stRoutineArgs_t args[10]; + for (int i = 0; i < 10; i++) + { + args[i].routine_id = i; + co_create(&args[i].co, NULL, RoutineFunc, (void*)&args[i]); + co_resume(args[i].co); + } + co_eventloop(co_get_epoll_ct(), NULL, NULL); + return 0; +} diff --git a/trunk/3rdparty/libco/example_thread.cpp b/trunk/3rdparty/libco/example_thread.cpp new file mode 100644 index 0000000000..401771071a --- /dev/null +++ b/trunk/3rdparty/libco/example_thread.cpp @@ -0,0 +1,56 @@ +/* +* Tencent is pleased to support the open source community by making Libco available. + +* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + + +#include "co_routine.h" +#include "co_routine_inner.h" + +#include +#include +#include +#include +#include + +int loop(void *) +{ + return 0; +} +static void *routine_func( void * ) +{ + stCoEpoll_t * ev = co_get_epoll_ct(); //ct = current thread + co_eventloop( ev,loop,0 ); + return 0; +} +int main(int argc,char *argv[]) +{ + int cnt = atoi( argv[1] ); + + pthread_t tid[ cnt ]; + for(int i=0;i -# -# To start with more than the default 64 initial pollfd slots -# (but the table grows dynamically anyway): -# DEFINES += -DST_MIN_POLLFDS_SIZE= -# -# Note that you can also add these defines by specifying them as -# make/gmake arguments (without editing this Makefile). For example: -# -# make EXTRA_CFLAGS=-DUSE_POLL -# -# (replace make with gmake if needed). -# -# You can also modify the default selection of an alternative event -# notification mechanism. E.g., to enable kqueue(2) support (if it's not -# enabled by default): -# -# gmake EXTRA_CFLAGS=-DMD_HAVE_KQUEUE -# -# or to disable default epoll(4) support: -# -# make EXTRA_CFLAGS=-UMD_HAVE_EPOLL -# -########################## - -CFLAGS += $(DEFINES) $(OTHER_FLAGS) $(EXTRA_CFLAGS) - -OBJS = $(TARGETDIR)/sched.o \ - $(TARGETDIR)/stk.o \ - $(TARGETDIR)/sync.o \ - $(TARGETDIR)/key.o \ - $(TARGETDIR)/io.o \ - $(TARGETDIR)/event.o -OBJS += $(EXTRA_OBJS) -HEADER = $(TARGETDIR)/st.h -SLIBRARY = $(TARGETDIR)/libst.a -DLIBRARY = $(TARGETDIR)/libst.$(DSO_SUFFIX).$(VERSION) -EXAMPLES = examples - -LINKNAME = libst.$(DSO_SUFFIX) -SONAME = libst.$(DSO_SUFFIX).$(MAJOR) -FULLNAME = libst.$(DSO_SUFFIX).$(VERSION) - -ifeq ($(OS), CYGWIN) -SONAME = cygst.$(DSO_SUFFIX) -SLIBRARY = $(TARGETDIR)/libst.dll.a -DLIBRARY = $(TARGETDIR)/$(SONAME) -LINKNAME = -# examples directory does not compile under cygwin -EXAMPLES = -endif - -# for SRS -# disable examples for ubuntu crossbuild failed. -# @see https://github.com/winlinvip/simple-rtmp-server/issues/308 -EXAMPLES = - -ifeq ($(OS), DARWIN) -LINKNAME = libst.$(DSO_SUFFIX) -SONAME = libst.$(MAJOR).$(DSO_SUFFIX) -FULLNAME = libst.$(VERSION).$(DSO_SUFFIX) -endif - -ifeq ($(STATIC_ONLY), yes) -LIBRARIES = $(SLIBRARY) -else -LIBRARIES = $(SLIBRARY) $(DLIBRARY) -endif - -ifeq ($(OS),) -ST_ALL = unknown -else -ST_ALL = $(TARGETDIR) $(LIBRARIES) $(HEADER) $(EXAMPLES) $(DESC) -endif - -all: $(ST_ALL) - -unknown: - @echo - @echo "Please specify one of the following targets:" - @echo - @for target in $(TARGETS); do echo $$target; done - @echo - -st.pc: st.pc.in - sed "s/@VERSION@/${VERSION}/g" < $< > $@ - -$(TARGETDIR): - if [ ! -d $(TARGETDIR) ]; then mkdir $(TARGETDIR); fi - -$(SLIBRARY): $(OBJS) - $(AR) $(ARFLAGS) $@ $(OBJS) - $(RANLIB) $@ - rm -f obj; $(LN) $(LNFLAGS) $(TARGETDIR) obj - -$(DLIBRARY): $(OBJS:%.o=%-pic.o) - $(LD) $(LDFLAGS) $^ -o $@ - if test "$(LINKNAME)"; then \ - cd $(TARGETDIR); \ - rm -f $(SONAME) $(LINKNAME); \ - $(LN) $(LNFLAGS) $(FULLNAME) $(SONAME); \ - $(LN) $(LNFLAGS) $(FULLNAME) $(LINKNAME); \ - fi - -$(HEADER): public.h - rm -f $@ - cp public.h $@ - -$(TARGETDIR)/md.o: md.S - $(CC) $(CFLAGS) -c $< -o $@ - -$(TARGETDIR)/%.o: %.c common.h md.h - $(CC) $(CFLAGS) -c $< -o $@ - -examples:: - @echo Making $@ - @cd $@; $(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS)" OS="$(OS)" TARGETDIR="$(TARGETDIR)" - -clean: - rm -rf *_OPT *_DBG obj st.pc - -########################## -# Pattern rules: - -ifneq ($(SFLAGS),) -# Compile with shared library options if it's a C file -$(TARGETDIR)/%-pic.o: %.c common.h md.h - $(CC) $(CFLAGS) $(SFLAGS) -c $< -o $@ -endif - -# Compile assembly as normal or C as normal if no SFLAGS -%-pic.o: %.o - rm -f $@; $(LN) $(LNFLAGS) $(. Install them with: - # rpm -i libst*.rpm -Requires GNU automake and rpm 3.0.3 or later. - -Debian users: - If you run potato, please upgrade to woody. - If you run woody, "apt-get install libst-dev" will get you v1.3. - If you run testing/unstable, you will get the newest available version. - If you *must* have the newest libst in woody, you may follow these - not-recommended instructions: - 1. Add "deb-src unstable main" to your - /etc/apt/sources.list - 2. apt-get update - 3. apt-get source st - 4. cd st-1.4 (or whatever version you got) - 5. debuild - 6. dpkg -i ../*.deb - -If your application uses autoconf to search for dependencies and you -want to search for a given version of libst, you can simply add - PKG_CHECK_MODULES(MYAPP, st >= 1.3 mumble >= 0.2.23) -to your configure.ac/in. This will define @MYAPP_LIBS@ and -@MYAPP_CFLAGS@ which you may then use in your Makefile.am/in files to -link against mumble and st. - - -LICENSE - -The State Threads library is a derivative of the Netscape Portable -Runtime library (NSPR). All source code in this directory is -distributed under the terms of the Mozilla Public License (MPL) version -1.1 or the GNU General Public License (GPL) version 2 or later. For -more information about these licenses please see -http://www.mozilla.org/MPL/ and http://www.gnu.org/copyleft/. - -All source code in the "examples" directory is distributed under the BSD -style license. - - -PLATFORMS - -Please see the "docs/notes.html" file for the list of currently -supported platforms. - - -DEBUGGER SUPPORT - -It's almost impossible to print SP and PC in a portable way. The only -way to see thread's stack platform-independently is to actually jump to -the saved context. That's what the _st_iterate_threads() function does. -Do the following to iterate over all threads: - -- set the _st_iterate_threads_flag to 1 in debugger -- set breakpoint at the _st_show_thread_stack() function - (which does nothing) -- call the _st_iterate_threads() function which jumps to the - next thread -- at each break you can explore thread's stack -- continue -- when iteration is complete, you return to the original - point (you can see thread id and a message as arguments of - the _st_show_thread_stack() function). - -You can call _st_iterate_threads() in three ways: - -- Insert it into your source code at the point you want to - go over threads. -- Just run application and this function will be called at - the first context switch. -- Call it directly from the debugger at any point. - -This works with gdb and dbx. - -Example using gdb: - -(gdb) set _st_iterate_threads_flag = 1 -(gdb) b _st_show_thread_stack -... -(gdb) call _st_iterate_threads() -... -(gdb) bt -... -(gdb) c -... -(gdb) bt -... -(gdb) c -... -and so on... - -_st_iterate_threads_flag will be set to 0 automatically -after iteration is over or you can set it to 0 at any time -to stop iteration. - -Sometimes gdb complains about SIGSEGV when you call a function -directly at gdb command-line. It can be ignored -- just call the -same function right away again, it works just fine. For example: - -(gdb) set _st_iterate_threads_flag = 1 -(gdb) b _st_show_thread_stack -Breakpoint 1 at 0x809bbbb: file sched.c, line 856. -(gdb) call _st_iterate_threads() -Program received signal SIGSEGV, Segmentation fault. -.... -(gdb) # just call the function again: -(gdb) call _st_iterate_threads() -Breakpoint 1, _st_show_thread_stack (thread=0x4017aee4, messg=0x80ae7a2 -"Iteration started") at sched.c:856 -856 } -.... - -You can use simple gdb command-line scripting to display -all threads and their stack traces at once: - -(gdb) while _st_iterate_threads_flag - >bt - >c - >end -.... - -Another script to stop at the thread with the specific thread id -(e.g., 0x40252ee4): - -(gdb) # set the flag again: -(gdb) set _st_iterate_threads_flag = 1 -(gdb) call _st_iterate_threads() -Breakpoint 1, _st_show_thread_stack (thread=0x4017aee4, messg=0x80ae7a2 -"Iteration started") at sched.c:856 -856 } -.... -(gdb) while thread != 0x40252ee4 - >c - >end -.... -.... -Breakpoint 1, _st_show_thread_stack (thread=0x40252ee4, messg=0x0) at -sched.c:856 -856 } -(gdb) bt -.... -(gdb) # don't want to continue iteration, unset the flag: -(gdb) set _st_iterate_threads_flag = 0 -(gdb) c -Continuing. -Breakpoint 1, _st_show_thread_stack (thread=0x0, messg=0x80ae78e "Iteration -completed") - at sched.c:856 -856 } -(gdb) c -Continuing. -(gdb) return -Make selected stack frame return now? (y or n) y -#0 0x4011254e in __select () - from /lib/libc.so.6 -(gdb) detach - - -CHANGE LOG - -Changes from 1.8 to 1.9. ------------------------- -o Support 32-bit and 64-bit Intel Macs. - -o Added ST_VERSION string, and ST_VERSION_MAJOR and ST_VERSION_MINOR - [bug 1796801]. - -o Fixed some compiler warnings, based on a patch from Brian Wellington - [bug 1932741]. - - -Changes from 1.7 to 1.8. --------------------------- -o Added support for kqueue and epoll on platforms that support them. - Added ability to choose the event notification system at program - startup. - -o Long-overdue public definitions of ST_UTIME_NO_TIMEOUT (-1ULL) and - ST_UTIME_NO_WAIT (0) [bug 1514436]. - -o Documentation patch for st_utime() [bug 1514484]. - -o Documentation patch for st_timecache_set() [bug 1514486]. - -o Documentation patch for st_netfd_serialize_accept() [bug 1514494]. - -o Added st_writev_resid() [rfe 1538344]. - -o Added st_readv_resid() [rfe 1538768] and, for symmetry, st_readv(). - - -Changes from 1.6 to 1.7. ------------------------- -o Support glibc 2.4, which breaks programs that manipulate jump buffers. - Replaced Linux IA64 special cases with new md.S that covers all - Linux. - - -Changes from 1.5.2 to 1.6. --------------------------- -none - - -Changes from 1.5.1 to 1.5.2. ----------------------------- -o Alfred Perlstein's context switch callback feature. - -o Claus Assmann's st_recvmsg/st_sendmsg wrappers. - -o Extra stack padding for platforms that need it. - -o Ron Arts's timeout clarifications in the reference manual. - -o Raymond Bero and Anton Berezin's AMD64 FreeBSD port. - -o Claus Assmann's AMD64 SunOS 5.10 port. - -o Claus Assmann's AMD64 OpenBSD port. - -o Michael Abd-El-Malek's Mac OS X port. - -o Michael Abd-El-Malek's stack printing patch. - - -Changes from 1.5.0 to 1.5.1. ----------------------------- -o Andreas Gustafsson's USE_POLL fix. - -o Gene's st_set_utime_function() enhancement. - - -Changes from 1.4 to 1.5.0. --------------------------- -o Andreas Gustafsson's performance patch. - -o New extensions: Improved DNS resolver, generic LRU cache, in-process - DNS cache, and a program to test the resolver and cache. - -o Support for AMD Opteron 64-bit CPUs under Linux. - -o Support for SPARC-64 under Solaris. - -o Andreas Gustafsson's support for VAX under NetBSD. - -o Changed unportable #warning directives in md.h to #error. - - -Changes from 1.3 to 1.4. ------------------------- -o Andreas Gustafsson's NetBSD port. - -o Wesley W. Terpstra's Darwin (MacOS X) port. - -o Support for many CPU architectures under Linux and *BSD. - -o Renamed private typedefs so they don't conflict with public ones any - more. - -o common.h now includes public.h for strict prototyping. - -o Joshua Levy's recommendation to make st_connect() and st_sendto() - accept const struct sockaddr pointers, as the originals do. - -o Clarified the documentation regarding blocking vs. non-blocking I/O. - -o Cygwin support. - -o Created the extensions directory. - -o Fixed warnings from ia64asm.S. - - -Changes from 1.2 to 1.3. ------------------------- -o Added st_read_resid() and st_write_resid() to allow the caller to know - how much data was transferred before an error occurred. Updated - documentation. - -o Updated project link, copyrights, and documentation regarding - timeouts. Added comment to st_connect(). - -o Optimized the _st_add_sleep_q() function in sched.c. Now we walk the - sleep queue *backward* when inserting a thread into it. When you - have lots (hundreds) of threads and several timeout values, it takes - a while to insert a thread at the appropriate point in the sleep - queue. The idea is that often this appropriate point is closer to - the end of the queue rather than the beginning. Measurements show - performance improves with this change. In any case this change - should do no harm. - -o Added a hint of when to define USE_POLL and when not to, to the - Makefile. - -o Added debugging support (files common.h and sched.c). See above. - -o Decreased the number of reallocations of _ST_POLLFDS in sched.c. - Inspired by Lev Walkin. - -o Fixed st_usleep(-1) and st_sleep(-1), and added a warning to the - documentation about too-large timeouts. - -o Linux/*BSD Alpha port. - -o Wesley W. Terpstra modernized the build process: - - properly build relocatable libraries under bsd and linux - - use library versioning - - added rpm spec file - - added debian/ files - See above for build instructions. - - -Changes from 1.1 to 1.2. ------------------------- -o Added st_randomize_stacks(). - -o Added a patch contributed by Sascha Schumann. - - -Changes from 1.0 to 1.1. ------------------------- -o Relicensed under dual MPL-GPL. - -o OpenBSD port. - -o Compile-time option to use poll() instead of select() for - event polling (see Makefile). - This is useful if you want to support a large number of open - file descriptors (larger than FD_SETSIZE) within a single - process. - -o Linux IA-64 port. - Two issues make IA-64 different from other platforms: - - - Besides the traditional call stack in memory, IA-64 uses the - general register stack. Thus each thread needs a backing store - for the register stack in addition to the memory stack. - - - Current implementation of setjmp()/longjmp() can not be used - for thread context-switching since it assumes that only one - register stack exists. Using special assembly functions for - context-switching is unavoidable. - -o Thread stack capping on IRIX. - This allows some profiling tools (such as SpeedShop) to know when - to stop unwinding the stack. Without this libexc, used by SpeedShop, - traces right off the stack and crashes. - -o Miscellaneous documentation additions. - - -COPYRIGHTS - -Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. -All Rights Reserved. diff --git a/trunk/3rdparty/st-srs/README.md b/trunk/3rdparty/st-srs/README.md deleted file mode 100644 index 60fc1a6518..0000000000 --- a/trunk/3rdparty/st-srs/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# state-threads - -![](http://ossrs.net:8000/gif/v1/sls.gif?site=github.com&path=/srs/srsst) -[![](https://cloud.githubusercontent.com/assets/2777660/22814959/c51cbe72-ef92-11e6-81cc-32b657b285d5.png)](https://github.com/ossrs/srs/wiki/v1_CN_Contact#wechat) - -Fork from http://sourceforge.net/projects/state-threads, patched for [SRS](https://github.com/ossrs/srs/tree/2.0release). - -> See: https://github.com/ossrs/state-threads/blob/srs/README - -For original ST without any changes, checkout the [ST master branch](https://github.com/ossrs/state-threads/tree/master). - -## Branch SRS - -The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patched the following patches: - -- [x] Patch [st.arm.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/1.st.arm.patch), for ARM. -- [x] Patch [st.osx.kqueue.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/3.st.osx.kqueue.patch), for osx. -- [x] Patch [st.disable.examples.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/4.st.disable.examples.patch), for ubuntu. -- [x] [Refine TAB of code](https://github.com/ossrs/state-threads/compare/c2001d30ca58f55d72a6cc6b9b6c70391eaf14db...d2101b26988b0e0db0aabc53ddf452068c1e2cbc). -- [x] Merge from [michaeltalyansky](https://github.com/michaeltalyansky/state-threads) and [xzh3836598](https://github.com/ossrs/state-threads/commit/9a17dec8f9c2814d93761665df7c5575a4d2d8a3), support [ARM](https://github.com/ossrs/state-threads/issues/1). -- [x] Merge from [toffaletti](https://github.com/toffaletti/state-threads), support [valgrind](https://github.com/ossrs/state-threads/issues/2) for ST. -- [x] Patch [st.osx10.14.build.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/6.st.osx10.14.build.patch), for osx 10.14 build. -- [x] Support macro `MD_ST_NO_ASM` to disable ASM, [#8](https://github.com/ossrs/state-threads/issues/8). -- [x] Merge patch [srs#1282](https://github.com/ossrs/srs/issues/1282#issuecomment-445539513) to support aarch64, [#9](https://github.com/ossrs/state-threads/issues/9). - -## Docs - -* Introduction: http://ossrs.github.io/state-threads/docs/st.html -* API reference: http://ossrs.github.io/state-threads/docs/reference.html -* Programming notes: http://ossrs.github.io/state-threads/docs/notes.html - -## Usage - -Get code: - -``` -git clone https://github.com/ossrs/state-threads.git st-1.9 && -git checkout -b srs origin/srs -``` - -For Linux: - -``` -make linux-debug EXTRA_CFLAGS="-DMD_HAVE_EPOLL" -``` - -For OSX: - -``` -make darwin-debug EXTRA_CFLAGS="-DMD_HAVE_KQUEUE" -``` - -Linux with valgrind: - -``` -make linux-debug EXTRA_CFLAGS="-DMD_VALGRIND" -``` - -> Remark: User must install valgrind, for instance, in centos6 `sudo yum install -y valgrind valgrind-devel`. - -Linux with valgrind and epoll: - -``` -make linux-debug EXTRA_CFLAGS="-DMD_HAVE_EPOLL -DMD_VALGRIND" -``` - -For OSX, user must specifies the valgrind header files: - -``` -make darwin-debug EXTRA_CFLAGS="-DMD_HAVE_KQUEUE -DMD_VALGRIND -I/usr/local/include" -``` - -> Remark: Latest OSX does not support ST, please use docker to run ST. - -## Valgrind - -How to debug with gdb under valgrind, read [valgrind manual](http://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver-simple). - -About startup parameters, read [valgrind cli](http://valgrind.org/docs/manual/mc-manual.html#mc-manual.options). - -Important cli options: - -1. `--undef-value-errors= [default: yes]`, Controls whether Memcheck reports uses of undefined value errors. Set this to no if you don't want to see undefined value errors. It also has the side effect of speeding up Memcheck somewhat. -1. `--leak-check= [default: summary]`, When enabled, search for memory leaks when the client program finishes. If set to summary, it says how many leaks occurred. If set to full or yes, each individual leak will be shown in detail and/or counted as an error, as specified by the options `--show-leak-kinds` and `--errors-for-leak-kinds`. -1. `--track-origins= [default: no]`, Controls whether Memcheck tracks the origin of uninitialised values. By default, it does not, which means that although it can tell you that an uninitialised value is being used in a dangerous way, it cannot tell you where the uninitialised value came from. This often makes it difficult to track down the root problem. -1. `--show-reachable= , --show-possibly-lost=`, to show the using memory. - -Winlin 2016 diff --git a/trunk/3rdparty/st-srs/common.h b/trunk/3rdparty/st-srs/common.h deleted file mode 100644 index 0c0685b9ae..0000000000 --- a/trunk/3rdparty/st-srs/common.h +++ /dev/null @@ -1,479 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#ifndef __ST_COMMON_H__ -#define __ST_COMMON_H__ - -#include -#include -#include -#include -#include - -/* Enable assertions only if DEBUG is defined */ -#ifndef DEBUG - #define NDEBUG -#endif -#include -#define ST_ASSERT(expr) assert(expr) - -#define ST_BEGIN_MACRO { -#define ST_END_MACRO } - -#ifdef DEBUG - #define ST_HIDDEN /*nothing*/ -#else - #define ST_HIDDEN static -#endif - -#include "public.h" -#include "md.h" - -/* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */ -#ifndef MD_VALGRIND - #ifndef NVALGRIND - #define NVALGRIND - #endif -#else - #undef NVALGRIND -#endif - - -/***************************************** - * Circular linked list definitions - */ - -typedef struct _st_clist { - struct _st_clist *next; - struct _st_clist *prev; -} _st_clist_t; - -/* Insert element "_e" into the list, before "_l" */ -#define ST_INSERT_BEFORE(_e,_l) \ - ST_BEGIN_MACRO \ - (_e)->next = (_l); \ - (_e)->prev = (_l)->prev; \ - (_l)->prev->next = (_e); \ - (_l)->prev = (_e); \ - ST_END_MACRO - -/* Insert element "_e" into the list, after "_l" */ -#define ST_INSERT_AFTER(_e,_l) \ - ST_BEGIN_MACRO \ - (_e)->next = (_l)->next; \ - (_e)->prev = (_l); \ - (_l)->next->prev = (_e); \ - (_l)->next = (_e); \ - ST_END_MACRO - -/* Return the element following element "_e" */ -#define ST_NEXT_LINK(_e) ((_e)->next) - -/* Append an element "_e" to the end of the list "_l" */ -#define ST_APPEND_LINK(_e,_l) ST_INSERT_BEFORE(_e,_l) - -/* Insert an element "_e" at the head of the list "_l" */ -#define ST_INSERT_LINK(_e,_l) ST_INSERT_AFTER(_e,_l) - -/* Return the head/tail of the list */ -#define ST_LIST_HEAD(_l) (_l)->next -#define ST_LIST_TAIL(_l) (_l)->prev - -/* Remove the element "_e" from it's circular list */ -#define ST_REMOVE_LINK(_e) \ - ST_BEGIN_MACRO \ - (_e)->prev->next = (_e)->next; \ - (_e)->next->prev = (_e)->prev; \ - ST_END_MACRO - -/* Return non-zero if the given circular list "_l" is empty, */ -/* zero if the circular list is not empty */ -#define ST_CLIST_IS_EMPTY(_l) \ - ((_l)->next == (_l)) - -/* Initialize a circular list */ -#define ST_INIT_CLIST(_l) \ - ST_BEGIN_MACRO \ - (_l)->next = (_l); \ - (_l)->prev = (_l); \ - ST_END_MACRO - -#define ST_INIT_STATIC_CLIST(_l) \ - {(_l), (_l)} - - -/***************************************** - * Basic types definitions - */ - -typedef void (*_st_destructor_t)(void *); - - -typedef struct _st_stack { - _st_clist_t links; - char *vaddr; /* Base of stack's allocated memory */ - int vaddr_size; /* Size of stack's allocated memory */ - int stk_size; /* Size of usable portion of the stack */ - char *stk_bottom; /* Lowest address of stack's usable portion */ - char *stk_top; /* Highest address of stack's usable portion */ - void *sp; /* Stack pointer from C's point of view */ -#ifdef __ia64__ - void *bsp; /* Register stack backing store pointer */ -#endif - /* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */ -#ifndef NVALGRIND - /* id returned by VALGRIND_STACK_REGISTER */ - /* http://valgrind.org/docs/manual/manual-core-adv.html */ - unsigned long valgrind_stack_id; -#endif -} _st_stack_t; - - -typedef struct _st_cond { - _st_clist_t wait_q; /* Condition variable wait queue */ -} _st_cond_t; - - -typedef struct _st_thread _st_thread_t; - -struct _st_thread { - int state; /* Thread's state */ - int flags; /* Thread's flags */ - - void *(*start)(void *arg); /* The start function of the thread */ - void *arg; /* Argument of the start function */ - void *retval; /* Return value of the start function */ - - _st_stack_t *stack; /* Info about thread's stack */ - - _st_clist_t links; /* For putting on run/sleep/zombie queue */ - _st_clist_t wait_links; /* For putting on mutex/condvar wait queue */ -#ifdef DEBUG - _st_clist_t tlink; /* For putting on thread queue */ -#endif - - st_utime_t due; /* Wakeup time when thread is sleeping */ - _st_thread_t *left; /* For putting in timeout heap */ - _st_thread_t *right; /* -- see docs/timeout_heap.txt for details */ - int heap_index; - - void **private_data; /* Per thread private data */ - - _st_cond_t *term; /* Termination condition variable for join */ - - jmp_buf context; /* Thread's context */ -}; - - -typedef struct _st_mutex { - _st_thread_t *owner; /* Current mutex owner */ - _st_clist_t wait_q; /* Mutex wait queue */ -} _st_mutex_t; - - -typedef struct _st_pollq { - _st_clist_t links; /* For putting on io queue */ - _st_thread_t *thread; /* Polling thread */ - struct pollfd *pds; /* Array of poll descriptors */ - int npds; /* Length of the array */ - int on_ioq; /* Is it on ioq? */ -} _st_pollq_t; - - -typedef struct _st_eventsys_ops { - const char *name; /* Name of this event system */ - int val; /* Type of this event system */ - int (*init)(void); /* Initialization */ - void (*dispatch)(void); /* Dispatch function */ - int (*pollset_add)(struct pollfd *, int); /* Add descriptor set */ - void (*pollset_del)(struct pollfd *, int); /* Delete descriptor set */ - int (*fd_new)(int); /* New descriptor allocated */ - int (*fd_close)(int); /* Descriptor closed */ - int (*fd_getlimit)(void); /* Descriptor hard limit */ -} _st_eventsys_t; - - -typedef struct _st_vp { - _st_thread_t *idle_thread; /* Idle thread for this vp */ - st_utime_t last_clock; /* The last time we went into vp_check_clock() */ - - _st_clist_t run_q; /* run queue for this vp */ - _st_clist_t io_q; /* io queue for this vp */ - _st_clist_t zombie_q; /* zombie queue for this vp */ -#ifdef DEBUG - _st_clist_t thread_q; /* all threads of this vp */ -#endif - int pagesize; - - _st_thread_t *sleep_q; /* sleep queue for this vp */ - int sleepq_size; /* number of threads on sleep queue */ - -#ifdef ST_SWITCH_CB - st_switch_cb_t switch_out_cb; /* called when a thread is switched out */ - st_switch_cb_t switch_in_cb; /* called when a thread is switched in */ -#endif -} _st_vp_t; - - -typedef struct _st_netfd { - int osfd; /* Underlying OS file descriptor */ - int inuse; /* In-use flag */ - void *private_data; /* Per descriptor private data */ - _st_destructor_t destructor; /* Private data destructor function */ - void *aux_data; /* Auxiliary data for internal use */ - struct _st_netfd *next; /* For putting on the free list */ -} _st_netfd_t; - - -/***************************************** - * Current vp, thread, and event system - */ - -extern _st_vp_t _st_this_vp; -extern _st_thread_t *_st_this_thread; -extern _st_eventsys_t *_st_eventsys; - -#define _ST_CURRENT_THREAD() (_st_this_thread) -#define _ST_SET_CURRENT_THREAD(_thread) (_st_this_thread = (_thread)) - -#define _ST_LAST_CLOCK (_st_this_vp.last_clock) - -#define _ST_RUNQ (_st_this_vp.run_q) -#define _ST_IOQ (_st_this_vp.io_q) -#define _ST_ZOMBIEQ (_st_this_vp.zombie_q) -#ifdef DEBUG - #define _ST_THREADQ (_st_this_vp.thread_q) -#endif - -#define _ST_PAGE_SIZE (_st_this_vp.pagesize) - -#define _ST_SLEEPQ (_st_this_vp.sleep_q) -#define _ST_SLEEPQ_SIZE (_st_this_vp.sleepq_size) - -#define _ST_VP_IDLE() (*_st_eventsys->dispatch)() - - -/***************************************** - * vp queues operations - */ - -#define _ST_ADD_IOQ(_pq) ST_APPEND_LINK(&_pq.links, &_ST_IOQ) -#define _ST_DEL_IOQ(_pq) ST_REMOVE_LINK(&_pq.links) - -#define _ST_ADD_RUNQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_RUNQ) -#define _ST_DEL_RUNQ(_thr) ST_REMOVE_LINK(&(_thr)->links) - -#define _ST_ADD_SLEEPQ(_thr, _timeout) _st_add_sleep_q(_thr, _timeout) -#define _ST_DEL_SLEEPQ(_thr) _st_del_sleep_q(_thr) - -#define _ST_ADD_ZOMBIEQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_ZOMBIEQ) -#define _ST_DEL_ZOMBIEQ(_thr) ST_REMOVE_LINK(&(_thr)->links) - -#ifdef DEBUG - #define _ST_ADD_THREADQ(_thr) ST_APPEND_LINK(&(_thr)->tlink, &_ST_THREADQ) - #define _ST_DEL_THREADQ(_thr) ST_REMOVE_LINK(&(_thr)->tlink) -#endif - - -/***************************************** - * Thread states and flags - */ - -#define _ST_ST_RUNNING 0 -#define _ST_ST_RUNNABLE 1 -#define _ST_ST_IO_WAIT 2 -#define _ST_ST_LOCK_WAIT 3 -#define _ST_ST_COND_WAIT 4 -#define _ST_ST_SLEEPING 5 -#define _ST_ST_ZOMBIE 6 -#define _ST_ST_SUSPENDED 7 - -#define _ST_FL_PRIMORDIAL 0x01 -#define _ST_FL_IDLE_THREAD 0x02 -#define _ST_FL_ON_SLEEPQ 0x04 -#define _ST_FL_INTERRUPT 0x08 -#define _ST_FL_TIMEDOUT 0x10 - - -/***************************************** - * Pointer conversion - */ - -#ifndef offsetof - #define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier)) -#endif - -#define _ST_THREAD_PTR(_qp) \ - ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, links))) - -#define _ST_THREAD_WAITQ_PTR(_qp) \ - ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, wait_links))) - -#define _ST_THREAD_STACK_PTR(_qp) \ - ((_st_stack_t *)((char*)(_qp) - offsetof(_st_stack_t, links))) - -#define _ST_POLLQUEUE_PTR(_qp) \ - ((_st_pollq_t *)((char *)(_qp) - offsetof(_st_pollq_t, links))) - -#ifdef DEBUG - #define _ST_THREAD_THREADQ_PTR(_qp) \ - ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, tlink))) -#endif - - -/***************************************** - * Constants - */ - -#ifndef ST_UTIME_NO_TIMEOUT - #define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL) -#endif - -#ifndef __ia64__ - #define ST_DEFAULT_STACK_SIZE (64*1024) -#else - #define ST_DEFAULT_STACK_SIZE (128*1024) /* Includes register stack size */ -#endif - -#ifndef ST_KEYS_MAX - #define ST_KEYS_MAX 16 -#endif - -#ifndef ST_MIN_POLLFDS_SIZE - #define ST_MIN_POLLFDS_SIZE 64 -#endif - - -/***************************************** - * Threads context switching - */ - -#ifdef DEBUG - void _st_iterate_threads(void); - #define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads() -#else - #define ST_DEBUG_ITERATE_THREADS() -#endif - -#ifdef ST_SWITCH_CB - #define ST_SWITCH_OUT_CB(_thread) \ - if (_st_this_vp.switch_out_cb != NULL && \ - _thread != _st_this_vp.idle_thread && \ - _thread->state != _ST_ST_ZOMBIE) { \ - _st_this_vp.switch_out_cb(); \ - } - #define ST_SWITCH_IN_CB(_thread) \ - if (_st_this_vp.switch_in_cb != NULL && \ - _thread != _st_this_vp.idle_thread && \ - _thread->state != _ST_ST_ZOMBIE) { \ - _st_this_vp.switch_in_cb(); \ - } -#else - #define ST_SWITCH_OUT_CB(_thread) - #define ST_SWITCH_IN_CB(_thread) -#endif - -/* - * Switch away from the current thread context by saving its state and - * calling the thread scheduler - */ -#define _ST_SWITCH_CONTEXT(_thread) \ - ST_BEGIN_MACRO \ - ST_SWITCH_OUT_CB(_thread); \ - if (!MD_SETJMP((_thread)->context)) { \ - _st_vp_schedule(); \ - } \ - ST_DEBUG_ITERATE_THREADS(); \ - ST_SWITCH_IN_CB(_thread); \ - ST_END_MACRO - -/* - * Restore a thread context that was saved by _ST_SWITCH_CONTEXT or - * initialized by _ST_INIT_CONTEXT - */ -#define _ST_RESTORE_CONTEXT(_thread) \ - ST_BEGIN_MACRO \ - _ST_SET_CURRENT_THREAD(_thread); \ - MD_LONGJMP((_thread)->context, 1); \ - ST_END_MACRO - -/* - * Initialize the thread context preparing it to execute _main - */ -#ifdef MD_INIT_CONTEXT - #define _ST_INIT_CONTEXT MD_INIT_CONTEXT -#else - #error Unknown OS -#endif - -/* - * Number of bytes reserved under the stack "bottom" - */ -#define _ST_STACK_PAD_SIZE MD_STACK_PAD_SIZE - - -/***************************************** - * Forward declarations - */ - -void _st_vp_schedule(void); -void _st_vp_check_clock(void); -void *_st_idle_thread_start(void *arg); -void _st_thread_main(void); -void _st_thread_cleanup(_st_thread_t *thread); -void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout); -void _st_del_sleep_q(_st_thread_t *thread); -_st_stack_t *_st_stack_new(int stack_size); -void _st_stack_free(_st_stack_t *ts); -int _st_io_init(void); - -st_utime_t st_utime(void); -_st_cond_t *st_cond_new(void); -int st_cond_destroy(_st_cond_t *cvar); -int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout); -int st_cond_signal(_st_cond_t *cvar); -ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout); -ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout); -int st_poll(struct pollfd *pds, int npds, st_utime_t timeout); -_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size); - -#endif /* !__ST_COMMON_H__ */ - diff --git a/trunk/3rdparty/st-srs/docs/fig.gif b/trunk/3rdparty/st-srs/docs/fig.gif deleted file mode 100644 index 7265a05db4f516b44fcf37c3949922ff4f62999d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5374 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 diff --git a/trunk/3rdparty/st-srs/docs/notes.html b/trunk/3rdparty/st-srs/docs/notes.html deleted file mode 100644 index 5a24369e22..0000000000 --- a/trunk/3rdparty/st-srs/docs/notes.html +++ /dev/null @@ -1,434 +0,0 @@ - - -State Threads Library Programming Notes - - -

Programming Notes

-

- -

- -

-


-

- -

Porting

-The State Threads library uses OS concepts that are available in some -form on most UNIX platforms, making the library very portable across -many flavors of UNIX. However, there are several parts of the library -that rely on platform-specific features. Here is the list of such parts: -

-

    -
  • Thread context initialization: Two ingredients of the -jmp_buf -data structure (the program counter and the stack pointer) have to be -manually set in the thread creation routine. The jmp_buf data -structure is defined in the setjmp.h header file and differs from -platform to platform. Usually the program counter is a structure member -with PC in the name and the stack pointer is a structure member -with SP in the name. One can also look in the -Netscape's NSPR library source -which already has this code for many UNIX-like platforms -(mozilla/nsprpub/pr/include/md/*.h files). -

    -Note that on some BSD-derived platforms _setjmp(3)/_longjmp(3) -calls should be used instead of setjmp(3)/longjmp(3) (that is -the calls that manipulate only the stack and registers and do not -save and restore the process's signal mask).

  • -

    -Starting with glibc 2.4 on Linux the opacity of the jmp_buf data -structure is enforced by setjmp(3)/longjmp(3) so the -jmp_buf ingredients cannot be accessed directly anymore (unless -special environmental variable LD_POINTER_GUARD is set before application -execution). To avoid dependency on custom environment, the State Threads -library provides setjmp/longjmp replacement functions for -all Intel CPU architectures. Other CPU architectures can also be easily -supported (the setjmp/longjmp source code is widely available for -many CPU architectures). -

    -

  • High resolution time function: Some platforms (IRIX, Solaris) -provide a high resolution time function based on the free running hardware -counter. This function returns the time counted since some arbitrary -moment in the past (usually machine power up time). It is not correlated in -any way to the time of day, and thus is not subject to resetting, -drifting, etc. This type of time is ideal for tasks where cheap, accurate -interval timing is required. If such a function is not available on a -particular platform, the gettimeofday(3) function can be used -(though on some platforms it involves a system call). -

    -

  • The stack growth direction: The library needs to know whether the -stack grows toward lower (down) or higher (up) memory addresses. -One can write a simple test program that detects the stack growth direction -on a particular platform.
  • -

    -

  • Non-blocking attribute inheritance: On some platforms (e.g. IRIX) -the socket created as a result of the accept(2) call inherits the -non-blocking attribute of the listening socket. One needs to consult the manual -pages or write a simple test program to see if this applies to a specific -platform.
  • -

    -

  • Anonymous memory mapping: The library allocates memory segments -for thread stacks by doing anonymous memory mapping (mmap(2)). This -mapping is somewhat different on SVR4 and BSD4.3 derived platforms. -

    -The memory mapping can be avoided altogether by using malloc(3) for -stack allocation. In this case the MALLOC_STACK macro should be -defined.

  • -
-

-All machine-dependent feature test macros should be defined in the -md.h header file. The assembly code for setjmp/longjmp -replacement functions for all CPU architectures should be placed in -the md.S file. -

-The current version of the library is ported to: -

    -
  • IRIX 6.x (both 32 and 64 bit)
  • -
  • Linux (kernel 2.x and glibc 2.x) on x86, Alpha, MIPS and MIPSEL, - SPARC, ARM, PowerPC, 68k, HPPA, S390, IA-64, and Opteron (AMD-64)
  • -
  • Solaris 2.x (SunOS 5.x) on x86, AMD64, SPARC, and SPARC-64
  • -
  • AIX 4.x
  • -
  • HP-UX 11 (both 32 and 64 bit)
  • -
  • Tru64/OSF1
  • -
  • FreeBSD on x86, AMD64, and Alpha
  • -
  • OpenBSD on x86, AMD64, Alpha, and SPARC
  • -
  • NetBSD on x86, Alpha, SPARC, and VAX
  • -
  • MacOS X (Darwin) on PowerPC (32 bit) and Intel (both 32 and 64 bit) [universal]
  • -
  • Cygwin
  • -
-

- - -

Signals

-Signal handling in an application using State Threads should be treated the -same way as in a classical UNIX process application. There is no such -thing as per-thread signal mask, all threads share the same signal handlers, -and only asynchronous-safe functions can be used in signal handlers. -However, there is a way to process signals synchronously by converting a -signal event to an I/O event: a signal catching function does a write to -a pipe which will be processed synchronously by a dedicated signal handling -thread. The following code demonstrates this technique (error handling is -omitted for clarity): -
-
-/* Per-process pipe which is used as a signal queue. */
-/* Up to PIPE_BUF/sizeof(int) signals can be queued up. */
-int sig_pipe[2];
-
-/* Signal catching function. */
-/* Converts signal event to I/O event. */
-void sig_catcher(int signo)
-{
-  int err;
-
-  /* Save errno to restore it after the write() */
-  err = errno;
-  /* write() is reentrant/async-safe */
-  write(sig_pipe[1], &signo, sizeof(int));
-  errno = err;
-}
-
-/* Signal processing function. */
-/* This is the "main" function of the signal processing thread. */
-void *sig_process(void *arg)
-{
-  st_netfd_t nfd;
-  int signo;
-
-  nfd = st_netfd_open(sig_pipe[0]);
-
-  for ( ; ; ) {
-    /* Read the next signal from the pipe */
-    st_read(nfd, &signo, sizeof(int), ST_UTIME_NO_TIMEOUT);
-
-    /* Process signal synchronously */
-    switch (signo) {
-    case SIGHUP:
-      /* do something here - reread config files, etc. */
-      break;
-    case SIGTERM:
-      /* do something here - cleanup, etc. */
-      break;
-      /*      .
-              .
-         Other signals
-              .
-              .
-      */
-    }
-  }
-
-  return NULL;
-}
-
-int main(int argc, char *argv[])
-{
-  struct sigaction sa;
-        .
-        .
-        .
-
-  /* Create signal pipe */
-  pipe(sig_pipe);
-
-  /* Create signal processing thread */
-  st_thread_create(sig_process, NULL, 0, 0);
-
-  /* Install sig_catcher() as a signal handler */
-  sa.sa_handler = sig_catcher;
-  sigemptyset(&sa.sa_mask);
-  sa.sa_flags = 0;
-  sigaction(SIGHUP, &sa, NULL);
-
-  sa.sa_handler = sig_catcher;
-  sigemptyset(&sa.sa_mask);
-  sa.sa_flags = 0;
-  sigaction(SIGTERM, &sa, NULL);
-
-        .
-        .
-        .
-      
-}
-
-
-

-Note that if multiple processes are used (see below), the signal pipe should -be initialized after the fork(2) call so that each process has its -own private pipe. -

- - -

Intra-Process Synchronization

-Due to the event-driven nature of the library scheduler, the thread context -switch (process state change) can only happen in a well-known set of -library functions. This set includes functions in which a thread may -"block": I/O functions (st_read(), st_write(), etc.), -sleep functions (st_sleep(), etc.), and thread synchronization -functions (st_thread_join(), st_cond_wait(), etc.). As a result, -process-specific global data need not to be protected by locks since a thread -cannot be rescheduled while in a critical section (and only one thread at a -time can access the same memory location). By the same token, -non thread-safe functions (in a traditional sense) can be safely used with -the State Threads. The library's mutex facilities are practically useless -for a correctly written application (no blocking functions in critical -section) and are provided mostly for completeness. This absence of locking -greatly simplifies an application design and provides a foundation for -scalability. -

- - -

Inter-Process Synchronization

-The State Threads library makes it possible to multiplex a large number -of simultaneous connections onto a much smaller number of separate -processes, where each process uses a many-to-one user-level threading -implementation (N of M:1 mappings rather than one M:N -mapping used in native threading libraries on some platforms). This design -is key to the application's scalability. One can think about it as if a -set of all threads is partitioned into separate groups (processes) where -each group has a separate pool of resources (virtual address space, file -descriptors, etc.). An application designer has full control of how many -groups (processes) an application creates and what resources, if any, -are shared among different groups via standard UNIX inter-process -communication (IPC) facilities.

-There are several reasons for creating multiple processes: -

-

    -
  • To take advantage of multiple hardware entities (CPUs, disks, etc.) -available in the system (hardware parallelism).
  • -

    -

  • To reduce risk of losing a large number of user connections when one of -the processes crashes. For example, if C user connections (threads) -are multiplexed onto P processes and one of the processes crashes, -only a fraction (C/P) of all connections will be lost.
  • -

    -

  • To overcome per-process resource limitations imposed by the OS. For -example, if select(2) is used for event polling, the number of -simultaneous connections (threads) per process is -limited by the FD_SETSIZE parameter (see select(2)). -If FD_SETSIZE is equal to 1024 and each connection needs one file -descriptor, then an application should create 10 processes to support 10,000 -simultaneous connections.
  • -
-

-Ideally all user sessions are completely independent, so there is no need for -inter-process communication. It is always better to have several separate -smaller process-specific resources (e.g., data caches) than to have one large -resource shared (and modified) by all processes. Sometimes, however, there -is a need to share a common resource among different processes. In that case, -standard UNIX IPC facilities can be used. In addition to that, there is a way -to synchronize different processes so that only the thread accessing the -shared resource will be suspended (but not the entire process) if that resource -is unavailable. In the following code fragment a pipe is used as a counting -semaphore for inter-process synchronization: -

-#ifndef PIPE_BUF
-#define PIPE_BUF 512  /* POSIX */
-#endif
-
-/* Semaphore data structure */
-typedef struct ipc_sem {
-  st_netfd_t rdfd;  /* read descriptor */
-  st_netfd_t wrfd;  /* write descriptor */
-} ipc_sem_t;
-
-/* Create and initialize the semaphore. Should be called before fork(2). */
-/* 'value' must be less than PIPE_BUF. */
-/* If 'value' is 1, the semaphore works as mutex. */
-ipc_sem_t *ipc_sem_create(int value)
-{
-  ipc_sem_t *sem;
-  int p[2];
-  char b[PIPE_BUF];
-
-  /* Error checking is omitted for clarity */
-  sem = malloc(sizeof(ipc_sem_t));
-
-  /* Create the pipe */
-  pipe(p);
-  sem->rdfd = st_netfd_open(p[0]);
-  sem->wrfd = st_netfd_open(p[1]);
-
-  /* Initialize the semaphore: put 'value' bytes into the pipe */
-  write(p[1], b, value);
-
-  return sem;
-}
-
-/* Try to decrement the "value" of the semaphore. */
-/* If "value" is 0, the calling thread blocks on the semaphore. */
-int ipc_sem_wait(ipc_sem_t *sem)
-{
-  char c;
-
-  /* Read one byte from the pipe */
-  if (st_read(sem->rdfd, &c, 1, ST_UTIME_NO_TIMEOUT) != 1)
-    return -1;
-
-  return 0;
-}
-
-/* Increment the "value" of the semaphore. */
-int ipc_sem_post(ipc_sem_t *sem)
-{
-  char c;
-
-  if (st_write(sem->wrfd, &c, 1, ST_UTIME_NO_TIMEOUT) != 1)
-    return -1;
-
-  return 0;
-}
-
-
-

- -Generally, the following steps should be followed when writing an application -using the State Threads library: -

-

    -
  1. Initialize the library (st_init()).
  2. -

    -

  3. Create resources that will be shared among different processes: - create and bind listening sockets, create shared memory segments, IPC - channels, synchronization primitives, etc.
  4. -

    -

  5. Create several processes (fork(2)). The parent process should - either exit or become a "watchdog" (e.g., it starts a new process when - an existing one crashes, does a cleanup upon application termination, - etc.).
  6. -

    -

  7. In each child process create a pool of threads - (st_thread_create()) to handle user connections.
  8. -
-

- - -

Non-Network I/O

- -The State Threads architecture uses non-blocking I/O on -st_netfd_t objects for concurrent processing of multiple user -connections. This architecture has a drawback: the entire process and -all its threads may block for the duration of a disk or other -non-network I/O operation, whether through State Threads I/O functions, -direct system calls, or standard I/O functions. (This is applicable -mostly to disk reads; disk writes are usually performed -asynchronously -- data goes to the buffer cache to be written to disk -later.) Fortunately, disk I/O (unlike network I/O) usually takes a -finite and predictable amount of time, but this may not be true for -special devices or user input devices (including stdin). Nevertheless, -such I/O reduces throughput of the system and increases response times. -There are several ways to design an application to overcome this -drawback: - -

-

-

- - -

Timeouts

- -The timeout parameter to st_cond_timedwait() and the -I/O functions, and the arguments to st_sleep() and -st_usleep() specify a maximum time to wait since the last -context switch not since the beginning of the function call. - -

The State Threads' time resolution is actually the time interval -between context switches. That time interval may be large in some -situations, for example, when a single thread does a lot of work -continuously. Note that a steady, uninterrupted stream of network I/O -qualifies for this description; a context switch occurs only when a -thread blocks. - -

If a specified I/O timeout is less than the time interval between -context switches the function may return with a timeout error before -that amount of time has elapsed since the beginning of the function -call. For example, if eight milliseconds have passed since the last -context switch and an I/O function with a timeout of 10 milliseconds -blocks, causing a switch, the call may return with a timeout error as -little as two milliseconds after it was called. (On Linux, -select()'s timeout is an upper bound on the amount of -time elapsed before select returns.) Similarly, if 12 ms have passed -already, the function may return immediately. - -

In almost all cases I/O timeouts should be used only for detecting a -broken network connection or for preventing a peer from holding an idle -connection for too long. Therefore for most applications realistic I/O -timeouts should be on the order of seconds. Furthermore, there's -probably no point in retrying operations that time out. Rather than -retrying simply use a larger timeout in the first place. - -

The largest valid timeout value is platform-dependent and may be -significantly less than INT_MAX seconds for select() -or INT_MAX milliseconds for poll(). Generally, you -should not use timeouts exceeding several hours. Use -ST_UTIME_NO_TIMEOUT (-1) as a special value to -indicate infinite timeout or indefinite sleep. Use -ST_UTIME_NO_WAIT (0) to indicate no waiting at all. - -

-


-

- - - diff --git a/trunk/3rdparty/st-srs/docs/reference.html b/trunk/3rdparty/st-srs/docs/reference.html deleted file mode 100644 index 3c9c7bd783..0000000000 --- a/trunk/3rdparty/st-srs/docs/reference.html +++ /dev/null @@ -1,3120 +0,0 @@ - - -State Threads Library Reference - - - -

State Threads Library Reference

- -
-
Types
-
st_thread_t
-
st_cond_t
-
st_mutex_t
-
st_utime_t
-
st_netfd_t
-
st_switch_cb_t
-

-

Error Handling
-

-

Library Initialization
-

-

st_init()
-
st_getfdlimit()
-
st_set_eventsys()
-
st_get_eventsys()
-
st_get_eventsys_name()
-
st_set_utime_function()
-
st_timecache_set()
-
st_randomize_stacks()
-

-

st_switch_cb_t type
-
st_set_switch_in_cb()
-
st_set_switch_out_cb()
-

-

Thread Control and Identification
-

-

st_thread_t type
-
st_thread_create()
-
st_thread_exit()
-
st_thread_join()
-
st_thread_self()
-
st_thread_interrupt()
-
st_sleep()
-
st_usleep()
-
st_randomize_stacks()
-

-

Per-Thread Private Data
-

-

st_key_create()
-
st_key_getlimit()
-
st_thread_setspecific()
-
st_thread_getspecific()
-

-

Synchronization
-

-

st_cond_t type
-
st_cond_new()
-
st_cond_destroy()
-
st_cond_wait()
-
st_cond_timedwait()
-
st_cond_signal()
-
st_cond_broadcast()
-

-

st_mutex_t type
-
st_mutex_new()
-
st_mutex_destroy()
-
st_mutex_lock()
-
st_mutex_trylock()
-
st_mutex_unlock()
-

-

Timing
-

-

st_utime_t type
-
st_utime()
-
st_set_utime_function()
-
st_timecache_set()
-
st_time()
-

-

I/O Functions
-

-

st_netfd_t type
-
st_netfd_open()
-
st_netfd_open_socket()
-
st_netfd_free()
-
st_netfd_close()
-
st_netfd_fileno()
-
st_netfd_setspecific()
-
st_netfd_getspecific()
-
st_netfd_serialize_accept()
-
-
st_netfd_poll()
-

-

st_accept()
-
st_connect()
-
st_read()
-
st_read_fully()
-
st_read_resid()
-
st_readv()
-
st_readv_resid()
-
st_write()
-
st_write_resid()
-
st_writev()
-
st_writev_resid()
-
st_recvfrom()
-
st_sendto()
-
st_recvmsg()
-
st_sendmsg()
-

-

st_open()
-
st_poll()
-

-

Program Structure
-

-

List of Blocking Functions
-

-

-

-


-

- - - -

Types

- -The State Thread library defines the following types in the st.h -header file: -

-

-
st_thread_t
-
st_cond_t
-
st_mutex_t
-
st_utime_t
-
st_netfd_t
-
-

-


-

- - -

st_thread_t

- -Thread type. -

-

Syntax
- -
-#include <st.h>
-
-typedef void *  st_thread_t;
-
-

-

Description
- -A thread is represented and identified by a pointer to an opaque data -structure. This pointer is a required parameter for most of the functions -that operate on threads. -

-The thread identifier remains valid until the thread returns from its root -function and, if the thread was created joinable, is joined. -

-


-

- - -

st_cond_t

- -Condition variable type. -

-

Syntax
- -
-#include <st.h>
-
-typedef void *  st_cond_t;
-
-

-

Description
- -A condition variable is an opaque object identified by a pointer. -Condition variables provide synchronization primitives to wait for or wake -up threads waiting for certain conditions to be satisfied. -

-In the State Threads library there is no need to lock a mutex before -waiting on a condition variable. -

-


-

- - -

st_mutex_t

- -Mutex type. -

-

Syntax
- -
-#include <st.h>
-
-typedef void *  st_mutex_t;
-
-

-

Description
- -A mutex is an opaque object identified by a pointer. -Mutual exclusion locks (mutexes) are used to serialize the execution of -threads through critical sections of code. -

-If application using the State Threads library is written with no -I/O or control yielding in critical sections (that is no -blocking functions in critical sections), then there is -no need for mutexes.

-These mutexes can only be used for intra-process thread synchronization. -They cannot be used for inter-process synchronization. -

-


-

- - -

st_utime_t

- -High resolution time type ("u" stands for "micro"). -

-

Syntax
- -
-#include <st.h>
-
-typedef unsigned long long  st_utime_t;
-
-

-

Description
- -This datatype (unsigned 64-bit integer) represents high-resolution real time -expressed in microseconds since some arbitrary time in the past. It is not -correlated in any way to the time of day. -

-


-

- - -

st_netfd_t

- -File descriptor type. -

-

Syntax
- -
-#include <st.h>
-
-typedef void *  st_netfd_t;
-
-

-

Description
- -This datatype typically represents any open end point of network -communication (socket, end point of a pipe, FIFO, etc.) but can -encapsulate any open file descriptor. Objects of this type are -identified by a pointer to an opaque data structure. - -

-


-

- - -

st_switch_cb_t

- -Context switch callback function type. -

-

Syntax
- -
-#include <st.h>
-
-typedef void (*st_switch_cb_t)(void);
-
-

-

Description
- -This datatype is a convenience type for describing a pointer -to a function that will be called when a thread is set to stop -or set to run. -This feature is available only when ST_SWITCH_CB is defined -in <st.h>. - -

-


-

- - -

Error Handling

- - -All State Threads library non-void functions return on success either a -non-negative integer or a pointer to a newly created object (constructor-type -functions). On failure they return either -1 or a NULL -pointer respectively and set global errno to indicate the error. -It is safe to use errno because it is set right before the function -return and only one thread at a time can modify its value.

-The perror(3) function can be used to produce an error message on the -standard error output. -

-


-

- - -

Library Initialization

- -

-

-
st_init()
-
st_getfdlimit()
-
st_set_eventsys()
-
st_get_eventsys()
-
st_get_eventsys_name()
-

-These functions operate on a callback function of type -st_switch_cb_t: -

st_set_switch_in_cb()
-
st_set_switch_out_cb()
-
-

-


-

- - -

st_init()

- -Initializes the runtime. -

-

Syntax
- -
-#include <st.h>
-
-int st_init(void);
-
-

-

Parameters
-None. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error. -

-

Description
-This function initializes the library runtime. It should be called near -the beginning of the application's main() function before any other -State Threads library function is called.

-Among other things, this function limits the number of open file descriptors -to the OS imposed per-process maximum number or, if select(2) is -used, to FD_SETSIZE, whichever is less (getrlimit(2)). -This limit can be -retrieved by st_getfdlimit(). It also sets the -disposition of the SIGPIPE signal to SIG_IGN (to be ignored) -(signal(5)). -

-Unlike POSIX threads, a new process created by the fork(2) system -call is an exact copy of the calling process and all state threads -which are running in the parent do exist in the child. That means that -st_init() may be called either before or after multiple processes -are created by fork(2). -

-If the library runtime is not properly initialized (e.g., st_init() -is accidentally omitted), then the process will receive either an arithmetic -exception (SIGFPE or SIGTRAP) or segmentation fault (SIGSEGV) signal upon -new thread creation or the first context switch, respectively. -

-


-

- -

st_getfdlimit()

- -Returns the maximum number of file descriptors that the calling process -can open. -

-

Syntax
- -
-#include <st.h>
-
-int st_getfdlimit(void);
-
-

-

Parameters
-None. -

-

Returns
-The maximum number of file descriptors that the calling process can open. -If this function is called before the library is successfully initialized by -st_init(), a value of -1 is returned. -

-

Description
-This function returns the limit on the number of open file descriptors which -is set by the st_init() function. -

-


-

- - -

st_set_eventsys()

- -Sets event notification mechanism. -

-

Syntax
- -
-#include <st.h>
-
-int st_set_eventsys(int eventsys);
-
-

-

Parameters
-st_set_eventsys() has the following parameter:

-eventsys

-An integer value identifying selected event notification mechanism. The -following values are defined in the st.h header file: -

- - - - - - - - - - - - - - - -
ST_EVENTSYS_DEFAULTUse default event notification mechanism. Usually it's select(2) -but if the library was compiled with the USE_POLL macro defined -then the default is poll(2).
ST_EVENTSYS_SELECTUse select(2) as an event notification mechanism.
ST_EVENTSYS_POLLUse poll(2) as an event notification mechanism.
ST_EVENTSYS_ALTUse an alternative event notification mechanism. The actual -mechanism selected depends on OS support. For example, epoll(4) -will be used on Linux if supported and kqueue(2) will be used -on FreeBSD/OpenBSD. If the OS supports no alternative event -notification mechanism, setting ST_EVENTSYS_ALT has no effect -and the ST_EVENTSYS_DEFAULT mechanism will be used.
-

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - - - - -
EINVAL -The supplied eventsys parameter has an invalid value. -
EBUSY -The event notification mechanism has already been set. -
-

-

Description
-This function sets the event notification mechanism that will be used by -the State Threads library. To have any effect, it must be called -before the st_init() function which performs -the actual initialization. If st_set_eventsys() is not called, -st_init() will set the ST_EVENTSYS_DEFAULT -mechanism. The mechanism cannot be changed once set. -

-There are no strict rules for selecting an event notification -mechanism. The "best" one depends on how your application behaves. -Try a few to see which one works best for you. As a rule of -thumb, you should use the ST_EVENTSYS_ALT mechanism if your -application deals with a very large number of network connections of -which only a few are active at once. -

-


-

- -

st_get_eventsys()

- -Returns the integer value identifying the event notification mechanism -being used by the State Threads library. -

-

Syntax
- -
-#include <st.h>
-
-int st_get_eventsys(void);
-
-

-

Parameters
-None. -

-

Returns
-The integer value identifying the current event notification mechanism. -This value can be one of the following (see st_set_eventsys()): -ST_EVENTSYS_SELECT, ST_EVENTSYS_POLL, or -ST_EVENTSYS_ALT. Future versions of the library may return other -values. If a mechanism hasn't been set yet, a value of -1 is returned. -

-

Description
-This function returns the integer value identifying the event notification -mechanism which is actually being used by the State Threads library. -

-


-

- -

st_get_eventsys_name()

- -Returns the name of the event notification mechanism being used by the -State Threads library. -

-

Syntax
- -
-#include <st.h>
-
-const char *st_get_eventsys_name(void);
-
-

-

Parameters
-None. -

-

Returns
-The string identifying the current event notification mechanism. If a -mechanism hasn't been set yet (see st_set_eventsys()), an empty string is -returned. Possible return values are "select", -"poll", "kqueue", or "epoll". Future versions -of the library may return other values. -

-

Description
-This function returns the string identifying the event notification -mechanism which is actually being used by the State Threads library. -

-


-

- - -

st_set_switch_in_cb()

- - -

st_set_switch_out_cb()

-
-Set the optional callback function for thread switches. -

-

Syntax
- -
-#include <st.h>
-
-st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb);
-st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb);
-
-

-

Parameters
-st_set_switch_in_cb() and st_set_switch_out_cb() have the -following parameter:

-cb

-A function to be called when a thread is resumed and stopped respectively.

-

Returns
-The previous callback function pointer. -

-

Description
-These functions set the callback for when a thread is resumed and stopped -respectively. After being called any thread switch will call the callback. -Use a NULL pointer to disable the callback (this is the default). -Use st_thread_self() or thread -specific data to differentiate between threads.

-These functions can be called at any time.

-This feature is available only when ST_SWITCH_CB is defined -in <st.h>. -

-


-

- - -

Thread Control and Identification

- -

-These functions operate on a thread object of type -st_thread_t. -

-

-
st_thread_create()
-
st_thread_exit()
-
st_thread_join()
-
st_thread_self()
-
st_thread_interrupt()
-
st_sleep()
-
st_usleep()
-
st_randomize_stacks()
-
-

-


-

- -

st_thread_create()

- -Creates a new thread. -

-

Syntax
- -
-#include <st.h>
-
-st_thread_t st_thread_create(void *(*start)(void *arg), void *arg,
-                             int joinable, int stack_size);
-
-
-

-

Parameters
-st_thread_create() has the following parameters:

-start

-A pointer to the thread's start function, which is called as the root of the -new thread. Return from this function terminates a thread.

-arg

-A pointer to the root function's only parameter.

-joinable

-Specifies whether the thread is joinable or unjoinable. If this parameter -is zero, the thread is unjoinable. Otherwise, it is joinable. -See also st_thread_join().

-stack_size

-Specifies your preference for the size of the stack, in bytes, associated -with the newly created thread. If you pass zero in this parameter, the -default stack size will be used. The default stack size is 128 KB on IA-64 -and 64 KB on all other platforms. On IA-64 only a half of stack_size -bytes is used for the memory stack. The other half is used for the register -stack backing store. -

-

Returns
-Upon successful completion, a new thread identifier is returned (this -identifier remains valid until the thread returns from its start function). -Otherwise, NULL is returned and errno is set -to indicate the error. -

-

Description
-This function creates a new thread. Note that the total number of threads -created by the application is limited by the amount of swap space available. -Upon thread creation, stack_size bytes are reserved on the swap -space. The stack pages are not actually used (valid) until touched by the -application. -

-


-

- -

st_thread_exit()

- -Terminates the calling thread. -

-

Syntax
- -
-#include <st.h>
-
-void st_thread_exit(void *retval);
-
-

-

Parameters
-st_thread_exit() has the following parameters:

-retval

-If the thread is joinable, then the value retval may be retrieved -by st_thread_join(). If a thread returns from its -start function, it acts as if it had called st_thread_exit() with -retval as the value returned. -

-

Returns
-Nothing. -

-

Description
-This function terminates the calling thread. When a thread exits, per-thread -private data is destroyed by invoking the destructor function for any -non-NULL thread specific values associated with active keys (see -st_key_create()). This function is implicitly called -when a thread returns from its start function.

-When the last thread terminates the process exits with a zero status value. -

-


-

- -

st_thread_join()

- -Blocks the calling thread until a specified thread terminates. -

-

Syntax
- -
-#include <st.h>
-
-int st_thread_join(st_thread_t thread, void **retvalp);
-
-

-

Parameters
-st_thread_join() has the following parameters:

-thread

-A valid identifier for the thread that is to be joined.

-retvalp

-If this parameter is not NULL, then the exit value of the -thread will be placed in the location referenced by this parameter -(see st_thread_exit()). -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - - - - -
EINVALTarget thread is unjoinable.
EINVALOther thread already waits on the same -joinable thread.
EDEADLKTarget thread is the same as the -calling thread.
EINTRCurrent thread was interrupted by -st_thread_interrupt().
-

-

Description
-This function is used to synchronize the termination of a thread and possibly -retrieve its exit value. Several threads cannot wait for the same thread -to complete - one of the calling threads operates successfully, and the others -terminate with the error. The calling thread is not blocked if the target -thread has already terminated. -

-


-

- -

st_thread_self()

- -Identifies the calling thread. -

-

Syntax
- -
-#include <st.h>
-
-st_thread_t st_thread_self(void);
-
-

-

Parameters
-None. -

-

Returns
-Always returns a valid reference to the calling thread - a self-identity. -

-

Description
-This function identifies the calling thread. This is the same identifier -that the creating thread obtains from -st_thread_create(). -

-


-

- -

st_thread_interrupt()

- -Interrupts a target thread. -

-

Syntax
- -
-#include <st.h>
-
-void st_thread_interrupt(st_thread_t thread);
-
-

-

Parameters
-st_thread_interrupt() has the following parameters:

-thread

-A valid identifier for the thread being interrupted. -

-

Returns
-Nothing. -

-

Description
-This function interrupts (unblocks) a target thread that is blocked in one -of the blocking functions. A function that was interrupted -returns an error and sets errno to EINTR. It is up to -the target thread to act upon an interrupt (e.g., it may exit or just -abort the current transaction).

-Note: State Threads library functions are never interrupted by a -caught signal. A blocking library function returns an error and sets -errno to EINTR only if the current thread was -interrupted via st_thread_interrupt(). -

-If a target thread is already runnable or running (e.g., it is a newly -created thread or calling thread itself), this function will prevent it -from subsequent blocking. In other words, the interrupt will be "delivered" -only when a target thread is about to block. -

-


-

- -

st_sleep(), st_usleep()

- -Suspends current thread for a specified amount of time. -

-

Syntax
- -
-#include <st.h>
-
-int st_sleep(int secs);
-
-int st_usleep(st_utime_t usecs);
-
-

-

Parameters
-st_sleep() has the following parameters:

-secs

-The number of seconds you want the thread to sleep for. -

-st_usleep() has the following parameters:

-usecs

-The number of microseconds you want the thread to sleep for. This parameter -is a variable of type st_utime_t. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
-

-

Description
-These functions suspend the calling thread from execution for a specified -number of seconds (st_sleep()) or microseconds (st_usleep()). -

- -If zero is passed as a parameter to st_sleep(), or -ST_UTIME_NO_WAIT (0) is passed to -st_usleep(), the calling thread yields, thus potentially -allowing another thread to run. - -

- -If -1 is passed as a parameter to st_sleep(), or -ST_UTIME_NO_TIMEOUT (-1) is passed to -st_usleep(), the calling thread will be suspended permanently. -It can be resumed again by interrupting it via st_thread_interrupt(). - -

-


-

- -

st_randomize_stacks()

- -Turns stack base address randomization on or off. -

-

Syntax
- -
-#include <st.h>
-
-int st_randomize_stacks(int on);
-
-

-

Parameters
-st_randomize_stacks() has the following parameters:

-on

-If this parameter has a non-zero value, the State Threads library -randomizes the base addresses of stacks allocated for threads created -after this call. Otherwise new threads' stacks are typically page -aligned. -

-

Returns
-The previous state of stack randomization (a value of 0 if it -was off and a non-zero value otherwise). -

-

Description
-Randomizing state threads' stack bases may improve cache performance on -some systems when large numbers of state threads all perform roughly the -same work, as when they all start from the same root function. On many -modern systems the performance increase is negligible. You should -compare your application's performance with this feature on and off to -see if you really need it. -

-When randomization is enabled, new stacks are allocated one page larger -to accomodate the randomization. -

-This call affects only threads created afterward. It has no effect on -existing threads. -

-


-

- - -

Per-Thread Private Data

- -These functions allow to associate private data with each of the threads in -a process. -

-

-
st_key_create()
-
st_key_getlimit()
-
st_thread_setspecific()
-
st_thread_getspecific()
-
-

-


-

- -

st_key_create()

- -Creates a key (non-negative integer) that can be used by all -threads in the process to get and set thread-specific data. -

-

Syntax
- -
-#include <st.h>
-
-int st_key_create(int *keyp, void (*destructor)(void *));
-
-

-

Parameters
-st_key_create() has the following parameters:

-keyp

-The newly created key is returned in the memory pointed to by this parameter. -The new key can be used with -st_thread_setspecific() and -st_thread_getspecific().

-destructor

-Specifies an optional destructor function for the private data associated -with the key. This function can be specified as NULL. -Upon thread exit (see st_thread_exit()), if a key -has a non-NULL destructor and has a non-NULL value -associated with that key, then the destructor function will be -called with the associated value. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - -
EAGAINThe limit on the total number of keys per -process has been exceeded (see st_key_getlimit()). -
-

-

Description
-If this function is successful, every thread in the same process is capable -of associating private data with the new key. After a new key is created, all -active threads have the value NULL associated with that key. -After a new thread is created, the value NULL is associated with -all keys for that thread. If a non-NULL destructor function is -registered with a new key, it will be called at one of two times, as long as -the private data is not NULL: - -

-The key maintains independent data values for each binding thread. A thread -can get access only to its own thread-specific data. There is no way to -deallocate a private data key once it is allocated. -

-


-

- -

st_key_getlimit()

- -Returns the key limit. -

-

Syntax
- -
-#include <st.h>
-
-int st_key_getlimit(void);
-
-

-

Parameters
-None. -

-

Returns
-The limit on the total number of keys per process. -

-

Description
-This function can be used to obtain the limit on the total number of keys -per process (see st_key_create()). -

-


-

- -

st_thread_setspecific()

- -Sets per-thread private data. -

-

Syntax
- -
-#include <st.h>
-
-int st_thread_setspecific(int key, void *value);
-
-

-

Parameters
-st_thread_setspecific() has the following parameters:

-key

-This parameter represents a key with which thread-specific data is associated. -

-value

-The per-thread private data, or more likely, a pointer to the data which is -associated with key. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - - -
EINVALThe specified key is invalid.
-

-

Description
-This function associates a thread-specific value with key. -Different threads may bind different values to the same key.

-If the thread already has non-NULL private data associated with -key, and if the destructor function for that key is not -NULL, this destructor function will be called before setting the -new data value. -

-


-

- -

st_thread_getspecific()

- -Retrieves the per-thread private data for the current thread. -

-

Syntax
- -
-#include <st.h>
-
-void *st_thread_getspecific(int key);
-
-

-

Parameters
-st_thread_getspecific() has the following parameters:

-key

-This parameter represents a key with which thread-specific data is associated. -

-

Returns
-The thread-specific data associated with key. If no data is -associated with key, then NULL is returned. -

-

Description
-This function returns the calling thread's value that is bound to the -specified key (see -st_thread_setspecific()). -

-


-

- - -

Synchronization

- -

-These functions operate on condition variables -and mutual exclusion locks (mutexes).

-Functions are provided to wait on a condition variable and to wake up -(signal) threads that are waiting on the condition variable. -

-

-
st_cond_new()
-
st_cond_destroy()
-
st_cond_wait()
-
st_cond_timedwait()
-
st_cond_signal()
-
st_cond_broadcast()
-

-

st_mutex_new()
-
st_mutex_destroy()
-
st_mutex_lock()
-
st_mutex_trylock()
-
st_mutex_unlock()
-
-

-


-

- -

st_cond_new()

- -Creates a new condition variable. -

-

Syntax
- -
-#include <st.h>
-
-st_cond_t st_cond_new(void);
-
-

-

Parameters
-None. -

-

Returns
-Upon successful completion, a new condition variable identifier is returned. -Otherwise, NULL is returned and errno is set -to indicate the error. -

-

Description
-This function creates a new condition variable. -

-


-

- -

st_cond_destroy()

- -Destroys a condition variable. -

-

Syntax
- -
-#include <st.h>
-
-int st_cond_destroy(st_cond_t cvar);
-
-

-

Parameters
-st_cond_destroy() has the following parameters:

-cvar

-An identifier of the condition variable object to be destroyed. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - - -
EBUSYThe condition variable is currently being -used by one or more threads.
-

-

Description
-This function destroys a condition variable. The caller is responsible for -ensuring that the condition variable is no longer in use. -

-


-

- -

st_cond_wait()

- -Waits on a condition. -

-

Syntax
- -
-#include <st.h>
-
-int st_cond_wait(st_cond_t cvar);
-
-

-

Parameters
-st_cond_wait() has the following parameters:

-cvar

-The condition variable on which to wait. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
-

-

Description
-This function is used to block on a condition variable. A return from this -function does not guarantee that the condition or event for which the caller -was waiting actually occurred. It is the responsibility of the caller -to recheck the condition wait predicate before proceeding.

-Note: The State Threads library scheduling guarantees that the -condition cannot change between the checking and blocking, therefore there -is no need for mutex protection. You must not call any -blocking functions between the condition checking and -the st_cond_wait() call. -

-


-

- -

st_cond_timedwait()

- -Waits on a condition. -

-

Syntax
- -
-#include <st.h>
-
-int st_cond_timedwait(st_cond_t cvar, st_utime_t timeout);
-
-

-

Parameters
-st_cond_timedwait() has the following parameters:

-cvar

-The condition variable on which to wait.

-timeout

-If the number of microseconds specified by this parameter passes before the -waiting thread is signalled, an error is returned. This parameter is a -variable of type st_utime_t. Note that this -time value is a time delta; it is not an absolute time. -Also note that timeouts are measured since -the last context switch. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred before the thread was -awakened by st_cond_signal() or -st_cond_broadcast().
-

-

Description
-This function works the same way as st_cond_wait(), -except that an error is returned if the number of microseconds specified by -timeout passes before the waiting thread is signalled. -

-


-

- -

st_cond_signal()

- -Unblocks a thread waiting on a condition variable. -

-

Syntax
- -
-#include <st.h>
-
-int st_cond_signal(st_cond_t cvar);
-
-

-

Parameters
-st_cond_signal() has the following parameters:

-cvar

-The condition variable to signal. -

-

Returns
-Always zero. -

-

Description
-This function unblocks (signals) one of the threads that are blocked on -cvar at the time of the call. If no thread is waiting on the -condition variable, the signal operation is a no-op. -

-


-

- -

st_cond_broadcast()

- -Unblocks all threads waiting on a condition variable. -

-

Syntax
- -
-#include <st.h>
-
-int st_cond_broadcast(st_cond_t cvar);
-
-

-

Parameters
-st_cond_broadcast() has the following parameters:

-cvar

-The condition variable to broadcast. -

-

Returns
-Always zero. -

-

Description
-This function unblocks all threads blocked on the specified condition -variable at the time of the call. If no threads are waiting, this operation -is a no-op. -

-


-

- - -

st_mutex_new()

- -Creates a new mutual exclusion lock (mutex). -

-

Syntax
- -
-#include <st.h>
-
-st_mutex_t st_mutex_new(void);
-
-

-

Parameters
-None. -

-

Returns
-Upon successful completion, a new mutex identifier is returned. -Otherwise, NULL is returned and errno is set to -indicate the error. -

-

Description
-This function creates a new opaque mutual exclusion lock (see -st_mutex_t). -

-


-

- -

st_mutex_destroy()

- -Destroys a specified mutex object. -

-

Syntax
- -
-#include <st.h>
-
-int st_mutex_destroy(st_mutex_t lock);
-
-

-

Parameters
-st_mutex_destroy() has the following parameters:

-lock

-An identifier of the mutex object to be destroyed. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - - -
EBUSYThe mutex is currently being used by -other threads.
-

-

Description
-This function destroys a mutex. The caller is responsible for ensuring -that the mutex is no longer in use. -

-


-

- -

st_mutex_lock()

- -Locks a specified mutex object. -

-

Syntax
- -
-#include <st.h>
-
-int st_mutex_lock(st_mutex_t lock);
-
-

-

Parameters
-st_mutex_lock() has the following parameters:

-lock

-An identifier of the mutex object to be locked. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - - -
EDEADLKThe current thread already owns the mutex. -
EINTRThe current thread was interrupted by -st_thread_interrupt().
-

-

Description
-A thread that calls this function will block until it can gain exclusive -ownership of a mutex, and retains ownership until it calls -st_mutex_unlock(). -

-


-

- -

st_mutex_trylock()

- -Attempts to acquire a mutex. -

-

Syntax
- -
-#include <st.h>
-
-int st_mutex_trylock(st_mutex_t lock);
-
-

-

Parameters
-st_mutex_trylock() has the following parameters:

-lock

-An identifier of the mutex object to be locked. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - -
EBUSYThe mutex is currently held by another -thread.
-

-

Description
-This function attempts to acquire a mutex. If the mutex object is locked -(by any thread, including the current thread), the call returns immediately -with an error. -

-


-

- -

st_mutex_unlock()

- -Releases a specified mutex object. -

-

Syntax
- -
-#include <st.h>
-
-int st_mutex_unlock(st_mutex_t lock);
-
-

-

Parameters
-st_mutex_unlock() has the following parameters:

-lock

-An identifier of the mutex object to be unlocked. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error:

- - -
EPERMThe current thread does not own the mutex. -
-

-

Description
-This function releases a specified mutex object previously acquired by -st_mutex_lock() or -st_mutex_trylock(). Only the thread that locked -a mutex should unlock it. -

-


-

- - -

Timing

- -

-

-
st_utime()
-
st_set_utime_function()
-
st_timecache_set()
-
st_time()
-
-

-


-

- -

st_utime()

- -Returns current high-resolution time. -

-

Syntax
- -
-#include <st.h>
-
-st_utime_t st_utime(void);
-
-

-

Parameters
-None. -

-

Returns
-Current high-resolution time value of type -st_utime_t. -

-

Description
-This function returns the current high-resolution time. Time is -expressed as microseconds since some arbitrary time in the past. It is -not correlated in any way to the time of day. See also st_utime_t and st_time(). -

-


-

- -

st_set_utime_function()

- -Set high-resolution time function. -

-

Syntax
- -
-#include <st.h>
-
-int st_set_utime_function(st_utime_t (*func)(void));
-
-

-

Parameters
-st_set_utime_function() has the following parameters:

-func

-This function will be called to get high-resolution time instead of the -default st_utime() function. It must return -number of microseconds since some arbitrary time in the past. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to EINVAL to indicate the error. -

-

Description
-This function may be called to replace the default implementation of the -st_utime() function. It must be called before the ST -library has been initialized (see st_init()). -The user-provided function func will be invoked whenever -st_utime() is called to obtain current high-resolution time. -Replacing default implementation may be useful, for example, for taking -advantage of high performance CPU cycle counters. -

-


-

- -

st_timecache_set()

- -Turns the time caching on or off. -

-

Syntax
- -
-#include <st.h>
-
-int st_timecache_set(int on);
-
-

-

Parameters
-st_timecache_set() has the following parameters:

-on

-If this parameter has a non-zero value, the time caching is turned on -(enabled). Otherwise, the time caching is turned off (disabled). -By default time caching is disabled. -

-

Returns
-The previous state of time caching (a value of 0 if it was off and -a value of 1 otherwise). -

-

Description
-The State Threads library has the ability to "cache" the time value that is -reported by the time(2) system call. If the time caching is enabled -by calling this function with a non-zero argument, then the result value -of time(2) will be stored and updated at most once per second. The -cached time can be retrieved by st_time(). -By default time caching is disabled. -You may enable or disable time caching at any time but generally -you enable it once (if desired) during program initialization.

-Note: There are some pathological cases (e.g., very heavy loads during -application benchmarking) when a single thread runs for a long time without -giving up control and the cached time value is not updated properly. If you -always need "real-time" time values, don't enable the time caching. -

-


-

- -

st_time()

- -Returns the value of time in seconds since 00:00:00 UTC, January 1, 1970. -

-

Syntax
- -
-#include <st.h>
-
-time_t st_time(void);
-
-

-

Parameters
-None. -

-

Returns
-The value of time in seconds since 00:00:00 UTC, January 1, 1970 as reported -by the time(2) system call. -

-

Description
-If the time caching was enabled by -st_timecache_set(), then this function returns -the cached result. Otherwise, it just calls time(2). -

-


-

- - -

I/O Functions

- -

-Most State Threads library I/O functions look like corresponding C library -functions with two exceptions: -

    -
  • They operate on file descriptor objects of type -st_netfd_t.
  • -
  • They take an additional argument of type -st_utime_t which represents an inactivity -timeout: if no I/O is possible during this amount of time, I/O functions -return an error code and set errno to ETIME. - -The boundary values ST_UTIME_NO_WAIT (0) and -ST_UTIME_NO_TIMEOUT (-1) for this argument indicate -that the thread should wait no time (function returns immediately) or -wait forever (never time out), respectively. - -Note that timeouts are measured since the -last context switch. -
  • -
-

-

-
st_netfd_open()
-
st_netfd_open_socket()
-
st_netfd_free()
-
st_netfd_close()
-
st_netfd_fileno()
-
st_netfd_setspecific()
-
st_netfd_getspecific()
-
st_netfd_serialize_accept()
-
st_netfd_poll()
-

-

st_accept()
-
st_connect()
-
st_read()
-
st_read_fully()
-
st_read_resid()
-
st_readv()
-
st_read_resid()
-
st_write()
-
st_write_resid()
-
st_writev()
-
st_writev_resid()
-
st_recvfrom()
-
st_sendto()
-
st_recvmsg()
-
st_sendmsg()
-
st_open()
-
st_poll()
-
-

-


-

- -

st_netfd_open()

- -Creates a new file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-st_netfd_t st_netfd_open(int osfd);
-
-

-

Parameters
-st_netfd_open() has the following parameters:

-osfd

- -Any open OS file descriptor; can be obtained from calls to -functions including, but not restricted to, pipe(2), socket(3), -socketpair(3), fcntl(2), dup(2), etc. - - -

-

Returns
-Upon successful completion, a new file descriptor object identifier is -returned. Otherwise, NULL is returned and errno is set -to indicate the error. -

-

Description
-This function creates a new file descriptor object of type -st_netfd_t.

- -Note: Among other things, this function sets a non-blocking -flag on the underlying OS file descriptor. You should not modify this -flag directly. Also, once an st_netfd_t -has been created with a given file descriptor, you should avoid -passing that descriptor to normal I/O or stdio functions. Since the -O_NONBLOCK flag is shared across dup(2), this applies to -dup()'ed file descriptors as well - for instance, if you pass -standard output or standard input to st_netfd_open(), then -you should use st_write() instead of write -or fprintf when writing to standard error as well - since all -three descriptors could point to the same terminal. If necessary, you -can still use write directly if you remember to check -errno for EAGAIN, but fprintf and other -stdio functions should be avoided completely because, at least on -Linux, the stdio library cannot be made to work reliably with -non-blocking files. (This only applies to file descriptors which are -passed to st_netfd_open() or st_netfd_open_socket(), or which are -related to such descriptors through dup(); other file -descriptors are untouched by State Threads.) -

-


-

- -

st_netfd_open_socket()

- -Creates a new file descriptor object from a socket. -

-

Syntax
- -
-#include <st.h>
-
-st_netfd_t st_netfd_open_socket(int osfd);
-
-

-

Parameters
-st_netfd_open_socket() has the following parameters:

-osfd

-An open OS file descriptor which is a socket initially obtained from a -socket(3) or socketpair(3) call. -

-

Returns
-Upon successful completion, a new file descriptor object identifier is -returned. Otherwise, NULL is returned and errno is set -to indicate the error. -

-

Description
-This function creates a new file descriptor object of type -st_netfd_t which represents an open end -point of network communication.

-Unlike the st_netfd_open() function which may be used -on OS file descriptors of any origin, st_netfd_open_socket() must -be used only on sockets. It is slightly more efficient than -st_netfd_open().

-Note: Among other things, this function sets a non-blocking flag -on the underlying OS socket. You should not modify this flag directly. -See st_netfd_open(). -

-


-

- -

st_netfd_free()

- -Frees a file descriptor object without closing the underlying OS file -descriptor. -

-

Syntax
- -
-#include <st.h>
-
-void st_netfd_free(st_netfd_t fd);
-
-

-

Parameters
-st_netfd_free() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t). -

-

Returns
-Nothing. -

-

Description
-This function frees the memory and other resources identified by the -fd parameter without closing the underlying OS file descriptor. -Any non-NULL descriptor-specific data is destroyed by invoking -the specified destructor function (see st_netfd_setspecific()).

A thread should -not free file descriptor objects that are in use by other threads -because it may lead to unpredictable results (e.g., a freed file -descriptor may be reused without other threads knowing that). -

-


-

- -

st_netfd_close()

- -Closes a file descriptor. -

-

Syntax
- -
-#include <st.h>
-
-int st_netfd_close(st_netfd_t fd);
-
-

-

Parameters
-st_netfd_close() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t). -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error. -

-

Description
-This function closes the underlying OS file descriptor, frees the memory and -other resources identified by the fd parameter. Any non-NULL -descriptor-specific data is destroyed by invoking the specified destructor -function (see st_netfd_setspecific()).

-A thread should not close file descriptor objects that are in use by other -threads because it may lead to unpredictable results (e.g., a closed -file descriptor may be reused without other threads knowing that). -

-


-

- -

st_netfd_fileno()

- -Returns an underlying OS file descriptor. -

-

Syntax
- -
-#include <st.h>
-
-int st_netfd_fileno(st_netfd_t fd);
-
-

-

Parameters
-st_netfd_fileno() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t). -

-

Returns
-An underlying OS file descriptor. -

-

Description
-This function returns the integer OS file descriptor associated with the named -file descriptor object. -

-


-

- -

st_netfd_setspecific()

- -Sets per-descriptor private data. -

-

Syntax
- -
-#include <st.h>
-
-void st_netfd_setspecific(st_netfd_t fd, void *value,
-                          void (*destructor)(void *));
-
-

-

Parameters
-st_netfd_setspecific() has the following parameters:

-fd

-A valid file descriptor object identifier (see -st_netfd_t). -

-value

-The per-descriptor private data, or more likely, a pointer to the data which -is being associated with the named file descriptor object. -

-destructor

-Specifies an optional destructor function for the private data associated -with fd. This function can be specified as NULL. -If value is not NULL, then this destructor function will -be called with value as an argument upon freeing the file descriptor -object (see st_netfd_free() and -st_netfd_close()). -

-

Returns
-Nothing. -

-

Description
-This function allows to associate any data with the specified file -descriptor object (network connection). If a non-NULL destructor -function is registered, it will be called at one of two times, as long as -the associated data is not NULL: -
    -
  • when private data is replaced by calling -st_netfd_setspecific() again -
  • upon freeing the file descriptor object (see -st_netfd_free() and -st_netfd_close()) -
-

-


-

- -

st_netfd_getspecific()

- -Retrieves the per-descriptor private data. -

-

Syntax
- -
-#include <st.h>
-
-void *st_netfd_getspecific(st_netfd_t fd);
-
-

-

Parameters
-st_netfd_getspecific() has the following parameters:

-fd

-A valid file descriptor object identifier (see -st_netfd_t). -

-

Returns
-The data associated with the named file descriptor object. If no data is -associated with fd, then NULL is returned. -

-

Description
-This function allows to retrieve the data that was associated with the -specified file descriptor object (see -st_netfd_setspecific()). -

-


-

- -

st_netfd_serialize_accept()

- -Serializes all subsequent accept(3) calls on a specified file -descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-int st_netfd_serialize_accept(st_netfd_t fd);
-
-

-

Parameters
-st_netfd_serialize_accept() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t) which has been successfully created -from a valid listening socket by st_netfd_open() or -st_netfd_open_socket(). -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error. -

-

Description
-On some platforms (e.g., Solaris 2.5 and possibly other SVR4 implementations) -accept(3) calls from different processes on -the same listening socket (see bind(3), listen(3)) must be -serialized. This function causes all subsequent accept(3) calls -made by st_accept() on the specified file descriptor -object to be serialized. -

-st_netfd_serialize_accept() must be called before -creating multiple server processes via fork(2). If the application -does not create multiple processes to accept network connections on -the same listening socket, there is no need to call this function. -

-Deciding whether or not to serialize accepts is tricky. On some -platforms (IRIX, Linux) it's not needed at all and -st_netfd_serialize_accept() is a no-op. On other platforms -it depends on the version of the OS (Solaris 2.6 doesn't need it but -earlier versions do). Serializing accepts does incur a slight -performance penalty so you want to enable it only if necessary. Read -your system's manual pages for accept(2) and select(2) -to see if accept serialization is necessary on your system. -

-st_netfd_serialize_accept() allocates resources that are -freed upon freeing of the specified file descriptor object (see -st_netfd_free() and -st_netfd_close()). -

-


-

- -

st_netfd_poll()

- -Waits for I/O on a single file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-int st_netfd_poll(st_netfd_t fd, int how, st_utime_t timeout);
-
-

-

Parameters
-st_netfd_poll() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t). -

-how

-Specifies I/O events of interest. This parameter can be constructed by -OR-ing any combination of the following event flags which are defined -in the poll.h header file:

- - - - - -
POLLINfd is readable.
POLLOUTfd is is writable.
POLLPRIfd has an exception condition.
-

-timeout

-Amount of time in microseconds the call will block waiting for I/O -to become ready. This parameter is a variable of type -st_utime_t. If this time expires without any -I/O becoming ready, st_netfd_poll() returns an error and sets -errno to ETIME. -Note that timeouts are measured since the -last context switch. -

-

Returns
-If the named file descriptor object is ready for I/O within the specified -amount of time, a value of 0 is returned. Otherwise, a value -of -1 is returned and errno is set to indicate the error: -

- - - - -
EBADFThe underlying OS file descriptor is invalid. -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred without any I/O -becoming ready.
-

-

Description
-This function returns as soon as I/O is ready on the named file -descriptor object or the specified amount of time expires. The -how parameter should be set to the I/O events (readable, -writable, exception, or some combination) that the caller is interested -in. If the value of timeout is ST_UTIME_NO_TIMEOUT -(-1), this function blocks until a requested I/O event occurs -or until the call is interrupted by st_thread_interrupt().

-Despite having an interface like poll(2), this function uses -the same event notification mechanism as the rest of the library. For -instance if an alternative event nofication mechanism was set using st_set_eventsys(), this function uses that -mechanism to check for events.

-Note: if kqueue(2) is used as an alternative event -notification mechanism (see st_set_eventsys()), the POLLPRI -event flag is not supported and st_netfd_poll() will return an error -if it's set (errno will be set to EINVAL). -

-


-

- -

st_accept()

- -Accepts a connection on a specified file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-st_netfd_t st_accept(st_netfd_t fd, struct sockaddr *addr, int *addrlen,
-                     st_utime_t timeout);
-
-

-

Parameters
-st_accept() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t) representing the rendezvous socket -on which the caller is willing to accept new connections. This object has been -created from a valid listening socket by -st_netfd_open() or -st_netfd_open_socket().

-addr

-If this value is non-zero, it is a result parameter that is filled -in with the address of the connecting entity, as known to the communications -layer (see accept(3)).

-addrlen

-This parameter should initially contain the amount of space pointed to by -addr; on return it will contain the actual length (in bytes) of the -address returned (see accept(3)).

-timeout

-A value of type st_utime_t specifying the time -limit in microseconds for completion of the accept operation. -Note that timeouts are measured since the -last context switch. -

-

Returns
-Upon successful completion, a new file descriptor object identifier -representing the newly accepted connection is returned. Otherwise, -NULL is returned and errno is set to indicate the error. -Possible errno values are the same as set by the accept(3) -call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred and no pending -connection was accepted.
-

-

Description
-This function accepts the first connection from the queue of pending -connections and creates a new file descriptor object for the newly -accepted connection. The rendezvous socket can still be used to accept -more connections.

-st_accept() blocks the calling thread until either a new connection -is successfully accepted or an error occurs. If no pending connection can -be accepted before the time limit, this function returns NULL -and sets errno to ETIME. -

-


-

- -

st_connect()

- -Initiates a connection on a specified file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-int st_connect(st_netfd_t fd, struct sockaddr *addr, int addrlen,
-               st_utime_t timeout);
-
-

-

Parameters
-st_connect() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t) representing a socket.

-addr

-A pointer to the address of the peer to which the socket is to be connected. -

-addrlen

-This parameter specifies the amount of space pointed to by addr. -

-timeout

-A value of type st_utime_t specifying the time -limit in microseconds for completion of the connect operation. -Note that timeouts are measured since the -last context switch. -

-

Returns
-Upon successful completion, a value of 0 is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error. Possible errno values are the same as set -by the connect(3) call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred and connection setup -was not completed.
-

-

Description
-This function is usually invoked on a file descriptor object representing -a TCP socket. Upon completion it establishes a TCP connection to the peer. -If the underlying OS socket is not bound, it will be bound to an arbitrary -local address (see connect(3)).

-st_connect() blocks the calling thread until either the connection -is successfully established or an error occurs. If the connection setup -cannot complete before the specified time limit, this function fails with -errno set to ETIME. -

-


-

- -

st_read()

- -Reads data from a specified file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-ssize_t st_read(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout);
-
-

-

Parameters
-st_read() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t).

-buf

-A pointer to a buffer to hold the data read in. On output the buffer -contains the data.

-nbyte

-The size of buf in bytes.

-timeout

-A value of type st_utime_t specifying the time -limit in microseconds for completion of the read operation. -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success a non-negative integer indicating the number of bytes actually -read is returned (a value of 0 means the network connection is -closed or end of file is reached). Otherwise, a value of -1 is -returned and errno is set to indicate the error. -Possible errno values are the same as set by the read(2) -call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred and no data was read. -
-

-

Description
-This function blocks the calling thread until it encounters an end-of-stream -indication, some positive number of bytes (but no more than nbyte -bytes) are read in, a timeout occurs, or an error occurs. -

-


-

- -

st_read_fully()

- -Reads the specified amount of data in full from a file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-ssize_t st_read_fully(st_netfd_t fd, void *buf, size_t nbyte,
-                      st_utime_t timeout);
-
-

-

Parameters
-st_read_fully() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t).

-buf

-A pointer to a buffer to hold the data read in. On output the buffer -contains the data.

-nbyte

-The amount of data to be read in full (in bytes). It must not exceed the -size of buf.

-timeout

-A value of type st_utime_t specifying the -inactivity timeout (in microseconds). -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success a non-negative integer indicating the number of bytes actually -read is returned (a value less than nbyte means the network -connection is closed or end of file is reached). Otherwise, a value of --1 is returned and errno is set to indicate the error. -Possible errno values are the same as set by the read(2) -call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred. -
-

-

Description
-This function blocks the calling thread until the specified amount of data -is read in full, it encounters an end-of-stream indication, a timeout occurs, -or an error occurs. -

-


-

- -

st_read_resid()

- -Reads the specified amount of data in full from a file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-int st_read_resid(st_netfd_t fd, void *buf, size_t *resid,
-		  st_utime_t timeout);
-
-

-

Parameters
-st_read_resid() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t).

-buf

-A pointer to a buffer to hold the data read in. On output the buffer -contains the data.

-resid

-A pointer to a number of bytes. -On entry, the amount of data to be read in full. -It must not exceed the size of buf. -On return, the amount of data remaining to be read. -(A non-zero returned value means some but not all of the data was read.)

-timeout

-A value of type st_utime_t specifying the -inactivity timeout (in microseconds). -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success, zero is returned. *resid may be zero, indicating -a complete read, or non-zero, indicating the network -connection is closed or end of file is reached. -

-Otherwise, a value of -1 is returned, *resid is non-zero, -and errno is set to indicate the error. -Possible errno values are the same as set by the read(2) -call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred. -
-

-

Description
-This function blocks the calling thread until the specified amount of data -is read in full, it encounters an end-of-stream indication, a timeout occurs, -or an error occurs. It differs from st_read_fully() only in that -it allows the caller to know how many bytes were transferred before an error -occurred. -

-


-

- -

st_readv()

- -Reads data from a specified file descriptor object into multiple buffers. -

-

Syntax
- -
-#include <st.h>
-
-ssize_t st_readv(st_netfd_t fd, const struct iovec *iov, int iov_size,
-		 st_utime_t timeout);
-
-

-

Parameters
-st_readv() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t).

-iov

-An array of iovec structures that identify the buffers for holding -the data read in. -On return the buffers contain the data.

-iov_size

-The number of iovec structures in the iov array.

-timeout

-A value of type st_utime_t specifying the time -limit in microseconds for completion of the read operation. -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success a non-negative integer indicating the number of bytes actually -read is returned (a value of 0 means the network connection is -closed or end of file is reached). Otherwise, a value of -1 is -returned and errno is set to indicate the error. -Possible errno values are the same as set by the readv(2) -call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred and no data was read. -
-

-

Description
-This function blocks the calling thread until it encounters an end-of-stream -indication, some positive number of bytes (but no more than fit in the buffers) -are read in, a timeout occurs, or an error occurs. -

-


-

- -

st_readv_resid()

- -Reads the specified amount of data in full from a file descriptor object -into multiple buffers. -

-

Syntax
- -
-#include <st.h>
-
-int st_readv_resid(st_netfd_t fd, struct iovec **iov, int *iov_size,
-		   st_utime_t timeout);
-
-

-

Parameters
-st_readv_resid() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t).

-iov

-A pointer to an array of iovec structures. -On entry, the iovecs identify the buffers for holding the data read in. -On return, the incomplete iovecs. -This function modifies both the pointer and the array to which it points.

-iov_size

-A pointer to a number of iovec structures. -On entry, the number of iovec structures pointed to by *iov. -On return, the number of incomplete or unused iovec structures. -(A non-zero returned value means some but not all of the data was read.)

-timeout

-A value of type st_utime_t specifying the -inactivity timeout (in microseconds). -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success, zero is returned. *iov_size may be zero, indicating -a complete read, or non-zero, indicating the network connection is -closed or end of file is reached. *iov points to the first -iovec after the end of the original array on a complete read, or to the -first incomplete iovec on an incomplete read. -

-Otherwise, a value of -1 is returned, *iov_size is non-zero, -and errno is set to indicate the error. *iov points to the -first unused iovec. -Possible errno values are the same as set by the readv(2) -call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred. -
-

All of the iovecs before *iov are modified such that -iov_base points to the end of the original buffer and -iov_len is zero. -

-

Description
-This function blocks the calling thread until the specified amount of data -is read in full, it encounters an end-of-stream indication, a timeout occurs, -or an error occurs. Like st_read_resid() it blocks the thread until -all of the requested data is read or an error occurs. Use -st_readv() to read up to the requested amount of data. -

-


-

- -

st_write()

- -Writes a buffer of data to a specified file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-ssize_t st_write(st_netfd_t fd, const void *buf, size_t nbyte,
-                 st_utime_t timeout);
-
-

-

Parameters
-st_write() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t).

-buf

-A pointer to the buffer holding the data to be written.

-nbyte

-The amount of data in bytes to be written from the buffer.

-timeout

-A value of type st_utime_t specifying the -inactivity timeout (in microseconds). -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success a non-negative integer equal to nbyte is returned. -Otherwise, a value of -1 is returned and errno is set -to indicate the error. Possible errno values are the same as set -by the write(2) call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred. -
-

-

Description
-This function blocks the calling thread until all the data is written, -a timeout occurs, or the write operation fails. The return value is equal to -either nbyte (on success) or -1 (on failure). Note that if -st_write() returns -1, some data (less than nbyte -bytes) may have been written before an error occurred. -

-


-

- -

st_write_resid()

- -Writes a buffer of data to a specified file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-int st_write_resid(st_netfd_t fd, const void *buf, size_t *resid,
-                   st_utime_t timeout);
-
-

-

Parameters
-st_write_resid() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t).

-buf

-A pointer to the buffer holding the data to be written.

-resid

-A pointer to a number of bytes. -On entry, the amount of data to be written from the buffer. -On return, the amount of data remaining to be written. -(A non-zero returned value means some but not all of the data was written.)

-timeout

-A value of type st_utime_t specifying the -inactivity timeout (in microseconds). -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success, zero is returned and *resid is zero. -Otherwise, a value of -1 is returned, *resid is non-zero, -and errno is set -to indicate the error. Possible errno values are the same as set -by the write(2) call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred. -
-

-

Description
-This function blocks the calling thread until all the data is written, -a timeout occurs, or the write operation fails. It differs from -st_write() only in that it allows the caller to know how many bytes -were transferred before an error occurred. -

-


-

- -

st_writev()

- -Writes data to a specified file descriptor object from multiple buffers. -

-

Syntax
- -
-#include <st.h>
-
-ssize_t st_writev(st_netfd_t fd, const struct iovec *iov, int iov_size,
-                  st_utime_t timeout);
-
-

-

Parameters
-st_writev() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t).

-iov

-An array of iovec structures that describe the buffers to write -from (see writev(2)).

-iov_size

-Number of iovec structures in the iov array.

-timeout

-A value of type st_utime_t specifying the -inactivity timeout (in microseconds). -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success a non-negative integer equal to the sum of all the buffer lengths -is returned. Otherwise, a value of -1 is returned and errno -is set to indicate the error. Possible errno values are the same as -set by the writev(2) call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred. -
-

-

Description
-This function blocks the calling thread until all the data is written, -a timeout occurs, or the write operation fails. The return value is equal to -either the sum of all the buffer lengths (on success) or -1 (on -failure). Note that if st_writev() returns -1, part of the -data may have been written before an error occurred. -

-


-

- -

st_writev_resid()

- -Writes multiple buffers of data to a specified file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-int st_writev_resid(st_netfd_t fd, struct iovec **iov, int *iov_size,
-		    st_utime_t timeout);
-
-

-

Parameters
-st_writev_resid() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t).

-iov

-A pointer to an array of iovec structures. -On entry, the iovecs identify the buffers holding the data to write. -On return, the incomplete iovecs. -This function modifies both the pointer and the array to which it points.

-iov_size

-A pointer to a number of iovec structures. -On entry, the number of iovec structures pointed to by *iov. -On return, the number of incomplete or unused iovec structures. -(A non-zero returned value means some but not all of the data was written.)

-timeout

-A value of type st_utime_t specifying the -inactivity timeout (in microseconds). -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success, zero is returned, *iov_size is zero, and *iov -points to the first iovec after the end of the original array. -Otherwise, a value of -1 is returned, *iov_size is non-zero, -*iov points to the first incomplete iovec, and errno is set -to indicate the error. Possible errno values are the same as set -by the writev(2) call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred. -
-

-All of the iovecs before *iov are modified such that -iov_base points to the end of the original buffer and -iov_len is zero. -

-

Description
-This function blocks the calling thread until all the data is written, -a timeout occurs, or the write operation fails. It differs from -st_writev() only in that it allows the caller to know how many bytes -were transferred before an error occurred. -

-


-

- -

st_recvfrom()

- -Receives bytes from a file descriptor object and stores the sending peer's -address. -

-

Syntax
- -
-#include <st.h>
-
-int st_recvfrom(st_netfd_t fd, void *buf, int len, struct sockaddr *from,
-                int *fromlen, st_utime_t timeout);
-
-

-

Parameters
-st_recvfrom() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t) representing a UDP socket.

-buf

-A pointer to a buffer to hold the data received.

-len

-The size of buf in bytes.

-from

-If this parameter is not a NULL pointer, the source address of the -message is filled in (see recvfrom(3)).

-fromlen

-This is a value-result parameter, initialized to the size of the buffer -associated with from, and modified on return to indicate the actual -size of the address stored there.

-timeout

-A value of type st_utime_t specifying the time -limit in microseconds for completion of the receive operation. -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success a non-negative integer indicating the length of the received -message in bytes is returned. Otherwise, a value of -1 is returned -and errno is set to indicate the error. Possible errno -values are the same as set by the recvfrom(3) call with two -exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred and no data was received. -
-

-

Description
-This function receives up to a specified number of bytes from the specified -file descriptor object representing a UDP socket.

-st_recvfrom() blocks the calling thread until one or more bytes are -transferred, a timeout has occurred, or there is an error. No more than -len bytes will be transferred. -

-


-

- -

st_sendto()

- -Sends bytes to a specified destination. -

-

Syntax
- -
-#include <st.h>
-
-int st_sendto(st_netfd_t fd, const void *msg, int len, struct sockaddr *to,
-              int tolen, st_utime_t timeout);
-
-

-

Parameters
-st_sendto() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t) representing a UDP socket.

-msg

-A pointer to a buffer containing the message to be sent.

-len

-The length of the message to be sent (in bytes).

-to

-A pointer to the address of the destination (see sendto(3)).

-tolen

-This parameter specifies the size of the destination address.

-timeout

-A value of type st_utime_t specifying the time -limit in microseconds for completion of the send operation. -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success a non-negative integer indicating the number of bytes sent is -returned. Otherwise, a value of -1 is returned and errno is -set to indicate the error. Possible errno values are the same as -set by the sendto(3) call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred and no data was sent. -
-

-

Description
-This function sends a specified number of bytes from a file descriptor -object representing a UDP socket to the specified destination address. -If no buffer space is available at the underlying OS socket to hold the -message to be transmitted, then st_sendto() blocks the calling -thread until the space becomes available, a timeout occurs, or an error -occurs. -

-


-

- -

st_recvmsg()

- -Receives a message from a file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-int st_recvmsg(st_netfd_t fd, struct msghdr *msg, int flags,
-               st_utime_t timeout);
-
-

-

Parameters
-st_recvmsg() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t) representing a UDP socket.

-msg

-A pointer to a msghdr structure to describe the data received.

-flags

-Control flags for recvmsg(3).

-timeout

-A value of type st_utime_t specifying the time -limit in microseconds for completion of the receive operation. -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success a non-negative integer indicating the number of bytes received -is returned. Otherwise, a value of -1 is returned -and errno is set to indicate the error. Possible errno -values are the same as set by the recvmsg(3) call with two -exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred and no data was received. -
-

-

Description
-This function receives bytes from the specified file descriptor object -representing a UDP socket. The operation is controlled by the in/out -msg parameter.

-st_recvmsg() blocks the calling thread until one or more bytes are -transferred, a timeout has occurred, or there is an error. -

-


-

- -

st_sendmsg()

- -Sends a message to a file descriptor object. -

-

Syntax
- -
-#include <st.h>
-
-int st_sendmsg(st_netfd_t fd, const struct msghdr *msg, int flags,
-               st_utime_t timeout);
-
-

-

Parameters
-st_sendmsg() has the following parameters:

-fd

-A file descriptor object identifier (see -st_netfd_t) representing a UDP socket.

-msg

-A pointer to a msghdr structure describing the message to be sent.

-flags

-Control flags for sendmsg(3).

-timeout

-A value of type st_utime_t specifying the time -limit in microseconds for completion of the send operation. -Note that timeouts are measured since the -last context switch. -

-

Returns
-On success a non-negative integer indicating the number of bytes sent is -returned. Otherwise, a value of -1 is returned and errno is -set to indicate the error. Possible errno values are the same as -set by the sendmsg(3) call with two exceptions:

- - - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
ETIMEThe timeout occurred and no data was sent. -
-

-

Description
-This function sends bytes to a file descriptor object representing a UDP -socket. The operation is controlled by the msg parameter. -If no buffer space is available at the underlying OS socket to hold the -message to be transmitted, then st_sendmsg() blocks the calling -thread until the space becomes available, a timeout occurs, or an error -occurs. -

-


-

- -

st_open()

- -Opens a file for reading, writing, or both. -

-

Syntax
- -
-#include <st.h>
-
-st_netfd_t st_open(const char *path, int oflags, mode_t mode);
-
-

-

Parameters
-st_open() has the following parameters:

-path

-The pathname of the file to be opened.

-oflags

-File status flags. These are the same flags that are used by the -open(2) system call.

-mode

-Access permission bits of the file mode, if the file is created when -O_CREAT is set in oflags (see open(2)). -

-

Returns
-Upon successful completion, a new file descriptor object identifier is -returned. Otherwise, NULL is returned and errno is set -to indicate the error. -

-

Description
-This function creates a new file descriptor object of type -st_netfd_t for the file with the pathname -path. This object can be freed by -st_netfd_free() or -st_netfd_close().

-The primary purpose of this function is to open FIFOs (named pipes) or -other special files in order to create an end point of communication. -However, it can be used on regular files as well.

-Among other things, this function always sets a non-blocking flag on the -underlying OS file descriptor, so there is no need to include that flag in -oflags. -

-


-

- -

st_poll()

- -Detects when I/O is ready for a set of OS file descriptors. -

-

Syntax
- -
-#include <st.h>
-
-int st_poll(struct pollfd *pds, int npds, st_utime_t timeout);
-
-

-

Parameters
-st_poll() has the following parameters:

-pds

-A pointer to an array of pollfd structures (see poll(2)). -

-npds

-The number of elements in the pds array.

-timeout

-A value of type st_utime_t specifying the -amount of time in microseconds the call will block waiting for I/O -to become ready. If this time expires without any I/O becoming ready, -st_poll() returns zero. -Note that timeouts are measured since the -last context switch. -

-

Returns
-Upon successful completion, a non-negative value is returned. A positive -value indicates the total number of OS file descriptors in pds -that have events. A value of 0 indicates that the call timed out. -Upon failure, a value of -1 is returned and errno is set -to indicate the error:

- - -
EINTRThe current thread was interrupted by -st_thread_interrupt().
-

-If an alternative event notification mechanism has been set by -st_set_eventsys(), other values of -errno could be set upon failure as well. The values -depend on the specific mechanism in use. -

-

Description
-This function returns as soon as I/O is ready on one or more of the specified -OS file descriptors. A count of the number of ready descriptors is returned -unless a timeout occurs, in which case zero is returned.

-The pollfd structure is defined in the poll.h header file -and contains the following members:

-

-    int fd;             /* OS file descriptor */
-    short events;       /* requested events   */
-    short revents;      /* returned events    */
-
-The events field should be set to the I/O events (readable, -writable, exception, or some combination) that the caller is interested in. -On return, the revents field is set to indicate what kind of I/O -is ready on the respective descriptor.

-The events and revents fields are constructed by OR-ing -any combination of the following event flags (defined in poll.h): -

- - - - - - -
POLLINfd is readable.
POLLOUTfd is is writable.
POLLPRIfd has an exception condition.
POLLNVALfd is bad.
-

-The POLLNVAL flag is only valid in the revents field; -it is not used in the events field.

-Despite having an interface like poll(2), this function uses -the same event notification mechanism as the rest of the library. For -instance if an alternative event nofication mechanism was set using st_set_eventsys(), this function uses that -mechanism to check for events.

-Note that unlike the poll(2) call, this function has the -timeout parameter expressed in microseconds. If the value of -timeout is ST_UTIME_NO_TIMEOUT -(-1), this function blocks until a requested I/O -event occurs or until the call is interrupted by -st_thread_interrupt(). -

-Note: if kqueue(2) is used as an alternative event -notification mechanism (see st_set_eventsys()), the POLLPRI -event flag is not supported and st_poll() will return an error -if it's set (errno will be set to EINVAL). -

-


-

- - -

Program Structure

- -

-Generally, the following steps should be followed when writing an application -using the State Threads library: -

-

    -
  1. Configure the library by calling these pre-init functions, if desired. - -
  2. -

    -

  3. Initialize the library by calling st_init().
  4. -

    -

  5. Configure the library by calling these post-init functions, if desired. - -
  6. -

    -

  7. Create resources that will be shared among different processes: - create and bind listening sockets (see socket(3), - bind(3), listen(3), - st_netfd_open_socket(), and possibly - st_netfd_serialize_accept()), - create shared memory segments, inter-process communication (IPC) - channels and synchronization primitives (if any).
  8. -

    -

  9. Create several processes via fork(2). The parent process should - either exit or become a "watchdog" (e.g., it starts a new process when - an existing one crashes, does a cleanup upon application termination, - etc.).
  10. -

    -

  11. In each child process create a pool of threads (see - st_thread_create()) to handle user - connections. Each thread in the pool may accept client connections - (st_accept()), connect to other servers - (st_connect()), perform various network I/O - (st_read(), st_write(), etc.).
  12. -
-

-Note that only State Threads library I/O functions should -be used for a network I/O: any other I/O calls may block the calling process -indefinitely. For example, standard I/O functions (fgets(3), -fread(3), fwrite(3), fprintf(3), etc.) call -read(2) and write(2) directly and therefore should not be -used on sockets or pipes. -

-Also note that for short timeouts to work the program -should do context switches (for example by calling -st_usleep()) on a regular basis. -

-


-

- - -

List of Blocking Functions

- -

-The thread context switch (process state change) can only happen -in a well-known set of blocking functions. -Only the following functions can block the calling thread: -

-

-
st_thread_join()
-
st_sleep()
-
st_usleep()
-
st_cond_wait()
-
st_cond_timedwait()
-
st_mutex_lock()
-
st_netfd_poll()
-
st_accept()
-
st_connect()
-
st_read()
-
st_read_fully()
-
st_read_resid()
-
st_readv()
-
st_readv_resid()
-
st_write()
-
st_write_resid()
-
st_writev()
-
st_writev_resid()
-
st_recvfrom()
-
st_sendto()
-
st_recvmsg()
-
st_sendmsg()
-
st_poll()
-
-

-


-

- - - - diff --git a/trunk/3rdparty/st-srs/docs/st.html b/trunk/3rdparty/st-srs/docs/st.html deleted file mode 100644 index a6b932a819..0000000000 --- a/trunk/3rdparty/st-srs/docs/st.html +++ /dev/null @@ -1,504 +0,0 @@ - - -State Threads for Internet Applications - - -

State Threads for Internet Applications

-

Introduction

-

-State Threads is an application library which provides a -foundation for writing fast and highly scalable Internet Applications -on UNIX-like platforms. It combines the simplicity of the multithreaded -programming paradigm, in which one thread supports each simultaneous -connection, with the performance and scalability of an event-driven -state machine architecture.

- -

1. Definitions

-

- -

1.1 Internet Applications

- -

-An Internet Application (IA) is either a server or client network -application that accepts connections from clients and may or may not -connect to servers. In an IA the arrival or departure of network data -often controls processing (that is, IA is a data-driven application). -For each connection, an IA does some finite amount of work -involving data exchange with its peer, where its peer may be either -a client or a server. -The typical transaction steps of an IA are to accept a connection, -read a request, do some finite and predictable amount of work to -process the request, then write a response to the peer that sent the -request. One example of an IA is a Web server; -the most general example of an IA is a proxy server, because it both -accepts connections from clients and connects to other servers.

-

-We assume that the performance of an IA is constrained by available CPU -cycles rather than network bandwidth or disk I/O (that is, CPU -is a bottleneck resource). -

- - -

1.2 Performance and Scalability

- -

-The performance of an IA is usually evaluated as its -throughput measured in transactions per second or bytes per second (one -can be converted to the other, given the average transaction size). There are -several benchmarks that can be used to measure throughput of Web serving -applications for specific workloads (such as -SPECweb96, -WebStone, -WebBench). -Although there is no common definition for scalability, in general it -expresses the ability of an application to sustain its performance when some -external condition changes. For IAs this external condition is either the -number of clients (also known as "users," "simultaneous connections," or "load -generators") or the underlying hardware system size (number of CPUs, memory -size, and so on). Thus there are two types of scalability: load -scalability and system scalability, respectively. -

-The figure below shows how the throughput of an idealized IA changes with -the increasing number of clients (solid blue line). Initially the throughput -grows linearly (the slope represents the maximal throughput that one client -can provide). Within this initial range, the IA is underutilized and CPUs are -partially idle. Further increase in the number of clients leads to a system -saturation, and the throughput gradually stops growing as all CPUs become fully -utilized. After that point, the throughput stays flat because there are no -more CPU cycles available. -In the real world, however, each simultaneous connection -consumes some computational and memory resources, even when idle, and this -overhead grows with the number of clients. Therefore, the throughput of the -real world IA starts dropping after some point (dashed blue line in the figure -below). The rate at which the throughput drops depends, among other things, on -application design. -

-We say that an application has a good load scalability if it can -sustain its throughput over a wide range of loads. -Interestingly, the SPECweb99 -benchmark somewhat reflects the Web server's load scalability because it -measures the number of clients (load generators) given a mandatory minimal -throughput per client (that is, it measures the server's capacity). -This is unlike SPECweb96 and -other benchmarks that use the throughput as their main metric (see the figure -below). -

-

Figure: Throughput vs. Number of clients -
-

-System scalability is the ability of an application to sustain its -performance per hardware unit (such as a CPU) with the increasing number of -these units. In other words, good system scalability means that doubling the -number of processors will roughly double the application's throughput (dashed -green line). We assume here that the underlying operating system also scales -well. Good system scalability allows you to initially run an application on -the smallest system possible, while retaining the ability to move that -application to a larger system if necessary, without excessive effort or -expense. That is, an application need not be rewritten or even undergo a -major porting effort when changing system size. -

-Although scalability and performance are more important in the case of server -IAs, they should also be considered for some client applications (such as -benchmark load generators). -

- - -

1.3 Concurrency

- -

-Concurrency reflects the parallelism in a system. The two unrelated types -are virtual concurrency and real concurrency. -

    -
  • Virtual (or apparent) concurrency is the number of simultaneous -connections that a system supports. -

    -
  • Real concurrency is the number of hardware devices, including -CPUs, network cards, and disks, that actually allow a system to perform -tasks in parallel. -
-

-An IA must provide virtual concurrency in order to serve many users -simultaneously. -To achieve maximum performance and scalability in doing so, the number of -programming entities than an IA creates to be scheduled by the OS kernel -should be -kept close to (within an order of magnitude of) the real concurrency found on -the system. These programming entities scheduled by the kernel are known as -kernel execution vehicles. Examples of kernel execution vehicles -include Solaris lightweight processes and IRIX kernel threads. -In other words, the number of kernel execution vehicles should be dictated by -the system size and not by the number of simultaneous connections. -

- -

2. Existing Architectures

-

-There are a few different architectures that are commonly used by IAs. -These include the Multi-Process, -Multi-Threaded, and Event-Driven State Machine -architectures. -

- -

2.1 Multi-Process Architecture

- -

-In the Multi-Process (MP) architecture, an individual process is -dedicated to each simultaneous connection. -A process performs all of a transaction's initialization steps -and services a connection completely before moving on to service -a new connection. -

-User sessions in IAs are relatively independent; therefore, no -synchronization between processes handling different connections is -necessary. Because each process has its own private address space, -this architecture is very robust. If a process serving one of the connections -crashes, the other sessions will not be affected. However, to serve many -concurrent connections, an equal number of processes must be employed. -Because processes are kernel entities (and are in fact the heaviest ones), -the number of kernel entities will be at least as large as the number of -concurrent sessions. On most systems, good performance will not be achieved -when more than a few hundred processes are created because of the high -context-switching overhead. In other words, MP applications have poor load -scalability. -

-On the other hand, MP applications have very good system scalability, because -no resources are shared among different processes and there is no -synchronization overhead. -

-The Apache Web Server 1.x ([Reference 1]) uses the MP -architecture on UNIX systems. -

- -

2.2 Multi-Threaded Architecture

- -

-In the Multi-Threaded (MT) architecture, multiple independent threads -of control are employed within a single shared address space. Like a -process in the MP architecture, each thread performs all of a -transaction's initialization steps and services a connection completely -before moving on to service a new connection. -

-Many modern UNIX operating systems implement a many-to-few model when -mapping user-level threads to kernel entities. In this model, an -arbitrarily large number of user-level threads is multiplexed onto a -lesser number of kernel execution vehicles. Kernel execution -vehicles are also known as virtual processors. Whenever a user-level -thread makes a blocking system call, the kernel execution vehicle it is using -will become blocked in the kernel. If there are no other non-blocked kernel -execution vehicles and there are other runnable user-level threads, a new -kernel execution vehicle will be created automatically. This prevents the -application from blocking when it can continue to make useful forward -progress. -

-Because IAs are by nature network I/O driven, all concurrent sessions block on -network I/O at various points. As a result, the number of virtual processors -created in the kernel grows close to the number of user-level threads -(or simultaneous connections). When this occurs, the many-to-few model -effectively degenerates to a one-to-one model. Again, like in -the MP architecture, the number of kernel execution vehicles is dictated by -the number of simultaneous connections rather than by number of CPUs. This -reduces an application's load scalability. However, because kernel threads -(lightweight processes) use fewer resources and are more light-weight than -traditional UNIX processes, an MT application should scale better with load -than an MP application. -

-Unexpectedly, the small number of virtual processors sharing the same address -space in the MT architecture destroys an application's system scalability -because of contention among the threads on various locks. Even if an -application itself is carefully -optimized to avoid lock contention around its own global data (a non-trivial -task), there are still standard library functions and system calls -that use common resources hidden from the application. For example, -on many platforms thread safety of memory allocation routines -(malloc(3), free(3), and so on) is achieved by using a single -global lock. Another example is a per-process file descriptor table. -This common resource table is shared by all kernel execution vehicles within -the same process and must be protected when one modifies it via -certain system calls (such as open(2), close(2), and so on). -In addition to that, maintaining the caches coherent -among CPUs on multiprocessor systems hurts performance when different threads -running on different CPUs modify data items on the same cache line. -

-In order to improve load scalability, some applications employ a different -type of MT architecture: they create one or more thread(s) per task -rather than one thread per connection. For example, one small group -of threads may be responsible for accepting client connections, another -for request processing, and yet another for serving responses. The main -advantage of this architecture is that it eliminates the tight coupling -between the number of threads and number of simultaneous connections. However, -in this architecture, different task-specific thread groups must share common -work queues that must be protected by mutual exclusion locks (a typical -producer-consumer problem). This adds synchronization overhead that causes an -application to perform badly on multiprocessor systems. In other words, in -this architecture, the application's system scalability is sacrificed for the -sake of load scalability. -

-Of course, the usual nightmares of threaded programming, including data -corruption, deadlocks, and race conditions, also make MT architecture (in any -form) non-simplistic to use. -

- - -

2.3 Event-Driven State Machine Architecture

- -

-In the Event-Driven State Machine (EDSM) architecture, a single process -is employed to concurrently process multiple connections. The basics of this -architecture are described in Comer and Stevens -[Reference 2]. -The EDSM architecture performs one basic data-driven step associated with -a particular connection at a time, thus multiplexing many concurrent -connections. The process operates as a state machine that receives an event -and then reacts to it. -

-In the idle state the EDSM calls select(2) or poll(2) to -wait for network I/O events. When a particular file descriptor is ready for -I/O, the EDSM completes the corresponding basic step (usually by invoking a -handler function) and starts the next one. This architecture uses -non-blocking system calls to perform asynchronous network I/O operations. -For more details on non-blocking I/O see Stevens -[Reference 3]. -

-To take advantage of hardware parallelism (real concurrency), multiple -identical processes may be created. This is called Symmetric Multi-Process -EDSM and is used, for example, in the Zeus Web Server -([Reference 4]). To more efficiently multiplex disk I/O, -special "helper" processes may be created. This is called Asymmetric -Multi-Process EDSM and was proposed for Web servers by Druschel -and others [Reference 5]. -

-EDSM is probably the most scalable architecture for IAs. -Because the number of simultaneous connections (virtual concurrency) is -completely decoupled from the number of kernel execution vehicles (processes), -this architecture has very good load scalability. It requires only minimal -user-level resources to create and maintain additional connection. -

-Like MP applications, Multi-Process EDSM has very good system scalability -because no resources are shared among different processes and there is no -synchronization overhead. -

-Unfortunately, the EDSM architecture is monolithic rather than based on the -concept of threads, so new applications generally need to be implemented from -the ground up. In effect, the EDSM architecture simulates threads and their -stacks the hard way. -

- - -

3. State Threads Library

- -

-The State Threads library combines the advantages of all of the above -architectures. The interface preserves the programming simplicity of thread -abstraction, allowing each simultaneous connection to be treated as a separate -thread of execution within a single process. The underlying implementation is -close to the EDSM architecture as the state of each particular concurrent -session is saved in a separate memory segment. -

- -

3.1 State Changes and Scheduling

-

-The state of each concurrent session includes its stack environment -(stack pointer, program counter, CPU registers) and its stack. Conceptually, -a thread context switch can be viewed as a process changing its state. There -are no kernel entities involved other than processes. -Unlike other general-purpose threading libraries, the State Threads library -is fully deterministic. The thread context switch (process state change) can -only happen in a well-known set of functions (at I/O points or at explicit -synchronization points). As a result, process-specific global data does not -have to be protected by mutual exclusion locks in most cases. The entire -application is free to use all the static variables and non-reentrant library -functions it wants, greatly simplifying programming and debugging while -increasing performance. This is somewhat similar to a co-routine model -(co-operatively multitasked threads), except that no explicit yield is needed --- -sooner or later, a thread performs a blocking I/O operation and thus surrenders -control. All threads of execution (simultaneous connections) have the -same priority, so scheduling is non-preemptive, like in the EDSM architecture. -Because IAs are data-driven (processing is limited by the size of network -buffers and data arrival rates), scheduling is non-time-slicing. -

-Only two types of external events are handled by the library's -scheduler, because only these events can be detected by -select(2) or poll(2): I/O events (a file descriptor is ready -for I/O) and time events -(some timeout has expired). However, other types of events (such as -a signal sent to a process) can also be handled by converting them to I/O -events. For example, a signal handling function can perform a write to a pipe -(write(2) is reentrant/asynchronous-safe), thus converting a signal -event to an I/O event. -

-To take advantage of hardware parallelism, as in the EDSM architecture, -multiple processes can be created in either a symmetric or asymmetric manner. -Process management is not in the library's scope but instead is left up to the -application. -

-There are several general-purpose threading libraries that implement a -many-to-one model (many user-level threads to one kernel execution -vehicle), using the same basic techniques as the State Threads library -(non-blocking I/O, event-driven scheduler, and so on). For an example, see GNU -Portable Threads ([Reference 6]). Because they are -general-purpose, these libraries have different objectives than the State -Threads library. The State Threads library is not a general-purpose -threading library, -but rather an application library that targets only certain types of -applications (IAs) in order to achieve the highest possible performance and -scalability for those applications. -

- -

3.2 Scalability

-

-State threads are very lightweight user-level entities, and therefore creating -and maintaining user connections requires minimal resources. An application -using the State Threads library scales very well with the increasing number -of connections. -

-On multiprocessor systems an application should create multiple processes -to take advantage of hardware parallelism. Using multiple separate processes -is the only way to achieve the highest possible system scalability. -This is because duplicating per-process resources is the only way to avoid -significant synchronization overhead on multiprocessor systems. Creating -separate UNIX processes naturally offers resource duplication. Again, -as in the EDSM architecture, there is no connection between the number of -simultaneous connections (which may be very large and changes within a wide -range) and the number of kernel entities (which is usually small and constant). -In other words, the State Threads library makes it possible to multiplex a -large number of simultaneous connections onto a much smaller number of -separate processes, thus allowing an application to scale well with both -the load and system size. -

- -

3.3 Performance

-

-Performance is one of the library's main objectives. The State Threads -library is implemented to minimize the number of system calls and -to make thread creation and context switching as fast as possible. -For example, per-thread signal mask does not exist (unlike -POSIX threads), so there is no need to save and restore a process's -signal mask on every thread context switch. This eliminates two system -calls per context switch. Signal events can be handled much more -efficiently by converting them to I/O events (see above). -

- -

3.4 Portability

-

-The library uses the same general, underlying concepts as the EDSM -architecture, including non-blocking I/O, file descriptors, and -I/O multiplexing. These concepts are available in some form on most -UNIX platforms, making the library very portable across many -flavors of UNIX. There are only a few platform-dependent sections in the -source. -

- -

3.5 State Threads and NSPR

-

-The State Threads library is a derivative of the Netscape Portable -Runtime library (NSPR) [Reference 7]. The primary goal of -NSPR is to provide a platform-independent layer for system facilities, -where system facilities include threads, thread synchronization, and I/O. -Performance and scalability are not the main concern of NSPR. The -State Threads library addresses performance and scalability while -remaining much smaller than NSPR. It is contained in 8 source files -as opposed to more than 400, but provides all the functionality that -is needed to write efficient IAs on UNIX-like platforms. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
NSPRState Threads
Lines of code~150,000~3000
Dynamic library size  
(debug version)
IRIX~700 KB~60 KB
Linux~900 KB~70 KB
-

- -

Conclusion

-

-State Threads is an application library which provides a foundation for -writing Internet Applications. To summarize, it has the -following advantages: -

-

    -
  • It allows the design of fast and highly scalable applications. An -application will scale well with both load and number of CPUs. -

    -

  • It greatly simplifies application programming and debugging because, as a -rule, no mutual exclusion locking is necessary and the entire application is -free to use static variables and non-reentrant library functions. -
-

-The library's main limitation: -

-

    -
  • All I/O operations on sockets must use the State Thread library's I/O -functions because only those functions perform thread scheduling and prevent -the application's processes from blocking. -
-

- -

References

-
    - -
  1. Apache Software Foundation, -http://www.apache.org. - -
  2. Douglas E. Comer, David L. Stevens, Internetworking With TCP/IP, -Vol. III: Client-Server Programming And Applications, Second Edition, -Ch. 8, 12. - -
  3. W. Richard Stevens, UNIX Network Programming, Second Edition, -Vol. 1, Ch. 15. - -
  4. Zeus Technology Limited, -http://www.zeus.co.uk. - -
  5. Peter Druschel, Vivek S. Pai, Willy Zwaenepoel, - -Flash: An Efficient and Portable Web Server. In Proceedings of the -USENIX 1999 Annual Technical Conference, Monterey, CA, June 1999. - -
  6. GNU Portable Threads, -http://www.gnu.org/software/pth/. - -
  7. Netscape Portable Runtime, -http://www.mozilla.org/docs/refList/refNSPR/. -
- -

Other resources covering various architectural issues in IAs

-
    -
  1. Dan Kegel, The C10K problem, -http://www.kegel.com/c10k.html. -
  2. -
  3. James C. Hu, Douglas C. Schmidt, Irfan Pyarali, JAWS: Understanding -High Performance Web Systems, -http://www.cs.wustl.edu/~jxh/research/research.html.
  4. -
-

-


-

- -

Portions created by SGI are Copyright © 2000 -Silicon Graphics, Inc. All rights reserved.
-

- - - - diff --git a/trunk/3rdparty/st-srs/docs/timeout_heap.txt b/trunk/3rdparty/st-srs/docs/timeout_heap.txt deleted file mode 100644 index 1582dc1293..0000000000 --- a/trunk/3rdparty/st-srs/docs/timeout_heap.txt +++ /dev/null @@ -1,60 +0,0 @@ -How the timeout heap works - -As of version 1.5, the State Threads Library represents the queue of -sleeping threads using a heap data structure rather than a sorted -linked list. This improves performance when there is a large number -of sleeping threads, since insertion into a heap takes O(log N) time -while insertion into a sorted list takes O(N) time. For example, in -one test 1000 threads were created, each thread called st_usleep() -with a random time interval, and then all the threads where -immediately interrupted and joined before the sleeps had a chance to -finish. The whole process was repeated 1000 times, for a total of a -million sleep queue insertions and removals. With the old list-based -sleep queue, this test took 100 seconds; now it takes only 12 seconds. - -Heap data structures are typically based on dynamically resized -arrays. However, since the existing ST code base was very nicely -structured around linking the thread objects into pointer-based lists -without the need for any auxiliary data structures, implementing the -heap using a similar nodes-and-pointers based approach seemed more -appropriate for ST than introducing a separate array. - -Thus, the new ST timeout heap works by organizing the existing -_st_thread_t objects in a balanced binary tree, just as they were -previously organized into a doubly-linked, sorted list. The global -_ST_SLEEPQ variable, formerly a linked list head, is now simply a -pointer to the root of this tree, and the root node of the tree is the -thread with the earliest timeout. Each thread object has two child -pointers, "left" and "right", pointing to threads with later timeouts. - -Each node in the tree is numbered with an integer index, corresponding -to the array index in an array-based heap, and the tree is kept fully -balanced and left-adjusted at all times. In other words, the tree -consists of any number of fully populated top levels, followed by a -single bottom level which may be partially populated, such that any -existing nodes form a contiguous block to the left and the spaces for -missing nodes form a contiguous block to the right. For example, if -there are nine threads waiting for a timeout, they are numbered and -arranged in a tree exactly as follows: - - 1 - / \ - 2 3 - / \ / \ - 4 5 6 7 - / \ - 8 9 - -Each node has either no children, only a left child, or both a left -and a right child. Children always time out later than their parents -(this is called the "heap invariant"), but when a node has two -children, their mutual order is unspecified - the left child may time -out before or after the right child. If a node is numbered N, its -left child is numbered 2N, and its right child is numbered 2N+1. - -There is no pointer from a child to its parent; all pointers point -downward. Additions and deletions both work by starting at the root -and traversing the tree towards the leaves, going left or right -according to the binary digits forming the index of the destination -node. As nodes are added or deleted, existing nodes are rearranged to -maintain the heap invariant. diff --git a/trunk/3rdparty/st-srs/event.c b/trunk/3rdparty/st-srs/event.c deleted file mode 100644 index 142882a51e..0000000000 --- a/trunk/3rdparty/st-srs/event.c +++ /dev/null @@ -1,1413 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * Yahoo! Inc. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -#include -#include -#include -#include -#include -#include -#include "common.h" - -#ifdef MD_HAVE_KQUEUE -#include -#endif -#ifdef MD_HAVE_EPOLL -#include -#endif - -#if defined(USE_POLL) && !defined(MD_HAVE_POLL) - /* Force poll usage if explicitly asked for it */ - #define MD_HAVE_POLL -#endif - - -static struct _st_seldata { - fd_set fd_read_set, fd_write_set, fd_exception_set; - int fd_ref_cnts[FD_SETSIZE][3]; - int maxfd; -} *_st_select_data; - -#define _ST_SELECT_MAX_OSFD (_st_select_data->maxfd) -#define _ST_SELECT_READ_SET (_st_select_data->fd_read_set) -#define _ST_SELECT_WRITE_SET (_st_select_data->fd_write_set) -#define _ST_SELECT_EXCEP_SET (_st_select_data->fd_exception_set) -#define _ST_SELECT_READ_CNT(fd) (_st_select_data->fd_ref_cnts[fd][0]) -#define _ST_SELECT_WRITE_CNT(fd) (_st_select_data->fd_ref_cnts[fd][1]) -#define _ST_SELECT_EXCEP_CNT(fd) (_st_select_data->fd_ref_cnts[fd][2]) - - -#ifdef MD_HAVE_POLL -static struct _st_polldata { - struct pollfd *pollfds; - int pollfds_size; - int fdcnt; -} *_st_poll_data; - -#define _ST_POLL_OSFD_CNT (_st_poll_data->fdcnt) -#define _ST_POLLFDS (_st_poll_data->pollfds) -#define _ST_POLLFDS_SIZE (_st_poll_data->pollfds_size) -#endif /* MD_HAVE_POLL */ - - -#ifdef MD_HAVE_KQUEUE -typedef struct _kq_fd_data { - int rd_ref_cnt; - int wr_ref_cnt; - int revents; -} _kq_fd_data_t; - -static struct _st_kqdata { - _kq_fd_data_t *fd_data; - struct kevent *evtlist; - struct kevent *addlist; - struct kevent *dellist; - int fd_data_size; - int evtlist_size; - int addlist_size; - int addlist_cnt; - int dellist_size; - int dellist_cnt; - int kq; - pid_t pid; -} *_st_kq_data; - -#ifndef ST_KQ_MIN_EVTLIST_SIZE -#define ST_KQ_MIN_EVTLIST_SIZE 64 -#endif - -#define _ST_KQ_READ_CNT(fd) (_st_kq_data->fd_data[fd].rd_ref_cnt) -#define _ST_KQ_WRITE_CNT(fd) (_st_kq_data->fd_data[fd].wr_ref_cnt) -#define _ST_KQ_REVENTS(fd) (_st_kq_data->fd_data[fd].revents) -#endif /* MD_HAVE_KQUEUE */ - - -#ifdef MD_HAVE_EPOLL -typedef struct _epoll_fd_data { - int rd_ref_cnt; - int wr_ref_cnt; - int ex_ref_cnt; - int revents; -} _epoll_fd_data_t; - -static struct _st_epolldata { - _epoll_fd_data_t *fd_data; - struct epoll_event *evtlist; - int fd_data_size; - int evtlist_size; - int evtlist_cnt; - int fd_hint; - int epfd; - pid_t pid; -} *_st_epoll_data; - -#ifndef ST_EPOLL_EVTLIST_SIZE - /* Not a limit, just a hint */ - #define ST_EPOLL_EVTLIST_SIZE 4096 -#endif - -#define _ST_EPOLL_READ_CNT(fd) (_st_epoll_data->fd_data[fd].rd_ref_cnt) -#define _ST_EPOLL_WRITE_CNT(fd) (_st_epoll_data->fd_data[fd].wr_ref_cnt) -#define _ST_EPOLL_EXCEP_CNT(fd) (_st_epoll_data->fd_data[fd].ex_ref_cnt) -#define _ST_EPOLL_REVENTS(fd) (_st_epoll_data->fd_data[fd].revents) - -#define _ST_EPOLL_READ_BIT(fd) (_ST_EPOLL_READ_CNT(fd) ? EPOLLIN : 0) -#define _ST_EPOLL_WRITE_BIT(fd) (_ST_EPOLL_WRITE_CNT(fd) ? EPOLLOUT : 0) -#define _ST_EPOLL_EXCEP_BIT(fd) (_ST_EPOLL_EXCEP_CNT(fd) ? EPOLLPRI : 0) -#define _ST_EPOLL_EVENTS(fd) \ - (_ST_EPOLL_READ_BIT(fd)|_ST_EPOLL_WRITE_BIT(fd)|_ST_EPOLL_EXCEP_BIT(fd)) - -#endif /* MD_HAVE_EPOLL */ - -_st_eventsys_t *_st_eventsys = NULL; - - -/***************************************** - * select event system - */ - -ST_HIDDEN int _st_select_init(void) -{ - _st_select_data = (struct _st_seldata *) malloc(sizeof(*_st_select_data)); - if (!_st_select_data) - return -1; - - memset(_st_select_data, 0, sizeof(*_st_select_data)); - _st_select_data->maxfd = -1; - - return 0; -} - -ST_HIDDEN int _st_select_pollset_add(struct pollfd *pds, int npds) -{ - struct pollfd *pd; - struct pollfd *epd = pds + npds; - - /* Do checks up front */ - for (pd = pds; pd < epd; pd++) { - if (pd->fd < 0 || pd->fd >= FD_SETSIZE || !pd->events || - (pd->events & ~(POLLIN | POLLOUT | POLLPRI))) { - errno = EINVAL; - return -1; - } - } - - for (pd = pds; pd < epd; pd++) { - if (pd->events & POLLIN) { - FD_SET(pd->fd, &_ST_SELECT_READ_SET); - _ST_SELECT_READ_CNT(pd->fd)++; - } - if (pd->events & POLLOUT) { - FD_SET(pd->fd, &_ST_SELECT_WRITE_SET); - _ST_SELECT_WRITE_CNT(pd->fd)++; - } - if (pd->events & POLLPRI) { - FD_SET(pd->fd, &_ST_SELECT_EXCEP_SET); - _ST_SELECT_EXCEP_CNT(pd->fd)++; - } - if (_ST_SELECT_MAX_OSFD < pd->fd) - _ST_SELECT_MAX_OSFD = pd->fd; - } - - return 0; -} - -ST_HIDDEN void _st_select_pollset_del(struct pollfd *pds, int npds) -{ - struct pollfd *pd; - struct pollfd *epd = pds + npds; - - for (pd = pds; pd < epd; pd++) { - if (pd->events & POLLIN) { - if (--_ST_SELECT_READ_CNT(pd->fd) == 0) - FD_CLR(pd->fd, &_ST_SELECT_READ_SET); - } - if (pd->events & POLLOUT) { - if (--_ST_SELECT_WRITE_CNT(pd->fd) == 0) - FD_CLR(pd->fd, &_ST_SELECT_WRITE_SET); - } - if (pd->events & POLLPRI) { - if (--_ST_SELECT_EXCEP_CNT(pd->fd) == 0) - FD_CLR(pd->fd, &_ST_SELECT_EXCEP_SET); - } - } -} - -ST_HIDDEN void _st_select_find_bad_fd(void) -{ - _st_clist_t *q; - _st_pollq_t *pq; - int notify; - struct pollfd *pds, *epds; - int pq_max_osfd, osfd; - short events; - - _ST_SELECT_MAX_OSFD = -1; - - for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { - pq = _ST_POLLQUEUE_PTR(q); - notify = 0; - epds = pq->pds + pq->npds; - pq_max_osfd = -1; - - for (pds = pq->pds; pds < epds; pds++) { - osfd = pds->fd; - pds->revents = 0; - if (pds->events == 0) - continue; - if (fcntl(osfd, F_GETFL, 0) < 0) { - pds->revents = POLLNVAL; - notify = 1; - } - if (osfd > pq_max_osfd) { - pq_max_osfd = osfd; - } - } - - if (notify) { - ST_REMOVE_LINK(&pq->links); - pq->on_ioq = 0; - /* - * Decrement the count of descriptors for each descriptor/event - * because this I/O request is being removed from the ioq - */ - for (pds = pq->pds; pds < epds; pds++) { - osfd = pds->fd; - events = pds->events; - if (events & POLLIN) { - if (--_ST_SELECT_READ_CNT(osfd) == 0) { - FD_CLR(osfd, &_ST_SELECT_READ_SET); - } - } - if (events & POLLOUT) { - if (--_ST_SELECT_WRITE_CNT(osfd) == 0) { - FD_CLR(osfd, &_ST_SELECT_WRITE_SET); - } - } - if (events & POLLPRI) { - if (--_ST_SELECT_EXCEP_CNT(osfd) == 0) { - FD_CLR(osfd, &_ST_SELECT_EXCEP_SET); - } - } - } - - if (pq->thread->flags & _ST_FL_ON_SLEEPQ) - _ST_DEL_SLEEPQ(pq->thread); - pq->thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(pq->thread); - } else { - if (_ST_SELECT_MAX_OSFD < pq_max_osfd) - _ST_SELECT_MAX_OSFD = pq_max_osfd; - } - } -} - -ST_HIDDEN void _st_select_dispatch(void) -{ - struct timeval timeout, *tvp; - fd_set r, w, e; - fd_set *rp, *wp, *ep; - int nfd, pq_max_osfd, osfd; - _st_clist_t *q; - st_utime_t min_timeout; - _st_pollq_t *pq; - int notify; - struct pollfd *pds, *epds; - short events, revents; - - /* - * Assignment of fd_sets - */ - r = _ST_SELECT_READ_SET; - w = _ST_SELECT_WRITE_SET; - e = _ST_SELECT_EXCEP_SET; - - rp = &r; - wp = &w; - ep = &e; - - if (_ST_SLEEPQ == NULL) { - tvp = NULL; - } else { - min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : - (_ST_SLEEPQ->due - _ST_LAST_CLOCK); - timeout.tv_sec = (int) (min_timeout / 1000000); - timeout.tv_usec = (int) (min_timeout % 1000000); - tvp = &timeout; - } - - /* Check for I/O operations */ - nfd = select(_ST_SELECT_MAX_OSFD + 1, rp, wp, ep, tvp); - - /* Notify threads that are associated with the selected descriptors */ - if (nfd > 0) { - _ST_SELECT_MAX_OSFD = -1; - for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { - pq = _ST_POLLQUEUE_PTR(q); - notify = 0; - epds = pq->pds + pq->npds; - pq_max_osfd = -1; - - for (pds = pq->pds; pds < epds; pds++) { - osfd = pds->fd; - events = pds->events; - revents = 0; - if ((events & POLLIN) && FD_ISSET(osfd, rp)) { - revents |= POLLIN; - } - if ((events & POLLOUT) && FD_ISSET(osfd, wp)) { - revents |= POLLOUT; - } - if ((events & POLLPRI) && FD_ISSET(osfd, ep)) { - revents |= POLLPRI; - } - pds->revents = revents; - if (revents) { - notify = 1; - } - if (osfd > pq_max_osfd) { - pq_max_osfd = osfd; - } - } - if (notify) { - ST_REMOVE_LINK(&pq->links); - pq->on_ioq = 0; - /* - * Decrement the count of descriptors for each descriptor/event - * because this I/O request is being removed from the ioq - */ - for (pds = pq->pds; pds < epds; pds++) { - osfd = pds->fd; - events = pds->events; - if (events & POLLIN) { - if (--_ST_SELECT_READ_CNT(osfd) == 0) { - FD_CLR(osfd, &_ST_SELECT_READ_SET); - } - } - if (events & POLLOUT) { - if (--_ST_SELECT_WRITE_CNT(osfd) == 0) { - FD_CLR(osfd, &_ST_SELECT_WRITE_SET); - } - } - if (events & POLLPRI) { - if (--_ST_SELECT_EXCEP_CNT(osfd) == 0) { - FD_CLR(osfd, &_ST_SELECT_EXCEP_SET); - } - } - } - - if (pq->thread->flags & _ST_FL_ON_SLEEPQ) - _ST_DEL_SLEEPQ(pq->thread); - pq->thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(pq->thread); - } else { - if (_ST_SELECT_MAX_OSFD < pq_max_osfd) - _ST_SELECT_MAX_OSFD = pq_max_osfd; - } - } - } else if (nfd < 0) { - /* - * It can happen when a thread closes file descriptor - * that is being used by some other thread -- BAD! - */ - if (errno == EBADF) - _st_select_find_bad_fd(); - } -} - -ST_HIDDEN int _st_select_fd_new(int osfd) -{ - if (osfd >= FD_SETSIZE) { - errno = EMFILE; - return -1; - } - - return 0; -} - -ST_HIDDEN int _st_select_fd_close(int osfd) -{ - if (_ST_SELECT_READ_CNT(osfd) || _ST_SELECT_WRITE_CNT(osfd) || - _ST_SELECT_EXCEP_CNT(osfd)) { - errno = EBUSY; - return -1; - } - - return 0; -} - -ST_HIDDEN int _st_select_fd_getlimit(void) -{ - return FD_SETSIZE; -} - -static _st_eventsys_t _st_select_eventsys = { - "select", - ST_EVENTSYS_SELECT, - _st_select_init, - _st_select_dispatch, - _st_select_pollset_add, - _st_select_pollset_del, - _st_select_fd_new, - _st_select_fd_close, - _st_select_fd_getlimit -}; - - -#ifdef MD_HAVE_POLL -/***************************************** - * poll event system - */ - -ST_HIDDEN int _st_poll_init(void) -{ - _st_poll_data = (struct _st_polldata *) malloc(sizeof(*_st_poll_data)); - if (!_st_poll_data) - return -1; - - _ST_POLLFDS = (struct pollfd *) malloc(ST_MIN_POLLFDS_SIZE * - sizeof(struct pollfd)); - if (!_ST_POLLFDS) { - free(_st_poll_data); - _st_poll_data = NULL; - return -1; - } - _ST_POLLFDS_SIZE = ST_MIN_POLLFDS_SIZE; - _ST_POLL_OSFD_CNT = 0; - - return 0; -} - -ST_HIDDEN int _st_poll_pollset_add(struct pollfd *pds, int npds) -{ - struct pollfd *pd; - struct pollfd *epd = pds + npds; - - for (pd = pds; pd < epd; pd++) { - if (pd->fd < 0 || !pd->events) { - errno = EINVAL; - return -1; - } - } - - _ST_POLL_OSFD_CNT += npds; - - return 0; -} - -/* ARGSUSED */ -ST_HIDDEN void _st_poll_pollset_del(struct pollfd *pds, int npds) -{ - _ST_POLL_OSFD_CNT -= npds; - ST_ASSERT(_ST_POLL_OSFD_CNT >= 0); -} - -ST_HIDDEN void _st_poll_dispatch(void) -{ - int timeout, nfd; - _st_clist_t *q; - st_utime_t min_timeout; - _st_pollq_t *pq; - struct pollfd *pds, *epds, *pollfds; - - /* - * Build up the array of struct pollfd to wait on. - * If existing array is not big enough, release it and allocate a new one. - */ - ST_ASSERT(_ST_POLL_OSFD_CNT >= 0); - if (_ST_POLL_OSFD_CNT > _ST_POLLFDS_SIZE) { - free(_ST_POLLFDS); - _ST_POLLFDS = (struct pollfd *) malloc((_ST_POLL_OSFD_CNT + 10) * - sizeof(struct pollfd)); - ST_ASSERT(_ST_POLLFDS != NULL); - _ST_POLLFDS_SIZE = _ST_POLL_OSFD_CNT + 10; - } - pollfds = _ST_POLLFDS; - - /* Gather all descriptors into one array */ - for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { - pq = _ST_POLLQUEUE_PTR(q); - memcpy(pollfds, pq->pds, sizeof(struct pollfd) * pq->npds); - pollfds += pq->npds; - } - ST_ASSERT(pollfds <= _ST_POLLFDS + _ST_POLLFDS_SIZE); - - if (_ST_SLEEPQ == NULL) { - timeout = -1; - } else { - min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : - (_ST_SLEEPQ->due - _ST_LAST_CLOCK); - timeout = (int) (min_timeout / 1000); - } - - /* Check for I/O operations */ - nfd = poll(_ST_POLLFDS, _ST_POLL_OSFD_CNT, timeout); - - /* Notify threads that are associated with the selected descriptors */ - if (nfd > 0) { - pollfds = _ST_POLLFDS; - for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { - pq = _ST_POLLQUEUE_PTR(q); - epds = pollfds + pq->npds; - for (pds = pollfds; pds < epds; pds++) { - if (pds->revents) - break; - } - if (pds < epds) { - memcpy(pq->pds, pollfds, sizeof(struct pollfd) * pq->npds); - ST_REMOVE_LINK(&pq->links); - pq->on_ioq = 0; - - if (pq->thread->flags & _ST_FL_ON_SLEEPQ) - _ST_DEL_SLEEPQ(pq->thread); - pq->thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(pq->thread); - - _ST_POLL_OSFD_CNT -= pq->npds; - ST_ASSERT(_ST_POLL_OSFD_CNT >= 0); - } - pollfds = epds; - } - } -} - -/* ARGSUSED */ -ST_HIDDEN int _st_poll_fd_new(int osfd) -{ - return 0; -} - -/* ARGSUSED */ -ST_HIDDEN int _st_poll_fd_close(int osfd) -{ - /* - * We don't maintain I/O counts for poll event system - * so nothing to check here. - */ - return 0; -} - -ST_HIDDEN int _st_poll_fd_getlimit(void) -{ - /* zero means no specific limit */ - return 0; -} - -static _st_eventsys_t _st_poll_eventsys = { - "poll", - ST_EVENTSYS_POLL, - _st_poll_init, - _st_poll_dispatch, - _st_poll_pollset_add, - _st_poll_pollset_del, - _st_poll_fd_new, - _st_poll_fd_close, - _st_poll_fd_getlimit -}; -#endif /* MD_HAVE_POLL */ - - -#ifdef MD_HAVE_KQUEUE -/***************************************** - * kqueue event system - */ - -ST_HIDDEN int _st_kq_init(void) -{ - int err = 0; - int rv = 0; - - _st_kq_data = (struct _st_kqdata *) calloc(1, sizeof(*_st_kq_data)); - if (!_st_kq_data) - return -1; - - if ((_st_kq_data->kq = kqueue()) < 0) { - err = errno; - rv = -1; - goto cleanup_kq; - } - fcntl(_st_kq_data->kq, F_SETFD, FD_CLOEXEC); - _st_kq_data->pid = getpid(); - - /* - * Allocate file descriptor data array. - * FD_SETSIZE looks like good initial size. - */ - _st_kq_data->fd_data_size = FD_SETSIZE; - _st_kq_data->fd_data = (_kq_fd_data_t *)calloc(_st_kq_data->fd_data_size, sizeof(_kq_fd_data_t)); - if (!_st_kq_data->fd_data) { - err = errno; - rv = -1; - goto cleanup_kq; - } - - /* Allocate event lists */ - _st_kq_data->evtlist_size = ST_KQ_MIN_EVTLIST_SIZE; - _st_kq_data->evtlist = (struct kevent *)malloc(_st_kq_data->evtlist_size * sizeof(struct kevent)); - _st_kq_data->addlist_size = ST_KQ_MIN_EVTLIST_SIZE; - _st_kq_data->addlist = (struct kevent *)malloc(_st_kq_data->addlist_size * sizeof(struct kevent)); - _st_kq_data->dellist_size = ST_KQ_MIN_EVTLIST_SIZE; - _st_kq_data->dellist = (struct kevent *)malloc(_st_kq_data->dellist_size * sizeof(struct kevent)); - if (!_st_kq_data->evtlist || !_st_kq_data->addlist || - !_st_kq_data->dellist) { - err = ENOMEM; - rv = -1; - } - - cleanup_kq: - if (rv < 0) { - if (_st_kq_data->kq >= 0) - close(_st_kq_data->kq); - free(_st_kq_data->fd_data); - free(_st_kq_data->evtlist); - free(_st_kq_data->addlist); - free(_st_kq_data->dellist); - free(_st_kq_data); - _st_kq_data = NULL; - errno = err; - } - - return rv; -} - -ST_HIDDEN int _st_kq_fd_data_expand(int maxfd) -{ - _kq_fd_data_t *ptr; - int n = _st_kq_data->fd_data_size; - - while (maxfd >= n) - n <<= 1; - - ptr = (_kq_fd_data_t *)realloc(_st_kq_data->fd_data, n * sizeof(_kq_fd_data_t)); - if (!ptr) - return -1; - - memset(ptr + _st_kq_data->fd_data_size, 0, (n - _st_kq_data->fd_data_size) * sizeof(_kq_fd_data_t)); - - _st_kq_data->fd_data = ptr; - _st_kq_data->fd_data_size = n; - - return 0; -} - -ST_HIDDEN int _st_kq_addlist_expand(int avail) -{ - struct kevent *ptr; - int n = _st_kq_data->addlist_size; - - while (avail > n - _st_kq_data->addlist_cnt) - n <<= 1; - - ptr = (struct kevent *)realloc(_st_kq_data->addlist, n * sizeof(struct kevent)); - if (!ptr) - return -1; - - _st_kq_data->addlist = ptr; - _st_kq_data->addlist_size = n; - - /* - * Try to expand the result event list too - * (although we don't have to do it). - */ - ptr = (struct kevent *)realloc(_st_kq_data->evtlist, n * sizeof(struct kevent)); - if (ptr) { - _st_kq_data->evtlist = ptr; - _st_kq_data->evtlist_size = n; - } - - return 0; -} - -ST_HIDDEN void _st_kq_addlist_add(const struct kevent *kev) -{ - ST_ASSERT(_st_kq_data->addlist_cnt < _st_kq_data->addlist_size); - memcpy(_st_kq_data->addlist + _st_kq_data->addlist_cnt, kev, sizeof(struct kevent)); - _st_kq_data->addlist_cnt++; -} - -ST_HIDDEN void _st_kq_dellist_add(const struct kevent *kev) -{ - int n = _st_kq_data->dellist_size; - - if (_st_kq_data->dellist_cnt >= n) { - struct kevent *ptr; - - n <<= 1; - ptr = (struct kevent *)realloc(_st_kq_data->dellist, n * sizeof(struct kevent)); - if (!ptr) { - /* See comment in _st_kq_pollset_del() */ - return; - } - - _st_kq_data->dellist = ptr; - _st_kq_data->dellist_size = n; - } - - memcpy(_st_kq_data->dellist + _st_kq_data->dellist_cnt, kev, sizeof(struct kevent)); - _st_kq_data->dellist_cnt++; -} - -ST_HIDDEN int _st_kq_pollset_add(struct pollfd *pds, int npds) -{ - struct kevent kev; - struct pollfd *pd; - struct pollfd *epd = pds + npds; - - /* - * Pollset adding is "atomic". That is, either it succeeded for - * all descriptors in the set or it failed. It means that we - * need to do all the checks up front so we don't have to - * "unwind" if adding of one of the descriptors failed. - */ - for (pd = pds; pd < epd; pd++) { - /* POLLIN and/or POLLOUT must be set, but nothing else */ - if (pd->fd < 0 || !pd->events || (pd->events & ~(POLLIN | POLLOUT))) { - errno = EINVAL; - return -1; - } - if (pd->fd >= _st_kq_data->fd_data_size && - _st_kq_fd_data_expand(pd->fd) < 0) - return -1; - } - - /* - * Make sure we have enough room in the addlist for twice as many - * descriptors as in the pollset (for both READ and WRITE filters). - */ - npds <<= 1; - if (npds > _st_kq_data->addlist_size - _st_kq_data->addlist_cnt && _st_kq_addlist_expand(npds) < 0) - return -1; - - for (pd = pds; pd < epd; pd++) { - if ((pd->events & POLLIN) && (_ST_KQ_READ_CNT(pd->fd)++ == 0)) { - memset(&kev, 0, sizeof(kev)); - kev.ident = pd->fd; - kev.filter = EVFILT_READ; -#ifdef NOTE_EOF - /* Make it behave like select() and poll() */ - kev.fflags = NOTE_EOF; -#endif - kev.flags = (EV_ADD | EV_ONESHOT); - _st_kq_addlist_add(&kev); - } - if ((pd->events & POLLOUT) && (_ST_KQ_WRITE_CNT(pd->fd)++ == 0)) { - memset(&kev, 0, sizeof(kev)); - kev.ident = pd->fd; - kev.filter = EVFILT_WRITE; - kev.flags = (EV_ADD | EV_ONESHOT); - _st_kq_addlist_add(&kev); - } - } - - return 0; -} - -ST_HIDDEN void _st_kq_pollset_del(struct pollfd *pds, int npds) -{ - struct kevent kev; - struct pollfd *pd; - struct pollfd *epd = pds + npds; - - /* - * It's OK if deleting fails because a descriptor will either be - * closed or fire only once (we set EV_ONESHOT flag). - */ - _st_kq_data->dellist_cnt = 0; - for (pd = pds; pd < epd; pd++) { - if ((pd->events & POLLIN) && (--_ST_KQ_READ_CNT(pd->fd) == 0)) { - memset(&kev, 0, sizeof(kev)); - kev.ident = pd->fd; - kev.filter = EVFILT_READ; - kev.flags = EV_DELETE; - _st_kq_dellist_add(&kev); - } - if ((pd->events & POLLOUT) && (--_ST_KQ_WRITE_CNT(pd->fd) == 0)) { - memset(&kev, 0, sizeof(kev)); - kev.ident = pd->fd; - kev.filter = EVFILT_WRITE; - kev.flags = EV_DELETE; - _st_kq_dellist_add(&kev); - } - } - - if (_st_kq_data->dellist_cnt > 0) { - /* - * We do "synchronous" kqueue deletes to avoid deleting - * closed descriptors and other possible problems. - */ - int rv; - do { - /* This kevent() won't block since result list size is 0 */ - rv = kevent(_st_kq_data->kq, _st_kq_data->dellist, _st_kq_data->dellist_cnt, NULL, 0, NULL); - } while (rv < 0 && errno == EINTR); - } -} - -ST_HIDDEN void _st_kq_dispatch(void) -{ - struct timespec timeout, *tsp; - struct kevent kev; - st_utime_t min_timeout; - _st_clist_t *q; - _st_pollq_t *pq; - struct pollfd *pds, *epds; - int nfd, i, osfd, notify, filter; - short events, revents; - - if (_ST_SLEEPQ == NULL) { - tsp = NULL; - } else { - min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : (_ST_SLEEPQ->due - _ST_LAST_CLOCK); - timeout.tv_sec = (time_t) (min_timeout / 1000000); - timeout.tv_nsec = (long) ((min_timeout % 1000000) * 1000); - tsp = &timeout; - } - - retry_kevent: - /* Check for I/O operations */ - nfd = kevent(_st_kq_data->kq, - _st_kq_data->addlist, _st_kq_data->addlist_cnt, - _st_kq_data->evtlist, _st_kq_data->evtlist_size, tsp); - - _st_kq_data->addlist_cnt = 0; - - if (nfd > 0) { - for (i = 0; i < nfd; i++) { - osfd = _st_kq_data->evtlist[i].ident; - filter = _st_kq_data->evtlist[i].filter; - - if (filter == EVFILT_READ) { - _ST_KQ_REVENTS(osfd) |= POLLIN; - } else if (filter == EVFILT_WRITE) { - _ST_KQ_REVENTS(osfd) |= POLLOUT; - } - if (_st_kq_data->evtlist[i].flags & EV_ERROR) { - if (_st_kq_data->evtlist[i].data == EBADF) { - _ST_KQ_REVENTS(osfd) |= POLLNVAL; - } else { - _ST_KQ_REVENTS(osfd) |= POLLERR; - } - } - } - - _st_kq_data->dellist_cnt = 0; - - for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { - pq = _ST_POLLQUEUE_PTR(q); - notify = 0; - epds = pq->pds + pq->npds; - - for (pds = pq->pds; pds < epds; pds++) { - osfd = pds->fd; - events = pds->events; - revents = (short)(_ST_KQ_REVENTS(osfd) & ~(POLLIN | POLLOUT)); - if ((events & POLLIN) && (_ST_KQ_REVENTS(osfd) & POLLIN)) { - revents |= POLLIN; - } - if ((events & POLLOUT) && (_ST_KQ_REVENTS(osfd) & POLLOUT)) { - revents |= POLLOUT; - } - pds->revents = revents; - if (revents) { - notify = 1; - } - } - if (notify) { - ST_REMOVE_LINK(&pq->links); - pq->on_ioq = 0; - for (pds = pq->pds; pds < epds; pds++) { - osfd = pds->fd; - events = pds->events; - /* - * We set EV_ONESHOT flag so we only need to delete - * descriptor if it didn't fire. - */ - if ((events & POLLIN) && (--_ST_KQ_READ_CNT(osfd) == 0) && ((_ST_KQ_REVENTS(osfd) & POLLIN) == 0)) { - memset(&kev, 0, sizeof(kev)); - kev.ident = osfd; - kev.filter = EVFILT_READ; - kev.flags = EV_DELETE; - _st_kq_dellist_add(&kev); - } - if ((events & POLLOUT) && (--_ST_KQ_WRITE_CNT(osfd) == 0) && ((_ST_KQ_REVENTS(osfd) & POLLOUT) == 0)) { - memset(&kev, 0, sizeof(kev)); - kev.ident = osfd; - kev.filter = EVFILT_WRITE; - kev.flags = EV_DELETE; - _st_kq_dellist_add(&kev); - } - } - - if (pq->thread->flags & _ST_FL_ON_SLEEPQ) - _ST_DEL_SLEEPQ(pq->thread); - pq->thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(pq->thread); - } - } - - if (_st_kq_data->dellist_cnt > 0) { - int rv; - do { - /* This kevent() won't block since result list size is 0 */ - rv = kevent(_st_kq_data->kq, _st_kq_data->dellist, _st_kq_data->dellist_cnt, NULL, 0, NULL); - } while (rv < 0 && errno == EINTR); - } - - for (i = 0; i < nfd; i++) { - osfd = _st_kq_data->evtlist[i].ident; - _ST_KQ_REVENTS(osfd) = 0; - } - - } else if (nfd < 0) { - if (errno == EBADF && _st_kq_data->pid != getpid()) { - /* We probably forked, reinitialize kqueue */ - if ((_st_kq_data->kq = kqueue()) < 0) { - /* There is nothing we can do here, will retry later */ - return; - } - fcntl(_st_kq_data->kq, F_SETFD, FD_CLOEXEC); - _st_kq_data->pid = getpid(); - /* Re-register all descriptors on ioq with new kqueue */ - memset(_st_kq_data->fd_data, 0, _st_kq_data->fd_data_size * sizeof(_kq_fd_data_t)); - for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { - pq = _ST_POLLQUEUE_PTR(q); - _st_kq_pollset_add(pq->pds, pq->npds); - } - goto retry_kevent; - } - } -} - -ST_HIDDEN int _st_kq_fd_new(int osfd) -{ - if (osfd >= _st_kq_data->fd_data_size && _st_kq_fd_data_expand(osfd) < 0) - return -1; - - return 0; -} - -ST_HIDDEN int _st_kq_fd_close(int osfd) -{ - if (_ST_KQ_READ_CNT(osfd) || _ST_KQ_WRITE_CNT(osfd)) { - errno = EBUSY; - return -1; - } - - return 0; -} - -ST_HIDDEN int _st_kq_fd_getlimit(void) -{ - /* zero means no specific limit */ - return 0; -} - -static _st_eventsys_t _st_kq_eventsys = { - "kqueue", - ST_EVENTSYS_ALT, - _st_kq_init, - _st_kq_dispatch, - _st_kq_pollset_add, - _st_kq_pollset_del, - _st_kq_fd_new, - _st_kq_fd_close, - _st_kq_fd_getlimit -}; -#endif /* MD_HAVE_KQUEUE */ - - -#ifdef MD_HAVE_EPOLL -/***************************************** - * epoll event system - */ - -ST_HIDDEN int _st_epoll_init(void) -{ - int fdlim; - int err = 0; - int rv = 0; - - _st_epoll_data = (struct _st_epolldata *) calloc(1, sizeof(*_st_epoll_data)); - if (!_st_epoll_data) - return -1; - - fdlim = st_getfdlimit(); - _st_epoll_data->fd_hint = (fdlim > 0 && fdlim < ST_EPOLL_EVTLIST_SIZE) ? fdlim : ST_EPOLL_EVTLIST_SIZE; - - if ((_st_epoll_data->epfd = epoll_create(_st_epoll_data->fd_hint)) < 0) { - err = errno; - rv = -1; - goto cleanup_epoll; - } - fcntl(_st_epoll_data->epfd, F_SETFD, FD_CLOEXEC); - _st_epoll_data->pid = getpid(); - - /* Allocate file descriptor data array */ - _st_epoll_data->fd_data_size = _st_epoll_data->fd_hint; - _st_epoll_data->fd_data = (_epoll_fd_data_t *)calloc(_st_epoll_data->fd_data_size, sizeof(_epoll_fd_data_t)); - if (!_st_epoll_data->fd_data) { - err = errno; - rv = -1; - goto cleanup_epoll; - } - - /* Allocate event lists */ - _st_epoll_data->evtlist_size = _st_epoll_data->fd_hint; - _st_epoll_data->evtlist = (struct epoll_event *)malloc(_st_epoll_data->evtlist_size * sizeof(struct epoll_event)); - if (!_st_epoll_data->evtlist) { - err = errno; - rv = -1; - } - - cleanup_epoll: - if (rv < 0) { - if (_st_epoll_data->epfd >= 0) - close(_st_epoll_data->epfd); - free(_st_epoll_data->fd_data); - free(_st_epoll_data->evtlist); - free(_st_epoll_data); - _st_epoll_data = NULL; - errno = err; - } - - return rv; -} - -ST_HIDDEN int _st_epoll_fd_data_expand(int maxfd) -{ - _epoll_fd_data_t *ptr; - int n = _st_epoll_data->fd_data_size; - - while (maxfd >= n) - n <<= 1; - - ptr = (_epoll_fd_data_t *)realloc(_st_epoll_data->fd_data, n * sizeof(_epoll_fd_data_t)); - if (!ptr) - return -1; - - memset(ptr + _st_epoll_data->fd_data_size, 0, (n - _st_epoll_data->fd_data_size) * sizeof(_epoll_fd_data_t)); - - _st_epoll_data->fd_data = ptr; - _st_epoll_data->fd_data_size = n; - - return 0; -} - -ST_HIDDEN void _st_epoll_evtlist_expand(void) -{ - struct epoll_event *ptr; - int n = _st_epoll_data->evtlist_size; - - while (_st_epoll_data->evtlist_cnt > n) - n <<= 1; - - ptr = (struct epoll_event *)realloc(_st_epoll_data->evtlist, n * sizeof(struct epoll_event)); - if (ptr) { - _st_epoll_data->evtlist = ptr; - _st_epoll_data->evtlist_size = n; - } -} - -ST_HIDDEN void _st_epoll_pollset_del(struct pollfd *pds, int npds) -{ - struct epoll_event ev; - struct pollfd *pd; - struct pollfd *epd = pds + npds; - int old_events, events, op; - - /* - * It's more or less OK if deleting fails because a descriptor - * will either be closed or deleted in dispatch function after - * it fires. - */ - for (pd = pds; pd < epd; pd++) { - old_events = _ST_EPOLL_EVENTS(pd->fd); - - if (pd->events & POLLIN) - _ST_EPOLL_READ_CNT(pd->fd)--; - if (pd->events & POLLOUT) - _ST_EPOLL_WRITE_CNT(pd->fd)--; - if (pd->events & POLLPRI) - _ST_EPOLL_EXCEP_CNT(pd->fd)--; - - events = _ST_EPOLL_EVENTS(pd->fd); - /* - * The _ST_EPOLL_REVENTS check below is needed so we can use - * this function inside dispatch(). Outside of dispatch() - * _ST_EPOLL_REVENTS is always zero for all descriptors. - */ - if (events != old_events && _ST_EPOLL_REVENTS(pd->fd) == 0) { - op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; - ev.events = events; - ev.data.fd = pd->fd; - if (epoll_ctl(_st_epoll_data->epfd, op, pd->fd, &ev) == 0 && op == EPOLL_CTL_DEL) { - _st_epoll_data->evtlist_cnt--; - } - } - } -} - -ST_HIDDEN int _st_epoll_pollset_add(struct pollfd *pds, int npds) -{ - struct epoll_event ev; - int i, fd; - int old_events, events, op; - - /* Do as many checks as possible up front */ - for (i = 0; i < npds; i++) { - fd = pds[i].fd; - if (fd < 0 || !pds[i].events || - (pds[i].events & ~(POLLIN | POLLOUT | POLLPRI))) { - errno = EINVAL; - return -1; - } - if (fd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(fd) < 0) - return -1; - } - - for (i = 0; i < npds; i++) { - fd = pds[i].fd; - old_events = _ST_EPOLL_EVENTS(fd); - - if (pds[i].events & POLLIN) - _ST_EPOLL_READ_CNT(fd)++; - if (pds[i].events & POLLOUT) - _ST_EPOLL_WRITE_CNT(fd)++; - if (pds[i].events & POLLPRI) - _ST_EPOLL_EXCEP_CNT(fd)++; - - events = _ST_EPOLL_EVENTS(fd); - if (events != old_events) { - op = old_events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; - ev.events = events; - ev.data.fd = fd; - if (epoll_ctl(_st_epoll_data->epfd, op, fd, &ev) < 0 && (op != EPOLL_CTL_ADD || errno != EEXIST)) - break; - if (op == EPOLL_CTL_ADD) { - _st_epoll_data->evtlist_cnt++; - if (_st_epoll_data->evtlist_cnt > _st_epoll_data->evtlist_size) - _st_epoll_evtlist_expand(); - } - } - } - - if (i < npds) { - /* Error */ - int err = errno; - /* Unroll the state */ - _st_epoll_pollset_del(pds, i + 1); - errno = err; - return -1; - } - - return 0; -} - -ST_HIDDEN void _st_epoll_dispatch(void) -{ - st_utime_t min_timeout; - _st_clist_t *q; - _st_pollq_t *pq; - struct pollfd *pds, *epds; - struct epoll_event ev; - int timeout, nfd, i, osfd, notify; - int events, op; - short revents; - - if (_ST_SLEEPQ == NULL) { - timeout = -1; - } else { - min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : (_ST_SLEEPQ->due - _ST_LAST_CLOCK); - timeout = (int) (min_timeout / 1000); - } - - if (_st_epoll_data->pid != getpid()) { - /* We probably forked, reinitialize epoll set */ - close(_st_epoll_data->epfd); - _st_epoll_data->epfd = epoll_create(_st_epoll_data->fd_hint); - if (_st_epoll_data->epfd < 0) { - /* There is nothing we can do here, will retry later */ - return; - } - fcntl(_st_epoll_data->epfd, F_SETFD, FD_CLOEXEC); - _st_epoll_data->pid = getpid(); - - /* Put all descriptors on ioq into new epoll set */ - memset(_st_epoll_data->fd_data, 0, _st_epoll_data->fd_data_size * sizeof(_epoll_fd_data_t)); - _st_epoll_data->evtlist_cnt = 0; - for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { - pq = _ST_POLLQUEUE_PTR(q); - _st_epoll_pollset_add(pq->pds, pq->npds); - } - } - - /* Check for I/O operations */ - nfd = epoll_wait(_st_epoll_data->epfd, _st_epoll_data->evtlist, _st_epoll_data->evtlist_size, timeout); - - if (nfd > 0) { - for (i = 0; i < nfd; i++) { - osfd = _st_epoll_data->evtlist[i].data.fd; - _ST_EPOLL_REVENTS(osfd) = _st_epoll_data->evtlist[i].events; - if (_ST_EPOLL_REVENTS(osfd) & (EPOLLERR | EPOLLHUP)) { - /* Also set I/O bits on error */ - _ST_EPOLL_REVENTS(osfd) |= _ST_EPOLL_EVENTS(osfd); - } - } - - for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { - pq = _ST_POLLQUEUE_PTR(q); - notify = 0; - epds = pq->pds + pq->npds; - - for (pds = pq->pds; pds < epds; pds++) { - if (_ST_EPOLL_REVENTS(pds->fd) == 0) { - pds->revents = 0; - continue; - } - osfd = pds->fd; - events = pds->events; - revents = 0; - if ((events & POLLIN) && (_ST_EPOLL_REVENTS(osfd) & EPOLLIN)) - revents |= POLLIN; - if ((events & POLLOUT) && (_ST_EPOLL_REVENTS(osfd) & EPOLLOUT)) - revents |= POLLOUT; - if ((events & POLLPRI) && (_ST_EPOLL_REVENTS(osfd) & EPOLLPRI)) - revents |= POLLPRI; - if (_ST_EPOLL_REVENTS(osfd) & EPOLLERR) - revents |= POLLERR; - if (_ST_EPOLL_REVENTS(osfd) & EPOLLHUP) - revents |= POLLHUP; - - pds->revents = revents; - if (revents) { - notify = 1; - } - } - if (notify) { - ST_REMOVE_LINK(&pq->links); - pq->on_ioq = 0; - /* - * Here we will only delete/modify descriptors that - * didn't fire (see comments in _st_epoll_pollset_del()). - */ - _st_epoll_pollset_del(pq->pds, pq->npds); - - if (pq->thread->flags & _ST_FL_ON_SLEEPQ) - _ST_DEL_SLEEPQ(pq->thread); - pq->thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(pq->thread); - } - } - - for (i = 0; i < nfd; i++) { - /* Delete/modify descriptors that fired */ - osfd = _st_epoll_data->evtlist[i].data.fd; - _ST_EPOLL_REVENTS(osfd) = 0; - events = _ST_EPOLL_EVENTS(osfd); - op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; - ev.events = events; - ev.data.fd = osfd; - if (epoll_ctl(_st_epoll_data->epfd, op, osfd, &ev) == 0 && op == EPOLL_CTL_DEL) { - _st_epoll_data->evtlist_cnt--; - } - } - } -} - -ST_HIDDEN int _st_epoll_fd_new(int osfd) -{ - if (osfd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(osfd) < 0) - return -1; - - return 0; -} - -ST_HIDDEN int _st_epoll_fd_close(int osfd) -{ - if (_ST_EPOLL_READ_CNT(osfd) || _ST_EPOLL_WRITE_CNT(osfd) || _ST_EPOLL_EXCEP_CNT(osfd)) { - errno = EBUSY; - return -1; - } - - return 0; -} - -ST_HIDDEN int _st_epoll_fd_getlimit(void) -{ - /* zero means no specific limit */ - return 0; -} - -/* - * Check if epoll functions are just stubs. - */ -ST_HIDDEN int _st_epoll_is_supported(void) -{ - struct epoll_event ev; - - ev.events = EPOLLIN; - ev.data.ptr = NULL; - /* Guaranteed to fail */ - epoll_ctl(-1, EPOLL_CTL_ADD, -1, &ev); - - return (errno != ENOSYS); -} - -static _st_eventsys_t _st_epoll_eventsys = { - "epoll", - ST_EVENTSYS_ALT, - _st_epoll_init, - _st_epoll_dispatch, - _st_epoll_pollset_add, - _st_epoll_pollset_del, - _st_epoll_fd_new, - _st_epoll_fd_close, - _st_epoll_fd_getlimit -}; -#endif /* MD_HAVE_EPOLL */ - - -/***************************************** - * Public functions - */ - -int st_set_eventsys(int eventsys) -{ - if (_st_eventsys) { - errno = EBUSY; - return -1; - } - - switch (eventsys) { - case ST_EVENTSYS_DEFAULT: -#ifdef USE_POLL - _st_eventsys = &_st_poll_eventsys; -#else - _st_eventsys = &_st_select_eventsys; -#endif - break; - case ST_EVENTSYS_SELECT: - _st_eventsys = &_st_select_eventsys; - break; -#ifdef MD_HAVE_POLL - case ST_EVENTSYS_POLL: - _st_eventsys = &_st_poll_eventsys; - break; -#endif - case ST_EVENTSYS_ALT: -#if defined (MD_HAVE_KQUEUE) - _st_eventsys = &_st_kq_eventsys; -#elif defined (MD_HAVE_EPOLL) - if (_st_epoll_is_supported()) - _st_eventsys = &_st_epoll_eventsys; -#endif - break; - default: - errno = EINVAL; - return -1; - } - - return 0; -} - -int st_get_eventsys(void) -{ - return _st_eventsys ? _st_eventsys->val : -1; -} - -const char *st_get_eventsys_name(void) -{ - return _st_eventsys ? _st_eventsys->name : ""; -} - diff --git a/trunk/3rdparty/st-srs/examples/Makefile b/trunk/3rdparty/st-srs/examples/Makefile deleted file mode 100644 index 31c0a6e240..0000000000 --- a/trunk/3rdparty/st-srs/examples/Makefile +++ /dev/null @@ -1,115 +0,0 @@ -# -# Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. -# All Rights Reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of Silicon Graphics, Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -########################## -# Supported OSes: -# -# AIX -# FREEBSD -# HPUX -# HPUX_64 -# IRIX -# IRIX_64 -# LINUX -# LINUX_IA64 -# NETBSD -# OPENBSD -# OSF1 -# SOLARIS -# SOLARIS_64 - -########################## - -CC = cc - -SHELL = /bin/sh -ECHO = /bin/echo - -DEPTH = .. -BUILD = -TARGETDIR = - -DEFINES = -CFLAGS = -OTHER_FLAGS = - -OBJDIR = $(DEPTH)/$(TARGETDIR) -INCDIR = $(DEPTH)/$(TARGETDIR) -LIBST = $(OBJDIR)/libst.a -HEADER = $(INCDIR)/st.h - -LIBRESOLV = -EXTRALIBS = - -ifeq ($(OS),) -EXAMPLES = unknown -else -EXAMPLES = $(OBJDIR)/lookupdns $(OBJDIR)/proxy $(OBJDIR)/server -endif - - -########################## -# Platform section. -# - -ifeq (DARWIN, $(findstring DARWIN, $(OS))) -LIBRESOLV = -lresolv -endif - -ifeq (LINUX, $(findstring LINUX, $(OS))) -LIBRESOLV = -lresolv -endif - -ifeq (SOLARIS, $(findstring SOLARIS, $(OS))) -LIBRESOLV = -lresolv -EXTRALIBS = -lsocket -lnsl -endif - -# -# End of platform section. -########################## - - -all: $(EXAMPLES) - -$(OBJDIR)/lookupdns: lookupdns.c $(OBJDIR)/res.o $(LIBST) $(HEADER) - $(CC) $(CFLAGS) -I$(INCDIR) lookupdns.c $(OBJDIR)/res.o $(LIBST) $(LIBRESOLV) $(EXTRALIBS) -o $@ - -$(OBJDIR)/proxy: proxy.c $(LIBST) $(HEADER) - $(CC) $(CFLAGS) -I$(INCDIR) proxy.c $(LIBST) $(EXTRALIBS) -o $@ - -$(OBJDIR)/server: server.c $(OBJDIR)/error.o $(LIBST) $(HEADER) - $(CC) $(CFLAGS) -I$(INCDIR) server.c $(OBJDIR)/error.o $(LIBST) $(EXTRALIBS) -o $@ - -$(OBJDIR)/%.o: %.c - $(CC) $(CFLAGS) -I$(INCDIR) -c $< -o $@ - -.DEFAULT: - @cd $(DEPTH); $(MAKE) $@ - diff --git a/trunk/3rdparty/st-srs/examples/README b/trunk/3rdparty/st-srs/examples/README deleted file mode 100644 index 646d4f6236..0000000000 --- a/trunk/3rdparty/st-srs/examples/README +++ /dev/null @@ -1,98 +0,0 @@ -Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. -All Rights Reserved. - - -This directory contains three example programs. - - ---------------------------------------------------------------------------- - -PROGRAM - - lookupdns - -FILES - - lookupdns.c - res.c - -USAGE - - lookupdns [] ... - -DESCRIPTION - - This program performs asynchronous DNS host name resolution and reports - IP address for each specified as a command line argument. - One ST thread is created for each host name. All threads do host name - resolution concurrently. - - ---------------------------------------------------------------------------- - -PROGRAM - - proxy - -FILES - - proxy.c - -USAGE - - proxy -l -r [-p ] [-S] - - -l bind to local address specified as []: - -r connect to remote address specified as : - -p create specified number of processes - -S serialize accept() calls from different processes - on the same listening socket (if needed). - -DESCRIPTION - - This program acts as a generic gateway. It listens for connections to a - local address. Upon accepting a client connection, it connects to the - specified remote address and then just pumps the data through without any - modification. - - ---------------------------------------------------------------------------- - -PROGRAM - - server - -FILES - - server.c - error.c - -USAGE - - server -l [] - - -l open all log files in specified directory. - - Possible options: - - -b : bind to specified address (multiple addresses - are permitted) - -p create specified number of processes - -t : specify thread limits per listening socket - across all processes - -u change server's user id to specified value - -q set max length of pending connections queue - -a enable access logging - -i run in interactive mode (useful for debugging) - -S serialize accept() calls from different processes - on the same listening socket (if needed). - -DESCRIPTION - - This program is a general server example. It accepts a client connection - and outputs a short HTML page. It can be easily adapted to provide - other services. - - ---------------------------------------------------------------------------- - diff --git a/trunk/3rdparty/st-srs/examples/error.c b/trunk/3rdparty/st-srs/examples/error.c deleted file mode 100644 index 0b2e772874..0000000000 --- a/trunk/3rdparty/st-srs/examples/error.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Silicon Graphics, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include "st.h" - -/* - * Simple error reporting functions. - * Suggested in W. Richard Stevens' "Advanced Programming in UNIX - * Environment". - */ - -#define MAXLINE 4096 /* max line length */ - -static void err_doit(int, int, const char *, va_list); - - -/* - * Nonfatal error related to a system call. - * Print a message and return. - */ -void err_sys_report(int fd, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(fd, 1, fmt, ap); - va_end(ap); -} - - -/* - * Fatal error related to a system call. - * Print a message and terminate. - */ -void err_sys_quit(int fd, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(fd, 1, fmt, ap); - va_end(ap); - exit(1); -} - - -/* - * Fatal error related to a system call. - * Print a message, dump core, and terminate. - */ -void err_sys_dump(int fd, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(fd, 1, fmt, ap); - va_end(ap); - abort(); /* dump core and terminate */ - exit(1); /* shouldn't get here */ -} - - -/* - * Nonfatal error unrelated to a system call. - * Print a message and return. - */ -void err_report(int fd, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(fd, 0, fmt, ap); - va_end(ap); -} - - -/* - * Fatal error unrelated to a system call. - * Print a message and terminate. - */ -void err_quit(int fd, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - err_doit(fd, 0, fmt, ap); - va_end(ap); - exit(1); -} - - -/* - * Return a pointer to a string containing current time. - */ -char *err_tstamp(void) -{ - static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - static char str[32]; - static time_t lastt = 0; - struct tm *tmp; - time_t currt = st_time(); - - if (currt == lastt) - return str; - - tmp = localtime(&currt); - sprintf(str, "[%02d/%s/%d:%02d:%02d:%02d] ", tmp->tm_mday, - months[tmp->tm_mon], 1900 + tmp->tm_year, tmp->tm_hour, - tmp->tm_min, tmp->tm_sec); - lastt = currt; - - return str; -} - - -/* - * Print a message and return to caller. - * Caller specifies "errnoflag". - */ -static void err_doit(int fd, int errnoflag, const char *fmt, va_list ap) -{ - int errno_save; - char buf[MAXLINE]; - - errno_save = errno; /* value caller might want printed */ - strcpy(buf, err_tstamp()); /* prepend a message with time stamp */ - vsprintf(buf + strlen(buf), fmt, ap); - if (errnoflag) - sprintf(buf + strlen(buf), ": %s\n", strerror(errno_save)); - else - strcat(buf, "\n"); - write(fd, buf, strlen(buf)); - errno = errno_save; -} - diff --git a/trunk/3rdparty/st-srs/examples/lookupdns.c b/trunk/3rdparty/st-srs/examples/lookupdns.c deleted file mode 100644 index 98f6ec5d82..0000000000 --- a/trunk/3rdparty/st-srs/examples/lookupdns.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Silicon Graphics, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "st.h" - -#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL) -#define NETDB_INTERNAL h_NETDB_INTERNAL -#endif - -/* Resolution timeout (in microseconds) */ -#define TIMEOUT (2*1000000LL) - -/* External function defined in the res.c file */ -int dns_getaddr(const char *host, struct in_addr *addr, st_utime_t timeout); - - -void *do_resolve(void *host) -{ - struct in_addr addr; - - /* Use dns_getaddr() instead of gethostbyname(3) to get IP address */ - if (dns_getaddr(host, &addr, TIMEOUT) < 0) { - fprintf(stderr, "dns_getaddr: can't resolve %s: ", (char *)host); - if (h_errno == NETDB_INTERNAL) - perror(""); - else - herror(""); - } else - printf("%-40s %s\n", (char *)host, inet_ntoa(addr)); - - return NULL; -} - - -/* - * Asynchronous DNS host name resolution. This program creates one - * ST thread for each host name (specified as command line arguments). - * All threads do host name resolution concurrently. - */ -int main(int argc, char *argv[]) -{ - int i; - - if (argc < 2) { - fprintf(stderr, "Usage: %s [] ...\n", argv[0]); - exit(1); - } - - if (st_init() < 0) { - perror("st_init"); - exit(1); - } - - for (i = 1; i < argc; i++) { - /* Create a separate thread for each host name */ - if (st_thread_create(do_resolve, argv[i], 0, 0) == NULL) { - perror("st_thread_create"); - exit(1); - } - } - - st_thread_exit(NULL); - - /* NOTREACHED */ - return 1; -} - diff --git a/trunk/3rdparty/st-srs/examples/proxy.c b/trunk/3rdparty/st-srs/examples/proxy.c deleted file mode 100644 index 2f4636d6b8..0000000000 --- a/trunk/3rdparty/st-srs/examples/proxy.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Silicon Graphics, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "st.h" - -#define IOBUFSIZE (16*1024) - -#define IOV_LEN 256 -#define IOV_COUNT (IOBUFSIZE / IOV_LEN) - -#ifndef INADDR_NONE -#define INADDR_NONE 0xffffffff -#endif - -static char *prog; /* Program name */ -static struct sockaddr_in rmt_addr; /* Remote address */ - -static unsigned long testing; -#define TESTING_VERBOSE 0x1 -#define TESTING_READV 0x2 -#define TESTING_READ_RESID 0x4 -#define TESTING_WRITEV 0x8 -#define TESTING_WRITE_RESID 0x10 - -static void read_address(const char *str, struct sockaddr_in *sin); -static void start_daemon(void); -static int cpu_count(void); -static void set_concurrency(int nproc); -static void *handle_request(void *arg); -static void print_sys_error(const char *msg); - - -/* - * This program acts as a generic gateway. It listens for connections - * to a local address ('-l' option). Upon accepting a client connection, - * it connects to the specified remote address ('-r' option) and then - * just pumps the data through without any modification. - */ -int main(int argc, char *argv[]) -{ - extern char *optarg; - int opt, sock, n; - int laddr, raddr, num_procs, alt_ev, one_process; - int serialize_accept = 0; - struct sockaddr_in lcl_addr, cli_addr; - st_netfd_t cli_nfd, srv_nfd; - - prog = argv[0]; - num_procs = laddr = raddr = alt_ev = one_process = 0; - - /* Parse arguments */ - while((opt = getopt(argc, argv, "l:r:p:Saht:X")) != EOF) { - switch (opt) { - case 'a': - alt_ev = 1; - break; - case 'l': - read_address(optarg, &lcl_addr); - laddr = 1; - break; - case 'r': - read_address(optarg, &rmt_addr); - if (rmt_addr.sin_addr.s_addr == INADDR_ANY) { - fprintf(stderr, "%s: invalid remote address: %s\n", prog, optarg); - exit(1); - } - raddr = 1; - break; - case 'p': - num_procs = atoi(optarg); - if (num_procs < 1) { - fprintf(stderr, "%s: invalid number of processes: %s\n", prog, optarg); - exit(1); - } - break; - case 'S': - /* - * Serialization decision is tricky on some platforms. For example, - * Solaris 2.6 and above has kernel sockets implementation, so supposedly - * there is no need for serialization. The ST library may be compiled - * on one OS version, but used on another, so the need for serialization - * should be determined at run time by the application. Since it's just - * an example, the serialization decision is left up to user. - * Only on platforms where the serialization is never needed on any OS - * version st_netfd_serialize_accept() is a no-op. - */ - serialize_accept = 1; - break; - case 't': - testing = strtoul(optarg, NULL, 0); - break; - case 'X': - one_process = 1; - break; - case 'h': - case '?': - fprintf(stderr, "Usage: %s [options] -l <[host]:port> -r \n", - prog); - fprintf(stderr, "options are:\n"); - fprintf(stderr, " -p number of parallel processes\n"); - fprintf(stderr, " -S serialize accepts\n"); - fprintf(stderr, " -a use alternate event system\n"); -#ifdef DEBUG - fprintf(stderr, " -t mask testing/debugging mode\n"); - fprintf(stderr, " -X one process, don't daemonize\n"); -#endif - exit(1); - } - } - if (!laddr) { - fprintf(stderr, "%s: local address required\n", prog); - exit(1); - } - if (!raddr) { - fprintf(stderr, "%s: remote address required\n", prog); - exit(1); - } - if (num_procs == 0) - num_procs = cpu_count(); - - fprintf(stderr, "%s: starting proxy daemon on %s:%d\n", prog, - inet_ntoa(lcl_addr.sin_addr), ntohs(lcl_addr.sin_port)); - - /* Start the daemon */ - if (one_process) - num_procs = 1; - else - start_daemon(); - - if (alt_ev) - st_set_eventsys(ST_EVENTSYS_ALT); - - /* Initialize the ST library */ - if (st_init() < 0) { - print_sys_error("st_init"); - exit(1); - } - - /* Create and bind listening socket */ - if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - print_sys_error("socket"); - exit(1); - } - n = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof(n)) < 0) { - print_sys_error("setsockopt"); - exit(1); - } - if (bind(sock, (struct sockaddr *)&lcl_addr, sizeof(lcl_addr)) < 0) { - print_sys_error("bind"); - exit(1); - } - listen(sock, 128); - if ((srv_nfd = st_netfd_open_socket(sock)) == NULL) { - print_sys_error("st_netfd_open"); - exit(1); - } - /* See the comment regarding serialization decision above */ - if (num_procs > 1 && serialize_accept && st_netfd_serialize_accept(srv_nfd) - < 0) { - print_sys_error("st_netfd_serialize_accept"); - exit(1); - } - - /* Start server processes */ - if (!one_process) - set_concurrency(num_procs); - - for ( ; ; ) { - n = sizeof(cli_addr); - cli_nfd = st_accept(srv_nfd, (struct sockaddr *)&cli_addr, &n, - ST_UTIME_NO_TIMEOUT); - if (cli_nfd == NULL) { - print_sys_error("st_accept"); - exit(1); - } - if (st_thread_create(handle_request, cli_nfd, 0, 0) == NULL) { - print_sys_error("st_thread_create"); - exit(1); - } - } - - /* NOTREACHED */ - return 1; -} - - -static void read_address(const char *str, struct sockaddr_in *sin) -{ - char host[128], *p; - struct hostent *hp; - unsigned short port; - - strcpy(host, str); - if ((p = strchr(host, ':')) == NULL) { - fprintf(stderr, "%s: invalid address: %s\n", prog, host); - exit(1); - } - *p++ = '\0'; - port = (unsigned short) atoi(p); - if (port < 1) { - fprintf(stderr, "%s: invalid port: %s\n", prog, p); - exit(1); - } - - memset(sin, 0, sizeof(struct sockaddr_in)); - sin->sin_family = AF_INET; - sin->sin_port = htons(port); - if (host[0] == '\0') { - sin->sin_addr.s_addr = INADDR_ANY; - return; - } - sin->sin_addr.s_addr = inet_addr(host); - if (sin->sin_addr.s_addr == INADDR_NONE) { - /* not dotted-decimal */ - if ((hp = gethostbyname(host)) == NULL) { - fprintf(stderr, "%s: can't resolve address: %s\n", prog, host); - exit(1); - } - memcpy(&sin->sin_addr, hp->h_addr, hp->h_length); - } -} - -#ifdef DEBUG -static void show_iov(const struct iovec *iov, int niov) -{ - int i; - size_t total; - - printf("iov %p has %d entries:\n", iov, niov); - total = 0; - for (i = 0; i < niov; i++) { - printf("iov[%3d] iov_base=%p iov_len=0x%lx(%lu)\n", - i, iov[i].iov_base, (unsigned long) iov[i].iov_len, - (unsigned long) iov[i].iov_len); - total += iov[i].iov_len; - } - printf("total 0x%lx(%ld)\n", (unsigned long) total, (unsigned long) total); -} - -/* - * This version is tricked out to test all the - * st_(read|write)v?(_resid)? variants. Use the non-DEBUG version for - * anything serious. st_(read|write) are all this function really - * needs. - */ -static int pass(st_netfd_t in, st_netfd_t out) -{ - char buf[IOBUFSIZE]; - struct iovec iov[IOV_COUNT]; - int ioviter, nw, nr; - - if (testing & TESTING_READV) { - for (ioviter = 0; ioviter < IOV_COUNT; ioviter++) { - iov[ioviter].iov_base = &buf[ioviter * IOV_LEN]; - iov[ioviter].iov_len = IOV_LEN; - } - if (testing & TESTING_VERBOSE) { - printf("readv(%p)...\n", in); - show_iov(iov, IOV_COUNT); - } - if (testing & TESTING_READ_RESID) { - struct iovec *riov = iov; - int riov_cnt = IOV_COUNT; - if (st_readv_resid(in, &riov, &riov_cnt, ST_UTIME_NO_TIMEOUT) == 0) { - if (testing & TESTING_VERBOSE) { - printf("resid\n"); - show_iov(riov, riov_cnt); - printf("full\n"); - show_iov(iov, IOV_COUNT); - } - nr = 0; - for (ioviter = 0; ioviter < IOV_COUNT; ioviter++) - nr += iov[ioviter].iov_len; - nr = IOBUFSIZE - nr; - } else - nr = -1; - } else - nr = (int) st_readv(in, iov, IOV_COUNT, ST_UTIME_NO_TIMEOUT); - } else { - if (testing & TESTING_READ_RESID) { - size_t resid = IOBUFSIZE; - if (st_read_resid(in, buf, &resid, ST_UTIME_NO_TIMEOUT) == 0) - nr = IOBUFSIZE - resid; - else - nr = -1; - } else - nr = (int) st_read(in, buf, IOBUFSIZE, ST_UTIME_NO_TIMEOUT); - } - if (testing & TESTING_VERBOSE) - printf("got 0x%x(%d) E=%d\n", nr, nr, errno); - - if (nr <= 0) - return 0; - - if (testing & TESTING_WRITEV) { - for (nw = 0, ioviter = 0; nw < nr; - nw += iov[ioviter].iov_len, ioviter++) { - iov[ioviter].iov_base = &buf[nw]; - iov[ioviter].iov_len = nr - nw; - if (iov[ioviter].iov_len > IOV_LEN) - iov[ioviter].iov_len = IOV_LEN; - } - if (testing & TESTING_VERBOSE) { - printf("writev(%p)...\n", out); - show_iov(iov, ioviter); - } - if (testing & TESTING_WRITE_RESID) { - struct iovec *riov = iov; - int riov_cnt = ioviter; - if (st_writev_resid(out, &riov, &riov_cnt, ST_UTIME_NO_TIMEOUT) == 0) { - if (testing & TESTING_VERBOSE) { - printf("resid\n"); - show_iov(riov, riov_cnt); - printf("full\n"); - show_iov(iov, ioviter); - } - nw = 0; - while (--ioviter >= 0) - nw += iov[ioviter].iov_len; - nw = nr - nw; - } else - nw = -1; - } else - nw = st_writev(out, iov, ioviter, ST_UTIME_NO_TIMEOUT); - } else { - if (testing & TESTING_WRITE_RESID) { - size_t resid = nr; - if (st_write_resid(out, buf, &resid, ST_UTIME_NO_TIMEOUT) == 0) - nw = nr - resid; - else - nw = -1; - } else - nw = st_write(out, buf, nr, ST_UTIME_NO_TIMEOUT); - } - if (testing & TESTING_VERBOSE) - printf("put 0x%x(%d) E=%d\n", nw, nw, errno); - - if (nw != nr) - return 0; - - return 1; -} -#else /* DEBUG */ -/* - * This version is the simple one suitable for serious use. - */ -static int pass(st_netfd_t in, st_netfd_t out) -{ - char buf[IOBUFSIZE]; - int nw, nr; - - nr = (int) st_read(in, buf, IOBUFSIZE, ST_UTIME_NO_TIMEOUT); - if (nr <= 0) - return 0; - - nw = st_write(out, buf, nr, ST_UTIME_NO_TIMEOUT); - if (nw != nr) - return 0; - - return 1; -} -#endif - -static void *handle_request(void *arg) -{ - struct pollfd pds[2]; - st_netfd_t cli_nfd, rmt_nfd; - int sock; - - cli_nfd = (st_netfd_t) arg; - pds[0].fd = st_netfd_fileno(cli_nfd); - pds[0].events = POLLIN; - - /* Connect to remote host */ - if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - print_sys_error("socket"); - goto done; - } - if ((rmt_nfd = st_netfd_open_socket(sock)) == NULL) { - print_sys_error("st_netfd_open_socket"); - close(sock); - goto done; - } - if (st_connect(rmt_nfd, (struct sockaddr *)&rmt_addr, - sizeof(rmt_addr), ST_UTIME_NO_TIMEOUT) < 0) { - print_sys_error("st_connect"); - st_netfd_close(rmt_nfd); - goto done; - } - pds[1].fd = sock; - pds[1].events = POLLIN; - - /* - * Now just pump the data through. - * XXX This should use one thread for each direction for true full-duplex. - */ - for ( ; ; ) { - pds[0].revents = 0; - pds[1].revents = 0; - - if (st_poll(pds, 2, ST_UTIME_NO_TIMEOUT) <= 0) { - print_sys_error("st_poll"); - break; - } - - if (pds[0].revents & POLLIN) { - if (!pass(cli_nfd, rmt_nfd)) - break; - } - - if (pds[1].revents & POLLIN) { - if (!pass(rmt_nfd, cli_nfd)) - break; - } - } - st_netfd_close(rmt_nfd); - -done: - - st_netfd_close(cli_nfd); - - return NULL; -} - -static void start_daemon(void) -{ - pid_t pid; - - /* Start forking */ - if ((pid = fork()) < 0) { - print_sys_error("fork"); - exit(1); - } - if (pid > 0) - exit(0); /* parent */ - - /* First child process */ - setsid(); /* become session leader */ - - if ((pid = fork()) < 0) { - print_sys_error("fork"); - exit(1); - } - if (pid > 0) /* first child */ - exit(0); - - chdir("/"); - umask(022); -} - -/* - * Create separate processes ("virtual processors"). Since it's just an - * example, there is no watchdog - the parent just exits leaving children - * on their own. - */ -static void set_concurrency(int nproc) -{ - pid_t pid; - int i; - - if (nproc < 1) - nproc = 1; - - for (i = 0; i < nproc; i++) { - if ((pid = fork()) < 0) { - print_sys_error("fork"); - exit(1); - } - /* Child returns */ - if (pid == 0) - return; - } - - /* Parent just exits */ - exit(0); -} - -static int cpu_count(void) -{ - int n; - -#if defined (_SC_NPROCESSORS_ONLN) - n = (int) sysconf(_SC_NPROCESSORS_ONLN); -#elif defined (_SC_NPROC_ONLN) - n = (int) sysconf(_SC_NPROC_ONLN); -#elif defined (HPUX) -#include - n = mpctl(MPC_GETNUMSPUS, 0, 0); -#else - n = -1; - errno = ENOSYS; -#endif - - return n; -} - -static void print_sys_error(const char *msg) -{ - fprintf(stderr, "%s: %s: %s\n", prog, msg, strerror(errno)); -} - diff --git a/trunk/3rdparty/st-srs/examples/res.c b/trunk/3rdparty/st-srs/examples/res.c deleted file mode 100644 index 14ecd8c927..0000000000 --- a/trunk/3rdparty/st-srs/examples/res.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (c) 1985, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Silicon Graphics, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined (DARWIN) -#define BIND_8_COMPAT -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "st.h" - -#define MAXPACKET 1024 - -#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL) -#define NETDB_INTERNAL h_NETDB_INTERNAL -#endif - -/* New in Solaris 7 */ -#if !defined(_getshort) && defined(ns_get16) -#define _getshort(cp) ns_get16(cp) -#endif - -typedef union { - HEADER hdr; - u_char buf[MAXPACKET]; -} querybuf_t; - - -static int parse_answer(querybuf_t *ans, int len, struct in_addr *addr) -{ - char buf[MAXPACKET]; - HEADER *ahp; - u_char *cp, *eoa; - int type, n; - - ahp = &ans->hdr; - eoa = ans->buf + len; - cp = ans->buf + sizeof(HEADER); - - while (ahp->qdcount > 0) { - ahp->qdcount--; - cp += dn_skipname(cp, eoa) + QFIXEDSZ; - } - while (ahp->ancount > 0 && cp < eoa) { - ahp->ancount--; - if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0) - break; - cp += n; - type = _getshort(cp); - cp += 8; - n = _getshort(cp); - cp += 2; - if (type == T_CNAME) { - cp += n; - continue; - } - memcpy(addr, cp, n); - return 0; - } - - h_errno = TRY_AGAIN; - return -1; -} - - -static int query_domain(st_netfd_t nfd, const char *name, struct in_addr *addr, - st_utime_t timeout) -{ - querybuf_t qbuf; - u_char *buf = qbuf.buf; - HEADER *hp = &qbuf.hdr; - int blen = sizeof(qbuf); - int i, len, id; - - for (i = 0; i < _res.nscount; i++) { - len = res_mkquery(QUERY, name, C_IN, T_A, NULL, 0, NULL, buf, blen); - if (len <= 0) { - h_errno = NO_RECOVERY; - return -1; - } - id = hp->id; - - if (st_sendto(nfd, buf, len, (struct sockaddr *)&(_res.nsaddr_list[i]), - sizeof(struct sockaddr), timeout) != len) { - h_errno = NETDB_INTERNAL; - /* EINTR means interrupt by other thread, NOT by a caught signal */ - if (errno == EINTR) - return -1; - continue; - } - - /* Wait for reply */ - do { - len = st_recvfrom(nfd, buf, blen, NULL, NULL, timeout); - if (len <= 0) - break; - } while (id != hp->id); - - if (len < HFIXEDSZ) { - h_errno = NETDB_INTERNAL; - if (len >= 0) - errno = EMSGSIZE; - else if (errno == EINTR) /* see the comment above */ - return -1; - continue; - } - - hp->ancount = ntohs(hp->ancount); - hp->qdcount = ntohs(hp->qdcount); - if ((hp->rcode != NOERROR) || (hp->ancount == 0)) { - switch (hp->rcode) { - case NXDOMAIN: - h_errno = HOST_NOT_FOUND; - break; - case SERVFAIL: - h_errno = TRY_AGAIN; - break; - case NOERROR: - h_errno = NO_DATA; - break; - case FORMERR: - case NOTIMP: - case REFUSED: - default: - h_errno = NO_RECOVERY; - } - continue; - } - - if (parse_answer(&qbuf, len, addr) == 0) - return 0; - } - - return -1; -} - - -#define CLOSE_AND_RETURN(ret) \ - { \ - n = errno; \ - st_netfd_close(nfd); \ - errno = n; \ - return (ret); \ - } - - -int dns_getaddr(const char *host, struct in_addr *addr, st_utime_t timeout) -{ - char name[MAXDNAME], **domain; - const char *cp; - int s, n, maxlen, dots; - int trailing_dot, tried_as_is; - st_netfd_t nfd; - - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return -1; - } - if (_res.options & RES_USEVC) { - h_errno = NETDB_INTERNAL; - errno = ENOSYS; - return -1; - } - if (!host || *host == '\0') { - h_errno = HOST_NOT_FOUND; - return -1; - } - - /* Create UDP socket */ - if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - h_errno = NETDB_INTERNAL; - return -1; - } - if ((nfd = st_netfd_open_socket(s)) == NULL) { - h_errno = NETDB_INTERNAL; - n = errno; - close(s); - errno = n; - return -1; - } - - maxlen = sizeof(name) - 1; - n = 0; - dots = 0; - trailing_dot = 0; - tried_as_is = 0; - - for (cp = host; *cp && n < maxlen; cp++) { - dots += (*cp == '.'); - name[n++] = *cp; - } - if (name[n - 1] == '.') - trailing_dot = 1; - - /* - * If there are dots in the name already, let's just give it a try - * 'as is'. The threshold can be set with the "ndots" option. - */ - if (dots >= _res.ndots) { - if (query_domain(nfd, host, addr, timeout) == 0) - CLOSE_AND_RETURN(0); - if (h_errno == NETDB_INTERNAL && errno == EINTR) - CLOSE_AND_RETURN(-1); - tried_as_is = 1; - } - - /* - * We do at least one level of search if - * - there is no dot and RES_DEFNAME is set, or - * - there is at least one dot, there is no trailing dot, - * and RES_DNSRCH is set. - */ - if ((!dots && (_res.options & RES_DEFNAMES)) || - (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { - name[n++] = '.'; - for (domain = _res.dnsrch; *domain; domain++) { - strncpy(name + n, *domain, maxlen - n); - if (query_domain(nfd, name, addr, timeout) == 0) - CLOSE_AND_RETURN(0); - if (h_errno == NETDB_INTERNAL && errno == EINTR) - CLOSE_AND_RETURN(-1); - if (!(_res.options & RES_DNSRCH)) - break; - } - } - - /* - * If we have not already tried the name "as is", do that now. - * note that we do this regardless of how many dots were in the - * name or whether it ends with a dot. - */ - if (!tried_as_is) { - if (query_domain(nfd, host, addr, timeout) == 0) - CLOSE_AND_RETURN(0); - } - - CLOSE_AND_RETURN(-1); -} - diff --git a/trunk/3rdparty/st-srs/examples/server.c b/trunk/3rdparty/st-srs/examples/server.c deleted file mode 100644 index 5d5aa6d726..0000000000 --- a/trunk/3rdparty/st-srs/examples/server.c +++ /dev/null @@ -1,1025 +0,0 @@ -/* - * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Silicon Graphics, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "st.h" - - -/****************************************************************** - * Server configuration parameters - */ - -/* Log files */ -#define PID_FILE "pid" -#define ERRORS_FILE "errors" -#define ACCESS_FILE "access" - -/* Default server port */ -#define SERV_PORT_DEFAULT 8000 - -/* Socket listen queue size */ -#define LISTENQ_SIZE_DEFAULT 256 - -/* Max number of listening sockets ("hardware virtual servers") */ -#define MAX_BIND_ADDRS 16 - -/* Max number of "spare" threads per process per socket */ -#define MAX_WAIT_THREADS_DEFAULT 8 - -/* Number of file descriptors needed to handle one client session */ -#define FD_PER_THREAD 2 - -/* Access log buffer flushing interval (in seconds) */ -#define ACCLOG_FLUSH_INTERVAL 30 - -/* Request read timeout (in seconds) */ -#define REQUEST_TIMEOUT 30 - - -/****************************************************************** - * Global data - */ - -struct socket_info { - st_netfd_t nfd; /* Listening socket */ - char *addr; /* Bind address */ - unsigned int port; /* Port */ - int wait_threads; /* Number of threads waiting to accept */ - int busy_threads; /* Number of threads processing request */ - int rqst_count; /* Total number of processed requests */ -} srv_socket[MAX_BIND_ADDRS]; /* Array of listening sockets */ - -static int sk_count = 0; /* Number of listening sockets */ - -static int vp_count = 0; /* Number of server processes (VPs) */ -static pid_t *vp_pids; /* Array of VP pids */ - -static int my_index = -1; /* Current process index */ -static pid_t my_pid = -1; /* Current process pid */ - -static st_netfd_t sig_pipe[2]; /* Signal pipe */ - -/* - * Configuration flags/parameters - */ -static int interactive_mode = 0; -static int serialize_accept = 0; -static int log_access = 0; -static char *logdir = NULL; -static char *username = NULL; -static int listenq_size = LISTENQ_SIZE_DEFAULT; -static int errfd = STDERR_FILENO; - -/* - * Thread throttling parameters (all numbers are per listening socket). - * Zero values mean use default. - */ -static int max_threads = 0; /* Max number of threads */ -static int max_wait_threads = 0; /* Max number of "spare" threads */ -static int min_wait_threads = 2; /* Min number of "spare" threads */ - - -/****************************************************************** - * Useful macros - */ - -#ifndef INADDR_NONE -#define INADDR_NONE 0xffffffff -#endif - -#define SEC2USEC(s) ((s)*1000000LL) - -#define WAIT_THREADS(i) (srv_socket[i].wait_threads) -#define BUSY_THREADS(i) (srv_socket[i].busy_threads) -#define TOTAL_THREADS(i) (WAIT_THREADS(i) + BUSY_THREADS(i)) -#define RQST_COUNT(i) (srv_socket[i].rqst_count) - - -/****************************************************************** - * Forward declarations - */ - -static void usage(const char *progname); -static void parse_arguments(int argc, char *argv[]); -static void start_daemon(void); -static void set_thread_throttling(void); -static void create_listeners(void); -static void change_user(void); -static void open_log_files(void); -static void start_processes(void); -static void wdog_sighandler(int signo); -static void child_sighandler(int signo); -static void install_sighandlers(void); -static void start_threads(void); -static void *process_signals(void *arg); -static void *flush_acclog_buffer(void *arg); -static void *handle_connections(void *arg); -static void dump_server_info(void); - -static void Signal(int sig, void (*handler)(int)); -static int cpu_count(void); - -extern void handle_session(long srv_socket_index, st_netfd_t cli_nfd); -extern void load_configs(void); -extern void logbuf_open(void); -extern void logbuf_flush(void); -extern void logbuf_close(void); - -/* Error reporting functions defined in the error.c file */ -extern void err_sys_report(int fd, const char *fmt, ...); -extern void err_sys_quit(int fd, const char *fmt, ...); -extern void err_sys_dump(int fd, const char *fmt, ...); -extern void err_report(int fd, const char *fmt, ...); -extern void err_quit(int fd, const char *fmt, ...); - - -/* - * General server example: accept a client connection and do something. - * This program just outputs a short HTML page, but can be easily adapted - * to do other things. - * - * This server creates a constant number of processes ("virtual processors" - * or VPs) and replaces them when they die. Each virtual processor manages - * its own independent set of state threads (STs), the number of which varies - * with load against the server. Each state thread listens to exactly one - * listening socket. The initial process becomes the watchdog, waiting for - * children (VPs) to die or for a signal requesting termination or restart. - * Upon receiving a restart signal (SIGHUP), all VPs close and then reopen - * log files and reload configuration. All currently active connections remain - * active. It is assumed that new configuration affects only request - * processing and not the general server parameters such as number of VPs, - * thread limits, bind addresses, etc. Those are specified as command line - * arguments, so the server has to be stopped and then started again in order - * to change them. - * - * Each state thread loops processing connections from a single listening - * socket. Only one ST runs on a VP at a time, and VPs do not share memory, - * so no mutual exclusion locking is necessary on any data, and the entire - * server is free to use all the static variables and non-reentrant library - * functions it wants, greatly simplifying programming and debugging and - * increasing performance (for example, it is safe to ++ and -- all global - * counters or call inet_ntoa(3) without any mutexes). The current thread on - * each VP maintains equilibrium on that VP, starting a new thread or - * terminating itself if the number of spare threads exceeds the lower or - * upper limit. - * - * All I/O operations on sockets must use the State Thread library's I/O - * functions because only those functions prevent blocking of the entire VP - * process and perform state thread scheduling. - */ -int main(int argc, char *argv[]) -{ - /* Parse command-line options */ - parse_arguments(argc, argv); - - /* Allocate array of server pids */ - if ((vp_pids = calloc(vp_count, sizeof(pid_t))) == NULL) - err_sys_quit(errfd, "ERROR: calloc failed"); - - /* Start the daemon */ - if (!interactive_mode) - start_daemon(); - - /* Initialize the ST library */ - if (st_init() < 0) - err_sys_quit(errfd, "ERROR: initialization failed: st_init"); - - /* Set thread throttling parameters */ - set_thread_throttling(); - - /* Create listening sockets */ - create_listeners(); - - /* Change the user */ - if (username) - change_user(); - - /* Open log files */ - open_log_files(); - - /* Start server processes (VPs) */ - start_processes(); - - /* Turn time caching on */ - st_timecache_set(1); - - /* Install signal handlers */ - install_sighandlers(); - - /* Load configuration from config files */ - load_configs(); - - /* Start all threads */ - start_threads(); - - /* Become a signal processing thread */ - process_signals(NULL); - - /* NOTREACHED */ - return 1; -} - - -/******************************************************************/ - -static void usage(const char *progname) -{ - fprintf(stderr, "Usage: %s -l []\n\n" - "Possible options:\n\n" - "\t-b : Bind to specified address. Multiple" - " addresses\n" - "\t are permitted.\n" - "\t-p Create specified number of processes.\n" - "\t-t : Specify thread limits per listening" - " socket\n" - "\t across all processes.\n" - "\t-u Change server's user id to specified" - " value.\n" - "\t-q Set max length of pending connections" - " queue.\n" - "\t-a Enable access logging.\n" - "\t-i Run in interactive mode.\n" - "\t-S Serialize all accept() calls.\n" - "\t-h Print this message.\n", - progname); - exit(1); -} - - -/******************************************************************/ - -static void parse_arguments(int argc, char *argv[]) -{ - extern char *optarg; - int opt; - char *c; - - while ((opt = getopt(argc, argv, "b:p:l:t:u:q:aiSh")) != EOF) { - switch (opt) { - case 'b': - if (sk_count >= MAX_BIND_ADDRS) - err_quit(errfd, "ERROR: max number of bind addresses (%d) exceeded", - MAX_BIND_ADDRS); - if ((c = strdup(optarg)) == NULL) - err_sys_quit(errfd, "ERROR: strdup"); - srv_socket[sk_count++].addr = c; - break; - case 'p': - vp_count = atoi(optarg); - if (vp_count < 1) - err_quit(errfd, "ERROR: invalid number of processes: %s", optarg); - break; - case 'l': - logdir = optarg; - break; - case 't': - max_wait_threads = (int) strtol(optarg, &c, 10); - if (*c++ == ':') - max_threads = atoi(c); - if (max_wait_threads < 0 || max_threads < 0) - err_quit(errfd, "ERROR: invalid number of threads: %s", optarg); - break; - case 'u': - username = optarg; - break; - case 'q': - listenq_size = atoi(optarg); - if (listenq_size < 1) - err_quit(errfd, "ERROR: invalid listen queue size: %s", optarg); - break; - case 'a': - log_access = 1; - break; - case 'i': - interactive_mode = 1; - break; - case 'S': - /* - * Serialization decision is tricky on some platforms. For example, - * Solaris 2.6 and above has kernel sockets implementation, so supposedly - * there is no need for serialization. The ST library may be compiled - * on one OS version, but used on another, so the need for serialization - * should be determined at run time by the application. Since it's just - * an example, the serialization decision is left up to user. - * Only on platforms where the serialization is never needed on any OS - * version st_netfd_serialize_accept() is a no-op. - */ - serialize_accept = 1; - break; - case 'h': - case '?': - usage(argv[0]); - } - } - - if (logdir == NULL && !interactive_mode) { - err_report(errfd, "ERROR: logging directory is required\n"); - usage(argv[0]); - } - - if (getuid() == 0 && username == NULL) - err_report(errfd, "WARNING: running as super-user!"); - - if (vp_count == 0 && (vp_count = cpu_count()) < 1) - vp_count = 1; - - if (sk_count == 0) { - sk_count = 1; - srv_socket[0].addr = "0.0.0.0"; - } -} - - -/******************************************************************/ - -static void start_daemon(void) -{ - pid_t pid; - - /* Start forking */ - if ((pid = fork()) < 0) - err_sys_quit(errfd, "ERROR: fork"); - if (pid > 0) - exit(0); /* parent */ - - /* First child process */ - setsid(); /* become session leader */ - - if ((pid = fork()) < 0) - err_sys_quit(errfd, "ERROR: fork"); - if (pid > 0) /* first child */ - exit(0); - - umask(022); - - if (chdir(logdir) < 0) - err_sys_quit(errfd, "ERROR: can't change directory to %s: chdir", logdir); -} - - -/****************************************************************** - * For simplicity, the minimal size of thread pool is considered - * as a maximum number of spare threads (max_wait_threads) that - * will be created upon server startup. The pool size can grow up - * to the max_threads value. Note that this is a per listening - * socket limit. It is also possible to limit the total number of - * threads for all sockets rather than impose a per socket limit. - */ - -static void set_thread_throttling(void) -{ - /* - * Calculate total values across all processes. - * All numbers are per listening socket. - */ - if (max_wait_threads == 0) - max_wait_threads = MAX_WAIT_THREADS_DEFAULT * vp_count; - /* Assuming that each client session needs FD_PER_THREAD file descriptors */ - if (max_threads == 0) - max_threads = (st_getfdlimit() * vp_count) / FD_PER_THREAD / sk_count; - if (max_wait_threads > max_threads) - max_wait_threads = max_threads; - - /* - * Now calculate per-process values. - */ - if (max_wait_threads % vp_count) - max_wait_threads = max_wait_threads / vp_count + 1; - else - max_wait_threads = max_wait_threads / vp_count; - if (max_threads % vp_count) - max_threads = max_threads / vp_count + 1; - else - max_threads = max_threads / vp_count; - - if (min_wait_threads > max_wait_threads) - min_wait_threads = max_wait_threads; -} - - -/******************************************************************/ - -static void create_listeners(void) -{ - int i, n, sock; - char *c; - struct sockaddr_in serv_addr; - struct hostent *hp; - unsigned short port; - - for (i = 0; i < sk_count; i++) { - port = 0; - if ((c = strchr(srv_socket[i].addr, ':')) != NULL) { - *c++ = '\0'; - port = (unsigned short) atoi(c); - } - if (srv_socket[i].addr[0] == '\0') - srv_socket[i].addr = "0.0.0.0"; - if (port == 0) - port = SERV_PORT_DEFAULT; - - /* Create server socket */ - if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) - err_sys_quit(errfd, "ERROR: can't create socket: socket"); - n = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof(n)) < 0) - err_sys_quit(errfd, "ERROR: can't set SO_REUSEADDR: setsockopt"); - memset(&serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(port); - serv_addr.sin_addr.s_addr = inet_addr(srv_socket[i].addr); - if (serv_addr.sin_addr.s_addr == INADDR_NONE) { - /* not dotted-decimal */ - if ((hp = gethostbyname(srv_socket[i].addr)) == NULL) - err_quit(errfd, "ERROR: can't resolve address: %s", - srv_socket[i].addr); - memcpy(&serv_addr.sin_addr, hp->h_addr, hp->h_length); - } - srv_socket[i].port = port; - - /* Do bind and listen */ - if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) - err_sys_quit(errfd, "ERROR: can't bind to address %s, port %hu", - srv_socket[i].addr, port); - if (listen(sock, listenq_size) < 0) - err_sys_quit(errfd, "ERROR: listen"); - - /* Create file descriptor object from OS socket */ - if ((srv_socket[i].nfd = st_netfd_open_socket(sock)) == NULL) - err_sys_quit(errfd, "ERROR: st_netfd_open_socket"); - /* - * On some platforms (e.g. IRIX, Linux) accept() serialization is never - * needed for any OS version. In that case st_netfd_serialize_accept() - * is just a no-op. Also see the comment above. - */ - if (serialize_accept && st_netfd_serialize_accept(srv_socket[i].nfd) < 0) - err_sys_quit(errfd, "ERROR: st_netfd_serialize_accept"); - } -} - - -/******************************************************************/ - -static void change_user(void) -{ - struct passwd *pw; - - if ((pw = getpwnam(username)) == NULL) - err_quit(errfd, "ERROR: can't find user '%s': getpwnam failed", username); - - if (setgid(pw->pw_gid) < 0) - err_sys_quit(errfd, "ERROR: can't change group id: setgid"); - if (setuid(pw->pw_uid) < 0) - err_sys_quit(errfd, "ERROR: can't change user id: setuid"); - - err_report(errfd, "INFO: changed process user id to '%s'", username); -} - - -/******************************************************************/ - -static void open_log_files(void) -{ - int fd; - char str[32]; - - if (interactive_mode) - return; - - /* Open access log */ - if (log_access) - logbuf_open(); - - /* Open and write pid to pid file */ - if ((fd = open(PID_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0) - err_sys_quit(errfd, "ERROR: can't open pid file: open"); - sprintf(str, "%d\n", (int)getpid()); - if (write(fd, str, strlen(str)) != strlen(str)) - err_sys_quit(errfd, "ERROR: can't write to pid file: write"); - close(fd); - - /* Open error log file */ - if ((fd = open(ERRORS_FILE, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0) - err_sys_quit(errfd, "ERROR: can't open error log file: open"); - errfd = fd; - - err_report(errfd, "INFO: starting the server..."); -} - - -/******************************************************************/ - -static void start_processes(void) -{ - int i, status; - pid_t pid; - sigset_t mask, omask; - - if (interactive_mode) { - my_index = 0; - my_pid = getpid(); - return; - } - - for (i = 0; i < vp_count; i++) { - if ((pid = fork()) < 0) { - err_sys_report(errfd, "ERROR: can't create process: fork"); - if (i == 0) - exit(1); - err_report(errfd, "WARN: started only %d processes out of %d", i, - vp_count); - vp_count = i; - break; - } - if (pid == 0) { - my_index = i; - my_pid = getpid(); - /* Child returns to continue in main() */ - return; - } - vp_pids[i] = pid; - } - - /* - * Parent process becomes a "watchdog" and never returns to main(). - */ - - /* Install signal handlers */ - Signal(SIGTERM, wdog_sighandler); /* terminate */ - Signal(SIGHUP, wdog_sighandler); /* restart */ - Signal(SIGUSR1, wdog_sighandler); /* dump info */ - - /* Now go to sleep waiting for a child termination or a signal */ - for ( ; ; ) { - if ((pid = wait(&status)) < 0) { - if (errno == EINTR) - continue; - err_sys_quit(errfd, "ERROR: watchdog: wait"); - } - /* Find index of the exited child */ - for (i = 0; i < vp_count; i++) { - if (vp_pids[i] == pid) - break; - } - - /* Block signals while printing and forking */ - sigemptyset(&mask); - sigaddset(&mask, SIGTERM); - sigaddset(&mask, SIGHUP); - sigaddset(&mask, SIGUSR1); - sigprocmask(SIG_BLOCK, &mask, &omask); - - if (WIFEXITED(status)) - err_report(errfd, "WARN: watchdog: process %d (pid %d) exited" - " with status %d", i, pid, WEXITSTATUS(status)); - else if (WIFSIGNALED(status)) - err_report(errfd, "WARN: watchdog: process %d (pid %d) terminated" - " by signal %d", i, pid, WTERMSIG(status)); - else if (WIFSTOPPED(status)) - err_report(errfd, "WARN: watchdog: process %d (pid %d) stopped" - " by signal %d", i, pid, WSTOPSIG(status)); - else - err_report(errfd, "WARN: watchdog: process %d (pid %d) terminated:" - " unknown termination reason", i, pid); - - /* Fork another VP */ - if ((pid = fork()) < 0) { - err_sys_report(errfd, "ERROR: watchdog: can't create process: fork"); - } else if (pid == 0) { - my_index = i; - my_pid = getpid(); - /* Child returns to continue in main() */ - return; - } - vp_pids[i] = pid; - - /* Restore the signal mask */ - sigprocmask(SIG_SETMASK, &omask, NULL); - } -} - - -/******************************************************************/ - -static void wdog_sighandler(int signo) -{ - int i, err; - - /* Save errno */ - err = errno; - /* Forward the signal to all children */ - for (i = 0; i < vp_count; i++) { - if (vp_pids[i] > 0) - kill(vp_pids[i], signo); - } - /* - * It is safe to do pretty much everything here because process is - * sleeping in wait() which is async-safe. - */ - switch (signo) { - case SIGHUP: - err_report(errfd, "INFO: watchdog: caught SIGHUP"); - /* Reopen log files - needed for log rotation */ - if (log_access) { - logbuf_close(); - logbuf_open(); - } - close(errfd); - if ((errfd = open(ERRORS_FILE, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0) - err_sys_quit(STDERR_FILENO, "ERROR: watchdog: open"); - break; - case SIGTERM: - /* Non-graceful termination */ - err_report(errfd, "INFO: watchdog: caught SIGTERM, terminating"); - unlink(PID_FILE); - exit(0); - case SIGUSR1: - err_report(errfd, "INFO: watchdog: caught SIGUSR1"); - break; - default: - err_report(errfd, "INFO: watchdog: caught signal %d", signo); - } - /* Restore errno */ - errno = err; -} - - -/******************************************************************/ - -static void install_sighandlers(void) -{ - sigset_t mask; - int p[2]; - - /* Create signal pipe */ - if (pipe(p) < 0) - err_sys_quit(errfd, "ERROR: process %d (pid %d): can't create" - " signal pipe: pipe", my_index, my_pid); - if ((sig_pipe[0] = st_netfd_open(p[0])) == NULL || - (sig_pipe[1] = st_netfd_open(p[1])) == NULL) - err_sys_quit(errfd, "ERROR: process %d (pid %d): can't create" - " signal pipe: st_netfd_open", my_index, my_pid); - - /* Install signal handlers */ - Signal(SIGTERM, child_sighandler); /* terminate */ - Signal(SIGHUP, child_sighandler); /* restart */ - Signal(SIGUSR1, child_sighandler); /* dump info */ - - /* Unblock signals */ - sigemptyset(&mask); - sigaddset(&mask, SIGTERM); - sigaddset(&mask, SIGHUP); - sigaddset(&mask, SIGUSR1); - sigprocmask(SIG_UNBLOCK, &mask, NULL); -} - - -/******************************************************************/ - -static void child_sighandler(int signo) -{ - int err, fd; - - err = errno; - fd = st_netfd_fileno(sig_pipe[1]); - - /* write() is async-safe */ - if (write(fd, &signo, sizeof(int)) != sizeof(int)) - err_sys_quit(errfd, "ERROR: process %d (pid %d): child's signal" - " handler: write", my_index, my_pid); - errno = err; -} - - -/****************************************************************** - * The "main" function of the signal processing thread. - */ - -/* ARGSUSED */ -static void *process_signals(void *arg) -{ - int signo; - - for ( ; ; ) { - /* Read the next signal from the signal pipe */ - if (st_read(sig_pipe[0], &signo, sizeof(int), - ST_UTIME_NO_TIMEOUT) != sizeof(int)) - err_sys_quit(errfd, "ERROR: process %d (pid %d): signal processor:" - " st_read", my_index, my_pid); - - switch (signo) { - case SIGHUP: - err_report(errfd, "INFO: process %d (pid %d): caught SIGHUP," - " reloading configuration", my_index, my_pid); - if (interactive_mode) { - load_configs(); - break; - } - /* Reopen log files - needed for log rotation */ - if (log_access) { - logbuf_flush(); - logbuf_close(); - logbuf_open(); - } - close(errfd); - if ((errfd = open(ERRORS_FILE, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0) - err_sys_quit(STDERR_FILENO, "ERROR: process %d (pid %d): signal" - " processor: open", my_index, my_pid); - /* Reload configuration */ - load_configs(); - break; - case SIGTERM: - /* - * Terminate ungracefully since it is generally not known how long - * it will take to gracefully complete all client sessions. - */ - err_report(errfd, "INFO: process %d (pid %d): caught SIGTERM," - " terminating", my_index, my_pid); - if (log_access) - logbuf_flush(); - exit(0); - case SIGUSR1: - err_report(errfd, "INFO: process %d (pid %d): caught SIGUSR1", - my_index, my_pid); - /* Print server info to stderr */ - dump_server_info(); - break; - default: - err_report(errfd, "INFO: process %d (pid %d): caught signal %d", - my_index, my_pid, signo); - } - } - - /* NOTREACHED */ - return NULL; -} - - -/****************************************************************** - * The "main" function of the access log flushing thread. - */ - -/* ARGSUSED */ -static void *flush_acclog_buffer(void *arg) -{ - for ( ; ; ) { - st_sleep(ACCLOG_FLUSH_INTERVAL); - logbuf_flush(); - } - - /* NOTREACHED */ - return NULL; -} - - -/******************************************************************/ - -static void start_threads(void) -{ - long i, n; - - /* Create access log flushing thread */ - if (log_access && st_thread_create(flush_acclog_buffer, NULL, 0, 0) == NULL) - err_sys_quit(errfd, "ERROR: process %d (pid %d): can't create" - " log flushing thread", my_index, my_pid); - - /* Create connections handling threads */ - for (i = 0; i < sk_count; i++) { - err_report(errfd, "INFO: process %d (pid %d): starting %d threads" - " on %s:%u", my_index, my_pid, max_wait_threads, - srv_socket[i].addr, srv_socket[i].port); - WAIT_THREADS(i) = 0; - BUSY_THREADS(i) = 0; - RQST_COUNT(i) = 0; - for (n = 0; n < max_wait_threads; n++) { - if (st_thread_create(handle_connections, (void *)i, 0, 0) != NULL) - WAIT_THREADS(i)++; - else - err_sys_report(errfd, "ERROR: process %d (pid %d): can't create" - " thread", my_index, my_pid); - } - if (WAIT_THREADS(i) == 0) - exit(1); - } -} - - -/******************************************************************/ - -static void *handle_connections(void *arg) -{ - st_netfd_t srv_nfd, cli_nfd; - struct sockaddr_in from; - int fromlen; - long i = (long) arg; - - srv_nfd = srv_socket[i].nfd; - fromlen = sizeof(from); - - while (WAIT_THREADS(i) <= max_wait_threads) { - cli_nfd = st_accept(srv_nfd, (struct sockaddr *)&from, &fromlen, - ST_UTIME_NO_TIMEOUT); - if (cli_nfd == NULL) { - err_sys_report(errfd, "ERROR: can't accept connection: st_accept"); - continue; - } - /* Save peer address, so we can retrieve it later */ - st_netfd_setspecific(cli_nfd, &from.sin_addr, NULL); - - WAIT_THREADS(i)--; - BUSY_THREADS(i)++; - if (WAIT_THREADS(i) < min_wait_threads && TOTAL_THREADS(i) < max_threads) { - /* Create another spare thread */ - if (st_thread_create(handle_connections, (void *)i, 0, 0) != NULL) - WAIT_THREADS(i)++; - else - err_sys_report(errfd, "ERROR: process %d (pid %d): can't create" - " thread", my_index, my_pid); - } - - handle_session(i, cli_nfd); - - st_netfd_close(cli_nfd); - WAIT_THREADS(i)++; - BUSY_THREADS(i)--; - } - - WAIT_THREADS(i)--; - return NULL; -} - - -/******************************************************************/ - -static void dump_server_info(void) -{ - char *buf; - int i, len; - - if ((buf = malloc(sk_count * 512)) == NULL) { - err_sys_report(errfd, "ERROR: malloc failed"); - return; - } - - len = sprintf(buf, "\n\nProcess #%d (pid %d):\n", my_index, (int)my_pid); - for (i = 0; i < sk_count; i++) { - len += sprintf(buf + len, "\nListening Socket #%d:\n" - "-------------------------\n" - "Address %s:%u\n" - "Thread limits (min/max) %d/%d\n" - "Waiting threads %d\n" - "Busy threads %d\n" - "Requests served %d\n", - i, srv_socket[i].addr, srv_socket[i].port, - max_wait_threads, max_threads, - WAIT_THREADS(i), BUSY_THREADS(i), RQST_COUNT(i)); - } - - write(STDERR_FILENO, buf, len); - free(buf); -} - - -/****************************************************************** - * Stubs - */ - -/* - * Session handling function stub. Just dumps small HTML page. - */ -void handle_session(long srv_socket_index, st_netfd_t cli_nfd) -{ - static char resp[] = "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n" - "Connection: close\r\n\r\n

It worked!

\n"; - char buf[512]; - int n = sizeof(resp) - 1; - struct in_addr *from = st_netfd_getspecific(cli_nfd); - - if (st_read(cli_nfd, buf, sizeof(buf), SEC2USEC(REQUEST_TIMEOUT)) < 0) { - err_sys_report(errfd, "WARN: can't read request from %s: st_read", - inet_ntoa(*from)); - return; - } - if (st_write(cli_nfd, resp, n, ST_UTIME_NO_TIMEOUT) != n) { - err_sys_report(errfd, "WARN: can't write response to %s: st_write", - inet_ntoa(*from)); - return; - } - - RQST_COUNT(srv_socket_index)++; -} - - -/* - * Configuration loading function stub. - */ -void load_configs(void) -{ - err_report(errfd, "INFO: process %d (pid %d): configuration loaded", - my_index, my_pid); -} - - -/* - * Buffered access logging methods. - * Note that stdio functions (fopen(3), fprintf(3), fflush(3), etc.) cannot - * be used if multiple VPs are created since these functions can flush buffer - * at any point and thus write only partial log record to disk. - * Also, it is completely safe for all threads of the same VP to write to - * the same log buffer without any mutex protection (one buffer per VP, of - * course). - */ -void logbuf_open(void) -{ - -} - - -void logbuf_flush(void) -{ - -} - - -void logbuf_close(void) -{ - -} - - -/****************************************************************** - * Small utility functions - */ - -static void Signal(int sig, void (*handler)(int)) -{ - struct sigaction sa; - - sa.sa_handler = handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(sig, &sa, NULL); -} - -static int cpu_count(void) -{ - int n; - -#if defined (_SC_NPROCESSORS_ONLN) - n = (int) sysconf(_SC_NPROCESSORS_ONLN); -#elif defined (_SC_NPROC_ONLN) - n = (int) sysconf(_SC_NPROC_ONLN); -#elif defined (HPUX) -#include - n = mpctl(MPC_GETNUMSPUS, 0, 0); -#else - n = -1; - errno = ENOSYS; -#endif - - return n; -} - -/******************************************************************/ - diff --git a/trunk/3rdparty/st-srs/extensions/Makefile b/trunk/3rdparty/st-srs/extensions/Makefile deleted file mode 100644 index fc6634f93f..0000000000 --- a/trunk/3rdparty/st-srs/extensions/Makefile +++ /dev/null @@ -1,91 +0,0 @@ -# -# Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. -# All Rights Reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of Silicon Graphics, Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -CC = cc - -SHELL = /bin/sh -ECHO = /bin/echo - -DEPTH = .. -BUILD = -TARGETDIR = obj - -DEFINES = -OTHER_FLAGS = -CFLAGS = - -OBJDIR = $(DEPTH)/$(TARGETDIR) -INCDIR = $(DEPTH)/$(TARGETDIR) - -LIBRESOLV = -EXTRALIBS = - -SLIBRARY = $(OBJDIR)/libstx.a -OBJS = $(OBJDIR)/dnscache.o $(OBJDIR)/dnsres.o $(OBJDIR)/lrucache.o - - -CFLAGS += -Wall -I$(INCDIR) -AR = ar -ARFLAGS = rv -RANLIB = ranlib - - -########################## -# Platform section. -# - -ifeq (LINUX, $(findstring LINUX, $(OS))) -LIBRESOLV = -lresolv -endif - -ifeq ($(OS), SOLARIS) -LIBRESOLV = -lresolv -EXTRALIBS = -lsocket -lnsl -endif - -# -# End of platform section. -########################## - - -all: $(SLIBRARY) - -$(SLIBRARY): $(OBJS) - $(AR) $(ARFLAGS) $@ $(OBJS) - $(RANLIB) $@ - -$(OBJDIR)/%.o: %.c stx.h common.h - $(CC) $(CFLAGS) -c $< -o $@ - -clean: - rm -rf $(OBJS) $(SLIBRARY) - -#.DEFAULT: -# @cd $(DEPTH); $(MAKE) $@ - diff --git a/trunk/3rdparty/st-srs/extensions/README b/trunk/3rdparty/st-srs/extensions/README deleted file mode 100644 index f768aa7125..0000000000 --- a/trunk/3rdparty/st-srs/extensions/README +++ /dev/null @@ -1,42 +0,0 @@ -This directory contains extensions to the core State Threads Library -that were contributed by users. All files hereunder are not part of the -State Threads Library itself. They are provided as-is, without warranty -or support, and under whatever license terms their authors provided. To -contribute your own extensions, just mail them to the project -administrators or to one of the project's mailing lists; see -state-threads.sourceforge.net. Please indicate the license terms under -which the project may distribute your contribution. - -======================================================================== - -stx_fileio ----------- -Contributed by Jeff , 4 Nov 2002. - -Provides non-blocking random access file reading capability for -programs using the State Threads library. There is one public function: - -ssize_t stx_file_read(st_netfd_t fd, off_t offset, - void *buf, size_t nbytes, st_utime_t timeout); - -The implementation is not optimal in that the data is copied at least once -more than should be necessary. Its usefulness is limited to cases where -random access to a file is required and where starvation of other threads -is unacceptable. - -The particular application which motivated this implementation was a UDP -file transfer protocol. Because the OS does very little buffering of UDP -traffic it is important that UDP transmission threads are not starved for -periods of time which are long relative to the interval required to -maintain a steady send rate. - -Licensed under the same dual MPL/GPL as core State Threads. - -======================================================================== - -stx_dns -------- - -Documentation coming. - -======================================================================== diff --git a/trunk/3rdparty/st-srs/extensions/common.h b/trunk/3rdparty/st-srs/extensions/common.h deleted file mode 100644 index f6298ba09e..0000000000 --- a/trunk/3rdparty/st-srs/extensions/common.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _STX_COMMON_H_ -#define _STX_COMMON_H_ - -#include -#include - - -#define STX_BEGIN_MACRO { -#define STX_END_MACRO } - - -/***************************************** - * Circular linked list definitions - */ - -typedef struct _stx_clist { - struct _stx_clist *next; - struct _stx_clist *prev; -} stx_clist_t; - -/* Insert element "_e" into the list, before "_l" */ -#define STX_CLIST_INSERT_BEFORE(_e,_l) \ - STX_BEGIN_MACRO \ - (_e)->next = (_l); \ - (_e)->prev = (_l)->prev; \ - (_l)->prev->next = (_e); \ - (_l)->prev = (_e); \ - STX_END_MACRO - -/* Insert element "_e" into the list, after "_l" */ -#define STX_CLIST_INSERT_AFTER(_e,_l) \ - STX_BEGIN_MACRO \ - (_e)->next = (_l)->next; \ - (_e)->prev = (_l); \ - (_l)->next->prev = (_e); \ - (_l)->next = (_e); \ - STX_END_MACRO - -/* Append an element "_e" to the end of the list "_l" */ -#define STX_CLIST_APPEND_LINK(_e,_l) STX_CLIST_INSERT_BEFORE(_e,_l) - -/* Remove the element "_e" from it's circular list */ -#define STX_CLIST_REMOVE_LINK(_e) \ - STX_BEGIN_MACRO \ - (_e)->prev->next = (_e)->next; \ - (_e)->next->prev = (_e)->prev; \ - STX_END_MACRO - -/* Return the head/tail of the list */ -#define STX_CLIST_HEAD(_l) (_l)->next -#define STX_CLIST_TAIL(_l) (_l)->prev - -/* Return non-zero if the given circular list "_l" is empty, */ -/* zero if the circular list is not empty */ -#define STX_CLIST_IS_EMPTY(_l) \ - ((_l)->next == (_l)) - -/* Initialize a circular list */ -#define STX_CLIST_INIT_CLIST(_l) \ - STX_BEGIN_MACRO \ - (_l)->next = (_l); \ - (_l)->prev = (_l); \ - STX_END_MACRO - - -/***************************************** - * Useful macros - */ - -#ifndef offsetof -#define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier)) -#endif - -#define STX_MIN(a, b) (((a) < (b)) ? (a) : (b)) - -#endif /* !_STX_COMMON_H_ */ - diff --git a/trunk/3rdparty/st-srs/extensions/dnscache.c b/trunk/3rdparty/st-srs/extensions/dnscache.c deleted file mode 100644 index ac49166a14..0000000000 --- a/trunk/3rdparty/st-srs/extensions/dnscache.c +++ /dev/null @@ -1,190 +0,0 @@ -#include "stx.h" -#include "common.h" - - -/***************************************** - * Basic types definitions - */ - -typedef struct _stx_dns_data { - struct in_addr *addrs; - int num_addrs; - int cur; - time_t expires; -} stx_dns_data_t; - - -#define MAX_HOST_ADDRS 1024 - -static struct in_addr addr_list[MAX_HOST_ADDRS]; - -stx_cache_t *_stx_dns_cache = NULL; - -extern int _stx_dns_ttl; -extern int _stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs, - int *num_addrs, st_utime_t timeout); - - -static unsigned long hash_hostname(const void *key) -{ - const char *name = (const char *)key; - unsigned long hash = 0; - - while (*name) - hash = (hash << 4) - hash + *name++; /* hash = hash * 15 + *name++ */ - - return hash; -} - -static void cleanup_entry(void *key, void *data) -{ - if (key) - free(key); - - if (data) { - if (((stx_dns_data_t *)data)->addrs) - free(((stx_dns_data_t *)data)->addrs); - free(data); - } -} - -static int lookup_entry(const char *host, struct in_addr *addrs, - int *num_addrs, int rotate) -{ - stx_cache_entry_t *entry; - stx_dns_data_t *data; - int n; - - entry = stx_cache_entry_lookup(_stx_dns_cache, host); - if (entry) { - data = (stx_dns_data_t *)stx_cache_entry_getdata(entry); - if (st_time() <= data->expires) { - if (*num_addrs == 1) { - if (rotate) { - *addrs = data->addrs[data->cur++]; - if (data->cur >= data->num_addrs) - data->cur = 0; - } else { - *addrs = data->addrs[0]; - } - } else { - n = STX_MIN(*num_addrs, data->num_addrs); - memcpy(addrs, data->addrs, n * sizeof(*addrs)); - *num_addrs = n; - } - - stx_cache_entry_release(_stx_dns_cache, entry); - return 1; - } - - /* - * Cache entry expired: decrement its refcount and purge it from cache. - */ - stx_cache_entry_release(_stx_dns_cache, entry); - stx_cache_entry_delete(_stx_dns_cache, entry); - } - - return 0; -} - -static void insert_entry(const char *host, struct in_addr *addrs, int count) -{ - stx_cache_entry_t *entry; - stx_dns_data_t *data; - char *key; - size_t n; - - if (_stx_dns_ttl > 0) { - key = strdup(host); - data = (stx_dns_data_t *)malloc(sizeof(stx_dns_data_t)); - n = count * sizeof(*addrs); - if (data) { - data->addrs = (struct in_addr *)malloc(n); - if (data->addrs) - memcpy(data->addrs, addrs, n); - data->num_addrs = count; - data->cur = 0; - data->expires = st_time() + _stx_dns_ttl; - } - entry = stx_cache_entry_create(key, data, strlen(host) + 1 + - sizeof(stx_dns_data_t) + n + - stx_cache_entry_sizeof()); - if (key && data && data->addrs && entry && - stx_cache_entry_insert(_stx_dns_cache, entry) == 0) { - stx_cache_entry_release(_stx_dns_cache, entry); - return; - } - - if (entry) - stx_cache_entry_delete(_stx_dns_cache, entry); - else - cleanup_entry(key, data); - } -} - - - -int _stx_dns_cache_getaddrlist(const char *hostname, struct in_addr *addrs, - int *num_addrs, st_utime_t timeout, - int rotate) -{ - char host[128]; - int n, count; - - if (!_stx_dns_cache) - return _stx_dns_getaddrlist(hostname, addrs, num_addrs, timeout); - - for (n = 0; n < sizeof(host) - 1 && hostname[n]; n++) { - host[n] = tolower(hostname[n]); - } - host[n] = '\0'; - - if (lookup_entry(host, addrs, num_addrs, rotate)) - return 0; - - count = MAX_HOST_ADDRS; - if (_stx_dns_getaddrlist(host, addr_list, &count, timeout) < 0) - return -1; - n = STX_MIN(*num_addrs, count); - memcpy(addrs, addr_list, n * sizeof(*addrs)); - *num_addrs = n; - - insert_entry(host, addr_list, count); - return 0; -} - - -int stx_dns_cache_init(size_t max_size, size_t max_bytes, size_t hash_size) -{ - _stx_dns_cache = stx_cache_create(max_size, max_bytes, hash_size, - hash_hostname, - (long (*)(const void *, const void *))strcmp, - cleanup_entry); - if (!_stx_dns_cache) - return -1; - - return 0; -} - -void stx_dns_cache_getinfo(stx_cache_info_t *info) -{ - if (_stx_dns_cache) - stx_cache_getinfo(_stx_dns_cache, info); - else - memset(info, 0, sizeof(stx_cache_info_t)); -} - -int stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs, - int *num_addrs, st_utime_t timeout) -{ - return _stx_dns_cache_getaddrlist(hostname, addrs, num_addrs, timeout, 0); -} - -int stx_dns_getaddr(const char *hostname, struct in_addr *addr, - st_utime_t timeout) -{ - int n = 1; - - return _stx_dns_cache_getaddrlist(hostname, addr, &n, timeout, 1); -} - diff --git a/trunk/3rdparty/st-srs/extensions/dnsres.c b/trunk/3rdparty/st-srs/extensions/dnsres.c deleted file mode 100644 index 04a91ccafa..0000000000 --- a/trunk/3rdparty/st-srs/extensions/dnsres.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (c) 1985, 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Silicon Graphics, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "stx.h" - -#define MAXPACKET 1024 - -#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL) -#define NETDB_INTERNAL h_NETDB_INTERNAL -#endif - -/* New in Solaris 7 */ -#if !defined(_getshort) && defined(ns_get16) -#define _getshort(cp) ns_get16(cp) -#define _getlong(cp) ns_get32(cp) -#endif - -typedef union { - HEADER hdr; - u_char buf[MAXPACKET]; -} querybuf_t; - -int _stx_dns_ttl; - - -static int parse_answer(querybuf_t *ans, int len, struct in_addr *addrs, - int *num_addrs) -{ - char buf[MAXPACKET]; - HEADER *ahp; - u_char *cp, *eoa; - int type, n, i; - - ahp = &ans->hdr; - eoa = ans->buf + len; - cp = ans->buf + sizeof(HEADER); - h_errno = TRY_AGAIN; - _stx_dns_ttl = -1; - i = 0; - - while (ahp->qdcount > 0) { - ahp->qdcount--; - cp += dn_skipname(cp, eoa) + QFIXEDSZ; - } - while (ahp->ancount > 0 && cp < eoa && i < *num_addrs) { - ahp->ancount--; - if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0) - return -1; - cp += n; - if (cp + 4 + 4 + 2 >= eoa) - return -1; - type = _getshort(cp); - cp += 4; - if (type == T_A) - _stx_dns_ttl = _getlong(cp); - cp += 4; - n = _getshort(cp); - cp += 2; - if (type == T_A) { - if (n > sizeof(*addrs) || cp + n > eoa) - return -1; - memcpy(&addrs[i++], cp, n); - } - cp += n; - } - - *num_addrs = i; - return 0; -} - - -static int query_domain(st_netfd_t nfd, const char *name, - struct in_addr *addrs, int *num_addrs, - st_utime_t timeout) -{ - querybuf_t qbuf; - u_char *buf = qbuf.buf; - HEADER *hp = &qbuf.hdr; - int blen = sizeof(qbuf); - int i, len, id; - - for (i = 0; i < _res.nscount; i++) { - len = res_mkquery(QUERY, name, C_IN, T_A, NULL, 0, NULL, buf, blen); - if (len <= 0) { - h_errno = NO_RECOVERY; - return -1; - } - id = hp->id; - - if (st_sendto(nfd, buf, len, (struct sockaddr *)&(_res.nsaddr_list[i]), - sizeof(struct sockaddr), timeout) != len) { - h_errno = NETDB_INTERNAL; - /* EINTR means interrupt by other thread, NOT by a caught signal */ - if (errno == EINTR) - return -1; - continue; - } - - /* Wait for reply */ - do { - len = st_recvfrom(nfd, buf, blen, NULL, NULL, timeout); - if (len <= 0) - break; - } while (id != hp->id); - - if (len < HFIXEDSZ) { - h_errno = NETDB_INTERNAL; - if (len >= 0) - errno = EMSGSIZE; - else if (errno == EINTR) /* see the comment above */ - return -1; - continue; - } - - hp->ancount = ntohs(hp->ancount); - hp->qdcount = ntohs(hp->qdcount); - if ((hp->rcode != NOERROR) || (hp->ancount == 0)) { - switch (hp->rcode) { - case NXDOMAIN: - h_errno = HOST_NOT_FOUND; - break; - case SERVFAIL: - h_errno = TRY_AGAIN; - break; - case NOERROR: - h_errno = NO_DATA; - break; - case FORMERR: - case NOTIMP: - case REFUSED: - default: - h_errno = NO_RECOVERY; - } - continue; - } - - if (parse_answer(&qbuf, len, addrs, num_addrs) == 0) - return 0; - } - - return -1; -} - - -#define CLOSE_AND_RETURN(ret) \ - { \ - n = errno; \ - st_netfd_close(nfd); \ - errno = n; \ - return (ret); \ - } - - -int _stx_dns_getaddrlist(const char *host, struct in_addr *addrs, - int *num_addrs, st_utime_t timeout) -{ - char name[MAXDNAME], **domain; - const char *cp; - int s, n, maxlen, dots; - int trailing_dot, tried_as_is; - st_netfd_t nfd; - - if ((_res.options & RES_INIT) == 0 && res_init() == -1) { - h_errno = NETDB_INTERNAL; - return -1; - } - if (_res.options & RES_USEVC) { - h_errno = NETDB_INTERNAL; - errno = ENOSYS; - return -1; - } - if (!host || *host == '\0') { - h_errno = HOST_NOT_FOUND; - return -1; - } - - /* Create UDP socket */ - if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - h_errno = NETDB_INTERNAL; - return -1; - } - if ((nfd = st_netfd_open_socket(s)) == NULL) { - h_errno = NETDB_INTERNAL; - n = errno; - close(s); - errno = n; - return -1; - } - - maxlen = sizeof(name) - 1; - n = 0; - dots = 0; - trailing_dot = 0; - tried_as_is = 0; - - for (cp = host; *cp && n < maxlen; cp++) { - dots += (*cp == '.'); - name[n++] = *cp; - } - if (name[n - 1] == '.') - trailing_dot = 1; - - /* - * If there are dots in the name already, let's just give it a try - * 'as is'. The threshold can be set with the "ndots" option. - */ - if (dots >= _res.ndots) { - if (query_domain(nfd, host, addrs, num_addrs, timeout) == 0) - CLOSE_AND_RETURN(0); - if (h_errno == NETDB_INTERNAL && errno == EINTR) - CLOSE_AND_RETURN(-1); - tried_as_is = 1; - } - - /* - * We do at least one level of search if - * - there is no dot and RES_DEFNAME is set, or - * - there is at least one dot, there is no trailing dot, - * and RES_DNSRCH is set. - */ - if ((!dots && (_res.options & RES_DEFNAMES)) || - (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { - name[n++] = '.'; - for (domain = _res.dnsrch; *domain; domain++) { - strncpy(name + n, *domain, maxlen - n); - if (query_domain(nfd, name, addrs, num_addrs, timeout) == 0) - CLOSE_AND_RETURN(0); - if (h_errno == NETDB_INTERNAL && errno == EINTR) - CLOSE_AND_RETURN(-1); - if (!(_res.options & RES_DNSRCH)) - break; - } - } - - /* - * If we have not already tried the name "as is", do that now. - * note that we do this regardless of how many dots were in the - * name or whether it ends with a dot. - */ - if (!tried_as_is) { - if (query_domain(nfd, host, addrs, num_addrs, timeout) == 0) - CLOSE_AND_RETURN(0); - } - - CLOSE_AND_RETURN(-1); -} - diff --git a/trunk/3rdparty/st-srs/extensions/lrucache.c b/trunk/3rdparty/st-srs/extensions/lrucache.c deleted file mode 100644 index 33494fee62..0000000000 --- a/trunk/3rdparty/st-srs/extensions/lrucache.c +++ /dev/null @@ -1,343 +0,0 @@ -#include "stx.h" -#include "common.h" - - -/***************************************** - * Basic types definitions - */ - -struct _stx_centry { - void *key; /* key for doing lookups */ - void *data; /* data in the cache */ - size_t weight; /* "weight" of this entry */ - struct _stx_centry *next; /* next entry */ - struct _stx_centry **pthis; - stx_clist_t lru_link; /* for putting this entry on LRU list */ - int ref_count; /* use count for this entry */ - int delete_pending; /* pending delete flag */ -}; - -struct _stx_cache { - size_t max_size; /* max size of cache */ - size_t cur_size; /* current size of cache */ - - size_t max_weight; /* cache capacity */ - size_t cur_weight; /* current total "weight" of all entries */ - - size_t hash_size; /* size of hash table */ - stx_cache_entry_t **table; /* hash table for this cache */ - - stx_clist_t lru_list; /* least-recently-used list */ - - /* Cache stats */ - unsigned long hits; /* num cache hits */ - unsigned long lookups; /* num cache lookups */ - unsigned long inserts; /* num inserts */ - unsigned long deletes; /* num deletes */ - - /* Functions */ - unsigned long (*key_hash_fn)(const void *); - long (*key_cmp_fn)(const void *, const void *); - void (*cleanup_fn)(void *, void *); -}; - - -#define STX_CACHE_ENTRY_PTR(_qp) \ - ((stx_cache_entry_t *)((char *)(_qp) - offsetof(stx_cache_entry_t, lru_link))) - - -/***************************************** - * Cache methods - */ - -stx_cache_t *stx_cache_create(size_t max_size, size_t max_weight, - size_t hash_size, - unsigned long (*key_hash_fn)(const void *key), - long (*key_cmp_fn)(const void *key1, - const void *key2), - void (*cleanup_fn)(void *key, void *data)) -{ - stx_cache_t *newcache; - - newcache = (stx_cache_t *)calloc(1, sizeof(stx_cache_t)); - if (newcache == NULL) - return NULL; - newcache->table = (stx_cache_entry_t **)calloc(hash_size, - sizeof(stx_cache_entry_t *)); - if (newcache->table == NULL) { - free(newcache); - return NULL; - } - - newcache->max_size = max_size; - newcache->max_weight = max_weight; - newcache->hash_size = hash_size; - STX_CLIST_INIT_CLIST(&(newcache->lru_list)); - newcache->key_hash_fn = key_hash_fn; - newcache->key_cmp_fn = key_cmp_fn; - newcache->cleanup_fn = cleanup_fn; - - return newcache; -} - - -void stx_cache_empty(stx_cache_t *cache) -{ - size_t i; - stx_cache_entry_t *entry, *next_entry; - - for (i = 0; i < cache->hash_size; i++) { - entry = cache->table[i]; - while (entry) { - next_entry = entry->next; - stx_cache_entry_delete(cache, entry); - entry = next_entry; - } - } -} - - -void stx_cache_traverse(stx_cache_t *cache, - void (*callback)(void *key, void *data)) -{ - size_t i; - stx_cache_entry_t *entry; - - for (i = 0; i < cache->hash_size; i++) { - for (entry = cache->table[i]; entry; entry = entry->next) { - if (!entry->delete_pending) - (*callback)(entry->key, entry->data); - } - } -} - - -void stx_cache_traverse_lru(stx_cache_t *cache, - void (*callback)(void *key, void *data), - unsigned int n) -{ - stx_clist_t *q; - stx_cache_entry_t *entry; - - for (q = STX_CLIST_HEAD(&cache->lru_list); q != &cache->lru_list && n; - q = q->next, n--) { - entry = STX_CACHE_ENTRY_PTR(q); - (*callback)(entry->key, entry->data); - } -} - - -void stx_cache_traverse_mru(stx_cache_t *cache, - void (*callback)(void *key, void *data), - unsigned int n) -{ - stx_clist_t *q; - stx_cache_entry_t *entry; - - for (q = STX_CLIST_TAIL(&cache->lru_list); q != &cache->lru_list && n; - q = q->prev, n--) { - entry = STX_CACHE_ENTRY_PTR(q); - (*callback)(entry->key, entry->data); - } -} - - -size_t stx_cache_getsize(stx_cache_t *cache) -{ - return cache->cur_size; -} - - -size_t stx_cache_getweight(stx_cache_t *cache) -{ - return cache->cur_weight; -} - - -void stx_cache_getinfo(stx_cache_t *cache, stx_cache_info_t *info) -{ - info->max_size = cache->max_size; - info->max_weight = cache->max_weight; - info->hash_size = cache->hash_size; - info->cur_size = cache->cur_size; - info->cur_weight = cache->cur_weight; - info->hits = cache->hits; - info->lookups = cache->lookups; - info->inserts = cache->inserts; - info->deletes = cache->deletes; -} - - -/***************************************** - * Cache entry methods - */ - -stx_cache_entry_t *stx_cache_entry_create(void *key, void *data, - size_t weight) -{ - stx_cache_entry_t *newentry; - - newentry = (stx_cache_entry_t *)calloc(1, sizeof(stx_cache_entry_t)); - if (newentry == NULL) - return NULL; - - newentry->key = key; - newentry->data = data; - newentry->weight = weight; - - return newentry; -} - - -void stx_cache_entry_delete(stx_cache_t *cache, stx_cache_entry_t *entry) -{ - entry->delete_pending = 1; - - if (entry->ref_count > 0) - return; - - if (entry->pthis) { - *entry->pthis = entry->next; - if (entry->next) - entry->next->pthis = entry->pthis; - - cache->cur_size--; - cache->cur_weight -= entry->weight; - cache->deletes++; - STX_CLIST_REMOVE_LINK(&(entry->lru_link)); - } - - if (cache->cleanup_fn) - cache->cleanup_fn(entry->key, entry->data); - - entry->pthis = NULL; - entry->key = NULL; - entry->data = NULL; - free(entry); -} - - -stx_cache_entry_t *stx_cache_entry_lookup(stx_cache_t *cache, const void *key) -{ - unsigned long bucket; - stx_cache_entry_t *entry; - - cache->lookups++; - bucket = cache->key_hash_fn(key) % cache->hash_size; - for (entry = cache->table[bucket]; entry; entry = entry->next) { - if (!entry->delete_pending && cache->key_cmp_fn(key, entry->key) == 0) - break; - } - if (entry) { - cache->hits++; - if (entry->ref_count == 0) - STX_CLIST_REMOVE_LINK(&(entry->lru_link)); - entry->ref_count++; - } - - return entry; -} - - -void stx_cache_entry_release(stx_cache_t *cache, stx_cache_entry_t *entry) -{ - if (entry->ref_count == 0) - return; - - entry->ref_count--; - - if (entry->ref_count == 0) { - STX_CLIST_APPEND_LINK(&(entry->lru_link), &(cache->lru_list)); - if (entry->delete_pending) - stx_cache_entry_delete(cache, entry); - } -} - - -int stx_cache_entry_insert(stx_cache_t *cache, stx_cache_entry_t *entry) -{ - stx_cache_entry_t *old_entry; - unsigned long bucket; - - /* - * If cache capacity is exceeded, try to remove LRU entries till there is - * enough room or LRU list is empty. - */ - while (cache->cur_weight + entry->weight > cache->max_weight) { - old_entry = stx_cache_entry_getlru(cache); - if (!old_entry) { - /* cache capacity is exceeded and all entries are in use */ - return -1; - } - stx_cache_entry_delete(cache, old_entry); - } - - /* If cache size is exceeded, remove LRU entry */ - if (cache->cur_size >= cache->max_size) { - old_entry = stx_cache_entry_getlru(cache); - if (!old_entry) { - /* cache size is exceeded and all entries are in use */ - return -1; - } - stx_cache_entry_delete(cache, old_entry); - } - - /* Don't add duplicate entries in the cache */ - bucket = cache->key_hash_fn(entry->key) % cache->hash_size; - for (old_entry = cache->table[bucket]; old_entry; - old_entry = old_entry->next) { - if (!old_entry->delete_pending && - cache->key_cmp_fn(entry->key, old_entry->key) == 0) - break; - } - if (old_entry) - stx_cache_entry_delete(cache, old_entry); - - /* Insert in the hash table */ - entry->next = cache->table[bucket]; - cache->table[bucket] = entry; - entry->pthis = &cache->table[bucket]; - if (entry->next) - entry->next->pthis = &entry->next; - entry->ref_count++; - - cache->inserts++; - cache->cur_size++; - cache->cur_weight += entry->weight; - - return 0; -} - - -stx_cache_entry_t *stx_cache_entry_getlru(stx_cache_t *cache) -{ - if (STX_CLIST_IS_EMPTY(&(cache->lru_list))) - return NULL; - - return STX_CACHE_ENTRY_PTR(STX_CLIST_HEAD(&(cache->lru_list))); -} - - -int stx_cache_entry_sizeof(void) -{ - return (int)sizeof(stx_cache_entry_t); -} - - -void *stx_cache_entry_getdata(stx_cache_entry_t *entry) -{ - return entry->data; -} - - -void *stx_cache_entry_getkey(stx_cache_entry_t *entry) -{ - return entry->key; -} - - -size_t stx_cache_entry_getweight(stx_cache_entry_t *entry) -{ - return entry->weight; -} - diff --git a/trunk/3rdparty/st-srs/extensions/print_stk.patch b/trunk/3rdparty/st-srs/extensions/print_stk.patch deleted file mode 100644 index f7451c7b07..0000000000 --- a/trunk/3rdparty/st-srs/extensions/print_stk.patch +++ /dev/null @@ -1,367 +0,0 @@ -Michael Abd-El-Malek contributed this patch. He wrote: ----------------------------------------- -Hello, - -This is a patch that enables programmatically dumping the stack of -every thread. This has been useful in debugging deadlocks, etc... -Our usage model is that the SIGUSR2 handler calls the new -_st_print_thread_stacks function, which dumps the stack for all -threads. A convenient feature is that for thread stacks that are the -same (which is common for application with a lot of worker threads -waiting for work), only one stack trace is printed, along with a -count of how many threads have that same stack. - -I use the glibc backtrace function to get the backtrace, and then use -popen to execute addr2line and convert memory addresses to file -names, function names, and line numbers. If glibc isn't available, -_st_print_thread_stacks just prints a warning. And this feature is -only available if DEBUG is turned on. - -We've found this feature extremely helpful when debugging. - -The patch can be a bit more robust (it assumes addr2line exists). -But I didn't want to go through the hassle of doing this, if the -StateThreads community doesn't want to use this patch. (In our -environment, addr2line will always be there.) - -Cheers, -Mike ----------------------------------------- -Invoking complex functions from a signal handler is not recommended, -plus this patch changes the behavior of existing API hooks. It will -not become part of State Threads proper but you may find it useful -nonetheless. This patch applies to st-1.5.2. - -diff -Nur Makefile.1.5.2 Makefile ---- Makefile.1.5.2 Wed Sep 7 14:19:50 2005 -+++ Makefile Wed Sep 7 14:33:08 2005 -@@ -255,7 +255,8 @@ - $(TARGETDIR)/stk.o \ - $(TARGETDIR)/sync.o \ - $(TARGETDIR)/key.o \ -- $(TARGETDIR)/io.o -+ $(TARGETDIR)/io.o \ -+ $(TARGETDIR)/backtrace.o - OBJS += $(EXTRA_OBJS) - HEADER = $(TARGETDIR)/st.h - SLIBRARY = $(TARGETDIR)/libst.a -diff -Nur backtrace.c.1.5.2 backtrace.c ---- backtrace.c.1.5.2 Wed Dec 31 16:00:00 1969 -+++ backtrace.c Wed Sep 7 13:40:21 2005 -@@ -0,0 +1,211 @@ -+/* -+ * The contents of this file are subject to the Mozilla Public -+ * License Version 1.1 (the "License"); you may not use this file -+ * except in compliance with the License. You may obtain a copy of -+ * the License at http://www.mozilla.org/MPL/ -+ * -+ * Software distributed under the License is distributed on an "AS -+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -+ * implied. See the License for the specific language governing -+ * rights and limitations under the License. -+ * -+ * Contributor(s): Michael Abd-El-Malek (mabdelmalek@cmu.edu) -+ * Carnegie Mellon University -+ * -+ * Alternatively, the contents of this file may be used under the -+ * terms of the GNU General Public License Version 2 or later (the -+ * "GPL"), in which case the provisions of the GPL are applicable -+ * instead of those above. If you wish to allow use of your -+ * version of this file only under the terms of the GPL and not to -+ * allow others to use your version of this file under the MPL, -+ * indicate your decision by deleting the provisions above and -+ * replace them with the notice and other provisions required by -+ * the GPL. If you do not delete the provisions above, a recipient -+ * may use your version of this file under either the MPL or the -+ * GPL. -+ */ -+ -+ -+ -+/* -+ * This file contains routines for printing a stack trace of all threads. -+ * Only works when DEBUG is defined and where glibc is available, since it -+ * provides the backtrace() function. -+ */ -+ -+#define _GNU_SOURCE /* to get program_invocation_name */ -+ -+#include -+#include -+ -+ -+#if defined(DEBUG) && defined(__GLIBC__) -+ -+#include -+#include "common.h" -+#include -+#include -+#include -+ -+ -+/* The maximum number of frames to get a stack trace for. If a thread has more -+ * frames than this, then we only show the latest X frames. */ -+#define MAX_NUM_FRAMES 64 -+ -+ -+typedef struct thread_stack_s { -+ uint32_t num_frames; -+ void* addresses[MAX_NUM_FRAMES]; /* frame pointers */ -+ char* locations[MAX_NUM_FRAMES]; /* file/function/line numbers */ -+ uint32_t num_matches; -+ -+ struct thread_stack_s* next; -+} thread_stack_t; -+ -+static thread_stack_t* stacks = NULL; -+ -+ -+/* Converts the function's memory addresses to function names, file names, and -+ * line numbers. Calls binutil's addr2line program. */ -+static void get_symbol_names(thread_stack_t *stack) -+{ -+ char program_to_run[1024], function[256], filename_lineno[256], temp[19]; -+ FILE* output; -+ int num_bytes_left; -+ uint32_t i; -+ -+ /* Construct the arguments to addr2line */ -+ num_bytes_left = sizeof(program_to_run); -+ num_bytes_left -= snprintf(program_to_run, sizeof(program_to_run), -+ "addr2line -fCe %s", program_invocation_name); -+ for (i = 0; i < stack->num_frames && num_bytes_left > 0; ++i) { -+ num_bytes_left -= snprintf(temp, sizeof(temp), " %p", stack->addresses[i]); -+ strncat(program_to_run, temp, num_bytes_left); -+ } -+ -+ /* Use popen to execute addr2line and read its ouput */ -+ output = popen(program_to_run, "r"); -+ for (i = 0; i < stack->num_frames; ++i) { -+ char* function_listing = (char*) malloc(512); -+ fscanf(output, "%255s\n", function); -+ fscanf(output, "%255s\n", filename_lineno); -+ snprintf(function_listing, 512, "%s at %s", function, filename_lineno); -+ stack->locations[i] = function_listing; -+ } -+ pclose(output); -+} -+ -+ -+static void print_stack(thread_stack_t* stack) -+{ -+ int skip_offset = 0, cmp_len; -+ uint32_t i; -+ -+ /* Get the function names/filenames/line numbers */ -+ get_symbol_names(stack); -+ -+ cmp_len = strlen("_st_iterate_threads_helper"); -+ -+ /* Print the backtrace */ -+ for (i = 0; i < stack->num_frames; ++i) { -+ /* Skip frames we don't have location info for */ -+ if (!strncmp(stack->locations[i], "??", 2)) { -+ continue; -+ } -+ -+ /* Skip the frames that are used for printing the stack trace */ -+ if (skip_offset) { -+ printf("\t#%2d %s %p\n", i - skip_offset, stack->locations[i], -+ stack->addresses[i]); -+ } else if (!strncmp(stack->locations[i], "_st_iterate_threads_helper", -+ cmp_len)) { -+ skip_offset = i + 1; -+ } -+ } -+} -+ -+ -+static void add_current_thread_stack(void) -+{ -+ thread_stack_t *new_stack = malloc(sizeof(thread_stack_t)); -+ thread_stack_t *search; -+ -+ /* Call glibc function to get the backtrace */ -+ new_stack->num_frames = backtrace(new_stack->addresses, MAX_NUM_FRAMES); -+ -+ /* Check if we have another stacks that is equivalent. If so, then coaelsce -+ * two stacks into one, to minimize output to user. */ -+ search = stacks; -+ while (search) { -+ if (search->num_frames == new_stack->num_frames && -+ !memcmp(search->addresses, new_stack->addresses, -+ search->num_frames * sizeof(void*))) { -+ /* Found an existing stack that is the same as this thread's stack */ -+ ++search->num_matches; -+ free(new_stack); -+ return; -+ } else { -+ search = search->next; -+ } -+ } -+ -+ /* This is a new stack. Add it to the list of stacks. */ -+ new_stack->num_matches = 1; -+ new_stack->next = stacks; -+ stacks = new_stack; -+} -+ -+static void print_stack_frames(void) -+{ -+ while (stacks) { -+ printf("\n%u thread(s) with this backtrace:\n", stacks->num_matches); -+ print_stack(stacks); -+ stacks = stacks->next; -+ } -+ printf("\n"); -+} -+ -+static void free_stacks(void) -+{ -+ uint32_t i; -+ while (stacks) { -+ thread_stack_t *next = stacks->next; -+ for (i = 0; i < stacks->num_frames; ++i) { -+ free(stacks->locations[i]); -+ } -+ free(stacks); -+ stacks = next; -+ } -+ stacks = NULL; -+} -+ -+ -+static void st_print_thread_stack(_st_thread_t *thread, int start_flag, -+ int end_flag) -+{ -+ if (end_flag == 0) { -+ add_current_thread_stack(); -+ } else { -+ print_stack_frames(); -+ } -+} -+ -+ -+void _st_print_thread_stacks(int ignore) -+{ -+ _st_iterate_threads_flag = 1; -+ _st_iterate_threads_helper(st_print_thread_stack); -+ _st_iterate_threads_flag = 0; -+ -+ /* Deallocate memory */ -+ free_stacks(); -+} -+ -+#else /* defined(DEBUG) && defined(__GLIBC__) */ -+ -+void _st_print_thread_stacks(int ignore) -+{ -+ printf("%s: need DEBUG mode and glibc-specific functions to read stack.\n", -+ __FUNCTION__); -+} -+#endif /* defined(DEBUG) && defined(__GLIBC__) */ -diff -Nur common.h.1.5.2 common.h ---- common.h.1.5.2 Wed Sep 7 14:18:37 2005 -+++ common.h Wed Sep 7 14:35:36 2005 -@@ -371,8 +371,18 @@ - */ - - #ifdef DEBUG --void _st_iterate_threads(void); --#define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads() -+typedef void(*_st_func_ptr_t)(_st_thread_t *thread, -+ int start_flag, -+ int end_flag); -+/* Pointer to function that will be called on thread switch */ -+extern _st_func_ptr_t _st_iterate_func_ptr; -+extern int _st_iterate_threads_flag; -+/* Thread iteration function that will call an arbitrary function */ -+extern void _st_iterate_threads_helper(_st_func_ptr_t func); -+#define ST_DEBUG_ITERATE_THREADS() \ -+ if (_st_iterate_func_ptr) { \ -+ _st_iterate_threads_helper(_st_iterate_func_ptr); \ -+ } - #else - #define ST_DEBUG_ITERATE_THREADS() - #endif -diff -Nur public.h.1.5.2 public.h ---- public.h.1.5.2 Wed Sep 7 11:46:58 2005 -+++ public.h Wed Sep 7 13:38:46 2005 -@@ -171,8 +171,10 @@ - extern st_netfd_t st_open(const char *path, int oflags, mode_t mode); - - #ifdef DEBUG --extern void _st_show_thread_stack(st_thread_t thread, const char *messg); -+extern void _st_show_thread_stack(st_thread_t thread, int start_flag, -+ int end_flag); - extern void _st_iterate_threads(void); -+extern void _st_print_thread_stacks(int ignore); - #endif - - #ifdef __cplusplus -diff -Nur sched.c.1.5.2 sched.c ---- sched.c.1.5.2 Wed Sep 7 10:48:05 2005 -+++ sched.c Wed Sep 7 13:38:46 2005 -@@ -919,16 +919,13 @@ - - - #ifdef DEBUG --/* ARGSUSED */ --void _st_show_thread_stack(_st_thread_t *thread, const char *messg) --{ -- --} -- - /* To be set from debugger */ - int _st_iterate_threads_flag = 0; -+/* Thread iteration function that will call an arbitrary function */ -+_st_func_ptr_t _st_iterate_func_ptr = NULL; - --void _st_iterate_threads(void) -+/* This function iterates over all threads, calling "func" for each thread. */ -+void _st_iterate_threads_helper(_st_func_ptr_t func) - { - static _st_thread_t *thread = NULL; - static jmp_buf orig_jb, save_jb; -@@ -944,16 +941,20 @@ - - if (thread) { - memcpy(thread->context, save_jb, sizeof(jmp_buf)); -- _st_show_thread_stack(thread, NULL); -+ func(thread, 0, 0); - } else { - if (MD_SETJMP(orig_jb)) { - _st_iterate_threads_flag = 0; -+ _st_iterate_func_ptr = NULL; - thread = NULL; -- _st_show_thread_stack(thread, "Iteration completed"); -+ /* Last thread to iterate through */ -+ func(thread, 0, 1); - return; - } -+ /* First thread to iterate through */ - thread = _ST_CURRENT_THREAD(); -- _st_show_thread_stack(thread, "Iteration started"); -+ _st_iterate_func_ptr = func; -+ func(thread, 1, 0); - } - - q = thread->tlink.next; -@@ -966,5 +967,17 @@ - memcpy(save_jb, thread->context, sizeof(jmp_buf)); - MD_LONGJMP(thread->context, 1); - } -+ -+/* ARGSUSED */ -+void _st_show_thread_stack(_st_thread_t *thread, int start_flag, int end_flag) -+{ -+} -+ -+/* Iterate over threads inside debugger; see st/README */ -+void _st_iterate_threads(void) -+{ -+ _st_iterate_threads_helper(_st_show_thread_stack); -+} -+ - #endif /* DEBUG */ - diff --git a/trunk/3rdparty/st-srs/extensions/stx.h b/trunk/3rdparty/st-srs/extensions/stx.h deleted file mode 100644 index 8371e0d93c..0000000000 --- a/trunk/3rdparty/st-srs/extensions/stx.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef _STX_H_ -#define _STX_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "st.h" - - -#ifdef __cplusplus -extern "C" { -#endif - - -/***************************************** - * Basic types definitions - */ - -typedef struct _stx_centry stx_cache_entry_t; -typedef struct _stx_cache stx_cache_t; - -/* This is public type */ -typedef struct _stx_cache_info { - size_t max_size; - size_t max_weight; - size_t hash_size; - size_t cur_size; - size_t cur_weight; - unsigned long hits; - unsigned long lookups; - unsigned long inserts; - unsigned long deletes; -} stx_cache_info_t; - - -/***************************************** - * Cache and cache entry methods - */ - -stx_cache_t *stx_cache_create(size_t max_size, size_t max_weight, - size_t hash_size, - unsigned long (*key_hash_fn)(const void *key), - long (*key_cmp_fn)(const void *key1, - const void *key2), - void (*cleanup_fn)(void *key, void *data)); -void stx_cache_empty(stx_cache_t *cache); -void stx_cache_traverse(stx_cache_t *cache, - void (*callback)(void *key, void *data)); -void stx_cache_traverse_lru(stx_cache_t *, void (*)(void *, void *), - unsigned int); -void stx_cache_traverse_mru(stx_cache_t *, void (*)(void *, void *), - unsigned int); -void stx_cache_getinfo(stx_cache_t *cache, stx_cache_info_t *info); -size_t stx_cache_getsize(stx_cache_t *cache); -size_t stx_cache_getweight(stx_cache_t *cache); - - -stx_cache_entry_t *stx_cache_entry_create(void *key, void *data, - size_t weight); -void stx_cache_entry_delete(stx_cache_t *cache, stx_cache_entry_t *entry); -stx_cache_entry_t *stx_cache_entry_lookup(stx_cache_t *cache, const void *key); -void stx_cache_entry_release(stx_cache_t *, stx_cache_entry_t *); -int stx_cache_entry_insert(stx_cache_t *cache, stx_cache_entry_t *entry); -stx_cache_entry_t *stx_cache_entry_getlru(stx_cache_t *cache); -int stx_cache_entry_sizeof(void); -void *stx_cache_entry_getdata(stx_cache_entry_t *entry); -void *stx_cache_entry_getkey(stx_cache_entry_t *entry); -size_t stx_cache_entry_getweight(stx_cache_entry_t *entry); - - -int stx_dns_cache_init(size_t max_size, size_t max_bytes, size_t hash_size); -void stx_dns_cache_getinfo(stx_cache_info_t *info); -int stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs, - int *num_addrs, st_utime_t timeout); -int stx_dns_getaddr(const char *hostname, struct in_addr *addr, - st_utime_t timeout); - -#ifdef __cplusplus -} -#endif - -#endif /* !_STX_H_ */ - diff --git a/trunk/3rdparty/st-srs/extensions/stx_fileio.c b/trunk/3rdparty/st-srs/extensions/stx_fileio.c deleted file mode 100644 index cb24346e8a..0000000000 --- a/trunk/3rdparty/st-srs/extensions/stx_fileio.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * File I/O extension to the State Threads Library. - */ - -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the file I/O extension to the State Threads Library. - * - * The Initial Developer of the Original Code is Jeff - * . Portions created by the Initial - * Developer are Copyright (C) 2002 the Initial Developer. All Rights - * Reserved. - * - * Contributor(s): (none) - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -#include - -#include "stx_fileio.h" - -#define STX_FILEIO_SIGNUM SIGUSR2 - -typedef struct { - st_netfd_t data_fd; - st_netfd_t control_fd; - pid_t pid; -} fileio_data_t; - -#define FILEREADER_MAX_READ 1024 - -typedef struct { - off_t offset; - ssize_t nbytes; -} file_reader_cb_t; - -/** - * Fork a process to read a file and return its pid. Receives - * offset/length commands from control stream and sends corresponding data - * to out stream. A zero length on the control stream signals an end. - * - * @param fd stream from which to read - * @param control_out receives the file descriptor to which control commands can be sent - * @param fd_out receives the file descriptor from which the output of the command can be read. - * @return PID of the process created to execute the command - */ -pid_t -file_reader(int fd, int *fd_control, int *fd_out) -{ - pid_t pid; - int control_pipe[2], out_pipe[2]; - - if (pipe(control_pipe) < 0 || pipe(out_pipe) < 0) - return (pid_t)-1; - - pid = fork(); - if (pid == (pid_t) -1) - { - close(control_pipe[0]); - close(control_pipe[1]); - close(out_pipe[0]); - close(out_pipe[1]); - return pid; - } - else if (pid == (pid_t) 0) - { - // child - off_t pos = 0; - file_reader_cb_t cb; - char buf[FILEREADER_MAX_READ]; - if (fd == -1) - _exit(EXIT_FAILURE); - - while (sizeof(cb) == read(control_pipe[0], &cb, sizeof(cb))) { - ssize_t nb; - if (0 >= cb.nbytes) - goto clean_exit; - if (pos != cb.offset) { - pos = lseek(fd, cb.offset, SEEK_SET); - if (pos == (off_t)-1) - break; - } - nb = read(fd, buf, cb.nbytes); - if (nb == (ssize_t)-1) - break; - pos += nb; - write(out_pipe[1], (char *)&nb, sizeof(nb)); - write(out_pipe[1], buf, nb); - } - perror("ERROR: file_reader: "); - clean_exit: - close(control_pipe[0]); - close(control_pipe[1]); - close(out_pipe[0]); - close(out_pipe[1]); - _exit(EXIT_SUCCESS); - } - - // parent - close(out_pipe[1]); - close(control_pipe[0]); - *fd_out = out_pipe[0]; - *fd_control = control_pipe[1]; - return pid; -} - -/** - * fileio_data_t destructor callback - */ -static void -fileio_data_destructor(void *dat_in) -{ - if (dat_in) { - fileio_data_t *dat = (fileio_data_t *)dat_in; - file_reader_cb_t cb; - cb.offset = 0; - cb.nbytes = 0; - st_write(dat->control_fd, (char *)&cb, sizeof(cb), - ST_UTIME_NO_TIMEOUT); - waitpid(dat->pid, NULL, 0); - st_netfd_close(dat->control_fd); - st_netfd_close(dat->data_fd); - free(dat_in); - } -} - -/** - * Retrieve fileio_data_t struct from an st descriptor. Create and store - * a new one if needed. - */ -static fileio_data_t *get_fileio_data(st_netfd_t fd) -{ - fileio_data_t *dat = (fileio_data_t *)st_netfd_getspecific(fd); - if (!dat) { - int fd_control, fd_out; - pid_t pid = file_reader(st_netfd_fileno(fd), &fd_control, &fd_out); - if (pid != (pid_t)-1) { - dat = (fileio_data_t *)calloc(1, sizeof(fileio_data_t)); - dat->control_fd = st_netfd_open(fd_control); - dat->data_fd = st_netfd_open(fd_out); - dat->pid = pid; - st_netfd_setspecific(fd, dat, fileio_data_destructor); - } - } - return dat; -} - -/** - * Read data from the specified section of a file. Uses a forked - * file_reader process to do the actual reading so as to avoid causing all - * State Threads to block. - * - * @param fd must refer to a seekable file. - * @param offset absolute offset within the file - * @param buf output buffer - * @param nbytes size of the output buffer - * @param timeout - */ -ssize_t -stx_file_read(st_netfd_t fd, off_t offset, void *buf, size_t nbytes, st_utime_t timeout) -{ - fileio_data_t *dat = get_fileio_data(fd); - if (dat) { - file_reader_cb_t cb; - ssize_t ret = (ssize_t)-1; - cb.offset = offset; - cb.nbytes = nbytes; - st_write(dat->control_fd, (char *)&cb, sizeof(cb), timeout); - if (sizeof(ret) == st_read(dat->data_fd, (char *)&ret, sizeof(ret), timeout) && 0 < ret && ret <= nbytes) { - return st_read(dat->data_fd, buf, ret, timeout); - } else { - return ret; - } - } - - return (ssize_t)-1; -} diff --git a/trunk/3rdparty/st-srs/extensions/stx_fileio.h b/trunk/3rdparty/st-srs/extensions/stx_fileio.h deleted file mode 100644 index b6bec190b7..0000000000 --- a/trunk/3rdparty/st-srs/extensions/stx_fileio.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * File I/O extension to the State Threads Library. - */ - -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the file I/O extension to the State Threads Library. - * - * The Initial Developer of the Original Code is Jeff - * . Portions created by the Initial - * Developer are Copyright (C) 2002 the Initial Developer. All Rights - * Reserved. - * - * Contributor(s): (none) - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -#ifndef __STX_FILEIO_H__ -#define __STX_FILEIO_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern ssize_t stx_file_read(st_netfd_t fd, off_t offset, void *buf, size_t nbytes, st_utime_t timeout); - -#ifdef __cplusplus -} -#endif -#endif /* !__STX_FILEIO_H__ */ diff --git a/trunk/3rdparty/st-srs/extensions/testdns.c b/trunk/3rdparty/st-srs/extensions/testdns.c deleted file mode 100644 index aa896b25e5..0000000000 --- a/trunk/3rdparty/st-srs/extensions/testdns.c +++ /dev/null @@ -1,112 +0,0 @@ -#include "stx.h" -#include -#include - - -#define MAX_ADDRS 128 -#define TIMEOUT (4*1000000LL) - -static void do_resolve(const char *host) -{ - struct in_addr addrs[MAX_ADDRS]; - int i, n = MAX_ADDRS; - - if (stx_dns_getaddrlist(host, addrs, &n, TIMEOUT) < 0) { - fprintf(stderr, "stx_dns_getaddrlist: can't resolve %s: ", host); - if (h_errno == NETDB_INTERNAL) - perror(""); - else - herror(""); - } else { - if (n > 0) - printf("%-40s %s\n", (char *)host, inet_ntoa(addrs[0])); - for (i = 1; i < n; i++) - printf("%-40s %s\n", "", inet_ntoa(addrs[i])); - } -} - -static void show_info(void) -{ - stx_cache_info_t info; - - stx_dns_cache_getinfo(&info); - printf("DNS cache info:\n\n"); - printf("max_size: %8d\n", (int)info.max_size); - printf("capacity: %8d bytes\n", (int)info.max_weight); - printf("hash_size: %8d\n", (int)info.hash_size); - printf("cur_size: %8d\n" - "cur_mem: %8d bytes\n" - "hits: %8d\n" - "lookups: %8d\n" - "inserts: %8d\n" - "deletes: %8d\n", - (int)info.cur_size, (int)info.cur_weight, (int)info.hits, - (int)info.lookups, (int)info.inserts, (int)info.deletes); -} - -extern stx_cache_t *_stx_dns_cache; - -static void printhost(void *host, void *data) -{ - printf("%s\n", (char *)host); -} - -static void show_lru(void) -{ - printf("LRU hosts:\n\n"); - stx_cache_traverse_lru(_stx_dns_cache, printhost, 10); -} - -static void show_mru(void) -{ - printf("MRU hosts:\n\n"); - stx_cache_traverse_mru(_stx_dns_cache, printhost, 10); -} - -static void flush_cache(void) -{ - stx_cache_empty(_stx_dns_cache); - printf("DNS cache is empty\n"); -} - - -int main() -{ - char line[256]; - char str[sizeof(line)]; - - st_init(); - stx_dns_cache_init(100, 10000, 101); - - for ( ; ; ) { - fputs("> ", stdout); - fflush(stdout); - if (!fgets(line, sizeof(line), stdin)) - break; - if (sscanf(line, "%s", str) != 1) - continue; - if (strcmp(str, "exit") == 0 || strcmp(str, "quit") == 0) - break; - if (strcmp(str, "info") == 0) { - show_info(); - continue; - } - if (strcmp(str, "lru") == 0) { - show_lru(); - continue; - } - if (strcmp(str, "mru") == 0) { - show_mru(); - continue; - } - if (strcmp(str, "flush") == 0) { - flush_cache(); - continue; - } - - do_resolve(str); - } - - return 0; -} - diff --git a/trunk/3rdparty/st-srs/io.c b/trunk/3rdparty/st-srs/io.c deleted file mode 100644 index 912de0b286..0000000000 --- a/trunk/3rdparty/st-srs/io.c +++ /dev/null @@ -1,769 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - - -#if EAGAIN != EWOULDBLOCK - #define _IO_NOT_READY_ERROR ((errno == EAGAIN) || (errno == EWOULDBLOCK)) -#else - #define _IO_NOT_READY_ERROR (errno == EAGAIN) -#endif - -#define _LOCAL_MAXIOV 16 - -/* File descriptor object free list */ -static _st_netfd_t *_st_netfd_freelist = NULL; -/* Maximum number of file descriptors that the process can open */ -static int _st_osfd_limit = -1; - -static void _st_netfd_free_aux_data(_st_netfd_t *fd); - -int _st_io_init(void) -{ - struct sigaction sigact; - struct rlimit rlim; - int fdlim; - - /* Ignore SIGPIPE */ - sigact.sa_handler = SIG_IGN; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - if (sigaction(SIGPIPE, &sigact, NULL) < 0) - return -1; - - /* Set maximum number of open file descriptors */ - if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) - return -1; - - fdlim = (*_st_eventsys->fd_getlimit)(); - if (fdlim > 0 && rlim.rlim_max > (rlim_t) fdlim) { - rlim.rlim_max = fdlim; - } - - /** - * by SRS, for osx. - * when rlimit max is negative, for example, osx, use cur directly. - * @see https://github.com/winlinvip/simple-rtmp-server/issues/336 - */ - if ((int)rlim.rlim_max < 0) { - _st_osfd_limit = (int)(fdlim > 0? fdlim : rlim.rlim_cur); - return 0; - } - - rlim.rlim_cur = rlim.rlim_max; - if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) - return -1; - _st_osfd_limit = (int) rlim.rlim_max; - - return 0; -} - - -int st_getfdlimit(void) -{ - return _st_osfd_limit; -} - - -void st_netfd_free(_st_netfd_t *fd) -{ - if (!fd->inuse) - return; - - fd->inuse = 0; - if (fd->aux_data) - _st_netfd_free_aux_data(fd); - if (fd->private_data && fd->destructor) - (*(fd->destructor))(fd->private_data); - fd->private_data = NULL; - fd->destructor = NULL; - fd->next = _st_netfd_freelist; - _st_netfd_freelist = fd; -} - - -static _st_netfd_t *_st_netfd_new(int osfd, int nonblock, int is_socket) -{ - _st_netfd_t *fd; - int flags = 1; - - if ((*_st_eventsys->fd_new)(osfd) < 0) - return NULL; - - if (_st_netfd_freelist) { - fd = _st_netfd_freelist; - _st_netfd_freelist = _st_netfd_freelist->next; - } else { - fd = calloc(1, sizeof(_st_netfd_t)); - if (!fd) - return NULL; - } - - fd->osfd = osfd; - fd->inuse = 1; - fd->next = NULL; - - if (nonblock) { - /* Use just one system call */ - if (is_socket && ioctl(osfd, FIONBIO, &flags) != -1) - return fd; - /* Do it the Posix way */ - if ((flags = fcntl(osfd, F_GETFL, 0)) < 0 || - fcntl(osfd, F_SETFL, flags | O_NONBLOCK) < 0) { - st_netfd_free(fd); - return NULL; - } - } - - return fd; -} - - -_st_netfd_t *st_netfd_open(int osfd) -{ - return _st_netfd_new(osfd, 1, 0); -} - - -_st_netfd_t *st_netfd_open_socket(int osfd) -{ - return _st_netfd_new(osfd, 1, 1); -} - - -int st_netfd_close(_st_netfd_t *fd) -{ - if ((*_st_eventsys->fd_close)(fd->osfd) < 0) - return -1; - - st_netfd_free(fd); - return close(fd->osfd); -} - - -int st_netfd_fileno(_st_netfd_t *fd) -{ - return (fd->osfd); -} - - -void st_netfd_setspecific(_st_netfd_t *fd, void *value, _st_destructor_t destructor) -{ - if (value != fd->private_data) { - /* Free up previously set non-NULL data value */ - if (fd->private_data && fd->destructor) - (*(fd->destructor))(fd->private_data); - } - fd->private_data = value; - fd->destructor = destructor; -} - - -void *st_netfd_getspecific(_st_netfd_t *fd) -{ - return (fd->private_data); -} - - -/* - * Wait for I/O on a single descriptor. - */ -int st_netfd_poll(_st_netfd_t *fd, int how, st_utime_t timeout) -{ - struct pollfd pd; - int n; - - pd.fd = fd->osfd; - pd.events = (short) how; - pd.revents = 0; - - if ((n = st_poll(&pd, 1, timeout)) < 0) - return -1; - if (n == 0) { - /* Timed out */ - errno = ETIME; - return -1; - } - if (pd.revents & POLLNVAL) { - errno = EBADF; - return -1; - } - - return 0; -} - - -#ifdef MD_ALWAYS_UNSERIALIZED_ACCEPT -/* No-op */ -int st_netfd_serialize_accept(_st_netfd_t *fd) -{ - fd->aux_data = NULL; - return 0; -} - -/* No-op */ -static void _st_netfd_free_aux_data(_st_netfd_t *fd) -{ - fd->aux_data = NULL; -} - -_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout) -{ - int osfd, err; - _st_netfd_t *newfd; - - while ((osfd = accept(fd->osfd, addr, (socklen_t *)addrlen)) < 0) { - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) - return NULL; - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) - return NULL; - } - - /* On some platforms the new socket created by accept() inherits */ - /* the nonblocking attribute of the listening socket */ -#if defined (MD_ACCEPT_NB_INHERITED) - newfd = _st_netfd_new(osfd, 0, 1); -#elif defined (MD_ACCEPT_NB_NOT_INHERITED) - newfd = _st_netfd_new(osfd, 1, 1); -#else - #error Unknown OS -#endif - - if (!newfd) { - err = errno; - close(osfd); - errno = err; - } - - return newfd; -} - -#else /* MD_ALWAYS_UNSERIALIZED_ACCEPT */ -/* - * On some platforms accept() calls from different processes - * on the same listen socket must be serialized. - * The following code serializes accept()'s without process blocking. - * A pipe is used as an inter-process semaphore. - */ -int st_netfd_serialize_accept(_st_netfd_t *fd) -{ - _st_netfd_t **p; - int osfd[2], err; - - if (fd->aux_data) { - errno = EINVAL; - return -1; - } - if ((p = (_st_netfd_t **)calloc(2, sizeof(_st_netfd_t *))) == NULL) - return -1; - if (pipe(osfd) < 0) { - free(p); - return -1; - } - if ((p[0] = st_netfd_open(osfd[0])) != NULL && (p[1] = st_netfd_open(osfd[1])) != NULL && write(osfd[1], " ", 1) == 1) { - fd->aux_data = p; - return 0; - } - /* Error */ - err = errno; - if (p[0]) - st_netfd_free(p[0]); - if (p[1]) - st_netfd_free(p[1]); - close(osfd[0]); - close(osfd[1]); - free(p); - errno = err; - - return -1; -} - -static void _st_netfd_free_aux_data(_st_netfd_t *fd) -{ - _st_netfd_t **p = (_st_netfd_t **) fd->aux_data; - - st_netfd_close(p[0]); - st_netfd_close(p[1]); - free(p); - fd->aux_data = NULL; -} - -_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout) -{ - int osfd, err; - _st_netfd_t *newfd; - _st_netfd_t **p = (_st_netfd_t **) fd->aux_data; - ssize_t n; - char c; - - for ( ; ; ) { - if (p == NULL) { - osfd = accept(fd->osfd, addr, (socklen_t *)addrlen); - } else { - /* Get the lock */ - n = st_read(p[0], &c, 1, timeout); - if (n < 0) - return NULL; - ST_ASSERT(n == 1); - /* Got the lock */ - osfd = accept(fd->osfd, addr, (socklen_t *)addrlen); - /* Unlock */ - err = errno; - n = st_write(p[1], &c, 1, timeout); - ST_ASSERT(n == 1); - errno = err; - } - if (osfd >= 0) - break; - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) - return NULL; - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) - return NULL; - } - - /* On some platforms the new socket created by accept() inherits */ - /* the nonblocking attribute of the listening socket */ -#if defined (MD_ACCEPT_NB_INHERITED) - newfd = _st_netfd_new(osfd, 0, 1); -#elif defined (MD_ACCEPT_NB_NOT_INHERITED) - newfd = _st_netfd_new(osfd, 1, 1); -#else -#error Unknown OS -#endif - - if (!newfd) { - err = errno; - close(osfd); - errno = err; - } - - return newfd; -} -#endif /* MD_ALWAYS_UNSERIALIZED_ACCEPT */ - - -int st_connect(_st_netfd_t *fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout) -{ - int n, err = 0; - - while (connect(fd->osfd, addr, addrlen) < 0) { - if (errno != EINTR) { - /* - * On some platforms, if connect() is interrupted (errno == EINTR) - * after the kernel binds the socket, a subsequent connect() - * attempt will fail with errno == EADDRINUSE. Ignore EADDRINUSE - * iff connect() was previously interrupted. See Rich Stevens' - * "UNIX Network Programming," Vol. 1, 2nd edition, p. 413 - * ("Interrupted connect"). - */ - if (errno != EINPROGRESS && (errno != EADDRINUSE || err == 0)) - return -1; - /* Wait until the socket becomes writable */ - if (st_netfd_poll(fd, POLLOUT, timeout) < 0) - return -1; - /* Try to find out whether the connection setup succeeded or failed */ - n = sizeof(int); - if (getsockopt(fd->osfd, SOL_SOCKET, SO_ERROR, (char *)&err, (socklen_t *)&n) < 0) - return -1; - if (err) { - errno = err; - return -1; - } - break; - } - err = 1; - } - - return 0; -} - - -ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout) -{ - ssize_t n; - - while ((n = read(fd->osfd, buf, nbyte)) < 0) { - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) - return -1; - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) - return -1; - } - - return n; -} - - -int st_read_resid(_st_netfd_t *fd, void *buf, size_t *resid, st_utime_t timeout) -{ - struct iovec iov, *riov; - int riov_size, rv; - - iov.iov_base = buf; - iov.iov_len = *resid; - riov = &iov; - riov_size = 1; - rv = st_readv_resid(fd, &riov, &riov_size, timeout); - *resid = iov.iov_len; - return rv; -} - - -ssize_t st_readv(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout) -{ - ssize_t n; - - while ((n = readv(fd->osfd, iov, iov_size)) < 0) { - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) - return -1; - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) - return -1; - } - - return n; -} - -int st_readv_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout) -{ - ssize_t n; - - while (*iov_size > 0) { - if (*iov_size == 1) - n = read(fd->osfd, (*iov)->iov_base, (*iov)->iov_len); - else - n = readv(fd->osfd, *iov, *iov_size); - if (n < 0) { - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) - return -1; - } else if (n == 0) - break; - else { - while ((size_t) n >= (*iov)->iov_len) { - n -= (*iov)->iov_len; - (*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len; - (*iov)->iov_len = 0; - (*iov)++; - (*iov_size)--; - if (n == 0) - break; - } - if (*iov_size == 0) - break; - (*iov)->iov_base = (char *) (*iov)->iov_base + n; - (*iov)->iov_len -= n; - } - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) - return -1; - } - - return 0; -} - - -ssize_t st_read_fully(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout) -{ - size_t resid = nbyte; - return st_read_resid(fd, buf, &resid, timeout) == 0 ? - (ssize_t) (nbyte - resid) : -1; -} - - -int st_write_resid(_st_netfd_t *fd, const void *buf, size_t *resid, st_utime_t timeout) -{ - struct iovec iov, *riov; - int riov_size, rv; - - iov.iov_base = (void *) buf; /* we promise not to modify buf */ - iov.iov_len = *resid; - riov = &iov; - riov_size = 1; - rv = st_writev_resid(fd, &riov, &riov_size, timeout); - *resid = iov.iov_len; - return rv; -} - - -ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout) -{ - size_t resid = nbyte; - return st_write_resid(fd, buf, &resid, timeout) == 0 ? - (ssize_t) (nbyte - resid) : -1; -} - - -ssize_t st_writev(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout) -{ - ssize_t n, rv; - size_t nleft, nbyte; - int index, iov_cnt; - struct iovec *tmp_iov; - struct iovec local_iov[_LOCAL_MAXIOV]; - - /* Calculate the total number of bytes to be sent */ - nbyte = 0; - for (index = 0; index < iov_size; index++) - nbyte += iov[index].iov_len; - - rv = (ssize_t)nbyte; - nleft = nbyte; - tmp_iov = (struct iovec *) iov; /* we promise not to modify iov */ - iov_cnt = iov_size; - - while (nleft > 0) { - if (iov_cnt == 1) { - if (st_write(fd, tmp_iov[0].iov_base, nleft, timeout) != (ssize_t) nleft) - rv = -1; - break; - } - if ((n = writev(fd->osfd, tmp_iov, iov_cnt)) < 0) { - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) { - rv = -1; - break; - } - } else { - if ((size_t) n == nleft) - break; - nleft -= n; - /* Find the next unwritten vector */ - n = (ssize_t)(nbyte - nleft); - for (index = 0; (size_t) n >= iov[index].iov_len; index++) - n -= iov[index].iov_len; - - if (tmp_iov == iov) { - /* Must copy iov's around */ - if (iov_size - index <= _LOCAL_MAXIOV) { - tmp_iov = local_iov; - } else { - tmp_iov = calloc(1, (iov_size - index) * sizeof(struct iovec)); - if (tmp_iov == NULL) - return -1; - } - } - - /* Fill in the first partial read */ - tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[n]); - tmp_iov[0].iov_len = iov[index].iov_len - n; - index++; - /* Copy the remaining vectors */ - for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) { - tmp_iov[iov_cnt].iov_base = iov[index].iov_base; - tmp_iov[iov_cnt].iov_len = iov[index].iov_len; - } - } - /* Wait until the socket becomes writable */ - if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { - rv = -1; - break; - } - } - - if (tmp_iov != iov && tmp_iov != local_iov) - free(tmp_iov); - - return rv; -} - - -int st_writev_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout) -{ - ssize_t n; - - while (*iov_size > 0) { - if (*iov_size == 1) - n = write(fd->osfd, (*iov)->iov_base, (*iov)->iov_len); - else - n = writev(fd->osfd, *iov, *iov_size); - if (n < 0) { - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) - return -1; - } else { - while ((size_t) n >= (*iov)->iov_len) { - n -= (*iov)->iov_len; - (*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len; - (*iov)->iov_len = 0; - (*iov)++; - (*iov_size)--; - if (n == 0) - break; - } - if (*iov_size == 0) - break; - (*iov)->iov_base = (char *) (*iov)->iov_base + n; - (*iov)->iov_len -= n; - } - /* Wait until the socket becomes writable */ - if (st_netfd_poll(fd, POLLOUT, timeout) < 0) - return -1; - } - - return 0; -} - - -/* - * Simple I/O functions for UDP. - */ -int st_recvfrom(_st_netfd_t *fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout) -{ - int n; - - while ((n = recvfrom(fd->osfd, buf, len, 0, from, (socklen_t *)fromlen)) < 0) { - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) - return -1; - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) - return -1; - } - - return n; -} - - -int st_sendto(_st_netfd_t *fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout) -{ - int n; - - while ((n = sendto(fd->osfd, msg, len, 0, to, tolen)) < 0) { - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) - return -1; - /* Wait until the socket becomes writable */ - if (st_netfd_poll(fd, POLLOUT, timeout) < 0) - return -1; - } - - return n; -} - - -int st_recvmsg(_st_netfd_t *fd, struct msghdr *msg, int flags, st_utime_t timeout) -{ - int n; - - while ((n = recvmsg(fd->osfd, msg, flags)) < 0) { - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) - return -1; - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) - return -1; - } - - return n; -} - - -int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags, st_utime_t timeout) -{ - int n; - - while ((n = sendmsg(fd->osfd, msg, flags)) < 0) { - if (errno == EINTR) - continue; - if (!_IO_NOT_READY_ERROR) - return -1; - /* Wait until the socket becomes writable */ - if (st_netfd_poll(fd, POLLOUT, timeout) < 0) - return -1; - } - - return n; -} - - - -/* - * To open FIFOs or other special files. - */ -_st_netfd_t *st_open(const char *path, int oflags, mode_t mode) -{ - int osfd, err; - _st_netfd_t *newfd; - - while ((osfd = open(path, oflags | O_NONBLOCK, mode)) < 0) { - if (errno != EINTR) - return NULL; - } - - newfd = _st_netfd_new(osfd, 0, 0); - if (!newfd) { - err = errno; - close(osfd); - errno = err; - } - - return newfd; -} - diff --git a/trunk/3rdparty/st-srs/key.c b/trunk/3rdparty/st-srs/key.c deleted file mode 100644 index 5e64022c04..0000000000 --- a/trunk/3rdparty/st-srs/key.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#include -#include -#include "common.h" - - -/* - * Destructor table for per-thread private data - */ -static _st_destructor_t _st_destructors[ST_KEYS_MAX]; -static int key_max = 0; - - -/* - * Return a key to be used for thread specific data - */ -int st_key_create(int *keyp, _st_destructor_t destructor) -{ - if (key_max >= ST_KEYS_MAX) { - errno = EAGAIN; - return -1; - } - - *keyp = key_max++; - _st_destructors[*keyp] = destructor; - - return 0; -} - - -int st_key_getlimit(void) -{ - return ST_KEYS_MAX; -} - - -int st_thread_setspecific(int key, void *value) -{ - _st_thread_t *me = _ST_CURRENT_THREAD(); - - if (key < 0 || key >= key_max) { - errno = EINVAL; - return -1; - } - - if (value != me->private_data[key]) { - /* free up previously set non-NULL data value */ - if (me->private_data[key] && _st_destructors[key]) { - (*_st_destructors[key])(me->private_data[key]); - } - me->private_data[key] = value; - } - - return 0; -} - - -void *st_thread_getspecific(int key) -{ - if (key < 0 || key >= key_max) - return NULL; - - return ((_ST_CURRENT_THREAD())->private_data[key]); -} - - -/* - * Free up all per-thread private data - */ -void _st_thread_cleanup(_st_thread_t *thread) -{ - int key; - - for (key = 0; key < key_max; key++) { - if (thread->private_data[key] && _st_destructors[key]) { - (*_st_destructors[key])(thread->private_data[key]); - thread->private_data[key] = NULL; - } - } -} - diff --git a/trunk/3rdparty/st-srs/libst.def b/trunk/3rdparty/st-srs/libst.def deleted file mode 100644 index 6eaf149a97..0000000000 --- a/trunk/3rdparty/st-srs/libst.def +++ /dev/null @@ -1,51 +0,0 @@ -EXPORTS - st_accept @62 - st_cond_broadcast @63 - st_cond_destroy @64 - st_cond_new @65 - st_cond_signal @66 - st_cond_timedwait @67 - st_cond_wait @68 - st_connect @69 - st_getfdlimit @70 - st_init @71 - st_key_create @72 - st_key_getlimit @73 - st_mutex_destroy @74 - st_mutex_lock @75 - st_mutex_new @76 - st_mutex_trylock @77 - st_mutex_unlock @78 - st_netfd_close @79 - st_netfd_fileno @80 - st_netfd_free @81 - st_netfd_getspecific @82 - st_netfd_open @83 - st_netfd_open_socket @84 - st_netfd_poll @85 - st_netfd_serialize_accept @86 - st_netfd_setspecific @87 - st_open @88 - st_poll @89 - st_randomize_stacks @90 - st_read @91 - st_read_fully @92 - st_read_resid @93 - st_recvfrom @94 - st_sendto @95 - st_sleep @96 - st_thread_create @97 - st_thread_exit @98 - st_thread_getspecific @99 - st_thread_interrupt @100 - st_thread_join @101 - st_thread_self @102 - st_thread_setspecific @103 - st_time @104 - st_timecache_set @105 - st_usleep @106 - st_utime @107 - st_utime_last_clock @108 - st_write @109 - st_write_resid @110 - st_writev @111 diff --git a/trunk/3rdparty/st-srs/md.S b/trunk/3rdparty/st-srs/md.S deleted file mode 100644 index 2ef9c41f75..0000000000 --- a/trunk/3rdparty/st-srs/md.S +++ /dev/null @@ -1,644 +0,0 @@ - -/* If user disable the ASM, such as avoiding bugs in ASM, donot compile it. */ -#if !defined(MD_ST_NO_ASM) - -/* - * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. - * All Rights Reserved. - */ - -#if defined(__ia64__) - - /****************************************************************/ - - /* - * The internal __jmp_buf layout is different from one used - * by setjmp()/longjmp(). - * - * Offset Description - * ------ ----------- - * 0x000 stack pointer (r12) - * 0x008 gp (r1) - * 0x010 caller's unat - * 0x018 fpsr - * 0x020 r4 - * 0x028 r5 - * 0x030 r6 - * 0x038 r7 - * 0x040 rp (b0) - * 0x048 b1 - * 0x050 b2 - * 0x058 b3 - * 0x060 b4 - * 0x068 b5 - * 0x070 ar.pfs - * 0x078 ar.lc - * 0x080 pr - * 0x088 ar.bsp - * 0x090 ar.unat - * 0x098 &__jmp_buf - * 0x0a0 ar.rsc - * 0x0a8 ar.rnat - * 0x0b0 f2 - * 0x0c0 f3 - * 0x0d0 f4 - * 0x0e0 f5 - * 0x0f0 f16 - * 0x100 f17 - * 0x110 f18 - * 0x120 f19 - * 0x130 f20 - * 0x130 f21 - * 0x140 f22 - * 0x150 f23 - * 0x160 f24 - * 0x170 f25 - * 0x180 f26 - * 0x190 f27 - * 0x1a0 f28 - * 0x1b0 f29 - * 0x1c0 f30 - * 0x1d0 f31 - * - * Note that the address of __jmp_buf is saved but not used: we assume - * that the jmp_buf data structure is never moved around in memory. - */ - - /* - * Implemented according to "IA-64 Software Conventions and Runtime - * Architecture Guide", Chapter 10: "Context Management". - */ - - .text - .psr abi64 - .psr lsb - .lsb - - /* _st_md_cxt_save(__jmp_buf env) */ - .align 32 - .global _st_md_cxt_save - .proc _st_md_cxt_save - _st_md_cxt_save: - alloc r14 = ar.pfs,1,0,0,0 - mov r16 = ar.unat - ;; - mov r17 = ar.fpsr - mov r2 = in0 - add r3 = 8,in0 - ;; - st8.spill.nta [r2] = sp,16 // r12 (sp) - ;; - st8.spill.nta [r3] = gp,16 // r1 (gp) - ;; - st8.nta [r2] = r16,16 // save caller's unat - st8.nta [r3] = r17,16 // save fpsr - add r8 = 0xb0,in0 - ;; - st8.spill.nta [r2] = r4,16 // r4 - ;; - st8.spill.nta [r3] = r5,16 // r5 - add r9 = 0xc0,in0 - ;; - stf.spill.nta [r8] = f2,32 - stf.spill.nta [r9] = f3,32 - mov r15 = rp - ;; - stf.spill.nta [r8] = f4,32 - stf.spill.nta [r9] = f5,32 - mov r17 = b1 - ;; - stf.spill.nta [r8] = f16,32 - stf.spill.nta [r9] = f17,32 - mov r18 = b2 - ;; - stf.spill.nta [r8] = f18,32 - stf.spill.nta [r9] = f19,32 - mov r19 = b3 - ;; - stf.spill.nta [r8] = f20,32 - stf.spill.nta [r9] = f21,32 - mov r20 = b4 - ;; - stf.spill.nta [r8] = f22,32 - stf.spill.nta [r9] = f23,32 - mov r21 = b5 - ;; - stf.spill.nta [r8] = f24,32 - stf.spill.nta [r9] = f25,32 - mov r22 = ar.lc - ;; - stf.spill.nta [r8] = f26,32 - stf.spill.nta [r9] = f27,32 - mov r24 = pr - ;; - stf.spill.nta [r8] = f28,32 - stf.spill.nta [r9] = f29,32 - ;; - stf.spill.nta [r8] = f30 - stf.spill.nta [r9] = f31 - - st8.spill.nta [r2] = r6,16 // r6 - ;; - st8.spill.nta [r3] = r7,16 // r7 - ;; - mov r23 = ar.bsp - mov r25 = ar.unat - - st8.nta [r2] = r15,16 // b0 - st8.nta [r3] = r17,16 // b1 - ;; - st8.nta [r2] = r18,16 // b2 - st8.nta [r3] = r19,16 // b3 - mov r26 = ar.rsc - ;; - st8.nta [r2] = r20,16 // b4 - st8.nta [r3] = r21,16 // b5 - ;; - st8.nta [r2] = r14,16 // ar.pfs - st8.nta [r3] = r22,16 // ar.lc - ;; - st8.nta [r2] = r24,16 // pr - st8.nta [r3] = r23,16 // ar.bsp - ;; - st8.nta [r2] = r25,16 // ar.unat - st8.nta [r3] = in0,16 // &__jmp_buf (just in case) - ;; - st8.nta [r2] = r26 // ar.rsc - ;; - flushrs // flush dirty regs to backing store - ;; - and r27 = ~0x3,r26 // clear ar.rsc.mode - ;; - mov ar.rsc = r27 // put RSE in enforced lazy mode - ;; - mov r28 = ar.rnat - ;; - st8.nta [r3] = r28 // ar.rnat - mov ar.rsc = r26 // restore ar.rsc - ;; - mov r8 = 0 - br.ret.sptk.few b0 - .endp _st_md_cxt_save - - - /****************************************************************/ - - /* _st_md_cxt_restore(__jmp_buf env, int val) */ - .global _st_md_cxt_restore - .proc _st_md_cxt_restore - _st_md_cxt_restore: - alloc r8 = ar.pfs,2,0,0,0 - add r2 = 0x88,in0 // r2 <- &jmpbuf.ar_bsp - mov r16 = ar.rsc - ;; - flushrs // flush dirty regs to backing store - ;; - and r17 = ~0x3,r16 // clear ar.rsc.mode - ;; - mov ar.rsc = r17 // put RSE in enforced lazy mode - ;; - invala // invalidate the ALAT - ;; - ld8 r23 = [r2],8 // r23 <- jmpbuf.ar_bsp - ;; - mov ar.bspstore = r23 // write BSPSTORE - ld8 r25 = [r2],24 // r25 <- jmpbuf.ar_unat - ;; - ld8 r26 = [r2],-8 // r26 <- jmpbuf.ar_rnat - ;; - mov ar.rnat = r26 // write RNAT - ld8 r27 = [r2] // r27 <- jmpbuf.ar_rsc - ;; - mov ar.rsc = r27 // write RSE control - mov r2 = in0 - ;; - mov ar.unat = r25 // write ar.unat - add r3 = 8,in0 - ;; - ld8.fill.nta sp = [r2],16 // r12 (sp) - ld8.fill.nta gp = [r3],16 // r1 (gp) - ;; - ld8.nta r16 = [r2],16 // caller's unat - ld8.nta r17 = [r3],16 // fpsr - ;; - ld8.fill.nta r4 = [r2],16 // r4 - ld8.fill.nta r5 = [r3],16 // r5 - ;; - ld8.fill.nta r6 = [r2],16 // r6 - ld8.fill.nta r7 = [r3],16 // r7 - ;; - mov ar.unat = r16 // restore caller's unat - mov ar.fpsr = r17 // restore fpsr - ;; - ld8.nta r16 = [r2],16 // b0 - ld8.nta r17 = [r3],16 // b1 - ;; - ld8.nta r18 = [r2],16 // b2 - ld8.nta r19 = [r3],16 // b3 - ;; - ld8.nta r20 = [r2],16 // b4 - ld8.nta r21 = [r3],16 // b5 - ;; - ld8.nta r11 = [r2],16 // ar.pfs - ld8.nta r22 = [r3],72 // ar.lc - ;; - ld8.nta r24 = [r2],48 // pr - mov b0 = r16 - ;; - ldf.fill.nta f2 = [r2],32 - ldf.fill.nta f3 = [r3],32 - mov b1 = r17 - ;; - ldf.fill.nta f4 = [r2],32 - ldf.fill.nta f5 = [r3],32 - mov b2 = r18 - ;; - ldf.fill.nta f16 = [r2],32 - ldf.fill.nta f17 = [r3],32 - mov b3 = r19 - ;; - ldf.fill.nta f18 = [r2],32 - ldf.fill.nta f19 = [r3],32 - mov b4 = r20 - ;; - ldf.fill.nta f20 = [r2],32 - ldf.fill.nta f21 = [r3],32 - mov b5 = r21 - ;; - ldf.fill.nta f22 = [r2],32 - ldf.fill.nta f23 = [r3],32 - mov ar.lc = r22 - ;; - ldf.fill.nta f24 = [r2],32 - ldf.fill.nta f25 = [r3],32 - cmp.eq p6,p7 = 0,in1 - ;; - ldf.fill.nta f26 = [r2],32 - ldf.fill.nta f27 = [r3],32 - mov ar.pfs = r11 - ;; - ldf.fill.nta f28 = [r2],32 - ldf.fill.nta f29 = [r3],32 - ;; - ldf.fill.nta f30 = [r2] - ldf.fill.nta f31 = [r3] - (p6) mov r8 = 1 - (p7) mov r8 = in1 - - mov pr = r24,-1 - br.ret.sptk.few b0 - .endp _st_md_cxt_restore - - /****************************************************************/ - - - - - - - - - -#elif defined(__i386__) - - /****************************************************************/ - - /* - * Internal __jmp_buf layout - */ - #define JB_BX 0 - #define JB_SI 1 - #define JB_DI 2 - #define JB_BP 3 - #define JB_SP 4 - #define JB_PC 5 - - .file "md.S" - .text - - /* _st_md_cxt_save(__jmp_buf env) */ - .globl _st_md_cxt_save - .type _st_md_cxt_save, @function - .align 16 - _st_md_cxt_save: - movl 4(%esp), %eax - - /* - * Save registers. - */ - movl %ebx, (JB_BX*4)(%eax) - movl %esi, (JB_SI*4)(%eax) - movl %edi, (JB_DI*4)(%eax) - /* Save SP */ - leal 4(%esp), %ecx - movl %ecx, (JB_SP*4)(%eax) - /* Save PC we are returning to */ - movl 0(%esp), %ecx - movl %ecx, (JB_PC*4)(%eax) - /* Save caller frame pointer */ - movl %ebp, (JB_BP*4)(%eax) - xorl %eax, %eax - ret - .size _st_md_cxt_save, .-_st_md_cxt_save - - - /****************************************************************/ - - /* _st_md_cxt_restore(__jmp_buf env, int val) */ - .globl _st_md_cxt_restore - .type _st_md_cxt_restore, @function - .align 16 - _st_md_cxt_restore: - /* First argument is jmp_buf */ - movl 4(%esp), %ecx - /* Second argument is return value */ - movl 8(%esp), %eax - /* Set the return address */ - movl (JB_PC*4)(%ecx), %edx - /* - * Restore registers. - */ - movl (JB_BX*4)(%ecx), %ebx - movl (JB_SI*4)(%ecx), %esi - movl (JB_DI*4)(%ecx), %edi - movl (JB_BP*4)(%ecx), %ebp - movl (JB_SP*4)(%ecx), %esp - testl %eax, %eax - jnz 1f - incl %eax - /* Jump to saved PC */ - 1: jmp *%edx - .size _st_md_cxt_restore, .-_st_md_cxt_restore - - /****************************************************************/ - - - - - - - - - - -#elif defined(__amd64__) || defined(__x86_64__) - - /****************************************************************/ - - /* - * Internal __jmp_buf layout - */ - #define JB_RBX 0 - #define JB_RBP 1 - #define JB_R12 2 - #define JB_R13 3 - #define JB_R14 4 - #define JB_R15 5 - #define JB_RSP 6 - #define JB_PC 7 - - .file "md.S" - .text - - /* _st_md_cxt_save(__jmp_buf env) */ - .globl _st_md_cxt_save - .type _st_md_cxt_save, @function - .align 16 - _st_md_cxt_save: - /* - * Save registers. - */ - movq %rbx, (JB_RBX*8)(%rdi) - movq %rbp, (JB_RBP*8)(%rdi) - movq %r12, (JB_R12*8)(%rdi) - movq %r13, (JB_R13*8)(%rdi) - movq %r14, (JB_R14*8)(%rdi) - movq %r15, (JB_R15*8)(%rdi) - /* Save SP */ - leaq 8(%rsp), %rdx - movq %rdx, (JB_RSP*8)(%rdi) - /* Save PC we are returning to */ - movq (%rsp), %rax - movq %rax, (JB_PC*8)(%rdi) - xorq %rax, %rax - ret - .size _st_md_cxt_save, .-_st_md_cxt_save - - - /****************************************************************/ - - /* _st_md_cxt_restore(__jmp_buf env, int val) */ - .globl _st_md_cxt_restore - .type _st_md_cxt_restore, @function - .align 16 - _st_md_cxt_restore: - /* - * Restore registers. - */ - movq (JB_RBX*8)(%rdi), %rbx - movq (JB_RBP*8)(%rdi), %rbp - movq (JB_R12*8)(%rdi), %r12 - movq (JB_R13*8)(%rdi), %r13 - movq (JB_R14*8)(%rdi), %r14 - movq (JB_R15*8)(%rdi), %r15 - /* Set return value */ - test %esi, %esi - mov $01, %eax - cmove %eax, %esi - mov %esi, %eax - movq (JB_PC*8)(%rdi), %rdx - movq (JB_RSP*8)(%rdi), %rsp - /* Jump to saved PC */ - jmpq *%rdx - .size _st_md_cxt_restore, .-_st_md_cxt_restore - - /****************************************************************/ - - - - - - - - - - -#elif defined(__aarch64__) - - /****************************************************************/ - /* https://github.com/ossrs/srs/issues/1282#issuecomment-445539513 */ - - #define JB_X19 0 - #define JB_X20 1 - #define JB_X21 2 - #define JB_X22 3 - #define JB_X23 4 - #define JB_X24 5 - #define JB_X25 6 - #define JB_X26 7 - #define JB_X27 8 - #define JB_X28 9 - #define JB_X29 10 - #define JB_LR 11 - #define JB_SP 13 - - #define JB_D8 14 - #define JB_D9 15 - #define JB_D10 16 - #define JB_D11 17 - #define JB_D12 18 - #define JB_D13 19 - #define JB_D14 20 - #define JB_D15 21 - - .file "md.S" - .text - - /* _st_md_cxt_save(__jmp_buf env) */ - .globl _st_md_cxt_save - .type _st_md_cxt_save, %function - .align 4 - _st_md_cxt_save: - stp x19, x20, [x0, #JB_X19<<3] - stp x21, x22, [x0, #JB_X21<<3] - stp x23, x24, [x0, #JB_X23<<3] - stp x25, x26, [x0, #JB_X25<<3] - stp x27, x28, [x0, #JB_X27<<3] - stp x29, x30, [x0, #JB_X29<<3] - - stp d8, d9, [x0, #JB_D8<<3] - stp d10, d11, [x0, #JB_D10<<3] - stp d12, d13, [x0, #JB_D12<<3] - stp d14, d15, [x0, #JB_D14<<3] - mov x2, sp - str x2, [x0, #JB_SP<<3] - - mov x0, #0 - ret - .size _st_md_cxt_save, .-_st_md_cxt_save - - /****************************************************************/ - - /* _st_md_cxt_restore(__jmp_buf env, int val) */ - .globl _st_md_cxt_restore - .type _st_md_cxt_restore, %function - .align 4 - _st_md_cxt_restore: - ldp x19, x20, [x0, #JB_X19<<3] - ldp x21, x22, [x0, #JB_X21<<3] - ldp x23, x24, [x0, #JB_X23<<3] - ldp x25, x26, [x0, #JB_X25<<3] - ldp x27, x28, [x0, #JB_X27<<3] - - ldp x29, x30, [x0, #JB_X29<<3] - - ldp d8, d9, [x0, #JB_D8<<3] - ldp d10, d11, [x0, #JB_D10<<3] - ldp d12, d13, [x0, #JB_D12<<3] - ldp d14, d15, [x0, #JB_D14<<3] - - ldr x5, [x0, #JB_SP<<3] - mov sp, x5 - - cmp x1, #0 - mov x0, #1 - csel x0, x1, x0, ne - /* Use br instead of ret because ret is guaranteed to mispredict */ - br x30 - .size _st_md_cxt_restore, .-_st_md_cxt_restore - - /****************************************************************/ - - - - - - - - - - -#elif defined(__arm__) - - /****************************************************************/ - /* https://github.com/ossrs/srs/issues/1282#issuecomment-445539513 */ - - /* Register list for a ldm/stm instruction to load/store - the general registers from a __jmp_buf. */ - # define JMP_BUF_REGLIST {v1-v6, sl, fp, sp, lr} - - .file "md.S" - .text - - /* _st_md_cxt_save(__jmp_buf env) */ - .globl _st_md_cxt_save - .type _st_md_cxt_save, %function - .align 2 - _st_md_cxt_save: - mov ip, r0 - - /* Save registers */ - stmia ip!, JMP_BUF_REGLIST - - #ifdef __VFP_FP__ - /* Store the VFP registers. */ - /* Following instruction is vstmia ip!, {d8-d15}. */ - stc p11, cr8, [ip], #64 - #endif - - #ifdef __IWMMXT__ - /* Save the call-preserved iWMMXt registers. */ - /* Following instructions are wstrd wr10, [ip], #8 (etc.) */ - stcl p1, cr10, [r12], #8 - stcl p1, cr11, [r12], #8 - stcl p1, cr12, [r12], #8 - stcl p1, cr13, [r12], #8 - stcl p1, cr14, [r12], #8 - stcl p1, cr15, [r12], #8 - #endif - - mov r0, #0 - bx lr - - .size _st_md_cxt_save, .-_st_md_cxt_save - - /****************************************************************/ - - /* _st_md_cxt_restore(__jmp_buf env, int val) */ - .globl _st_md_cxt_restore - .type _st_md_cxt_restore, %function - .align 2 - _st_md_cxt_restore: - mov ip, r0 - - /* Restore registers */ - ldmia ip!, JMP_BUF_REGLIST - - #ifdef __VFP_FP__ - /* Restore the VFP registers. */ - /* Following instruction is vldmia ip!, {d8-d15}. */ - ldc p11, cr8, [r12], #64 - #endif - - #ifdef __IWMMXT__ - /* Restore the call-preserved iWMMXt registers. */ - /* Following instructions are wldrd wr10, [ip], #8 (etc.) */ - ldcl p1, cr10, [r12], #8 - ldcl p1, cr11, [r12], #8 - ldcl p1, cr12, [r12], #8 - ldcl p1, cr13, [r12], #8 - ldcl p1, cr14, [r12], #8 - ldcl p1, cr15, [r12], #8 - #endif - - movs r0, r1 /* get the return value in place */ - moveq r0, #1 /* can't let setjmp() return zero! */ - bx lr - - .size _st_md_cxt_restore, .-_st_md_cxt_restore - - /****************************************************************/ - -#endif - -#endif diff --git a/trunk/3rdparty/st-srs/md.h b/trunk/3rdparty/st-srs/md.h deleted file mode 100644 index dc4ef54c90..0000000000 --- a/trunk/3rdparty/st-srs/md.h +++ /dev/null @@ -1,641 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#ifndef __ST_MD_H__ -#define __ST_MD_H__ - -#if defined(ETIMEDOUT) && !defined(ETIME) - #define ETIME ETIMEDOUT -#endif - -#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON) - #define MAP_ANON MAP_ANONYMOUS -#endif - -#ifndef MAP_FAILED - #define MAP_FAILED -1 -#endif - -/***************************************** - * Platform specifics - */ - -#if defined (AIX) - - #define MD_STACK_GROWS_DOWN - #define MD_USE_SYSV_ANON_MMAP - #define MD_ACCEPT_NB_INHERITED - #define MD_ALWAYS_UNSERIALIZED_ACCEPT - - #ifndef MD_HAVE_SOCKLEN_T - #define MD_HAVE_SOCKLEN_T - #define socklen_t unsigned long - #endif - - #define MD_SETJMP(env) _setjmp(env) - #define MD_LONGJMP(env, val) _longjmp(env, val) - - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - (_thread)->context[3] = (long) (_sp); \ - ST_END_MACRO - - #define MD_GET_UTIME() \ - timebasestruct_t rt; \ - (void) read_real_time(&rt, TIMEBASE_SZ); \ - (void) time_base_to_time(&rt, TIMEBASE_SZ); \ - return (rt.tb_high * 1000000LL + rt.tb_low / 1000) - -#elif defined (CYGWIN) - - #define MD_STACK_GROWS_DOWN - #define MD_USE_BSD_ANON_MMAP - #define MD_ACCEPT_NB_NOT_INHERITED - #define MD_ALWAYS_UNSERIALIZED_ACCEPT - - #define MD_SETJMP(env) setjmp(env) - #define MD_LONGJMP(env, val) longjmp(env, val) - - #define MD_JB_SP 7 - - #define MD_GET_SP(_t) (_t)->context[MD_JB_SP] - - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - MD_GET_SP(_thread) = (long) (_sp); \ - ST_END_MACRO - - #define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) - -#elif defined (DARWIN) - - #define MD_STACK_GROWS_DOWN - #define MD_USE_BSD_ANON_MMAP - #define MD_ACCEPT_NB_INHERITED - #define MD_ALWAYS_UNSERIALIZED_ACCEPT - #define MD_HAVE_SOCKLEN_T - - #define MD_SETJMP(env) _setjmp(env) - #define MD_LONGJMP(env, val) _longjmp(env, val) - - #if defined(__ppc__) - #define MD_JB_SP 0 - #elif defined(__i386__) - #define MD_JB_SP 9 - #elif defined(__x86_64__) - #define MD_JB_SP 4 - #else - #error Unknown CPU architecture - #endif - - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - *((long *)&((_thread)->context[MD_JB_SP])) = (long) (_sp); \ - ST_END_MACRO - - #define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) - -#elif defined (FREEBSD) - - #define MD_STACK_GROWS_DOWN - #define MD_USE_BSD_ANON_MMAP - #define MD_ACCEPT_NB_INHERITED - #define MD_ALWAYS_UNSERIALIZED_ACCEPT - - #define MD_SETJMP(env) _setjmp(env) - #define MD_LONGJMP(env, val) _longjmp(env, val) - - #if defined(__i386__) - #define MD_JB_SP 2 - #elif defined(__alpha__) - #define MD_JB_SP 34 - #elif defined(__amd64__) - #define MD_JB_SP 2 - #else - #error Unknown CPU architecture - #endif - - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - (_thread)->context[0]._jb[MD_JB_SP] = (long) (_sp); \ - ST_END_MACRO - - #define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) - -#elif defined (HPUX) - - #define MD_STACK_GROWS_UP - #define MD_USE_BSD_ANON_MMAP - #define MD_ACCEPT_NB_INHERITED - #define MD_ALWAYS_UNSERIALIZED_ACCEPT - - #define MD_SETJMP(env) _setjmp(env) - #define MD_LONGJMP(env, val) _longjmp(env, val) - - #ifndef __LP64__ - /* 32-bit mode (ILP32 data model) */ - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - ((long *)((_thread)->context))[1] = (long) (_sp); \ - ST_END_MACRO - #else - /* 64-bit mode (LP64 data model) */ - #define MD_STACK_PAD_SIZE 256 - /* Last stack frame must be preserved */ - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - memcpy((char *)(_sp) - MD_STACK_PAD_SIZE, \ - ((char **)((_thread)->context))[1] - MD_STACK_PAD_SIZE, \ - MD_STACK_PAD_SIZE); \ - ((long *)((_thread)->context))[1] = (long) (_sp); \ - ST_END_MACRO - #endif /* !__LP64__ */ - - #define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) - -#elif defined (IRIX) - - #include - - #define MD_STACK_GROWS_DOWN - #define MD_USE_SYSV_ANON_MMAP - #define MD_ACCEPT_NB_INHERITED - #define MD_ALWAYS_UNSERIALIZED_ACCEPT - - #define MD_SETJMP(env) setjmp(env) - #define MD_LONGJMP(env, val) longjmp(env, val) - - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - (void) MD_SETJMP((_thread)->context); \ - (_thread)->context[JB_SP] = (long) (_sp); \ - (_thread)->context[JB_PC] = (long) _main; \ - ST_END_MACRO - - #define MD_GET_UTIME() \ - static int inited = 0; \ - static clockid_t clock_id = CLOCK_SGI_CYCLE; \ - struct timespec ts; \ - if (!inited) { \ - if (syssgi(SGI_CYCLECNTR_SIZE) < 64) \ - clock_id = CLOCK_REALTIME; \ - inited = 1; \ - } \ - (void) clock_gettime(clock_id, &ts); \ - return (ts.tv_sec * 1000000LL + ts.tv_nsec / 1000) - - /* - * Cap the stack by zeroing out the saved return address register - * value. This allows libexc, used by SpeedShop, to know when to stop - * backtracing since it won't find main, start, or any other known - * stack root function in a state thread's stack. Without this libexc - * traces right off the stack and crashes. - * The function preamble stores ra at 8(sp), this stores zero there. - * N.B. This macro is compiler/ABI dependent. It must change if ANY more - * automatic variables are added to the _st_thread_main() routine, because - * the address where ra is stored will change. - */ - #if !defined(__GNUC__) && defined(_MIPS_SIM) && _MIPS_SIM != _ABIO32 - #define MD_CAP_STACK(var_addr) \ - (((volatile __uint64_t *)(var_addr))[1] = 0) - #endif - -#elif defined (LINUX) - - /* - * These are properties of the linux kernel and are the same on every - * flavor and architecture. - */ - #define MD_USE_BSD_ANON_MMAP - #define MD_ACCEPT_NB_NOT_INHERITED - #define MD_ALWAYS_UNSERIALIZED_ACCEPT - /* - * Modern GNU/Linux is Posix.1g compliant. - */ - #define MD_HAVE_SOCKLEN_T - - /* - * All architectures and flavors of linux have the gettimeofday - * function but if you know of a faster way, use it. - */ - #define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) - - #if defined(__ia64__) - #define MD_STACK_GROWS_DOWN - - /* - * IA-64 architecture. Besides traditional memory call stack, IA-64 - * uses general register stack. Thus each thread needs a backing store - * for register stack in addition to memory stack. Standard - * setjmp()/longjmp() cannot be used for thread context switching - * because their implementation implicitly assumes that only one - * register stack exists. - */ - #ifdef USE_LIBC_SETJMP - #undef USE_LIBC_SETJMP - #endif - #define MD_USE_BUILTIN_SETJMP - - #define MD_STACK_PAD_SIZE 128 - /* Last register stack frame must be preserved */ - #define MD_INIT_CONTEXT(_thread, _sp, _bsp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - memcpy((char *)(_bsp) - MD_STACK_PAD_SIZE, \ - (char *)(_thread)->context[0].__jmpbuf[17] - MD_STACK_PAD_SIZE, \ - MD_STACK_PAD_SIZE); \ - (_thread)->context[0].__jmpbuf[0] = (long) (_sp); \ - (_thread)->context[0].__jmpbuf[17] = (long) (_bsp); \ - ST_END_MACRO - - #elif defined(__mips__) - #define MD_STACK_GROWS_DOWN - - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - MD_SETJMP((_thread)->context); \ - _thread->context[0].__jmpbuf[0].__pc = (__ptr_t) _main; \ - _thread->context[0].__jmpbuf[0].__sp = _sp; \ - ST_END_MACRO - - #else /* Not IA-64 or mips */ - - /* - * On linux, there are a few styles of jmpbuf format. These vary based - * on architecture/glibc combination. - * - * Most of the glibc based toggles were lifted from: - * mozilla/nsprpub/pr/include/md/_linux.h - */ - - /* - * Starting with glibc 2.4, JB_SP definitions are not public anymore. - * They, however, can still be found in glibc source tree in - * architecture-specific "jmpbuf-offsets.h" files. - * Most importantly, the content of jmp_buf is mangled by setjmp to make - * it completely opaque (the mangling can be disabled by setting the - * LD_POINTER_GUARD environment variable before application execution). - * Therefore we will use built-in _st_md_cxt_save/_st_md_cxt_restore - * functions as a setjmp/longjmp replacement wherever they are available - * unless USE_LIBC_SETJMP is defined. - */ - - #if defined(__powerpc__) - #define MD_STACK_GROWS_DOWN - - #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) - #ifndef JB_GPR1 - #define JB_GPR1 0 - #endif - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_GPR1] - #else - /* not an error but certainly cause for caution */ - #error "Untested use of old glibc on powerpc" - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__misc[0] - #endif /* glibc 2.1 or later */ - - #elif defined(__alpha) - #define MD_STACK_GROWS_DOWN - - #if defined(__GLIBC__) && __GLIBC__ >= 2 - #ifndef JB_SP - #define JB_SP 8 - #endif - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP] - #else - /* not an error but certainly cause for caution */ - #error "Untested use of old glibc on alpha" - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp - #endif - - #elif defined(__mc68000__) - #define MD_STACK_GROWS_DOWN - - /* m68k still uses old style sigjmp_buf */ - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp - - #elif defined(__sparc__) - #define MD_STACK_GROWS_DOWN - - #if defined(__GLIBC__) && __GLIBC__ >= 2 - #ifndef JB_SP - #define JB_SP 0 - #endif - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP] - #else - /* not an error but certainly cause for caution */ - #error "Untested use of old glic on sparc -- also using odd mozilla derived __fp" - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__fp - #endif - - #elif defined(__i386__) - #define MD_STACK_GROWS_DOWN - #define MD_USE_BUILTIN_SETJMP - - #if defined(__GLIBC__) && __GLIBC__ >= 2 - #ifndef JB_SP - #define JB_SP 4 - #endif - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP] - #else - /* not an error but certainly cause for caution */ - #error "Untested use of old glibc on i386" - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp - #endif - - #elif defined(__amd64__) || defined(__x86_64__) - #define MD_STACK_GROWS_DOWN - #define MD_USE_BUILTIN_SETJMP - - #ifndef JB_RSP - #define JB_RSP 6 - #endif - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_RSP] - - #elif defined(__aarch64__) - /* https://github.com/ossrs/state-threads/issues/9 */ - #define MD_STACK_GROWS_DOWN - #define MD_USE_BUILTIN_SETJMP - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[13] - - #elif defined(__arm__) - #define MD_STACK_GROWS_DOWN - /* https://github.com/ossrs/state-threads/issues/1#issuecomment-244648573 */ - #define MD_USE_BUILTIN_SETJMP - - /* force to use glibc solution, hack the guard jmpbuf from michaeltalyansky */ - #ifdef USE_LIBC_SETJMP - #undef MD_USE_BUILTIN_SETJMP - #endif - - #if defined(__GLIBC__) && __GLIBC__ >= 2 - /* Merge from https://github.com/michaeltalyansky/state-threads/commit/56554a5c425aee8e7a73782eae23d74d83c4120a */ - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[8] - #else - #error "ARM/Linux pre-glibc2 not supported yet" - #endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ - - #elif defined(__s390__) - #define MD_STACK_GROWS_DOWN - - /* There is no JB_SP in glibc at this time. (glibc 2.2.5) - */ - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__gregs[9] - - #elif defined(__hppa__) - #define MD_STACK_GROWS_UP - - /* yes, this is gross, unfortunately at the moment (2002/08/01) there is - * a bug in hppa's glibc header definition for JB_SP, so we can't - * use that... - */ - #define MD_GET_SP(_t) (*(long *)(((char *)&(_t)->context[0].__jmpbuf[0]) + 76)) - - #else - #error "Unknown CPU architecture" - #endif /* Cases with common MD_INIT_CONTEXT and different SP locations */ - - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - MD_GET_SP(_thread) = (long) (_sp); \ - ST_END_MACRO - - #endif /* Cases with different MD_INIT_CONTEXT */ - - #if defined(MD_USE_BUILTIN_SETJMP) && !defined(USE_LIBC_SETJMP) - #define MD_SETJMP(env) _st_md_cxt_save(env) - #define MD_LONGJMP(env, val) _st_md_cxt_restore(env, val) - - extern int _st_md_cxt_save(jmp_buf env); - extern void _st_md_cxt_restore(jmp_buf env, int val); - #else - #define MD_SETJMP(env) setjmp(env) - #define MD_LONGJMP(env, val) longjmp(env, val) - #endif - -#elif defined (NETBSD) - - #define MD_STACK_GROWS_DOWN - #define MD_USE_BSD_ANON_MMAP - #define MD_ACCEPT_NB_INHERITED - #define MD_ALWAYS_UNSERIALIZED_ACCEPT - #define MD_HAVE_SOCKLEN_T - - #define MD_SETJMP(env) _setjmp(env) - #define MD_LONGJMP(env, val) _longjmp(env, val) - - #if defined(__i386__) - #define MD_JB_SP 2 - #elif defined(__alpha__) - #define MD_JB_SP 34 - #elif defined(__sparc__) - #define MD_JB_SP 0 - #elif defined(__vax__) - #define MD_JB_SP 2 - #else - #error Unknown CPU architecture - #endif - - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - (_thread)->context[MD_JB_SP] = (long) (_sp); \ - ST_END_MACRO - - #define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) - -#elif defined (OPENBSD) - - #define MD_STACK_GROWS_DOWN - #define MD_USE_BSD_ANON_MMAP - #define MD_ACCEPT_NB_INHERITED - #define MD_ALWAYS_UNSERIALIZED_ACCEPT - - #define MD_SETJMP(env) _setjmp(env) - #define MD_LONGJMP(env, val) _longjmp(env, val) - - #if defined(__i386__) - #define MD_JB_SP 2 - #elif defined(__alpha__) - #define MD_JB_SP 34 - #elif defined(__sparc__) - #define MD_JB_SP 0 - #elif defined(__amd64__) - #define MD_JB_SP 6 - #else - #error Unknown CPU architecture - #endif - - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - (_thread)->context[MD_JB_SP] = (long) (_sp); \ - ST_END_MACRO - - #define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) - -#elif defined (OSF1) - - #include - - #define MD_STACK_GROWS_DOWN - #define MD_USE_SYSV_ANON_MMAP - #define MD_ACCEPT_NB_NOT_INHERITED - #define MD_ALWAYS_UNSERIALIZED_ACCEPT - - #define MD_SETJMP(env) _setjmp(env) - #define MD_LONGJMP(env, val) _longjmp(env, val) - - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - ((struct sigcontext *)((_thread)->context))->sc_sp = (long) (_sp); \ - ST_END_MACRO - - #define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) - -#elif defined (SOLARIS) - - #include - extern int getpagesize(void); - - #define MD_STACK_GROWS_DOWN - #define MD_USE_SYSV_ANON_MMAP - #define MD_ACCEPT_NB_NOT_INHERITED - - #define MD_SETJMP(env) setjmp(env) - #define MD_LONGJMP(env, val) longjmp(env, val) - - #if defined(sparc) || defined(__sparc) - #ifdef _LP64 - #define MD_STACK_PAD_SIZE 4095 - #endif - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - (void) MD_SETJMP((_thread)->context); \ - (_thread)->context[1] = (long) (_sp); \ - (_thread)->context[2] = (long) _main; \ - ST_END_MACRO - #elif defined(i386) || defined(__i386) - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - (void) MD_SETJMP((_thread)->context); \ - (_thread)->context[4] = (long) (_sp); \ - (_thread)->context[5] = (long) _main; \ - ST_END_MACRO - #elif defined(__amd64__) - #define MD_INIT_CONTEXT(_thread, _sp, _main) \ - ST_BEGIN_MACRO \ - if (MD_SETJMP((_thread)->context)) \ - _main(); \ - (_thread)->context[6] = (long) (_sp); \ - ST_END_MACRO - #else - #error Unknown CPU architecture - #endif - - #define MD_GET_UTIME() \ - return (gethrtime() / 1000) - -#else - #error Unknown OS -#endif /* OS */ - -#if !defined(MD_HAVE_POLL) && !defined(MD_DONT_HAVE_POLL) - #define MD_HAVE_POLL -#endif - -#ifndef MD_STACK_PAD_SIZE - #define MD_STACK_PAD_SIZE 128 -#endif - -#if !defined(MD_HAVE_SOCKLEN_T) && !defined(socklen_t) - #define socklen_t int -#endif - -#ifndef MD_CAP_STACK - #define MD_CAP_STACK(var_addr) -#endif - -#endif /* !__ST_MD_H__ */ - diff --git a/trunk/3rdparty/st-srs/osguess.sh b/trunk/3rdparty/st-srs/osguess.sh deleted file mode 100644 index 531681efe6..0000000000 --- a/trunk/3rdparty/st-srs/osguess.sh +++ /dev/null @@ -1,45 +0,0 @@ -# -# This script can be used to automatically guess target OS. -# It requires the config.guess utility which is a part of GNU Autoconf. -# GNU Autoconf can be downloaded from ftp://ftp.gnu.org/gnu/autoconf/ -# -# Use "default" as a make target for automatic builds. -# - - -# Specify path to the config.guess utility (unless set via environment) -#CONFIG_GUESS_PATH= - - -if [ x"$CONFIG_GUESS_PATH" = x ]; then - echo "Error: CONFIG_GUESS_PATH variable is not set" - exit 1 -fi - -if [ ! -f "$CONFIG_GUESS_PATH/config.guess" ]; then - echo "Can't find $CONFIG_GUESS_PATH/config.guess utility. Wrong path?" - exit 1 -fi - -sys_info=`/bin/sh $CONFIG_GUESS_PATH/config.guess` - -echo "Building for $sys_info" - -case "$sys_info" in - *-ibm-aix4* ) OS=AIX ;; - *-freebsd* ) OS=FREEBSD ;; - hppa*-hp-hpux11*) OS=HPUX ;; - *-sgi-irix6* ) OS=IRIX ;; - *-linux* ) OS=LINUX ;; - *-netbsd* ) OS=NETBSD ;; - *-openbsd* ) OS=OPENBSD ;; - *-dec-osf* ) OS=OSF1 ;; - *-solaris2* ) OS=SOLARIS ;; - *-darwin* ) OS=DARWIN ;; - * ) OS= - echo "Sorry, unsupported OS" - exit 1 ;; -esac - -echo "Making with OS=$OS" - diff --git a/trunk/3rdparty/st-srs/public.h b/trunk/3rdparty/st-srs/public.h deleted file mode 100644 index 20b09407b2..0000000000 --- a/trunk/3rdparty/st-srs/public.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -#ifndef __ST_THREAD_H__ -#define __ST_THREAD_H__ - -#include -#include -#include -#include -#include -#include -#include - -#define ST_VERSION "1.9" -#define ST_VERSION_MAJOR 1 -#define ST_VERSION_MINOR 9 - -/* Undefine this to remove the context switch callback feature. */ -#define ST_SWITCH_CB - -#ifndef ETIME - #define ETIME ETIMEDOUT -#endif - -#ifndef ST_UTIME_NO_TIMEOUT - #define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL) -#endif - -#ifndef ST_UTIME_NO_WAIT - #define ST_UTIME_NO_WAIT 0 -#endif - -#define ST_EVENTSYS_DEFAULT 0 -#define ST_EVENTSYS_SELECT 1 -#define ST_EVENTSYS_POLL 2 -#define ST_EVENTSYS_ALT 3 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef unsigned long long st_utime_t; -typedef struct _st_thread * st_thread_t; -typedef struct _st_cond * st_cond_t; -typedef struct _st_mutex * st_mutex_t; -typedef struct _st_netfd * st_netfd_t; -#ifdef ST_SWITCH_CB -typedef void (*st_switch_cb_t)(void); -#endif - -extern int st_init(void); -extern int st_getfdlimit(void); - -extern int st_set_eventsys(int eventsys); -extern int st_get_eventsys(void); -extern const char *st_get_eventsys_name(void); - -#ifdef ST_SWITCH_CB -extern st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb); -extern st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb); -#endif - -extern st_thread_t st_thread_self(void); -extern void st_thread_exit(void *retval); -extern int st_thread_join(st_thread_t thread, void **retvalp); -extern void st_thread_interrupt(st_thread_t thread); -extern st_thread_t st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stack_size); -extern int st_randomize_stacks(int on); -extern int st_set_utime_function(st_utime_t (*func)(void)); - -extern st_utime_t st_utime(void); -extern st_utime_t st_utime_last_clock(void); -extern int st_timecache_set(int on); -extern time_t st_time(void); -extern int st_usleep(st_utime_t usecs); -extern int st_sleep(int secs); -extern st_cond_t st_cond_new(void); -extern int st_cond_destroy(st_cond_t cvar); -extern int st_cond_timedwait(st_cond_t cvar, st_utime_t timeout); -extern int st_cond_wait(st_cond_t cvar); -extern int st_cond_signal(st_cond_t cvar); -extern int st_cond_broadcast(st_cond_t cvar); -extern st_mutex_t st_mutex_new(void); -extern int st_mutex_destroy(st_mutex_t lock); -extern int st_mutex_lock(st_mutex_t lock); -extern int st_mutex_unlock(st_mutex_t lock); -extern int st_mutex_trylock(st_mutex_t lock); - -extern int st_key_create(int *keyp, void (*destructor)(void *)); -extern int st_key_getlimit(void); -extern int st_thread_setspecific(int key, void *value); -extern void *st_thread_getspecific(int key); - -extern st_netfd_t st_netfd_open(int osfd); -extern st_netfd_t st_netfd_open_socket(int osfd); -extern void st_netfd_free(st_netfd_t fd); -extern int st_netfd_close(st_netfd_t fd); -extern int st_netfd_fileno(st_netfd_t fd); -extern void st_netfd_setspecific(st_netfd_t fd, void *value, void (*destructor)(void *)); -extern void *st_netfd_getspecific(st_netfd_t fd); -extern int st_netfd_serialize_accept(st_netfd_t fd); -extern int st_netfd_poll(st_netfd_t fd, int how, st_utime_t timeout); - -extern int st_poll(struct pollfd *pds, int npds, st_utime_t timeout); -extern st_netfd_t st_accept(st_netfd_t fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout); -extern int st_connect(st_netfd_t fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout); -extern ssize_t st_read(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout); -extern ssize_t st_read_fully(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout); -extern int st_read_resid(st_netfd_t fd, void *buf, size_t *resid, st_utime_t timeout); -extern ssize_t st_readv(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout); -extern int st_readv_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout); -extern ssize_t st_write(st_netfd_t fd, const void *buf, size_t nbyte, st_utime_t timeout); -extern int st_write_resid(st_netfd_t fd, const void *buf, size_t *resid, st_utime_t timeout); -extern ssize_t st_writev(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout); -extern int st_writev_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout); -extern int st_recvfrom(st_netfd_t fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout); -extern int st_sendto(st_netfd_t fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout); -extern int st_recvmsg(st_netfd_t fd, struct msghdr *msg, int flags, st_utime_t timeout); -extern int st_sendmsg(st_netfd_t fd, const struct msghdr *msg, int flags, st_utime_t timeout); -extern st_netfd_t st_open(const char *path, int oflags, mode_t mode); - -#ifdef DEBUG -extern void _st_show_thread_stack(st_thread_t thread, const char *messg); -extern void _st_iterate_threads(void); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !__ST_THREAD_H__ */ - diff --git a/trunk/3rdparty/st-srs/sched.c b/trunk/3rdparty/st-srs/sched.c deleted file mode 100644 index 87515827e9..0000000000 --- a/trunk/3rdparty/st-srs/sched.c +++ /dev/null @@ -1,705 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#include -#include -#include -#include -#include -#include -#include "common.h" - -/* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */ -#ifndef NVALGRIND -#include -#endif - - -/* Global data */ -_st_vp_t _st_this_vp; /* This VP */ -_st_thread_t *_st_this_thread; /* Current thread */ -int _st_active_count = 0; /* Active thread count */ - -time_t _st_curr_time = 0; /* Current time as returned by time(2) */ -st_utime_t _st_last_tset; /* Last time it was fetched */ - - -int st_poll(struct pollfd *pds, int npds, st_utime_t timeout) -{ - struct pollfd *pd; - struct pollfd *epd = pds + npds; - _st_pollq_t pq; - _st_thread_t *me = _ST_CURRENT_THREAD(); - int n; - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - if ((*_st_eventsys->pollset_add)(pds, npds) < 0) - return -1; - - pq.pds = pds; - pq.npds = npds; - pq.thread = me; - pq.on_ioq = 1; - _ST_ADD_IOQ(pq); - if (timeout != ST_UTIME_NO_TIMEOUT) - _ST_ADD_SLEEPQ(me, timeout); - me->state = _ST_ST_IO_WAIT; - - _ST_SWITCH_CONTEXT(me); - - n = 0; - if (pq.on_ioq) { - /* If we timed out, the pollq might still be on the ioq. Remove it */ - _ST_DEL_IOQ(pq); - (*_st_eventsys->pollset_del)(pds, npds); - } else { - /* Count the number of ready descriptors */ - for (pd = pds; pd < epd; pd++) { - if (pd->revents) - n++; - } - } - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - return n; -} - - -void _st_vp_schedule(void) -{ - _st_thread_t *thread; - - if (_ST_RUNQ.next != &_ST_RUNQ) { - /* Pull thread off of the run queue */ - thread = _ST_THREAD_PTR(_ST_RUNQ.next); - _ST_DEL_RUNQ(thread); - } else { - /* If there are no threads to run, switch to the idle thread */ - thread = _st_this_vp.idle_thread; - } - ST_ASSERT(thread->state == _ST_ST_RUNNABLE); - - /* Resume the thread */ - thread->state = _ST_ST_RUNNING; - _ST_RESTORE_CONTEXT(thread); -} - - -/* - * Initialize this Virtual Processor - */ -int st_init(void) -{ - _st_thread_t *thread; - - if (_st_active_count) { - /* Already initialized */ - return 0; - } - - /* We can ignore return value here */ - st_set_eventsys(ST_EVENTSYS_DEFAULT); - - if (_st_io_init() < 0) - return -1; - - memset(&_st_this_vp, 0, sizeof(_st_vp_t)); - - ST_INIT_CLIST(&_ST_RUNQ); - ST_INIT_CLIST(&_ST_IOQ); - ST_INIT_CLIST(&_ST_ZOMBIEQ); -#ifdef DEBUG - ST_INIT_CLIST(&_ST_THREADQ); -#endif - - if ((*_st_eventsys->init)() < 0) - return -1; - - _st_this_vp.pagesize = getpagesize(); - _st_this_vp.last_clock = st_utime(); - - /* - * Create idle thread - */ - _st_this_vp.idle_thread = st_thread_create(_st_idle_thread_start, NULL, 0, 0); - if (!_st_this_vp.idle_thread) - return -1; - _st_this_vp.idle_thread->flags = _ST_FL_IDLE_THREAD; - _st_active_count--; - _ST_DEL_RUNQ(_st_this_vp.idle_thread); - - /* - * Initialize primordial thread - */ - thread = (_st_thread_t *) calloc(1, sizeof(_st_thread_t) + (ST_KEYS_MAX * sizeof(void *))); - if (!thread) - return -1; - thread->private_data = (void **) (thread + 1); - thread->state = _ST_ST_RUNNING; - thread->flags = _ST_FL_PRIMORDIAL; - _ST_SET_CURRENT_THREAD(thread); - _st_active_count++; -#ifdef DEBUG - _ST_ADD_THREADQ(thread); -#endif - - return 0; -} - - -#ifdef ST_SWITCH_CB -st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb) -{ - st_switch_cb_t ocb = _st_this_vp.switch_in_cb; - _st_this_vp.switch_in_cb = cb; - return ocb; -} - -st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb) -{ - st_switch_cb_t ocb = _st_this_vp.switch_out_cb; - _st_this_vp.switch_out_cb = cb; - return ocb; -} -#endif - - -/* - * Start function for the idle thread - */ -/* ARGSUSED */ -void *_st_idle_thread_start(void *arg) -{ - _st_thread_t *me = _ST_CURRENT_THREAD(); - - while (_st_active_count > 0) { - /* Idle vp till I/O is ready or the smallest timeout expired */ - _ST_VP_IDLE(); - - /* Check sleep queue for expired threads */ - _st_vp_check_clock(); - - me->state = _ST_ST_RUNNABLE; - _ST_SWITCH_CONTEXT(me); - } - - /* No more threads */ - exit(0); - - /* NOTREACHED */ - return NULL; -} - - -void st_thread_exit(void *retval) -{ - _st_thread_t *thread = _ST_CURRENT_THREAD(); - - thread->retval = retval; - _st_thread_cleanup(thread); - _st_active_count--; - if (thread->term) { - /* Put thread on the zombie queue */ - thread->state = _ST_ST_ZOMBIE; - _ST_ADD_ZOMBIEQ(thread); - - /* Notify on our termination condition variable */ - st_cond_signal(thread->term); - - /* Switch context and come back later */ - _ST_SWITCH_CONTEXT(thread); - - /* Continue the cleanup */ - st_cond_destroy(thread->term); - thread->term = NULL; - } - -#ifdef DEBUG - _ST_DEL_THREADQ(thread); -#endif - - /* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */ -#ifndef NVALGRIND - if (!(thread->flags & _ST_FL_PRIMORDIAL)) { - VALGRIND_STACK_DEREGISTER(thread->stack->valgrind_stack_id); - } -#endif - - if (!(thread->flags & _ST_FL_PRIMORDIAL)) - _st_stack_free(thread->stack); - - /* Find another thread to run */ - _ST_SWITCH_CONTEXT(thread); - /* Not going to land here */ -} - - -int st_thread_join(_st_thread_t *thread, void **retvalp) -{ - _st_cond_t *term = thread->term; - - /* Can't join a non-joinable thread */ - if (term == NULL) { - errno = EINVAL; - return -1; - } - if (_ST_CURRENT_THREAD() == thread) { - errno = EDEADLK; - return -1; - } - - /* Multiple threads can't wait on the same joinable thread */ - if (term->wait_q.next != &term->wait_q) { - errno = EINVAL; - return -1; - } - - while (thread->state != _ST_ST_ZOMBIE) { - if (st_cond_timedwait(term, ST_UTIME_NO_TIMEOUT) != 0) - return -1; - } - - if (retvalp) - *retvalp = thread->retval; - - /* - * Remove target thread from the zombie queue and make it runnable. - * When it gets scheduled later, it will do the clean up. - */ - thread->state = _ST_ST_RUNNABLE; - _ST_DEL_ZOMBIEQ(thread); - _ST_ADD_RUNQ(thread); - - return 0; -} - - -void _st_thread_main(void) -{ - _st_thread_t *thread = _ST_CURRENT_THREAD(); - - /* - * Cap the stack by zeroing out the saved return address register - * value. This allows some debugging/profiling tools to know when - * to stop unwinding the stack. It's a no-op on most platforms. - */ - MD_CAP_STACK(&thread); - - /* Run thread main */ - thread->retval = (*thread->start)(thread->arg); - - /* All done, time to go away */ - st_thread_exit(thread->retval); -} - - -/* - * Insert "thread" into the timeout heap, in the position - * specified by thread->heap_index. See docs/timeout_heap.txt - * for details about the timeout heap. - */ -static _st_thread_t **heap_insert(_st_thread_t *thread) { - int target = thread->heap_index; - int s = target; - _st_thread_t **p = &_ST_SLEEPQ; - int bits = 0; - int bit; - int index = 1; - - while (s) { - s >>= 1; - bits++; - } - for (bit = bits - 2; bit >= 0; bit--) { - if (thread->due < (*p)->due) { - _st_thread_t *t = *p; - thread->left = t->left; - thread->right = t->right; - *p = thread; - thread->heap_index = index; - thread = t; - } - index <<= 1; - if (target & (1 << bit)) { - p = &((*p)->right); - index |= 1; - } else { - p = &((*p)->left); - } - } - thread->heap_index = index; - *p = thread; - thread->left = thread->right = NULL; - return p; -} - - -/* - * Delete "thread" from the timeout heap. - */ -static void heap_delete(_st_thread_t *thread) { - _st_thread_t *t, **p; - int bits = 0; - int s, bit; - - /* First find and unlink the last heap element */ - p = &_ST_SLEEPQ; - s = _ST_SLEEPQ_SIZE; - while (s) { - s >>= 1; - bits++; - } - for (bit = bits - 2; bit >= 0; bit--) { - if (_ST_SLEEPQ_SIZE & (1 << bit)) { - p = &((*p)->right); - } else { - p = &((*p)->left); - } - } - t = *p; - *p = NULL; - --_ST_SLEEPQ_SIZE; - if (t != thread) { - /* - * Insert the unlinked last element in place of the element we are deleting - */ - t->heap_index = thread->heap_index; - p = heap_insert(t); - t = *p; - t->left = thread->left; - t->right = thread->right; - - /* - * Reestablish the heap invariant. - */ - for (;;) { - _st_thread_t *y; /* The younger child */ - int index_tmp; - if (t->left == NULL) - break; - else if (t->right == NULL) - y = t->left; - else if (t->left->due < t->right->due) - y = t->left; - else - y = t->right; - if (t->due > y->due) { - _st_thread_t *tl = y->left; - _st_thread_t *tr = y->right; - *p = y; - if (y == t->left) { - y->left = t; - y->right = t->right; - p = &y->left; - } else { - y->left = t->left; - y->right = t; - p = &y->right; - } - t->left = tl; - t->right = tr; - index_tmp = t->heap_index; - t->heap_index = y->heap_index; - y->heap_index = index_tmp; - } else { - break; - } - } - } - thread->left = thread->right = NULL; -} - - -void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout) -{ - thread->due = _ST_LAST_CLOCK + timeout; - thread->flags |= _ST_FL_ON_SLEEPQ; - thread->heap_index = ++_ST_SLEEPQ_SIZE; - heap_insert(thread); -} - - -void _st_del_sleep_q(_st_thread_t *thread) -{ - heap_delete(thread); - thread->flags &= ~_ST_FL_ON_SLEEPQ; -} - - -void _st_vp_check_clock(void) -{ - _st_thread_t *thread; - st_utime_t elapsed, now; - - now = st_utime(); - elapsed = now - _ST_LAST_CLOCK; - _ST_LAST_CLOCK = now; - - if (_st_curr_time && now - _st_last_tset > 999000) { - _st_curr_time = time(NULL); - _st_last_tset = now; - } - - while (_ST_SLEEPQ != NULL) { - thread = _ST_SLEEPQ; - ST_ASSERT(thread->flags & _ST_FL_ON_SLEEPQ); - if (thread->due > now) - break; - _ST_DEL_SLEEPQ(thread); - - /* If thread is waiting on condition variable, set the time out flag */ - if (thread->state == _ST_ST_COND_WAIT) - thread->flags |= _ST_FL_TIMEDOUT; - - /* Make thread runnable */ - ST_ASSERT(!(thread->flags & _ST_FL_IDLE_THREAD)); - thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(thread); - } -} - - -void st_thread_interrupt(_st_thread_t *thread) -{ - /* If thread is already dead */ - if (thread->state == _ST_ST_ZOMBIE) - return; - - thread->flags |= _ST_FL_INTERRUPT; - - if (thread->state == _ST_ST_RUNNING || thread->state == _ST_ST_RUNNABLE) - return; - - if (thread->flags & _ST_FL_ON_SLEEPQ) - _ST_DEL_SLEEPQ(thread); - - /* Make thread runnable */ - thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(thread); -} - - -/* Merge from https://github.com/michaeltalyansky/state-threads/commit/cce736426c2320ffec7c9820df49ee7a18ae638c */ -#if defined(__arm__) && !defined(MD_USE_BUILTIN_SETJMP) && __GLIBC_MINOR__ >= 19 - extern unsigned long __pointer_chk_guard; - #define PTR_MANGLE(var) \ - (var) = (__typeof (var)) ((unsigned long) (var) ^ __pointer_chk_guard) - #define PTR_DEMANGLE(var) PTR_MANGLE (var) -#endif - - -_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size) -{ - _st_thread_t *thread; - _st_stack_t *stack; - void **ptds; - char *sp; -#ifdef __ia64__ - char *bsp; -#endif - - /* Adjust stack size */ - if (stk_size == 0) - stk_size = ST_DEFAULT_STACK_SIZE; - stk_size = ((stk_size + _ST_PAGE_SIZE - 1) / _ST_PAGE_SIZE) * _ST_PAGE_SIZE; - stack = _st_stack_new(stk_size); - if (!stack) - return NULL; - - /* Allocate thread object and per-thread data off the stack */ -#if defined (MD_STACK_GROWS_DOWN) - sp = stack->stk_top; -#ifdef __ia64__ - /* - * The stack segment is split in the middle. The upper half is used - * as backing store for the register stack which grows upward. - * The lower half is used for the traditional memory stack which - * grows downward. Both stacks start in the middle and grow outward - * from each other. - */ - sp -= (stk_size >> 1); - bsp = sp; - /* Make register stack 64-byte aligned */ - if ((unsigned long)bsp & 0x3f) - bsp = bsp + (0x40 - ((unsigned long)bsp & 0x3f)); - stack->bsp = bsp + _ST_STACK_PAD_SIZE; -#endif - sp = sp - (ST_KEYS_MAX * sizeof(void *)); - ptds = (void **) sp; - sp = sp - sizeof(_st_thread_t); - thread = (_st_thread_t *) sp; - - /* Make stack 64-byte aligned */ - if ((unsigned long)sp & 0x3f) - sp = sp - ((unsigned long)sp & 0x3f); - stack->sp = sp - _ST_STACK_PAD_SIZE; -#elif defined (MD_STACK_GROWS_UP) - sp = stack->stk_bottom; - thread = (_st_thread_t *) sp; - sp = sp + sizeof(_st_thread_t); - ptds = (void **) sp; - sp = sp + (ST_KEYS_MAX * sizeof(void *)); - - /* Make stack 64-byte aligned */ - if ((unsigned long)sp & 0x3f) - sp = sp + (0x40 - ((unsigned long)sp & 0x3f)); - stack->sp = sp + _ST_STACK_PAD_SIZE; -#else -#error Unknown OS -#endif - - memset(thread, 0, sizeof(_st_thread_t)); - memset(ptds, 0, ST_KEYS_MAX * sizeof(void *)); - - /* Initialize thread */ - thread->private_data = ptds; - thread->stack = stack; - thread->start = start; - thread->arg = arg; - -#ifndef __ia64__ - /* Merge from https://github.com/michaeltalyansky/state-threads/commit/cce736426c2320ffec7c9820df49ee7a18ae638c */ - #if defined(__arm__) && !defined(MD_USE_BUILTIN_SETJMP) && __GLIBC_MINOR__ >= 19 - volatile void * lsp = PTR_MANGLE(stack->sp); - if (_setjmp ((thread)->context)) - _st_thread_main(); - (thread)->context[0].__jmpbuf[8] = (long) (lsp); - #else - _ST_INIT_CONTEXT(thread, stack->sp, _st_thread_main); - #endif -#else - _ST_INIT_CONTEXT(thread, stack->sp, stack->bsp, _st_thread_main); -#endif - - /* If thread is joinable, allocate a termination condition variable */ - if (joinable) { - thread->term = st_cond_new(); - if (thread->term == NULL) { - _st_stack_free(thread->stack); - return NULL; - } - } - - /* Make thread runnable */ - thread->state = _ST_ST_RUNNABLE; - _st_active_count++; - _ST_ADD_RUNQ(thread); -#ifdef DEBUG - _ST_ADD_THREADQ(thread); -#endif - - /* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */ -#ifndef NVALGRIND - if (!(thread->flags & _ST_FL_PRIMORDIAL)) { - thread->stack->valgrind_stack_id = VALGRIND_STACK_REGISTER(thread->stack->stk_top, thread->stack->stk_bottom); - } -#endif - - return thread; -} - - -_st_thread_t *st_thread_self(void) -{ - return _ST_CURRENT_THREAD(); -} - - -#ifdef DEBUG -/* ARGSUSED */ -void _st_show_thread_stack(_st_thread_t *thread, const char *messg) -{ - -} - -/* To be set from debugger */ -int _st_iterate_threads_flag = 0; - -void _st_iterate_threads(void) -{ - static _st_thread_t *thread = NULL; - static jmp_buf orig_jb, save_jb; - _st_clist_t *q; - - if (!_st_iterate_threads_flag) { - if (thread) { - memcpy(thread->context, save_jb, sizeof(jmp_buf)); - MD_LONGJMP(orig_jb, 1); - } - return; - } - - if (thread) { - memcpy(thread->context, save_jb, sizeof(jmp_buf)); - _st_show_thread_stack(thread, NULL); - } else { - if (MD_SETJMP(orig_jb)) { - _st_iterate_threads_flag = 0; - thread = NULL; - _st_show_thread_stack(thread, "Iteration completed"); - return; - } - thread = _ST_CURRENT_THREAD(); - _st_show_thread_stack(thread, "Iteration started"); - } - - q = thread->tlink.next; - if (q == &_ST_THREADQ) - q = q->next; - ST_ASSERT(q != &_ST_THREADQ); - thread = _ST_THREAD_THREADQ_PTR(q); - if (thread == _ST_CURRENT_THREAD()) - MD_LONGJMP(orig_jb, 1); - memcpy(save_jb, thread->context, sizeof(jmp_buf)); - MD_LONGJMP(thread->context, 1); -} -#endif /* DEBUG */ - diff --git a/trunk/3rdparty/st-srs/st.pc.in b/trunk/3rdparty/st-srs/st.pc.in deleted file mode 100644 index 46c39ec522..0000000000 --- a/trunk/3rdparty/st-srs/st.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: libst -Description: State Thread Library -Version: @VERSION@ -Libs: -L${libdir} -lst -Cflags: -I${includedir} diff --git a/trunk/3rdparty/st-srs/st.spec b/trunk/3rdparty/st-srs/st.spec deleted file mode 100644 index 4914aa1961..0000000000 --- a/trunk/3rdparty/st-srs/st.spec +++ /dev/null @@ -1,79 +0,0 @@ -Summary: State Threads Library -Name: st -Version: 1.9 -Release: 1 -Copyright: MPL 1.2 or GPL 2+ -Packager: Wesley W. Terpstra -Source: http://prdownloads.sourceforge.net/state-threads/st-%{version}.tar.gz -Prefix: /usr -BuildRoot: /tmp/%{name}-%{version}-build -Group: Development/Libraries - -%description -The State Threads library has an interface similar to POSIX threads. - -However, the threads are actually all run in-process. This type of -threading allows for controlled schedualing points. It is highly useful -for designing robust and extremely scalable internet applications since -there is no resource contention and locking is generally unnecessary. - -It can be combined with traditional threading or multiple process -parallelism to take advantage of multiple processors. - -See: for further -information about how state threads improve performance. - -%package -n libst-devel -Summary: State Threads Library - Development Files -Group: Development/Libraries -Requires: libst1 - -%description -n libst-devel -Development headers and documentation for libst - -%package -n libst1 -Summary: State Threads Library - Shared Libs Major 1 -Group: System/Libraries - -%description -n libst1 -Shared libraries for running applications linked against api version 1. - -%prep -%setup -q - -%build -make CONFIG_GUESS_PATH=/usr/share/automake default-optimized - -%install -if [ -d ${RPM_BUILD_ROOT} ]; then rm -rf ${RPM_BUILD_ROOT}; fi - -mkdir -m 0755 -p ${RPM_BUILD_ROOT}/%{prefix}/lib/pkgconfig -mkdir -m 0755 -p ${RPM_BUILD_ROOT}/%{prefix}/include -mkdir -m 0755 -p ${RPM_BUILD_ROOT}/%{prefix}/share/doc/libst-devel -cp -a obj/libst.* ${RPM_BUILD_ROOT}/%{prefix}/lib -cp -a obj/st.h ${RPM_BUILD_ROOT}/%{prefix}/include -sed "s*@prefix@*%{prefix}*g" ${RPM_BUILD_ROOT}/%{prefix}/lib/pkgconfig/st.pc -cp -a docs/* ${RPM_BUILD_ROOT}/%{prefix}/share/doc/libst-devel/ -cp -a examples ${RPM_BUILD_ROOT}/%{prefix}/share/doc/libst-devel/ - -%post -n libst1 -/sbin/ldconfig %{prefix}/lib - -%files -n libst1 -%defattr(-,root,root) -%{prefix}/lib/lib*.so.* - -%files -n libst-devel -%defattr(-,root,root) -%{prefix}/include/* -%{prefix}/lib/lib*.a -%{prefix}/lib/lib*.so -%{prefix}/lib/pkgconfig/st.pc -%{prefix}/share/doc/libst-devel/* - -%clean -if [ -d ${RPM_BUILD_ROOT} ]; then rm -rf ${RPM_BUILD_ROOT}; fi - -%changelog -* Wed Dec 26 2001 Wesley W. Terpstra -- first rpms for libst-1.3.tar.gz diff --git a/trunk/3rdparty/st-srs/stk.c b/trunk/3rdparty/st-srs/stk.c deleted file mode 100644 index 3e681e5954..0000000000 --- a/trunk/3rdparty/st-srs/stk.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#include -#include -#include -#include -#include -#include "common.h" - - -/* How much space to leave between the stacks, at each end */ -#define REDZONE _ST_PAGE_SIZE - -_st_clist_t _st_free_stacks = ST_INIT_STATIC_CLIST(&_st_free_stacks); -int _st_num_free_stacks = 0; -int _st_randomize_stacks = 0; - -static char *_st_new_stk_segment(int size); - -_st_stack_t *_st_stack_new(int stack_size) -{ - _st_clist_t *qp; - _st_stack_t *ts; - int extra; - - for (qp = _st_free_stacks.next; qp != &_st_free_stacks; qp = qp->next) { - ts = _ST_THREAD_STACK_PTR(qp); - if (ts->stk_size >= stack_size) { - /* Found a stack that is big enough */ - ST_REMOVE_LINK(&ts->links); - _st_num_free_stacks--; - ts->links.next = NULL; - ts->links.prev = NULL; - return ts; - } - } - - /* Make a new thread stack object. */ - if ((ts = (_st_stack_t *)calloc(1, sizeof(_st_stack_t))) == NULL) - return NULL; - extra = _st_randomize_stacks ? _ST_PAGE_SIZE : 0; - ts->vaddr_size = stack_size + 2*REDZONE + extra; - ts->vaddr = _st_new_stk_segment(ts->vaddr_size); - if (!ts->vaddr) { - free(ts); - return NULL; - } - ts->stk_size = stack_size; - ts->stk_bottom = ts->vaddr + REDZONE; - ts->stk_top = ts->stk_bottom + stack_size; - -#ifdef DEBUG - mprotect(ts->vaddr, REDZONE, PROT_NONE); - mprotect(ts->stk_top + extra, REDZONE, PROT_NONE); -#endif - - if (extra) { - long offset = (random() % extra) & ~0xf; - - ts->stk_bottom += offset; - ts->stk_top += offset; - } - - return ts; -} - - -/* - * Free the stack for the current thread - */ -void _st_stack_free(_st_stack_t *ts) -{ - if (!ts) - return; - - /* Put the stack on the free list */ - ST_APPEND_LINK(&ts->links, _st_free_stacks.prev); - _st_num_free_stacks++; -} - - -static char *_st_new_stk_segment(int size) -{ -#ifdef MALLOC_STACK - void *vaddr = malloc(size); -#else - static int zero_fd = -1; - int mmap_flags = MAP_PRIVATE; - void *vaddr; - -#if defined (MD_USE_SYSV_ANON_MMAP) - if (zero_fd < 0) { - if ((zero_fd = open("/dev/zero", O_RDWR, 0)) < 0) - return NULL; - fcntl(zero_fd, F_SETFD, FD_CLOEXEC); - } -#elif defined (MD_USE_BSD_ANON_MMAP) - mmap_flags |= MAP_ANON; -#else -#error Unknown OS -#endif - - vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, zero_fd, 0); - if (vaddr == (void *)MAP_FAILED) - return NULL; - -#endif /* MALLOC_STACK */ - - return (char *)vaddr; -} - - -/* Not used */ -#if 0 -void _st_delete_stk_segment(char *vaddr, int size) -{ -#ifdef MALLOC_STACK - free(vaddr); -#else - (void) munmap(vaddr, size); -#endif -} -#endif - -int st_randomize_stacks(int on) -{ - int wason = _st_randomize_stacks; - - _st_randomize_stacks = on; - if (on) - srandom((unsigned int) st_utime()); - - return wason; -} diff --git a/trunk/3rdparty/st-srs/sync.c b/trunk/3rdparty/st-srs/sync.c deleted file mode 100644 index 907fdfac3c..0000000000 --- a/trunk/3rdparty/st-srs/sync.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#include -#include -#include -#include "common.h" - - -extern time_t _st_curr_time; -extern st_utime_t _st_last_tset; -extern int _st_active_count; - -static st_utime_t (*_st_utime)(void) = NULL; - - -/***************************************** - * Time functions - */ - -st_utime_t st_utime(void) -{ - if (_st_utime == NULL) { -#ifdef MD_GET_UTIME - MD_GET_UTIME(); -#else -#error Unknown OS -#endif - } - - return (*_st_utime)(); -} - - -int st_set_utime_function(st_utime_t (*func)(void)) -{ - if (_st_active_count) { - errno = EINVAL; - return -1; - } - - _st_utime = func; - - return 0; -} - - -st_utime_t st_utime_last_clock(void) -{ - return _ST_LAST_CLOCK; -} - - -int st_timecache_set(int on) -{ - int wason = (_st_curr_time) ? 1 : 0; - - if (on) { - _st_curr_time = time(NULL); - _st_last_tset = st_utime(); - } else - _st_curr_time = 0; - - return wason; -} - - -time_t st_time(void) -{ - if (_st_curr_time) - return _st_curr_time; - - return time(NULL); -} - - -int st_usleep(st_utime_t usecs) -{ - _st_thread_t *me = _ST_CURRENT_THREAD(); - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - if (usecs != ST_UTIME_NO_TIMEOUT) { - me->state = _ST_ST_SLEEPING; - _ST_ADD_SLEEPQ(me, usecs); - } else - me->state = _ST_ST_SUSPENDED; - - _ST_SWITCH_CONTEXT(me); - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - return 0; -} - - -int st_sleep(int secs) -{ - return st_usleep((secs >= 0) ? secs * (st_utime_t) 1000000LL : ST_UTIME_NO_TIMEOUT); -} - - -/***************************************** - * Condition variable functions - */ - -_st_cond_t *st_cond_new(void) -{ - _st_cond_t *cvar; - - cvar = (_st_cond_t *) calloc(1, sizeof(_st_cond_t)); - if (cvar) { - ST_INIT_CLIST(&cvar->wait_q); - } - - return cvar; -} - - -int st_cond_destroy(_st_cond_t *cvar) -{ - if (cvar->wait_q.next != &cvar->wait_q) { - errno = EBUSY; - return -1; - } - - free(cvar); - - return 0; -} - - -int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout) -{ - _st_thread_t *me = _ST_CURRENT_THREAD(); - int rv; - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - /* Put caller thread on the condition variable's wait queue */ - me->state = _ST_ST_COND_WAIT; - ST_APPEND_LINK(&me->wait_links, &cvar->wait_q); - - if (timeout != ST_UTIME_NO_TIMEOUT) - _ST_ADD_SLEEPQ(me, timeout); - - _ST_SWITCH_CONTEXT(me); - - ST_REMOVE_LINK(&me->wait_links); - rv = 0; - - if (me->flags & _ST_FL_TIMEDOUT) { - me->flags &= ~_ST_FL_TIMEDOUT; - errno = ETIME; - rv = -1; - } - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - rv = -1; - } - - return rv; -} - - -int st_cond_wait(_st_cond_t *cvar) -{ - return st_cond_timedwait(cvar, ST_UTIME_NO_TIMEOUT); -} - - -static int _st_cond_signal(_st_cond_t *cvar, int broadcast) -{ - _st_thread_t *thread; - _st_clist_t *q; - - for (q = cvar->wait_q.next; q != &cvar->wait_q; q = q->next) { - thread = _ST_THREAD_WAITQ_PTR(q); - if (thread->state == _ST_ST_COND_WAIT) { - if (thread->flags & _ST_FL_ON_SLEEPQ) - _ST_DEL_SLEEPQ(thread); - - /* Make thread runnable */ - thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(thread); - if (!broadcast) - break; - } - } - - return 0; -} - - -int st_cond_signal(_st_cond_t *cvar) -{ - return _st_cond_signal(cvar, 0); -} - - -int st_cond_broadcast(_st_cond_t *cvar) -{ - return _st_cond_signal(cvar, 1); -} - - -/***************************************** - * Mutex functions - */ - -_st_mutex_t *st_mutex_new(void) -{ - _st_mutex_t *lock; - - lock = (_st_mutex_t *) calloc(1, sizeof(_st_mutex_t)); - if (lock) { - ST_INIT_CLIST(&lock->wait_q); - lock->owner = NULL; - } - - return lock; -} - - -int st_mutex_destroy(_st_mutex_t *lock) -{ - if (lock->owner != NULL || lock->wait_q.next != &lock->wait_q) { - errno = EBUSY; - return -1; - } - - free(lock); - - return 0; -} - - -int st_mutex_lock(_st_mutex_t *lock) -{ - _st_thread_t *me = _ST_CURRENT_THREAD(); - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - if (lock->owner == NULL) { - /* Got the mutex */ - lock->owner = me; - return 0; - } - - if (lock->owner == me) { - errno = EDEADLK; - return -1; - } - - /* Put caller thread on the mutex's wait queue */ - me->state = _ST_ST_LOCK_WAIT; - ST_APPEND_LINK(&me->wait_links, &lock->wait_q); - - _ST_SWITCH_CONTEXT(me); - - ST_REMOVE_LINK(&me->wait_links); - - if ((me->flags & _ST_FL_INTERRUPT) && lock->owner != me) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - return 0; -} - - -int st_mutex_unlock(_st_mutex_t *lock) -{ - _st_thread_t *thread; - _st_clist_t *q; - - if (lock->owner != _ST_CURRENT_THREAD()) { - errno = EPERM; - return -1; - } - - for (q = lock->wait_q.next; q != &lock->wait_q; q = q->next) { - thread = _ST_THREAD_WAITQ_PTR(q); - if (thread->state == _ST_ST_LOCK_WAIT) { - lock->owner = thread; - /* Make thread runnable */ - thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(thread); - return 0; - } - } - - /* No threads waiting on this mutex */ - lock->owner = NULL; - - return 0; -} - - -int st_mutex_trylock(_st_mutex_t *lock) -{ - if (lock->owner != NULL) { - errno = EBUSY; - return -1; - } - - /* Got the mutex */ - lock->owner = _ST_CURRENT_THREAD(); - - return 0; -} - diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index a4c8730dfe..843439357e 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -212,34 +212,23 @@ if [[ $OS_IS_UBUNTU = NO && $OS_IS_CENTOS = NO && $SRS_EXPORT_LIBRTMP_PROJECT = fi ##################################################################################### -# state-threads +# libco ##################################################################################### if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then - # check the cross build flag file, if flag changed, need to rebuild the st. - _ST_MAKE=linux-debug && _ST_EXTRA_CFLAGS="-DMD_HAVE_EPOLL" - if [[ $SRS_VALGRIND == YES ]]; then - _ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -DMD_VALGRIND" - fi - # Pass the global extra flags. - if [[ $SRS_EXTRA_FLAGS != '' ]]; then - _ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS $SRS_EXTRA_FLAGS" - fi - # Patched ST from https://github.com/ossrs/state-threads/tree/srs - if [[ -f ${SRS_OBJS}/st/libst.a ]]; then - echo "The state-threads is ok."; + if [[ -f ${SRS_OBJS}/co/libcolib.a ]]; then + echo "The libco is ok."; else - echo "Building state-threads."; + echo "Building libco."; ( - rm -rf ${SRS_OBJS}/st-srs && cd ${SRS_OBJS} && - ln -sf ../3rdparty/st-srs && cd st-srs && - make clean && make ${_ST_MAKE} EXTRA_CFLAGS="${_ST_EXTRA_CFLAGS}" \ - CC=${SRS_TOOL_CC} AR=${SRS_TOOL_AR} LD=${SRS_TOOL_LD} RANDLIB=${SRS_TOOL_RANDLIB} && - cd .. && rm -f st && ln -sf st-srs/obj st + rm -rf ${SRS_OBJS}/co && cd ${SRS_OBJS} && + ln -sf ../3rdparty/libco && cd libco && + make clean && make colib && + cd .. && rm -f co && ln -sf libco/ co ) fi # check status - ret=$?; if [[ $ret -ne 0 ]]; then echo "Build state-threads failed, ret=$ret"; exit $ret; fi - if [ ! -f ${SRS_OBJS}/st/libst.a ]; then echo "Build state-threads static lib failed."; exit -1; fi + ret=$?; if [[ $ret -ne 0 ]]; then echo "Build libco failed, ret=$ret"; exit $ret; fi + if [ ! -f ${SRS_OBJS}/co/lib/libcolib.a ]; then echo "Build libco static lib failed."; exit -1; fi fi ##################################################################################### diff --git a/trunk/configure b/trunk/configure index d233f66dbb..e67644a200 100755 --- a/trunk/configure +++ b/trunk/configure @@ -142,12 +142,12 @@ END ##################################################################################### # Libraries, external library to build in srs, -# header(.h): add to ModuleLibIncs if need the specified library. for example, LibSTRoot -# library(.a): add to ModuleLibFiles if binary need the specifeid library. for example, LibSTfile +# header(.h): add to ModuleLibIncs if need the specified library. for example, LibCoRoot +# library(.a): add to ModuleLibFiles if binary need the specifeid library. for example, LibCofile # -# st(state-threads) the basic network library for SRS. -LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a" -if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-lst"; fi +# libco the basic network library for SRS. +LibcoRoot="${SRS_OBJS_DIR}/co"; Libcofile="${LibcoRoot}/lib/libcolib.a -lpthread" +if [[ $SRS_SHARED_LIBCO == YES ]]; then Libcofile="-lcolib -lpthread"; fi # openssl-1.1.0e, for the RTMP complex handshake. LibSSLRoot="";LibSSLfile="" if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == NO ]]; then @@ -233,7 +233,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVICE" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibcoRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_service_log" "srs_service_st" "srs_service_http_client" "srs_service_http_conn" "srs_service_rtmp_conn" "srs_service_utility" "srs_service_conn") @@ -246,7 +246,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibcoRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -284,7 +284,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then if [[ $SRS_SRT == YES ]]; then MODULE_DEPENDS+=("SRT") fi - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibcoRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi @@ -297,7 +297,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="MAIN" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibcoRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) MODULE_FILES=() DEFINES="" # add each modules for main @@ -324,24 +324,24 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then done # # all depends libraries - ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${Libcofile} ${LibSSLfile} ${LibGperfFile}) if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi # all depends objects MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibcoRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then MODULE_OBJS="${MODULE_OBJS} ${SRT_OBJS[@]}" fi LINK_OPTIONS="${SrsLinkOptions}${SrsGprofLink}${SrsGperfLink}" # - # srs: srs(simple rtmp server) over st(state-threads) + # srs: srs(simple rtmp server) over co(libco) BUILD_KEY="srs" APP_MAIN="srs_main_server" APP_NAME="srs" . auto/apps.sh # # For modules, without the app module. MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" - ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${Libcofile} ${LibSSLfile} ${LibGperfFile}) # for SRS_MODULE in ${SRS_MODULES[*]}; do . $SRS_MODULE/config @@ -361,11 +361,11 @@ if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibcoRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi - ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) + ModuleLibFiles=(${Libcofile} ${LibSSLfile}) if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi @@ -413,7 +413,7 @@ help: @echo "Usage: make |||||||" @echo " help display this help menu" @echo " clean cleanup project" - @echo " server build the srs(simple rtmp server) over st(state-threads)" + @echo " server build the srs(simple rtmp server) over co(libco)" @echo " librtmp build the client publish/play library, and samples" @echo " utest build the utest for srs" @echo " install install srs to the prefix path" @@ -451,7 +451,7 @@ END else cat << END >> ${SRS_WORKDIR}/${SRS_MAKEFILE} server: _prepare_dir - @echo "Build the srs(simple rtmp server) over ST(state-threads)" + @echo "Build the srs(simple rtmp server) over co(libco)" \$(MAKE) -f ${SRS_OBJS_DIR}/${SRS_MAKEFILE} srs END diff --git a/trunk/research/st/Makefile b/trunk/research/st/Makefile deleted file mode 100755 index 0b24bb80c2..0000000000 --- a/trunk/research/st/Makefile +++ /dev/null @@ -1,100 +0,0 @@ -# The contents of this file are subject to the Mozilla Public -# License Version 1.1 (the "License"); you may not use this file -# except in compliance with the License. You may obtain a copy of -# the License at http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS -# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -# implied. See the License for the specific language governing -# rights and limitations under the License. -# -# The Original Code is the Netscape Portable Runtime library. -# -# The Initial Developer of the Original Code is Netscape -# Communications Corporation. Portions created by Netscape are -# Copyright (C) 1994-2000 Netscape Communications Corporation. All -# Rights Reserved. -# -# Contributor(s): Silicon Graphics, Inc. -# -# Portions created by SGI are Copyright (C) 2000-2001 Silicon -# Graphics, Inc. All Rights Reserved. -# -# Alternatively, the contents of this file may be used under the -# terms of the GNU General Public License Version 2 or later (the -# "GPL"), in which case the provisions of the GPL are applicable -# instead of those above. If you wish to allow use of your -# version of this file only under the terms of the GPL and not to -# allow others to use your version of this file under the MPL, -# indicate your decision by deleting the provisions above and -# replace them with the notice and other provisions required by -# the GPL. If you do not delete the provisions above, a recipient -# may use your version of this file under either the MPL or the -# GPL. - -########################## -# Target dir and cc: -CC = cc -TARGETDIR = objs - -########################## -# Supported OSes: -OS = LINUX - -ifneq ($(shell test -f /usr/include/sys/epoll.h && echo yes), yes) -default: - @echo "epoll not found" - @exit 1 -endif - -EXTRA_OBJS = $(TARGETDIR)/md.o - -CFLAGS = -OTHER_FLAGS += -Wall -g -O0 -DEFINES = -D$(OS) -DDEBUG -DMD_HAVE_EPOLL -DMALLOC_STACK - -########################## -# Other possible defines: -# To use malloc(3) instead of mmap(2) for stack allocation: -# DEFINES += -DMALLOC_STACK -# -# To provision more than the default 16 thread-specific-data keys -# (but not too many!): -# DEFINES += -DST_KEYS_MAX= -# -# Note that you can also add these defines by specifying them as -# make/gmake arguments (without editing this Makefile). For example: -# -# make EXTRA_CFLAGS=-UMD_HAVE_EPOLL -# -########################## - -CFLAGS += $(DEFINES) $(OTHER_FLAGS) $(EXTRA_CFLAGS) - -OBJS = $(TARGETDIR)/sched.o \ - $(TARGETDIR)/stk.o \ - $(TARGETDIR)/sync.o \ - $(TARGETDIR)/key.o \ - $(TARGETDIR)/io.o \ - $(TARGETDIR)/event.o \ - $(TARGETDIR)/srs.o -OBJS += $(EXTRA_OBJS) -SRS = $(TARGETDIR)/srs - -linux-debug: all -all: $(TARGETDIR) $(SRS) - -$(TARGETDIR): - if [ ! -d $(TARGETDIR) ]; then mkdir $(TARGETDIR); fi - -$(SRS): $(OBJS) - $(CC) $(CFLAGS) -o $@ $(OBJS) - -$(TARGETDIR)/md.o: md.S - $(CC) $(CFLAGS) -c $< -o $@ - -$(TARGETDIR)/%.o: %.c common.h md.h Makefile - $(CC) $(CFLAGS) -c $< -o $@ - -clean: - rm -rf $(TARGETDIR) diff --git a/trunk/research/st/common.h b/trunk/research/st/common.h deleted file mode 100644 index b83e575caf..0000000000 --- a/trunk/research/st/common.h +++ /dev/null @@ -1,445 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#ifndef __ST_COMMON_H__ -#define __ST_COMMON_H__ - -#include -#include -#include -#include -#include - -/* Enable assertions only if DEBUG is defined */ -#ifndef DEBUG - #define NDEBUG -#endif -#include -#define ST_ASSERT(expr) assert(expr) - -#define ST_BEGIN_MACRO { -#define ST_END_MACRO } - -#ifdef DEBUG - #define ST_HIDDEN /*nothing*/ -#else - #define ST_HIDDEN static -#endif - -#include "public.h" -#include "md.h" - -/***************************************** - * Circular linked list definitions - */ - -typedef struct _st_clist { - struct _st_clist *next; - struct _st_clist *prev; -} _st_clist_t; - -/* Insert element "_e" into the list, before "_l" */ -#define ST_INSERT_BEFORE(_e,_l) \ - ST_BEGIN_MACRO \ - (_e)->next = (_l); \ - (_e)->prev = (_l)->prev; \ - (_l)->prev->next = (_e); \ - (_l)->prev = (_e); \ - ST_END_MACRO - -/* Insert element "_e" into the list, after "_l" */ -#define ST_INSERT_AFTER(_e,_l) \ - ST_BEGIN_MACRO \ - (_e)->next = (_l)->next; \ - (_e)->prev = (_l); \ - (_l)->next->prev = (_e); \ - (_l)->next = (_e); \ - ST_END_MACRO - -/* Return the element following element "_e" */ -#define ST_NEXT_LINK(_e) ((_e)->next) - -/* Append an element "_e" to the end of the list "_l" */ -#define ST_APPEND_LINK(_e,_l) ST_INSERT_BEFORE(_e,_l) - -/* Insert an element "_e" at the head of the list "_l" */ -#define ST_INSERT_LINK(_e,_l) ST_INSERT_AFTER(_e,_l) - -/* Return the head/tail of the list */ -#define ST_LIST_HEAD(_l) (_l)->next -#define ST_LIST_TAIL(_l) (_l)->prev - -/* Remove the element "_e" from it's circular list */ -#define ST_REMOVE_LINK(_e) \ - ST_BEGIN_MACRO \ - (_e)->prev->next = (_e)->next; \ - (_e)->next->prev = (_e)->prev; \ - ST_END_MACRO - -/* Return non-zero if the given circular list "_l" is empty, */ -/* zero if the circular list is not empty */ -#define ST_CLIST_IS_EMPTY(_l) \ - ((_l)->next == (_l)) - -/* Initialize a circular list */ -#define ST_INIT_CLIST(_l) \ - ST_BEGIN_MACRO \ - (_l)->next = (_l); \ - (_l)->prev = (_l); \ - ST_END_MACRO - -#define ST_INIT_STATIC_CLIST(_l) \ - {(_l), (_l)} - - -/***************************************** - * Basic types definitions - */ - -typedef void (*_st_destructor_t)(void *); - -typedef struct _st_stack { - _st_clist_t links; - char *vaddr; /* Base of stack's allocated memory */ - int vaddr_size; /* Size of stack's allocated memory */ - int stk_size; /* Size of usable portion of the stack */ - char *stk_bottom; /* Lowest address of stack's usable portion */ - char *stk_top; /* Highest address of stack's usable portion */ - void *sp; /* Stack pointer from C's point of view */ -} _st_stack_t; - - -typedef struct _st_cond { - _st_clist_t wait_q; /* Condition variable wait queue */ -} _st_cond_t; - - -typedef struct _st_thread _st_thread_t; - -struct _st_thread { - int state; /* Thread's state */ - int flags; /* Thread's flags */ - - void *(*start)(void *arg); /* The start function of the thread */ - void *arg; /* Argument of the start function */ - void *retval; /* Return value of the start function */ - - _st_stack_t *stack; /* Info about thread's stack */ - - _st_clist_t links; /* For putting on run/sleep/zombie queue */ - _st_clist_t wait_links; /* For putting on mutex/condvar wait queue */ - #ifdef DEBUG - _st_clist_t tlink; /* For putting on thread queue */ - #endif - - st_utime_t due; /* Wakeup time when thread is sleeping */ - _st_thread_t *left; /* For putting in timeout heap */ - _st_thread_t *right; /* -- see docs/timeout_heap.txt for details */ - int heap_index; - - void **private_data; /* Per thread private data */ - - _st_cond_t *term; /* Termination condition variable for join */ - - jmp_buf context; /* Thread's context */ -}; - - -typedef struct _st_mutex { - _st_thread_t *owner; /* Current mutex owner */ - _st_clist_t wait_q; /* Mutex wait queue */ -} _st_mutex_t; - - -typedef struct _st_pollq { - _st_clist_t links; /* For putting on io queue */ - _st_thread_t *thread; /* Polling thread */ - struct pollfd *pds; /* Array of poll descriptors */ - int npds; /* Length of the array */ - int on_ioq; /* Is it on ioq? */ -} _st_pollq_t; - - -typedef struct _st_eventsys_ops { - const char *name; /* Name of this event system */ - int val; /* Type of this event system */ - int (*init)(void); /* Initialization */ - void (*dispatch)(void); /* Dispatch function */ - int (*pollset_add)(struct pollfd *, int); /* Add descriptor set */ - void (*pollset_del)(struct pollfd *, int); /* Delete descriptor set */ - int (*fd_new)(int); /* New descriptor allocated */ - int (*fd_close)(int); /* Descriptor closed */ - int (*fd_getlimit)(void); /* Descriptor hard limit */ -} _st_eventsys_t; - - -typedef struct _st_vp { - _st_thread_t *idle_thread; /* Idle thread for this vp */ - st_utime_t last_clock; /* The last time we went into vp_check_clock() */ - - _st_clist_t run_q; /* run queue for this vp */ - _st_clist_t io_q; /* io queue for this vp */ - _st_clist_t zombie_q; /* zombie queue for this vp */ - #ifdef DEBUG - _st_clist_t thread_q; /* all threads of this vp */ - #endif - int pagesize; - - _st_thread_t *sleep_q; /* sleep queue for this vp */ - int sleepq_size; /* number of threads on sleep queue */ - - #ifdef ST_SWITCH_CB - st_switch_cb_t switch_out_cb; /* called when a thread is switched out */ - st_switch_cb_t switch_in_cb; /* called when a thread is switched in */ - #endif -} _st_vp_t; - - -typedef struct _st_netfd { - int osfd; /* Underlying OS file descriptor */ - int inuse; /* In-use flag */ - void *private_data; /* Per descriptor private data */ - _st_destructor_t destructor; /* Private data destructor function */ - void *aux_data; /* Auxiliary data for internal use */ - struct _st_netfd *next; /* For putting on the free list */ -} _st_netfd_t; - - -/***************************************** - * Current vp, thread, and event system - */ - -extern _st_vp_t _st_this_vp; -extern _st_thread_t *_st_this_thread; -extern _st_eventsys_t *_st_eventsys; - -#define _ST_CURRENT_THREAD() (_st_this_thread) -#define _ST_SET_CURRENT_THREAD(_thread) (_st_this_thread = (_thread)) - -#define _ST_LAST_CLOCK (_st_this_vp.last_clock) - -#define _ST_RUNQ (_st_this_vp.run_q) -#define _ST_IOQ (_st_this_vp.io_q) -#define _ST_ZOMBIEQ (_st_this_vp.zombie_q) -#ifdef DEBUG - #define _ST_THREADQ (_st_this_vp.thread_q) -#endif - -#define _ST_PAGE_SIZE (_st_this_vp.pagesize) - -#define _ST_SLEEPQ (_st_this_vp.sleep_q) -#define _ST_SLEEPQ_SIZE (_st_this_vp.sleepq_size) - -#define _ST_VP_IDLE() (*_st_eventsys->dispatch)() - - -/***************************************** - * vp queues operations - */ - -#define _ST_ADD_IOQ(_pq) ST_APPEND_LINK(&_pq.links, &_ST_IOQ) -#define _ST_DEL_IOQ(_pq) ST_REMOVE_LINK(&_pq.links) - -#define _ST_ADD_RUNQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_RUNQ) -#define _ST_DEL_RUNQ(_thr) ST_REMOVE_LINK(&(_thr)->links) - -#define _ST_ADD_SLEEPQ(_thr, _timeout) _st_add_sleep_q(_thr, _timeout) -#define _ST_DEL_SLEEPQ(_thr) _st_del_sleep_q(_thr) - -#define _ST_ADD_ZOMBIEQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_ZOMBIEQ) -#define _ST_DEL_ZOMBIEQ(_thr) ST_REMOVE_LINK(&(_thr)->links) - -#ifdef DEBUG - #define _ST_ADD_THREADQ(_thr) ST_APPEND_LINK(&(_thr)->tlink, &_ST_THREADQ) - #define _ST_DEL_THREADQ(_thr) ST_REMOVE_LINK(&(_thr)->tlink) -#endif - - -/***************************************** - * Thread states and flags - */ - -#define _ST_ST_RUNNING 0 -#define _ST_ST_RUNNABLE 1 -#define _ST_ST_IO_WAIT 2 -#define _ST_ST_LOCK_WAIT 3 -#define _ST_ST_COND_WAIT 4 -#define _ST_ST_SLEEPING 5 -#define _ST_ST_ZOMBIE 6 -#define _ST_ST_SUSPENDED 7 - -#define _ST_FL_PRIMORDIAL 0x01 -#define _ST_FL_IDLE_THREAD 0x02 -#define _ST_FL_ON_SLEEPQ 0x04 -#define _ST_FL_INTERRUPT 0x08 -#define _ST_FL_TIMEDOUT 0x10 - -/***************************************** - * Pointer conversion - */ - -#ifndef offsetof - #define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier)) -#endif - -#define _ST_THREAD_PTR(_qp) \ - ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, links))) - -#define _ST_THREAD_WAITQ_PTR(_qp) \ - ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, wait_links))) - -#define _ST_THREAD_STACK_PTR(_qp) \ - ((_st_stack_t *)((char*)(_qp) - offsetof(_st_stack_t, links))) - -#define _ST_POLLQUEUE_PTR(_qp) \ - ((_st_pollq_t *)((char *)(_qp) - offsetof(_st_pollq_t, links))) - -#ifdef DEBUG - #define _ST_THREAD_THREADQ_PTR(_qp) \ - ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, tlink))) -#endif - - -/***************************************** - * Constants - */ - -#ifndef ST_UTIME_NO_TIMEOUT - #define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL) -#endif - -#define ST_DEFAULT_STACK_SIZE (64*1024) - -#ifndef ST_KEYS_MAX - #define ST_KEYS_MAX 16 -#endif - -#ifndef ST_MIN_POLLFDS_SIZE - #define ST_MIN_POLLFDS_SIZE 64 -#endif - - -/***************************************** - * Threads context switching - */ - -#ifdef DEBUG - void _st_iterate_threads(void); - #define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads() -#else - #define ST_DEBUG_ITERATE_THREADS() -#endif - -#ifdef ST_SWITCH_CB - #define ST_SWITCH_OUT_CB(_thread) \ - if (_st_this_vp.switch_out_cb != NULL && \ - _thread != _st_this_vp.idle_thread && \ - _thread->state != _ST_ST_ZOMBIE) { \ - _st_this_vp.switch_out_cb(); \ - } - #define ST_SWITCH_IN_CB(_thread) \ - if (_st_this_vp.switch_in_cb != NULL && \ - _thread != _st_this_vp.idle_thread && \ - _thread->state != _ST_ST_ZOMBIE) { \ - _st_this_vp.switch_in_cb(); \ - } -#else - #define ST_SWITCH_OUT_CB(_thread) - #define ST_SWITCH_IN_CB(_thread) -#endif - -/* - * Switch away from the current thread context by saving its state and - * calling the thread scheduler - */ -#define _ST_SWITCH_CONTEXT(_thread) \ - ST_BEGIN_MACRO \ - ST_SWITCH_OUT_CB(_thread); \ - if (!MD_SETJMP((_thread)->context)) { \ - _st_vp_schedule(); \ - } \ - ST_DEBUG_ITERATE_THREADS(); \ - ST_SWITCH_IN_CB(_thread); \ - ST_END_MACRO - -/* - * Restore a thread context that was saved by _ST_SWITCH_CONTEXT or - * initialized by _ST_INIT_CONTEXT - */ -#define _ST_RESTORE_CONTEXT(_thread) \ - ST_BEGIN_MACRO \ - _ST_SET_CURRENT_THREAD(_thread); \ - MD_LONGJMP((_thread)->context, 1); \ - ST_END_MACRO - -/* - * Number of bytes reserved under the stack "bottom" - */ -#define _ST_STACK_PAD_SIZE MD_STACK_PAD_SIZE - - -/***************************************** - * Forward declarations - */ - -void _st_vp_schedule(void); -void _st_vp_check_clock(void); -void *_st_idle_thread_start(void *arg); -void _st_thread_main(void); -void _st_thread_cleanup(_st_thread_t *thread); -void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout); -void _st_del_sleep_q(_st_thread_t *thread); -_st_stack_t *_st_stack_new(int stack_size); -void _st_stack_free(_st_stack_t *ts); -int _st_io_init(void); - -st_utime_t st_utime(void); -_st_cond_t *st_cond_new(void); -int st_cond_destroy(_st_cond_t *cvar); -int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout); -int st_cond_signal(_st_cond_t *cvar); -ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout); -ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout); -int st_poll(struct pollfd *pds, int npds, st_utime_t timeout); -_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size); - -#endif /* !__ST_COMMON_H__ */ - diff --git a/trunk/research/st/event.c b/trunk/research/st/event.c deleted file mode 100644 index 5704f520a9..0000000000 --- a/trunk/research/st/event.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * Yahoo! Inc. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -#include -#include -#include -#include -#include -#include -#include "common.h" - -#ifdef USE_POLL - #error "Not support USE_POLL" -#endif -#ifdef MD_HAVE_KQUEUE - #error "Not support MD_HAVE_KQUEUE" -#endif -#ifdef MD_HAVE_POLL - #error "Not support MD_HAVE_POLL" -#endif -#ifndef MD_HAVE_EPOLL - #error "Only support MD_HAVE_EPOLL" -#endif - -#include - -typedef struct _epoll_fd_data { - int rd_ref_cnt; - int wr_ref_cnt; - int ex_ref_cnt; - int revents; -} _epoll_fd_data_t; - -static struct _st_epolldata { - _epoll_fd_data_t *fd_data; - struct epoll_event *evtlist; - int fd_data_size; - int evtlist_size; - int evtlist_cnt; - int fd_hint; - int epfd; - pid_t pid; -} *_st_epoll_data; - -#ifndef ST_EPOLL_EVTLIST_SIZE -/* Not a limit, just a hint */ -#define ST_EPOLL_EVTLIST_SIZE 4096 -#endif - -#define _ST_EPOLL_READ_CNT(fd) (_st_epoll_data->fd_data[fd].rd_ref_cnt) -#define _ST_EPOLL_WRITE_CNT(fd) (_st_epoll_data->fd_data[fd].wr_ref_cnt) -#define _ST_EPOLL_EXCEP_CNT(fd) (_st_epoll_data->fd_data[fd].ex_ref_cnt) -#define _ST_EPOLL_REVENTS(fd) (_st_epoll_data->fd_data[fd].revents) - -#define _ST_EPOLL_READ_BIT(fd) (_ST_EPOLL_READ_CNT(fd) ? EPOLLIN : 0) -#define _ST_EPOLL_WRITE_BIT(fd) (_ST_EPOLL_WRITE_CNT(fd) ? EPOLLOUT : 0) -#define _ST_EPOLL_EXCEP_BIT(fd) (_ST_EPOLL_EXCEP_CNT(fd) ? EPOLLPRI : 0) -#define _ST_EPOLL_EVENTS(fd) \ - (_ST_EPOLL_READ_BIT(fd)|_ST_EPOLL_WRITE_BIT(fd)|_ST_EPOLL_EXCEP_BIT(fd)) - -_st_eventsys_t *_st_eventsys = NULL; - -/***************************************** - * epoll event system - */ - -ST_HIDDEN int _st_epoll_init(void) -{ - int fdlim; - int err = 0; - int rv = 0; - - _st_epoll_data = (struct _st_epolldata *) calloc(1, sizeof(*_st_epoll_data)); - if (!_st_epoll_data) { - return -1; - } - - fdlim = st_getfdlimit(); - _st_epoll_data->fd_hint = (fdlim > 0 && fdlim < ST_EPOLL_EVTLIST_SIZE) ? fdlim : ST_EPOLL_EVTLIST_SIZE; - - if ((_st_epoll_data->epfd = epoll_create(_st_epoll_data->fd_hint)) < 0) { - err = errno; - rv = -1; - goto cleanup_epoll; - } - fcntl(_st_epoll_data->epfd, F_SETFD, FD_CLOEXEC); - _st_epoll_data->pid = getpid(); - - /* Allocate file descriptor data array */ - _st_epoll_data->fd_data_size = _st_epoll_data->fd_hint; - _st_epoll_data->fd_data = (_epoll_fd_data_t *)calloc(_st_epoll_data->fd_data_size, sizeof(_epoll_fd_data_t)); - if (!_st_epoll_data->fd_data) { - err = errno; - rv = -1; - goto cleanup_epoll; - } - - /* Allocate event lists */ - _st_epoll_data->evtlist_size = _st_epoll_data->fd_hint; - _st_epoll_data->evtlist = (struct epoll_event *)malloc(_st_epoll_data->evtlist_size * sizeof(struct epoll_event)); - if (!_st_epoll_data->evtlist) { - err = errno; - rv = -1; - } - - cleanup_epoll: - if (rv < 0) { - if (_st_epoll_data->epfd >= 0) { - close(_st_epoll_data->epfd); - } - free(_st_epoll_data->fd_data); - free(_st_epoll_data->evtlist); - free(_st_epoll_data); - _st_epoll_data = NULL; - errno = err; - } - - return rv; -} - -ST_HIDDEN int _st_epoll_fd_data_expand(int maxfd) -{ - _epoll_fd_data_t *ptr; - int n = _st_epoll_data->fd_data_size; - - while (maxfd >= n) { - n <<= 1; - } - - ptr = (_epoll_fd_data_t *)realloc(_st_epoll_data->fd_data, n * sizeof(_epoll_fd_data_t)); - if (!ptr) { - return -1; - } - - memset(ptr + _st_epoll_data->fd_data_size, 0, (n - _st_epoll_data->fd_data_size) * sizeof(_epoll_fd_data_t)); - - _st_epoll_data->fd_data = ptr; - _st_epoll_data->fd_data_size = n; - - return 0; -} - -ST_HIDDEN void _st_epoll_evtlist_expand(void) -{ - struct epoll_event *ptr; - int n = _st_epoll_data->evtlist_size; - - while (_st_epoll_data->evtlist_cnt > n) { - n <<= 1; - } - - ptr = (struct epoll_event *)realloc(_st_epoll_data->evtlist, n * sizeof(struct epoll_event)); - if (ptr) { - _st_epoll_data->evtlist = ptr; - _st_epoll_data->evtlist_size = n; - } -} - -ST_HIDDEN void _st_epoll_pollset_del(struct pollfd *pds, int npds) -{ - struct epoll_event ev; - struct pollfd *pd; - struct pollfd *epd = pds + npds; - int old_events, events, op; - - /* - * It's more or less OK if deleting fails because a descriptor - * will either be closed or deleted in dispatch function after - * it fires. - */ - for (pd = pds; pd < epd; pd++) { - old_events = _ST_EPOLL_EVENTS(pd->fd); - - if (pd->events & POLLIN) { - _ST_EPOLL_READ_CNT(pd->fd)--; - } - if (pd->events & POLLOUT) { - _ST_EPOLL_WRITE_CNT(pd->fd)--; - } - if (pd->events & POLLPRI) { - _ST_EPOLL_EXCEP_CNT(pd->fd)--; - } - - events = _ST_EPOLL_EVENTS(pd->fd); - /* - * The _ST_EPOLL_REVENTS check below is needed so we can use - * this function inside dispatch(). Outside of dispatch() - * _ST_EPOLL_REVENTS is always zero for all descriptors. - */ - if (events != old_events && _ST_EPOLL_REVENTS(pd->fd) == 0) { - op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; - ev.events = events; - ev.data.fd = pd->fd; - if (epoll_ctl(_st_epoll_data->epfd, op, pd->fd, &ev) == 0 && op == EPOLL_CTL_DEL) { - _st_epoll_data->evtlist_cnt--; - } - } - } -} - -ST_HIDDEN int _st_epoll_pollset_add(struct pollfd *pds, int npds) -{ - struct epoll_event ev; - int i, fd; - int old_events, events, op; - - /* Do as many checks as possible up front */ - for (i = 0; i < npds; i++) { - fd = pds[i].fd; - if (fd < 0 || !pds[i].events || (pds[i].events & ~(POLLIN | POLLOUT | POLLPRI))) { - errno = EINVAL; - return -1; - } - if (fd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(fd) < 0) { - return -1; - } - } - - for (i = 0; i < npds; i++) { - fd = pds[i].fd; - old_events = _ST_EPOLL_EVENTS(fd); - - if (pds[i].events & POLLIN) { - _ST_EPOLL_READ_CNT(fd)++; - } - if (pds[i].events & POLLOUT) { - _ST_EPOLL_WRITE_CNT(fd)++; - } - if (pds[i].events & POLLPRI) { - _ST_EPOLL_EXCEP_CNT(fd)++; - } - - events = _ST_EPOLL_EVENTS(fd); - if (events != old_events) { - op = old_events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; - ev.events = events; - ev.data.fd = fd; - if (epoll_ctl(_st_epoll_data->epfd, op, fd, &ev) < 0 && (op != EPOLL_CTL_ADD || errno != EEXIST)) { - break; - } - if (op == EPOLL_CTL_ADD) { - _st_epoll_data->evtlist_cnt++; - if (_st_epoll_data->evtlist_cnt > _st_epoll_data->evtlist_size) { - _st_epoll_evtlist_expand(); - } - } - } - } - - if (i < npds) { - /* Error */ - int err = errno; - /* Unroll the state */ - _st_epoll_pollset_del(pds, i + 1); - errno = err; - return -1; - } - - return 0; -} - -ST_HIDDEN void _st_epoll_dispatch(void) -{ - st_utime_t min_timeout; - _st_clist_t *q; - _st_pollq_t *pq; - struct pollfd *pds, *epds; - struct epoll_event ev; - int timeout, nfd, i, osfd, notify; - int events, op; - short revents; - - if (_ST_SLEEPQ == NULL) { - timeout = -1; - } else { - min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : (_ST_SLEEPQ->due - _ST_LAST_CLOCK); - timeout = (int) (min_timeout / 1000); - } - - if (_st_epoll_data->pid != getpid()) { - // WINLIN: remove it for bug introduced. - // @see: https://github.com/ossrs/srs/issues/193 - exit(-1); - } - - /* Check for I/O operations */ - nfd = epoll_wait(_st_epoll_data->epfd, _st_epoll_data->evtlist, _st_epoll_data->evtlist_size, timeout); - - if (nfd > 0) { - for (i = 0; i < nfd; i++) { - osfd = _st_epoll_data->evtlist[i].data.fd; - _ST_EPOLL_REVENTS(osfd) = _st_epoll_data->evtlist[i].events; - if (_ST_EPOLL_REVENTS(osfd) & (EPOLLERR | EPOLLHUP)) { - /* Also set I/O bits on error */ - _ST_EPOLL_REVENTS(osfd) |= _ST_EPOLL_EVENTS(osfd); - } - } - - for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { - pq = _ST_POLLQUEUE_PTR(q); - notify = 0; - epds = pq->pds + pq->npds; - - for (pds = pq->pds; pds < epds; pds++) { - if (_ST_EPOLL_REVENTS(pds->fd) == 0) { - pds->revents = 0; - continue; - } - osfd = pds->fd; - events = pds->events; - revents = 0; - if ((events & POLLIN) && (_ST_EPOLL_REVENTS(osfd) & EPOLLIN)) { - revents |= POLLIN; - } - if ((events & POLLOUT) && (_ST_EPOLL_REVENTS(osfd) & EPOLLOUT)) { - revents |= POLLOUT; - } - if ((events & POLLPRI) && (_ST_EPOLL_REVENTS(osfd) & EPOLLPRI)) { - revents |= POLLPRI; - } - if (_ST_EPOLL_REVENTS(osfd) & EPOLLERR) { - revents |= POLLERR; - } - if (_ST_EPOLL_REVENTS(osfd) & EPOLLHUP) { - revents |= POLLHUP; - } - - pds->revents = revents; - if (revents) { - notify = 1; - } - } - if (notify) { - ST_REMOVE_LINK(&pq->links); - pq->on_ioq = 0; - /* - * Here we will only delete/modify descriptors that - * didn't fire (see comments in _st_epoll_pollset_del()). - */ - _st_epoll_pollset_del(pq->pds, pq->npds); - - if (pq->thread->flags & _ST_FL_ON_SLEEPQ) { - _ST_DEL_SLEEPQ(pq->thread); - } - pq->thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(pq->thread); - } - } - - for (i = 0; i < nfd; i++) { - /* Delete/modify descriptors that fired */ - osfd = _st_epoll_data->evtlist[i].data.fd; - _ST_EPOLL_REVENTS(osfd) = 0; - events = _ST_EPOLL_EVENTS(osfd); - op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; - ev.events = events; - ev.data.fd = osfd; - if (epoll_ctl(_st_epoll_data->epfd, op, osfd, &ev) == 0 && op == EPOLL_CTL_DEL) { - _st_epoll_data->evtlist_cnt--; - } - } - } -} - -ST_HIDDEN int _st_epoll_fd_new(int osfd) -{ - if (osfd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(osfd) < 0) { - return -1; - } - - return 0; -} - -ST_HIDDEN int _st_epoll_fd_close(int osfd) -{ - if (_ST_EPOLL_READ_CNT(osfd) || _ST_EPOLL_WRITE_CNT(osfd) || _ST_EPOLL_EXCEP_CNT(osfd)) { - errno = EBUSY; - return -1; - } - - return 0; -} - -ST_HIDDEN int _st_epoll_fd_getlimit(void) -{ - /* zero means no specific limit */ - return 0; -} - -/* - * Check if epoll functions are just stubs. - */ -ST_HIDDEN int _st_epoll_is_supported(void) -{ - struct epoll_event ev; - - ev.events = EPOLLIN; - ev.data.ptr = NULL; - /* Guaranteed to fail */ - epoll_ctl(-1, EPOLL_CTL_ADD, -1, &ev); - - return (errno != ENOSYS); -} - -static _st_eventsys_t _st_epoll_eventsys = { - "epoll", - ST_EVENTSYS_ALT, - _st_epoll_init, - _st_epoll_dispatch, - _st_epoll_pollset_add, - _st_epoll_pollset_del, - _st_epoll_fd_new, - _st_epoll_fd_close, - _st_epoll_fd_getlimit -}; - -/***************************************** - * Public functions - */ - -int st_set_eventsys(int eventsys) -{ - if (_st_eventsys) { - errno = EBUSY; - return -1; - } - - switch (eventsys) { - case ST_EVENTSYS_DEFAULT: - case ST_EVENTSYS_ALT: - default: - if (_st_epoll_is_supported()) { - _st_eventsys = &_st_epoll_eventsys; - break; - } - errno = EINVAL; - return -1; - } - - return 0; -} - -int st_get_eventsys(void) -{ - return _st_eventsys ? _st_eventsys->val : -1; -} - -const char *st_get_eventsys_name(void) -{ - return _st_eventsys ? _st_eventsys->name : ""; -} - diff --git a/trunk/research/st/io.c b/trunk/research/st/io.c deleted file mode 100644 index bc77dc8e10..0000000000 --- a/trunk/research/st/io.c +++ /dev/null @@ -1,792 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -#if EAGAIN != EWOULDBLOCK - #define _IO_NOT_READY_ERROR ((errno == EAGAIN) || (errno == EWOULDBLOCK)) -#else - #define _IO_NOT_READY_ERROR (errno == EAGAIN) -#endif - -#define _LOCAL_MAXIOV 16 - -/* File descriptor object free list */ -static _st_netfd_t *_st_netfd_freelist = NULL; -/* Maximum number of file descriptors that the process can open */ -static int _st_osfd_limit = -1; - -static void _st_netfd_free_aux_data(_st_netfd_t *fd); - -int _st_io_init(void) -{ - struct sigaction sigact; - struct rlimit rlim; - int fdlim; - - /* Ignore SIGPIPE */ - sigact.sa_handler = SIG_IGN; - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - if (sigaction(SIGPIPE, &sigact, NULL) < 0) { - return -1; - } - - /* Set maximum number of open file descriptors */ - if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { - return -1; - } - - fdlim = (*_st_eventsys->fd_getlimit)(); - if (fdlim > 0 && rlim.rlim_max > (rlim_t) fdlim) { - rlim.rlim_max = fdlim; - } - rlim.rlim_cur = rlim.rlim_max; - if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { - return -1; - } - _st_osfd_limit = (int) rlim.rlim_max; - - return 0; -} - -int st_getfdlimit(void) -{ - return _st_osfd_limit; -} - -void st_netfd_free(_st_netfd_t *fd) -{ - if (!fd->inuse) { - return; - } - - fd->inuse = 0; - if (fd->aux_data) { - _st_netfd_free_aux_data(fd); - } - if (fd->private_data && fd->destructor) { - (*(fd->destructor))(fd->private_data); - } - fd->private_data = NULL; - fd->destructor = NULL; - fd->next = _st_netfd_freelist; - _st_netfd_freelist = fd; -} - -static _st_netfd_t *_st_netfd_new(int osfd, int nonblock, int is_socket) -{ - _st_netfd_t *fd; - int flags = 1; - - if ((*_st_eventsys->fd_new)(osfd) < 0) { - return NULL; - } - - if (_st_netfd_freelist) { - fd = _st_netfd_freelist; - _st_netfd_freelist = _st_netfd_freelist->next; - } else { - fd = calloc(1, sizeof(_st_netfd_t)); - if (!fd) { - return NULL; - } - } - - fd->osfd = osfd; - fd->inuse = 1; - fd->next = NULL; - - if (nonblock) { - /* Use just one system call */ - if (is_socket && ioctl(osfd, FIONBIO, &flags) != -1) { - return fd; - } - /* Do it the Posix way */ - if ((flags = fcntl(osfd, F_GETFL, 0)) < 0 || fcntl(osfd, F_SETFL, flags | O_NONBLOCK) < 0) { - st_netfd_free(fd); - return NULL; - } - } - - return fd; -} - -_st_netfd_t *st_netfd_open(int osfd) -{ - return _st_netfd_new(osfd, 1, 0); -} - -_st_netfd_t *st_netfd_open_socket(int osfd) -{ - return _st_netfd_new(osfd, 1, 1); -} - -int st_netfd_close(_st_netfd_t *fd) -{ - if ((*_st_eventsys->fd_close)(fd->osfd) < 0) { - return -1; - } - - st_netfd_free(fd); - return close(fd->osfd); -} - -int st_netfd_fileno(_st_netfd_t *fd) -{ - return (fd->osfd); -} - -void st_netfd_setspecific(_st_netfd_t *fd, void *value, _st_destructor_t destructor) -{ - if (value != fd->private_data) { - /* Free up previously set non-NULL data value */ - if (fd->private_data && fd->destructor) { - (*(fd->destructor))(fd->private_data); - } - } - fd->private_data = value; - fd->destructor = destructor; -} - -void *st_netfd_getspecific(_st_netfd_t *fd) -{ - return (fd->private_data); -} - -/* - * Wait for I/O on a single descriptor. - */ -int st_netfd_poll(_st_netfd_t *fd, int how, st_utime_t timeout) -{ - struct pollfd pd; - int n; - - pd.fd = fd->osfd; - pd.events = (short) how; - pd.revents = 0; - - if ((n = st_poll(&pd, 1, timeout)) < 0) { - return -1; - } - if (n == 0) { - /* Timed out */ - errno = ETIME; - return -1; - } - if (pd.revents & POLLNVAL) { - errno = EBADF; - return -1; - } - - return 0; -} - -#ifdef MD_ALWAYS_UNSERIALIZED_ACCEPT -/* No-op */ -int st_netfd_serialize_accept(_st_netfd_t *fd) -{ - fd->aux_data = NULL; - return 0; -} - -/* No-op */ -static void _st_netfd_free_aux_data(_st_netfd_t *fd) -{ - fd->aux_data = NULL; -} - -_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout) -{ - int osfd, err; - _st_netfd_t *newfd; - - while ((osfd = accept(fd->osfd, addr, (socklen_t *)addrlen)) < 0) { - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - return NULL; - } - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) { - return NULL; - } - } - - /* On some platforms the new socket created by accept() inherits */ - /* the nonblocking attribute of the listening socket */ -#if defined (MD_ACCEPT_NB_INHERITED) - newfd = _st_netfd_new(osfd, 0, 1); -#elif defined (MD_ACCEPT_NB_NOT_INHERITED) - newfd = _st_netfd_new(osfd, 1, 1); -#else - #error Unknown OS -#endif - - if (!newfd) { - err = errno; - close(osfd); - errno = err; - } - - return newfd; -} - -#else /* MD_ALWAYS_UNSERIALIZED_ACCEPT */ -/* - * On some platforms accept() calls from different processes - * on the same listen socket must be serialized. - * The following code serializes accept()'s without process blocking. - * A pipe is used as an inter-process semaphore. - */ -int st_netfd_serialize_accept(_st_netfd_t *fd) -{ - _st_netfd_t **p; - int osfd[2], err; - - if (fd->aux_data) { - errno = EINVAL; - return -1; - } - if ((p = (_st_netfd_t **)calloc(2, sizeof(_st_netfd_t *))) == NULL) { - return -1; - } - if (pipe(osfd) < 0) { - free(p); - return -1; - } - if ((p[0] = st_netfd_open(osfd[0])) != NULL && (p[1] = st_netfd_open(osfd[1])) != NULL && write(osfd[1], " ", 1) == 1) { - fd->aux_data = p; - return 0; - } - /* Error */ - err = errno; - if (p[0]) { - st_netfd_free(p[0]); - } - if (p[1]) { - st_netfd_free(p[1]); - } - close(osfd[0]); - close(osfd[1]); - free(p); - errno = err; - - return -1; -} - -static void _st_netfd_free_aux_data(_st_netfd_t *fd) -{ - _st_netfd_t **p = (_st_netfd_t **) fd->aux_data; - - st_netfd_close(p[0]); - st_netfd_close(p[1]); - free(p); - fd->aux_data = NULL; -} - -_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout) -{ - int osfd, err; - _st_netfd_t *newfd; - _st_netfd_t **p = (_st_netfd_t **) fd->aux_data; - ssize_t n; - char c; - - for ( ; ; ) { - if (p == NULL) { - osfd = accept(fd->osfd, addr, (socklen_t *)addrlen); - } else { - /* Get the lock */ - n = st_read(p[0], &c, 1, timeout); - if (n < 0) { - return NULL; - } - ST_ASSERT(n == 1); - /* Got the lock */ - osfd = accept(fd->osfd, addr, (socklen_t *)addrlen); - /* Unlock */ - err = errno; - n = st_write(p[1], &c, 1, timeout); - ST_ASSERT(n == 1); - errno = err; - } - if (osfd >= 0) { - break; - } - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - return NULL; - } - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) { - return NULL; - } - } - - /* On some platforms the new socket created by accept() inherits */ - /* the nonblocking attribute of the listening socket */ -#if defined (MD_ACCEPT_NB_INHERITED) - newfd = _st_netfd_new(osfd, 0, 1); -#elif defined (MD_ACCEPT_NB_NOT_INHERITED) - newfd = _st_netfd_new(osfd, 1, 1); -#else - #error Unknown OS -#endif - - if (!newfd) { - err = errno; - close(osfd); - errno = err; - } - - return newfd; -} -#endif /* MD_ALWAYS_UNSERIALIZED_ACCEPT */ - -int st_connect(_st_netfd_t *fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout) -{ - int n, err = 0; - - while (connect(fd->osfd, addr, addrlen) < 0) { - if (errno != EINTR) { - /* - * On some platforms, if connect() is interrupted (errno == EINTR) - * after the kernel binds the socket, a subsequent connect() - * attempt will fail with errno == EADDRINUSE. Ignore EADDRINUSE - * iff connect() was previously interrupted. See Rich Stevens' - * "UNIX Network Programming," Vol. 1, 2nd edition, p. 413 - * ("Interrupted connect"). - */ - if (errno != EINPROGRESS && (errno != EADDRINUSE || err == 0)) { - return -1; - } - /* Wait until the socket becomes writable */ - if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { - return -1; - } - /* Try to find out whether the connection setup succeeded or failed */ - n = sizeof(int); - if (getsockopt(fd->osfd, SOL_SOCKET, SO_ERROR, (char *)&err, (socklen_t *)&n) < 0) { - return -1; - } - if (err) { - errno = err; - return -1; - } - break; - } - err = 1; - } - - return 0; -} - -ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout) -{ - ssize_t n; - - while ((n = read(fd->osfd, buf, nbyte)) < 0) { - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - return -1; - } - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) { - return -1; - } - } - - return n; -} - -int st_read_resid(_st_netfd_t *fd, void *buf, size_t *resid, st_utime_t timeout) -{ - struct iovec iov, *riov; - int riov_size, rv; - - iov.iov_base = buf; - iov.iov_len = *resid; - riov = &iov; - riov_size = 1; - rv = st_readv_resid(fd, &riov, &riov_size, timeout); - *resid = iov.iov_len; - return rv; -} - -ssize_t st_readv(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout) -{ - ssize_t n; - - while ((n = readv(fd->osfd, iov, iov_size)) < 0) { - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - return -1; - } - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) { - return -1; - } - } - - return n; -} - -int st_readv_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout) -{ - ssize_t n; - - while (*iov_size > 0) { - if (*iov_size == 1) { - n = read(fd->osfd, (*iov)->iov_base, (*iov)->iov_len); - } else { - n = readv(fd->osfd, *iov, *iov_size); - } - if (n < 0) { - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - return -1; - } - } else if (n == 0) { - break; - } else { - while ((size_t) n >= (*iov)->iov_len) { - n -= (*iov)->iov_len; - (*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len; - (*iov)->iov_len = 0; - (*iov)++; - (*iov_size)--; - if (n == 0) { - break; - } - } - if (*iov_size == 0) { - break; - } - (*iov)->iov_base = (char *) (*iov)->iov_base + n; - (*iov)->iov_len -= n; - } - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) { - return -1; - } - } - - return 0; -} - -ssize_t st_read_fully(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout) -{ - size_t resid = nbyte; - return st_read_resid(fd, buf, &resid, timeout) == 0 ? (ssize_t) (nbyte - resid) : -1; -} - -int st_write_resid(_st_netfd_t *fd, const void *buf, size_t *resid, st_utime_t timeout) -{ - struct iovec iov, *riov; - int riov_size, rv; - - iov.iov_base = (void *) buf; /* we promise not to modify buf */ - iov.iov_len = *resid; - riov = &iov; - riov_size = 1; - rv = st_writev_resid(fd, &riov, &riov_size, timeout); - *resid = iov.iov_len; - return rv; -} - -ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout) -{ - size_t resid = nbyte; - return st_write_resid(fd, buf, &resid, timeout) == 0 ? (ssize_t) (nbyte - resid) : -1; -} - -ssize_t st_writev(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout) -{ - ssize_t n, rv; - size_t nleft, nbyte; - int index, iov_cnt; - struct iovec *tmp_iov; - struct iovec local_iov[_LOCAL_MAXIOV]; - - /* Calculate the total number of bytes to be sent */ - nbyte = 0; - for (index = 0; index < iov_size; index++) { - nbyte += iov[index].iov_len; - } - - rv = (ssize_t)nbyte; - nleft = nbyte; - tmp_iov = (struct iovec *) iov; /* we promise not to modify iov */ - iov_cnt = iov_size; - - while (nleft > 0) { - if (iov_cnt == 1) { - if (st_write(fd, tmp_iov[0].iov_base, nleft, timeout) != (ssize_t) nleft) { - rv = -1; - } - break; - } - if ((n = writev(fd->osfd, tmp_iov, iov_cnt)) < 0) { - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - rv = -1; - break; - } - } else { - if ((size_t) n == nleft) { - break; - } - nleft -= n; - /* Find the next unwritten vector */ - n = (ssize_t)(nbyte - nleft); - for (index = 0; (size_t) n >= iov[index].iov_len; index++) { - n -= iov[index].iov_len; - } - - if (tmp_iov == iov) { - /* Must copy iov's around */ - if (iov_size - index <= _LOCAL_MAXIOV) { - tmp_iov = local_iov; - } else { - tmp_iov = calloc(1, (iov_size - index) * sizeof(struct iovec)); - if (tmp_iov == NULL) { - return -1; - } - } - } - - /* Fill in the first partial read */ - tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[n]); - tmp_iov[0].iov_len = iov[index].iov_len - n; - index++; - /* Copy the remaining vectors */ - for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) { - tmp_iov[iov_cnt].iov_base = iov[index].iov_base; - tmp_iov[iov_cnt].iov_len = iov[index].iov_len; - } - } - /* Wait until the socket becomes writable */ - if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { - rv = -1; - break; - } - } - - if (tmp_iov != iov && tmp_iov != local_iov) { - free(tmp_iov); - } - - return rv; -} - -int st_writev_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout) -{ - ssize_t n; - - while (*iov_size > 0) { - if (*iov_size == 1) { - n = write(fd->osfd, (*iov)->iov_base, (*iov)->iov_len); - } else { - n = writev(fd->osfd, *iov, *iov_size); - } - if (n < 0) { - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - return -1; - } - } else { - while ((size_t) n >= (*iov)->iov_len) { - n -= (*iov)->iov_len; - (*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len; - (*iov)->iov_len = 0; - (*iov)++; - (*iov_size)--; - if (n == 0) { - break; - } - } - if (*iov_size == 0) { - break; - } - (*iov)->iov_base = (char *) (*iov)->iov_base + n; - (*iov)->iov_len -= n; - } - /* Wait until the socket becomes writable */ - if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { - return -1; - } - } - - return 0; -} - -/* - * Simple I/O functions for UDP. - */ -int st_recvfrom(_st_netfd_t *fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout) -{ - int n; - - while ((n = recvfrom(fd->osfd, buf, len, 0, from, (socklen_t *)fromlen)) < 0) { - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - return -1; - } - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) { - return -1; - } - } - - return n; -} - -int st_sendto(_st_netfd_t *fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout) -{ - int n; - - while ((n = sendto(fd->osfd, msg, len, 0, to, tolen)) < 0) { - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - return -1; - } - /* Wait until the socket becomes writable */ - if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { - return -1; - } - } - - return n; -} - -int st_recvmsg(_st_netfd_t *fd, struct msghdr *msg, int flags, st_utime_t timeout) -{ - int n; - - while ((n = recvmsg(fd->osfd, msg, flags)) < 0) { - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - return -1; - } - /* Wait until the socket becomes readable */ - if (st_netfd_poll(fd, POLLIN, timeout) < 0) { - return -1; - } - } - - return n; -} - -int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags, st_utime_t timeout) -{ - int n; - - while ((n = sendmsg(fd->osfd, msg, flags)) < 0) { - if (errno == EINTR) { - continue; - } - if (!_IO_NOT_READY_ERROR) { - return -1; - } - /* Wait until the socket becomes writable */ - if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { - return -1; - } - } - - return n; -} - -/* - * To open FIFOs or other special files. - */ -_st_netfd_t *st_open(const char *path, int oflags, mode_t mode) -{ - int osfd, err; - _st_netfd_t *newfd; - - while ((osfd = open(path, oflags | O_NONBLOCK, mode)) < 0) { - if (errno != EINTR) { - return NULL; - } - } - - newfd = _st_netfd_new(osfd, 0, 0); - if (!newfd) { - err = errno; - close(osfd); - errno = err; - } - - return newfd; -} - diff --git a/trunk/research/st/key.c b/trunk/research/st/key.c deleted file mode 100644 index 49d778a187..0000000000 --- a/trunk/research/st/key.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#include -#include -#include "common.h" - -/* - * Destructor table for per-thread private data - */ -static _st_destructor_t _st_destructors[ST_KEYS_MAX]; -static int key_max = 0; - -/* - * Return a key to be used for thread specific data - */ -int st_key_create(int *keyp, _st_destructor_t destructor) -{ - if (key_max >= ST_KEYS_MAX) { - errno = EAGAIN; - return -1; - } - - *keyp = key_max++; - _st_destructors[*keyp] = destructor; - - return 0; -} - -int st_key_getlimit(void) -{ - return ST_KEYS_MAX; -} - -int st_thread_setspecific(int key, void *value) -{ - _st_thread_t *me = _ST_CURRENT_THREAD(); - - if (key < 0 || key >= key_max) { - errno = EINVAL; - return -1; - } - - if (value != me->private_data[key]) { - /* free up previously set non-NULL data value */ - if (me->private_data[key] && _st_destructors[key]) { - (*_st_destructors[key])(me->private_data[key]); - } - me->private_data[key] = value; - } - - return 0; -} - -void *st_thread_getspecific(int key) -{ - if (key < 0 || key >= key_max) { - return NULL; - } - - return ((_ST_CURRENT_THREAD())->private_data[key]); -} - -/* - * Free up all per-thread private data - */ -void _st_thread_cleanup(_st_thread_t *thread) -{ - int key; - - for (key = 0; key < key_max; key++) { - if (thread->private_data[key] && _st_destructors[key]) { - (*_st_destructors[key])(thread->private_data[key]); - thread->private_data[key] = NULL; - } - } -} - diff --git a/trunk/research/st/md.S b/trunk/research/st/md.S deleted file mode 100755 index 883da302b2..0000000000 --- a/trunk/research/st/md.S +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. - * All Rights Reserved. - */ - -/****************************************************************/ - -#if defined(__i386__) - -/* - * Internal __jmp_buf layout - */ -#define JB_BX 0 -#define JB_SI 1 -#define JB_DI 2 -#define JB_BP 3 -#define JB_SP 4 -#define JB_PC 5 - - .file "md.S" - .text - - /* _st_md_cxt_save(__jmp_buf env) */ -.globl _st_md_cxt_save - .type _st_md_cxt_save, @function - .align 16 -_st_md_cxt_save: - movl 4(%esp), %eax - - /* - * Save registers. - */ - movl %ebx, (JB_BX*4)(%eax) - movl %esi, (JB_SI*4)(%eax) - movl %edi, (JB_DI*4)(%eax) - /* Save SP */ - leal 4(%esp), %ecx - movl %ecx, (JB_SP*4)(%eax) - /* Save PC we are returning to */ - movl 0(%esp), %ecx - movl %ecx, (JB_PC*4)(%eax) - /* Save caller frame pointer */ - movl %ebp, (JB_BP*4)(%eax) - xorl %eax, %eax - ret - .size _st_md_cxt_save, .-_st_md_cxt_save - - -/****************************************************************/ - - /* _st_md_cxt_restore(__jmp_buf env, int val) */ -.globl _st_md_cxt_restore - .type _st_md_cxt_restore, @function - .align 16 -_st_md_cxt_restore: - /* First argument is jmp_buf */ - movl 4(%esp), %ecx - /* Second argument is return value */ - movl 8(%esp), %eax - /* Set the return address */ - movl (JB_PC*4)(%ecx), %edx - /* - * Restore registers. - */ - movl (JB_BX*4)(%ecx), %ebx - movl (JB_SI*4)(%ecx), %esi - movl (JB_DI*4)(%ecx), %edi - movl (JB_BP*4)(%ecx), %ebp - movl (JB_SP*4)(%ecx), %esp - testl %eax, %eax - jnz 1f - incl %eax - /* Jump to saved PC */ -1: jmp *%edx - .size _st_md_cxt_restore, .-_st_md_cxt_restore - -/****************************************************************/ - -#elif defined(__amd64__) || defined(__x86_64__) - -/* - * Internal __jmp_buf layout - */ -#define JB_RBX 0 -#define JB_RBP 1 -#define JB_R12 2 -#define JB_R13 3 -#define JB_R14 4 -#define JB_R15 5 -#define JB_RSP 6 -#define JB_PC 7 - - .file "md.S" - .text - - /* _st_md_cxt_save(__jmp_buf env) */ -.globl _st_md_cxt_save - .type _st_md_cxt_save, @function - .align 16 -_st_md_cxt_save: - /* - * Save registers. - */ - movq %rbx, (JB_RBX*8)(%rdi) - movq %rbp, (JB_RBP*8)(%rdi) - movq %r12, (JB_R12*8)(%rdi) - movq %r13, (JB_R13*8)(%rdi) - movq %r14, (JB_R14*8)(%rdi) - movq %r15, (JB_R15*8)(%rdi) - /* Save SP */ - leaq 8(%rsp), %rdx - movq %rdx, (JB_RSP*8)(%rdi) - /* Save PC we are returning to */ - movq (%rsp), %rax - movq %rax, (JB_PC*8)(%rdi) - xorq %rax, %rax - ret - .size _st_md_cxt_save, .-_st_md_cxt_save - - -/****************************************************************/ - - /* _st_md_cxt_restore(__jmp_buf env, int val) */ -.globl _st_md_cxt_restore - .type _st_md_cxt_restore, @function - .align 16 -_st_md_cxt_restore: - /* - * Restore registers. - */ - movq (JB_RBX*8)(%rdi), %rbx - movq (JB_RBP*8)(%rdi), %rbp - movq (JB_R12*8)(%rdi), %r12 - movq (JB_R13*8)(%rdi), %r13 - movq (JB_R14*8)(%rdi), %r14 - movq (JB_R15*8)(%rdi), %r15 - /* Set return value */ - test %esi, %esi - mov $01, %eax - cmove %eax, %esi - mov %esi, %eax - movq (JB_PC*8)(%rdi), %rdx - movq (JB_RSP*8)(%rdi), %rsp - /* Jump to saved PC */ - jmpq *%rdx - .size _st_md_cxt_restore, .-_st_md_cxt_restore - -/****************************************************************/ - -#endif - diff --git a/trunk/research/st/md.h b/trunk/research/st/md.h deleted file mode 100644 index bf82f4d55c..0000000000 --- a/trunk/research/st/md.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#ifndef __ST_MD_H__ -#define __ST_MD_H__ - -#if defined(ETIMEDOUT) && !defined(ETIME) - #define ETIME ETIMEDOUT -#endif - -#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON) - #define MAP_ANON MAP_ANONYMOUS -#endif - -#ifndef MAP_FAILED - #define MAP_FAILED -1 -#endif - -/***************************************** - * Platform specifics - */ -#if defined (LINUX) - /* linux ok, defined bellow */ -#elif defined (AIX) - #error "AIX not supported" -#elif defined (CYGWIN) - #error "CYGWIN not supported" -#elif defined (DARWIN) - #error "DARWIN not supported" -#elif defined (FREEBSD) - #error "FREEBSD not supported" -#elif defined (HPUX) - #error "HPUX not supported" -#elif defined (IRIX) - #error "IRIX not supported" -#elif defined (NETBSD) - #error "NETBSD not supported" -#elif defined (OPENBSD) - #error "OPENBSD not supported" -#elif defined (OSF1) - #error "OSF1 not supported" -#elif defined (SOLARIS) - #error "SOLARIS not supported" -#else - #error "Unknown OS" -#endif /* OS */ - -/* linux only, defined bellow */ -/* - * These are properties of the linux kernel and are the same on every - * flavor and architecture. - */ -#define MD_USE_BSD_ANON_MMAP -#define MD_ACCEPT_NB_NOT_INHERITED -#define MD_ALWAYS_UNSERIALIZED_ACCEPT -/* - * Modern GNU/Linux is Posix.1g compliant. - */ -#define MD_HAVE_SOCKLEN_T - -/* - * All architectures and flavors of linux have the gettimeofday - * function but if you know of a faster way, use it. - */ -#define MD_GET_UTIME() \ - struct timeval tv; \ - (void) gettimeofday(&tv, NULL); \ - return (tv.tv_sec * 1000000LL + tv.tv_usec) - -#if defined(__mips__) - #define MD_STACK_GROWS_DOWN -#else /* Not or mips */ - /* - * On linux, there are a few styles of jmpbuf format. These vary based - * on architecture/glibc combination. - * - * Most of the glibc based toggles were lifted from: - * mozilla/nsprpub/pr/include/md/_linux.h - */ - /* - * Starting with glibc 2.4, JB_SP definitions are not public anymore. - * They, however, can still be found in glibc source tree in - * architecture-specific "jmpbuf-offsets.h" files. - * Most importantly, the content of jmp_buf is mangled by setjmp to make - * it completely opaque (the mangling can be disabled by setting the - * LD_POINTER_GUARD environment variable before application execution). - * Therefore we will use built-in _st_md_cxt_save/_st_md_cxt_restore - * functions as a setjmp/longjmp replacement wherever they are available - * unless USE_LIBC_SETJMP is defined. - */ - #if defined(__i386__) - #define MD_STACK_GROWS_DOWN - #define MD_USE_BUILTIN_SETJMP - - #if defined(__GLIBC__) && __GLIBC__ >= 2 - #ifndef JB_SP - #define JB_SP 4 - #endif - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP] - #else - /* not an error but certainly cause for caution */ - #error "Untested use of old glibc on i386" - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp - #endif - #elif defined(__amd64__) || defined(__x86_64__) - #define MD_STACK_GROWS_DOWN - #define MD_USE_BUILTIN_SETJMP - - #ifndef JB_RSP - #define JB_RSP 6 - #endif - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_RSP] - #elif defined(__arm__) - #define MD_STACK_GROWS_DOWN - - #if defined(__GLIBC__) && __GLIBC__ >= 2 - #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[8] - #else - #error "ARM/Linux pre-glibc2 not supported yet" - #endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ - #else - #error "Unknown CPU architecture" - #endif /* Cases with common MD_INIT_CONTEXT and different SP locations */ -#endif /* Cases with different MD_INIT_CONTEXT */ - -#if defined(MD_USE_BUILTIN_SETJMP) && !defined(USE_LIBC_SETJMP) - /* i386/x86_64 */ - #define MD_SETJMP(env) _st_md_cxt_save(env) - #define MD_LONGJMP(env, val) _st_md_cxt_restore(env, val) - - extern int _st_md_cxt_save(jmp_buf env); - extern void _st_md_cxt_restore(jmp_buf env, int val); -#else - /* arm/mips */ - #define MD_SETJMP(env) setjmp(env) - #define MD_LONGJMP(env, val) longjmp(env, val) -#endif - -/***************************************** - * Other defines - */ -#ifndef MD_STACK_PAD_SIZE - #define MD_STACK_PAD_SIZE 128 -#endif - -#if !defined(MD_HAVE_SOCKLEN_T) && !defined(socklen_t) - #define socklen_t int -#endif - -#ifndef MD_CAP_STACK - #define MD_CAP_STACK(var_addr) -#endif - -#endif /* !__ST_MD_H__ */ - diff --git a/trunk/research/st/public.h b/trunk/research/st/public.h deleted file mode 100644 index 3275191bc7..0000000000 --- a/trunk/research/st/public.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -#ifndef __ST_THREAD_H__ -#define __ST_THREAD_H__ - -#include -#include -#include -#include -#include -#include -#include - -#define ST_VERSION "1.9" -#define ST_VERSION_MAJOR 1 -#define ST_VERSION_MINOR 9 - -/* Undefine this to remove the context switch callback feature. */ -#define ST_SWITCH_CB - -#ifndef ETIME - #define ETIME ETIMEDOUT -#endif - -#ifndef ST_UTIME_NO_TIMEOUT - #define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL) -#endif - -#ifndef ST_UTIME_NO_WAIT - #define ST_UTIME_NO_WAIT 0 -#endif - -#define ST_EVENTSYS_DEFAULT 0 -#define ST_EVENTSYS_SELECT 1 -#define ST_EVENTSYS_POLL 2 -#define ST_EVENTSYS_ALT 3 - -#ifdef __cplusplus -extern "C" { -#endif - typedef unsigned long long st_utime_t; - typedef struct _st_thread * st_thread_t; - typedef struct _st_cond * st_cond_t; - typedef struct _st_mutex * st_mutex_t; - typedef struct _st_netfd * st_netfd_t; - #ifdef ST_SWITCH_CB - typedef void (*st_switch_cb_t)(void); - #endif - - extern int st_init(void); - extern int st_getfdlimit(void); - - extern int st_set_eventsys(int eventsys); - extern int st_get_eventsys(void); - extern const char *st_get_eventsys_name(void); - - #ifdef ST_SWITCH_CB - extern st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb); - extern st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb); - #endif - - extern st_thread_t st_thread_self(void); - extern void st_thread_exit(void *retval); - extern int st_thread_join(st_thread_t trd, void **retvalp); - extern void st_thread_interrupt(st_thread_t trd); - extern st_thread_t st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stack_size); - extern int st_randomize_stacks(int on); - extern int st_set_utime_function(st_utime_t (*func)(void)); - - extern st_utime_t st_utime(void); - extern st_utime_t st_utime_last_clock(void); - extern int st_timecache_set(int on); - extern time_t st_time(void); - extern int st_usleep(st_utime_t usecs); - extern int st_sleep(int secs); - extern st_cond_t st_cond_new(void); - extern int st_cond_destroy(st_cond_t cvar); - extern int st_cond_timedwait(st_cond_t cvar, st_utime_t timeout); - extern int st_cond_wait(st_cond_t cvar); - extern int st_cond_signal(st_cond_t cvar); - extern int st_cond_broadcast(st_cond_t cvar); - extern st_mutex_t st_mutex_new(void); - extern int st_mutex_destroy(st_mutex_t lock); - extern int st_mutex_lock(st_mutex_t lock); - extern int st_mutex_unlock(st_mutex_t lock); - extern int st_mutex_trylock(st_mutex_t lock); - - extern int st_key_create(int *keyp, void (*destructor)(void *)); - extern int st_key_getlimit(void); - extern int st_thread_setspecific(int key, void *value); - extern void *st_thread_getspecific(int key); - - extern st_netfd_t st_netfd_open(int osfd); - extern st_netfd_t st_netfd_open_socket(int osfd); - extern void st_netfd_free(st_netfd_t fd); - extern int st_netfd_close(st_netfd_t fd); - extern int st_netfd_fileno(st_netfd_t fd); - extern void st_netfd_setspecific(st_netfd_t fd, void *value, void (*destructor)(void *)); - extern void *st_netfd_getspecific(st_netfd_t fd); - extern int st_netfd_serialize_accept(st_netfd_t fd); - extern int st_netfd_poll(st_netfd_t fd, int how, st_utime_t timeout); - - extern int st_poll(struct pollfd *pds, int npds, st_utime_t timeout); - extern st_netfd_t st_accept(st_netfd_t fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout); - extern int st_connect(st_netfd_t fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout); - extern ssize_t st_read(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout); - extern ssize_t st_read_fully(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout); - extern int st_read_resid(st_netfd_t fd, void *buf, size_t *resid, st_utime_t timeout); - extern ssize_t st_readv(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout); - extern int st_readv_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout); - extern ssize_t st_write(st_netfd_t fd, const void *buf, size_t nbyte, st_utime_t timeout); - extern int st_write_resid(st_netfd_t fd, const void *buf, size_t *resid, st_utime_t timeout); - extern ssize_t st_writev(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout); - extern int st_writev_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout); - extern int st_recvfrom(st_netfd_t fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout); - extern int st_sendto(st_netfd_t fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout); - extern int st_recvmsg(st_netfd_t fd, struct msghdr *msg, int flags, st_utime_t timeout); - extern int st_sendmsg(st_netfd_t fd, const struct msghdr *msg, int flags, st_utime_t timeout); - extern st_netfd_t st_open(const char *path, int oflags, mode_t mode); - - #ifdef DEBUG - extern void _st_show_thread_stack(st_thread_t thread, const char *messg); - extern void _st_iterate_threads(void); - #endif -#ifdef __cplusplus -} -#endif - -#endif /* !__ST_THREAD_H__ */ - diff --git a/trunk/research/st/sched.c b/trunk/research/st/sched.c deleted file mode 100755 index 66095cfd1b..0000000000 --- a/trunk/research/st/sched.c +++ /dev/null @@ -1,680 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#include -#include -#include -#include -#include -#include -#include "common.h" - -/* Global data */ -_st_vp_t _st_this_vp; /* This VP */ -_st_thread_t *_st_this_thread; /* Current thread */ -int _st_active_count = 0; /* Active thread count */ - -time_t _st_curr_time = 0; /* Current time as returned by time(2) */ -st_utime_t _st_last_tset; /* Last time it was fetched */ - -int st_poll(struct pollfd *pds, int npds, st_utime_t timeout) -{ - struct pollfd *pd; - struct pollfd *epd = pds + npds; - _st_pollq_t pq; - _st_thread_t *me = _ST_CURRENT_THREAD(); - int n; - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - if ((*_st_eventsys->pollset_add)(pds, npds) < 0) { - return -1; - } - - pq.pds = pds; - pq.npds = npds; - pq.thread = me; - pq.on_ioq = 1; - _ST_ADD_IOQ(pq); - if (timeout != ST_UTIME_NO_TIMEOUT) { - _ST_ADD_SLEEPQ(me, timeout); - } - me->state = _ST_ST_IO_WAIT; - - _ST_SWITCH_CONTEXT(me); - - n = 0; - if (pq.on_ioq) { - /* If we timed out, the pollq might still be on the ioq. Remove it */ - _ST_DEL_IOQ(pq); - (*_st_eventsys->pollset_del)(pds, npds); - } else { - /* Count the number of ready descriptors */ - for (pd = pds; pd < epd; pd++) { - if (pd->revents) { - n++; - } - } - } - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - return n; -} - -void _st_vp_schedule(void) -{ - _st_thread_t *trd; - - if (_ST_RUNQ.next != &_ST_RUNQ) { - /* Pull thread off of the run queue */ - trd = _ST_THREAD_PTR(_ST_RUNQ.next); - _ST_DEL_RUNQ(trd); - } else { - /* If there are no threads to run, switch to the idle thread */ - trd = _st_this_vp.idle_thread; - } - ST_ASSERT(trd->state == _ST_ST_RUNNABLE); - - /* Resume the thread */ - trd->state = _ST_ST_RUNNING; - _ST_RESTORE_CONTEXT(trd); -} - -/* - * Initialize this Virtual Processor - */ -int st_init(void) -{ - _st_thread_t *trd; - - if (_st_active_count) { - /* Already initialized */ - return 0; - } - - /* We can ignore return value here */ - st_set_eventsys(ST_EVENTSYS_DEFAULT); - - if (_st_io_init() < 0) { - return -1; - } - - memset(&_st_this_vp, 0, sizeof(_st_vp_t)); - - ST_INIT_CLIST(&_ST_RUNQ); - ST_INIT_CLIST(&_ST_IOQ); - ST_INIT_CLIST(&_ST_ZOMBIEQ); -#ifdef DEBUG - ST_INIT_CLIST(&_ST_THREADQ); -#endif - - if ((*_st_eventsys->init)() < 0) { - return -1; - } - - _st_this_vp.pagesize = getpagesize(); - _st_this_vp.last_clock = st_utime(); - - /* - * Create idle thread - */ - _st_this_vp.idle_thread = st_thread_create(_st_idle_thread_start, NULL, 0, 0); - if (!_st_this_vp.idle_thread) { - return -1; - } - _st_this_vp.idle_thread->flags = _ST_FL_IDLE_THREAD; - _st_active_count--; - _ST_DEL_RUNQ(_st_this_vp.idle_thread); - - /* - * Initialize primordial thread - */ - trd = (_st_thread_t *) calloc(1, sizeof(_st_thread_t) + - (ST_KEYS_MAX * sizeof(void *))); - if (!trd) { - return -1; - } - trd->private_data = (void **) (trd + 1); - trd->state = _ST_ST_RUNNING; - trd->flags = _ST_FL_PRIMORDIAL; - _ST_SET_CURRENT_THREAD(trd); - _st_active_count++; -#ifdef DEBUG - _ST_ADD_THREADQ(trd); -#endif - - return 0; -} - -#ifdef ST_SWITCH_CB -st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb) -{ - st_switch_cb_t ocb = _st_this_vp.switch_in_cb; - _st_this_vp.switch_in_cb = cb; - return ocb; -} - -st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb) -{ - st_switch_cb_t ocb = _st_this_vp.switch_out_cb; - _st_this_vp.switch_out_cb = cb; - return ocb; -} -#endif - -/* - * Start function for the idle thread - */ -/* ARGSUSED */ -void *_st_idle_thread_start(void *arg) -{ - _st_thread_t *me = _ST_CURRENT_THREAD(); - - while (_st_active_count > 0) { - /* Idle vp till I/O is ready or the smallest timeout expired */ - _ST_VP_IDLE(); - - /* Check sleep queue for expired threads */ - _st_vp_check_clock(); - - me->state = _ST_ST_RUNNABLE; - _ST_SWITCH_CONTEXT(me); - } - - /* No more threads */ - exit(0); - - /* NOTREACHED */ - return NULL; -} - -void st_thread_exit(void *retval) -{ - _st_thread_t *trd = _ST_CURRENT_THREAD(); - - trd->retval = retval; - _st_thread_cleanup(trd); - _st_active_count--; - if (trd->term) { - /* Put thread on the zombie queue */ - trd->state = _ST_ST_ZOMBIE; - _ST_ADD_ZOMBIEQ(trd); - - /* Notify on our termination condition variable */ - st_cond_signal(trd->term); - - /* Switch context and come back later */ - _ST_SWITCH_CONTEXT(trd); - - /* Continue the cleanup */ - st_cond_destroy(trd->term); - trd->term = NULL; - } - -#ifdef DEBUG - _ST_DEL_THREADQ(trd); -#endif - - if (!(trd->flags & _ST_FL_PRIMORDIAL)) { - _st_stack_free(trd->stack); - } - - /* Find another thread to run */ - _ST_SWITCH_CONTEXT(trd); - /* Not going to land here */ -} - -int st_thread_join(_st_thread_t *trd, void **retvalp) -{ - _st_cond_t *term = trd->term; - - /* Can't join a non-joinable thread */ - if (term == NULL) { - errno = EINVAL; - return -1; - } - if (_ST_CURRENT_THREAD() == trd) { - errno = EDEADLK; - return -1; - } - - /* Multiple threads can't wait on the same joinable thread */ - if (term->wait_q.next != &term->wait_q) { - errno = EINVAL; - return -1; - } - - while (trd->state != _ST_ST_ZOMBIE) { - if (st_cond_timedwait(term, ST_UTIME_NO_TIMEOUT) != 0) { - return -1; - } - } - - if (retvalp) { - *retvalp = trd->retval; - } - - /* - * Remove target thread from the zombie queue and make it runnable. - * When it gets scheduled later, it will do the clean up. - */ - trd->state = _ST_ST_RUNNABLE; - _ST_DEL_ZOMBIEQ(trd); - _ST_ADD_RUNQ(trd); - - return 0; -} - -void _st_thread_main(void) -{ - _st_thread_t *trd = _ST_CURRENT_THREAD(); - - /* - * Cap the stack by zeroing out the saved return address register - * value. This allows some debugging/profiling tools to know when - * to stop unwinding the stack. It's a no-op on most platforms. - */ - MD_CAP_STACK(&trd); - - /* Run thread main */ - trd->retval = (*trd->start)(trd->arg); - - /* All done, time to go away */ - st_thread_exit(trd->retval); -} - -/* - * Insert "thread" into the timeout heap, in the position - * specified by thread->heap_index. See docs/timeout_heap.txt - * for details about the timeout heap. - */ -static _st_thread_t **heap_insert(_st_thread_t *trd) -{ - int target = trd->heap_index; - int s = target; - _st_thread_t **p = &_ST_SLEEPQ; - int bits = 0; - int bit; - int index = 1; - - while (s) { - s >>= 1; - bits++; - } - - for (bit = bits - 2; bit >= 0; bit--) { - if (trd->due < (*p)->due) { - _st_thread_t *t = *p; - trd->left = t->left; - trd->right = t->right; - *p = trd; - trd->heap_index = index; - trd = t; - } - index <<= 1; - if (target & (1 << bit)) { - p = &((*p)->right); - index |= 1; - } else { - p = &((*p)->left); - } - } - - trd->heap_index = index; - *p = trd; - trd->left = trd->right = NULL; - - return p; -} - -/* - * Delete "thread" from the timeout heap. - */ -static void heap_delete(_st_thread_t *trd) -{ - _st_thread_t *t, **p; - int bits = 0; - int s, bit; - - /* First find and unlink the last heap element */ - p = &_ST_SLEEPQ; - s = _ST_SLEEPQ_SIZE; - while (s) { - s >>= 1; - bits++; - } - - for (bit = bits - 2; bit >= 0; bit--) { - if (_ST_SLEEPQ_SIZE & (1 << bit)) { - p = &((*p)->right); - } else { - p = &((*p)->left); - } - } - - t = *p; - *p = NULL; - --_ST_SLEEPQ_SIZE; - if (t != trd) { - /* - * Insert the unlinked last element in place of the element we are deleting - */ - t->heap_index = trd->heap_index; - p = heap_insert(t); - t = *p; - t->left = trd->left; - t->right = trd->right; - - /* - * Reestablish the heap invariant. - */ - for (;;) { - _st_thread_t *y; /* The younger child */ - int index_tmp; - - if (t->left == NULL) { - break; - } else if (t->right == NULL) { - y = t->left; - } else if (t->left->due < t->right->due) { - y = t->left; - } else { - y = t->right; - } - - if (t->due > y->due) { - _st_thread_t *tl = y->left; - _st_thread_t *tr = y->right; - *p = y; - if (y == t->left) { - y->left = t; - y->right = t->right; - p = &y->left; - } else { - y->left = t->left; - y->right = t; - p = &y->right; - } - t->left = tl; - t->right = tr; - index_tmp = t->heap_index; - t->heap_index = y->heap_index; - y->heap_index = index_tmp; - } else { - break; - } - } - } - - trd->left = trd->right = NULL; -} - -void _st_add_sleep_q(_st_thread_t *trd, st_utime_t timeout) -{ - trd->due = _ST_LAST_CLOCK + timeout; - trd->flags |= _ST_FL_ON_SLEEPQ; - trd->heap_index = ++_ST_SLEEPQ_SIZE; - heap_insert(trd); -} - -void _st_del_sleep_q(_st_thread_t *trd) -{ - heap_delete(trd); - trd->flags &= ~_ST_FL_ON_SLEEPQ; -} - -void _st_vp_check_clock(void) -{ - _st_thread_t *trd; - st_utime_t elapsed, now; - - now = st_utime(); - elapsed = now - _ST_LAST_CLOCK; - _ST_LAST_CLOCK = now; - - if (_st_curr_time && now - _st_last_tset > 999000) { - _st_curr_time = time(NULL); - _st_last_tset = now; - } - - while (_ST_SLEEPQ != NULL) { - trd = _ST_SLEEPQ; - ST_ASSERT(trd->flags & _ST_FL_ON_SLEEPQ); - if (trd->due > now) { - break; - } - _ST_DEL_SLEEPQ(trd); - - /* If thread is waiting on condition variable, set the time out flag */ - if (trd->state == _ST_ST_COND_WAIT) { - trd->flags |= _ST_FL_TIMEDOUT; - } - - /* Make thread runnable */ - ST_ASSERT(!(trd->flags & _ST_FL_IDLE_THREAD)); - trd->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(trd); - } -} - -void st_thread_interrupt(_st_thread_t* trd) -{ - /* If thread is already dead */ - if (trd->state == _ST_ST_ZOMBIE) { - return; - } - - trd->flags |= _ST_FL_INTERRUPT; - - if (trd->state == _ST_ST_RUNNING || trd->state == _ST_ST_RUNNABLE) { - return; - } - - if (trd->flags & _ST_FL_ON_SLEEPQ) { - _ST_DEL_SLEEPQ(trd); - } - - /* Make thread runnable */ - trd->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(trd); -} - -_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size) -{ - _st_thread_t *trd; - _st_stack_t *stack; - void **ptds; - char *sp; - - /* Adjust stack size */ - if (stk_size == 0) { - stk_size = ST_DEFAULT_STACK_SIZE; - } - stk_size = ((stk_size + _ST_PAGE_SIZE - 1) / _ST_PAGE_SIZE) * _ST_PAGE_SIZE; - stack = _st_stack_new(stk_size); - if (!stack) { - return NULL; - } - - /* Allocate thread object and per-thread data off the stack */ -#if defined (MD_STACK_GROWS_DOWN) - sp = stack->stk_top; - /* - * The stack segment is split in the middle. The upper half is used - * as backing store for the register stack which grows upward. - * The lower half is used for the traditional memory stack which - * grows downward. Both stacks start in the middle and grow outward - * from each other. - */ - /** - The below comments is by winlin: - The Stack public structure: - +--------------------------------------------------------------+ - | stack | - +--------------------------------------------------------------+ - bottom top - The code bellow use the stack as: - +-----------------+-----------------+-------------+------------+ - | stack of thread |pad+align(128B+) |thread(336B) | keys(128B) | - +-----------------+-----------------+-------------+------------+ - bottom sp trd ptds top - (context[0].__jmpbuf.sp) (private_data) - */ - sp = sp - (ST_KEYS_MAX * sizeof(void *)); - ptds = (void **) sp; - sp = sp - sizeof(_st_thread_t); - trd = (_st_thread_t *) sp; - - /* Make stack 64-byte aligned */ - if ((unsigned long)sp & 0x3f) { - sp = sp - ((unsigned long)sp & 0x3f); - } - stack->sp = sp - _ST_STACK_PAD_SIZE; -#else - #error "Only Supports Stack Grown Down" -#endif - - memset(trd, 0, sizeof(_st_thread_t)); - memset(ptds, 0, ST_KEYS_MAX * sizeof(void *)); - - /* Initialize thread */ - trd->private_data = ptds; - trd->stack = stack; - trd->start = start; - trd->arg = arg; - -// by winlin, expand macro MD_INIT_CONTEXT -#if defined(__mips__) - MD_SETJMP((trd)->context); - trd->context[0].__jmpbuf[0].__pc = (__ptr_t) _st_thread_main; - trd->context[0].__jmpbuf[0].__sp = stack->sp; -#else - if (MD_SETJMP((trd)->context)) { - _st_thread_main(); - } - MD_GET_SP(trd) = (long) (stack->sp); -#endif - - /* If thread is joinable, allocate a termination condition variable */ - if (joinable) { - trd->term = st_cond_new(); - if (trd->term == NULL) { - _st_stack_free(trd->stack); - return NULL; - } - } - - /* Make thread runnable */ - trd->state = _ST_ST_RUNNABLE; - _st_active_count++; - _ST_ADD_RUNQ(trd); -#ifdef DEBUG - _ST_ADD_THREADQ(trd); -#endif - - return trd; -} - -_st_thread_t *st_thread_self(void) -{ - return _ST_CURRENT_THREAD(); -} - -#ifdef DEBUG -/* ARGSUSED */ -void _st_show_thread_stack(_st_thread_t *trd, const char *messg) -{ -} - -/* To be set from debugger */ -int _st_iterate_threads_flag = 0; - -void _st_iterate_threads(void) -{ - static _st_thread_t *trd = NULL; - static jmp_buf orig_jb, save_jb; - _st_clist_t *q; - - if (!_st_iterate_threads_flag) { - if (trd) { - memcpy(trd->context, save_jb, sizeof(jmp_buf)); - MD_LONGJMP(orig_jb, 1); - } - return; - } - - if (trd) { - memcpy(trd->context, save_jb, sizeof(jmp_buf)); - _st_show_thread_stack(trd, NULL); - } else { - if (MD_SETJMP(orig_jb)) { - _st_iterate_threads_flag = 0; - trd = NULL; - _st_show_thread_stack(trd, "Iteration completed"); - return; - } - trd = _ST_CURRENT_THREAD(); - _st_show_thread_stack(trd, "Iteration started"); - } - - q = trd->tlink.next; - if (q == &_ST_THREADQ) { - q = q->next; - } - ST_ASSERT(q != &_ST_THREADQ); - trd = _ST_THREAD_THREADQ_PTR(q); - if (trd == _ST_CURRENT_THREAD()) { - MD_LONGJMP(orig_jb, 1); - } - memcpy(save_jb, trd->context, sizeof(jmp_buf)); - MD_LONGJMP(trd->context, 1); -} -#endif /* DEBUG */ - diff --git a/trunk/research/st/srs.c b/trunk/research/st/srs.c deleted file mode 100644 index 09bc5eacca..0000000000 --- a/trunk/research/st/srs.c +++ /dev/null @@ -1,497 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "public.h" - -#define srs_trace(msg, ...) printf(msg, ##__VA_ARGS__);printf("\n") - -int io_port = 1990; -int sleep_ms = 100; - -void stack_print(long int previous_sp, int level) -{ - if (level <= 0) { - return; - } - - register long int rsp asm("sp"); - char buf[level * 1024]; - - stack_print(rsp, level - 1); - - srs_trace("%d. psp=%#lx, sp=%#lx, size=%dB(%dB+%dKB)", - level, previous_sp, rsp, (int)(previous_sp - rsp), - (int)(previous_sp - rsp - sizeof(buf)), (int)(sizeof(buf) / 1024)); -} - -int huge_stack_test() -{ - srs_trace("==================================================="); - srs_trace("huge_stack test: start"); - - register long int rsp asm("sp"); - stack_print(rsp, 10); - - srs_trace("huge_stack test: end"); - - return 0; -} - -int sleep_test() -{ - srs_trace("==================================================="); - srs_trace("sleep test: start"); - - srs_trace("1. sleep..."); - st_utime_t start = st_utime(); - st_usleep(sleep_ms * 1000); - st_utime_t end = st_utime(); - - srs_trace("2. sleep ok, sleep=%dus, deviation=%dus", - (int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000)); - - srs_trace("sleep test: end"); - - return 0; -} - -void* sleep2_func0(void* arg) -{ - int sleep_ms = 100; - st_utime_t start = st_utime(); - st_usleep(sleep_ms * 1000); - st_utime_t end = st_utime(); - - srs_trace("sleep ok, sleep=%dus, deviation=%dus", - (int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000)); - - return NULL; -} - -void* sleep2_func1(void* arg) -{ - int sleep_ms = 250; - st_utime_t start = st_utime(); - st_usleep(sleep_ms * 1000); - st_utime_t end = st_utime(); - - srs_trace("sleep ok, sleep=%dus, deviation=%dus", - (int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000)); - - return NULL; -} - -int sleep2_test() -{ - srs_trace("==================================================="); - srs_trace("sleep2 test: start"); - - st_thread_t trd0 = st_thread_create(sleep2_func0, NULL, 1, 0); - st_thread_t trd1 = st_thread_create(sleep2_func1, NULL, 1, 0); - st_thread_join(trd0, NULL); - st_thread_join(trd1, NULL); - - srs_trace("sleep test: end"); - - return 0; -} - -st_mutex_t sleep_work_cond = NULL; -void* sleep_deviation_func(void* arg) -{ - st_mutex_lock(sleep_work_cond); - srs_trace("2. work thread start."); - - int64_t i; - for (i = 0; i < 3000000000ULL; i++) { - } - - st_mutex_unlock(sleep_work_cond); - srs_trace("3. work thread end."); - - return NULL; -} - -int sleep_deviation_test() -{ - srs_trace("==================================================="); - srs_trace("sleep deviation test: start"); - - sleep_work_cond = st_mutex_new(); - - st_thread_create(sleep_deviation_func, NULL, 0, 0); - st_mutex_lock(sleep_work_cond); - - srs_trace("1. sleep..."); - st_utime_t start = st_utime(); - - // other thread to do some complex work. - st_mutex_unlock(sleep_work_cond); - st_usleep(1000 * 1000); - - st_utime_t end = st_utime(); - - srs_trace("4. sleep ok, sleep=%dus, deviation=%dus", - (int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000)); - - st_mutex_lock(sleep_work_cond); - srs_trace("sleep deviation test: end"); - - st_mutex_destroy(sleep_work_cond); - - return 0; -} - -void* thread_func(void* arg) -{ - srs_trace("1. thread run"); - st_usleep(sleep_ms * 1000); - srs_trace("2. thread completed"); - return NULL; -} - -int thread_test() -{ - srs_trace("==================================================="); - srs_trace("thread test: start"); - - st_thread_t trd = st_thread_create(thread_func, NULL, 1, 0); - if (trd == NULL) { - srs_trace("st_thread_create failed"); - return -1; - } - - st_thread_join(trd, NULL); - srs_trace("3. thread joined"); - - srs_trace("thread test: end"); - - return 0; -} - -st_mutex_t sync_start = NULL; -st_cond_t sync_cond = NULL; -st_mutex_t sync_mutex = NULL; -st_cond_t sync_end = NULL; - -void* sync_master(void* arg) -{ - // wait for main to sync_start this thread. - st_mutex_lock(sync_start); - st_mutex_unlock(sync_start); - - st_usleep(sleep_ms * 1000); - st_cond_signal(sync_cond); - - st_mutex_lock(sync_mutex); - srs_trace("2. st mutex is ok"); - st_mutex_unlock(sync_mutex); - - st_usleep(sleep_ms * 1000); - srs_trace("3. st thread is ok"); - st_cond_signal(sync_cond); - - return NULL; -} - -void* sync_slave(void* arg) -{ - // lock mutex to control thread. - st_mutex_lock(sync_mutex); - - // wait for main to sync_start this thread. - st_mutex_lock(sync_start); - st_mutex_unlock(sync_start); - - // wait thread to ready. - st_cond_wait(sync_cond); - srs_trace("1. st cond is ok"); - - // release mutex to control thread - st_usleep(sleep_ms * 1000); - st_mutex_unlock(sync_mutex); - - // wait thread to exit. - st_cond_wait(sync_cond); - srs_trace("4. st is ok"); - - st_cond_signal(sync_end); - - return NULL; -} - -int sync_test() -{ - srs_trace("==================================================="); - srs_trace("sync test: start"); - - if ((sync_start = st_mutex_new()) == NULL) { - srs_trace("st_mutex_new sync_start failed"); - return -1; - } - st_mutex_lock(sync_start); - - if ((sync_cond = st_cond_new()) == NULL) { - srs_trace("st_cond_new cond failed"); - return -1; - } - - if ((sync_end = st_cond_new()) == NULL) { - srs_trace("st_cond_new end failed"); - return -1; - } - - if ((sync_mutex = st_mutex_new()) == NULL) { - srs_trace("st_mutex_new mutex failed"); - return -1; - } - - if (!st_thread_create(sync_master, NULL, 0, 0)) { - srs_trace("st_thread_create failed"); - return -1; - } - - if (!st_thread_create(sync_slave, NULL, 0, 0)) { - srs_trace("st_thread_create failed"); - return -1; - } - - // run all threads. - st_mutex_unlock(sync_start); - - st_cond_wait(sync_end); - srs_trace("sync test: end"); - - return 0; -} - -void* io_client(void* arg) -{ - - int fd; - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - srs_trace("create linux socket error."); - return NULL; - } - srs_trace("6. client create linux socket success. fd=%d", fd); - - st_netfd_t stfd; - if ((stfd = st_netfd_open_socket(fd)) == NULL){ - srs_trace("st_netfd_open_socket open socket failed."); - return NULL; - } - srs_trace("7. client st open socket success. fd=%d", fd); - - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(io_port); - addr.sin_addr.s_addr = INADDR_ANY; - if (st_connect(stfd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_in), ST_UTIME_NO_TIMEOUT) == -1) { - srs_trace("bind socket error."); - return NULL; - } - - char buf[1024]; - if (st_read_fully(stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) { - srs_trace("st_read_fully failed"); - return NULL; - } - if (st_write(stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) { - srs_trace("st_write failed"); - return NULL; - } - - st_netfd_close(stfd); - - return NULL; -} - -int io_test() -{ - srs_trace("==================================================="); - srs_trace("io test: start, port=%d", io_port); - - int fd; - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - srs_trace("create linux socket error."); - return -1; - } - srs_trace("1. server create linux socket success. fd=%d", fd); - - int reuse_socket = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) { - srs_trace("setsockopt reuse-addr error."); - return -1; - } - srs_trace("2. server setsockopt reuse-addr success. fd=%d", fd); - - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(io_port); - addr.sin_addr.s_addr = INADDR_ANY; - if (bind(fd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) { - srs_trace("bind socket error."); - return -1; - } - srs_trace("3. server bind socket success. fd=%d", fd); - - if (listen(fd, 10) == -1) { - srs_trace("listen socket error."); - return -1; - } - srs_trace("4. server listen socket success. fd=%d", fd); - - st_netfd_t stfd; - if ((stfd = st_netfd_open_socket(fd)) == NULL){ - srs_trace("st_netfd_open_socket open socket failed."); - return -1; - } - srs_trace("5. server st open socket success. fd=%d", fd); - - if (!st_thread_create(io_client, NULL, 0, 0)) { - srs_trace("st_thread_create failed"); - return -1; - } - - st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT); - srs_trace("8. server get a client. fd=%d", st_netfd_fileno(client_stfd)); - - char buf[1024]; - if (st_write(client_stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) { - srs_trace("st_write failed"); - return -1; - } - if (st_read_fully(client_stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) { - srs_trace("st_read_fully failed"); - return -1; - } - srs_trace("9. server io completed."); - - st_netfd_close(stfd); - st_netfd_close(client_stfd); - - srs_trace("io test: end"); - return 0; -} - -int pipe_test() -{ - srs_trace("==================================================="); - srs_trace("pipe test: start"); - - int fds[2]; - if (pipe(fds) < 0) { - srs_trace("pipe failed"); - return -1; - } - srs_trace("1. pipe ok, %d=>%d", fds[1], fds[0]); - - st_netfd_t fdw; - if ((fdw = st_netfd_open_socket(fds[1])) == NULL) { - srs_trace("st_netfd_open_socket open socket failed."); - return -1; - } - srs_trace("2. open write fd ok"); - - st_netfd_t fdr; - if ((fdr = st_netfd_open_socket(fds[0])) == NULL) { - srs_trace("st_netfd_open_socket open socket failed."); - return -1; - } - srs_trace("3. open read fd ok"); - - char buf[1024]; - if (st_write(fdw, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) < 0) { - srs_trace("st_write socket failed."); - return -1; - } - srs_trace("4. write to pipe ok"); - - if (st_read(fdr, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) < 0) { - srs_trace("st_read socket failed."); - return -1; - } - srs_trace("5. read from pipe ok"); - - st_netfd_close(fdw); - st_netfd_close(fdr); - - srs_trace("pipe test: end"); - return 0; -} - -int main(int argc, char** argv) -{ - srs_trace("ETIME=%d", ETIME); - - if (st_set_eventsys(ST_EVENTSYS_ALT) < 0) { - srs_trace("st_set_eventsys failed"); - return -1; - } - - if (st_init() < 0) { - srs_trace("st_init failed"); - return -1; - } - - if (sleep2_test() < 0) { - srs_trace("sleep2_test failed"); - return -1; - } - - if (sleep_test() < 0) { - srs_trace("sleep_test failed"); - return -1; - } - - if (sleep_deviation_test() < 0) { - srs_trace("sleep_deviation_test failed"); - return -1; - } - - if (huge_stack_test() < 0) { - srs_trace("huge_stack_test failed"); - return -1; - } - - if (thread_test() < 0) { - srs_trace("thread_test failed"); - return -1; - } - - if (sync_test() < 0) { - srs_trace("sync_test failed"); - return -1; - } - - if (io_test() < 0) { - srs_trace("io_test failed"); - return -1; - } - - if (pipe_test() < 0) { - srs_trace("pipe_test failed"); - return -1; - } - - // cleanup. - srs_trace("wait for all thread completed"); - st_thread_exit(NULL); - // the following never enter, - // the above code will exit when all thread exit, - // current is a primordial st-thread, when all thread exit, - // the st idle thread will exit(0), see _st_idle_thread_start() - srs_trace("all thread completed"); - - return 0; -} - diff --git a/trunk/research/st/st/init b/trunk/research/st/st/init deleted file mode 100644 index 61604b75fb..0000000000 --- a/trunk/research/st/st/init +++ /dev/null @@ -1,3 +0,0 @@ -#ifndef _st_icpp_init_stub -#define _st_icpp_init_stub -#endif diff --git a/trunk/research/st/st/st.upp b/trunk/research/st/st/st.upp deleted file mode 100755 index dab6d49589..0000000000 --- a/trunk/research/st/st/st.upp +++ /dev/null @@ -1,18 +0,0 @@ -file - main readonly separator, - ..\srs.c, - st readonly separator, - ..\common.h, - ..\event.c, - ..\io.c, - ..\key.c, - ..\md.h, - ..\md.S, - ..\public.h, - ..\sched.c, - ..\stk.c, - ..\sync.c; - -mainconfig - "" = "MAIN"; - diff --git a/trunk/research/st/stk.c b/trunk/research/st/stk.c deleted file mode 100644 index c26223ba5f..0000000000 --- a/trunk/research/st/stk.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#include -#include -#include -#include -#include -#include "common.h" - -/* How much space to leave between the stacks, at each end */ -#define REDZONE _ST_PAGE_SIZE - -_st_clist_t _st_free_stacks = ST_INIT_STATIC_CLIST(&_st_free_stacks); -int _st_num_free_stacks = 0; -int _st_randomize_stacks = 0; - -static char *_st_new_stk_segment(int size); - -/** -The below comments is by winlin: -The stack memory struct: - | REDZONE | stack | extra | REDZONE | - +---------+------------------------+---------+---------+ - | 4k | | 4k/0 | 4k | - +---------+------------------------+---------+---------+ - vaddr bottom top -When _st_randomize_stacks is on, by st_randomize_stacks(), -the bottom and top will random movided in the extra: - long offset = (random() % extra) & ~0xf; - ts->stk_bottom += offset; - ts->stk_top += offset; -Both REDZONE are protected by mprotect when DEBUG is on. -*/ -_st_stack_t *_st_stack_new(int stack_size) -{ - _st_clist_t *qp; - _st_stack_t *ts; - int extra; - - // TODO: WINLIN: remove the stack reuse. - for (qp = _st_free_stacks.next; qp != &_st_free_stacks; qp = qp->next) { - ts = _ST_THREAD_STACK_PTR(qp); - if (ts->stk_size >= stack_size) { - /* Found a stack that is big enough */ - ST_REMOVE_LINK(&ts->links); - _st_num_free_stacks--; - ts->links.next = NULL; - ts->links.prev = NULL; - return ts; - } - } - - /* Make a new thread stack object. */ - if ((ts = (_st_stack_t *)calloc(1, sizeof(_st_stack_t))) == NULL) { - return NULL; - } - extra = _st_randomize_stacks ? _ST_PAGE_SIZE : 0; - ts->vaddr_size = stack_size + 2*REDZONE + extra; - ts->vaddr = _st_new_stk_segment(ts->vaddr_size); - if (!ts->vaddr) { - free(ts); - return NULL; - } - ts->stk_size = stack_size; - ts->stk_bottom = ts->vaddr + REDZONE; - ts->stk_top = ts->stk_bottom + stack_size; - -#ifdef DEBUG - mprotect(ts->vaddr, REDZONE, PROT_NONE); - mprotect(ts->stk_top + extra, REDZONE, PROT_NONE); -#endif - - if (extra) { - long offset = (random() % extra) & ~0xf; - - ts->stk_bottom += offset; - ts->stk_top += offset; - } - - return ts; -} - -/* - * Free the stack for the current thread - */ -void _st_stack_free(_st_stack_t *ts) -{ - if (!ts) { - return; - } - - /* Put the stack on the free list */ - ST_APPEND_LINK(&ts->links, _st_free_stacks.prev); - _st_num_free_stacks++; -} - -static char *_st_new_stk_segment(int size) -{ -#ifdef MALLOC_STACK - void *vaddr = malloc(size); -#else - #error "Only Supports Malloc Stack" -#endif - - return (char *)vaddr; -} - -/* Not used */ -#if 0 -void _st_delete_stk_segment(char *vaddr, int size) -{ -#ifdef MALLOC_STACK - free(vaddr); -#else - #error Unknown Stack Malloc -#endif -} -#endif - -int st_randomize_stacks(int on) -{ - int wason = _st_randomize_stacks; - - _st_randomize_stacks = on; - if (on) { - srandom((unsigned int) st_utime()); - } - - return wason; -} diff --git a/trunk/research/st/sync.c b/trunk/research/st/sync.c deleted file mode 100644 index 3e5324084a..0000000000 --- a/trunk/research/st/sync.c +++ /dev/null @@ -1,352 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape Portable Runtime library. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): Silicon Graphics, Inc. - * - * Portions created by SGI are Copyright (C) 2000-2001 Silicon - * Graphics, Inc. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -/* - * This file is derived directly from Netscape Communications Corporation, - * and consists of extensive modifications made during the year(s) 1999-2000. - */ - -#include -#include -#include -#include "common.h" - -extern time_t _st_curr_time; -extern st_utime_t _st_last_tset; -extern int _st_active_count; - -static st_utime_t (*_st_utime)(void) = NULL; - -/***************************************** - * Time functions - */ - -st_utime_t st_utime(void) -{ - if (_st_utime == NULL) { -#ifdef MD_GET_UTIME - MD_GET_UTIME(); -#else - #error Unknown OS -#endif - } - - return (*_st_utime)(); -} - -int st_set_utime_function(st_utime_t (*func)(void)) -{ - if (_st_active_count) { - errno = EINVAL; - return -1; - } - - _st_utime = func; - - return 0; -} - -st_utime_t st_utime_last_clock(void) -{ - return _ST_LAST_CLOCK; -} - -int st_timecache_set(int on) -{ - int wason = (_st_curr_time) ? 1 : 0; - - if (on) { - _st_curr_time = time(NULL); - _st_last_tset = st_utime(); - } else { - _st_curr_time = 0; - } - - return wason; -} - -time_t st_time(void) -{ - if (_st_curr_time) { - return _st_curr_time; - } - - return time(NULL); -} - -int st_usleep(st_utime_t usecs) -{ - _st_thread_t *me = _ST_CURRENT_THREAD(); - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - if (usecs != ST_UTIME_NO_TIMEOUT) { - me->state = _ST_ST_SLEEPING; - _ST_ADD_SLEEPQ(me, usecs); - } else { - me->state = _ST_ST_SUSPENDED; - } - - _ST_SWITCH_CONTEXT(me); - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - return 0; -} - -int st_sleep(int secs) -{ - return st_usleep((secs >= 0) ? secs * (st_utime_t) 1000000LL : ST_UTIME_NO_TIMEOUT); -} - -/***************************************** - * Condition variable functions - */ -_st_cond_t *st_cond_new(void) -{ - _st_cond_t *cvar; - - cvar = (_st_cond_t *) calloc(1, sizeof(_st_cond_t)); - if (cvar) { - ST_INIT_CLIST(&cvar->wait_q); - } - - return cvar; -} - -int st_cond_destroy(_st_cond_t *cvar) -{ - if (cvar->wait_q.next != &cvar->wait_q) { - errno = EBUSY; - return -1; - } - - free(cvar); - - return 0; -} - -int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout) -{ - _st_thread_t *me = _ST_CURRENT_THREAD(); - int rv; - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - /* Put caller thread on the condition variable's wait queue */ - me->state = _ST_ST_COND_WAIT; - ST_APPEND_LINK(&me->wait_links, &cvar->wait_q); - - if (timeout != ST_UTIME_NO_TIMEOUT) { - _ST_ADD_SLEEPQ(me, timeout); - } - - _ST_SWITCH_CONTEXT(me); - - ST_REMOVE_LINK(&me->wait_links); - rv = 0; - - if (me->flags & _ST_FL_TIMEDOUT) { - me->flags &= ~_ST_FL_TIMEDOUT; - errno = ETIME; - rv = -1; - } - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - rv = -1; - } - - return rv; -} - -int st_cond_wait(_st_cond_t *cvar) -{ - return st_cond_timedwait(cvar, ST_UTIME_NO_TIMEOUT); -} - -static int _st_cond_signal(_st_cond_t *cvar, int broadcast) -{ - _st_thread_t *thread; - _st_clist_t *q; - - for (q = cvar->wait_q.next; q != &cvar->wait_q; q = q->next) { - thread = _ST_THREAD_WAITQ_PTR(q); - if (thread->state == _ST_ST_COND_WAIT) { - if (thread->flags & _ST_FL_ON_SLEEPQ) { - _ST_DEL_SLEEPQ(thread); - } - - /* Make thread runnable */ - thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(thread); - if (!broadcast) { - break; - } - } - } - - return 0; -} - -int st_cond_signal(_st_cond_t *cvar) -{ - return _st_cond_signal(cvar, 0); -} - -int st_cond_broadcast(_st_cond_t *cvar) -{ - return _st_cond_signal(cvar, 1); -} - -/***************************************** - * Mutex functions - */ -_st_mutex_t *st_mutex_new(void) -{ - _st_mutex_t *lock; - - lock = (_st_mutex_t *) calloc(1, sizeof(_st_mutex_t)); - if (lock) { - ST_INIT_CLIST(&lock->wait_q); - lock->owner = NULL; - } - - return lock; -} - -int st_mutex_destroy(_st_mutex_t *lock) -{ - if (lock->owner != NULL || lock->wait_q.next != &lock->wait_q) { - errno = EBUSY; - return -1; - } - - free(lock); - - return 0; -} - -int st_mutex_lock(_st_mutex_t *lock) -{ - _st_thread_t *me = _ST_CURRENT_THREAD(); - - if (me->flags & _ST_FL_INTERRUPT) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - if (lock->owner == NULL) { - /* Got the mutex */ - lock->owner = me; - return 0; - } - - if (lock->owner == me) { - errno = EDEADLK; - return -1; - } - - /* Put caller thread on the mutex's wait queue */ - me->state = _ST_ST_LOCK_WAIT; - ST_APPEND_LINK(&me->wait_links, &lock->wait_q); - - _ST_SWITCH_CONTEXT(me); - - ST_REMOVE_LINK(&me->wait_links); - - if ((me->flags & _ST_FL_INTERRUPT) && lock->owner != me) { - me->flags &= ~_ST_FL_INTERRUPT; - errno = EINTR; - return -1; - } - - return 0; -} - -int st_mutex_unlock(_st_mutex_t *lock) -{ - _st_thread_t *thread; - _st_clist_t *q; - - if (lock->owner != _ST_CURRENT_THREAD()) { - errno = EPERM; - return -1; - } - - for (q = lock->wait_q.next; q != &lock->wait_q; q = q->next) { - thread = _ST_THREAD_WAITQ_PTR(q); - if (thread->state == _ST_ST_LOCK_WAIT) { - lock->owner = thread; - /* Make thread runnable */ - thread->state = _ST_ST_RUNNABLE; - _ST_ADD_RUNQ(thread); - return 0; - } - } - - /* No threads waiting on this mutex */ - lock->owner = NULL; - - return 0; -} - -int st_mutex_trylock(_st_mutex_t *lock) -{ - if (lock->owner != NULL) { - errno = EBUSY; - return -1; - } - - /* Got the mutex */ - lock->owner = _ST_CURRENT_THREAD(); - - return 0; -} - diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index b33b4f6f8e..7ebb10b146 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -72,7 +72,7 @@ SrsUdpListener::SrsUdpListener(ISrsUdpHandler* h, string i, int p) handler = h; ip = i; port = p; - lfd = NULL; + lfd = -1; nb_buf = SRS_UDP_MAX_PACKET_SIZE; buf = new char[nb_buf]; @@ -148,7 +148,7 @@ SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p) ip = i; port = p; - lfd = NULL; + lfd = -1; trd = new SrsDummyCoroutine(); } @@ -161,7 +161,7 @@ SrsTcpListener::~SrsTcpListener() int SrsTcpListener::fd() { - return srs_netfd_fileno(lfd);; + return srs_netfd_fileno(lfd); } srs_error_t SrsTcpListener::listen() @@ -191,10 +191,10 @@ srs_error_t SrsTcpListener::cycle() } srs_netfd_t fd = srs_accept(lfd, NULL, NULL, SRS_UTIME_NO_TIMEOUT); - if(fd == NULL){ + if(fd < 0){ return srs_error_new(ERROR_SOCKET_ACCEPT, "accept at fd=%d", srs_netfd_fileno(lfd)); } - + if ((err = srs_fd_closeexec(srs_netfd_fileno(fd))) != srs_success) { return srs_error_wrap(err, "set closeexec"); } diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 61eeb23094..e42f8314b2 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -32,6 +32,8 @@ #include using namespace std; +#include + #include #include #include @@ -344,7 +346,7 @@ SrsSignalManager::SrsSignalManager(SrsServer* s) server = s; sig_pipe[0] = sig_pipe[1] = -1; trd = new SrsSTCoroutine("signal", this); - signal_read_stfd = NULL; + signal_read_stfd = -1; } SrsSignalManager::~SrsSignalManager() @@ -368,7 +370,7 @@ srs_error_t SrsSignalManager::initialize() return srs_error_new(ERROR_SYSTEM_CREATE_PIPE, "create pipe"); } - if ((signal_read_stfd = srs_netfd_open(sig_pipe[0])) == NULL) { + if ((signal_read_stfd = srs_netfd_open(sig_pipe[0])) < 0) { return srs_error_new(ERROR_SYSTEM_CREATE_PIPE, "open pipe"); } @@ -794,7 +796,7 @@ srs_error_t SrsServer::ingest() srs_error_t SrsServer::cycle() { srs_error_t err = do_cycle(); - + #ifdef SRS_AUTO_GPERF_MC destroy(); @@ -885,6 +887,10 @@ srs_error_t SrsServer::do_cycle() // the daemon thread, update the time cache // TODO: FIXME: use SrsHourGlass. + + // FIXME: libco will take over user's event loop + co_eventloop(co_get_epoll_ct(), NULL, NULL); + while (true) { if (handler && (err = handler->on_cycle()) != srs_success) { return srs_error_wrap(err, "handle callback"); diff --git a/trunk/src/app/srs_app_st.cpp b/trunk/src/app/srs_app_st.cpp index 831a0613a7..5c4c7b87bf 100755 --- a/trunk/src/app/srs_app_st.cpp +++ b/trunk/src/app/srs_app_st.cpp @@ -23,7 +23,7 @@ #include -#include +#include #include using namespace std; @@ -79,13 +79,24 @@ int SrsDummyCoroutine::cid() return 0; } -_ST_THREAD_CREATE_PFN _pfn_st_thread_create = (_ST_THREAD_CREATE_PFN)st_thread_create; +void* co_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stack_size) { + (void)joinable; + (void)stack_size; + + stCoRoutine_t *co = NULL; + co_create(&co, NULL, start, arg); + co_resume(co); + return co; +} + +_ST_THREAD_CREATE_PFN _pfn_st_thread_create = (_ST_THREAD_CREATE_PFN)co_thread_create; SrsSTCoroutine::SrsSTCoroutine(string n, ISrsCoroutineHandler* h, int cid) { name = n; handler = h; context = cid; + term = co_cond_alloc(); trd = NULL; trd_err = srs_success; started = interrupted = disposed = cycle_done = false; @@ -94,7 +105,8 @@ SrsSTCoroutine::SrsSTCoroutine(string n, ISrsCoroutineHandler* h, int cid) SrsSTCoroutine::~SrsSTCoroutine() { stop(); - + + co_cond_free(term); srs_freep(trd_err); } @@ -142,8 +154,8 @@ void SrsSTCoroutine::stop() // When not started, the rd is NULL. if (trd) { void* res = NULL; - int r0 = st_thread_join((st_thread_t)trd, &res); - srs_assert(!r0); + + co_cond_timedwait(term, -1); srs_error_t err_res = (srs_error_t)res; if (err_res != srs_success) { @@ -171,8 +183,6 @@ void SrsSTCoroutine::interrupt() if (trd_err == srs_success) { trd_err = srs_error_new(ERROR_THREAD_INTERRUPED, "interrupted"); } - - st_thread_interrupt((st_thread_t)trd); } srs_error_t SrsSTCoroutine::pull() @@ -220,6 +230,9 @@ void* SrsSTCoroutine::pfn(void* arg) p->trd_err = err; } + // FIXME: + //co_cond_signal(term); + return (void*)err; } diff --git a/trunk/src/app/srs_app_st.hpp b/trunk/src/app/srs_app_st.hpp index 956e00b42b..f158d5ba63 100644 --- a/trunk/src/app/srs_app_st.hpp +++ b/trunk/src/app/srs_app_st.hpp @@ -102,6 +102,8 @@ class SrsDummyCoroutine : public SrsCoroutine typedef void* (*_ST_THREAD_CREATE_PFN)(void *(*start)(void *arg), void *arg, int joinable, int stack_size); extern _ST_THREAD_CREATE_PFN _pfn_st_thread_create; +struct stCoCond_t; + // A ST-coroutine is a lightweight thread, just like the goroutine. // But the goroutine maybe run on different thread, while ST-coroutine only // run in single thread, because it use setjmp and longjmp, so it may cause @@ -120,6 +122,7 @@ class SrsSTCoroutine : public SrsCoroutine std::string name; ISrsCoroutineHandler* handler; private: + stCoCond_t* term; srs_thread_t trd; int context; srs_error_t trd_err; diff --git a/trunk/src/service/srs_service_st.cpp b/trunk/src/service/srs_service_st.cpp index f63cd42794..dba7adbe8d 100644 --- a/trunk/src/service/srs_service_st.cpp +++ b/trunk/src/service/srs_service_st.cpp @@ -23,10 +23,11 @@ #include -#include +#include #include #include #include +#include using namespace std; #include @@ -41,6 +42,17 @@ using namespace std; #ifdef __linux__ #include +static int set_fd_nonblock(int fd) +{ + int flags; + + flags = fcntl(fd, F_GETFL, 0); + flags |= O_NONBLOCK; + flags |= O_NDELAY; + int ret = fcntl(fd, F_SETFL, flags); + return ret; +} + bool srs_st_epoll_is_supported(void) { struct epoll_event ev; @@ -56,37 +68,12 @@ bool srs_st_epoll_is_supported(void) srs_error_t srs_st_init() { -#ifdef __linux__ - // check epoll, some old linux donot support epoll. - // @see https://github.com/ossrs/srs/issues/162 - if (!srs_st_epoll_is_supported()) { - return srs_error_new(ERROR_ST_SET_EPOLL, "linux epoll disabled"); - } -#endif - - // Select the best event system available on the OS. In Linux this is - // epoll(). On BSD it will be kqueue. - if (st_set_eventsys(ST_EVENTSYS_ALT) == -1) { - return srs_error_new(ERROR_ST_SET_EPOLL, "st enable st failed, current is %s", st_get_eventsys_name()); - } - - int r0 = 0; - if((r0 = st_init()) != 0){ - return srs_error_new(ERROR_ST_INITIALIZE, "st initialize failed, r0=%d", r0); - } - srs_trace("st_init success, use %s", st_get_eventsys_name()); - return srs_success; } void srs_close_stfd(srs_netfd_t& stfd) { - if (stfd) { - // we must ensure the close is ok. - int err = st_netfd_close((st_netfd_t)stfd); - srs_assert(err != -1); - stfd = NULL; - } + ::close(stfd); } srs_error_t srs_fd_closeexec(int fd) @@ -144,18 +131,17 @@ srs_error_t srs_fd_keepalive(int fd) srs_thread_t srs_thread_self() { - return (srs_thread_t)st_thread_self(); + return (srs_thread_t)co_self(); } srs_error_t srs_tcp_connect(string server, int port, srs_utime_t tm, srs_netfd_t* pstfd) { - st_utime_t timeout = ST_UTIME_NO_TIMEOUT; + srs_utime_t timeout = SRS_UTIME_NO_TIMEOUT; if (tm != SRS_UTIME_NO_TIMEOUT) { timeout = tm; } - - *pstfd = NULL; - srs_netfd_t stfd = NULL; + + (void)timeout; char sport[8]; snprintf(sport, sizeof(sport), "%d", port); @@ -175,20 +161,15 @@ srs_error_t srs_tcp_connect(string server, int port, srs_utime_t tm, srs_netfd_t if(sock == -1){ return srs_error_new(ERROR_SOCKET_CREATE, "create socket"); } + + *pstfd = sock; - srs_assert(!stfd); - stfd = st_netfd_open_socket(sock); - if(stfd == NULL){ - ::close(sock); - return srs_error_new(ERROR_ST_OPEN_SOCKET, "open socket"); - } - - if (st_connect((st_netfd_t)stfd, r->ai_addr, r->ai_addrlen, timeout) == -1){ - srs_close_stfd(stfd); + // TODO: timeout + if (connect(sock, r->ai_addr, r->ai_addrlen) == -1) { + srs_close_stfd(sock); return srs_error_new(ERROR_ST_CONNECT, "connect to %s:%d", server.c_str(), port); } - *pstfd = stfd; return srs_success; } @@ -214,7 +195,7 @@ srs_error_t do_srs_tcp_listen(int fd, addrinfo* r, srs_netfd_t* pfd) return srs_error_wrap(err, "set reuseport"); } - if (bind(fd, r->ai_addr, r->ai_addrlen) == -1) { + if (::bind(fd, r->ai_addr, r->ai_addrlen) == -1) { return srs_error_new(ERROR_SOCKET_BIND, "bind"); } @@ -222,10 +203,6 @@ srs_error_t do_srs_tcp_listen(int fd, addrinfo* r, srs_netfd_t* pfd) return srs_error_new(ERROR_SOCKET_LISTEN, "listen"); } - if ((*pfd = srs_netfd_open_socket(fd)) == NULL){ - return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open"); - } - return err; } @@ -255,11 +232,15 @@ srs_error_t srs_tcp_listen(std::string ip, int port, srs_netfd_t* pfd) r->ai_family, r->ai_socktype, r->ai_protocol); } + set_fd_nonblock(fd); + if ((err = do_srs_tcp_listen(fd, r, pfd)) != srs_success) { ::close(fd); return srs_error_wrap(err, "fd=%d", fd); } + *pfd = fd; + return err; } @@ -283,10 +264,6 @@ srs_error_t do_srs_udp_listen(int fd, addrinfo* r, srs_netfd_t* pfd) return srs_error_new(ERROR_SOCKET_BIND, "bind"); } - if ((*pfd = srs_netfd_open_socket(fd)) == NULL){ - return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open"); - } - return err; } @@ -326,85 +303,121 @@ srs_error_t srs_udp_listen(std::string ip, int port, srs_netfd_t* pfd) srs_cond_t srs_cond_new() { - return (srs_cond_t)st_cond_new(); + return (srs_cond_t)co_cond_alloc(); } int srs_cond_destroy(srs_cond_t cond) { - return st_cond_destroy((st_cond_t)cond); + return co_cond_free((stCoCond_t*)cond); } int srs_cond_wait(srs_cond_t cond) { - return st_cond_wait((st_cond_t)cond); + return co_cond_timedwait((stCoCond_t*)cond, -1); } int srs_cond_timedwait(srs_cond_t cond, srs_utime_t timeout) { - return st_cond_timedwait((st_cond_t)cond, (st_utime_t)timeout); + return co_cond_timedwait((stCoCond_t*)cond, timeout); } int srs_cond_signal(srs_cond_t cond) { - return st_cond_signal((st_cond_t)cond); + return co_cond_signal((stCoCond_t*)cond); } srs_mutex_t srs_mutex_new() { - return (srs_mutex_t)st_mutex_new(); + return NULL; } int srs_mutex_destroy(srs_mutex_t mutex) { - if (!mutex) { - return 0; - } - return st_mutex_destroy((st_mutex_t)mutex); + return 0; } int srs_mutex_lock(srs_mutex_t mutex) { - return st_mutex_lock((st_mutex_t)mutex); + return 0; } int srs_mutex_unlock(srs_mutex_t mutex) { - return st_mutex_unlock((st_mutex_t)mutex); + return 0; } int srs_netfd_fileno(srs_netfd_t stfd) { - return st_netfd_fileno((st_netfd_t)stfd); + return stfd; } int srs_usleep(srs_utime_t usecs) { - return st_usleep((st_utime_t)usecs); + // XXX: libco has no API like co_sleep, use co_cond_timedwait instead + stCoCond_t* cond = co_cond_alloc(); + co_cond_timedwait(cond, usecs/1000.0); + + return 0; } srs_netfd_t srs_netfd_open_socket(int osfd) { - return (srs_netfd_t)st_netfd_open_socket(osfd); + set_fd_nonblock(osfd); + return osfd; } srs_netfd_t srs_netfd_open(int osfd) { - return (srs_netfd_t)st_netfd_open(osfd); + set_fd_nonblock(osfd); + return osfd; } int srs_recvfrom(srs_netfd_t stfd, void *buf, int len, struct sockaddr *from, int *fromlen, srs_utime_t timeout) { - return st_recvfrom((st_netfd_t)stfd, buf, len, from, fromlen, (st_utime_t)timeout); + // TODO: timeout + return recvfrom(stfd, buf, len, 0, from, (socklen_t*)fromlen); } srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout) { - return (srs_netfd_t)st_accept((st_netfd_t)stfd, addr, addrlen, (st_utime_t)timeout); + struct pollfd pf = { 0 }; + pf.fd = stfd; + pf.events = (POLLIN | POLLERR | POLLHUP); + + srs_utime_t atm = timeout; + if (atm != SRS_UTIME_NO_TIMEOUT) + atm /= 1000; + + int client_fd; + while ((client_fd = accept(stfd, addr, (socklen_t*)addrlen)) < 0) { + if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { + return -1; + } + + co_poll(co_get_epoll_ct(), &pf, 1, atm); + } + + set_fd_nonblock(client_fd); + + return client_fd; } ssize_t srs_read(srs_netfd_t stfd, void *buf, size_t nbyte, srs_utime_t timeout) { - return st_read((st_netfd_t)stfd, buf, nbyte, (st_utime_t)timeout); + struct pollfd pf = { 0 }; + pf.fd = stfd; + pf.events = (POLLIN | POLLERR | POLLHUP); + + int n; + while ((n = ::read(stfd, buf, nbyte)) < 0) { + if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { + return -1; + } + + co_poll(co_get_epoll_ct(), &pf, 1, timeout); + } + + return n; } bool srs_is_never_timeout(srs_utime_t tm) @@ -414,7 +427,6 @@ bool srs_is_never_timeout(srs_utime_t tm) SrsStSocket::SrsStSocket() { - stfd = NULL; stm = rtm = SRS_UTIME_NO_TIMEOUT; rbytes = sbytes = 0; } @@ -465,15 +477,15 @@ srs_error_t SrsStSocket::read(void* buf, size_t size, ssize_t* nread) ssize_t nb_read; if (rtm == SRS_UTIME_NO_TIMEOUT) { - nb_read = st_read((st_netfd_t)stfd, buf, size, ST_UTIME_NO_TIMEOUT); + nb_read = srs_read(stfd, buf, size, -1); } else { - nb_read = st_read((st_netfd_t)stfd, buf, size, rtm); + nb_read = srs_read(stfd, buf, size, rtm / 1000); } if (nread) { *nread = nb_read; } - + // On success a non-negative integer indicating the number of bytes actually read is returned // (a value of 0 means the network connection is closed or end of file is reached). // Otherwise, a value of -1 is returned and errno is set to indicate the error. @@ -499,13 +511,25 @@ srs_error_t SrsStSocket::read_fully(void* buf, size_t size, ssize_t* nread) { srs_error_t err = srs_success; - ssize_t nb_read; - if (rtm == SRS_UTIME_NO_TIMEOUT) { - nb_read = st_read_fully((st_netfd_t)stfd, buf, size, ST_UTIME_NO_TIMEOUT); - } else { - nb_read = st_read_fully((st_netfd_t)stfd, buf, size, rtm); + ssize_t nb_read = 0; + + int wait_read_bytes = size; + while (wait_read_bytes > 0) { + int bytes = ::read(stfd, buf, wait_read_bytes); + if (bytes > 0) { + nb_read += bytes; + wait_read_bytes -= bytes; + if (nb_read == (ssize_t)size) { + break; + } + } else if (bytes == 0) { + break; + } else { + if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) + break; + } } - + if (nread) { *nread = nb_read; } @@ -535,11 +559,30 @@ srs_error_t SrsStSocket::write(void* buf, size_t size, ssize_t* nwrite) { srs_error_t err = srs_success; - ssize_t nb_write; - if (stm == SRS_UTIME_NO_TIMEOUT) { - nb_write = st_write((st_netfd_t)stfd, buf, size, ST_UTIME_NO_TIMEOUT); - } else { - nb_write = st_write((st_netfd_t)stfd, buf, size, stm); + ssize_t nb_write = 0; + + struct pollfd pf = { 0 }; + pf.fd = stfd; + pf.events = (POLLOUT | POLLERR | POLLHUP); + + srs_utime_t wtm = stm; + if (wtm != SRS_UTIME_NO_TIMEOUT) + wtm = stm / 1000; + + int wait_write_bytes = size; + while (wait_write_bytes > 0) { + int n = 0; + if ((n = ::write(stfd, buf, size)) < 0) { + if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { + break; + } + + co_poll(co_get_epoll_ct(), &pf, 1, wtm); + continue; + } + + wait_write_bytes -= n; + nb_write += n; } if (nwrite) { @@ -566,11 +609,44 @@ srs_error_t SrsStSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite) { srs_error_t err = srs_success; - ssize_t nb_write; - if (stm == SRS_UTIME_NO_TIMEOUT) { - nb_write = st_writev((st_netfd_t)stfd, iov, iov_size, ST_UTIME_NO_TIMEOUT); - } else { - nb_write = st_writev((st_netfd_t)stfd, iov, iov_size, stm); + srs_utime_t tm = stm; + if (tm != SRS_UTIME_NO_TIMEOUT) + tm = stm / 1000; + + int wait_write_bytes = 0; + for (int i = 0; i < iov_size; ++i) + wait_write_bytes += iov[i].iov_len; + + ssize_t nb_write = 0; + iovec* cur_iov = (iovec*)iov; + int cur_iov_size = iov_size; + + while (wait_write_bytes > 0) { + int n = 0; + if ((n = ::writev(stfd, cur_iov, cur_iov_size)) < 0) { + if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { + break; + } + + struct pollfd pf = {0}; + pf.fd = stfd; + pf.events = (POLLOUT | POLLERR | POLLHUP); + + co_poll(co_get_epoll_ct(), &pf, 1, tm); + continue; + } + + wait_write_bytes -= n; + nb_write += n; + + while (n >= (int)cur_iov->iov_len) { + n -= cur_iov->iov_len; + --cur_iov_size; + ++cur_iov; + } + // FIXME: no modify iov + (*cur_iov).iov_base = (void*)((char*)(*cur_iov).iov_base + n); + (*cur_iov).iov_len -= n; } if (nwrite) { @@ -595,7 +671,7 @@ srs_error_t SrsStSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite) SrsTcpClient::SrsTcpClient(string h, int p, srs_utime_t tm) { - stfd = NULL; + stfd = -1; io = new SrsStSocket(); host = h; @@ -616,7 +692,7 @@ srs_error_t SrsTcpClient::connect() close(); - srs_assert(stfd == NULL); + srs_assert(stfd == -1); if ((err = srs_tcp_connect(host, port, timeout, &stfd)) != srs_success) { return srs_error_wrap(err, "tcp: connect %s:%d to=%dms", host.c_str(), port, srsu2msi(timeout)); } diff --git a/trunk/src/service/srs_service_st.hpp b/trunk/src/service/srs_service_st.hpp index 510b9ba8ac..ca6da3f7cc 100644 --- a/trunk/src/service/srs_service_st.hpp +++ b/trunk/src/service/srs_service_st.hpp @@ -31,7 +31,7 @@ #include // Wrap for coroutine. -typedef void* srs_netfd_t; +typedef int srs_netfd_t; typedef void* srs_thread_t; typedef void* srs_cond_t; typedef void* srs_mutex_t; From 1c74083de84315a105f5a4e535d657e0fbdbb6df Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Mon, 17 Feb 2020 15:30:20 +0800 Subject: [PATCH 02/69] Revert "use libco instead of state-thread(st), still have some bug" This reverts commit 7c8a35aea9b6108bffdc39390cdb00db525be2ac. --- trunk/3rdparty/libco/.gitignore | 1 - trunk/3rdparty/libco/CMakeLists.txt | 55 - trunk/3rdparty/libco/LICENSE.txt | Bin 18962 -> 0 bytes trunk/3rdparty/libco/Makefile | 84 - trunk/3rdparty/libco/co.mk | 85 - trunk/3rdparty/libco/co_closure.h | 96 - trunk/3rdparty/libco/co_epoll.cpp | 318 -- trunk/3rdparty/libco/co_epoll.h | 93 - trunk/3rdparty/libco/co_hook_sys_call.cpp | 1003 ------ trunk/3rdparty/libco/co_routine.cpp | 1196 ------- trunk/3rdparty/libco/co_routine.h | 93 - trunk/3rdparty/libco/co_routine_inner.h | 111 - trunk/3rdparty/libco/co_routine_specific.h | 86 - trunk/3rdparty/libco/coctx.cpp | 132 - trunk/3rdparty/libco/coctx.h | 42 - trunk/3rdparty/libco/coctx_swap.S | 83 - trunk/3rdparty/libco/example_closure.cpp | 91 - trunk/3rdparty/libco/example_cond.cpp | 83 - trunk/3rdparty/libco/example_copystack.cpp | 61 - trunk/3rdparty/libco/example_echocli.cpp | 218 -- trunk/3rdparty/libco/example_echosvr.cpp | 255 -- trunk/3rdparty/libco/example_poll.cpp | 211 -- trunk/3rdparty/libco/example_setenv.cpp | 89 - trunk/3rdparty/libco/example_specific.cpp | 61 - trunk/3rdparty/libco/example_thread.cpp | 56 - trunk/3rdparty/st-srs/.gitignore | 4 + trunk/3rdparty/st-srs/Makefile | 474 +++ trunk/3rdparty/st-srs/README | 394 +++ trunk/3rdparty/st-srs/README.md | 88 + trunk/3rdparty/st-srs/common.h | 479 +++ trunk/3rdparty/st-srs/docs/fig.gif | Bin 0 -> 5374 bytes trunk/3rdparty/st-srs/docs/notes.html | 434 +++ trunk/3rdparty/st-srs/docs/reference.html | 3120 +++++++++++++++++ trunk/3rdparty/st-srs/docs/st.html | 504 +++ trunk/3rdparty/st-srs/docs/timeout_heap.txt | 60 + trunk/3rdparty/st-srs/event.c | 1413 ++++++++ trunk/3rdparty/st-srs/examples/Makefile | 115 + trunk/3rdparty/st-srs/examples/README | 98 + trunk/3rdparty/st-srs/examples/error.c | 168 + trunk/3rdparty/st-srs/examples/lookupdns.c | 103 + trunk/3rdparty/st-srs/examples/proxy.c | 541 +++ trunk/3rdparty/st-srs/examples/res.c | 305 ++ trunk/3rdparty/st-srs/examples/server.c | 1025 ++++++ trunk/3rdparty/st-srs/extensions/Makefile | 91 + trunk/3rdparty/st-srs/extensions/README | 42 + trunk/3rdparty/st-srs/extensions/common.h | 77 + trunk/3rdparty/st-srs/extensions/dnscache.c | 190 + trunk/3rdparty/st-srs/extensions/dnsres.c | 305 ++ trunk/3rdparty/st-srs/extensions/lrucache.c | 343 ++ .../st-srs/extensions/print_stk.patch | 367 ++ trunk/3rdparty/st-srs/extensions/stx.h | 91 + trunk/3rdparty/st-srs/extensions/stx_fileio.c | 197 ++ trunk/3rdparty/st-srs/extensions/stx_fileio.h | 52 + trunk/3rdparty/st-srs/extensions/testdns.c | 112 + trunk/3rdparty/st-srs/io.c | 769 ++++ trunk/3rdparty/st-srs/key.c | 121 + trunk/3rdparty/st-srs/libst.def | 51 + trunk/3rdparty/st-srs/md.S | 644 ++++ trunk/3rdparty/st-srs/md.h | 641 ++++ trunk/3rdparty/st-srs/osguess.sh | 45 + trunk/3rdparty/st-srs/public.h | 166 + trunk/3rdparty/st-srs/sched.c | 705 ++++ trunk/3rdparty/st-srs/st.pc.in | 10 + trunk/3rdparty/st-srs/st.spec | 79 + trunk/3rdparty/st-srs/stk.c | 173 + trunk/3rdparty/st-srs/sync.c | 368 ++ trunk/auto/depends.sh | 31 +- trunk/configure | 34 +- trunk/research/st/Makefile | 100 + trunk/research/st/common.h | 445 +++ trunk/research/st/event.c | 483 +++ trunk/research/st/io.c | 792 +++++ trunk/research/st/key.c | 116 + trunk/research/st/md.S | 151 + trunk/research/st/md.h | 193 + trunk/research/st/public.h | 164 + trunk/research/st/sched.c | 680 ++++ trunk/research/st/srs.c | 497 +++ trunk/research/st/st/init | 3 + trunk/research/st/st/st.upp | 18 + trunk/research/st/stk.c | 169 + trunk/research/st/sync.c | 352 ++ trunk/src/app/srs_app_listener.cpp | 10 +- trunk/src/app/srs_app_server.cpp | 12 +- trunk/src/app/srs_app_st.cpp | 27 +- trunk/src/app/srs_app_st.hpp | 3 - trunk/src/service/srs_service_st.cpp | 260 +- trunk/src/service/srs_service_st.hpp | 2 +- 88 files changed, 19273 insertions(+), 4836 deletions(-) delete mode 100644 trunk/3rdparty/libco/.gitignore delete mode 100644 trunk/3rdparty/libco/CMakeLists.txt delete mode 100644 trunk/3rdparty/libco/LICENSE.txt delete mode 100644 trunk/3rdparty/libco/Makefile delete mode 100644 trunk/3rdparty/libco/co.mk delete mode 100644 trunk/3rdparty/libco/co_closure.h delete mode 100644 trunk/3rdparty/libco/co_epoll.cpp delete mode 100644 trunk/3rdparty/libco/co_epoll.h delete mode 100644 trunk/3rdparty/libco/co_hook_sys_call.cpp delete mode 100644 trunk/3rdparty/libco/co_routine.cpp delete mode 100644 trunk/3rdparty/libco/co_routine.h delete mode 100644 trunk/3rdparty/libco/co_routine_inner.h delete mode 100644 trunk/3rdparty/libco/co_routine_specific.h delete mode 100644 trunk/3rdparty/libco/coctx.cpp delete mode 100644 trunk/3rdparty/libco/coctx.h delete mode 100644 trunk/3rdparty/libco/coctx_swap.S delete mode 100644 trunk/3rdparty/libco/example_closure.cpp delete mode 100644 trunk/3rdparty/libco/example_cond.cpp delete mode 100644 trunk/3rdparty/libco/example_copystack.cpp delete mode 100644 trunk/3rdparty/libco/example_echocli.cpp delete mode 100644 trunk/3rdparty/libco/example_echosvr.cpp delete mode 100644 trunk/3rdparty/libco/example_poll.cpp delete mode 100644 trunk/3rdparty/libco/example_setenv.cpp delete mode 100644 trunk/3rdparty/libco/example_specific.cpp delete mode 100644 trunk/3rdparty/libco/example_thread.cpp create mode 100644 trunk/3rdparty/st-srs/.gitignore create mode 100644 trunk/3rdparty/st-srs/Makefile create mode 100644 trunk/3rdparty/st-srs/README create mode 100644 trunk/3rdparty/st-srs/README.md create mode 100644 trunk/3rdparty/st-srs/common.h create mode 100644 trunk/3rdparty/st-srs/docs/fig.gif create mode 100644 trunk/3rdparty/st-srs/docs/notes.html create mode 100644 trunk/3rdparty/st-srs/docs/reference.html create mode 100644 trunk/3rdparty/st-srs/docs/st.html create mode 100644 trunk/3rdparty/st-srs/docs/timeout_heap.txt create mode 100644 trunk/3rdparty/st-srs/event.c create mode 100644 trunk/3rdparty/st-srs/examples/Makefile create mode 100644 trunk/3rdparty/st-srs/examples/README create mode 100644 trunk/3rdparty/st-srs/examples/error.c create mode 100644 trunk/3rdparty/st-srs/examples/lookupdns.c create mode 100644 trunk/3rdparty/st-srs/examples/proxy.c create mode 100644 trunk/3rdparty/st-srs/examples/res.c create mode 100644 trunk/3rdparty/st-srs/examples/server.c create mode 100644 trunk/3rdparty/st-srs/extensions/Makefile create mode 100644 trunk/3rdparty/st-srs/extensions/README create mode 100644 trunk/3rdparty/st-srs/extensions/common.h create mode 100644 trunk/3rdparty/st-srs/extensions/dnscache.c create mode 100644 trunk/3rdparty/st-srs/extensions/dnsres.c create mode 100644 trunk/3rdparty/st-srs/extensions/lrucache.c create mode 100644 trunk/3rdparty/st-srs/extensions/print_stk.patch create mode 100644 trunk/3rdparty/st-srs/extensions/stx.h create mode 100644 trunk/3rdparty/st-srs/extensions/stx_fileio.c create mode 100644 trunk/3rdparty/st-srs/extensions/stx_fileio.h create mode 100644 trunk/3rdparty/st-srs/extensions/testdns.c create mode 100644 trunk/3rdparty/st-srs/io.c create mode 100644 trunk/3rdparty/st-srs/key.c create mode 100644 trunk/3rdparty/st-srs/libst.def create mode 100644 trunk/3rdparty/st-srs/md.S create mode 100644 trunk/3rdparty/st-srs/md.h create mode 100644 trunk/3rdparty/st-srs/osguess.sh create mode 100644 trunk/3rdparty/st-srs/public.h create mode 100644 trunk/3rdparty/st-srs/sched.c create mode 100644 trunk/3rdparty/st-srs/st.pc.in create mode 100644 trunk/3rdparty/st-srs/st.spec create mode 100644 trunk/3rdparty/st-srs/stk.c create mode 100644 trunk/3rdparty/st-srs/sync.c create mode 100755 trunk/research/st/Makefile create mode 100644 trunk/research/st/common.h create mode 100644 trunk/research/st/event.c create mode 100644 trunk/research/st/io.c create mode 100644 trunk/research/st/key.c create mode 100755 trunk/research/st/md.S create mode 100644 trunk/research/st/md.h create mode 100644 trunk/research/st/public.h create mode 100755 trunk/research/st/sched.c create mode 100644 trunk/research/st/srs.c create mode 100644 trunk/research/st/st/init create mode 100755 trunk/research/st/st/st.upp create mode 100644 trunk/research/st/stk.c create mode 100644 trunk/research/st/sync.c diff --git a/trunk/3rdparty/libco/.gitignore b/trunk/3rdparty/libco/.gitignore deleted file mode 100644 index 42061c01a1..0000000000 --- a/trunk/3rdparty/libco/.gitignore +++ /dev/null @@ -1 +0,0 @@ -README.md \ No newline at end of file diff --git a/trunk/3rdparty/libco/CMakeLists.txt b/trunk/3rdparty/libco/CMakeLists.txt deleted file mode 100644 index 04399a55a3..0000000000 --- a/trunk/3rdparty/libco/CMakeLists.txt +++ /dev/null @@ -1,55 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -project(libco) - -# This for mac osx only -set(CMAKE_MACOSX_RPATH 0) - -# Set lib version -set(LIBCO_VERSION 0.5) - -# Set cflags -set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -g -fno-strict-aliasing -O2 -Wall -export-dynamic -Wall -pipe -D_GNU_SOURCE -D_REENTRANT -fPIC -Wno-deprecated -m64) - -# Use c and asm -enable_language(C ASM) - -# Add source files -set(SOURCE_FILES - co_epoll.cpp - co_hook_sys_call.cpp - co_routine.cpp - coctx.cpp - coctx_swap.S) - -# Add static and shared library target -add_library(colib_static STATIC ${SOURCE_FILES}) -add_library(colib_shared SHARED ${SOURCE_FILES}) - -# Set library output name -set_target_properties(colib_static PROPERTIES OUTPUT_NAME colib) -set_target_properties(colib_shared PROPERTIES OUTPUT_NAME colib) - -set_target_properties(colib_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) -set_target_properties(colib_shared PROPERTIES CLEAN_DIRECT_OUTPUT 1) - -# Set shared library version, will generate libcolib.${LIBCO_VERSION}.so and a symbol link named libcolib.so -# For mac osx, the extension name will be .dylib -set_target_properties(colib_shared PROPERTIES VERSION ${LIBCO_VERSION} SOVERSION ${LIBCO_VERSION}) - - - -# Macro for add example target -macro(add_example_target EXAMPLE_TARGET) - add_executable("example_${EXAMPLE_TARGET}" "example_${EXAMPLE_TARGET}.cpp") - target_link_libraries("example_${EXAMPLE_TARGET}" colib_static pthread dl) -endmacro(add_example_target) - -add_example_target(closure) -add_example_target(cond) -add_example_target(copystack) -add_example_target(echocli) -add_example_target(echosvr) -add_example_target(poll) -add_example_target(setenv) -add_example_target(specific) -add_example_target(thread) diff --git a/trunk/3rdparty/libco/LICENSE.txt b/trunk/3rdparty/libco/LICENSE.txt deleted file mode 100644 index bff49d4bc3a55637e1ed4bd7eeb9834a2b16dbd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18962 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 diff --git a/trunk/3rdparty/libco/Makefile b/trunk/3rdparty/libco/Makefile deleted file mode 100644 index 7db3749460..0000000000 --- a/trunk/3rdparty/libco/Makefile +++ /dev/null @@ -1,84 +0,0 @@ -# -# Tencent is pleased to support the open source community by making Libco available. -# -# Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - -COMM_MAKE = 1 -COMM_ECHO = 1 -version=0.5 -v=debug -include co.mk - -########## options ########## -CFLAGS += -g -fno-strict-aliasing -O2 -Wall -export-dynamic \ - -Wall -pipe -D_GNU_SOURCE -D_REENTRANT -fPIC -Wno-deprecated -m64 - -UNAME := $(shell uname -s) - -ifeq ($(UNAME), FreeBSD) -LINKS += -g -L./lib -lcolib -lpthread -else -LINKS += -g -L./lib -lcolib -lpthread -ldl -endif - -COLIB_OBJS=co_epoll.o co_routine.o co_hook_sys_call.o coctx_swap.o coctx.o -#co_swapcontext.o - -PROGS = colib example_poll example_echosvr example_echocli example_thread example_cond example_specific example_copystack example_closure - -all:$(PROGS) - -colib:libcolib.a libcolib.so - -libcolib.a: $(COLIB_OBJS) - $(ARSTATICLIB) -libcolib.so: $(COLIB_OBJS) - $(BUILDSHARELIB) - -example_echosvr:example_echosvr.o - $(BUILDEXE) -example_echocli:example_echocli.o - $(BUILDEXE) -example_thread:example_thread.o - $(BUILDEXE) -example_poll:example_poll.o - $(BUILDEXE) -example_exit:example_exit.o - $(BUILDEXE) -example_cond:example_cond.o - $(BUILDEXE) -example_specific:example_specific.o - $(BUILDEXE) -example_copystack:example_copystack.o - $(BUILDEXE) -example_setenv:example_setenv.o - $(BUILDEXE) -example_closure:example_closure.o - $(BUILDEXE) - -dist: clean libco-$(version).src.tar.gz - -libco-$(version).src.tar.gz: - @find . -type f | grep -v CVS | grep -v .svn | sed s:^./:libco-$(version)/: > MANIFEST - @(cd ..; ln -s libco_pub libco-$(version)) - (cd ..; tar cvf - `cat libco_pub/MANIFEST` | gzip > libco_pub/libco-$(version).src.tar.gz) - @(cd ..; rm libco-$(version)) - -clean: - $(CLEAN) *.o $(PROGS) - rm -fr MANIFEST lib solib libco-$(version).src.tar.gz libco-$(version) - diff --git a/trunk/3rdparty/libco/co.mk b/trunk/3rdparty/libco/co.mk deleted file mode 100644 index 29658b5116..0000000000 --- a/trunk/3rdparty/libco/co.mk +++ /dev/null @@ -1,85 +0,0 @@ -# -# Tencent is pleased to support the open source community by making Libco available. -# -# Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - - -##### Makefile Rules ########## -MAIL_ROOT=. -SRCROOT=. - -##define the compliers -CPP = $(CXX) -AR = ar -rc -RANLIB = ranlib - -CPPSHARE = $(CPP) -fPIC -shared -O2 -pipe -L$(SRCROOT)/solib/ -o -CSHARE = $(CC) -fPIC -shared -O2 -pipe -L$(SRCROOT)/solib/ -o - -ifeq ($v,release) -CFLAGS= -O2 $(INCLS) -fPIC -DLINUX -pipe -Wno-deprecated -c -else -CFLAGS= -g $(INCLS) -fPIC -DLINUX -pipe -c -fno-inline -endif - -ifneq ($v,release) -BFLAGS= -g -endif - -STATICLIBPATH=$(SRCROOT)/lib -DYNAMICLIBPATH=$(SRCROOT)/solib - -INCLS += -I$(SRCROOT) - -## default links -ifeq ($(LINKS_DYNAMIC), 1) -LINKS += -L$(DYNAMICLIBPATH) -L$(STATICLIBPATH) -else -LINKS += -L$(STATICLIBPATH) -endif - -CPPSRCS = $(wildcard *.cpp) -CSRCS = $(wildcard *.c) -CPPOBJS = $(patsubst %.cpp,%.o,$(CPPSRCS)) -COBJS = $(patsubst %.c,%.o,$(CSRCS)) - -SRCS = $(CPPSRCS) $(CSRCS) -OBJS = $(CPPOBJS) $(COBJS) - -CPPCOMPI=$(CPP) $(CFLAGS) -Wno-deprecated -CCCOMPI=$(CC) $(CFLAGS) - -BUILDEXE = $(CPP) $(BFLAGS) -o $@ $^ $(LINKS) -CLEAN = rm -f *.o - -CPPCOMPILE = $(CPPCOMPI) $< $(FLAGS) $(INCLS) $(MTOOL_INCL) -o $@ -CCCOMPILE = $(CCCOMPI) $< $(FLAGS) $(INCLS) $(MTOOL_INCL) -o $@ - -ARSTATICLIB = $(AR) $@.tmp $^ $(AR_FLAGS); \ - if [ $$? -ne 0 ]; then exit 1; fi; \ - test -d $(STATICLIBPATH) || mkdir -p $(STATICLIBPATH); \ - mv -f $@.tmp $(STATICLIBPATH)/$@; - -BUILDSHARELIB = $(CPPSHARE) $@.tmp $^ $(BS_FLAGS); \ - if [ $$? -ne 0 ]; then exit 1; fi; \ - test -d $(DYNAMICLIBPATH) || mkdir -p $(DYNAMICLIBPATH); \ - mv -f $@.tmp $(DYNAMICLIBPATH)/$@; - -.cpp.o: - $(CPPCOMPILE) -.c.o: - $(CCCOMPILE) diff --git a/trunk/3rdparty/libco/co_closure.h b/trunk/3rdparty/libco/co_closure.h deleted file mode 100644 index 87d5c6891d..0000000000 --- a/trunk/3rdparty/libco/co_closure.h +++ /dev/null @@ -1,96 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#ifndef __CO_CLOSURE_H__ -#define __CO_CLOSURE_H__ -struct stCoClosure_t -{ -public: - virtual void exec() = 0; -}; - -//1.base -//-- 1.1 comac_argc - -#define comac_get_args_cnt( ... ) comac_arg_n( __VA_ARGS__ ) -#define comac_arg_n( _0,_1,_2,_3,_4,_5,_6,_7,N,...) N -#define comac_args_seqs() 7,6,5,4,3,2,1,0 -#define comac_join_1( x,y ) x##y - -#define comac_argc( ... ) comac_get_args_cnt( 0,##__VA_ARGS__,comac_args_seqs() ) -#define comac_join( x,y) comac_join_1( x,y ) - -//-- 1.2 repeat -#define repeat_0( fun,a,... ) -#define repeat_1( fun,a,... ) fun( 1,a,__VA_ARGS__ ) repeat_0( fun,__VA_ARGS__ ) -#define repeat_2( fun,a,... ) fun( 2,a,__VA_ARGS__ ) repeat_1( fun,__VA_ARGS__ ) -#define repeat_3( fun,a,... ) fun( 3,a,__VA_ARGS__ ) repeat_2( fun,__VA_ARGS__ ) -#define repeat_4( fun,a,... ) fun( 4,a,__VA_ARGS__ ) repeat_3( fun,__VA_ARGS__ ) -#define repeat_5( fun,a,... ) fun( 5,a,__VA_ARGS__ ) repeat_4( fun,__VA_ARGS__ ) -#define repeat_6( fun,a,... ) fun( 6,a,__VA_ARGS__ ) repeat_5( fun,__VA_ARGS__ ) - -#define repeat( n,fun,... ) comac_join( repeat_,n )( fun,__VA_ARGS__) - -//2.implement -#if __cplusplus <= 199711L -#define decl_typeof( i,a,... ) typedef typeof( a ) typeof_##a; -#else -#define decl_typeof( i,a,... ) typedef decltype( a ) typeof_##a; -#endif -#define impl_typeof( i,a,... ) typeof_##a & a; -#define impl_typeof_cpy( i,a,... ) typeof_##a a; -#define con_param_typeof( i,a,... ) typeof_##a & a##r, -#define param_init_typeof( i,a,... ) a(a##r), - - -//2.1 reference - -#define co_ref( name,... )\ -repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\ -class type_##name\ -{\ -public:\ - repeat( comac_argc(__VA_ARGS__) ,impl_typeof,__VA_ARGS__ )\ - int _member_cnt;\ - type_##name( \ - repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \ - repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__)) \ - {}\ -} name( __VA_ARGS__ ) ; - - -//2.2 function - -#define co_func(name,...)\ -repeat( comac_argc(__VA_ARGS__) ,decl_typeof,__VA_ARGS__ )\ -class name:public stCoClosure_t\ -{\ -public:\ - repeat( comac_argc(__VA_ARGS__) ,impl_typeof_cpy,__VA_ARGS__ )\ - int _member_cnt;\ -public:\ - name( repeat( comac_argc(__VA_ARGS__),con_param_typeof,__VA_ARGS__ ) ... ): \ - repeat( comac_argc(__VA_ARGS__),param_init_typeof,__VA_ARGS__ ) _member_cnt(comac_argc(__VA_ARGS__))\ - {}\ - void exec() - -#define co_func_end } - - -#endif - diff --git a/trunk/3rdparty/libco/co_epoll.cpp b/trunk/3rdparty/libco/co_epoll.cpp deleted file mode 100644 index 12726218dd..0000000000 --- a/trunk/3rdparty/libco/co_epoll.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "co_epoll.h" -#include -#include -#include -#include - -#if !defined( __APPLE__ ) && !defined( __FreeBSD__ ) - -int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ) -{ - return epoll_wait( epfd,events->events,maxevents,timeout ); -} -int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev ) -{ - return epoll_ctl( epfd,op,fd,ev ); -} -int co_epoll_create( int size ) -{ - return epoll_create( size ); -} - -struct co_epoll_res *co_epoll_res_alloc( int n ) -{ - struct co_epoll_res * ptr = - (struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) ); - - ptr->size = n; - ptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) ); - - return ptr; - -} -void co_epoll_res_free( struct co_epoll_res * ptr ) -{ - if( !ptr ) return; - if( ptr->events ) free( ptr->events ); - free( ptr ); -} - -#else -class clsFdMap // million of fd , 1024 * 1024 -{ -private: - static const int row_size = 1024; - static const int col_size = 1024; - - void **m_pp[ 1024 ]; -public: - clsFdMap() - { - memset( m_pp,0,sizeof(m_pp) ); - } - ~clsFdMap() - { - for(int i=0;i= sizeof(m_pp)/sizeof(m_pp[0]) ) - { - assert( __LINE__ == 0 ); - return -__LINE__; - } - if( !m_pp[ idx ] ) - { - m_pp[ idx ] = (void**)calloc( 1,sizeof(void*) * col_size ); - } - m_pp[ idx ][ fd % col_size ] = (void*)ptr; - return 0; - } - inline void *get( int fd ) - { - int idx = fd / row_size; - if( idx < 0 || idx >= sizeof(m_pp)/sizeof(m_pp[0]) ) - { - return NULL; - } - void **lp = m_pp[ idx ]; - if( !lp ) return NULL; - - return lp[ fd % col_size ]; - } -}; - -__thread clsFdMap *s_fd_map = NULL; - -static inline clsFdMap *get_fd_map() -{ - if( !s_fd_map ) - { - s_fd_map = new clsFdMap(); - } - return s_fd_map; -} - -struct kevent_pair_t -{ - int fire_idx; - int events; - uint64_t u64; -}; -int co_epoll_create( int size ) -{ - return kqueue(); -} -int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ) -{ - struct timespec t = { 0 }; - if( timeout > 0 ) - { - t.tv_sec = timeout; - } - int ret = kevent( epfd, - NULL, 0, //register null - events->eventlist, maxevents,//just retrival - ( -1 == timeout ) ? NULL : &t ); - int j = 0; - for(int i=0;ieventlist[i]; - struct kevent_pair_t *ptr = (struct kevent_pair_t*)kev.udata; - struct epoll_event *ev = events->events + i; - if( 0 == ptr->fire_idx ) - { - ptr->fire_idx = i + 1; - memset( ev,0,sizeof(*ev) ); - ++j; - } - else - { - ev = events->events + ptr->fire_idx - 1; - } - if( EVFILT_READ == kev.filter ) - { - ev->events |= EPOLLIN; - } - else if( EVFILT_WRITE == kev.filter ) - { - ev->events |= EPOLLOUT; - } - ev->data.u64 = ptr->u64; - } - for(int i=0;ieventlist[i].udata) )->fire_idx = 0; - } - return j; -} -int co_epoll_del( int epfd,int fd ) -{ - - struct timespec t = { 0 }; - struct kevent_pair_t *ptr = ( struct kevent_pair_t* )get_fd_map()->get( fd ); - if( !ptr ) return 0; - if( EPOLLIN & ptr->events ) - { - struct kevent kev = { 0 }; - kev.ident = fd; - kev.filter = EVFILT_READ; - kev.flags = EV_DELETE; - kevent( epfd,&kev,1, NULL,0,&t ); - } - if( EPOLLOUT & ptr->events ) - { - struct kevent kev = { 0 }; - kev.ident = fd; - kev.filter = EVFILT_WRITE; - kev.flags = EV_DELETE; - kevent( epfd,&kev,1, NULL,0,&t ); - } - get_fd_map()->clear( fd ); - free( ptr ); - return 0; -} -int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ev ) -{ - if( EPOLL_CTL_DEL == op ) - { - return co_epoll_del( epfd,fd ); - } - - const int flags = ( EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP ); - if( ev->events & ~flags ) - { - return -1; - } - - if( EPOLL_CTL_ADD == op && get_fd_map()->get( fd ) ) - { - errno = EEXIST; - return -1; - } - else if( EPOLL_CTL_MOD == op && !get_fd_map()->get( fd ) ) - { - errno = ENOENT; - return -1; - } - - struct kevent_pair_t *ptr = (struct kevent_pair_t*)get_fd_map()->get( fd ); - if( !ptr ) - { - ptr = (kevent_pair_t*)calloc(1,sizeof(kevent_pair_t)); - get_fd_map()->set( fd,ptr ); - } - - int ret = 0; - struct timespec t = { 0 }; - - // printf("ptr->events 0x%X\n",ptr->events); - - if( EPOLL_CTL_MOD == op ) - { - //1.delete if exists - if( ptr->events & EPOLLIN ) - { - struct kevent kev = { 0 }; - EV_SET( &kev,fd,EVFILT_READ,EV_DELETE,0,0,NULL ); - kevent( epfd, &kev,1, NULL,0, &t ); - } - //1.delete if exists - if( ptr->events & EPOLLOUT ) - { - struct kevent kev = { 0 }; - EV_SET( &kev,fd,EVFILT_WRITE,EV_DELETE,0,0,NULL ); - ret = kevent( epfd, &kev,1, NULL,0, &t ); - // printf("delete write ret %d\n",ret ); - } - } - - do - { - if( ev->events & EPOLLIN ) - { - - //2.add - struct kevent kev = { 0 }; - EV_SET( &kev,fd,EVFILT_READ,EV_ADD,0,0,ptr ); - ret = kevent( epfd, &kev,1, NULL,0, &t ); - if( ret ) break; - } - if( ev->events & EPOLLOUT ) - { - //2.add - struct kevent kev = { 0 }; - EV_SET( &kev,fd,EVFILT_WRITE,EV_ADD,0,0,ptr ); - ret = kevent( epfd, &kev,1, NULL,0, &t ); - if( ret ) break; - } - } while( 0 ); - - if( ret ) - { - get_fd_map()->clear( fd ); - free( ptr ); - return ret; - } - - ptr->events = ev->events; - ptr->u64 = ev->data.u64; - - - return ret; -} - -struct co_epoll_res *co_epoll_res_alloc( int n ) -{ - struct co_epoll_res * ptr = - (struct co_epoll_res *)malloc( sizeof( struct co_epoll_res ) ); - - ptr->size = n; - ptr->events = (struct epoll_event*)calloc( 1,n * sizeof( struct epoll_event ) ); - ptr->eventlist = (struct kevent*)calloc( 1,n * sizeof( struct kevent) ); - - return ptr; -} - -void co_epoll_res_free( struct co_epoll_res * ptr ) -{ - if( !ptr ) return; - if( ptr->events ) free( ptr->events ); - if( ptr->eventlist ) free( ptr->eventlist ); - free( ptr ); -} - -#endif - - diff --git a/trunk/3rdparty/libco/co_epoll.h b/trunk/3rdparty/libco/co_epoll.h deleted file mode 100644 index a1b0e4a7d9..0000000000 --- a/trunk/3rdparty/libco/co_epoll.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#ifndef __CO_EPOLL_H__ -#define __CO_EPOLL_H__ -#include -#include -#include -#include -#include -#include -#include - -#if !defined( __APPLE__ ) && !defined( __FreeBSD__ ) - -#include - -struct co_epoll_res -{ - int size; - struct epoll_event *events; - struct kevent *eventlist; -}; -int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ); -int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ); -int co_epoll_create( int size ); -struct co_epoll_res *co_epoll_res_alloc( int n ); -void co_epoll_res_free( struct co_epoll_res * ); - -#else - -#include -enum EPOLL_EVENTS -{ - EPOLLIN = 0X001, - EPOLLPRI = 0X002, - EPOLLOUT = 0X004, - - EPOLLERR = 0X008, - EPOLLHUP = 0X010, - - EPOLLRDNORM = 0x40, - EPOLLWRNORM = 0x004, -}; -#define EPOLL_CTL_ADD 1 -#define EPOLL_CTL_DEL 2 -#define EPOLL_CTL_MOD 3 -typedef union epoll_data -{ - void *ptr; - int fd; - uint32_t u32; - uint64_t u64; - -} epoll_data_t; - -struct epoll_event -{ - uint32_t events; - epoll_data_t data; -}; - -struct co_epoll_res -{ - int size; - struct epoll_event *events; - struct kevent *eventlist; -}; -int co_epoll_wait( int epfd,struct co_epoll_res *events,int maxevents,int timeout ); -int co_epoll_ctl( int epfd,int op,int fd,struct epoll_event * ); -int co_epoll_create( int size ); -struct co_epoll_res *co_epoll_res_alloc( int n ); -void co_epoll_res_free( struct co_epoll_res * ); - -#endif -#endif - - diff --git a/trunk/3rdparty/libco/co_hook_sys_call.cpp b/trunk/3rdparty/libco/co_hook_sys_call.cpp deleted file mode 100644 index 7bb0c417b9..0000000000 --- a/trunk/3rdparty/libco/co_hook_sys_call.cpp +++ /dev/null @@ -1,1003 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include "co_routine.h" -#include "co_routine_inner.h" -#include "co_routine_specific.h" - -typedef long long ll64_t; - -struct rpchook_t -{ - int user_flag; - struct sockaddr_in dest; //maybe sockaddr_un; - int domain; //AF_LOCAL , AF_INET - - struct timeval read_timeout; - struct timeval write_timeout; -}; -static inline pid_t GetPid() -{ - char **p = (char**)pthread_self(); - return p ? *(pid_t*)(p + 18) : getpid(); -} -static rpchook_t *g_rpchook_socket_fd[ 102400 ] = { 0 }; - -typedef int (*socket_pfn_t)(int domain, int type, int protocol); -typedef int (*connect_pfn_t)(int socket, const struct sockaddr *address, socklen_t address_len); -typedef int (*close_pfn_t)(int fd); - -typedef ssize_t (*read_pfn_t)(int fildes, void *buf, size_t nbyte); -typedef ssize_t (*write_pfn_t)(int fildes, const void *buf, size_t nbyte); - -typedef ssize_t (*sendto_pfn_t)(int socket, const void *message, size_t length, - int flags, const struct sockaddr *dest_addr, - socklen_t dest_len); - -typedef ssize_t (*recvfrom_pfn_t)(int socket, void *buffer, size_t length, - int flags, struct sockaddr *address, - socklen_t *address_len); - -typedef size_t (*send_pfn_t)(int socket, const void *buffer, size_t length, int flags); -typedef ssize_t (*recv_pfn_t)(int socket, void *buffer, size_t length, int flags); - -typedef int (*poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout); -typedef int (*setsockopt_pfn_t)(int socket, int level, int option_name, - const void *option_value, socklen_t option_len); - -typedef int (*fcntl_pfn_t)(int fildes, int cmd, ...); -typedef struct tm *(*localtime_r_pfn_t)( const time_t *timep, struct tm *result ); - -typedef void *(*pthread_getspecific_pfn_t)(pthread_key_t key); -typedef int (*pthread_setspecific_pfn_t)(pthread_key_t key, const void *value); - -typedef int (*setenv_pfn_t)(const char *name, const char *value, int overwrite); -typedef int (*unsetenv_pfn_t)(const char *name); -typedef char *(*getenv_pfn_t)(const char *name); -typedef hostent* (*gethostbyname_pfn_t)(const char *name); -typedef res_state (*__res_state_pfn_t)(); -typedef int (*__poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout); - -static socket_pfn_t g_sys_socket_func = (socket_pfn_t)dlsym(RTLD_NEXT,"socket"); -static connect_pfn_t g_sys_connect_func = (connect_pfn_t)dlsym(RTLD_NEXT,"connect"); -static close_pfn_t g_sys_close_func = (close_pfn_t)dlsym(RTLD_NEXT,"close"); - -static read_pfn_t g_sys_read_func = (read_pfn_t)dlsym(RTLD_NEXT,"read"); -static write_pfn_t g_sys_write_func = (write_pfn_t)dlsym(RTLD_NEXT,"write"); - -static sendto_pfn_t g_sys_sendto_func = (sendto_pfn_t)dlsym(RTLD_NEXT,"sendto"); -static recvfrom_pfn_t g_sys_recvfrom_func = (recvfrom_pfn_t)dlsym(RTLD_NEXT,"recvfrom"); - -static send_pfn_t g_sys_send_func = (send_pfn_t)dlsym(RTLD_NEXT,"send"); -static recv_pfn_t g_sys_recv_func = (recv_pfn_t)dlsym(RTLD_NEXT,"recv"); - -static poll_pfn_t g_sys_poll_func = (poll_pfn_t)dlsym(RTLD_NEXT,"poll"); - -static setsockopt_pfn_t g_sys_setsockopt_func - = (setsockopt_pfn_t)dlsym(RTLD_NEXT,"setsockopt"); -static fcntl_pfn_t g_sys_fcntl_func = (fcntl_pfn_t)dlsym(RTLD_NEXT,"fcntl"); - -static setenv_pfn_t g_sys_setenv_func = (setenv_pfn_t)dlsym(RTLD_NEXT,"setenv"); -static unsetenv_pfn_t g_sys_unsetenv_func = (unsetenv_pfn_t)dlsym(RTLD_NEXT,"unsetenv"); -static getenv_pfn_t g_sys_getenv_func = (getenv_pfn_t)dlsym(RTLD_NEXT,"getenv"); -static __res_state_pfn_t g_sys___res_state_func = (__res_state_pfn_t)dlsym(RTLD_NEXT,"__res_state"); - -static gethostbyname_pfn_t g_sys_gethostbyname_func = (gethostbyname_pfn_t)dlsym(RTLD_NEXT, "gethostbyname"); - -static __poll_pfn_t g_sys___poll_func = (__poll_pfn_t)dlsym(RTLD_NEXT, "__poll"); - - -/* -static pthread_getspecific_pfn_t g_sys_pthread_getspecific_func - = (pthread_getspecific_pfn_t)dlsym(RTLD_NEXT,"pthread_getspecific"); - -static pthread_setspecific_pfn_t g_sys_pthread_setspecific_func - = (pthread_setspecific_pfn_t)dlsym(RTLD_NEXT,"pthread_setspecific"); - -static pthread_rwlock_rdlock_pfn_t g_sys_pthread_rwlock_rdlock_func - = (pthread_rwlock_rdlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_rdlock"); - -static pthread_rwlock_wrlock_pfn_t g_sys_pthread_rwlock_wrlock_func - = (pthread_rwlock_wrlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_wrlock"); - -static pthread_rwlock_unlock_pfn_t g_sys_pthread_rwlock_unlock_func - = (pthread_rwlock_unlock_pfn_t)dlsym(RTLD_NEXT,"pthread_rwlock_unlock"); -*/ - - - -static inline unsigned long long get_tick_count() -{ - uint32_t lo, hi; - __asm__ __volatile__ ( - "rdtscp" : "=a"(lo), "=d"(hi) - ); - return ((unsigned long long)lo) | (((unsigned long long)hi) << 32); -} - -struct rpchook_connagent_head_t -{ - unsigned char bVersion; - struct in_addr iIP; - unsigned short hPort; - unsigned int iBodyLen; - unsigned int iOssAttrID; - unsigned char bIsRespNotExist; - unsigned char sReserved[6]; -}__attribute__((packed)); - - -#define HOOK_SYS_FUNC(name) if( !g_sys_##name##_func ) { g_sys_##name##_func = (name##_pfn_t)dlsym(RTLD_NEXT,#name); } - -static inline ll64_t diff_ms(struct timeval &begin,struct timeval &end) -{ - ll64_t u = (end.tv_sec - begin.tv_sec) ; - u *= 1000 * 10; - u += ( end.tv_usec - begin.tv_usec ) / ( 100 ); - return u; -} - - - -static inline rpchook_t * get_by_fd( int fd ) -{ - if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) ) - { - return g_rpchook_socket_fd[ fd ]; - } - return NULL; -} -static inline rpchook_t * alloc_by_fd( int fd ) -{ - if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) ) - { - rpchook_t *lp = (rpchook_t*)calloc( 1,sizeof(rpchook_t) ); - lp->read_timeout.tv_sec = 1; - lp->write_timeout.tv_sec = 1; - g_rpchook_socket_fd[ fd ] = lp; - return lp; - } - return NULL; -} -static inline void free_by_fd( int fd ) -{ - if( fd > -1 && fd < (int)sizeof(g_rpchook_socket_fd) / (int)sizeof(g_rpchook_socket_fd[0]) ) - { - rpchook_t *lp = g_rpchook_socket_fd[ fd ]; - if( lp ) - { - g_rpchook_socket_fd[ fd ] = NULL; - free(lp); - } - } - return; - -} -int socket(int domain, int type, int protocol) -{ - HOOK_SYS_FUNC( socket ); - - if( !co_is_enable_sys_hook() ) - { - return g_sys_socket_func( domain,type,protocol ); - } - int fd = g_sys_socket_func(domain,type,protocol); - if( fd < 0 ) - { - return fd; - } - - rpchook_t *lp = alloc_by_fd( fd ); - lp->domain = domain; - - fcntl( fd, F_SETFL, g_sys_fcntl_func(fd, F_GETFL,0 ) ); - - return fd; -} - -int co_accept( int fd, struct sockaddr *addr, socklen_t *len ) -{ - int cli = accept( fd,addr,len ); - if( cli < 0 ) - { - return cli; - } - alloc_by_fd( cli ); - return cli; -} -int connect(int fd, const struct sockaddr *address, socklen_t address_len) -{ - HOOK_SYS_FUNC( connect ); - - if( !co_is_enable_sys_hook() ) - { - return g_sys_connect_func(fd,address,address_len); - } - - //1.sys call - int ret = g_sys_connect_func( fd,address,address_len ); - - rpchook_t *lp = get_by_fd( fd ); - if( !lp ) return ret; - - if( sizeof(lp->dest) >= address_len ) - { - memcpy( &(lp->dest),address,(int)address_len ); - } - if( O_NONBLOCK & lp->user_flag ) - { - return ret; - } - - if (!(ret < 0 && errno == EINPROGRESS)) - { - return ret; - } - - //2.wait - int pollret = 0; - struct pollfd pf = { 0 }; - - for(int i=0;i<3;i++) //25s * 3 = 75s - { - memset( &pf,0,sizeof(pf) ); - pf.fd = fd; - pf.events = ( POLLOUT | POLLERR | POLLHUP ); - - pollret = poll( &pf,1,25000 ); - - if( 1 == pollret ) - { - break; - } - } - - if( pf.revents & POLLOUT ) //connect succ - { - // 3.check getsockopt ret - int err = 0; - socklen_t errlen = sizeof(err); - ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen); - if (ret < 0) { - return ret; - } else if (err != 0) { - errno = err; - return -1; - } - errno = 0; - return 0; - } - - errno = ETIMEDOUT; - return ret; -} - - -int close(int fd) -{ - HOOK_SYS_FUNC( close ); - - if( !co_is_enable_sys_hook() ) - { - return g_sys_close_func( fd ); - } - - free_by_fd( fd ); - int ret = g_sys_close_func(fd); - - return ret; -} -ssize_t read( int fd, void *buf, size_t nbyte ) -{ - HOOK_SYS_FUNC( read ); - - if( !co_is_enable_sys_hook() ) - { - return g_sys_read_func( fd,buf,nbyte ); - } - rpchook_t *lp = get_by_fd( fd ); - - if( !lp || ( O_NONBLOCK & lp->user_flag ) ) - { - ssize_t ret = g_sys_read_func( fd,buf,nbyte ); - return ret; - } - int timeout = ( lp->read_timeout.tv_sec * 1000 ) - + ( lp->read_timeout.tv_usec / 1000 ); - - struct pollfd pf = { 0 }; - pf.fd = fd; - pf.events = ( POLLIN | POLLERR | POLLHUP ); - - int pollret = poll( &pf,1,timeout ); - - ssize_t readret = g_sys_read_func( fd,(char*)buf ,nbyte ); - - if( readret < 0 ) - { - co_log_err("CO_ERR: read fd %d ret %ld errno %d poll ret %d timeout %d", - fd,readret,errno,pollret,timeout); - } - - return readret; - -} -ssize_t write( int fd, const void *buf, size_t nbyte ) -{ - HOOK_SYS_FUNC( write ); - - if( !co_is_enable_sys_hook() ) - { - return g_sys_write_func( fd,buf,nbyte ); - } - rpchook_t *lp = get_by_fd( fd ); - - if( !lp || ( O_NONBLOCK & lp->user_flag ) ) - { - ssize_t ret = g_sys_write_func( fd,buf,nbyte ); - return ret; - } - size_t wrotelen = 0; - int timeout = ( lp->write_timeout.tv_sec * 1000 ) - + ( lp->write_timeout.tv_usec / 1000 ); - - ssize_t writeret = g_sys_write_func( fd,(const char*)buf + wrotelen,nbyte - wrotelen ); - - if (writeret == 0) - { - return writeret; - } - - if( writeret > 0 ) - { - wrotelen += writeret; - } - while( wrotelen < nbyte ) - { - - struct pollfd pf = { 0 }; - pf.fd = fd; - pf.events = ( POLLOUT | POLLERR | POLLHUP ); - poll( &pf,1,timeout ); - - writeret = g_sys_write_func( fd,(const char*)buf + wrotelen,nbyte - wrotelen ); - - if( writeret <= 0 ) - { - break; - } - wrotelen += writeret ; - } - if (writeret <= 0 && wrotelen == 0) - { - return writeret; - } - return wrotelen; -} - -ssize_t sendto(int socket, const void *message, size_t length, - int flags, const struct sockaddr *dest_addr, - socklen_t dest_len) -{ - /* - 1.no enable sys call ? sys - 2.( !lp || lp is non block ) ? sys - 3.try - 4.wait - 5.try - */ - HOOK_SYS_FUNC( sendto ); - if( !co_is_enable_sys_hook() ) - { - return g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); - } - - rpchook_t *lp = get_by_fd( socket ); - if( !lp || ( O_NONBLOCK & lp->user_flag ) ) - { - return g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); - } - - ssize_t ret = g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); - if( ret < 0 && EAGAIN == errno ) - { - int timeout = ( lp->write_timeout.tv_sec * 1000 ) - + ( lp->write_timeout.tv_usec / 1000 ); - - - struct pollfd pf = { 0 }; - pf.fd = socket; - pf.events = ( POLLOUT | POLLERR | POLLHUP ); - poll( &pf,1,timeout ); - - ret = g_sys_sendto_func( socket,message,length,flags,dest_addr,dest_len ); - - } - return ret; -} - -ssize_t recvfrom(int socket, void *buffer, size_t length, - int flags, struct sockaddr *address, - socklen_t *address_len) -{ - HOOK_SYS_FUNC( recvfrom ); - if( !co_is_enable_sys_hook() ) - { - return g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len ); - } - - rpchook_t *lp = get_by_fd( socket ); - if( !lp || ( O_NONBLOCK & lp->user_flag ) ) - { - return g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len ); - } - - int timeout = ( lp->read_timeout.tv_sec * 1000 ) - + ( lp->read_timeout.tv_usec / 1000 ); - - - struct pollfd pf = { 0 }; - pf.fd = socket; - pf.events = ( POLLIN | POLLERR | POLLHUP ); - poll( &pf,1,timeout ); - - ssize_t ret = g_sys_recvfrom_func( socket,buffer,length,flags,address,address_len ); - return ret; -} - -ssize_t send(int socket, const void *buffer, size_t length, int flags) -{ - HOOK_SYS_FUNC( send ); - - if( !co_is_enable_sys_hook() ) - { - return g_sys_send_func( socket,buffer,length,flags ); - } - rpchook_t *lp = get_by_fd( socket ); - - if( !lp || ( O_NONBLOCK & lp->user_flag ) ) - { - return g_sys_send_func( socket,buffer,length,flags ); - } - size_t wrotelen = 0; - int timeout = ( lp->write_timeout.tv_sec * 1000 ) - + ( lp->write_timeout.tv_usec / 1000 ); - - ssize_t writeret = g_sys_send_func( socket,buffer,length,flags ); - if (writeret == 0) - { - return writeret; - } - - if( writeret > 0 ) - { - wrotelen += writeret; - } - while( wrotelen < length ) - { - - struct pollfd pf = { 0 }; - pf.fd = socket; - pf.events = ( POLLOUT | POLLERR | POLLHUP ); - poll( &pf,1,timeout ); - - writeret = g_sys_send_func( socket,(const char*)buffer + wrotelen,length - wrotelen,flags ); - - if( writeret <= 0 ) - { - break; - } - wrotelen += writeret ; - } - if (writeret <= 0 && wrotelen == 0) - { - return writeret; - } - return wrotelen; -} - -ssize_t recv( int socket, void *buffer, size_t length, int flags ) -{ - HOOK_SYS_FUNC( recv ); - - if( !co_is_enable_sys_hook() ) - { - return g_sys_recv_func( socket,buffer,length,flags ); - } - rpchook_t *lp = get_by_fd( socket ); - - if( !lp || ( O_NONBLOCK & lp->user_flag ) ) - { - return g_sys_recv_func( socket,buffer,length,flags ); - } - int timeout = ( lp->read_timeout.tv_sec * 1000 ) - + ( lp->read_timeout.tv_usec / 1000 ); - - struct pollfd pf = { 0 }; - pf.fd = socket; - pf.events = ( POLLIN | POLLERR | POLLHUP ); - - int pollret = poll( &pf,1,timeout ); - - ssize_t readret = g_sys_recv_func( socket,buffer,length,flags ); - - if( readret < 0 ) - { - co_log_err("CO_ERR: read fd %d ret %ld errno %d poll ret %d timeout %d", - socket,readret,errno,pollret,timeout); - } - - return readret; - -} - -extern int co_poll_inner( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout, poll_pfn_t pollfunc); - -int poll(struct pollfd fds[], nfds_t nfds, int timeout) -{ - HOOK_SYS_FUNC( poll ); - - if (!co_is_enable_sys_hook() || timeout == 0) { - return g_sys_poll_func(fds, nfds, timeout); - } - pollfd *fds_merge = NULL; - nfds_t nfds_merge = 0; - std::map m; // fd --> idx - std::map::iterator it; - if (nfds > 1) { - fds_merge = (pollfd *)malloc(sizeof(pollfd) * nfds); - for (size_t i = 0; i < nfds; i++) { - if ((it = m.find(fds[i].fd)) == m.end()) { - fds_merge[nfds_merge] = fds[i]; - m[fds[i].fd] = nfds_merge; - nfds_merge++; - } else { - int j = it->second; - fds_merge[j].events |= fds[i].events; // merge in j slot - } - } - } - - int ret = 0; - if (nfds_merge == nfds || nfds == 1) { - ret = co_poll_inner(co_get_epoll_ct(), fds, nfds, timeout, g_sys_poll_func); - } else { - ret = co_poll_inner(co_get_epoll_ct(), fds_merge, nfds_merge, timeout, - g_sys_poll_func); - if (ret > 0) { - for (size_t i = 0; i < nfds; i++) { - it = m.find(fds[i].fd); - if (it != m.end()) { - int j = it->second; - fds[i].revents = fds_merge[j].revents & fds[i].events; - } - } - } - } - free(fds_merge); - return ret; - - -} -int setsockopt(int fd, int level, int option_name, - const void *option_value, socklen_t option_len) -{ - HOOK_SYS_FUNC( setsockopt ); - - if( !co_is_enable_sys_hook() ) - { - return g_sys_setsockopt_func( fd,level,option_name,option_value,option_len ); - } - rpchook_t *lp = get_by_fd( fd ); - - if( lp && SOL_SOCKET == level ) - { - struct timeval *val = (struct timeval*)option_value; - if( SO_RCVTIMEO == option_name ) - { - memcpy( &lp->read_timeout,val,sizeof(*val) ); - } - else if( SO_SNDTIMEO == option_name ) - { - memcpy( &lp->write_timeout,val,sizeof(*val) ); - } - } - return g_sys_setsockopt_func( fd,level,option_name,option_value,option_len ); -} - - -int fcntl(int fildes, int cmd, ...) -{ - HOOK_SYS_FUNC( fcntl ); - - if( fildes < 0 ) - { - return __LINE__; - } - - va_list arg_list; - va_start( arg_list,cmd ); - - int ret = -1; - rpchook_t *lp = get_by_fd( fildes ); - switch( cmd ) - { - case F_DUPFD: - { - int param = va_arg(arg_list,int); - ret = g_sys_fcntl_func( fildes,cmd,param ); - break; - } - case F_GETFD: - { - ret = g_sys_fcntl_func( fildes,cmd ); - if (lp && !(lp->user_flag & O_NONBLOCK)) { - ret = ret & (~O_NONBLOCK); - } - break; - } - case F_SETFD: - { - int param = va_arg(arg_list,int); - ret = g_sys_fcntl_func( fildes,cmd,param ); - break; - } - case F_GETFL: - { - ret = g_sys_fcntl_func( fildes,cmd ); - break; - } - case F_SETFL: - { - int param = va_arg(arg_list,int); - int flag = param; - if( co_is_enable_sys_hook() && lp ) - { - flag |= O_NONBLOCK; - } - ret = g_sys_fcntl_func( fildes,cmd,flag ); - if( 0 == ret && lp ) - { - lp->user_flag = param; - } - break; - } - case F_GETOWN: - { - ret = g_sys_fcntl_func( fildes,cmd ); - break; - } - case F_SETOWN: - { - int param = va_arg(arg_list,int); - ret = g_sys_fcntl_func( fildes,cmd,param ); - break; - } - case F_GETLK: - { - struct flock *param = va_arg(arg_list,struct flock *); - ret = g_sys_fcntl_func( fildes,cmd,param ); - break; - } - case F_SETLK: - { - struct flock *param = va_arg(arg_list,struct flock *); - ret = g_sys_fcntl_func( fildes,cmd,param ); - break; - } - case F_SETLKW: - { - struct flock *param = va_arg(arg_list,struct flock *); - ret = g_sys_fcntl_func( fildes,cmd,param ); - break; - } - } - - va_end( arg_list ); - - return ret; -} - -struct stCoSysEnv_t -{ - char *name; - char *value; -}; -struct stCoSysEnvArr_t -{ - stCoSysEnv_t *data; - size_t cnt; -}; -static stCoSysEnvArr_t *dup_co_sysenv_arr( stCoSysEnvArr_t * arr ) -{ - stCoSysEnvArr_t *lp = (stCoSysEnvArr_t*)calloc( sizeof(stCoSysEnvArr_t),1 ); - if( arr->cnt ) - { - lp->data = (stCoSysEnv_t*)calloc( sizeof(stCoSysEnv_t) * arr->cnt,1 ); - lp->cnt = arr->cnt; - memcpy( lp->data,arr->data,sizeof( stCoSysEnv_t ) * arr->cnt ); - } - return lp; -} - -static int co_sysenv_comp(const void *a, const void *b) -{ - return strcmp(((stCoSysEnv_t*)a)->name, ((stCoSysEnv_t*)b)->name); -} -static stCoSysEnvArr_t g_co_sysenv = { 0 }; - - - -void co_set_env_list( const char *name[],size_t cnt) -{ - if( g_co_sysenv.data ) - { - return ; - } - g_co_sysenv.data = (stCoSysEnv_t*)calloc( 1,sizeof(stCoSysEnv_t) * cnt ); - - for(size_t i=0;i 1 ) - { - qsort( g_co_sysenv.data,g_co_sysenv.cnt,sizeof(stCoSysEnv_t),co_sysenv_comp ); - stCoSysEnv_t *lp = g_co_sysenv.data; - stCoSysEnv_t *lq = g_co_sysenv.data + 1; - for(size_t i=1;iname,lq->name ) ) - { - ++lp; - if( lq != lp ) - { - *lp = *lq; - } - } - ++lq; - } - g_co_sysenv.cnt = lp - g_co_sysenv.data + 1; - } - -} - -int setenv(const char *n, const char *value, int overwrite) -{ - HOOK_SYS_FUNC( setenv ) - if( co_is_enable_sys_hook() && g_co_sysenv.data ) - { - stCoRoutine_t *self = co_self(); - if( self ) - { - if( !self->pvEnv ) - { - self->pvEnv = dup_co_sysenv_arr( &g_co_sysenv ); - } - stCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv); - - stCoSysEnv_t name = { (char*)n,0 }; - - stCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp ); - - if( e ) - { - if( overwrite || !e->value ) - { - if( e->value ) free( e->value ); - e->value = ( value ? strdup( value ) : 0 ); - } - return 0; - } - } - - } - return g_sys_setenv_func( n,value,overwrite ); -} -int unsetenv(const char *n) -{ - HOOK_SYS_FUNC( unsetenv ) - if( co_is_enable_sys_hook() && g_co_sysenv.data ) - { - stCoRoutine_t *self = co_self(); - if( self ) - { - if( !self->pvEnv ) - { - self->pvEnv = dup_co_sysenv_arr( &g_co_sysenv ); - } - stCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv); - - stCoSysEnv_t name = { (char*)n,0 }; - - stCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp ); - - if( e ) - { - if( e->value ) - { - free( e->value ); - e->value = 0; - } - return 0; - } - } - - } - return g_sys_unsetenv_func( n ); -} -char *getenv( const char *n ) -{ - HOOK_SYS_FUNC( getenv ) - if( co_is_enable_sys_hook() && g_co_sysenv.data ) - { - stCoRoutine_t *self = co_self(); - - stCoSysEnv_t name = { (char*)n,0 }; - - if( !self->pvEnv ) - { - self->pvEnv = dup_co_sysenv_arr( &g_co_sysenv ); - } - stCoSysEnvArr_t *arr = (stCoSysEnvArr_t*)(self->pvEnv); - - stCoSysEnv_t *e = (stCoSysEnv_t*)bsearch( &name,arr->data,arr->cnt,sizeof(name),co_sysenv_comp ); - - if( e ) - { - return e->value; - } - - } - return g_sys_getenv_func( n ); - -} -struct hostent* co_gethostbyname(const char *name); - -struct hostent *gethostbyname(const char *name) -{ - HOOK_SYS_FUNC( gethostbyname ); - -#if defined( __APPLE__ ) || defined( __FreeBSD__ ) - return g_sys_gethostbyname_func( name ); -#else - if (!co_is_enable_sys_hook()) - { - return g_sys_gethostbyname_func(name); - } - return co_gethostbyname(name); -#endif - -} - - -struct res_state_wrap -{ - struct __res_state state; -}; -CO_ROUTINE_SPECIFIC(res_state_wrap, __co_state_wrap); - -extern "C" -{ - res_state __res_state() - { - HOOK_SYS_FUNC(__res_state); - - if (!co_is_enable_sys_hook()) - { - return g_sys___res_state_func(); - } - - return &(__co_state_wrap->state); - } - int __poll(struct pollfd fds[], nfds_t nfds, int timeout) - { - return poll(fds, nfds, timeout); - } -} - -struct hostbuf_wrap -{ - struct hostent host; - char* buffer; - size_t iBufferSize; - int host_errno; -}; - -CO_ROUTINE_SPECIFIC(hostbuf_wrap, __co_hostbuf_wrap); - -#if !defined( __APPLE__ ) && !defined( __FreeBSD__ ) -struct hostent *co_gethostbyname(const char *name) -{ - if (!name) - { - return NULL; - } - - if (__co_hostbuf_wrap->buffer && __co_hostbuf_wrap->iBufferSize > 1024) - { - free(__co_hostbuf_wrap->buffer); - __co_hostbuf_wrap->buffer = NULL; - } - if (!__co_hostbuf_wrap->buffer) - { - __co_hostbuf_wrap->buffer = (char*)malloc(1024); - __co_hostbuf_wrap->iBufferSize = 1024; - } - - struct hostent *host = &__co_hostbuf_wrap->host; - struct hostent *result = NULL; - int *h_errnop = &(__co_hostbuf_wrap->host_errno); - - int ret = -1; - while (ret = gethostbyname_r(name, host, __co_hostbuf_wrap->buffer, - __co_hostbuf_wrap->iBufferSize, &result, h_errnop) == ERANGE && - *h_errnop == NETDB_INTERNAL ) - { - free(__co_hostbuf_wrap->buffer); - __co_hostbuf_wrap->iBufferSize = __co_hostbuf_wrap->iBufferSize * 2; - __co_hostbuf_wrap->buffer = (char*)malloc(__co_hostbuf_wrap->iBufferSize); - } - - if (ret == 0 && (host == result)) - { - return host; - } - return NULL; -} -#endif - - -void co_enable_hook_sys() //这函数必须在这里,否则本文件会被忽略!!! -{ - stCoRoutine_t *co = GetCurrThreadCo(); - if( co ) - { - co->cEnableSysHook = 1; - } -} - diff --git a/trunk/3rdparty/libco/co_routine.cpp b/trunk/3rdparty/libco/co_routine.cpp deleted file mode 100644 index 352ae7ea0b..0000000000 --- a/trunk/3rdparty/libco/co_routine.cpp +++ /dev/null @@ -1,1196 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "co_routine.h" -#include "co_routine_inner.h" -#include "co_epoll.h" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -extern "C" -{ - extern void coctx_swap( coctx_t *,coctx_t* ) asm("coctx_swap"); -}; -using namespace std; -stCoRoutine_t *GetCurrCo( stCoRoutineEnv_t *env ); -struct stCoEpoll_t; - -struct stCoRoutineEnv_t -{ - stCoRoutine_t *pCallStack[ 128 ]; - int iCallStackSize; - stCoEpoll_t *pEpoll; - - //for copy stack log lastco and nextco - stCoRoutine_t* pending_co; - stCoRoutine_t* occupy_co; -}; -//int socket(int domain, int type, int protocol); -void co_log_err( const char *fmt,... ) -{ -} - - -#if defined( __LIBCO_RDTSCP__) -static unsigned long long counter(void) -{ - register uint32_t lo, hi; - register unsigned long long o; - __asm__ __volatile__ ( - "rdtscp" : "=a"(lo), "=d"(hi)::"%rcx" - ); - o = hi; - o <<= 32; - return (o | lo); - -} -static unsigned long long getCpuKhz() -{ - FILE *fp = fopen("/proc/cpuinfo","r"); - if(!fp) return 1; - char buf[4096] = {0}; - fread(buf,1,sizeof(buf),fp); - fclose(fp); - - char *lp = strstr(buf,"cpu MHz"); - if(!lp) return 1; - lp += strlen("cpu MHz"); - while(*lp == ' ' || *lp == '\t' || *lp == ':') - { - ++lp; - } - - double mhz = atof(lp); - unsigned long long u = (unsigned long long)(mhz * 1000); - return u; -} -#endif - -static unsigned long long GetTickMS() -{ -#if defined( __LIBCO_RDTSCP__) - static uint32_t khz = getCpuKhz(); - return counter() / khz; -#else - struct timeval now = { 0 }; - gettimeofday( &now,NULL ); - unsigned long long u = now.tv_sec; - u *= 1000; - u += now.tv_usec / 1000; - return u; -#endif -} - -/* no longer use -static pid_t GetPid() -{ - static __thread pid_t pid = 0; - static __thread pid_t tid = 0; - if( !pid || !tid || pid != getpid() ) - { - pid = getpid(); -#if defined( __APPLE__ ) - tid = syscall( SYS_gettid ); - if( -1 == (long)tid ) - { - tid = pid; - } -#elif defined( __FreeBSD__ ) - syscall(SYS_thr_self, &tid); - if( tid < 0 ) - { - tid = pid; - } -#else - tid = syscall( __NR_gettid ); -#endif - - } - return tid; - -} -static pid_t GetPid() -{ - char **p = (char**)pthread_self(); - return p ? *(pid_t*)(p + 18) : getpid(); -} -*/ -template -void RemoveFromLink(T *ap) -{ - TLink *lst = ap->pLink; - if(!lst) return ; - assert( lst->head && lst->tail ); - - if( ap == lst->head ) - { - lst->head = ap->pNext; - if(lst->head) - { - lst->head->pPrev = NULL; - } - } - else - { - if(ap->pPrev) - { - ap->pPrev->pNext = ap->pNext; - } - } - - if( ap == lst->tail ) - { - lst->tail = ap->pPrev; - if(lst->tail) - { - lst->tail->pNext = NULL; - } - } - else - { - ap->pNext->pPrev = ap->pPrev; - } - - ap->pPrev = ap->pNext = NULL; - ap->pLink = NULL; -} - -template -void inline AddTail(TLink*apLink,TNode *ap) -{ - if( ap->pLink ) - { - return ; - } - if(apLink->tail) - { - apLink->tail->pNext = (TNode*)ap; - ap->pNext = NULL; - ap->pPrev = apLink->tail; - apLink->tail = ap; - } - else - { - apLink->head = apLink->tail = ap; - ap->pNext = ap->pPrev = NULL; - } - ap->pLink = apLink; -} -template -void inline PopHead( TLink*apLink ) -{ - if( !apLink->head ) - { - return ; - } - TNode *lp = apLink->head; - if( apLink->head == apLink->tail ) - { - apLink->head = apLink->tail = NULL; - } - else - { - apLink->head = apLink->head->pNext; - } - - lp->pPrev = lp->pNext = NULL; - lp->pLink = NULL; - - if( apLink->head ) - { - apLink->head->pPrev = NULL; - } -} - -template -void inline Join( TLink*apLink,TLink *apOther ) -{ - //printf("apOther %p\n",apOther); - if( !apOther->head ) - { - return ; - } - TNode *lp = apOther->head; - while( lp ) - { - lp->pLink = apLink; - lp = lp->pNext; - } - lp = apOther->head; - if(apLink->tail) - { - apLink->tail->pNext = (TNode*)lp; - lp->pPrev = apLink->tail; - apLink->tail = apOther->tail; - } - else - { - apLink->head = apOther->head; - apLink->tail = apOther->tail; - } - - apOther->head = apOther->tail = NULL; -} - -/////////////////for copy stack ////////////////////////// -stStackMem_t* co_alloc_stackmem(unsigned int stack_size) -{ - stStackMem_t* stack_mem = (stStackMem_t*)malloc(sizeof(stStackMem_t)); - stack_mem->occupy_co= NULL; - stack_mem->stack_size = stack_size; - stack_mem->stack_buffer = (char*)malloc(stack_size); - stack_mem->stack_bp = stack_mem->stack_buffer + stack_size; - return stack_mem; -} - -stShareStack_t* co_alloc_sharestack(int count, int stack_size) -{ - stShareStack_t* share_stack = (stShareStack_t*)malloc(sizeof(stShareStack_t)); - share_stack->alloc_idx = 0; - share_stack->stack_size = stack_size; - - //alloc stack array - share_stack->count = count; - stStackMem_t** stack_array = (stStackMem_t**)calloc(count, sizeof(stStackMem_t*)); - for (int i = 0; i < count; i++) - { - stack_array[i] = co_alloc_stackmem(stack_size); - } - share_stack->stack_array = stack_array; - return share_stack; -} - -static stStackMem_t* co_get_stackmem(stShareStack_t* share_stack) -{ - if (!share_stack) - { - return NULL; - } - int idx = share_stack->alloc_idx % share_stack->count; - share_stack->alloc_idx++; - - return share_stack->stack_array[idx]; -} - - -// ---------------------------------------------------------------------------- -struct stTimeoutItemLink_t; -struct stTimeoutItem_t; -struct stCoEpoll_t -{ - int iEpollFd; - static const int _EPOLL_SIZE = 1024 * 10; - - struct stTimeout_t *pTimeout; - - struct stTimeoutItemLink_t *pstTimeoutList; - - struct stTimeoutItemLink_t *pstActiveList; - - co_epoll_res *result; - -}; -typedef void (*OnPreparePfn_t)( stTimeoutItem_t *,struct epoll_event &ev, stTimeoutItemLink_t *active ); -typedef void (*OnProcessPfn_t)( stTimeoutItem_t *); -struct stTimeoutItem_t -{ - - enum - { - eMaxTimeout = 40 * 1000 //40s - }; - stTimeoutItem_t *pPrev; - stTimeoutItem_t *pNext; - stTimeoutItemLink_t *pLink; - - unsigned long long ullExpireTime; - - OnPreparePfn_t pfnPrepare; - OnProcessPfn_t pfnProcess; - - void *pArg; // routine - bool bTimeout; -}; -struct stTimeoutItemLink_t -{ - stTimeoutItem_t *head; - stTimeoutItem_t *tail; - -}; -struct stTimeout_t -{ - stTimeoutItemLink_t *pItems; - int iItemSize; - - unsigned long long ullStart; - long long llStartIdx; -}; -stTimeout_t *AllocTimeout( int iSize ) -{ - stTimeout_t *lp = (stTimeout_t*)calloc( 1,sizeof(stTimeout_t) ); - - lp->iItemSize = iSize; - lp->pItems = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) * lp->iItemSize ); - - lp->ullStart = GetTickMS(); - lp->llStartIdx = 0; - - return lp; -} -void FreeTimeout( stTimeout_t *apTimeout ) -{ - free( apTimeout->pItems ); - free ( apTimeout ); -} -int AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,unsigned long long allNow ) -{ - if( apTimeout->ullStart == 0 ) - { - apTimeout->ullStart = allNow; - apTimeout->llStartIdx = 0; - } - if( allNow < apTimeout->ullStart ) - { - co_log_err("CO_ERR: AddTimeout line %d allNow %llu apTimeout->ullStart %llu", - __LINE__,allNow,apTimeout->ullStart); - - return __LINE__; - } - if( apItem->ullExpireTime < allNow ) - { - co_log_err("CO_ERR: AddTimeout line %d apItem->ullExpireTime %llu allNow %llu apTimeout->ullStart %llu", - __LINE__,apItem->ullExpireTime,allNow,apTimeout->ullStart); - - return __LINE__; - } - unsigned long long diff = apItem->ullExpireTime - apTimeout->ullStart; - - if( diff >= (unsigned long long)apTimeout->iItemSize ) - { - diff = apTimeout->iItemSize - 1; - co_log_err("CO_ERR: AddTimeout line %d diff %d", - __LINE__,diff); - - //return __LINE__; - } - AddTail( apTimeout->pItems + ( apTimeout->llStartIdx + diff ) % apTimeout->iItemSize , apItem ); - - return 0; -} -inline void TakeAllTimeout( stTimeout_t *apTimeout,unsigned long long allNow,stTimeoutItemLink_t *apResult ) -{ - if( apTimeout->ullStart == 0 ) - { - apTimeout->ullStart = allNow; - apTimeout->llStartIdx = 0; - } - - if( allNow < apTimeout->ullStart ) - { - return ; - } - int cnt = allNow - apTimeout->ullStart + 1; - if( cnt > apTimeout->iItemSize ) - { - cnt = apTimeout->iItemSize; - } - if( cnt < 0 ) - { - return; - } - for( int i = 0;illStartIdx + i) % apTimeout->iItemSize; - Join( apResult,apTimeout->pItems + idx ); - } - apTimeout->ullStart = allNow; - apTimeout->llStartIdx += cnt - 1; - - -} -static int CoRoutineFunc( stCoRoutine_t *co,void * ) -{ - if( co->pfn ) - { - co->pfn( co->arg ); - } - co->cEnd = 1; - - stCoRoutineEnv_t *env = co->env; - - co_yield_env( env ); - - return 0; -} - - - -struct stCoRoutine_t *co_create_env( stCoRoutineEnv_t * env, const stCoRoutineAttr_t* attr, - pfn_co_routine_t pfn,void *arg ) -{ - - stCoRoutineAttr_t at; - if( attr ) - { - memcpy( &at,attr,sizeof(at) ); - } - if( at.stack_size <= 0 ) - { - at.stack_size = 128 * 1024; - } - else if( at.stack_size > 1024 * 1024 * 8 ) - { - at.stack_size = 1024 * 1024 * 8; - } - - if( at.stack_size & 0xFFF ) - { - at.stack_size &= ~0xFFF; - at.stack_size += 0x1000; - } - - stCoRoutine_t *lp = (stCoRoutine_t*)malloc( sizeof(stCoRoutine_t) ); - - memset( lp,0,(long)(sizeof(stCoRoutine_t))); - - - lp->env = env; - lp->pfn = pfn; - lp->arg = arg; - - stStackMem_t* stack_mem = NULL; - if( at.share_stack ) - { - stack_mem = co_get_stackmem( at.share_stack); - at.stack_size = at.share_stack->stack_size; - } - else - { - stack_mem = co_alloc_stackmem(at.stack_size); - } - lp->stack_mem = stack_mem; - - lp->ctx.ss_sp = stack_mem->stack_buffer; - lp->ctx.ss_size = at.stack_size; - - lp->cStart = 0; - lp->cEnd = 0; - lp->cIsMain = 0; - lp->cEnableSysHook = 0; - lp->cIsShareStack = at.share_stack != NULL; - - lp->save_size = 0; - lp->save_buffer = NULL; - - return lp; -} - -int co_create( stCoRoutine_t **ppco,const stCoRoutineAttr_t *attr,pfn_co_routine_t pfn,void *arg ) -{ - if( !co_get_curr_thread_env() ) - { - co_init_curr_thread_env(); - } - stCoRoutine_t *co = co_create_env( co_get_curr_thread_env(), attr, pfn,arg ); - *ppco = co; - return 0; -} -void co_free( stCoRoutine_t *co ) -{ - if (!co->cIsShareStack) - { - free(co->stack_mem->stack_buffer); - free(co->stack_mem); - } - //walkerdu fix at 2018-01-20 - //瀛樺湪鍐呭瓨娉勬紡 - else - { - if(co->save_buffer) - free(co->save_buffer); - - if(co->stack_mem->occupy_co == co) - co->stack_mem->occupy_co = NULL; - } - - free( co ); -} -void co_release( stCoRoutine_t *co ) -{ - co_free( co ); -} - -void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co); - -void co_resume( stCoRoutine_t *co ) -{ - stCoRoutineEnv_t *env = co->env; - stCoRoutine_t *lpCurrRoutine = env->pCallStack[ env->iCallStackSize - 1 ]; - if( !co->cStart ) - { - coctx_make( &co->ctx,(coctx_pfn_t)CoRoutineFunc,co,0 ); - co->cStart = 1; - } - env->pCallStack[ env->iCallStackSize++ ] = co; - co_swap( lpCurrRoutine, co ); - - -} - - -// walkerdu 2018-01-14 -// 鐢ㄤ簬reset瓒呮椂鏃犳硶閲嶅浣跨敤鐨勫崗绋 -void co_reset(stCoRoutine_t * co) -{ - if(!co->cStart || co->cIsMain) - return; - - co->cStart = 0; - co->cEnd = 0; - - // 濡傛灉褰撳墠鍗忕▼鏈夊叡浜爤琚垏鍑虹殑buff锛岃杩涜閲婃斁 - if(co->save_buffer) - { - free(co->save_buffer); - co->save_buffer = NULL; - co->save_size = 0; - } - - // 濡傛灉鍏变韩鏍堣褰撳墠鍗忕▼鍗犵敤锛岃閲婃斁鍗犵敤鏍囧織锛屽惁鍒欒鍒囨崲锛屼細鎵цsave_stack_buffer() - if(co->stack_mem->occupy_co == co) - co->stack_mem->occupy_co = NULL; -} - -void co_yield_env( stCoRoutineEnv_t *env ) -{ - - stCoRoutine_t *last = env->pCallStack[ env->iCallStackSize - 2 ]; - stCoRoutine_t *curr = env->pCallStack[ env->iCallStackSize - 1 ]; - - env->iCallStackSize--; - - co_swap( curr, last); -} - -void co_yield_ct() -{ - - co_yield_env( co_get_curr_thread_env() ); -} -void co_yield( stCoRoutine_t *co ) -{ - co_yield_env( co->env ); -} - -void save_stack_buffer(stCoRoutine_t* occupy_co) -{ - ///copy out - stStackMem_t* stack_mem = occupy_co->stack_mem; - int len = stack_mem->stack_bp - occupy_co->stack_sp; - - if (occupy_co->save_buffer) - { - free(occupy_co->save_buffer), occupy_co->save_buffer = NULL; - } - - occupy_co->save_buffer = (char*)malloc(len); //malloc buf; - occupy_co->save_size = len; - - memcpy(occupy_co->save_buffer, occupy_co->stack_sp, len); -} - -void co_swap(stCoRoutine_t* curr, stCoRoutine_t* pending_co) -{ - stCoRoutineEnv_t* env = co_get_curr_thread_env(); - - //get curr stack sp - char c; - curr->stack_sp= &c; - - if (!pending_co->cIsShareStack) - { - env->pending_co = NULL; - env->occupy_co = NULL; - } - else - { - env->pending_co = pending_co; - //get last occupy co on the same stack mem - stCoRoutine_t* occupy_co = pending_co->stack_mem->occupy_co; - //set pending co to occupy thest stack mem; - pending_co->stack_mem->occupy_co = pending_co; - - env->occupy_co = occupy_co; - if (occupy_co && occupy_co != pending_co) - { - save_stack_buffer(occupy_co); - } - } - - //swap context - coctx_swap(&(curr->ctx),&(pending_co->ctx) ); - - //stack buffer may be overwrite, so get again; - stCoRoutineEnv_t* curr_env = co_get_curr_thread_env(); - stCoRoutine_t* update_occupy_co = curr_env->occupy_co; - stCoRoutine_t* update_pending_co = curr_env->pending_co; - - if (update_occupy_co && update_pending_co && update_occupy_co != update_pending_co) - { - //resume stack buffer - if (update_pending_co->save_buffer && update_pending_co->save_size > 0) - { - memcpy(update_pending_co->stack_sp, update_pending_co->save_buffer, update_pending_co->save_size); - } - } -} - - - -//int poll(struct pollfd fds[], nfds_t nfds, int timeout); -// { fd,events,revents } -struct stPollItem_t ; -struct stPoll_t : public stTimeoutItem_t -{ - struct pollfd *fds; - nfds_t nfds; // typedef unsigned long int nfds_t; - - stPollItem_t *pPollItems; - - int iAllEventDetach; - - int iEpollFd; - - int iRaiseCnt; - - -}; -struct stPollItem_t : public stTimeoutItem_t -{ - struct pollfd *pSelf; - stPoll_t *pPoll; - - struct epoll_event stEvent; -}; -/* - * EPOLLPRI POLLPRI // There is urgent data to read. - * EPOLLMSG POLLMSG - * - * POLLREMOVE - * POLLRDHUP - * POLLNVAL - * - * */ -static uint32_t PollEvent2Epoll( short events ) -{ - uint32_t e = 0; - if( events & POLLIN ) e |= EPOLLIN; - if( events & POLLOUT ) e |= EPOLLOUT; - if( events & POLLHUP ) e |= EPOLLHUP; - if( events & POLLERR ) e |= EPOLLERR; - if( events & POLLRDNORM ) e |= EPOLLRDNORM; - if( events & POLLWRNORM ) e |= EPOLLWRNORM; - return e; -} -static short EpollEvent2Poll( uint32_t events ) -{ - short e = 0; - if( events & EPOLLIN ) e |= POLLIN; - if( events & EPOLLOUT ) e |= POLLOUT; - if( events & EPOLLHUP ) e |= POLLHUP; - if( events & EPOLLERR ) e |= POLLERR; - if( events & EPOLLRDNORM ) e |= POLLRDNORM; - if( events & EPOLLWRNORM ) e |= POLLWRNORM; - return e; -} - -static __thread stCoRoutineEnv_t* gCoEnvPerThread = NULL; - -void co_init_curr_thread_env() -{ - gCoEnvPerThread = (stCoRoutineEnv_t*)calloc( 1, sizeof(stCoRoutineEnv_t) ); - stCoRoutineEnv_t *env = gCoEnvPerThread; - - env->iCallStackSize = 0; - struct stCoRoutine_t *self = co_create_env( env, NULL, NULL,NULL ); - self->cIsMain = 1; - - env->pending_co = NULL; - env->occupy_co = NULL; - - coctx_init( &self->ctx ); - - env->pCallStack[ env->iCallStackSize++ ] = self; - - stCoEpoll_t *ev = AllocEpoll(); - SetEpoll( env,ev ); -} -stCoRoutineEnv_t *co_get_curr_thread_env() -{ - return gCoEnvPerThread; -} - -void OnPollProcessEvent( stTimeoutItem_t * ap ) -{ - stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; - co_resume( co ); -} - -void OnPollPreparePfn( stTimeoutItem_t * ap,struct epoll_event &e,stTimeoutItemLink_t *active ) -{ - stPollItem_t *lp = (stPollItem_t *)ap; - lp->pSelf->revents = EpollEvent2Poll( e.events ); - - - stPoll_t *pPoll = lp->pPoll; - pPoll->iRaiseCnt++; - - if( !pPoll->iAllEventDetach ) - { - pPoll->iAllEventDetach = 1; - - RemoveFromLink( pPoll ); - - AddTail( active,pPoll ); - - } -} - - -void co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg ) -{ - if( !ctx->result ) - { - ctx->result = co_epoll_res_alloc( stCoEpoll_t::_EPOLL_SIZE ); - } - co_epoll_res *result = ctx->result; - - - for(;;) - { - int ret = co_epoll_wait( ctx->iEpollFd,result,stCoEpoll_t::_EPOLL_SIZE, 1 ); - - stTimeoutItemLink_t *active = (ctx->pstActiveList); - stTimeoutItemLink_t *timeout = (ctx->pstTimeoutList); - - memset( timeout,0,sizeof(stTimeoutItemLink_t) ); - - for(int i=0;ievents[i].data.ptr; - if( item->pfnPrepare ) - { - item->pfnPrepare( item,result->events[i],active ); - } - else - { - AddTail( active,item ); - } - } - - - unsigned long long now = GetTickMS(); - TakeAllTimeout( ctx->pTimeout,now,timeout ); - - stTimeoutItem_t *lp = timeout->head; - while( lp ) - { - //printf("raise timeout %p\n",lp); - lp->bTimeout = true; - lp = lp->pNext; - } - - Join( active,timeout ); - - lp = active->head; - while( lp ) - { - - PopHead( active ); - if (lp->bTimeout && now < lp->ullExpireTime) - { - int ret = AddTimeout(ctx->pTimeout, lp, now); - if (!ret) - { - lp->bTimeout = false; - lp = active->head; - continue; - } - } - if( lp->pfnProcess ) - { - lp->pfnProcess( lp ); - } - - lp = active->head; - } - if( pfn ) - { - if( -1 == pfn( arg ) ) - { - break; - } - } - - } -} -void OnCoroutineEvent( stTimeoutItem_t * ap ) -{ - stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; - co_resume( co ); -} - - -stCoEpoll_t *AllocEpoll() -{ - stCoEpoll_t *ctx = (stCoEpoll_t*)calloc( 1,sizeof(stCoEpoll_t) ); - - ctx->iEpollFd = co_epoll_create( stCoEpoll_t::_EPOLL_SIZE ); - ctx->pTimeout = AllocTimeout( 60 * 1000 ); - - ctx->pstActiveList = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) ); - ctx->pstTimeoutList = (stTimeoutItemLink_t*)calloc( 1,sizeof(stTimeoutItemLink_t) ); - - - return ctx; -} - -void FreeEpoll( stCoEpoll_t *ctx ) -{ - if( ctx ) - { - free( ctx->pstActiveList ); - free( ctx->pstTimeoutList ); - FreeTimeout( ctx->pTimeout ); - co_epoll_res_free( ctx->result ); - } - free( ctx ); -} - -stCoRoutine_t *GetCurrCo( stCoRoutineEnv_t *env ) -{ - return env->pCallStack[ env->iCallStackSize - 1 ]; -} -stCoRoutine_t *GetCurrThreadCo( ) -{ - stCoRoutineEnv_t *env = co_get_curr_thread_env(); - if( !env ) return 0; - return GetCurrCo(env); -} - - - -typedef int (*poll_pfn_t)(struct pollfd fds[], nfds_t nfds, int timeout); -int co_poll_inner( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout, poll_pfn_t pollfunc) -{ - if (timeout == 0) - { - return pollfunc(fds, nfds, timeout); - } - if (timeout < 0) - { - timeout = INT_MAX; - } - int epfd = ctx->iEpollFd; - stCoRoutine_t* self = co_self(); - - //1.struct change - stPoll_t& arg = *((stPoll_t*)malloc(sizeof(stPoll_t))); - memset( &arg,0,sizeof(arg) ); - - arg.iEpollFd = epfd; - arg.fds = (pollfd*)calloc(nfds, sizeof(pollfd)); - arg.nfds = nfds; - - stPollItem_t arr[2]; - if( nfds < sizeof(arr) / sizeof(arr[0]) && !self->cIsShareStack) - { - arg.pPollItems = arr; - } - else - { - arg.pPollItems = (stPollItem_t*)malloc( nfds * sizeof( stPollItem_t ) ); - } - memset( arg.pPollItems,0,nfds * sizeof(stPollItem_t) ); - - arg.pfnProcess = OnPollProcessEvent; - arg.pArg = GetCurrCo( co_get_curr_thread_env() ); - - - //2. add epoll - for(nfds_t i=0;i -1 ) - { - ev.data.ptr = arg.pPollItems + i; - ev.events = PollEvent2Epoll( fds[i].events ); - - int ret = co_epoll_ctl( epfd,EPOLL_CTL_ADD, fds[i].fd, &ev ); - if (ret < 0 && errno == EPERM && nfds == 1 && pollfunc != NULL) - { - if( arg.pPollItems != arr ) - { - free( arg.pPollItems ); - arg.pPollItems = NULL; - } - free(arg.fds); - free(&arg); - return pollfunc(fds, nfds, timeout); - } - } - //if fail,the timeout would work - } - - //3.add timeout - - unsigned long long now = GetTickMS(); - arg.ullExpireTime = now + timeout; - int ret = AddTimeout( ctx->pTimeout,&arg,now ); - int iRaiseCnt = 0; - if( ret != 0 ) - { - co_log_err("CO_ERR: AddTimeout ret %d now %lld timeout %d arg.ullExpireTime %lld", - ret,now,timeout,arg.ullExpireTime); - errno = EINVAL; - iRaiseCnt = -1; - - } - else - { - co_yield_env( co_get_curr_thread_env() ); - iRaiseCnt = arg.iRaiseCnt; - } - - { - //clear epoll status and memory - RemoveFromLink( &arg ); - for(nfds_t i = 0;i < nfds;i++) - { - int fd = fds[i].fd; - if( fd > -1 ) - { - co_epoll_ctl( epfd,EPOLL_CTL_DEL,fd,&arg.pPollItems[i].stEvent ); - } - fds[i].revents = arg.fds[i].revents; - } - - - if( arg.pPollItems != arr ) - { - free( arg.pPollItems ); - arg.pPollItems = NULL; - } - - free(arg.fds); - free(&arg); - } - - return iRaiseCnt; -} - -int co_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms ) -{ - return co_poll_inner(ctx, fds, nfds, timeout_ms, NULL); -} - -void SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev ) -{ - env->pEpoll = ev; -} -stCoEpoll_t *co_get_epoll_ct() -{ - if( !co_get_curr_thread_env() ) - { - co_init_curr_thread_env(); - } - return co_get_curr_thread_env()->pEpoll; -} -struct stHookPThreadSpec_t -{ - stCoRoutine_t *co; - void *value; - - enum - { - size = 1024 - }; -}; -void *co_getspecific(pthread_key_t key) -{ - stCoRoutine_t *co = GetCurrThreadCo(); - if( !co || co->cIsMain ) - { - return pthread_getspecific( key ); - } - return co->aSpec[ key ].value; -} -int co_setspecific(pthread_key_t key, const void *value) -{ - stCoRoutine_t *co = GetCurrThreadCo(); - if( !co || co->cIsMain ) - { - return pthread_setspecific( key,value ); - } - co->aSpec[ key ].value = (void*)value; - return 0; -} - - - -void co_disable_hook_sys() -{ - stCoRoutine_t *co = GetCurrThreadCo(); - if( co ) - { - co->cEnableSysHook = 0; - } -} -bool co_is_enable_sys_hook() -{ - stCoRoutine_t *co = GetCurrThreadCo(); - return ( co && co->cEnableSysHook ); -} - -stCoRoutine_t *co_self() -{ - return GetCurrThreadCo(); -} - -//co cond -struct stCoCond_t; -struct stCoCondItem_t -{ - stCoCondItem_t *pPrev; - stCoCondItem_t *pNext; - stCoCond_t *pLink; - - stTimeoutItem_t timeout; -}; -struct stCoCond_t -{ - stCoCondItem_t *head; - stCoCondItem_t *tail; -}; -static void OnSignalProcessEvent( stTimeoutItem_t * ap ) -{ - stCoRoutine_t *co = (stCoRoutine_t*)ap->pArg; - co_resume( co ); -} - -stCoCondItem_t *co_cond_pop( stCoCond_t *link ); -int co_cond_signal( stCoCond_t *si ) -{ - stCoCondItem_t * sp = co_cond_pop( si ); - if( !sp ) - { - return 0; - } - RemoveFromLink( &sp->timeout ); - - AddTail( co_get_curr_thread_env()->pEpoll->pstActiveList,&sp->timeout ); - - return 0; -} -int co_cond_broadcast( stCoCond_t *si ) -{ - for(;;) - { - stCoCondItem_t * sp = co_cond_pop( si ); - if( !sp ) return 0; - - RemoveFromLink( &sp->timeout ); - - AddTail( co_get_curr_thread_env()->pEpoll->pstActiveList,&sp->timeout ); - } - - return 0; -} - - -int co_cond_timedwait( stCoCond_t *link,int ms ) -{ - stCoCondItem_t* psi = (stCoCondItem_t*)calloc(1, sizeof(stCoCondItem_t)); - psi->timeout.pArg = GetCurrThreadCo(); - psi->timeout.pfnProcess = OnSignalProcessEvent; - - if( ms > 0 ) - { - unsigned long long now = GetTickMS(); - psi->timeout.ullExpireTime = now + ms; - - int ret = AddTimeout( co_get_curr_thread_env()->pEpoll->pTimeout,&psi->timeout,now ); - if( ret != 0 ) - { - free(psi); - return ret; - } - } - AddTail( link, psi); - - co_yield_ct(); - - - RemoveFromLink( psi ); - free(psi); - - return 0; -} -stCoCond_t *co_cond_alloc() -{ - return (stCoCond_t*)calloc( 1,sizeof(stCoCond_t) ); -} -int co_cond_free( stCoCond_t * cc ) -{ - free( cc ); - return 0; -} - - -stCoCondItem_t *co_cond_pop( stCoCond_t *link ) -{ - stCoCondItem_t *p = link->head; - if( p ) - { - PopHead( link ); - } - return p; -} diff --git a/trunk/3rdparty/libco/co_routine.h b/trunk/3rdparty/libco/co_routine.h deleted file mode 100644 index d6f478928a..0000000000 --- a/trunk/3rdparty/libco/co_routine.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#ifndef __CO_ROUTINE_H__ -#define __CO_ROUTINE_H__ - -#include -#include -#include - -//1.struct - -struct stCoRoutine_t; -struct stShareStack_t; - -struct stCoRoutineAttr_t -{ - int stack_size; - stShareStack_t* share_stack; - stCoRoutineAttr_t() - { - stack_size = 128 * 1024; - share_stack = NULL; - } -}__attribute__ ((packed)); - -struct stCoEpoll_t; -typedef int (*pfn_co_eventloop_t)(void *); -typedef void *(*pfn_co_routine_t)( void * ); - -//2.co_routine - -int co_create( stCoRoutine_t **co,const stCoRoutineAttr_t *attr,void *(*routine)(void*),void *arg ); -void co_resume( stCoRoutine_t *co ); -void co_yield( stCoRoutine_t *co ); -void co_yield_ct(); //ct = current thread -void co_release( stCoRoutine_t *co ); -void co_reset(stCoRoutine_t * co); - -stCoRoutine_t *co_self(); - -int co_poll( stCoEpoll_t *ctx,struct pollfd fds[], nfds_t nfds, int timeout_ms ); -void co_eventloop( stCoEpoll_t *ctx,pfn_co_eventloop_t pfn,void *arg ); - -//3.specific - -int co_setspecific( pthread_key_t key, const void *value ); -void * co_getspecific( pthread_key_t key ); - -//4.event - -stCoEpoll_t * co_get_epoll_ct(); //ct = current thread - -//5.hook syscall ( poll/read/write/recv/send/recvfrom/sendto ) - -void co_enable_hook_sys(); -void co_disable_hook_sys(); -bool co_is_enable_sys_hook(); - -//6.sync -struct stCoCond_t; - -stCoCond_t *co_cond_alloc(); -int co_cond_free( stCoCond_t * cc ); - -int co_cond_signal( stCoCond_t * ); -int co_cond_broadcast( stCoCond_t * ); -int co_cond_timedwait( stCoCond_t *,int timeout_ms ); - -//7.share stack -stShareStack_t* co_alloc_sharestack(int iCount, int iStackSize); - -//8.init envlist for hook get/set env -void co_set_env_list( const char *name[],size_t cnt); - -void co_log_err( const char *fmt,... ); -#endif - diff --git a/trunk/3rdparty/libco/co_routine_inner.h b/trunk/3rdparty/libco/co_routine_inner.h deleted file mode 100644 index 9d0e092de2..0000000000 --- a/trunk/3rdparty/libco/co_routine_inner.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -#ifndef __CO_ROUTINE_INNER_H__ - -#include "co_routine.h" -#include "coctx.h" -struct stCoRoutineEnv_t; -struct stCoSpec_t -{ - void *value; -}; - -struct stStackMem_t -{ - stCoRoutine_t* occupy_co; - int stack_size; - char* stack_bp; //stack_buffer + stack_size - char* stack_buffer; - -}; - -struct stShareStack_t -{ - unsigned int alloc_idx; - int stack_size; - int count; - stStackMem_t** stack_array; -}; - - - -struct stCoRoutine_t -{ - stCoRoutineEnv_t *env; - pfn_co_routine_t pfn; - void *arg; - coctx_t ctx; - - char cStart; - char cEnd; - char cIsMain; - char cEnableSysHook; - char cIsShareStack; - - void *pvEnv; - - //char sRunStack[ 1024 * 128 ]; - stStackMem_t* stack_mem; - - - //save satck buffer while confilct on same stack_buffer; - char* stack_sp; - unsigned int save_size; - char* save_buffer; - - stCoSpec_t aSpec[1024]; - -}; - - - -//1.env -void co_init_curr_thread_env(); -stCoRoutineEnv_t * co_get_curr_thread_env(); - -//2.coroutine -void co_free( stCoRoutine_t * co ); -void co_yield_env( stCoRoutineEnv_t *env ); - -//3.func - - - -//----------------------------------------------------------------------------------------------- - -struct stTimeout_t; -struct stTimeoutItem_t ; - -stTimeout_t *AllocTimeout( int iSize ); -void FreeTimeout( stTimeout_t *apTimeout ); -int AddTimeout( stTimeout_t *apTimeout,stTimeoutItem_t *apItem ,uint64_t allNow ); - -struct stCoEpoll_t; -stCoEpoll_t * AllocEpoll(); -void FreeEpoll( stCoEpoll_t *ctx ); - -stCoRoutine_t * GetCurrThreadCo(); -void SetEpoll( stCoRoutineEnv_t *env,stCoEpoll_t *ev ); - -typedef void (*pfnCoRoutineFunc_t)(); - -#endif - -#define __CO_ROUTINE_INNER_H__ diff --git a/trunk/3rdparty/libco/co_routine_specific.h b/trunk/3rdparty/libco/co_routine_specific.h deleted file mode 100644 index 1b451caa52..0000000000 --- a/trunk/3rdparty/libco/co_routine_specific.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#include -#include - -/* -invoke only once in the whole program -CoRoutineSetSpecificCallBack(CoRoutineGetSpecificFunc_t pfnGet,CoRoutineSetSpecificFunc_t pfnSet) - -struct MyData_t -{ - int iValue; - char szValue[100]; -}; -CO_ROUTINE_SPECIFIC( MyData_t,__routine ); - -int main() -{ - CoRoutineSetSpecificCallBack( co_getspecific,co_setspecific ); - - __routine->iValue = 10; - strcpy( __routine->szValue,"hello world" ); - - return 0; -} -*/ -extern int co_setspecific( pthread_key_t key, const void *value ); -extern void * co_getspecific( pthread_key_t key ); - -#define CO_ROUTINE_SPECIFIC( name,y ) \ -\ -static pthread_once_t _routine_once_##name = PTHREAD_ONCE_INIT; \ -static pthread_key_t _routine_key_##name;\ -static int _routine_init_##name = 0;\ -static void _routine_make_key_##name() \ -{\ - (void) pthread_key_create(&_routine_key_##name, NULL); \ -}\ -template \ -class clsRoutineData_routine_##name\ -{\ -public:\ - inline T *operator->()\ - {\ - if( !_routine_init_##name ) \ - {\ - pthread_once( &_routine_once_##name,_routine_make_key_##name );\ - _routine_init_##name = 1;\ - }\ - T* p = (T*)co_getspecific( _routine_key_##name );\ - if( !p )\ - {\ - p = (T*)calloc(1,sizeof( T ));\ - int ret = co_setspecific( _routine_key_##name,p) ;\ - if ( ret )\ - {\ - if ( p )\ - {\ - free(p);\ - p = NULL;\ - }\ - }\ - }\ - return p;\ - }\ -};\ -\ -static clsRoutineData_routine_##name y; - diff --git a/trunk/3rdparty/libco/coctx.cpp b/trunk/3rdparty/libco/coctx.cpp deleted file mode 100644 index d5eeed1486..0000000000 --- a/trunk/3rdparty/libco/coctx.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco -available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "coctx.h" -#include -#include - -#define ESP 0 -#define EIP 1 -#define EAX 2 -#define ECX 3 -// ----------- -#define RSP 0 -#define RIP 1 -#define RBX 2 -#define RDI 3 -#define RSI 4 - -#define RBP 5 -#define R12 6 -#define R13 7 -#define R14 8 -#define R15 9 -#define RDX 10 -#define RCX 11 -#define R8 12 -#define R9 13 - -//----- -------- -// 32 bit -// | regs[0]: ret | -// | regs[1]: ebx | -// | regs[2]: ecx | -// | regs[3]: edx | -// | regs[4]: edi | -// | regs[5]: esi | -// | regs[6]: ebp | -// | regs[7]: eax | = esp -enum { - kEIP = 0, - kEBP = 6, - kESP = 7, -}; - -//------------- -// 64 bit -// low | regs[0]: r15 | -// | regs[1]: r14 | -// | regs[2]: r13 | -// | regs[3]: r12 | -// | regs[4]: r9 | -// | regs[5]: r8 | -// | regs[6]: rbp | -// | regs[7]: rdi | -// | regs[8]: rsi | -// | regs[9]: ret | //ret func addr -// | regs[10]: rdx | -// | regs[11]: rcx | -// | regs[12]: rbx | -// hig | regs[13]: rsp | -enum { - kRDI = 7, - kRSI = 8, - kRETAddr = 9, - kRSP = 13, -}; - -// 64 bit -extern "C" { -extern void coctx_swap(coctx_t*, coctx_t*) asm("coctx_swap"); -}; -#if defined(__i386__) -int coctx_init(coctx_t* ctx) { - memset(ctx, 0, sizeof(*ctx)); - return 0; -} -int coctx_make(coctx_t* ctx, coctx_pfn_t pfn, const void* s, const void* s1) { - // make room for coctx_param - char* sp = ctx->ss_sp + ctx->ss_size - sizeof(coctx_param_t); - sp = (char*)((unsigned long)sp & -16L); - - coctx_param_t* param = (coctx_param_t*)sp; - void** ret_addr = (void**)(sp - sizeof(void*) * 2); - *ret_addr = (void*)pfn; - param->s1 = s; - param->s2 = s1; - - memset(ctx->regs, 0, sizeof(ctx->regs)); - - ctx->regs[kESP] = (char*)(sp) - sizeof(void*) * 2; - return 0; -} -#elif defined(__x86_64__) -int coctx_make(coctx_t* ctx, coctx_pfn_t pfn, const void* s, const void* s1) { - char* sp = ctx->ss_sp + ctx->ss_size - sizeof(void*); - sp = (char*)((unsigned long)sp & -16LL); - - memset(ctx->regs, 0, sizeof(ctx->regs)); - void** ret_addr = (void**)(sp); - *ret_addr = (void*)pfn; - - ctx->regs[kRSP] = sp; - - ctx->regs[kRETAddr] = (char*)pfn; - - ctx->regs[kRDI] = (char*)s; - ctx->regs[kRSI] = (char*)s1; - return 0; -} - -int coctx_init(coctx_t* ctx) { - memset(ctx, 0, sizeof(*ctx)); - return 0; -} - -#endif diff --git a/trunk/3rdparty/libco/coctx.h b/trunk/3rdparty/libco/coctx.h deleted file mode 100644 index c1fdfa9da9..0000000000 --- a/trunk/3rdparty/libco/coctx.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#ifndef __CO_CTX_H__ -#define __CO_CTX_H__ -#include -typedef void* (*coctx_pfn_t)( void* s, void* s2 ); -struct coctx_param_t -{ - const void *s1; - const void *s2; -}; -struct coctx_t -{ -#if defined(__i386__) - void *regs[ 8 ]; -#else - void *regs[ 14 ]; -#endif - size_t ss_size; - char *ss_sp; - -}; - -int coctx_init( coctx_t *ctx ); -int coctx_make( coctx_t *ctx,coctx_pfn_t pfn,const void *s,const void *s1 ); -#endif diff --git a/trunk/3rdparty/libco/coctx_swap.S b/trunk/3rdparty/libco/coctx_swap.S deleted file mode 100644 index 0e4ce1c92b..0000000000 --- a/trunk/3rdparty/libco/coctx_swap.S +++ /dev/null @@ -1,83 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -.globl coctx_swap -#if !defined( __APPLE__ ) -.type coctx_swap, @function -#endif -coctx_swap: - -#if defined(__i386__) - movl 4(%esp), %eax - movl %esp, 28(%eax) - movl %ebp, 24(%eax) - movl %esi, 20(%eax) - movl %edi, 16(%eax) - movl %edx, 12(%eax) - movl %ecx, 8(%eax) - movl %ebx, 4(%eax) - - - movl 8(%esp), %eax - movl 4(%eax), %ebx - movl 8(%eax), %ecx - movl 12(%eax), %edx - movl 16(%eax), %edi - movl 20(%eax), %esi - movl 24(%eax), %ebp - movl 28(%eax), %esp - - ret - -#elif defined(__x86_64__) - leaq (%rsp),%rax - movq %rax, 104(%rdi) - movq %rbx, 96(%rdi) - movq %rcx, 88(%rdi) - movq %rdx, 80(%rdi) - movq 0(%rax), %rax - movq %rax, 72(%rdi) - movq %rsi, 64(%rdi) - movq %rdi, 56(%rdi) - movq %rbp, 48(%rdi) - movq %r8, 40(%rdi) - movq %r9, 32(%rdi) - movq %r12, 24(%rdi) - movq %r13, 16(%rdi) - movq %r14, 8(%rdi) - movq %r15, (%rdi) - xorq %rax, %rax - - movq 48(%rsi), %rbp - movq 104(%rsi), %rsp - movq (%rsi), %r15 - movq 8(%rsi), %r14 - movq 16(%rsi), %r13 - movq 24(%rsi), %r12 - movq 32(%rsi), %r9 - movq 40(%rsi), %r8 - movq 56(%rsi), %rdi - movq 80(%rsi), %rdx - movq 88(%rsi), %rcx - movq 96(%rsi), %rbx - leaq 8(%rsp), %rsp - pushq 72(%rsi) - - movq 64(%rsi), %rsi - ret -#endif diff --git a/trunk/3rdparty/libco/example_closure.cpp b/trunk/3rdparty/libco/example_closure.cpp deleted file mode 100644 index c5bae1cc4b..0000000000 --- a/trunk/3rdparty/libco/example_closure.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "co_closure.h" -#include -#include -#include -#include -#include -using namespace std; - -static void *thread_func( void * arg ) -{ - stCoClosure_t *p = (stCoClosure_t*) arg; - p->exec(); - return 0; -} -static void batch_exec( vector &v ) -{ - vector ths; - for( size_t i=0;i v; - - pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; - - int total = 100; - vector v2; - co_ref( ref,total,v2,m); - for(int i=0;i<10;i++) - { - co_func( f,ref,i ) - { - printf("ref.total %d i %d\n",ref.total,i ); - //lock - pthread_mutex_lock(&ref.m); - ref.v2.push_back( i ); - pthread_mutex_unlock(&ref.m); - //unlock - } - co_func_end; - v.push_back( new f( ref,i ) ); - } - for(int i=0;i<2;i++) - { - co_func( f2,i ) - { - printf("i: %d\n",i); - for(int j=0;j<2;j++) - { - usleep( 1000 ); - printf("i %d j %d\n",i,j); - } - } - co_func_end; - v.push_back( new f2( i ) ); - } - - batch_exec( v ); - printf("done\n"); - - return 0; -} - - diff --git a/trunk/3rdparty/libco/example_cond.cpp b/trunk/3rdparty/libco/example_cond.cpp deleted file mode 100644 index 5262568074..0000000000 --- a/trunk/3rdparty/libco/example_cond.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include -#include -#include -#include "co_routine.h" -using namespace std; -struct stTask_t -{ - int id; -}; -struct stEnv_t -{ - stCoCond_t* cond; - queue task_queue; -}; -void* Producer(void* args) -{ - co_enable_hook_sys(); - stEnv_t* env= (stEnv_t*)args; - int id = 0; - while (true) - { - stTask_t* task = (stTask_t*)calloc(1, sizeof(stTask_t)); - task->id = id++; - env->task_queue.push(task); - printf("%s:%d produce task %d\n", __func__, __LINE__, task->id); - co_cond_signal(env->cond); - poll(NULL, 0, 1000); - } - return NULL; -} -void* Consumer(void* args) -{ - co_enable_hook_sys(); - stEnv_t* env = (stEnv_t*)args; - while (true) - { - if (env->task_queue.empty()) - { - co_cond_timedwait(env->cond, -1); - continue; - } - stTask_t* task = env->task_queue.front(); - env->task_queue.pop(); - printf("%s:%d consume task %d\n", __func__, __LINE__, task->id); - free(task); - } - return NULL; -} -int main() -{ - stEnv_t* env = new stEnv_t; - env->cond = co_cond_alloc(); - - stCoRoutine_t* consumer_routine; - co_create(&consumer_routine, NULL, Consumer, env); - co_resume(consumer_routine); - - stCoRoutine_t* producer_routine; - co_create(&producer_routine, NULL, Producer, env); - co_resume(producer_routine); - - co_eventloop(co_get_epoll_ct(), NULL, NULL); - return 0; -} diff --git a/trunk/3rdparty/libco/example_copystack.cpp b/trunk/3rdparty/libco/example_copystack.cpp deleted file mode 100644 index 92062a6ea4..0000000000 --- a/trunk/3rdparty/libco/example_copystack.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include -#include -#include -#include -#include -#include "coctx.h" -#include "co_routine.h" -#include "co_routine_inner.h" - -void* RoutineFunc(void* args) -{ - co_enable_hook_sys(); - int* routineid = (int*)args; - while (true) - { - char sBuff[128]; - sprintf(sBuff, "from routineid %d stack addr %p\n", *routineid, sBuff); - - printf("%s", sBuff); - poll(NULL, 0, 1000); //sleep 1s - } - return NULL; -} - -int main() -{ - stShareStack_t* share_stack= co_alloc_sharestack(1, 1024 * 128); - stCoRoutineAttr_t attr; - attr.stack_size = 0; - attr.share_stack = share_stack; - - stCoRoutine_t* co[2]; - int routineid[2]; - for (int i = 0; i < 2; i++) - { - routineid[i] = i; - co_create(&co[i], &attr, RoutineFunc, routineid + i); - co_resume(co[i]); - } - co_eventloop(co_get_epoll_ct(), NULL, NULL); - return 0; -} diff --git a/trunk/3rdparty/libco/example_echocli.cpp b/trunk/3rdparty/libco/example_echocli.cpp deleted file mode 100644 index 083c1e7009..0000000000 --- a/trunk/3rdparty/libco/example_echocli.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "co_routine.h" - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -struct stEndPoint -{ - char *ip; - unsigned short int port; -}; - -static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr) -{ - bzero(&addr,sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(shPort); - int nIP = 0; - if( !pszIP || '\0' == *pszIP - || 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0") - || 0 == strcmp(pszIP,"*") - ) - { - nIP = htonl(INADDR_ANY); - } - else - { - nIP = inet_addr(pszIP); - } - addr.sin_addr.s_addr = nIP; - -} - -static int iSuccCnt = 0; -static int iFailCnt = 0; -static int iTime = 0; - -void AddSuccCnt() -{ - int now = time(NULL); - if (now >iTime) - { - printf("time %d Succ Cnt %d Fail Cnt %d\n", iTime, iSuccCnt, iFailCnt); - iTime = now; - iSuccCnt = 0; - iFailCnt = 0; - } - else - { - iSuccCnt++; - } -} -void AddFailCnt() -{ - int now = time(NULL); - if (now >iTime) - { - printf("time %d Succ Cnt %d Fail Cnt %d\n", iTime, iSuccCnt, iFailCnt); - iTime = now; - iSuccCnt = 0; - iFailCnt = 0; - } - else - { - iFailCnt++; - } -} - -static void *readwrite_routine( void *arg ) -{ - - co_enable_hook_sys(); - - stEndPoint *endpoint = (stEndPoint *)arg; - char str[8]="sarlmol"; - char buf[ 1024 * 16 ]; - int fd = -1; - int ret = 0; - for(;;) - { - if ( fd < 0 ) - { - fd = socket(PF_INET, SOCK_STREAM, 0); - struct sockaddr_in addr; - SetAddr(endpoint->ip, endpoint->port, addr); - ret = connect(fd,(struct sockaddr*)&addr,sizeof(addr)); - - if ( errno == EALREADY || errno == EINPROGRESS ) - { - struct pollfd pf = { 0 }; - pf.fd = fd; - pf.events = (POLLOUT|POLLERR|POLLHUP); - co_poll( co_get_epoll_ct(),&pf,1,200); - //check connect - int error = 0; - uint32_t socklen = sizeof(error); - errno = 0; - ret = getsockopt(fd, SOL_SOCKET, SO_ERROR,(void *)&error, &socklen); - if ( ret == -1 ) - { - //printf("getsockopt ERROR ret %d %d:%s\n", ret, errno, strerror(errno)); - close(fd); - fd = -1; - AddFailCnt(); - continue; - } - if ( error ) - { - errno = error; - //printf("connect ERROR ret %d %d:%s\n", error, errno, strerror(errno)); - close(fd); - fd = -1; - AddFailCnt(); - continue; - } - } - - } - - ret = write( fd,str, 8); - if ( ret > 0 ) - { - ret = read( fd,buf, sizeof(buf) ); - if ( ret <= 0 ) - { - //printf("co %p read ret %d errno %d (%s)\n", - // co_self(), ret,errno,strerror(errno)); - close(fd); - fd = -1; - AddFailCnt(); - } - else - { - //printf("echo %s fd %d\n", buf,fd); - AddSuccCnt(); - } - } - else - { - //printf("co %p write ret %d errno %d (%s)\n", - // co_self(), ret,errno,strerror(errno)); - close(fd); - fd = -1; - AddFailCnt(); - } - } - return 0; -} - -int main(int argc,char *argv[]) -{ - stEndPoint endpoint; - endpoint.ip = argv[1]; - endpoint.port = atoi(argv[2]); - int cnt = atoi( argv[3] ); - int proccnt = atoi( argv[4] ); - - struct sigaction sa; - sa.sa_handler = SIG_IGN; - sigaction( SIGPIPE, &sa, NULL ); - - for(int k=0;k 0 ) - { - continue; - } - else if( pid < 0 ) - { - break; - } - for(int i=0;i -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __FreeBSD__ -#include -#include -#include -#endif - -using namespace std; -struct task_t -{ - stCoRoutine_t *co; - int fd; -}; - -static stack g_readwrite; -static int g_listen_fd = -1; -static int SetNonBlock(int iSock) -{ - int iFlags; - - iFlags = fcntl(iSock, F_GETFL, 0); - iFlags |= O_NONBLOCK; - iFlags |= O_NDELAY; - int ret = fcntl(iSock, F_SETFL, iFlags); - return ret; -} - -static void *readwrite_routine( void *arg ) -{ - - co_enable_hook_sys(); - - task_t *co = (task_t*)arg; - char buf[ 1024 * 16 ]; - for(;;) - { - if( -1 == co->fd ) - { - g_readwrite.push( co ); - co_yield_ct(); - continue; - } - - int fd = co->fd; - co->fd = -1; - - for(;;) - { - struct pollfd pf = { 0 }; - pf.fd = fd; - pf.events = (POLLIN|POLLERR|POLLHUP); - co_poll( co_get_epoll_ct(),&pf,1,1000); - - int ret = read( fd,buf,sizeof(buf) ); - if( ret > 0 ) - { - ret = write( fd,buf,ret ); - } - if( ret > 0 || ( -1 == ret && EAGAIN == errno ) ) - { - continue; - } - close( fd ); - break; - } - - } - return 0; -} -int co_accept(int fd, struct sockaddr *addr, socklen_t *len ); -static void *accept_routine( void * ) -{ - co_enable_hook_sys(); - printf("accept_routine\n"); - fflush(stdout); - for(;;) - { - //printf("pid %ld g_readwrite.size %ld\n",getpid(),g_readwrite.size()); - if( g_readwrite.empty() ) - { - printf("empty\n"); //sleep - struct pollfd pf = { 0 }; - pf.fd = -1; - poll( &pf,1,1000); - - continue; - - } - struct sockaddr_in addr; //maybe sockaddr_un; - memset( &addr,0,sizeof(addr) ); - socklen_t len = sizeof(addr); - - int fd = co_accept(g_listen_fd, (struct sockaddr *)&addr, &len); - if( fd < 0 ) - { - struct pollfd pf = { 0 }; - pf.fd = g_listen_fd; - pf.events = (POLLIN|POLLERR|POLLHUP); - co_poll( co_get_epoll_ct(),&pf,1,1000 ); - continue; - } - if( g_readwrite.empty() ) - { - close( fd ); - continue; - } - SetNonBlock( fd ); - task_t *co = g_readwrite.top(); - co->fd = fd; - g_readwrite.pop(); - co_resume( co->co ); - } - return 0; -} - -static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr) -{ - bzero(&addr,sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(shPort); - int nIP = 0; - if( !pszIP || '\0' == *pszIP - || 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0") - || 0 == strcmp(pszIP,"*") - ) - { - nIP = htonl(INADDR_ANY); - } - else - { - nIP = inet_addr(pszIP); - } - addr.sin_addr.s_addr = nIP; - -} - -static int CreateTcpSocket(const unsigned short shPort /* = 0 */,const char *pszIP /* = "*" */,bool bReuse /* = false */) -{ - int fd = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP); - if( fd >= 0 ) - { - if(shPort != 0) - { - if(bReuse) - { - int nReuseAddr = 1; - setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&nReuseAddr,sizeof(nReuseAddr)); - } - struct sockaddr_in addr ; - SetAddr(pszIP,shPort,addr); - int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr)); - if( ret != 0) - { - close(fd); - return -1; - } - } - } - return fd; -} - - -int main(int argc,char *argv[]) -{ - if(argc<5){ - printf("Usage:\n" - "example_echosvr [IP] [PORT] [TASK_COUNT] [PROCESS_COUNT]\n" - "example_echosvr [IP] [PORT] [TASK_COUNT] [PROCESS_COUNT] -d # daemonize mode\n"); - return -1; - } - const char *ip = argv[1]; - int port = atoi( argv[2] ); - int cnt = atoi( argv[3] ); - int proccnt = atoi( argv[4] ); - bool deamonize = argc >= 6 && strcmp(argv[5], "-d") == 0; - - g_listen_fd = CreateTcpSocket( port,ip,true ); - listen( g_listen_fd,1024 ); - if(g_listen_fd==-1){ - printf("Port %d is in use\n", port); - return -1; - } - printf("listen %d %s:%d\n",g_listen_fd,ip,port); - - SetNonBlock( g_listen_fd ); - - for(int k=0;k 0 ) - { - continue; - } - else if( pid < 0 ) - { - break; - } - for(int i=0;ifd = -1; - - co_create( &(task->co),NULL,readwrite_routine,task ); - co_resume( task->co ); - - } - stCoRoutine_t *accept_co = NULL; - co_create( &accept_co,NULL,accept_routine,0 ); - co_resume( accept_co ); - - co_eventloop( co_get_epoll_ct(),0,0 ); - - exit(0); - } - if(!deamonize) wait(NULL); - return 0; -} - diff --git a/trunk/3rdparty/libco/example_poll.cpp b/trunk/3rdparty/libco/example_poll.cpp deleted file mode 100644 index eb92f219e7..0000000000 --- a/trunk/3rdparty/libco/example_poll.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "co_routine.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __FreeBSD__ -#include -#endif - -using namespace std; - -struct task_t -{ - stCoRoutine_t *co; - int fd; - struct sockaddr_in addr; -}; - -static int SetNonBlock(int iSock) -{ - int iFlags; - - iFlags = fcntl(iSock, F_GETFL, 0); - iFlags |= O_NONBLOCK; - iFlags |= O_NDELAY; - int ret = fcntl(iSock, F_SETFL, iFlags); - return ret; -} - - - -static void SetAddr(const char *pszIP,const unsigned short shPort,struct sockaddr_in &addr) -{ - bzero(&addr,sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(shPort); - int nIP = 0; - if( !pszIP || '\0' == *pszIP - || 0 == strcmp(pszIP,"0") || 0 == strcmp(pszIP,"0.0.0.0") - || 0 == strcmp(pszIP,"*") - ) - { - nIP = htonl(INADDR_ANY); - } - else - { - nIP = inet_addr(pszIP); - } - addr.sin_addr.s_addr = nIP; - -} - -static int CreateTcpSocket(const unsigned short shPort = 0 ,const char *pszIP = "*" ,bool bReuse = false ) -{ - int fd = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP); - if( fd >= 0 ) - { - if(shPort != 0) - { - if(bReuse) - { - int nReuseAddr = 1; - setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&nReuseAddr,sizeof(nReuseAddr)); - } - struct sockaddr_in addr ; - SetAddr(pszIP,shPort,addr); - int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr)); - if( ret != 0) - { - close(fd); - return -1; - } - } - } - return fd; -} - -static void *poll_routine( void *arg ) -{ - co_enable_hook_sys(); - - vector &v = *(vector*)arg; - for(size_t i=0;i setRaiseFds; - size_t iWaitCnt = v.size(); - for(;;) - { - int ret = poll( pf,iWaitCnt,1000 ); - printf("co %p poll wait %ld ret %d\n", - co_self(),iWaitCnt,ret); - for(int i=0;i<(int)iWaitCnt;i++) - { - printf("co %p fire fd %d revents 0x%X POLLOUT 0x%X POLLERR 0x%X POLLHUP 0x%X\n", - co_self(), - pf[i].fd, - pf[i].revents, - POLLOUT, - POLLERR, - POLLHUP - ); - setRaiseFds.insert( pf[i].fd ); - } - if( setRaiseFds.size() == v.size()) - { - break; - } - if( ret <= 0 ) - { - break; - } - - iWaitCnt = 0; - for(size_t i=0;i v; - for(int i=1;i v2 = v; - poll_routine( &v2 ); - printf("--------------------- routine -------------------\n"); - - for(int i=0;i<10;i++) - { - stCoRoutine_t *co = 0; - vector *v2 = new vector(); - *v2 = v; - co_create( &co,NULL,poll_routine,v2 ); - printf("routine i %d\n",i); - co_resume( co ); - } - - co_eventloop( co_get_epoll_ct(),0,0 ); - - return 0; -} -//./example_poll 127.0.0.1 12365 127.0.0.1 12222 192.168.1.1 1000 192.168.1.2 1111 - diff --git a/trunk/3rdparty/libco/example_setenv.cpp b/trunk/3rdparty/libco/example_setenv.cpp deleted file mode 100644 index 520cfb6333..0000000000 --- a/trunk/3rdparty/libco/example_setenv.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include -#include -#include -#include -#include -#include -#include "co_routine.h" - -const char* CGI_ENV_HOOK_LIST [] = -{ - "CGINAME", -}; -struct stRoutineArgs_t -{ - int iRoutineID; -}; -void SetAndGetEnv(int iRoutineID) -{ - printf("routineid %d begin\n", iRoutineID); - - //use poll as sleep - poll(NULL, 0, 500); - - char sBuf[128]; - sprintf(sBuf, "cgi_routine_%d", iRoutineID); - int ret = setenv("CGINAME", sBuf, 1); - if (ret) - { - printf("%s:%d set env err ret %d errno %d %s\n", __func__, __LINE__, - ret, errno, strerror(errno)); - return; - } - printf("routineid %d set env CGINAME %s\n", iRoutineID, sBuf); - - poll(NULL, 0, 500); - - char* env = getenv("CGINAME"); - if (!env) - { - printf("%s:%d get env err errno %d %s\n", __func__, __LINE__, - errno, strerror(errno)); - return; - } - printf("routineid %d get env CGINAME %s\n", iRoutineID, env); -} - -void* RoutineFunc(void* args) -{ - co_enable_hook_sys(); - - stRoutineArgs_t* g = (stRoutineArgs_t*)args; - - SetAndGetEnv(g->iRoutineID); - return NULL; -} - -int main(int argc, char* argv[]) -{ - co_set_env_list(CGI_ENV_HOOK_LIST, sizeof(CGI_ENV_HOOK_LIST) / sizeof(char*)); - stRoutineArgs_t args[3]; - for (int i = 0; i < 3; i++) - { - stCoRoutine_t* co = NULL; - args[i].iRoutineID = i; - co_create(&co, NULL, RoutineFunc, &args[i]); - co_resume(co); - } - co_eventloop(co_get_epoll_ct(), NULL, NULL); - return 0; -} - diff --git a/trunk/3rdparty/libco/example_specific.cpp b/trunk/3rdparty/libco/example_specific.cpp deleted file mode 100644 index 5d20a8b1a8..0000000000 --- a/trunk/3rdparty/libco/example_specific.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "co_routine_specific.h" -#include "co_routine.h" -#include -#include -#include -#include -using namespace std; -struct stRoutineArgs_t -{ - stCoRoutine_t* co; - int routine_id; -}; -struct stRoutineSpecificData_t -{ - int idx; -}; - -CO_ROUTINE_SPECIFIC(stRoutineSpecificData_t, __routine); - -void* RoutineFunc(void* args) -{ - co_enable_hook_sys(); - stRoutineArgs_t* routine_args = (stRoutineArgs_t*)args; - __routine->idx = routine_args->routine_id; - while (true) - { - printf("%s:%d routine specific data idx %d\n", __func__, __LINE__, __routine->idx); - poll(NULL, 0, 1000); - } - return NULL; -} -int main() -{ - stRoutineArgs_t args[10]; - for (int i = 0; i < 10; i++) - { - args[i].routine_id = i; - co_create(&args[i].co, NULL, RoutineFunc, (void*)&args[i]); - co_resume(args[i].co); - } - co_eventloop(co_get_epoll_ct(), NULL, NULL); - return 0; -} diff --git a/trunk/3rdparty/libco/example_thread.cpp b/trunk/3rdparty/libco/example_thread.cpp deleted file mode 100644 index 401771071a..0000000000 --- a/trunk/3rdparty/libco/example_thread.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* -* Tencent is pleased to support the open source community by making Libco available. - -* Copyright (C) 2014 THL A29 Limited, a Tencent company. All rights reserved. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - - -#include "co_routine.h" -#include "co_routine_inner.h" - -#include -#include -#include -#include -#include - -int loop(void *) -{ - return 0; -} -static void *routine_func( void * ) -{ - stCoEpoll_t * ev = co_get_epoll_ct(); //ct = current thread - co_eventloop( ev,loop,0 ); - return 0; -} -int main(int argc,char *argv[]) -{ - int cnt = atoi( argv[1] ); - - pthread_t tid[ cnt ]; - for(int i=0;i +# +# To start with more than the default 64 initial pollfd slots +# (but the table grows dynamically anyway): +# DEFINES += -DST_MIN_POLLFDS_SIZE= +# +# Note that you can also add these defines by specifying them as +# make/gmake arguments (without editing this Makefile). For example: +# +# make EXTRA_CFLAGS=-DUSE_POLL +# +# (replace make with gmake if needed). +# +# You can also modify the default selection of an alternative event +# notification mechanism. E.g., to enable kqueue(2) support (if it's not +# enabled by default): +# +# gmake EXTRA_CFLAGS=-DMD_HAVE_KQUEUE +# +# or to disable default epoll(4) support: +# +# make EXTRA_CFLAGS=-UMD_HAVE_EPOLL +# +########################## + +CFLAGS += $(DEFINES) $(OTHER_FLAGS) $(EXTRA_CFLAGS) + +OBJS = $(TARGETDIR)/sched.o \ + $(TARGETDIR)/stk.o \ + $(TARGETDIR)/sync.o \ + $(TARGETDIR)/key.o \ + $(TARGETDIR)/io.o \ + $(TARGETDIR)/event.o +OBJS += $(EXTRA_OBJS) +HEADER = $(TARGETDIR)/st.h +SLIBRARY = $(TARGETDIR)/libst.a +DLIBRARY = $(TARGETDIR)/libst.$(DSO_SUFFIX).$(VERSION) +EXAMPLES = examples + +LINKNAME = libst.$(DSO_SUFFIX) +SONAME = libst.$(DSO_SUFFIX).$(MAJOR) +FULLNAME = libst.$(DSO_SUFFIX).$(VERSION) + +ifeq ($(OS), CYGWIN) +SONAME = cygst.$(DSO_SUFFIX) +SLIBRARY = $(TARGETDIR)/libst.dll.a +DLIBRARY = $(TARGETDIR)/$(SONAME) +LINKNAME = +# examples directory does not compile under cygwin +EXAMPLES = +endif + +# for SRS +# disable examples for ubuntu crossbuild failed. +# @see https://github.com/winlinvip/simple-rtmp-server/issues/308 +EXAMPLES = + +ifeq ($(OS), DARWIN) +LINKNAME = libst.$(DSO_SUFFIX) +SONAME = libst.$(MAJOR).$(DSO_SUFFIX) +FULLNAME = libst.$(VERSION).$(DSO_SUFFIX) +endif + +ifeq ($(STATIC_ONLY), yes) +LIBRARIES = $(SLIBRARY) +else +LIBRARIES = $(SLIBRARY) $(DLIBRARY) +endif + +ifeq ($(OS),) +ST_ALL = unknown +else +ST_ALL = $(TARGETDIR) $(LIBRARIES) $(HEADER) $(EXAMPLES) $(DESC) +endif + +all: $(ST_ALL) + +unknown: + @echo + @echo "Please specify one of the following targets:" + @echo + @for target in $(TARGETS); do echo $$target; done + @echo + +st.pc: st.pc.in + sed "s/@VERSION@/${VERSION}/g" < $< > $@ + +$(TARGETDIR): + if [ ! -d $(TARGETDIR) ]; then mkdir $(TARGETDIR); fi + +$(SLIBRARY): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + $(RANLIB) $@ + rm -f obj; $(LN) $(LNFLAGS) $(TARGETDIR) obj + +$(DLIBRARY): $(OBJS:%.o=%-pic.o) + $(LD) $(LDFLAGS) $^ -o $@ + if test "$(LINKNAME)"; then \ + cd $(TARGETDIR); \ + rm -f $(SONAME) $(LINKNAME); \ + $(LN) $(LNFLAGS) $(FULLNAME) $(SONAME); \ + $(LN) $(LNFLAGS) $(FULLNAME) $(LINKNAME); \ + fi + +$(HEADER): public.h + rm -f $@ + cp public.h $@ + +$(TARGETDIR)/md.o: md.S + $(CC) $(CFLAGS) -c $< -o $@ + +$(TARGETDIR)/%.o: %.c common.h md.h + $(CC) $(CFLAGS) -c $< -o $@ + +examples:: + @echo Making $@ + @cd $@; $(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS)" OS="$(OS)" TARGETDIR="$(TARGETDIR)" + +clean: + rm -rf *_OPT *_DBG obj st.pc + +########################## +# Pattern rules: + +ifneq ($(SFLAGS),) +# Compile with shared library options if it's a C file +$(TARGETDIR)/%-pic.o: %.c common.h md.h + $(CC) $(CFLAGS) $(SFLAGS) -c $< -o $@ +endif + +# Compile assembly as normal or C as normal if no SFLAGS +%-pic.o: %.o + rm -f $@; $(LN) $(LNFLAGS) $(. Install them with: + # rpm -i libst*.rpm +Requires GNU automake and rpm 3.0.3 or later. + +Debian users: + If you run potato, please upgrade to woody. + If you run woody, "apt-get install libst-dev" will get you v1.3. + If you run testing/unstable, you will get the newest available version. + If you *must* have the newest libst in woody, you may follow these + not-recommended instructions: + 1. Add "deb-src unstable main" to your + /etc/apt/sources.list + 2. apt-get update + 3. apt-get source st + 4. cd st-1.4 (or whatever version you got) + 5. debuild + 6. dpkg -i ../*.deb + +If your application uses autoconf to search for dependencies and you +want to search for a given version of libst, you can simply add + PKG_CHECK_MODULES(MYAPP, st >= 1.3 mumble >= 0.2.23) +to your configure.ac/in. This will define @MYAPP_LIBS@ and +@MYAPP_CFLAGS@ which you may then use in your Makefile.am/in files to +link against mumble and st. + + +LICENSE + +The State Threads library is a derivative of the Netscape Portable +Runtime library (NSPR). All source code in this directory is +distributed under the terms of the Mozilla Public License (MPL) version +1.1 or the GNU General Public License (GPL) version 2 or later. For +more information about these licenses please see +http://www.mozilla.org/MPL/ and http://www.gnu.org/copyleft/. + +All source code in the "examples" directory is distributed under the BSD +style license. + + +PLATFORMS + +Please see the "docs/notes.html" file for the list of currently +supported platforms. + + +DEBUGGER SUPPORT + +It's almost impossible to print SP and PC in a portable way. The only +way to see thread's stack platform-independently is to actually jump to +the saved context. That's what the _st_iterate_threads() function does. +Do the following to iterate over all threads: + +- set the _st_iterate_threads_flag to 1 in debugger +- set breakpoint at the _st_show_thread_stack() function + (which does nothing) +- call the _st_iterate_threads() function which jumps to the + next thread +- at each break you can explore thread's stack +- continue +- when iteration is complete, you return to the original + point (you can see thread id and a message as arguments of + the _st_show_thread_stack() function). + +You can call _st_iterate_threads() in three ways: + +- Insert it into your source code at the point you want to + go over threads. +- Just run application and this function will be called at + the first context switch. +- Call it directly from the debugger at any point. + +This works with gdb and dbx. + +Example using gdb: + +(gdb) set _st_iterate_threads_flag = 1 +(gdb) b _st_show_thread_stack +... +(gdb) call _st_iterate_threads() +... +(gdb) bt +... +(gdb) c +... +(gdb) bt +... +(gdb) c +... +and so on... + +_st_iterate_threads_flag will be set to 0 automatically +after iteration is over or you can set it to 0 at any time +to stop iteration. + +Sometimes gdb complains about SIGSEGV when you call a function +directly at gdb command-line. It can be ignored -- just call the +same function right away again, it works just fine. For example: + +(gdb) set _st_iterate_threads_flag = 1 +(gdb) b _st_show_thread_stack +Breakpoint 1 at 0x809bbbb: file sched.c, line 856. +(gdb) call _st_iterate_threads() +Program received signal SIGSEGV, Segmentation fault. +.... +(gdb) # just call the function again: +(gdb) call _st_iterate_threads() +Breakpoint 1, _st_show_thread_stack (thread=0x4017aee4, messg=0x80ae7a2 +"Iteration started") at sched.c:856 +856 } +.... + +You can use simple gdb command-line scripting to display +all threads and their stack traces at once: + +(gdb) while _st_iterate_threads_flag + >bt + >c + >end +.... + +Another script to stop at the thread with the specific thread id +(e.g., 0x40252ee4): + +(gdb) # set the flag again: +(gdb) set _st_iterate_threads_flag = 1 +(gdb) call _st_iterate_threads() +Breakpoint 1, _st_show_thread_stack (thread=0x4017aee4, messg=0x80ae7a2 +"Iteration started") at sched.c:856 +856 } +.... +(gdb) while thread != 0x40252ee4 + >c + >end +.... +.... +Breakpoint 1, _st_show_thread_stack (thread=0x40252ee4, messg=0x0) at +sched.c:856 +856 } +(gdb) bt +.... +(gdb) # don't want to continue iteration, unset the flag: +(gdb) set _st_iterate_threads_flag = 0 +(gdb) c +Continuing. +Breakpoint 1, _st_show_thread_stack (thread=0x0, messg=0x80ae78e "Iteration +completed") + at sched.c:856 +856 } +(gdb) c +Continuing. +(gdb) return +Make selected stack frame return now? (y or n) y +#0 0x4011254e in __select () + from /lib/libc.so.6 +(gdb) detach + + +CHANGE LOG + +Changes from 1.8 to 1.9. +------------------------ +o Support 32-bit and 64-bit Intel Macs. + +o Added ST_VERSION string, and ST_VERSION_MAJOR and ST_VERSION_MINOR + [bug 1796801]. + +o Fixed some compiler warnings, based on a patch from Brian Wellington + [bug 1932741]. + + +Changes from 1.7 to 1.8. +-------------------------- +o Added support for kqueue and epoll on platforms that support them. + Added ability to choose the event notification system at program + startup. + +o Long-overdue public definitions of ST_UTIME_NO_TIMEOUT (-1ULL) and + ST_UTIME_NO_WAIT (0) [bug 1514436]. + +o Documentation patch for st_utime() [bug 1514484]. + +o Documentation patch for st_timecache_set() [bug 1514486]. + +o Documentation patch for st_netfd_serialize_accept() [bug 1514494]. + +o Added st_writev_resid() [rfe 1538344]. + +o Added st_readv_resid() [rfe 1538768] and, for symmetry, st_readv(). + + +Changes from 1.6 to 1.7. +------------------------ +o Support glibc 2.4, which breaks programs that manipulate jump buffers. + Replaced Linux IA64 special cases with new md.S that covers all + Linux. + + +Changes from 1.5.2 to 1.6. +-------------------------- +none + + +Changes from 1.5.1 to 1.5.2. +---------------------------- +o Alfred Perlstein's context switch callback feature. + +o Claus Assmann's st_recvmsg/st_sendmsg wrappers. + +o Extra stack padding for platforms that need it. + +o Ron Arts's timeout clarifications in the reference manual. + +o Raymond Bero and Anton Berezin's AMD64 FreeBSD port. + +o Claus Assmann's AMD64 SunOS 5.10 port. + +o Claus Assmann's AMD64 OpenBSD port. + +o Michael Abd-El-Malek's Mac OS X port. + +o Michael Abd-El-Malek's stack printing patch. + + +Changes from 1.5.0 to 1.5.1. +---------------------------- +o Andreas Gustafsson's USE_POLL fix. + +o Gene's st_set_utime_function() enhancement. + + +Changes from 1.4 to 1.5.0. +-------------------------- +o Andreas Gustafsson's performance patch. + +o New extensions: Improved DNS resolver, generic LRU cache, in-process + DNS cache, and a program to test the resolver and cache. + +o Support for AMD Opteron 64-bit CPUs under Linux. + +o Support for SPARC-64 under Solaris. + +o Andreas Gustafsson's support for VAX under NetBSD. + +o Changed unportable #warning directives in md.h to #error. + + +Changes from 1.3 to 1.4. +------------------------ +o Andreas Gustafsson's NetBSD port. + +o Wesley W. Terpstra's Darwin (MacOS X) port. + +o Support for many CPU architectures under Linux and *BSD. + +o Renamed private typedefs so they don't conflict with public ones any + more. + +o common.h now includes public.h for strict prototyping. + +o Joshua Levy's recommendation to make st_connect() and st_sendto() + accept const struct sockaddr pointers, as the originals do. + +o Clarified the documentation regarding blocking vs. non-blocking I/O. + +o Cygwin support. + +o Created the extensions directory. + +o Fixed warnings from ia64asm.S. + + +Changes from 1.2 to 1.3. +------------------------ +o Added st_read_resid() and st_write_resid() to allow the caller to know + how much data was transferred before an error occurred. Updated + documentation. + +o Updated project link, copyrights, and documentation regarding + timeouts. Added comment to st_connect(). + +o Optimized the _st_add_sleep_q() function in sched.c. Now we walk the + sleep queue *backward* when inserting a thread into it. When you + have lots (hundreds) of threads and several timeout values, it takes + a while to insert a thread at the appropriate point in the sleep + queue. The idea is that often this appropriate point is closer to + the end of the queue rather than the beginning. Measurements show + performance improves with this change. In any case this change + should do no harm. + +o Added a hint of when to define USE_POLL and when not to, to the + Makefile. + +o Added debugging support (files common.h and sched.c). See above. + +o Decreased the number of reallocations of _ST_POLLFDS in sched.c. + Inspired by Lev Walkin. + +o Fixed st_usleep(-1) and st_sleep(-1), and added a warning to the + documentation about too-large timeouts. + +o Linux/*BSD Alpha port. + +o Wesley W. Terpstra modernized the build process: + - properly build relocatable libraries under bsd and linux + - use library versioning + - added rpm spec file + - added debian/ files + See above for build instructions. + + +Changes from 1.1 to 1.2. +------------------------ +o Added st_randomize_stacks(). + +o Added a patch contributed by Sascha Schumann. + + +Changes from 1.0 to 1.1. +------------------------ +o Relicensed under dual MPL-GPL. + +o OpenBSD port. + +o Compile-time option to use poll() instead of select() for + event polling (see Makefile). + This is useful if you want to support a large number of open + file descriptors (larger than FD_SETSIZE) within a single + process. + +o Linux IA-64 port. + Two issues make IA-64 different from other platforms: + + - Besides the traditional call stack in memory, IA-64 uses the + general register stack. Thus each thread needs a backing store + for the register stack in addition to the memory stack. + + - Current implementation of setjmp()/longjmp() can not be used + for thread context-switching since it assumes that only one + register stack exists. Using special assembly functions for + context-switching is unavoidable. + +o Thread stack capping on IRIX. + This allows some profiling tools (such as SpeedShop) to know when + to stop unwinding the stack. Without this libexc, used by SpeedShop, + traces right off the stack and crashes. + +o Miscellaneous documentation additions. + + +COPYRIGHTS + +Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. +All Rights Reserved. diff --git a/trunk/3rdparty/st-srs/README.md b/trunk/3rdparty/st-srs/README.md new file mode 100644 index 0000000000..60fc1a6518 --- /dev/null +++ b/trunk/3rdparty/st-srs/README.md @@ -0,0 +1,88 @@ +# state-threads + +![](http://ossrs.net:8000/gif/v1/sls.gif?site=github.com&path=/srs/srsst) +[![](https://cloud.githubusercontent.com/assets/2777660/22814959/c51cbe72-ef92-11e6-81cc-32b657b285d5.png)](https://github.com/ossrs/srs/wiki/v1_CN_Contact#wechat) + +Fork from http://sourceforge.net/projects/state-threads, patched for [SRS](https://github.com/ossrs/srs/tree/2.0release). + +> See: https://github.com/ossrs/state-threads/blob/srs/README + +For original ST without any changes, checkout the [ST master branch](https://github.com/ossrs/state-threads/tree/master). + +## Branch SRS + +The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patched the following patches: + +- [x] Patch [st.arm.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/1.st.arm.patch), for ARM. +- [x] Patch [st.osx.kqueue.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/3.st.osx.kqueue.patch), for osx. +- [x] Patch [st.disable.examples.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/4.st.disable.examples.patch), for ubuntu. +- [x] [Refine TAB of code](https://github.com/ossrs/state-threads/compare/c2001d30ca58f55d72a6cc6b9b6c70391eaf14db...d2101b26988b0e0db0aabc53ddf452068c1e2cbc). +- [x] Merge from [michaeltalyansky](https://github.com/michaeltalyansky/state-threads) and [xzh3836598](https://github.com/ossrs/state-threads/commit/9a17dec8f9c2814d93761665df7c5575a4d2d8a3), support [ARM](https://github.com/ossrs/state-threads/issues/1). +- [x] Merge from [toffaletti](https://github.com/toffaletti/state-threads), support [valgrind](https://github.com/ossrs/state-threads/issues/2) for ST. +- [x] Patch [st.osx10.14.build.patch](https://github.com/ossrs/srs/blob/2.0release/trunk/3rdparty/patches/6.st.osx10.14.build.patch), for osx 10.14 build. +- [x] Support macro `MD_ST_NO_ASM` to disable ASM, [#8](https://github.com/ossrs/state-threads/issues/8). +- [x] Merge patch [srs#1282](https://github.com/ossrs/srs/issues/1282#issuecomment-445539513) to support aarch64, [#9](https://github.com/ossrs/state-threads/issues/9). + +## Docs + +* Introduction: http://ossrs.github.io/state-threads/docs/st.html +* API reference: http://ossrs.github.io/state-threads/docs/reference.html +* Programming notes: http://ossrs.github.io/state-threads/docs/notes.html + +## Usage + +Get code: + +``` +git clone https://github.com/ossrs/state-threads.git st-1.9 && +git checkout -b srs origin/srs +``` + +For Linux: + +``` +make linux-debug EXTRA_CFLAGS="-DMD_HAVE_EPOLL" +``` + +For OSX: + +``` +make darwin-debug EXTRA_CFLAGS="-DMD_HAVE_KQUEUE" +``` + +Linux with valgrind: + +``` +make linux-debug EXTRA_CFLAGS="-DMD_VALGRIND" +``` + +> Remark: User must install valgrind, for instance, in centos6 `sudo yum install -y valgrind valgrind-devel`. + +Linux with valgrind and epoll: + +``` +make linux-debug EXTRA_CFLAGS="-DMD_HAVE_EPOLL -DMD_VALGRIND" +``` + +For OSX, user must specifies the valgrind header files: + +``` +make darwin-debug EXTRA_CFLAGS="-DMD_HAVE_KQUEUE -DMD_VALGRIND -I/usr/local/include" +``` + +> Remark: Latest OSX does not support ST, please use docker to run ST. + +## Valgrind + +How to debug with gdb under valgrind, read [valgrind manual](http://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver-simple). + +About startup parameters, read [valgrind cli](http://valgrind.org/docs/manual/mc-manual.html#mc-manual.options). + +Important cli options: + +1. `--undef-value-errors= [default: yes]`, Controls whether Memcheck reports uses of undefined value errors. Set this to no if you don't want to see undefined value errors. It also has the side effect of speeding up Memcheck somewhat. +1. `--leak-check= [default: summary]`, When enabled, search for memory leaks when the client program finishes. If set to summary, it says how many leaks occurred. If set to full or yes, each individual leak will be shown in detail and/or counted as an error, as specified by the options `--show-leak-kinds` and `--errors-for-leak-kinds`. +1. `--track-origins= [default: no]`, Controls whether Memcheck tracks the origin of uninitialised values. By default, it does not, which means that although it can tell you that an uninitialised value is being used in a dangerous way, it cannot tell you where the uninitialised value came from. This often makes it difficult to track down the root problem. +1. `--show-reachable= , --show-possibly-lost=`, to show the using memory. + +Winlin 2016 diff --git a/trunk/3rdparty/st-srs/common.h b/trunk/3rdparty/st-srs/common.h new file mode 100644 index 0000000000..0c0685b9ae --- /dev/null +++ b/trunk/3rdparty/st-srs/common.h @@ -0,0 +1,479 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#ifndef __ST_COMMON_H__ +#define __ST_COMMON_H__ + +#include +#include +#include +#include +#include + +/* Enable assertions only if DEBUG is defined */ +#ifndef DEBUG + #define NDEBUG +#endif +#include +#define ST_ASSERT(expr) assert(expr) + +#define ST_BEGIN_MACRO { +#define ST_END_MACRO } + +#ifdef DEBUG + #define ST_HIDDEN /*nothing*/ +#else + #define ST_HIDDEN static +#endif + +#include "public.h" +#include "md.h" + +/* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */ +#ifndef MD_VALGRIND + #ifndef NVALGRIND + #define NVALGRIND + #endif +#else + #undef NVALGRIND +#endif + + +/***************************************** + * Circular linked list definitions + */ + +typedef struct _st_clist { + struct _st_clist *next; + struct _st_clist *prev; +} _st_clist_t; + +/* Insert element "_e" into the list, before "_l" */ +#define ST_INSERT_BEFORE(_e,_l) \ + ST_BEGIN_MACRO \ + (_e)->next = (_l); \ + (_e)->prev = (_l)->prev; \ + (_l)->prev->next = (_e); \ + (_l)->prev = (_e); \ + ST_END_MACRO + +/* Insert element "_e" into the list, after "_l" */ +#define ST_INSERT_AFTER(_e,_l) \ + ST_BEGIN_MACRO \ + (_e)->next = (_l)->next; \ + (_e)->prev = (_l); \ + (_l)->next->prev = (_e); \ + (_l)->next = (_e); \ + ST_END_MACRO + +/* Return the element following element "_e" */ +#define ST_NEXT_LINK(_e) ((_e)->next) + +/* Append an element "_e" to the end of the list "_l" */ +#define ST_APPEND_LINK(_e,_l) ST_INSERT_BEFORE(_e,_l) + +/* Insert an element "_e" at the head of the list "_l" */ +#define ST_INSERT_LINK(_e,_l) ST_INSERT_AFTER(_e,_l) + +/* Return the head/tail of the list */ +#define ST_LIST_HEAD(_l) (_l)->next +#define ST_LIST_TAIL(_l) (_l)->prev + +/* Remove the element "_e" from it's circular list */ +#define ST_REMOVE_LINK(_e) \ + ST_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + ST_END_MACRO + +/* Return non-zero if the given circular list "_l" is empty, */ +/* zero if the circular list is not empty */ +#define ST_CLIST_IS_EMPTY(_l) \ + ((_l)->next == (_l)) + +/* Initialize a circular list */ +#define ST_INIT_CLIST(_l) \ + ST_BEGIN_MACRO \ + (_l)->next = (_l); \ + (_l)->prev = (_l); \ + ST_END_MACRO + +#define ST_INIT_STATIC_CLIST(_l) \ + {(_l), (_l)} + + +/***************************************** + * Basic types definitions + */ + +typedef void (*_st_destructor_t)(void *); + + +typedef struct _st_stack { + _st_clist_t links; + char *vaddr; /* Base of stack's allocated memory */ + int vaddr_size; /* Size of stack's allocated memory */ + int stk_size; /* Size of usable portion of the stack */ + char *stk_bottom; /* Lowest address of stack's usable portion */ + char *stk_top; /* Highest address of stack's usable portion */ + void *sp; /* Stack pointer from C's point of view */ +#ifdef __ia64__ + void *bsp; /* Register stack backing store pointer */ +#endif + /* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */ +#ifndef NVALGRIND + /* id returned by VALGRIND_STACK_REGISTER */ + /* http://valgrind.org/docs/manual/manual-core-adv.html */ + unsigned long valgrind_stack_id; +#endif +} _st_stack_t; + + +typedef struct _st_cond { + _st_clist_t wait_q; /* Condition variable wait queue */ +} _st_cond_t; + + +typedef struct _st_thread _st_thread_t; + +struct _st_thread { + int state; /* Thread's state */ + int flags; /* Thread's flags */ + + void *(*start)(void *arg); /* The start function of the thread */ + void *arg; /* Argument of the start function */ + void *retval; /* Return value of the start function */ + + _st_stack_t *stack; /* Info about thread's stack */ + + _st_clist_t links; /* For putting on run/sleep/zombie queue */ + _st_clist_t wait_links; /* For putting on mutex/condvar wait queue */ +#ifdef DEBUG + _st_clist_t tlink; /* For putting on thread queue */ +#endif + + st_utime_t due; /* Wakeup time when thread is sleeping */ + _st_thread_t *left; /* For putting in timeout heap */ + _st_thread_t *right; /* -- see docs/timeout_heap.txt for details */ + int heap_index; + + void **private_data; /* Per thread private data */ + + _st_cond_t *term; /* Termination condition variable for join */ + + jmp_buf context; /* Thread's context */ +}; + + +typedef struct _st_mutex { + _st_thread_t *owner; /* Current mutex owner */ + _st_clist_t wait_q; /* Mutex wait queue */ +} _st_mutex_t; + + +typedef struct _st_pollq { + _st_clist_t links; /* For putting on io queue */ + _st_thread_t *thread; /* Polling thread */ + struct pollfd *pds; /* Array of poll descriptors */ + int npds; /* Length of the array */ + int on_ioq; /* Is it on ioq? */ +} _st_pollq_t; + + +typedef struct _st_eventsys_ops { + const char *name; /* Name of this event system */ + int val; /* Type of this event system */ + int (*init)(void); /* Initialization */ + void (*dispatch)(void); /* Dispatch function */ + int (*pollset_add)(struct pollfd *, int); /* Add descriptor set */ + void (*pollset_del)(struct pollfd *, int); /* Delete descriptor set */ + int (*fd_new)(int); /* New descriptor allocated */ + int (*fd_close)(int); /* Descriptor closed */ + int (*fd_getlimit)(void); /* Descriptor hard limit */ +} _st_eventsys_t; + + +typedef struct _st_vp { + _st_thread_t *idle_thread; /* Idle thread for this vp */ + st_utime_t last_clock; /* The last time we went into vp_check_clock() */ + + _st_clist_t run_q; /* run queue for this vp */ + _st_clist_t io_q; /* io queue for this vp */ + _st_clist_t zombie_q; /* zombie queue for this vp */ +#ifdef DEBUG + _st_clist_t thread_q; /* all threads of this vp */ +#endif + int pagesize; + + _st_thread_t *sleep_q; /* sleep queue for this vp */ + int sleepq_size; /* number of threads on sleep queue */ + +#ifdef ST_SWITCH_CB + st_switch_cb_t switch_out_cb; /* called when a thread is switched out */ + st_switch_cb_t switch_in_cb; /* called when a thread is switched in */ +#endif +} _st_vp_t; + + +typedef struct _st_netfd { + int osfd; /* Underlying OS file descriptor */ + int inuse; /* In-use flag */ + void *private_data; /* Per descriptor private data */ + _st_destructor_t destructor; /* Private data destructor function */ + void *aux_data; /* Auxiliary data for internal use */ + struct _st_netfd *next; /* For putting on the free list */ +} _st_netfd_t; + + +/***************************************** + * Current vp, thread, and event system + */ + +extern _st_vp_t _st_this_vp; +extern _st_thread_t *_st_this_thread; +extern _st_eventsys_t *_st_eventsys; + +#define _ST_CURRENT_THREAD() (_st_this_thread) +#define _ST_SET_CURRENT_THREAD(_thread) (_st_this_thread = (_thread)) + +#define _ST_LAST_CLOCK (_st_this_vp.last_clock) + +#define _ST_RUNQ (_st_this_vp.run_q) +#define _ST_IOQ (_st_this_vp.io_q) +#define _ST_ZOMBIEQ (_st_this_vp.zombie_q) +#ifdef DEBUG + #define _ST_THREADQ (_st_this_vp.thread_q) +#endif + +#define _ST_PAGE_SIZE (_st_this_vp.pagesize) + +#define _ST_SLEEPQ (_st_this_vp.sleep_q) +#define _ST_SLEEPQ_SIZE (_st_this_vp.sleepq_size) + +#define _ST_VP_IDLE() (*_st_eventsys->dispatch)() + + +/***************************************** + * vp queues operations + */ + +#define _ST_ADD_IOQ(_pq) ST_APPEND_LINK(&_pq.links, &_ST_IOQ) +#define _ST_DEL_IOQ(_pq) ST_REMOVE_LINK(&_pq.links) + +#define _ST_ADD_RUNQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_RUNQ) +#define _ST_DEL_RUNQ(_thr) ST_REMOVE_LINK(&(_thr)->links) + +#define _ST_ADD_SLEEPQ(_thr, _timeout) _st_add_sleep_q(_thr, _timeout) +#define _ST_DEL_SLEEPQ(_thr) _st_del_sleep_q(_thr) + +#define _ST_ADD_ZOMBIEQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_ZOMBIEQ) +#define _ST_DEL_ZOMBIEQ(_thr) ST_REMOVE_LINK(&(_thr)->links) + +#ifdef DEBUG + #define _ST_ADD_THREADQ(_thr) ST_APPEND_LINK(&(_thr)->tlink, &_ST_THREADQ) + #define _ST_DEL_THREADQ(_thr) ST_REMOVE_LINK(&(_thr)->tlink) +#endif + + +/***************************************** + * Thread states and flags + */ + +#define _ST_ST_RUNNING 0 +#define _ST_ST_RUNNABLE 1 +#define _ST_ST_IO_WAIT 2 +#define _ST_ST_LOCK_WAIT 3 +#define _ST_ST_COND_WAIT 4 +#define _ST_ST_SLEEPING 5 +#define _ST_ST_ZOMBIE 6 +#define _ST_ST_SUSPENDED 7 + +#define _ST_FL_PRIMORDIAL 0x01 +#define _ST_FL_IDLE_THREAD 0x02 +#define _ST_FL_ON_SLEEPQ 0x04 +#define _ST_FL_INTERRUPT 0x08 +#define _ST_FL_TIMEDOUT 0x10 + + +/***************************************** + * Pointer conversion + */ + +#ifndef offsetof + #define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier)) +#endif + +#define _ST_THREAD_PTR(_qp) \ + ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, links))) + +#define _ST_THREAD_WAITQ_PTR(_qp) \ + ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, wait_links))) + +#define _ST_THREAD_STACK_PTR(_qp) \ + ((_st_stack_t *)((char*)(_qp) - offsetof(_st_stack_t, links))) + +#define _ST_POLLQUEUE_PTR(_qp) \ + ((_st_pollq_t *)((char *)(_qp) - offsetof(_st_pollq_t, links))) + +#ifdef DEBUG + #define _ST_THREAD_THREADQ_PTR(_qp) \ + ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, tlink))) +#endif + + +/***************************************** + * Constants + */ + +#ifndef ST_UTIME_NO_TIMEOUT + #define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL) +#endif + +#ifndef __ia64__ + #define ST_DEFAULT_STACK_SIZE (64*1024) +#else + #define ST_DEFAULT_STACK_SIZE (128*1024) /* Includes register stack size */ +#endif + +#ifndef ST_KEYS_MAX + #define ST_KEYS_MAX 16 +#endif + +#ifndef ST_MIN_POLLFDS_SIZE + #define ST_MIN_POLLFDS_SIZE 64 +#endif + + +/***************************************** + * Threads context switching + */ + +#ifdef DEBUG + void _st_iterate_threads(void); + #define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads() +#else + #define ST_DEBUG_ITERATE_THREADS() +#endif + +#ifdef ST_SWITCH_CB + #define ST_SWITCH_OUT_CB(_thread) \ + if (_st_this_vp.switch_out_cb != NULL && \ + _thread != _st_this_vp.idle_thread && \ + _thread->state != _ST_ST_ZOMBIE) { \ + _st_this_vp.switch_out_cb(); \ + } + #define ST_SWITCH_IN_CB(_thread) \ + if (_st_this_vp.switch_in_cb != NULL && \ + _thread != _st_this_vp.idle_thread && \ + _thread->state != _ST_ST_ZOMBIE) { \ + _st_this_vp.switch_in_cb(); \ + } +#else + #define ST_SWITCH_OUT_CB(_thread) + #define ST_SWITCH_IN_CB(_thread) +#endif + +/* + * Switch away from the current thread context by saving its state and + * calling the thread scheduler + */ +#define _ST_SWITCH_CONTEXT(_thread) \ + ST_BEGIN_MACRO \ + ST_SWITCH_OUT_CB(_thread); \ + if (!MD_SETJMP((_thread)->context)) { \ + _st_vp_schedule(); \ + } \ + ST_DEBUG_ITERATE_THREADS(); \ + ST_SWITCH_IN_CB(_thread); \ + ST_END_MACRO + +/* + * Restore a thread context that was saved by _ST_SWITCH_CONTEXT or + * initialized by _ST_INIT_CONTEXT + */ +#define _ST_RESTORE_CONTEXT(_thread) \ + ST_BEGIN_MACRO \ + _ST_SET_CURRENT_THREAD(_thread); \ + MD_LONGJMP((_thread)->context, 1); \ + ST_END_MACRO + +/* + * Initialize the thread context preparing it to execute _main + */ +#ifdef MD_INIT_CONTEXT + #define _ST_INIT_CONTEXT MD_INIT_CONTEXT +#else + #error Unknown OS +#endif + +/* + * Number of bytes reserved under the stack "bottom" + */ +#define _ST_STACK_PAD_SIZE MD_STACK_PAD_SIZE + + +/***************************************** + * Forward declarations + */ + +void _st_vp_schedule(void); +void _st_vp_check_clock(void); +void *_st_idle_thread_start(void *arg); +void _st_thread_main(void); +void _st_thread_cleanup(_st_thread_t *thread); +void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout); +void _st_del_sleep_q(_st_thread_t *thread); +_st_stack_t *_st_stack_new(int stack_size); +void _st_stack_free(_st_stack_t *ts); +int _st_io_init(void); + +st_utime_t st_utime(void); +_st_cond_t *st_cond_new(void); +int st_cond_destroy(_st_cond_t *cvar); +int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout); +int st_cond_signal(_st_cond_t *cvar); +ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout); +ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout); +int st_poll(struct pollfd *pds, int npds, st_utime_t timeout); +_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size); + +#endif /* !__ST_COMMON_H__ */ + diff --git a/trunk/3rdparty/st-srs/docs/fig.gif b/trunk/3rdparty/st-srs/docs/fig.gif new file mode 100644 index 0000000000000000000000000000000000000000..7265a05db4f516b44fcf37c3949922ff4f62999d GIT binary patch literal 5374 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 literal 0 HcmV?d00001 diff --git a/trunk/3rdparty/st-srs/docs/notes.html b/trunk/3rdparty/st-srs/docs/notes.html new file mode 100644 index 0000000000..5a24369e22 --- /dev/null +++ b/trunk/3rdparty/st-srs/docs/notes.html @@ -0,0 +1,434 @@ + + +State Threads Library Programming Notes + + +

Programming Notes

+

+ +

+ +

+


+

+ +

Porting

+The State Threads library uses OS concepts that are available in some +form on most UNIX platforms, making the library very portable across +many flavors of UNIX. However, there are several parts of the library +that rely on platform-specific features. Here is the list of such parts: +

+

    +
  • Thread context initialization: Two ingredients of the +jmp_buf +data structure (the program counter and the stack pointer) have to be +manually set in the thread creation routine. The jmp_buf data +structure is defined in the setjmp.h header file and differs from +platform to platform. Usually the program counter is a structure member +with PC in the name and the stack pointer is a structure member +with SP in the name. One can also look in the +Netscape's NSPR library source +which already has this code for many UNIX-like platforms +(mozilla/nsprpub/pr/include/md/*.h files). +

    +Note that on some BSD-derived platforms _setjmp(3)/_longjmp(3) +calls should be used instead of setjmp(3)/longjmp(3) (that is +the calls that manipulate only the stack and registers and do not +save and restore the process's signal mask).

  • +

    +Starting with glibc 2.4 on Linux the opacity of the jmp_buf data +structure is enforced by setjmp(3)/longjmp(3) so the +jmp_buf ingredients cannot be accessed directly anymore (unless +special environmental variable LD_POINTER_GUARD is set before application +execution). To avoid dependency on custom environment, the State Threads +library provides setjmp/longjmp replacement functions for +all Intel CPU architectures. Other CPU architectures can also be easily +supported (the setjmp/longjmp source code is widely available for +many CPU architectures). +

    +

  • High resolution time function: Some platforms (IRIX, Solaris) +provide a high resolution time function based on the free running hardware +counter. This function returns the time counted since some arbitrary +moment in the past (usually machine power up time). It is not correlated in +any way to the time of day, and thus is not subject to resetting, +drifting, etc. This type of time is ideal for tasks where cheap, accurate +interval timing is required. If such a function is not available on a +particular platform, the gettimeofday(3) function can be used +(though on some platforms it involves a system call). +

    +

  • The stack growth direction: The library needs to know whether the +stack grows toward lower (down) or higher (up) memory addresses. +One can write a simple test program that detects the stack growth direction +on a particular platform.
  • +

    +

  • Non-blocking attribute inheritance: On some platforms (e.g. IRIX) +the socket created as a result of the accept(2) call inherits the +non-blocking attribute of the listening socket. One needs to consult the manual +pages or write a simple test program to see if this applies to a specific +platform.
  • +

    +

  • Anonymous memory mapping: The library allocates memory segments +for thread stacks by doing anonymous memory mapping (mmap(2)). This +mapping is somewhat different on SVR4 and BSD4.3 derived platforms. +

    +The memory mapping can be avoided altogether by using malloc(3) for +stack allocation. In this case the MALLOC_STACK macro should be +defined.

  • +
+

+All machine-dependent feature test macros should be defined in the +md.h header file. The assembly code for setjmp/longjmp +replacement functions for all CPU architectures should be placed in +the md.S file. +

+The current version of the library is ported to: +

    +
  • IRIX 6.x (both 32 and 64 bit)
  • +
  • Linux (kernel 2.x and glibc 2.x) on x86, Alpha, MIPS and MIPSEL, + SPARC, ARM, PowerPC, 68k, HPPA, S390, IA-64, and Opteron (AMD-64)
  • +
  • Solaris 2.x (SunOS 5.x) on x86, AMD64, SPARC, and SPARC-64
  • +
  • AIX 4.x
  • +
  • HP-UX 11 (both 32 and 64 bit)
  • +
  • Tru64/OSF1
  • +
  • FreeBSD on x86, AMD64, and Alpha
  • +
  • OpenBSD on x86, AMD64, Alpha, and SPARC
  • +
  • NetBSD on x86, Alpha, SPARC, and VAX
  • +
  • MacOS X (Darwin) on PowerPC (32 bit) and Intel (both 32 and 64 bit) [universal]
  • +
  • Cygwin
  • +
+

+ + +

Signals

+Signal handling in an application using State Threads should be treated the +same way as in a classical UNIX process application. There is no such +thing as per-thread signal mask, all threads share the same signal handlers, +and only asynchronous-safe functions can be used in signal handlers. +However, there is a way to process signals synchronously by converting a +signal event to an I/O event: a signal catching function does a write to +a pipe which will be processed synchronously by a dedicated signal handling +thread. The following code demonstrates this technique (error handling is +omitted for clarity): +
+
+/* Per-process pipe which is used as a signal queue. */
+/* Up to PIPE_BUF/sizeof(int) signals can be queued up. */
+int sig_pipe[2];
+
+/* Signal catching function. */
+/* Converts signal event to I/O event. */
+void sig_catcher(int signo)
+{
+  int err;
+
+  /* Save errno to restore it after the write() */
+  err = errno;
+  /* write() is reentrant/async-safe */
+  write(sig_pipe[1], &signo, sizeof(int));
+  errno = err;
+}
+
+/* Signal processing function. */
+/* This is the "main" function of the signal processing thread. */
+void *sig_process(void *arg)
+{
+  st_netfd_t nfd;
+  int signo;
+
+  nfd = st_netfd_open(sig_pipe[0]);
+
+  for ( ; ; ) {
+    /* Read the next signal from the pipe */
+    st_read(nfd, &signo, sizeof(int), ST_UTIME_NO_TIMEOUT);
+
+    /* Process signal synchronously */
+    switch (signo) {
+    case SIGHUP:
+      /* do something here - reread config files, etc. */
+      break;
+    case SIGTERM:
+      /* do something here - cleanup, etc. */
+      break;
+      /*      .
+              .
+         Other signals
+              .
+              .
+      */
+    }
+  }
+
+  return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+  struct sigaction sa;
+        .
+        .
+        .
+
+  /* Create signal pipe */
+  pipe(sig_pipe);
+
+  /* Create signal processing thread */
+  st_thread_create(sig_process, NULL, 0, 0);
+
+  /* Install sig_catcher() as a signal handler */
+  sa.sa_handler = sig_catcher;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = 0;
+  sigaction(SIGHUP, &sa, NULL);
+
+  sa.sa_handler = sig_catcher;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = 0;
+  sigaction(SIGTERM, &sa, NULL);
+
+        .
+        .
+        .
+      
+}
+
+
+

+Note that if multiple processes are used (see below), the signal pipe should +be initialized after the fork(2) call so that each process has its +own private pipe. +

+ + +

Intra-Process Synchronization

+Due to the event-driven nature of the library scheduler, the thread context +switch (process state change) can only happen in a well-known set of +library functions. This set includes functions in which a thread may +"block": I/O functions (st_read(), st_write(), etc.), +sleep functions (st_sleep(), etc.), and thread synchronization +functions (st_thread_join(), st_cond_wait(), etc.). As a result, +process-specific global data need not to be protected by locks since a thread +cannot be rescheduled while in a critical section (and only one thread at a +time can access the same memory location). By the same token, +non thread-safe functions (in a traditional sense) can be safely used with +the State Threads. The library's mutex facilities are practically useless +for a correctly written application (no blocking functions in critical +section) and are provided mostly for completeness. This absence of locking +greatly simplifies an application design and provides a foundation for +scalability. +

+ + +

Inter-Process Synchronization

+The State Threads library makes it possible to multiplex a large number +of simultaneous connections onto a much smaller number of separate +processes, where each process uses a many-to-one user-level threading +implementation (N of M:1 mappings rather than one M:N +mapping used in native threading libraries on some platforms). This design +is key to the application's scalability. One can think about it as if a +set of all threads is partitioned into separate groups (processes) where +each group has a separate pool of resources (virtual address space, file +descriptors, etc.). An application designer has full control of how many +groups (processes) an application creates and what resources, if any, +are shared among different groups via standard UNIX inter-process +communication (IPC) facilities.

+There are several reasons for creating multiple processes: +

+

    +
  • To take advantage of multiple hardware entities (CPUs, disks, etc.) +available in the system (hardware parallelism).
  • +

    +

  • To reduce risk of losing a large number of user connections when one of +the processes crashes. For example, if C user connections (threads) +are multiplexed onto P processes and one of the processes crashes, +only a fraction (C/P) of all connections will be lost.
  • +

    +

  • To overcome per-process resource limitations imposed by the OS. For +example, if select(2) is used for event polling, the number of +simultaneous connections (threads) per process is +limited by the FD_SETSIZE parameter (see select(2)). +If FD_SETSIZE is equal to 1024 and each connection needs one file +descriptor, then an application should create 10 processes to support 10,000 +simultaneous connections.
  • +
+

+Ideally all user sessions are completely independent, so there is no need for +inter-process communication. It is always better to have several separate +smaller process-specific resources (e.g., data caches) than to have one large +resource shared (and modified) by all processes. Sometimes, however, there +is a need to share a common resource among different processes. In that case, +standard UNIX IPC facilities can be used. In addition to that, there is a way +to synchronize different processes so that only the thread accessing the +shared resource will be suspended (but not the entire process) if that resource +is unavailable. In the following code fragment a pipe is used as a counting +semaphore for inter-process synchronization: +

+#ifndef PIPE_BUF
+#define PIPE_BUF 512  /* POSIX */
+#endif
+
+/* Semaphore data structure */
+typedef struct ipc_sem {
+  st_netfd_t rdfd;  /* read descriptor */
+  st_netfd_t wrfd;  /* write descriptor */
+} ipc_sem_t;
+
+/* Create and initialize the semaphore. Should be called before fork(2). */
+/* 'value' must be less than PIPE_BUF. */
+/* If 'value' is 1, the semaphore works as mutex. */
+ipc_sem_t *ipc_sem_create(int value)
+{
+  ipc_sem_t *sem;
+  int p[2];
+  char b[PIPE_BUF];
+
+  /* Error checking is omitted for clarity */
+  sem = malloc(sizeof(ipc_sem_t));
+
+  /* Create the pipe */
+  pipe(p);
+  sem->rdfd = st_netfd_open(p[0]);
+  sem->wrfd = st_netfd_open(p[1]);
+
+  /* Initialize the semaphore: put 'value' bytes into the pipe */
+  write(p[1], b, value);
+
+  return sem;
+}
+
+/* Try to decrement the "value" of the semaphore. */
+/* If "value" is 0, the calling thread blocks on the semaphore. */
+int ipc_sem_wait(ipc_sem_t *sem)
+{
+  char c;
+
+  /* Read one byte from the pipe */
+  if (st_read(sem->rdfd, &c, 1, ST_UTIME_NO_TIMEOUT) != 1)
+    return -1;
+
+  return 0;
+}
+
+/* Increment the "value" of the semaphore. */
+int ipc_sem_post(ipc_sem_t *sem)
+{
+  char c;
+
+  if (st_write(sem->wrfd, &c, 1, ST_UTIME_NO_TIMEOUT) != 1)
+    return -1;
+
+  return 0;
+}
+
+
+

+ +Generally, the following steps should be followed when writing an application +using the State Threads library: +

+

    +
  1. Initialize the library (st_init()).
  2. +

    +

  3. Create resources that will be shared among different processes: + create and bind listening sockets, create shared memory segments, IPC + channels, synchronization primitives, etc.
  4. +

    +

  5. Create several processes (fork(2)). The parent process should + either exit or become a "watchdog" (e.g., it starts a new process when + an existing one crashes, does a cleanup upon application termination, + etc.).
  6. +

    +

  7. In each child process create a pool of threads + (st_thread_create()) to handle user connections.
  8. +
+

+ + +

Non-Network I/O

+ +The State Threads architecture uses non-blocking I/O on +st_netfd_t objects for concurrent processing of multiple user +connections. This architecture has a drawback: the entire process and +all its threads may block for the duration of a disk or other +non-network I/O operation, whether through State Threads I/O functions, +direct system calls, or standard I/O functions. (This is applicable +mostly to disk reads; disk writes are usually performed +asynchronously -- data goes to the buffer cache to be written to disk +later.) Fortunately, disk I/O (unlike network I/O) usually takes a +finite and predictable amount of time, but this may not be true for +special devices or user input devices (including stdin). Nevertheless, +such I/O reduces throughput of the system and increases response times. +There are several ways to design an application to overcome this +drawback: + +

+

+

+ + +

Timeouts

+ +The timeout parameter to st_cond_timedwait() and the +I/O functions, and the arguments to st_sleep() and +st_usleep() specify a maximum time to wait since the last +context switch not since the beginning of the function call. + +

The State Threads' time resolution is actually the time interval +between context switches. That time interval may be large in some +situations, for example, when a single thread does a lot of work +continuously. Note that a steady, uninterrupted stream of network I/O +qualifies for this description; a context switch occurs only when a +thread blocks. + +

If a specified I/O timeout is less than the time interval between +context switches the function may return with a timeout error before +that amount of time has elapsed since the beginning of the function +call. For example, if eight milliseconds have passed since the last +context switch and an I/O function with a timeout of 10 milliseconds +blocks, causing a switch, the call may return with a timeout error as +little as two milliseconds after it was called. (On Linux, +select()'s timeout is an upper bound on the amount of +time elapsed before select returns.) Similarly, if 12 ms have passed +already, the function may return immediately. + +

In almost all cases I/O timeouts should be used only for detecting a +broken network connection or for preventing a peer from holding an idle +connection for too long. Therefore for most applications realistic I/O +timeouts should be on the order of seconds. Furthermore, there's +probably no point in retrying operations that time out. Rather than +retrying simply use a larger timeout in the first place. + +

The largest valid timeout value is platform-dependent and may be +significantly less than INT_MAX seconds for select() +or INT_MAX milliseconds for poll(). Generally, you +should not use timeouts exceeding several hours. Use +ST_UTIME_NO_TIMEOUT (-1) as a special value to +indicate infinite timeout or indefinite sleep. Use +ST_UTIME_NO_WAIT (0) to indicate no waiting at all. + +

+


+

+ + + diff --git a/trunk/3rdparty/st-srs/docs/reference.html b/trunk/3rdparty/st-srs/docs/reference.html new file mode 100644 index 0000000000..3c9c7bd783 --- /dev/null +++ b/trunk/3rdparty/st-srs/docs/reference.html @@ -0,0 +1,3120 @@ + + +State Threads Library Reference + + + +

State Threads Library Reference

+ +
+
Types
+
st_thread_t
+
st_cond_t
+
st_mutex_t
+
st_utime_t
+
st_netfd_t
+
st_switch_cb_t
+

+

Error Handling
+

+

Library Initialization
+

+

st_init()
+
st_getfdlimit()
+
st_set_eventsys()
+
st_get_eventsys()
+
st_get_eventsys_name()
+
st_set_utime_function()
+
st_timecache_set()
+
st_randomize_stacks()
+

+

st_switch_cb_t type
+
st_set_switch_in_cb()
+
st_set_switch_out_cb()
+

+

Thread Control and Identification
+

+

st_thread_t type
+
st_thread_create()
+
st_thread_exit()
+
st_thread_join()
+
st_thread_self()
+
st_thread_interrupt()
+
st_sleep()
+
st_usleep()
+
st_randomize_stacks()
+

+

Per-Thread Private Data
+

+

st_key_create()
+
st_key_getlimit()
+
st_thread_setspecific()
+
st_thread_getspecific()
+

+

Synchronization
+

+

st_cond_t type
+
st_cond_new()
+
st_cond_destroy()
+
st_cond_wait()
+
st_cond_timedwait()
+
st_cond_signal()
+
st_cond_broadcast()
+

+

st_mutex_t type
+
st_mutex_new()
+
st_mutex_destroy()
+
st_mutex_lock()
+
st_mutex_trylock()
+
st_mutex_unlock()
+

+

Timing
+

+

st_utime_t type
+
st_utime()
+
st_set_utime_function()
+
st_timecache_set()
+
st_time()
+

+

I/O Functions
+

+

st_netfd_t type
+
st_netfd_open()
+
st_netfd_open_socket()
+
st_netfd_free()
+
st_netfd_close()
+
st_netfd_fileno()
+
st_netfd_setspecific()
+
st_netfd_getspecific()
+
st_netfd_serialize_accept()
+
+
st_netfd_poll()
+

+

st_accept()
+
st_connect()
+
st_read()
+
st_read_fully()
+
st_read_resid()
+
st_readv()
+
st_readv_resid()
+
st_write()
+
st_write_resid()
+
st_writev()
+
st_writev_resid()
+
st_recvfrom()
+
st_sendto()
+
st_recvmsg()
+
st_sendmsg()
+

+

st_open()
+
st_poll()
+

+

Program Structure
+

+

List of Blocking Functions
+

+

+

+


+

+ + + +

Types

+ +The State Thread library defines the following types in the st.h +header file: +

+

+
st_thread_t
+
st_cond_t
+
st_mutex_t
+
st_utime_t
+
st_netfd_t
+
+

+


+

+ + +

st_thread_t

+ +Thread type. +

+

Syntax
+ +
+#include <st.h>
+
+typedef void *  st_thread_t;
+
+

+

Description
+ +A thread is represented and identified by a pointer to an opaque data +structure. This pointer is a required parameter for most of the functions +that operate on threads. +

+The thread identifier remains valid until the thread returns from its root +function and, if the thread was created joinable, is joined. +

+


+

+ + +

st_cond_t

+ +Condition variable type. +

+

Syntax
+ +
+#include <st.h>
+
+typedef void *  st_cond_t;
+
+

+

Description
+ +A condition variable is an opaque object identified by a pointer. +Condition variables provide synchronization primitives to wait for or wake +up threads waiting for certain conditions to be satisfied. +

+In the State Threads library there is no need to lock a mutex before +waiting on a condition variable. +

+


+

+ + +

st_mutex_t

+ +Mutex type. +

+

Syntax
+ +
+#include <st.h>
+
+typedef void *  st_mutex_t;
+
+

+

Description
+ +A mutex is an opaque object identified by a pointer. +Mutual exclusion locks (mutexes) are used to serialize the execution of +threads through critical sections of code. +

+If application using the State Threads library is written with no +I/O or control yielding in critical sections (that is no +blocking functions in critical sections), then there is +no need for mutexes.

+These mutexes can only be used for intra-process thread synchronization. +They cannot be used for inter-process synchronization. +

+


+

+ + +

st_utime_t

+ +High resolution time type ("u" stands for "micro"). +

+

Syntax
+ +
+#include <st.h>
+
+typedef unsigned long long  st_utime_t;
+
+

+

Description
+ +This datatype (unsigned 64-bit integer) represents high-resolution real time +expressed in microseconds since some arbitrary time in the past. It is not +correlated in any way to the time of day. +

+


+

+ + +

st_netfd_t

+ +File descriptor type. +

+

Syntax
+ +
+#include <st.h>
+
+typedef void *  st_netfd_t;
+
+

+

Description
+ +This datatype typically represents any open end point of network +communication (socket, end point of a pipe, FIFO, etc.) but can +encapsulate any open file descriptor. Objects of this type are +identified by a pointer to an opaque data structure. + +

+


+

+ + +

st_switch_cb_t

+ +Context switch callback function type. +

+

Syntax
+ +
+#include <st.h>
+
+typedef void (*st_switch_cb_t)(void);
+
+

+

Description
+ +This datatype is a convenience type for describing a pointer +to a function that will be called when a thread is set to stop +or set to run. +This feature is available only when ST_SWITCH_CB is defined +in <st.h>. + +

+


+

+ + +

Error Handling

+ + +All State Threads library non-void functions return on success either a +non-negative integer or a pointer to a newly created object (constructor-type +functions). On failure they return either -1 or a NULL +pointer respectively and set global errno to indicate the error. +It is safe to use errno because it is set right before the function +return and only one thread at a time can modify its value.

+The perror(3) function can be used to produce an error message on the +standard error output. +

+


+

+ + +

Library Initialization

+ +

+

+
st_init()
+
st_getfdlimit()
+
st_set_eventsys()
+
st_get_eventsys()
+
st_get_eventsys_name()
+

+These functions operate on a callback function of type +st_switch_cb_t: +

st_set_switch_in_cb()
+
st_set_switch_out_cb()
+
+

+


+

+ + +

st_init()

+ +Initializes the runtime. +

+

Syntax
+ +
+#include <st.h>
+
+int st_init(void);
+
+

+

Parameters
+None. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error. +

+

Description
+This function initializes the library runtime. It should be called near +the beginning of the application's main() function before any other +State Threads library function is called.

+Among other things, this function limits the number of open file descriptors +to the OS imposed per-process maximum number or, if select(2) is +used, to FD_SETSIZE, whichever is less (getrlimit(2)). +This limit can be +retrieved by st_getfdlimit(). It also sets the +disposition of the SIGPIPE signal to SIG_IGN (to be ignored) +(signal(5)). +

+Unlike POSIX threads, a new process created by the fork(2) system +call is an exact copy of the calling process and all state threads +which are running in the parent do exist in the child. That means that +st_init() may be called either before or after multiple processes +are created by fork(2). +

+If the library runtime is not properly initialized (e.g., st_init() +is accidentally omitted), then the process will receive either an arithmetic +exception (SIGFPE or SIGTRAP) or segmentation fault (SIGSEGV) signal upon +new thread creation or the first context switch, respectively. +

+


+

+ +

st_getfdlimit()

+ +Returns the maximum number of file descriptors that the calling process +can open. +

+

Syntax
+ +
+#include <st.h>
+
+int st_getfdlimit(void);
+
+

+

Parameters
+None. +

+

Returns
+The maximum number of file descriptors that the calling process can open. +If this function is called before the library is successfully initialized by +st_init(), a value of -1 is returned. +

+

Description
+This function returns the limit on the number of open file descriptors which +is set by the st_init() function. +

+


+

+ + +

st_set_eventsys()

+ +Sets event notification mechanism. +

+

Syntax
+ +
+#include <st.h>
+
+int st_set_eventsys(int eventsys);
+
+

+

Parameters
+st_set_eventsys() has the following parameter:

+eventsys

+An integer value identifying selected event notification mechanism. The +following values are defined in the st.h header file: +

+ + + + + + + + + + + + + + + +
ST_EVENTSYS_DEFAULTUse default event notification mechanism. Usually it's select(2) +but if the library was compiled with the USE_POLL macro defined +then the default is poll(2).
ST_EVENTSYS_SELECTUse select(2) as an event notification mechanism.
ST_EVENTSYS_POLLUse poll(2) as an event notification mechanism.
ST_EVENTSYS_ALTUse an alternative event notification mechanism. The actual +mechanism selected depends on OS support. For example, epoll(4) +will be used on Linux if supported and kqueue(2) will be used +on FreeBSD/OpenBSD. If the OS supports no alternative event +notification mechanism, setting ST_EVENTSYS_ALT has no effect +and the ST_EVENTSYS_DEFAULT mechanism will be used.
+

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + + + + +
EINVAL +The supplied eventsys parameter has an invalid value. +
EBUSY +The event notification mechanism has already been set. +
+

+

Description
+This function sets the event notification mechanism that will be used by +the State Threads library. To have any effect, it must be called +before the st_init() function which performs +the actual initialization. If st_set_eventsys() is not called, +st_init() will set the ST_EVENTSYS_DEFAULT +mechanism. The mechanism cannot be changed once set. +

+There are no strict rules for selecting an event notification +mechanism. The "best" one depends on how your application behaves. +Try a few to see which one works best for you. As a rule of +thumb, you should use the ST_EVENTSYS_ALT mechanism if your +application deals with a very large number of network connections of +which only a few are active at once. +

+


+

+ +

st_get_eventsys()

+ +Returns the integer value identifying the event notification mechanism +being used by the State Threads library. +

+

Syntax
+ +
+#include <st.h>
+
+int st_get_eventsys(void);
+
+

+

Parameters
+None. +

+

Returns
+The integer value identifying the current event notification mechanism. +This value can be one of the following (see st_set_eventsys()): +ST_EVENTSYS_SELECT, ST_EVENTSYS_POLL, or +ST_EVENTSYS_ALT. Future versions of the library may return other +values. If a mechanism hasn't been set yet, a value of -1 is returned. +

+

Description
+This function returns the integer value identifying the event notification +mechanism which is actually being used by the State Threads library. +

+


+

+ +

st_get_eventsys_name()

+ +Returns the name of the event notification mechanism being used by the +State Threads library. +

+

Syntax
+ +
+#include <st.h>
+
+const char *st_get_eventsys_name(void);
+
+

+

Parameters
+None. +

+

Returns
+The string identifying the current event notification mechanism. If a +mechanism hasn't been set yet (see st_set_eventsys()), an empty string is +returned. Possible return values are "select", +"poll", "kqueue", or "epoll". Future versions +of the library may return other values. +

+

Description
+This function returns the string identifying the event notification +mechanism which is actually being used by the State Threads library. +

+


+

+ + +

st_set_switch_in_cb()

+ + +

st_set_switch_out_cb()

+
+Set the optional callback function for thread switches. +

+

Syntax
+ +
+#include <st.h>
+
+st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb);
+st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb);
+
+

+

Parameters
+st_set_switch_in_cb() and st_set_switch_out_cb() have the +following parameter:

+cb

+A function to be called when a thread is resumed and stopped respectively.

+

Returns
+The previous callback function pointer. +

+

Description
+These functions set the callback for when a thread is resumed and stopped +respectively. After being called any thread switch will call the callback. +Use a NULL pointer to disable the callback (this is the default). +Use st_thread_self() or thread +specific data to differentiate between threads.

+These functions can be called at any time.

+This feature is available only when ST_SWITCH_CB is defined +in <st.h>. +

+


+

+ + +

Thread Control and Identification

+ +

+These functions operate on a thread object of type +st_thread_t. +

+

+
st_thread_create()
+
st_thread_exit()
+
st_thread_join()
+
st_thread_self()
+
st_thread_interrupt()
+
st_sleep()
+
st_usleep()
+
st_randomize_stacks()
+
+

+


+

+ +

st_thread_create()

+ +Creates a new thread. +

+

Syntax
+ +
+#include <st.h>
+
+st_thread_t st_thread_create(void *(*start)(void *arg), void *arg,
+                             int joinable, int stack_size);
+
+
+

+

Parameters
+st_thread_create() has the following parameters:

+start

+A pointer to the thread's start function, which is called as the root of the +new thread. Return from this function terminates a thread.

+arg

+A pointer to the root function's only parameter.

+joinable

+Specifies whether the thread is joinable or unjoinable. If this parameter +is zero, the thread is unjoinable. Otherwise, it is joinable. +See also st_thread_join().

+stack_size

+Specifies your preference for the size of the stack, in bytes, associated +with the newly created thread. If you pass zero in this parameter, the +default stack size will be used. The default stack size is 128 KB on IA-64 +and 64 KB on all other platforms. On IA-64 only a half of stack_size +bytes is used for the memory stack. The other half is used for the register +stack backing store. +

+

Returns
+Upon successful completion, a new thread identifier is returned (this +identifier remains valid until the thread returns from its start function). +Otherwise, NULL is returned and errno is set +to indicate the error. +

+

Description
+This function creates a new thread. Note that the total number of threads +created by the application is limited by the amount of swap space available. +Upon thread creation, stack_size bytes are reserved on the swap +space. The stack pages are not actually used (valid) until touched by the +application. +

+


+

+ +

st_thread_exit()

+ +Terminates the calling thread. +

+

Syntax
+ +
+#include <st.h>
+
+void st_thread_exit(void *retval);
+
+

+

Parameters
+st_thread_exit() has the following parameters:

+retval

+If the thread is joinable, then the value retval may be retrieved +by st_thread_join(). If a thread returns from its +start function, it acts as if it had called st_thread_exit() with +retval as the value returned. +

+

Returns
+Nothing. +

+

Description
+This function terminates the calling thread. When a thread exits, per-thread +private data is destroyed by invoking the destructor function for any +non-NULL thread specific values associated with active keys (see +st_key_create()). This function is implicitly called +when a thread returns from its start function.

+When the last thread terminates the process exits with a zero status value. +

+


+

+ +

st_thread_join()

+ +Blocks the calling thread until a specified thread terminates. +

+

Syntax
+ +
+#include <st.h>
+
+int st_thread_join(st_thread_t thread, void **retvalp);
+
+

+

Parameters
+st_thread_join() has the following parameters:

+thread

+A valid identifier for the thread that is to be joined.

+retvalp

+If this parameter is not NULL, then the exit value of the +thread will be placed in the location referenced by this parameter +(see st_thread_exit()). +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + + + + +
EINVALTarget thread is unjoinable.
EINVALOther thread already waits on the same +joinable thread.
EDEADLKTarget thread is the same as the +calling thread.
EINTRCurrent thread was interrupted by +st_thread_interrupt().
+

+

Description
+This function is used to synchronize the termination of a thread and possibly +retrieve its exit value. Several threads cannot wait for the same thread +to complete - one of the calling threads operates successfully, and the others +terminate with the error. The calling thread is not blocked if the target +thread has already terminated. +

+


+

+ +

st_thread_self()

+ +Identifies the calling thread. +

+

Syntax
+ +
+#include <st.h>
+
+st_thread_t st_thread_self(void);
+
+

+

Parameters
+None. +

+

Returns
+Always returns a valid reference to the calling thread - a self-identity. +

+

Description
+This function identifies the calling thread. This is the same identifier +that the creating thread obtains from +st_thread_create(). +

+


+

+ +

st_thread_interrupt()

+ +Interrupts a target thread. +

+

Syntax
+ +
+#include <st.h>
+
+void st_thread_interrupt(st_thread_t thread);
+
+

+

Parameters
+st_thread_interrupt() has the following parameters:

+thread

+A valid identifier for the thread being interrupted. +

+

Returns
+Nothing. +

+

Description
+This function interrupts (unblocks) a target thread that is blocked in one +of the blocking functions. A function that was interrupted +returns an error and sets errno to EINTR. It is up to +the target thread to act upon an interrupt (e.g., it may exit or just +abort the current transaction).

+Note: State Threads library functions are never interrupted by a +caught signal. A blocking library function returns an error and sets +errno to EINTR only if the current thread was +interrupted via st_thread_interrupt(). +

+If a target thread is already runnable or running (e.g., it is a newly +created thread or calling thread itself), this function will prevent it +from subsequent blocking. In other words, the interrupt will be "delivered" +only when a target thread is about to block. +

+


+

+ +

st_sleep(), st_usleep()

+ +Suspends current thread for a specified amount of time. +

+

Syntax
+ +
+#include <st.h>
+
+int st_sleep(int secs);
+
+int st_usleep(st_utime_t usecs);
+
+

+

Parameters
+st_sleep() has the following parameters:

+secs

+The number of seconds you want the thread to sleep for. +

+st_usleep() has the following parameters:

+usecs

+The number of microseconds you want the thread to sleep for. This parameter +is a variable of type st_utime_t. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
+

+

Description
+These functions suspend the calling thread from execution for a specified +number of seconds (st_sleep()) or microseconds (st_usleep()). +

+ +If zero is passed as a parameter to st_sleep(), or +ST_UTIME_NO_WAIT (0) is passed to +st_usleep(), the calling thread yields, thus potentially +allowing another thread to run. + +

+ +If -1 is passed as a parameter to st_sleep(), or +ST_UTIME_NO_TIMEOUT (-1) is passed to +st_usleep(), the calling thread will be suspended permanently. +It can be resumed again by interrupting it via st_thread_interrupt(). + +

+


+

+ +

st_randomize_stacks()

+ +Turns stack base address randomization on or off. +

+

Syntax
+ +
+#include <st.h>
+
+int st_randomize_stacks(int on);
+
+

+

Parameters
+st_randomize_stacks() has the following parameters:

+on

+If this parameter has a non-zero value, the State Threads library +randomizes the base addresses of stacks allocated for threads created +after this call. Otherwise new threads' stacks are typically page +aligned. +

+

Returns
+The previous state of stack randomization (a value of 0 if it +was off and a non-zero value otherwise). +

+

Description
+Randomizing state threads' stack bases may improve cache performance on +some systems when large numbers of state threads all perform roughly the +same work, as when they all start from the same root function. On many +modern systems the performance increase is negligible. You should +compare your application's performance with this feature on and off to +see if you really need it. +

+When randomization is enabled, new stacks are allocated one page larger +to accomodate the randomization. +

+This call affects only threads created afterward. It has no effect on +existing threads. +

+


+

+ + +

Per-Thread Private Data

+ +These functions allow to associate private data with each of the threads in +a process. +

+

+
st_key_create()
+
st_key_getlimit()
+
st_thread_setspecific()
+
st_thread_getspecific()
+
+

+


+

+ +

st_key_create()

+ +Creates a key (non-negative integer) that can be used by all +threads in the process to get and set thread-specific data. +

+

Syntax
+ +
+#include <st.h>
+
+int st_key_create(int *keyp, void (*destructor)(void *));
+
+

+

Parameters
+st_key_create() has the following parameters:

+keyp

+The newly created key is returned in the memory pointed to by this parameter. +The new key can be used with +st_thread_setspecific() and +st_thread_getspecific().

+destructor

+Specifies an optional destructor function for the private data associated +with the key. This function can be specified as NULL. +Upon thread exit (see st_thread_exit()), if a key +has a non-NULL destructor and has a non-NULL value +associated with that key, then the destructor function will be +called with the associated value. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + +
EAGAINThe limit on the total number of keys per +process has been exceeded (see st_key_getlimit()). +
+

+

Description
+If this function is successful, every thread in the same process is capable +of associating private data with the new key. After a new key is created, all +active threads have the value NULL associated with that key. +After a new thread is created, the value NULL is associated with +all keys for that thread. If a non-NULL destructor function is +registered with a new key, it will be called at one of two times, as long as +the private data is not NULL: + +

+The key maintains independent data values for each binding thread. A thread +can get access only to its own thread-specific data. There is no way to +deallocate a private data key once it is allocated. +

+


+

+ +

st_key_getlimit()

+ +Returns the key limit. +

+

Syntax
+ +
+#include <st.h>
+
+int st_key_getlimit(void);
+
+

+

Parameters
+None. +

+

Returns
+The limit on the total number of keys per process. +

+

Description
+This function can be used to obtain the limit on the total number of keys +per process (see st_key_create()). +

+


+

+ +

st_thread_setspecific()

+ +Sets per-thread private data. +

+

Syntax
+ +
+#include <st.h>
+
+int st_thread_setspecific(int key, void *value);
+
+

+

Parameters
+st_thread_setspecific() has the following parameters:

+key

+This parameter represents a key with which thread-specific data is associated. +

+value

+The per-thread private data, or more likely, a pointer to the data which is +associated with key. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + + +
EINVALThe specified key is invalid.
+

+

Description
+This function associates a thread-specific value with key. +Different threads may bind different values to the same key.

+If the thread already has non-NULL private data associated with +key, and if the destructor function for that key is not +NULL, this destructor function will be called before setting the +new data value. +

+


+

+ +

st_thread_getspecific()

+ +Retrieves the per-thread private data for the current thread. +

+

Syntax
+ +
+#include <st.h>
+
+void *st_thread_getspecific(int key);
+
+

+

Parameters
+st_thread_getspecific() has the following parameters:

+key

+This parameter represents a key with which thread-specific data is associated. +

+

Returns
+The thread-specific data associated with key. If no data is +associated with key, then NULL is returned. +

+

Description
+This function returns the calling thread's value that is bound to the +specified key (see +st_thread_setspecific()). +

+


+

+ + +

Synchronization

+ +

+These functions operate on condition variables +and mutual exclusion locks (mutexes).

+Functions are provided to wait on a condition variable and to wake up +(signal) threads that are waiting on the condition variable. +

+

+
st_cond_new()
+
st_cond_destroy()
+
st_cond_wait()
+
st_cond_timedwait()
+
st_cond_signal()
+
st_cond_broadcast()
+

+

st_mutex_new()
+
st_mutex_destroy()
+
st_mutex_lock()
+
st_mutex_trylock()
+
st_mutex_unlock()
+
+

+


+

+ +

st_cond_new()

+ +Creates a new condition variable. +

+

Syntax
+ +
+#include <st.h>
+
+st_cond_t st_cond_new(void);
+
+

+

Parameters
+None. +

+

Returns
+Upon successful completion, a new condition variable identifier is returned. +Otherwise, NULL is returned and errno is set +to indicate the error. +

+

Description
+This function creates a new condition variable. +

+


+

+ +

st_cond_destroy()

+ +Destroys a condition variable. +

+

Syntax
+ +
+#include <st.h>
+
+int st_cond_destroy(st_cond_t cvar);
+
+

+

Parameters
+st_cond_destroy() has the following parameters:

+cvar

+An identifier of the condition variable object to be destroyed. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + + +
EBUSYThe condition variable is currently being +used by one or more threads.
+

+

Description
+This function destroys a condition variable. The caller is responsible for +ensuring that the condition variable is no longer in use. +

+


+

+ +

st_cond_wait()

+ +Waits on a condition. +

+

Syntax
+ +
+#include <st.h>
+
+int st_cond_wait(st_cond_t cvar);
+
+

+

Parameters
+st_cond_wait() has the following parameters:

+cvar

+The condition variable on which to wait. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
+

+

Description
+This function is used to block on a condition variable. A return from this +function does not guarantee that the condition or event for which the caller +was waiting actually occurred. It is the responsibility of the caller +to recheck the condition wait predicate before proceeding.

+Note: The State Threads library scheduling guarantees that the +condition cannot change between the checking and blocking, therefore there +is no need for mutex protection. You must not call any +blocking functions between the condition checking and +the st_cond_wait() call. +

+


+

+ +

st_cond_timedwait()

+ +Waits on a condition. +

+

Syntax
+ +
+#include <st.h>
+
+int st_cond_timedwait(st_cond_t cvar, st_utime_t timeout);
+
+

+

Parameters
+st_cond_timedwait() has the following parameters:

+cvar

+The condition variable on which to wait.

+timeout

+If the number of microseconds specified by this parameter passes before the +waiting thread is signalled, an error is returned. This parameter is a +variable of type st_utime_t. Note that this +time value is a time delta; it is not an absolute time. +Also note that timeouts are measured since +the last context switch. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred before the thread was +awakened by st_cond_signal() or +st_cond_broadcast().
+

+

Description
+This function works the same way as st_cond_wait(), +except that an error is returned if the number of microseconds specified by +timeout passes before the waiting thread is signalled. +

+


+

+ +

st_cond_signal()

+ +Unblocks a thread waiting on a condition variable. +

+

Syntax
+ +
+#include <st.h>
+
+int st_cond_signal(st_cond_t cvar);
+
+

+

Parameters
+st_cond_signal() has the following parameters:

+cvar

+The condition variable to signal. +

+

Returns
+Always zero. +

+

Description
+This function unblocks (signals) one of the threads that are blocked on +cvar at the time of the call. If no thread is waiting on the +condition variable, the signal operation is a no-op. +

+


+

+ +

st_cond_broadcast()

+ +Unblocks all threads waiting on a condition variable. +

+

Syntax
+ +
+#include <st.h>
+
+int st_cond_broadcast(st_cond_t cvar);
+
+

+

Parameters
+st_cond_broadcast() has the following parameters:

+cvar

+The condition variable to broadcast. +

+

Returns
+Always zero. +

+

Description
+This function unblocks all threads blocked on the specified condition +variable at the time of the call. If no threads are waiting, this operation +is a no-op. +

+


+

+ + +

st_mutex_new()

+ +Creates a new mutual exclusion lock (mutex). +

+

Syntax
+ +
+#include <st.h>
+
+st_mutex_t st_mutex_new(void);
+
+

+

Parameters
+None. +

+

Returns
+Upon successful completion, a new mutex identifier is returned. +Otherwise, NULL is returned and errno is set to +indicate the error. +

+

Description
+This function creates a new opaque mutual exclusion lock (see +st_mutex_t). +

+


+

+ +

st_mutex_destroy()

+ +Destroys a specified mutex object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_mutex_destroy(st_mutex_t lock);
+
+

+

Parameters
+st_mutex_destroy() has the following parameters:

+lock

+An identifier of the mutex object to be destroyed. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + + +
EBUSYThe mutex is currently being used by +other threads.
+

+

Description
+This function destroys a mutex. The caller is responsible for ensuring +that the mutex is no longer in use. +

+


+

+ +

st_mutex_lock()

+ +Locks a specified mutex object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_mutex_lock(st_mutex_t lock);
+
+

+

Parameters
+st_mutex_lock() has the following parameters:

+lock

+An identifier of the mutex object to be locked. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + + +
EDEADLKThe current thread already owns the mutex. +
EINTRThe current thread was interrupted by +st_thread_interrupt().
+

+

Description
+A thread that calls this function will block until it can gain exclusive +ownership of a mutex, and retains ownership until it calls +st_mutex_unlock(). +

+


+

+ +

st_mutex_trylock()

+ +Attempts to acquire a mutex. +

+

Syntax
+ +
+#include <st.h>
+
+int st_mutex_trylock(st_mutex_t lock);
+
+

+

Parameters
+st_mutex_trylock() has the following parameters:

+lock

+An identifier of the mutex object to be locked. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + +
EBUSYThe mutex is currently held by another +thread.
+

+

Description
+This function attempts to acquire a mutex. If the mutex object is locked +(by any thread, including the current thread), the call returns immediately +with an error. +

+


+

+ +

st_mutex_unlock()

+ +Releases a specified mutex object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_mutex_unlock(st_mutex_t lock);
+
+

+

Parameters
+st_mutex_unlock() has the following parameters:

+lock

+An identifier of the mutex object to be unlocked. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error:

+ + +
EPERMThe current thread does not own the mutex. +
+

+

Description
+This function releases a specified mutex object previously acquired by +st_mutex_lock() or +st_mutex_trylock(). Only the thread that locked +a mutex should unlock it. +

+


+

+ + +

Timing

+ +

+

+
st_utime()
+
st_set_utime_function()
+
st_timecache_set()
+
st_time()
+
+

+


+

+ +

st_utime()

+ +Returns current high-resolution time. +

+

Syntax
+ +
+#include <st.h>
+
+st_utime_t st_utime(void);
+
+

+

Parameters
+None. +

+

Returns
+Current high-resolution time value of type +st_utime_t. +

+

Description
+This function returns the current high-resolution time. Time is +expressed as microseconds since some arbitrary time in the past. It is +not correlated in any way to the time of day. See also st_utime_t and st_time(). +

+


+

+ +

st_set_utime_function()

+ +Set high-resolution time function. +

+

Syntax
+ +
+#include <st.h>
+
+int st_set_utime_function(st_utime_t (*func)(void));
+
+

+

Parameters
+st_set_utime_function() has the following parameters:

+func

+This function will be called to get high-resolution time instead of the +default st_utime() function. It must return +number of microseconds since some arbitrary time in the past. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to EINVAL to indicate the error. +

+

Description
+This function may be called to replace the default implementation of the +st_utime() function. It must be called before the ST +library has been initialized (see st_init()). +The user-provided function func will be invoked whenever +st_utime() is called to obtain current high-resolution time. +Replacing default implementation may be useful, for example, for taking +advantage of high performance CPU cycle counters. +

+


+

+ +

st_timecache_set()

+ +Turns the time caching on or off. +

+

Syntax
+ +
+#include <st.h>
+
+int st_timecache_set(int on);
+
+

+

Parameters
+st_timecache_set() has the following parameters:

+on

+If this parameter has a non-zero value, the time caching is turned on +(enabled). Otherwise, the time caching is turned off (disabled). +By default time caching is disabled. +

+

Returns
+The previous state of time caching (a value of 0 if it was off and +a value of 1 otherwise). +

+

Description
+The State Threads library has the ability to "cache" the time value that is +reported by the time(2) system call. If the time caching is enabled +by calling this function with a non-zero argument, then the result value +of time(2) will be stored and updated at most once per second. The +cached time can be retrieved by st_time(). +By default time caching is disabled. +You may enable or disable time caching at any time but generally +you enable it once (if desired) during program initialization.

+Note: There are some pathological cases (e.g., very heavy loads during +application benchmarking) when a single thread runs for a long time without +giving up control and the cached time value is not updated properly. If you +always need "real-time" time values, don't enable the time caching. +

+


+

+ +

st_time()

+ +Returns the value of time in seconds since 00:00:00 UTC, January 1, 1970. +

+

Syntax
+ +
+#include <st.h>
+
+time_t st_time(void);
+
+

+

Parameters
+None. +

+

Returns
+The value of time in seconds since 00:00:00 UTC, January 1, 1970 as reported +by the time(2) system call. +

+

Description
+If the time caching was enabled by +st_timecache_set(), then this function returns +the cached result. Otherwise, it just calls time(2). +

+


+

+ + +

I/O Functions

+ +

+Most State Threads library I/O functions look like corresponding C library +functions with two exceptions: +

    +
  • They operate on file descriptor objects of type +st_netfd_t.
  • +
  • They take an additional argument of type +st_utime_t which represents an inactivity +timeout: if no I/O is possible during this amount of time, I/O functions +return an error code and set errno to ETIME. + +The boundary values ST_UTIME_NO_WAIT (0) and +ST_UTIME_NO_TIMEOUT (-1) for this argument indicate +that the thread should wait no time (function returns immediately) or +wait forever (never time out), respectively. + +Note that timeouts are measured since the +last context switch. +
  • +
+

+

+
st_netfd_open()
+
st_netfd_open_socket()
+
st_netfd_free()
+
st_netfd_close()
+
st_netfd_fileno()
+
st_netfd_setspecific()
+
st_netfd_getspecific()
+
st_netfd_serialize_accept()
+
st_netfd_poll()
+

+

st_accept()
+
st_connect()
+
st_read()
+
st_read_fully()
+
st_read_resid()
+
st_readv()
+
st_read_resid()
+
st_write()
+
st_write_resid()
+
st_writev()
+
st_writev_resid()
+
st_recvfrom()
+
st_sendto()
+
st_recvmsg()
+
st_sendmsg()
+
st_open()
+
st_poll()
+
+

+


+

+ +

st_netfd_open()

+ +Creates a new file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+st_netfd_t st_netfd_open(int osfd);
+
+

+

Parameters
+st_netfd_open() has the following parameters:

+osfd

+ +Any open OS file descriptor; can be obtained from calls to +functions including, but not restricted to, pipe(2), socket(3), +socketpair(3), fcntl(2), dup(2), etc. + + +

+

Returns
+Upon successful completion, a new file descriptor object identifier is +returned. Otherwise, NULL is returned and errno is set +to indicate the error. +

+

Description
+This function creates a new file descriptor object of type +st_netfd_t.

+ +Note: Among other things, this function sets a non-blocking +flag on the underlying OS file descriptor. You should not modify this +flag directly. Also, once an st_netfd_t +has been created with a given file descriptor, you should avoid +passing that descriptor to normal I/O or stdio functions. Since the +O_NONBLOCK flag is shared across dup(2), this applies to +dup()'ed file descriptors as well - for instance, if you pass +standard output or standard input to st_netfd_open(), then +you should use st_write() instead of write +or fprintf when writing to standard error as well - since all +three descriptors could point to the same terminal. If necessary, you +can still use write directly if you remember to check +errno for EAGAIN, but fprintf and other +stdio functions should be avoided completely because, at least on +Linux, the stdio library cannot be made to work reliably with +non-blocking files. (This only applies to file descriptors which are +passed to st_netfd_open() or st_netfd_open_socket(), or which are +related to such descriptors through dup(); other file +descriptors are untouched by State Threads.) +

+


+

+ +

st_netfd_open_socket()

+ +Creates a new file descriptor object from a socket. +

+

Syntax
+ +
+#include <st.h>
+
+st_netfd_t st_netfd_open_socket(int osfd);
+
+

+

Parameters
+st_netfd_open_socket() has the following parameters:

+osfd

+An open OS file descriptor which is a socket initially obtained from a +socket(3) or socketpair(3) call. +

+

Returns
+Upon successful completion, a new file descriptor object identifier is +returned. Otherwise, NULL is returned and errno is set +to indicate the error. +

+

Description
+This function creates a new file descriptor object of type +st_netfd_t which represents an open end +point of network communication.

+Unlike the st_netfd_open() function which may be used +on OS file descriptors of any origin, st_netfd_open_socket() must +be used only on sockets. It is slightly more efficient than +st_netfd_open().

+Note: Among other things, this function sets a non-blocking flag +on the underlying OS socket. You should not modify this flag directly. +See st_netfd_open(). +

+


+

+ +

st_netfd_free()

+ +Frees a file descriptor object without closing the underlying OS file +descriptor. +

+

Syntax
+ +
+#include <st.h>
+
+void st_netfd_free(st_netfd_t fd);
+
+

+

Parameters
+st_netfd_free() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t). +

+

Returns
+Nothing. +

+

Description
+This function frees the memory and other resources identified by the +fd parameter without closing the underlying OS file descriptor. +Any non-NULL descriptor-specific data is destroyed by invoking +the specified destructor function (see st_netfd_setspecific()).

A thread should +not free file descriptor objects that are in use by other threads +because it may lead to unpredictable results (e.g., a freed file +descriptor may be reused without other threads knowing that). +

+


+

+ +

st_netfd_close()

+ +Closes a file descriptor. +

+

Syntax
+ +
+#include <st.h>
+
+int st_netfd_close(st_netfd_t fd);
+
+

+

Parameters
+st_netfd_close() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t). +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error. +

+

Description
+This function closes the underlying OS file descriptor, frees the memory and +other resources identified by the fd parameter. Any non-NULL +descriptor-specific data is destroyed by invoking the specified destructor +function (see st_netfd_setspecific()).

+A thread should not close file descriptor objects that are in use by other +threads because it may lead to unpredictable results (e.g., a closed +file descriptor may be reused without other threads knowing that). +

+


+

+ +

st_netfd_fileno()

+ +Returns an underlying OS file descriptor. +

+

Syntax
+ +
+#include <st.h>
+
+int st_netfd_fileno(st_netfd_t fd);
+
+

+

Parameters
+st_netfd_fileno() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t). +

+

Returns
+An underlying OS file descriptor. +

+

Description
+This function returns the integer OS file descriptor associated with the named +file descriptor object. +

+


+

+ +

st_netfd_setspecific()

+ +Sets per-descriptor private data. +

+

Syntax
+ +
+#include <st.h>
+
+void st_netfd_setspecific(st_netfd_t fd, void *value,
+                          void (*destructor)(void *));
+
+

+

Parameters
+st_netfd_setspecific() has the following parameters:

+fd

+A valid file descriptor object identifier (see +st_netfd_t). +

+value

+The per-descriptor private data, or more likely, a pointer to the data which +is being associated with the named file descriptor object. +

+destructor

+Specifies an optional destructor function for the private data associated +with fd. This function can be specified as NULL. +If value is not NULL, then this destructor function will +be called with value as an argument upon freeing the file descriptor +object (see st_netfd_free() and +st_netfd_close()). +

+

Returns
+Nothing. +

+

Description
+This function allows to associate any data with the specified file +descriptor object (network connection). If a non-NULL destructor +function is registered, it will be called at one of two times, as long as +the associated data is not NULL: +
    +
  • when private data is replaced by calling +st_netfd_setspecific() again +
  • upon freeing the file descriptor object (see +st_netfd_free() and +st_netfd_close()) +
+

+


+

+ +

st_netfd_getspecific()

+ +Retrieves the per-descriptor private data. +

+

Syntax
+ +
+#include <st.h>
+
+void *st_netfd_getspecific(st_netfd_t fd);
+
+

+

Parameters
+st_netfd_getspecific() has the following parameters:

+fd

+A valid file descriptor object identifier (see +st_netfd_t). +

+

Returns
+The data associated with the named file descriptor object. If no data is +associated with fd, then NULL is returned. +

+

Description
+This function allows to retrieve the data that was associated with the +specified file descriptor object (see +st_netfd_setspecific()). +

+


+

+ +

st_netfd_serialize_accept()

+ +Serializes all subsequent accept(3) calls on a specified file +descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_netfd_serialize_accept(st_netfd_t fd);
+
+

+

Parameters
+st_netfd_serialize_accept() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t) which has been successfully created +from a valid listening socket by st_netfd_open() or +st_netfd_open_socket(). +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error. +

+

Description
+On some platforms (e.g., Solaris 2.5 and possibly other SVR4 implementations) +accept(3) calls from different processes on +the same listening socket (see bind(3), listen(3)) must be +serialized. This function causes all subsequent accept(3) calls +made by st_accept() on the specified file descriptor +object to be serialized. +

+st_netfd_serialize_accept() must be called before +creating multiple server processes via fork(2). If the application +does not create multiple processes to accept network connections on +the same listening socket, there is no need to call this function. +

+Deciding whether or not to serialize accepts is tricky. On some +platforms (IRIX, Linux) it's not needed at all and +st_netfd_serialize_accept() is a no-op. On other platforms +it depends on the version of the OS (Solaris 2.6 doesn't need it but +earlier versions do). Serializing accepts does incur a slight +performance penalty so you want to enable it only if necessary. Read +your system's manual pages for accept(2) and select(2) +to see if accept serialization is necessary on your system. +

+st_netfd_serialize_accept() allocates resources that are +freed upon freeing of the specified file descriptor object (see +st_netfd_free() and +st_netfd_close()). +

+


+

+ +

st_netfd_poll()

+ +Waits for I/O on a single file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_netfd_poll(st_netfd_t fd, int how, st_utime_t timeout);
+
+

+

Parameters
+st_netfd_poll() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t). +

+how

+Specifies I/O events of interest. This parameter can be constructed by +OR-ing any combination of the following event flags which are defined +in the poll.h header file:

+ + + + + +
POLLINfd is readable.
POLLOUTfd is is writable.
POLLPRIfd has an exception condition.
+

+timeout

+Amount of time in microseconds the call will block waiting for I/O +to become ready. This parameter is a variable of type +st_utime_t. If this time expires without any +I/O becoming ready, st_netfd_poll() returns an error and sets +errno to ETIME. +Note that timeouts are measured since the +last context switch. +

+

Returns
+If the named file descriptor object is ready for I/O within the specified +amount of time, a value of 0 is returned. Otherwise, a value +of -1 is returned and errno is set to indicate the error: +

+ + + + +
EBADFThe underlying OS file descriptor is invalid. +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred without any I/O +becoming ready.
+

+

Description
+This function returns as soon as I/O is ready on the named file +descriptor object or the specified amount of time expires. The +how parameter should be set to the I/O events (readable, +writable, exception, or some combination) that the caller is interested +in. If the value of timeout is ST_UTIME_NO_TIMEOUT +(-1), this function blocks until a requested I/O event occurs +or until the call is interrupted by st_thread_interrupt().

+Despite having an interface like poll(2), this function uses +the same event notification mechanism as the rest of the library. For +instance if an alternative event nofication mechanism was set using st_set_eventsys(), this function uses that +mechanism to check for events.

+Note: if kqueue(2) is used as an alternative event +notification mechanism (see st_set_eventsys()), the POLLPRI +event flag is not supported and st_netfd_poll() will return an error +if it's set (errno will be set to EINVAL). +

+


+

+ +

st_accept()

+ +Accepts a connection on a specified file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+st_netfd_t st_accept(st_netfd_t fd, struct sockaddr *addr, int *addrlen,
+                     st_utime_t timeout);
+
+

+

Parameters
+st_accept() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t) representing the rendezvous socket +on which the caller is willing to accept new connections. This object has been +created from a valid listening socket by +st_netfd_open() or +st_netfd_open_socket().

+addr

+If this value is non-zero, it is a result parameter that is filled +in with the address of the connecting entity, as known to the communications +layer (see accept(3)).

+addrlen

+This parameter should initially contain the amount of space pointed to by +addr; on return it will contain the actual length (in bytes) of the +address returned (see accept(3)).

+timeout

+A value of type st_utime_t specifying the time +limit in microseconds for completion of the accept operation. +Note that timeouts are measured since the +last context switch. +

+

Returns
+Upon successful completion, a new file descriptor object identifier +representing the newly accepted connection is returned. Otherwise, +NULL is returned and errno is set to indicate the error. +Possible errno values are the same as set by the accept(3) +call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred and no pending +connection was accepted.
+

+

Description
+This function accepts the first connection from the queue of pending +connections and creates a new file descriptor object for the newly +accepted connection. The rendezvous socket can still be used to accept +more connections.

+st_accept() blocks the calling thread until either a new connection +is successfully accepted or an error occurs. If no pending connection can +be accepted before the time limit, this function returns NULL +and sets errno to ETIME. +

+


+

+ +

st_connect()

+ +Initiates a connection on a specified file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_connect(st_netfd_t fd, struct sockaddr *addr, int addrlen,
+               st_utime_t timeout);
+
+

+

Parameters
+st_connect() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t) representing a socket.

+addr

+A pointer to the address of the peer to which the socket is to be connected. +

+addrlen

+This parameter specifies the amount of space pointed to by addr. +

+timeout

+A value of type st_utime_t specifying the time +limit in microseconds for completion of the connect operation. +Note that timeouts are measured since the +last context switch. +

+

Returns
+Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error. Possible errno values are the same as set +by the connect(3) call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred and connection setup +was not completed.
+

+

Description
+This function is usually invoked on a file descriptor object representing +a TCP socket. Upon completion it establishes a TCP connection to the peer. +If the underlying OS socket is not bound, it will be bound to an arbitrary +local address (see connect(3)).

+st_connect() blocks the calling thread until either the connection +is successfully established or an error occurs. If the connection setup +cannot complete before the specified time limit, this function fails with +errno set to ETIME. +

+


+

+ +

st_read()

+ +Reads data from a specified file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+ssize_t st_read(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout);
+
+

+

Parameters
+st_read() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t).

+buf

+A pointer to a buffer to hold the data read in. On output the buffer +contains the data.

+nbyte

+The size of buf in bytes.

+timeout

+A value of type st_utime_t specifying the time +limit in microseconds for completion of the read operation. +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success a non-negative integer indicating the number of bytes actually +read is returned (a value of 0 means the network connection is +closed or end of file is reached). Otherwise, a value of -1 is +returned and errno is set to indicate the error. +Possible errno values are the same as set by the read(2) +call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred and no data was read. +
+

+

Description
+This function blocks the calling thread until it encounters an end-of-stream +indication, some positive number of bytes (but no more than nbyte +bytes) are read in, a timeout occurs, or an error occurs. +

+


+

+ +

st_read_fully()

+ +Reads the specified amount of data in full from a file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+ssize_t st_read_fully(st_netfd_t fd, void *buf, size_t nbyte,
+                      st_utime_t timeout);
+
+

+

Parameters
+st_read_fully() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t).

+buf

+A pointer to a buffer to hold the data read in. On output the buffer +contains the data.

+nbyte

+The amount of data to be read in full (in bytes). It must not exceed the +size of buf.

+timeout

+A value of type st_utime_t specifying the +inactivity timeout (in microseconds). +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success a non-negative integer indicating the number of bytes actually +read is returned (a value less than nbyte means the network +connection is closed or end of file is reached). Otherwise, a value of +-1 is returned and errno is set to indicate the error. +Possible errno values are the same as set by the read(2) +call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred. +
+

+

Description
+This function blocks the calling thread until the specified amount of data +is read in full, it encounters an end-of-stream indication, a timeout occurs, +or an error occurs. +

+


+

+ +

st_read_resid()

+ +Reads the specified amount of data in full from a file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_read_resid(st_netfd_t fd, void *buf, size_t *resid,
+		  st_utime_t timeout);
+
+

+

Parameters
+st_read_resid() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t).

+buf

+A pointer to a buffer to hold the data read in. On output the buffer +contains the data.

+resid

+A pointer to a number of bytes. +On entry, the amount of data to be read in full. +It must not exceed the size of buf. +On return, the amount of data remaining to be read. +(A non-zero returned value means some but not all of the data was read.)

+timeout

+A value of type st_utime_t specifying the +inactivity timeout (in microseconds). +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success, zero is returned. *resid may be zero, indicating +a complete read, or non-zero, indicating the network +connection is closed or end of file is reached. +

+Otherwise, a value of -1 is returned, *resid is non-zero, +and errno is set to indicate the error. +Possible errno values are the same as set by the read(2) +call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred. +
+

+

Description
+This function blocks the calling thread until the specified amount of data +is read in full, it encounters an end-of-stream indication, a timeout occurs, +or an error occurs. It differs from st_read_fully() only in that +it allows the caller to know how many bytes were transferred before an error +occurred. +

+


+

+ +

st_readv()

+ +Reads data from a specified file descriptor object into multiple buffers. +

+

Syntax
+ +
+#include <st.h>
+
+ssize_t st_readv(st_netfd_t fd, const struct iovec *iov, int iov_size,
+		 st_utime_t timeout);
+
+

+

Parameters
+st_readv() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t).

+iov

+An array of iovec structures that identify the buffers for holding +the data read in. +On return the buffers contain the data.

+iov_size

+The number of iovec structures in the iov array.

+timeout

+A value of type st_utime_t specifying the time +limit in microseconds for completion of the read operation. +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success a non-negative integer indicating the number of bytes actually +read is returned (a value of 0 means the network connection is +closed or end of file is reached). Otherwise, a value of -1 is +returned and errno is set to indicate the error. +Possible errno values are the same as set by the readv(2) +call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred and no data was read. +
+

+

Description
+This function blocks the calling thread until it encounters an end-of-stream +indication, some positive number of bytes (but no more than fit in the buffers) +are read in, a timeout occurs, or an error occurs. +

+


+

+ +

st_readv_resid()

+ +Reads the specified amount of data in full from a file descriptor object +into multiple buffers. +

+

Syntax
+ +
+#include <st.h>
+
+int st_readv_resid(st_netfd_t fd, struct iovec **iov, int *iov_size,
+		   st_utime_t timeout);
+
+

+

Parameters
+st_readv_resid() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t).

+iov

+A pointer to an array of iovec structures. +On entry, the iovecs identify the buffers for holding the data read in. +On return, the incomplete iovecs. +This function modifies both the pointer and the array to which it points.

+iov_size

+A pointer to a number of iovec structures. +On entry, the number of iovec structures pointed to by *iov. +On return, the number of incomplete or unused iovec structures. +(A non-zero returned value means some but not all of the data was read.)

+timeout

+A value of type st_utime_t specifying the +inactivity timeout (in microseconds). +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success, zero is returned. *iov_size may be zero, indicating +a complete read, or non-zero, indicating the network connection is +closed or end of file is reached. *iov points to the first +iovec after the end of the original array on a complete read, or to the +first incomplete iovec on an incomplete read. +

+Otherwise, a value of -1 is returned, *iov_size is non-zero, +and errno is set to indicate the error. *iov points to the +first unused iovec. +Possible errno values are the same as set by the readv(2) +call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred. +
+

All of the iovecs before *iov are modified such that +iov_base points to the end of the original buffer and +iov_len is zero. +

+

Description
+This function blocks the calling thread until the specified amount of data +is read in full, it encounters an end-of-stream indication, a timeout occurs, +or an error occurs. Like st_read_resid() it blocks the thread until +all of the requested data is read or an error occurs. Use +st_readv() to read up to the requested amount of data. +

+


+

+ +

st_write()

+ +Writes a buffer of data to a specified file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+ssize_t st_write(st_netfd_t fd, const void *buf, size_t nbyte,
+                 st_utime_t timeout);
+
+

+

Parameters
+st_write() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t).

+buf

+A pointer to the buffer holding the data to be written.

+nbyte

+The amount of data in bytes to be written from the buffer.

+timeout

+A value of type st_utime_t specifying the +inactivity timeout (in microseconds). +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success a non-negative integer equal to nbyte is returned. +Otherwise, a value of -1 is returned and errno is set +to indicate the error. Possible errno values are the same as set +by the write(2) call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred. +
+

+

Description
+This function blocks the calling thread until all the data is written, +a timeout occurs, or the write operation fails. The return value is equal to +either nbyte (on success) or -1 (on failure). Note that if +st_write() returns -1, some data (less than nbyte +bytes) may have been written before an error occurred. +

+


+

+ +

st_write_resid()

+ +Writes a buffer of data to a specified file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_write_resid(st_netfd_t fd, const void *buf, size_t *resid,
+                   st_utime_t timeout);
+
+

+

Parameters
+st_write_resid() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t).

+buf

+A pointer to the buffer holding the data to be written.

+resid

+A pointer to a number of bytes. +On entry, the amount of data to be written from the buffer. +On return, the amount of data remaining to be written. +(A non-zero returned value means some but not all of the data was written.)

+timeout

+A value of type st_utime_t specifying the +inactivity timeout (in microseconds). +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success, zero is returned and *resid is zero. +Otherwise, a value of -1 is returned, *resid is non-zero, +and errno is set +to indicate the error. Possible errno values are the same as set +by the write(2) call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred. +
+

+

Description
+This function blocks the calling thread until all the data is written, +a timeout occurs, or the write operation fails. It differs from +st_write() only in that it allows the caller to know how many bytes +were transferred before an error occurred. +

+


+

+ +

st_writev()

+ +Writes data to a specified file descriptor object from multiple buffers. +

+

Syntax
+ +
+#include <st.h>
+
+ssize_t st_writev(st_netfd_t fd, const struct iovec *iov, int iov_size,
+                  st_utime_t timeout);
+
+

+

Parameters
+st_writev() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t).

+iov

+An array of iovec structures that describe the buffers to write +from (see writev(2)).

+iov_size

+Number of iovec structures in the iov array.

+timeout

+A value of type st_utime_t specifying the +inactivity timeout (in microseconds). +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success a non-negative integer equal to the sum of all the buffer lengths +is returned. Otherwise, a value of -1 is returned and errno +is set to indicate the error. Possible errno values are the same as +set by the writev(2) call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred. +
+

+

Description
+This function blocks the calling thread until all the data is written, +a timeout occurs, or the write operation fails. The return value is equal to +either the sum of all the buffer lengths (on success) or -1 (on +failure). Note that if st_writev() returns -1, part of the +data may have been written before an error occurred. +

+


+

+ +

st_writev_resid()

+ +Writes multiple buffers of data to a specified file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_writev_resid(st_netfd_t fd, struct iovec **iov, int *iov_size,
+		    st_utime_t timeout);
+
+

+

Parameters
+st_writev_resid() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t).

+iov

+A pointer to an array of iovec structures. +On entry, the iovecs identify the buffers holding the data to write. +On return, the incomplete iovecs. +This function modifies both the pointer and the array to which it points.

+iov_size

+A pointer to a number of iovec structures. +On entry, the number of iovec structures pointed to by *iov. +On return, the number of incomplete or unused iovec structures. +(A non-zero returned value means some but not all of the data was written.)

+timeout

+A value of type st_utime_t specifying the +inactivity timeout (in microseconds). +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success, zero is returned, *iov_size is zero, and *iov +points to the first iovec after the end of the original array. +Otherwise, a value of -1 is returned, *iov_size is non-zero, +*iov points to the first incomplete iovec, and errno is set +to indicate the error. Possible errno values are the same as set +by the writev(2) call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred. +
+

+All of the iovecs before *iov are modified such that +iov_base points to the end of the original buffer and +iov_len is zero. +

+

Description
+This function blocks the calling thread until all the data is written, +a timeout occurs, or the write operation fails. It differs from +st_writev() only in that it allows the caller to know how many bytes +were transferred before an error occurred. +

+


+

+ +

st_recvfrom()

+ +Receives bytes from a file descriptor object and stores the sending peer's +address. +

+

Syntax
+ +
+#include <st.h>
+
+int st_recvfrom(st_netfd_t fd, void *buf, int len, struct sockaddr *from,
+                int *fromlen, st_utime_t timeout);
+
+

+

Parameters
+st_recvfrom() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t) representing a UDP socket.

+buf

+A pointer to a buffer to hold the data received.

+len

+The size of buf in bytes.

+from

+If this parameter is not a NULL pointer, the source address of the +message is filled in (see recvfrom(3)).

+fromlen

+This is a value-result parameter, initialized to the size of the buffer +associated with from, and modified on return to indicate the actual +size of the address stored there.

+timeout

+A value of type st_utime_t specifying the time +limit in microseconds for completion of the receive operation. +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success a non-negative integer indicating the length of the received +message in bytes is returned. Otherwise, a value of -1 is returned +and errno is set to indicate the error. Possible errno +values are the same as set by the recvfrom(3) call with two +exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred and no data was received. +
+

+

Description
+This function receives up to a specified number of bytes from the specified +file descriptor object representing a UDP socket.

+st_recvfrom() blocks the calling thread until one or more bytes are +transferred, a timeout has occurred, or there is an error. No more than +len bytes will be transferred. +

+


+

+ +

st_sendto()

+ +Sends bytes to a specified destination. +

+

Syntax
+ +
+#include <st.h>
+
+int st_sendto(st_netfd_t fd, const void *msg, int len, struct sockaddr *to,
+              int tolen, st_utime_t timeout);
+
+

+

Parameters
+st_sendto() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t) representing a UDP socket.

+msg

+A pointer to a buffer containing the message to be sent.

+len

+The length of the message to be sent (in bytes).

+to

+A pointer to the address of the destination (see sendto(3)).

+tolen

+This parameter specifies the size of the destination address.

+timeout

+A value of type st_utime_t specifying the time +limit in microseconds for completion of the send operation. +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success a non-negative integer indicating the number of bytes sent is +returned. Otherwise, a value of -1 is returned and errno is +set to indicate the error. Possible errno values are the same as +set by the sendto(3) call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred and no data was sent. +
+

+

Description
+This function sends a specified number of bytes from a file descriptor +object representing a UDP socket to the specified destination address. +If no buffer space is available at the underlying OS socket to hold the +message to be transmitted, then st_sendto() blocks the calling +thread until the space becomes available, a timeout occurs, or an error +occurs. +

+


+

+ +

st_recvmsg()

+ +Receives a message from a file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_recvmsg(st_netfd_t fd, struct msghdr *msg, int flags,
+               st_utime_t timeout);
+
+

+

Parameters
+st_recvmsg() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t) representing a UDP socket.

+msg

+A pointer to a msghdr structure to describe the data received.

+flags

+Control flags for recvmsg(3).

+timeout

+A value of type st_utime_t specifying the time +limit in microseconds for completion of the receive operation. +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success a non-negative integer indicating the number of bytes received +is returned. Otherwise, a value of -1 is returned +and errno is set to indicate the error. Possible errno +values are the same as set by the recvmsg(3) call with two +exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred and no data was received. +
+

+

Description
+This function receives bytes from the specified file descriptor object +representing a UDP socket. The operation is controlled by the in/out +msg parameter.

+st_recvmsg() blocks the calling thread until one or more bytes are +transferred, a timeout has occurred, or there is an error. +

+


+

+ +

st_sendmsg()

+ +Sends a message to a file descriptor object. +

+

Syntax
+ +
+#include <st.h>
+
+int st_sendmsg(st_netfd_t fd, const struct msghdr *msg, int flags,
+               st_utime_t timeout);
+
+

+

Parameters
+st_sendmsg() has the following parameters:

+fd

+A file descriptor object identifier (see +st_netfd_t) representing a UDP socket.

+msg

+A pointer to a msghdr structure describing the message to be sent.

+flags

+Control flags for sendmsg(3).

+timeout

+A value of type st_utime_t specifying the time +limit in microseconds for completion of the send operation. +Note that timeouts are measured since the +last context switch. +

+

Returns
+On success a non-negative integer indicating the number of bytes sent is +returned. Otherwise, a value of -1 is returned and errno is +set to indicate the error. Possible errno values are the same as +set by the sendmsg(3) call with two exceptions:

+ + + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
ETIMEThe timeout occurred and no data was sent. +
+

+

Description
+This function sends bytes to a file descriptor object representing a UDP +socket. The operation is controlled by the msg parameter. +If no buffer space is available at the underlying OS socket to hold the +message to be transmitted, then st_sendmsg() blocks the calling +thread until the space becomes available, a timeout occurs, or an error +occurs. +

+


+

+ +

st_open()

+ +Opens a file for reading, writing, or both. +

+

Syntax
+ +
+#include <st.h>
+
+st_netfd_t st_open(const char *path, int oflags, mode_t mode);
+
+

+

Parameters
+st_open() has the following parameters:

+path

+The pathname of the file to be opened.

+oflags

+File status flags. These are the same flags that are used by the +open(2) system call.

+mode

+Access permission bits of the file mode, if the file is created when +O_CREAT is set in oflags (see open(2)). +

+

Returns
+Upon successful completion, a new file descriptor object identifier is +returned. Otherwise, NULL is returned and errno is set +to indicate the error. +

+

Description
+This function creates a new file descriptor object of type +st_netfd_t for the file with the pathname +path. This object can be freed by +st_netfd_free() or +st_netfd_close().

+The primary purpose of this function is to open FIFOs (named pipes) or +other special files in order to create an end point of communication. +However, it can be used on regular files as well.

+Among other things, this function always sets a non-blocking flag on the +underlying OS file descriptor, so there is no need to include that flag in +oflags. +

+


+

+ +

st_poll()

+ +Detects when I/O is ready for a set of OS file descriptors. +

+

Syntax
+ +
+#include <st.h>
+
+int st_poll(struct pollfd *pds, int npds, st_utime_t timeout);
+
+

+

Parameters
+st_poll() has the following parameters:

+pds

+A pointer to an array of pollfd structures (see poll(2)). +

+npds

+The number of elements in the pds array.

+timeout

+A value of type st_utime_t specifying the +amount of time in microseconds the call will block waiting for I/O +to become ready. If this time expires without any I/O becoming ready, +st_poll() returns zero. +Note that timeouts are measured since the +last context switch. +

+

Returns
+Upon successful completion, a non-negative value is returned. A positive +value indicates the total number of OS file descriptors in pds +that have events. A value of 0 indicates that the call timed out. +Upon failure, a value of -1 is returned and errno is set +to indicate the error:

+ + +
EINTRThe current thread was interrupted by +st_thread_interrupt().
+

+If an alternative event notification mechanism has been set by +st_set_eventsys(), other values of +errno could be set upon failure as well. The values +depend on the specific mechanism in use. +

+

Description
+This function returns as soon as I/O is ready on one or more of the specified +OS file descriptors. A count of the number of ready descriptors is returned +unless a timeout occurs, in which case zero is returned.

+The pollfd structure is defined in the poll.h header file +and contains the following members:

+

+    int fd;             /* OS file descriptor */
+    short events;       /* requested events   */
+    short revents;      /* returned events    */
+
+The events field should be set to the I/O events (readable, +writable, exception, or some combination) that the caller is interested in. +On return, the revents field is set to indicate what kind of I/O +is ready on the respective descriptor.

+The events and revents fields are constructed by OR-ing +any combination of the following event flags (defined in poll.h): +

+ + + + + + +
POLLINfd is readable.
POLLOUTfd is is writable.
POLLPRIfd has an exception condition.
POLLNVALfd is bad.
+

+The POLLNVAL flag is only valid in the revents field; +it is not used in the events field.

+Despite having an interface like poll(2), this function uses +the same event notification mechanism as the rest of the library. For +instance if an alternative event nofication mechanism was set using st_set_eventsys(), this function uses that +mechanism to check for events.

+Note that unlike the poll(2) call, this function has the +timeout parameter expressed in microseconds. If the value of +timeout is ST_UTIME_NO_TIMEOUT +(-1), this function blocks until a requested I/O +event occurs or until the call is interrupted by +st_thread_interrupt(). +

+Note: if kqueue(2) is used as an alternative event +notification mechanism (see st_set_eventsys()), the POLLPRI +event flag is not supported and st_poll() will return an error +if it's set (errno will be set to EINVAL). +

+


+

+ + +

Program Structure

+ +

+Generally, the following steps should be followed when writing an application +using the State Threads library: +

+

    +
  1. Configure the library by calling these pre-init functions, if desired. + +
  2. +

    +

  3. Initialize the library by calling st_init().
  4. +

    +

  5. Configure the library by calling these post-init functions, if desired. + +
  6. +

    +

  7. Create resources that will be shared among different processes: + create and bind listening sockets (see socket(3), + bind(3), listen(3), + st_netfd_open_socket(), and possibly + st_netfd_serialize_accept()), + create shared memory segments, inter-process communication (IPC) + channels and synchronization primitives (if any).
  8. +

    +

  9. Create several processes via fork(2). The parent process should + either exit or become a "watchdog" (e.g., it starts a new process when + an existing one crashes, does a cleanup upon application termination, + etc.).
  10. +

    +

  11. In each child process create a pool of threads (see + st_thread_create()) to handle user + connections. Each thread in the pool may accept client connections + (st_accept()), connect to other servers + (st_connect()), perform various network I/O + (st_read(), st_write(), etc.).
  12. +
+

+Note that only State Threads library I/O functions should +be used for a network I/O: any other I/O calls may block the calling process +indefinitely. For example, standard I/O functions (fgets(3), +fread(3), fwrite(3), fprintf(3), etc.) call +read(2) and write(2) directly and therefore should not be +used on sockets or pipes. +

+Also note that for short timeouts to work the program +should do context switches (for example by calling +st_usleep()) on a regular basis. +

+


+

+ + +

List of Blocking Functions

+ +

+The thread context switch (process state change) can only happen +in a well-known set of blocking functions. +Only the following functions can block the calling thread: +

+

+
st_thread_join()
+
st_sleep()
+
st_usleep()
+
st_cond_wait()
+
st_cond_timedwait()
+
st_mutex_lock()
+
st_netfd_poll()
+
st_accept()
+
st_connect()
+
st_read()
+
st_read_fully()
+
st_read_resid()
+
st_readv()
+
st_readv_resid()
+
st_write()
+
st_write_resid()
+
st_writev()
+
st_writev_resid()
+
st_recvfrom()
+
st_sendto()
+
st_recvmsg()
+
st_sendmsg()
+
st_poll()
+
+

+


+

+ + + + diff --git a/trunk/3rdparty/st-srs/docs/st.html b/trunk/3rdparty/st-srs/docs/st.html new file mode 100644 index 0000000000..a6b932a819 --- /dev/null +++ b/trunk/3rdparty/st-srs/docs/st.html @@ -0,0 +1,504 @@ + + +State Threads for Internet Applications + + +

State Threads for Internet Applications

+

Introduction

+

+State Threads is an application library which provides a +foundation for writing fast and highly scalable Internet Applications +on UNIX-like platforms. It combines the simplicity of the multithreaded +programming paradigm, in which one thread supports each simultaneous +connection, with the performance and scalability of an event-driven +state machine architecture.

+ +

1. Definitions

+

+ +

1.1 Internet Applications

+ +

+An Internet Application (IA) is either a server or client network +application that accepts connections from clients and may or may not +connect to servers. In an IA the arrival or departure of network data +often controls processing (that is, IA is a data-driven application). +For each connection, an IA does some finite amount of work +involving data exchange with its peer, where its peer may be either +a client or a server. +The typical transaction steps of an IA are to accept a connection, +read a request, do some finite and predictable amount of work to +process the request, then write a response to the peer that sent the +request. One example of an IA is a Web server; +the most general example of an IA is a proxy server, because it both +accepts connections from clients and connects to other servers.

+

+We assume that the performance of an IA is constrained by available CPU +cycles rather than network bandwidth or disk I/O (that is, CPU +is a bottleneck resource). +

+ + +

1.2 Performance and Scalability

+ +

+The performance of an IA is usually evaluated as its +throughput measured in transactions per second or bytes per second (one +can be converted to the other, given the average transaction size). There are +several benchmarks that can be used to measure throughput of Web serving +applications for specific workloads (such as +SPECweb96, +WebStone, +WebBench). +Although there is no common definition for scalability, in general it +expresses the ability of an application to sustain its performance when some +external condition changes. For IAs this external condition is either the +number of clients (also known as "users," "simultaneous connections," or "load +generators") or the underlying hardware system size (number of CPUs, memory +size, and so on). Thus there are two types of scalability: load +scalability and system scalability, respectively. +

+The figure below shows how the throughput of an idealized IA changes with +the increasing number of clients (solid blue line). Initially the throughput +grows linearly (the slope represents the maximal throughput that one client +can provide). Within this initial range, the IA is underutilized and CPUs are +partially idle. Further increase in the number of clients leads to a system +saturation, and the throughput gradually stops growing as all CPUs become fully +utilized. After that point, the throughput stays flat because there are no +more CPU cycles available. +In the real world, however, each simultaneous connection +consumes some computational and memory resources, even when idle, and this +overhead grows with the number of clients. Therefore, the throughput of the +real world IA starts dropping after some point (dashed blue line in the figure +below). The rate at which the throughput drops depends, among other things, on +application design. +

+We say that an application has a good load scalability if it can +sustain its throughput over a wide range of loads. +Interestingly, the SPECweb99 +benchmark somewhat reflects the Web server's load scalability because it +measures the number of clients (load generators) given a mandatory minimal +throughput per client (that is, it measures the server's capacity). +This is unlike SPECweb96 and +other benchmarks that use the throughput as their main metric (see the figure +below). +

+

Figure: Throughput vs. Number of clients +
+

+System scalability is the ability of an application to sustain its +performance per hardware unit (such as a CPU) with the increasing number of +these units. In other words, good system scalability means that doubling the +number of processors will roughly double the application's throughput (dashed +green line). We assume here that the underlying operating system also scales +well. Good system scalability allows you to initially run an application on +the smallest system possible, while retaining the ability to move that +application to a larger system if necessary, without excessive effort or +expense. That is, an application need not be rewritten or even undergo a +major porting effort when changing system size. +

+Although scalability and performance are more important in the case of server +IAs, they should also be considered for some client applications (such as +benchmark load generators). +

+ + +

1.3 Concurrency

+ +

+Concurrency reflects the parallelism in a system. The two unrelated types +are virtual concurrency and real concurrency. +

    +
  • Virtual (or apparent) concurrency is the number of simultaneous +connections that a system supports. +

    +
  • Real concurrency is the number of hardware devices, including +CPUs, network cards, and disks, that actually allow a system to perform +tasks in parallel. +
+

+An IA must provide virtual concurrency in order to serve many users +simultaneously. +To achieve maximum performance and scalability in doing so, the number of +programming entities than an IA creates to be scheduled by the OS kernel +should be +kept close to (within an order of magnitude of) the real concurrency found on +the system. These programming entities scheduled by the kernel are known as +kernel execution vehicles. Examples of kernel execution vehicles +include Solaris lightweight processes and IRIX kernel threads. +In other words, the number of kernel execution vehicles should be dictated by +the system size and not by the number of simultaneous connections. +

+ +

2. Existing Architectures

+

+There are a few different architectures that are commonly used by IAs. +These include the Multi-Process, +Multi-Threaded, and Event-Driven State Machine +architectures. +

+ +

2.1 Multi-Process Architecture

+ +

+In the Multi-Process (MP) architecture, an individual process is +dedicated to each simultaneous connection. +A process performs all of a transaction's initialization steps +and services a connection completely before moving on to service +a new connection. +

+User sessions in IAs are relatively independent; therefore, no +synchronization between processes handling different connections is +necessary. Because each process has its own private address space, +this architecture is very robust. If a process serving one of the connections +crashes, the other sessions will not be affected. However, to serve many +concurrent connections, an equal number of processes must be employed. +Because processes are kernel entities (and are in fact the heaviest ones), +the number of kernel entities will be at least as large as the number of +concurrent sessions. On most systems, good performance will not be achieved +when more than a few hundred processes are created because of the high +context-switching overhead. In other words, MP applications have poor load +scalability. +

+On the other hand, MP applications have very good system scalability, because +no resources are shared among different processes and there is no +synchronization overhead. +

+The Apache Web Server 1.x ([Reference 1]) uses the MP +architecture on UNIX systems. +

+ +

2.2 Multi-Threaded Architecture

+ +

+In the Multi-Threaded (MT) architecture, multiple independent threads +of control are employed within a single shared address space. Like a +process in the MP architecture, each thread performs all of a +transaction's initialization steps and services a connection completely +before moving on to service a new connection. +

+Many modern UNIX operating systems implement a many-to-few model when +mapping user-level threads to kernel entities. In this model, an +arbitrarily large number of user-level threads is multiplexed onto a +lesser number of kernel execution vehicles. Kernel execution +vehicles are also known as virtual processors. Whenever a user-level +thread makes a blocking system call, the kernel execution vehicle it is using +will become blocked in the kernel. If there are no other non-blocked kernel +execution vehicles and there are other runnable user-level threads, a new +kernel execution vehicle will be created automatically. This prevents the +application from blocking when it can continue to make useful forward +progress. +

+Because IAs are by nature network I/O driven, all concurrent sessions block on +network I/O at various points. As a result, the number of virtual processors +created in the kernel grows close to the number of user-level threads +(or simultaneous connections). When this occurs, the many-to-few model +effectively degenerates to a one-to-one model. Again, like in +the MP architecture, the number of kernel execution vehicles is dictated by +the number of simultaneous connections rather than by number of CPUs. This +reduces an application's load scalability. However, because kernel threads +(lightweight processes) use fewer resources and are more light-weight than +traditional UNIX processes, an MT application should scale better with load +than an MP application. +

+Unexpectedly, the small number of virtual processors sharing the same address +space in the MT architecture destroys an application's system scalability +because of contention among the threads on various locks. Even if an +application itself is carefully +optimized to avoid lock contention around its own global data (a non-trivial +task), there are still standard library functions and system calls +that use common resources hidden from the application. For example, +on many platforms thread safety of memory allocation routines +(malloc(3), free(3), and so on) is achieved by using a single +global lock. Another example is a per-process file descriptor table. +This common resource table is shared by all kernel execution vehicles within +the same process and must be protected when one modifies it via +certain system calls (such as open(2), close(2), and so on). +In addition to that, maintaining the caches coherent +among CPUs on multiprocessor systems hurts performance when different threads +running on different CPUs modify data items on the same cache line. +

+In order to improve load scalability, some applications employ a different +type of MT architecture: they create one or more thread(s) per task +rather than one thread per connection. For example, one small group +of threads may be responsible for accepting client connections, another +for request processing, and yet another for serving responses. The main +advantage of this architecture is that it eliminates the tight coupling +between the number of threads and number of simultaneous connections. However, +in this architecture, different task-specific thread groups must share common +work queues that must be protected by mutual exclusion locks (a typical +producer-consumer problem). This adds synchronization overhead that causes an +application to perform badly on multiprocessor systems. In other words, in +this architecture, the application's system scalability is sacrificed for the +sake of load scalability. +

+Of course, the usual nightmares of threaded programming, including data +corruption, deadlocks, and race conditions, also make MT architecture (in any +form) non-simplistic to use. +

+ + +

2.3 Event-Driven State Machine Architecture

+ +

+In the Event-Driven State Machine (EDSM) architecture, a single process +is employed to concurrently process multiple connections. The basics of this +architecture are described in Comer and Stevens +[Reference 2]. +The EDSM architecture performs one basic data-driven step associated with +a particular connection at a time, thus multiplexing many concurrent +connections. The process operates as a state machine that receives an event +and then reacts to it. +

+In the idle state the EDSM calls select(2) or poll(2) to +wait for network I/O events. When a particular file descriptor is ready for +I/O, the EDSM completes the corresponding basic step (usually by invoking a +handler function) and starts the next one. This architecture uses +non-blocking system calls to perform asynchronous network I/O operations. +For more details on non-blocking I/O see Stevens +[Reference 3]. +

+To take advantage of hardware parallelism (real concurrency), multiple +identical processes may be created. This is called Symmetric Multi-Process +EDSM and is used, for example, in the Zeus Web Server +([Reference 4]). To more efficiently multiplex disk I/O, +special "helper" processes may be created. This is called Asymmetric +Multi-Process EDSM and was proposed for Web servers by Druschel +and others [Reference 5]. +

+EDSM is probably the most scalable architecture for IAs. +Because the number of simultaneous connections (virtual concurrency) is +completely decoupled from the number of kernel execution vehicles (processes), +this architecture has very good load scalability. It requires only minimal +user-level resources to create and maintain additional connection. +

+Like MP applications, Multi-Process EDSM has very good system scalability +because no resources are shared among different processes and there is no +synchronization overhead. +

+Unfortunately, the EDSM architecture is monolithic rather than based on the +concept of threads, so new applications generally need to be implemented from +the ground up. In effect, the EDSM architecture simulates threads and their +stacks the hard way. +

+ + +

3. State Threads Library

+ +

+The State Threads library combines the advantages of all of the above +architectures. The interface preserves the programming simplicity of thread +abstraction, allowing each simultaneous connection to be treated as a separate +thread of execution within a single process. The underlying implementation is +close to the EDSM architecture as the state of each particular concurrent +session is saved in a separate memory segment. +

+ +

3.1 State Changes and Scheduling

+

+The state of each concurrent session includes its stack environment +(stack pointer, program counter, CPU registers) and its stack. Conceptually, +a thread context switch can be viewed as a process changing its state. There +are no kernel entities involved other than processes. +Unlike other general-purpose threading libraries, the State Threads library +is fully deterministic. The thread context switch (process state change) can +only happen in a well-known set of functions (at I/O points or at explicit +synchronization points). As a result, process-specific global data does not +have to be protected by mutual exclusion locks in most cases. The entire +application is free to use all the static variables and non-reentrant library +functions it wants, greatly simplifying programming and debugging while +increasing performance. This is somewhat similar to a co-routine model +(co-operatively multitasked threads), except that no explicit yield is needed +-- +sooner or later, a thread performs a blocking I/O operation and thus surrenders +control. All threads of execution (simultaneous connections) have the +same priority, so scheduling is non-preemptive, like in the EDSM architecture. +Because IAs are data-driven (processing is limited by the size of network +buffers and data arrival rates), scheduling is non-time-slicing. +

+Only two types of external events are handled by the library's +scheduler, because only these events can be detected by +select(2) or poll(2): I/O events (a file descriptor is ready +for I/O) and time events +(some timeout has expired). However, other types of events (such as +a signal sent to a process) can also be handled by converting them to I/O +events. For example, a signal handling function can perform a write to a pipe +(write(2) is reentrant/asynchronous-safe), thus converting a signal +event to an I/O event. +

+To take advantage of hardware parallelism, as in the EDSM architecture, +multiple processes can be created in either a symmetric or asymmetric manner. +Process management is not in the library's scope but instead is left up to the +application. +

+There are several general-purpose threading libraries that implement a +many-to-one model (many user-level threads to one kernel execution +vehicle), using the same basic techniques as the State Threads library +(non-blocking I/O, event-driven scheduler, and so on). For an example, see GNU +Portable Threads ([Reference 6]). Because they are +general-purpose, these libraries have different objectives than the State +Threads library. The State Threads library is not a general-purpose +threading library, +but rather an application library that targets only certain types of +applications (IAs) in order to achieve the highest possible performance and +scalability for those applications. +

+ +

3.2 Scalability

+

+State threads are very lightweight user-level entities, and therefore creating +and maintaining user connections requires minimal resources. An application +using the State Threads library scales very well with the increasing number +of connections. +

+On multiprocessor systems an application should create multiple processes +to take advantage of hardware parallelism. Using multiple separate processes +is the only way to achieve the highest possible system scalability. +This is because duplicating per-process resources is the only way to avoid +significant synchronization overhead on multiprocessor systems. Creating +separate UNIX processes naturally offers resource duplication. Again, +as in the EDSM architecture, there is no connection between the number of +simultaneous connections (which may be very large and changes within a wide +range) and the number of kernel entities (which is usually small and constant). +In other words, the State Threads library makes it possible to multiplex a +large number of simultaneous connections onto a much smaller number of +separate processes, thus allowing an application to scale well with both +the load and system size. +

+ +

3.3 Performance

+

+Performance is one of the library's main objectives. The State Threads +library is implemented to minimize the number of system calls and +to make thread creation and context switching as fast as possible. +For example, per-thread signal mask does not exist (unlike +POSIX threads), so there is no need to save and restore a process's +signal mask on every thread context switch. This eliminates two system +calls per context switch. Signal events can be handled much more +efficiently by converting them to I/O events (see above). +

+ +

3.4 Portability

+

+The library uses the same general, underlying concepts as the EDSM +architecture, including non-blocking I/O, file descriptors, and +I/O multiplexing. These concepts are available in some form on most +UNIX platforms, making the library very portable across many +flavors of UNIX. There are only a few platform-dependent sections in the +source. +

+ +

3.5 State Threads and NSPR

+

+The State Threads library is a derivative of the Netscape Portable +Runtime library (NSPR) [Reference 7]. The primary goal of +NSPR is to provide a platform-independent layer for system facilities, +where system facilities include threads, thread synchronization, and I/O. +Performance and scalability are not the main concern of NSPR. The +State Threads library addresses performance and scalability while +remaining much smaller than NSPR. It is contained in 8 source files +as opposed to more than 400, but provides all the functionality that +is needed to write efficient IAs on UNIX-like platforms. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NSPRState Threads
Lines of code~150,000~3000
Dynamic library size  
(debug version)
IRIX~700 KB~60 KB
Linux~900 KB~70 KB
+

+ +

Conclusion

+

+State Threads is an application library which provides a foundation for +writing Internet Applications. To summarize, it has the +following advantages: +

+

    +
  • It allows the design of fast and highly scalable applications. An +application will scale well with both load and number of CPUs. +

    +

  • It greatly simplifies application programming and debugging because, as a +rule, no mutual exclusion locking is necessary and the entire application is +free to use static variables and non-reentrant library functions. +
+

+The library's main limitation: +

+

    +
  • All I/O operations on sockets must use the State Thread library's I/O +functions because only those functions perform thread scheduling and prevent +the application's processes from blocking. +
+

+ +

References

+
    + +
  1. Apache Software Foundation, +http://www.apache.org. + +
  2. Douglas E. Comer, David L. Stevens, Internetworking With TCP/IP, +Vol. III: Client-Server Programming And Applications, Second Edition, +Ch. 8, 12. + +
  3. W. Richard Stevens, UNIX Network Programming, Second Edition, +Vol. 1, Ch. 15. + +
  4. Zeus Technology Limited, +http://www.zeus.co.uk. + +
  5. Peter Druschel, Vivek S. Pai, Willy Zwaenepoel, + +Flash: An Efficient and Portable Web Server. In Proceedings of the +USENIX 1999 Annual Technical Conference, Monterey, CA, June 1999. + +
  6. GNU Portable Threads, +http://www.gnu.org/software/pth/. + +
  7. Netscape Portable Runtime, +http://www.mozilla.org/docs/refList/refNSPR/. +
+ +

Other resources covering various architectural issues in IAs

+
    +
  1. Dan Kegel, The C10K problem, +http://www.kegel.com/c10k.html. +
  2. +
  3. James C. Hu, Douglas C. Schmidt, Irfan Pyarali, JAWS: Understanding +High Performance Web Systems, +http://www.cs.wustl.edu/~jxh/research/research.html.
  4. +
+

+


+

+ +

Portions created by SGI are Copyright © 2000 +Silicon Graphics, Inc. All rights reserved.
+

+ + + + diff --git a/trunk/3rdparty/st-srs/docs/timeout_heap.txt b/trunk/3rdparty/st-srs/docs/timeout_heap.txt new file mode 100644 index 0000000000..1582dc1293 --- /dev/null +++ b/trunk/3rdparty/st-srs/docs/timeout_heap.txt @@ -0,0 +1,60 @@ +How the timeout heap works + +As of version 1.5, the State Threads Library represents the queue of +sleeping threads using a heap data structure rather than a sorted +linked list. This improves performance when there is a large number +of sleeping threads, since insertion into a heap takes O(log N) time +while insertion into a sorted list takes O(N) time. For example, in +one test 1000 threads were created, each thread called st_usleep() +with a random time interval, and then all the threads where +immediately interrupted and joined before the sleeps had a chance to +finish. The whole process was repeated 1000 times, for a total of a +million sleep queue insertions and removals. With the old list-based +sleep queue, this test took 100 seconds; now it takes only 12 seconds. + +Heap data structures are typically based on dynamically resized +arrays. However, since the existing ST code base was very nicely +structured around linking the thread objects into pointer-based lists +without the need for any auxiliary data structures, implementing the +heap using a similar nodes-and-pointers based approach seemed more +appropriate for ST than introducing a separate array. + +Thus, the new ST timeout heap works by organizing the existing +_st_thread_t objects in a balanced binary tree, just as they were +previously organized into a doubly-linked, sorted list. The global +_ST_SLEEPQ variable, formerly a linked list head, is now simply a +pointer to the root of this tree, and the root node of the tree is the +thread with the earliest timeout. Each thread object has two child +pointers, "left" and "right", pointing to threads with later timeouts. + +Each node in the tree is numbered with an integer index, corresponding +to the array index in an array-based heap, and the tree is kept fully +balanced and left-adjusted at all times. In other words, the tree +consists of any number of fully populated top levels, followed by a +single bottom level which may be partially populated, such that any +existing nodes form a contiguous block to the left and the spaces for +missing nodes form a contiguous block to the right. For example, if +there are nine threads waiting for a timeout, they are numbered and +arranged in a tree exactly as follows: + + 1 + / \ + 2 3 + / \ / \ + 4 5 6 7 + / \ + 8 9 + +Each node has either no children, only a left child, or both a left +and a right child. Children always time out later than their parents +(this is called the "heap invariant"), but when a node has two +children, their mutual order is unspecified - the left child may time +out before or after the right child. If a node is numbered N, its +left child is numbered 2N, and its right child is numbered 2N+1. + +There is no pointer from a child to its parent; all pointers point +downward. Additions and deletions both work by starting at the root +and traversing the tree towards the leaves, going left or right +according to the binary digits forming the index of the destination +node. As nodes are added or deleted, existing nodes are rearranged to +maintain the heap invariant. diff --git a/trunk/3rdparty/st-srs/event.c b/trunk/3rdparty/st-srs/event.c new file mode 100644 index 0000000000..142882a51e --- /dev/null +++ b/trunk/3rdparty/st-srs/event.c @@ -0,0 +1,1413 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * Yahoo! Inc. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" + +#ifdef MD_HAVE_KQUEUE +#include +#endif +#ifdef MD_HAVE_EPOLL +#include +#endif + +#if defined(USE_POLL) && !defined(MD_HAVE_POLL) + /* Force poll usage if explicitly asked for it */ + #define MD_HAVE_POLL +#endif + + +static struct _st_seldata { + fd_set fd_read_set, fd_write_set, fd_exception_set; + int fd_ref_cnts[FD_SETSIZE][3]; + int maxfd; +} *_st_select_data; + +#define _ST_SELECT_MAX_OSFD (_st_select_data->maxfd) +#define _ST_SELECT_READ_SET (_st_select_data->fd_read_set) +#define _ST_SELECT_WRITE_SET (_st_select_data->fd_write_set) +#define _ST_SELECT_EXCEP_SET (_st_select_data->fd_exception_set) +#define _ST_SELECT_READ_CNT(fd) (_st_select_data->fd_ref_cnts[fd][0]) +#define _ST_SELECT_WRITE_CNT(fd) (_st_select_data->fd_ref_cnts[fd][1]) +#define _ST_SELECT_EXCEP_CNT(fd) (_st_select_data->fd_ref_cnts[fd][2]) + + +#ifdef MD_HAVE_POLL +static struct _st_polldata { + struct pollfd *pollfds; + int pollfds_size; + int fdcnt; +} *_st_poll_data; + +#define _ST_POLL_OSFD_CNT (_st_poll_data->fdcnt) +#define _ST_POLLFDS (_st_poll_data->pollfds) +#define _ST_POLLFDS_SIZE (_st_poll_data->pollfds_size) +#endif /* MD_HAVE_POLL */ + + +#ifdef MD_HAVE_KQUEUE +typedef struct _kq_fd_data { + int rd_ref_cnt; + int wr_ref_cnt; + int revents; +} _kq_fd_data_t; + +static struct _st_kqdata { + _kq_fd_data_t *fd_data; + struct kevent *evtlist; + struct kevent *addlist; + struct kevent *dellist; + int fd_data_size; + int evtlist_size; + int addlist_size; + int addlist_cnt; + int dellist_size; + int dellist_cnt; + int kq; + pid_t pid; +} *_st_kq_data; + +#ifndef ST_KQ_MIN_EVTLIST_SIZE +#define ST_KQ_MIN_EVTLIST_SIZE 64 +#endif + +#define _ST_KQ_READ_CNT(fd) (_st_kq_data->fd_data[fd].rd_ref_cnt) +#define _ST_KQ_WRITE_CNT(fd) (_st_kq_data->fd_data[fd].wr_ref_cnt) +#define _ST_KQ_REVENTS(fd) (_st_kq_data->fd_data[fd].revents) +#endif /* MD_HAVE_KQUEUE */ + + +#ifdef MD_HAVE_EPOLL +typedef struct _epoll_fd_data { + int rd_ref_cnt; + int wr_ref_cnt; + int ex_ref_cnt; + int revents; +} _epoll_fd_data_t; + +static struct _st_epolldata { + _epoll_fd_data_t *fd_data; + struct epoll_event *evtlist; + int fd_data_size; + int evtlist_size; + int evtlist_cnt; + int fd_hint; + int epfd; + pid_t pid; +} *_st_epoll_data; + +#ifndef ST_EPOLL_EVTLIST_SIZE + /* Not a limit, just a hint */ + #define ST_EPOLL_EVTLIST_SIZE 4096 +#endif + +#define _ST_EPOLL_READ_CNT(fd) (_st_epoll_data->fd_data[fd].rd_ref_cnt) +#define _ST_EPOLL_WRITE_CNT(fd) (_st_epoll_data->fd_data[fd].wr_ref_cnt) +#define _ST_EPOLL_EXCEP_CNT(fd) (_st_epoll_data->fd_data[fd].ex_ref_cnt) +#define _ST_EPOLL_REVENTS(fd) (_st_epoll_data->fd_data[fd].revents) + +#define _ST_EPOLL_READ_BIT(fd) (_ST_EPOLL_READ_CNT(fd) ? EPOLLIN : 0) +#define _ST_EPOLL_WRITE_BIT(fd) (_ST_EPOLL_WRITE_CNT(fd) ? EPOLLOUT : 0) +#define _ST_EPOLL_EXCEP_BIT(fd) (_ST_EPOLL_EXCEP_CNT(fd) ? EPOLLPRI : 0) +#define _ST_EPOLL_EVENTS(fd) \ + (_ST_EPOLL_READ_BIT(fd)|_ST_EPOLL_WRITE_BIT(fd)|_ST_EPOLL_EXCEP_BIT(fd)) + +#endif /* MD_HAVE_EPOLL */ + +_st_eventsys_t *_st_eventsys = NULL; + + +/***************************************** + * select event system + */ + +ST_HIDDEN int _st_select_init(void) +{ + _st_select_data = (struct _st_seldata *) malloc(sizeof(*_st_select_data)); + if (!_st_select_data) + return -1; + + memset(_st_select_data, 0, sizeof(*_st_select_data)); + _st_select_data->maxfd = -1; + + return 0; +} + +ST_HIDDEN int _st_select_pollset_add(struct pollfd *pds, int npds) +{ + struct pollfd *pd; + struct pollfd *epd = pds + npds; + + /* Do checks up front */ + for (pd = pds; pd < epd; pd++) { + if (pd->fd < 0 || pd->fd >= FD_SETSIZE || !pd->events || + (pd->events & ~(POLLIN | POLLOUT | POLLPRI))) { + errno = EINVAL; + return -1; + } + } + + for (pd = pds; pd < epd; pd++) { + if (pd->events & POLLIN) { + FD_SET(pd->fd, &_ST_SELECT_READ_SET); + _ST_SELECT_READ_CNT(pd->fd)++; + } + if (pd->events & POLLOUT) { + FD_SET(pd->fd, &_ST_SELECT_WRITE_SET); + _ST_SELECT_WRITE_CNT(pd->fd)++; + } + if (pd->events & POLLPRI) { + FD_SET(pd->fd, &_ST_SELECT_EXCEP_SET); + _ST_SELECT_EXCEP_CNT(pd->fd)++; + } + if (_ST_SELECT_MAX_OSFD < pd->fd) + _ST_SELECT_MAX_OSFD = pd->fd; + } + + return 0; +} + +ST_HIDDEN void _st_select_pollset_del(struct pollfd *pds, int npds) +{ + struct pollfd *pd; + struct pollfd *epd = pds + npds; + + for (pd = pds; pd < epd; pd++) { + if (pd->events & POLLIN) { + if (--_ST_SELECT_READ_CNT(pd->fd) == 0) + FD_CLR(pd->fd, &_ST_SELECT_READ_SET); + } + if (pd->events & POLLOUT) { + if (--_ST_SELECT_WRITE_CNT(pd->fd) == 0) + FD_CLR(pd->fd, &_ST_SELECT_WRITE_SET); + } + if (pd->events & POLLPRI) { + if (--_ST_SELECT_EXCEP_CNT(pd->fd) == 0) + FD_CLR(pd->fd, &_ST_SELECT_EXCEP_SET); + } + } +} + +ST_HIDDEN void _st_select_find_bad_fd(void) +{ + _st_clist_t *q; + _st_pollq_t *pq; + int notify; + struct pollfd *pds, *epds; + int pq_max_osfd, osfd; + short events; + + _ST_SELECT_MAX_OSFD = -1; + + for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { + pq = _ST_POLLQUEUE_PTR(q); + notify = 0; + epds = pq->pds + pq->npds; + pq_max_osfd = -1; + + for (pds = pq->pds; pds < epds; pds++) { + osfd = pds->fd; + pds->revents = 0; + if (pds->events == 0) + continue; + if (fcntl(osfd, F_GETFL, 0) < 0) { + pds->revents = POLLNVAL; + notify = 1; + } + if (osfd > pq_max_osfd) { + pq_max_osfd = osfd; + } + } + + if (notify) { + ST_REMOVE_LINK(&pq->links); + pq->on_ioq = 0; + /* + * Decrement the count of descriptors for each descriptor/event + * because this I/O request is being removed from the ioq + */ + for (pds = pq->pds; pds < epds; pds++) { + osfd = pds->fd; + events = pds->events; + if (events & POLLIN) { + if (--_ST_SELECT_READ_CNT(osfd) == 0) { + FD_CLR(osfd, &_ST_SELECT_READ_SET); + } + } + if (events & POLLOUT) { + if (--_ST_SELECT_WRITE_CNT(osfd) == 0) { + FD_CLR(osfd, &_ST_SELECT_WRITE_SET); + } + } + if (events & POLLPRI) { + if (--_ST_SELECT_EXCEP_CNT(osfd) == 0) { + FD_CLR(osfd, &_ST_SELECT_EXCEP_SET); + } + } + } + + if (pq->thread->flags & _ST_FL_ON_SLEEPQ) + _ST_DEL_SLEEPQ(pq->thread); + pq->thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(pq->thread); + } else { + if (_ST_SELECT_MAX_OSFD < pq_max_osfd) + _ST_SELECT_MAX_OSFD = pq_max_osfd; + } + } +} + +ST_HIDDEN void _st_select_dispatch(void) +{ + struct timeval timeout, *tvp; + fd_set r, w, e; + fd_set *rp, *wp, *ep; + int nfd, pq_max_osfd, osfd; + _st_clist_t *q; + st_utime_t min_timeout; + _st_pollq_t *pq; + int notify; + struct pollfd *pds, *epds; + short events, revents; + + /* + * Assignment of fd_sets + */ + r = _ST_SELECT_READ_SET; + w = _ST_SELECT_WRITE_SET; + e = _ST_SELECT_EXCEP_SET; + + rp = &r; + wp = &w; + ep = &e; + + if (_ST_SLEEPQ == NULL) { + tvp = NULL; + } else { + min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : + (_ST_SLEEPQ->due - _ST_LAST_CLOCK); + timeout.tv_sec = (int) (min_timeout / 1000000); + timeout.tv_usec = (int) (min_timeout % 1000000); + tvp = &timeout; + } + + /* Check for I/O operations */ + nfd = select(_ST_SELECT_MAX_OSFD + 1, rp, wp, ep, tvp); + + /* Notify threads that are associated with the selected descriptors */ + if (nfd > 0) { + _ST_SELECT_MAX_OSFD = -1; + for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { + pq = _ST_POLLQUEUE_PTR(q); + notify = 0; + epds = pq->pds + pq->npds; + pq_max_osfd = -1; + + for (pds = pq->pds; pds < epds; pds++) { + osfd = pds->fd; + events = pds->events; + revents = 0; + if ((events & POLLIN) && FD_ISSET(osfd, rp)) { + revents |= POLLIN; + } + if ((events & POLLOUT) && FD_ISSET(osfd, wp)) { + revents |= POLLOUT; + } + if ((events & POLLPRI) && FD_ISSET(osfd, ep)) { + revents |= POLLPRI; + } + pds->revents = revents; + if (revents) { + notify = 1; + } + if (osfd > pq_max_osfd) { + pq_max_osfd = osfd; + } + } + if (notify) { + ST_REMOVE_LINK(&pq->links); + pq->on_ioq = 0; + /* + * Decrement the count of descriptors for each descriptor/event + * because this I/O request is being removed from the ioq + */ + for (pds = pq->pds; pds < epds; pds++) { + osfd = pds->fd; + events = pds->events; + if (events & POLLIN) { + if (--_ST_SELECT_READ_CNT(osfd) == 0) { + FD_CLR(osfd, &_ST_SELECT_READ_SET); + } + } + if (events & POLLOUT) { + if (--_ST_SELECT_WRITE_CNT(osfd) == 0) { + FD_CLR(osfd, &_ST_SELECT_WRITE_SET); + } + } + if (events & POLLPRI) { + if (--_ST_SELECT_EXCEP_CNT(osfd) == 0) { + FD_CLR(osfd, &_ST_SELECT_EXCEP_SET); + } + } + } + + if (pq->thread->flags & _ST_FL_ON_SLEEPQ) + _ST_DEL_SLEEPQ(pq->thread); + pq->thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(pq->thread); + } else { + if (_ST_SELECT_MAX_OSFD < pq_max_osfd) + _ST_SELECT_MAX_OSFD = pq_max_osfd; + } + } + } else if (nfd < 0) { + /* + * It can happen when a thread closes file descriptor + * that is being used by some other thread -- BAD! + */ + if (errno == EBADF) + _st_select_find_bad_fd(); + } +} + +ST_HIDDEN int _st_select_fd_new(int osfd) +{ + if (osfd >= FD_SETSIZE) { + errno = EMFILE; + return -1; + } + + return 0; +} + +ST_HIDDEN int _st_select_fd_close(int osfd) +{ + if (_ST_SELECT_READ_CNT(osfd) || _ST_SELECT_WRITE_CNT(osfd) || + _ST_SELECT_EXCEP_CNT(osfd)) { + errno = EBUSY; + return -1; + } + + return 0; +} + +ST_HIDDEN int _st_select_fd_getlimit(void) +{ + return FD_SETSIZE; +} + +static _st_eventsys_t _st_select_eventsys = { + "select", + ST_EVENTSYS_SELECT, + _st_select_init, + _st_select_dispatch, + _st_select_pollset_add, + _st_select_pollset_del, + _st_select_fd_new, + _st_select_fd_close, + _st_select_fd_getlimit +}; + + +#ifdef MD_HAVE_POLL +/***************************************** + * poll event system + */ + +ST_HIDDEN int _st_poll_init(void) +{ + _st_poll_data = (struct _st_polldata *) malloc(sizeof(*_st_poll_data)); + if (!_st_poll_data) + return -1; + + _ST_POLLFDS = (struct pollfd *) malloc(ST_MIN_POLLFDS_SIZE * + sizeof(struct pollfd)); + if (!_ST_POLLFDS) { + free(_st_poll_data); + _st_poll_data = NULL; + return -1; + } + _ST_POLLFDS_SIZE = ST_MIN_POLLFDS_SIZE; + _ST_POLL_OSFD_CNT = 0; + + return 0; +} + +ST_HIDDEN int _st_poll_pollset_add(struct pollfd *pds, int npds) +{ + struct pollfd *pd; + struct pollfd *epd = pds + npds; + + for (pd = pds; pd < epd; pd++) { + if (pd->fd < 0 || !pd->events) { + errno = EINVAL; + return -1; + } + } + + _ST_POLL_OSFD_CNT += npds; + + return 0; +} + +/* ARGSUSED */ +ST_HIDDEN void _st_poll_pollset_del(struct pollfd *pds, int npds) +{ + _ST_POLL_OSFD_CNT -= npds; + ST_ASSERT(_ST_POLL_OSFD_CNT >= 0); +} + +ST_HIDDEN void _st_poll_dispatch(void) +{ + int timeout, nfd; + _st_clist_t *q; + st_utime_t min_timeout; + _st_pollq_t *pq; + struct pollfd *pds, *epds, *pollfds; + + /* + * Build up the array of struct pollfd to wait on. + * If existing array is not big enough, release it and allocate a new one. + */ + ST_ASSERT(_ST_POLL_OSFD_CNT >= 0); + if (_ST_POLL_OSFD_CNT > _ST_POLLFDS_SIZE) { + free(_ST_POLLFDS); + _ST_POLLFDS = (struct pollfd *) malloc((_ST_POLL_OSFD_CNT + 10) * + sizeof(struct pollfd)); + ST_ASSERT(_ST_POLLFDS != NULL); + _ST_POLLFDS_SIZE = _ST_POLL_OSFD_CNT + 10; + } + pollfds = _ST_POLLFDS; + + /* Gather all descriptors into one array */ + for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { + pq = _ST_POLLQUEUE_PTR(q); + memcpy(pollfds, pq->pds, sizeof(struct pollfd) * pq->npds); + pollfds += pq->npds; + } + ST_ASSERT(pollfds <= _ST_POLLFDS + _ST_POLLFDS_SIZE); + + if (_ST_SLEEPQ == NULL) { + timeout = -1; + } else { + min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : + (_ST_SLEEPQ->due - _ST_LAST_CLOCK); + timeout = (int) (min_timeout / 1000); + } + + /* Check for I/O operations */ + nfd = poll(_ST_POLLFDS, _ST_POLL_OSFD_CNT, timeout); + + /* Notify threads that are associated with the selected descriptors */ + if (nfd > 0) { + pollfds = _ST_POLLFDS; + for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { + pq = _ST_POLLQUEUE_PTR(q); + epds = pollfds + pq->npds; + for (pds = pollfds; pds < epds; pds++) { + if (pds->revents) + break; + } + if (pds < epds) { + memcpy(pq->pds, pollfds, sizeof(struct pollfd) * pq->npds); + ST_REMOVE_LINK(&pq->links); + pq->on_ioq = 0; + + if (pq->thread->flags & _ST_FL_ON_SLEEPQ) + _ST_DEL_SLEEPQ(pq->thread); + pq->thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(pq->thread); + + _ST_POLL_OSFD_CNT -= pq->npds; + ST_ASSERT(_ST_POLL_OSFD_CNT >= 0); + } + pollfds = epds; + } + } +} + +/* ARGSUSED */ +ST_HIDDEN int _st_poll_fd_new(int osfd) +{ + return 0; +} + +/* ARGSUSED */ +ST_HIDDEN int _st_poll_fd_close(int osfd) +{ + /* + * We don't maintain I/O counts for poll event system + * so nothing to check here. + */ + return 0; +} + +ST_HIDDEN int _st_poll_fd_getlimit(void) +{ + /* zero means no specific limit */ + return 0; +} + +static _st_eventsys_t _st_poll_eventsys = { + "poll", + ST_EVENTSYS_POLL, + _st_poll_init, + _st_poll_dispatch, + _st_poll_pollset_add, + _st_poll_pollset_del, + _st_poll_fd_new, + _st_poll_fd_close, + _st_poll_fd_getlimit +}; +#endif /* MD_HAVE_POLL */ + + +#ifdef MD_HAVE_KQUEUE +/***************************************** + * kqueue event system + */ + +ST_HIDDEN int _st_kq_init(void) +{ + int err = 0; + int rv = 0; + + _st_kq_data = (struct _st_kqdata *) calloc(1, sizeof(*_st_kq_data)); + if (!_st_kq_data) + return -1; + + if ((_st_kq_data->kq = kqueue()) < 0) { + err = errno; + rv = -1; + goto cleanup_kq; + } + fcntl(_st_kq_data->kq, F_SETFD, FD_CLOEXEC); + _st_kq_data->pid = getpid(); + + /* + * Allocate file descriptor data array. + * FD_SETSIZE looks like good initial size. + */ + _st_kq_data->fd_data_size = FD_SETSIZE; + _st_kq_data->fd_data = (_kq_fd_data_t *)calloc(_st_kq_data->fd_data_size, sizeof(_kq_fd_data_t)); + if (!_st_kq_data->fd_data) { + err = errno; + rv = -1; + goto cleanup_kq; + } + + /* Allocate event lists */ + _st_kq_data->evtlist_size = ST_KQ_MIN_EVTLIST_SIZE; + _st_kq_data->evtlist = (struct kevent *)malloc(_st_kq_data->evtlist_size * sizeof(struct kevent)); + _st_kq_data->addlist_size = ST_KQ_MIN_EVTLIST_SIZE; + _st_kq_data->addlist = (struct kevent *)malloc(_st_kq_data->addlist_size * sizeof(struct kevent)); + _st_kq_data->dellist_size = ST_KQ_MIN_EVTLIST_SIZE; + _st_kq_data->dellist = (struct kevent *)malloc(_st_kq_data->dellist_size * sizeof(struct kevent)); + if (!_st_kq_data->evtlist || !_st_kq_data->addlist || + !_st_kq_data->dellist) { + err = ENOMEM; + rv = -1; + } + + cleanup_kq: + if (rv < 0) { + if (_st_kq_data->kq >= 0) + close(_st_kq_data->kq); + free(_st_kq_data->fd_data); + free(_st_kq_data->evtlist); + free(_st_kq_data->addlist); + free(_st_kq_data->dellist); + free(_st_kq_data); + _st_kq_data = NULL; + errno = err; + } + + return rv; +} + +ST_HIDDEN int _st_kq_fd_data_expand(int maxfd) +{ + _kq_fd_data_t *ptr; + int n = _st_kq_data->fd_data_size; + + while (maxfd >= n) + n <<= 1; + + ptr = (_kq_fd_data_t *)realloc(_st_kq_data->fd_data, n * sizeof(_kq_fd_data_t)); + if (!ptr) + return -1; + + memset(ptr + _st_kq_data->fd_data_size, 0, (n - _st_kq_data->fd_data_size) * sizeof(_kq_fd_data_t)); + + _st_kq_data->fd_data = ptr; + _st_kq_data->fd_data_size = n; + + return 0; +} + +ST_HIDDEN int _st_kq_addlist_expand(int avail) +{ + struct kevent *ptr; + int n = _st_kq_data->addlist_size; + + while (avail > n - _st_kq_data->addlist_cnt) + n <<= 1; + + ptr = (struct kevent *)realloc(_st_kq_data->addlist, n * sizeof(struct kevent)); + if (!ptr) + return -1; + + _st_kq_data->addlist = ptr; + _st_kq_data->addlist_size = n; + + /* + * Try to expand the result event list too + * (although we don't have to do it). + */ + ptr = (struct kevent *)realloc(_st_kq_data->evtlist, n * sizeof(struct kevent)); + if (ptr) { + _st_kq_data->evtlist = ptr; + _st_kq_data->evtlist_size = n; + } + + return 0; +} + +ST_HIDDEN void _st_kq_addlist_add(const struct kevent *kev) +{ + ST_ASSERT(_st_kq_data->addlist_cnt < _st_kq_data->addlist_size); + memcpy(_st_kq_data->addlist + _st_kq_data->addlist_cnt, kev, sizeof(struct kevent)); + _st_kq_data->addlist_cnt++; +} + +ST_HIDDEN void _st_kq_dellist_add(const struct kevent *kev) +{ + int n = _st_kq_data->dellist_size; + + if (_st_kq_data->dellist_cnt >= n) { + struct kevent *ptr; + + n <<= 1; + ptr = (struct kevent *)realloc(_st_kq_data->dellist, n * sizeof(struct kevent)); + if (!ptr) { + /* See comment in _st_kq_pollset_del() */ + return; + } + + _st_kq_data->dellist = ptr; + _st_kq_data->dellist_size = n; + } + + memcpy(_st_kq_data->dellist + _st_kq_data->dellist_cnt, kev, sizeof(struct kevent)); + _st_kq_data->dellist_cnt++; +} + +ST_HIDDEN int _st_kq_pollset_add(struct pollfd *pds, int npds) +{ + struct kevent kev; + struct pollfd *pd; + struct pollfd *epd = pds + npds; + + /* + * Pollset adding is "atomic". That is, either it succeeded for + * all descriptors in the set or it failed. It means that we + * need to do all the checks up front so we don't have to + * "unwind" if adding of one of the descriptors failed. + */ + for (pd = pds; pd < epd; pd++) { + /* POLLIN and/or POLLOUT must be set, but nothing else */ + if (pd->fd < 0 || !pd->events || (pd->events & ~(POLLIN | POLLOUT))) { + errno = EINVAL; + return -1; + } + if (pd->fd >= _st_kq_data->fd_data_size && + _st_kq_fd_data_expand(pd->fd) < 0) + return -1; + } + + /* + * Make sure we have enough room in the addlist for twice as many + * descriptors as in the pollset (for both READ and WRITE filters). + */ + npds <<= 1; + if (npds > _st_kq_data->addlist_size - _st_kq_data->addlist_cnt && _st_kq_addlist_expand(npds) < 0) + return -1; + + for (pd = pds; pd < epd; pd++) { + if ((pd->events & POLLIN) && (_ST_KQ_READ_CNT(pd->fd)++ == 0)) { + memset(&kev, 0, sizeof(kev)); + kev.ident = pd->fd; + kev.filter = EVFILT_READ; +#ifdef NOTE_EOF + /* Make it behave like select() and poll() */ + kev.fflags = NOTE_EOF; +#endif + kev.flags = (EV_ADD | EV_ONESHOT); + _st_kq_addlist_add(&kev); + } + if ((pd->events & POLLOUT) && (_ST_KQ_WRITE_CNT(pd->fd)++ == 0)) { + memset(&kev, 0, sizeof(kev)); + kev.ident = pd->fd; + kev.filter = EVFILT_WRITE; + kev.flags = (EV_ADD | EV_ONESHOT); + _st_kq_addlist_add(&kev); + } + } + + return 0; +} + +ST_HIDDEN void _st_kq_pollset_del(struct pollfd *pds, int npds) +{ + struct kevent kev; + struct pollfd *pd; + struct pollfd *epd = pds + npds; + + /* + * It's OK if deleting fails because a descriptor will either be + * closed or fire only once (we set EV_ONESHOT flag). + */ + _st_kq_data->dellist_cnt = 0; + for (pd = pds; pd < epd; pd++) { + if ((pd->events & POLLIN) && (--_ST_KQ_READ_CNT(pd->fd) == 0)) { + memset(&kev, 0, sizeof(kev)); + kev.ident = pd->fd; + kev.filter = EVFILT_READ; + kev.flags = EV_DELETE; + _st_kq_dellist_add(&kev); + } + if ((pd->events & POLLOUT) && (--_ST_KQ_WRITE_CNT(pd->fd) == 0)) { + memset(&kev, 0, sizeof(kev)); + kev.ident = pd->fd; + kev.filter = EVFILT_WRITE; + kev.flags = EV_DELETE; + _st_kq_dellist_add(&kev); + } + } + + if (_st_kq_data->dellist_cnt > 0) { + /* + * We do "synchronous" kqueue deletes to avoid deleting + * closed descriptors and other possible problems. + */ + int rv; + do { + /* This kevent() won't block since result list size is 0 */ + rv = kevent(_st_kq_data->kq, _st_kq_data->dellist, _st_kq_data->dellist_cnt, NULL, 0, NULL); + } while (rv < 0 && errno == EINTR); + } +} + +ST_HIDDEN void _st_kq_dispatch(void) +{ + struct timespec timeout, *tsp; + struct kevent kev; + st_utime_t min_timeout; + _st_clist_t *q; + _st_pollq_t *pq; + struct pollfd *pds, *epds; + int nfd, i, osfd, notify, filter; + short events, revents; + + if (_ST_SLEEPQ == NULL) { + tsp = NULL; + } else { + min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : (_ST_SLEEPQ->due - _ST_LAST_CLOCK); + timeout.tv_sec = (time_t) (min_timeout / 1000000); + timeout.tv_nsec = (long) ((min_timeout % 1000000) * 1000); + tsp = &timeout; + } + + retry_kevent: + /* Check for I/O operations */ + nfd = kevent(_st_kq_data->kq, + _st_kq_data->addlist, _st_kq_data->addlist_cnt, + _st_kq_data->evtlist, _st_kq_data->evtlist_size, tsp); + + _st_kq_data->addlist_cnt = 0; + + if (nfd > 0) { + for (i = 0; i < nfd; i++) { + osfd = _st_kq_data->evtlist[i].ident; + filter = _st_kq_data->evtlist[i].filter; + + if (filter == EVFILT_READ) { + _ST_KQ_REVENTS(osfd) |= POLLIN; + } else if (filter == EVFILT_WRITE) { + _ST_KQ_REVENTS(osfd) |= POLLOUT; + } + if (_st_kq_data->evtlist[i].flags & EV_ERROR) { + if (_st_kq_data->evtlist[i].data == EBADF) { + _ST_KQ_REVENTS(osfd) |= POLLNVAL; + } else { + _ST_KQ_REVENTS(osfd) |= POLLERR; + } + } + } + + _st_kq_data->dellist_cnt = 0; + + for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { + pq = _ST_POLLQUEUE_PTR(q); + notify = 0; + epds = pq->pds + pq->npds; + + for (pds = pq->pds; pds < epds; pds++) { + osfd = pds->fd; + events = pds->events; + revents = (short)(_ST_KQ_REVENTS(osfd) & ~(POLLIN | POLLOUT)); + if ((events & POLLIN) && (_ST_KQ_REVENTS(osfd) & POLLIN)) { + revents |= POLLIN; + } + if ((events & POLLOUT) && (_ST_KQ_REVENTS(osfd) & POLLOUT)) { + revents |= POLLOUT; + } + pds->revents = revents; + if (revents) { + notify = 1; + } + } + if (notify) { + ST_REMOVE_LINK(&pq->links); + pq->on_ioq = 0; + for (pds = pq->pds; pds < epds; pds++) { + osfd = pds->fd; + events = pds->events; + /* + * We set EV_ONESHOT flag so we only need to delete + * descriptor if it didn't fire. + */ + if ((events & POLLIN) && (--_ST_KQ_READ_CNT(osfd) == 0) && ((_ST_KQ_REVENTS(osfd) & POLLIN) == 0)) { + memset(&kev, 0, sizeof(kev)); + kev.ident = osfd; + kev.filter = EVFILT_READ; + kev.flags = EV_DELETE; + _st_kq_dellist_add(&kev); + } + if ((events & POLLOUT) && (--_ST_KQ_WRITE_CNT(osfd) == 0) && ((_ST_KQ_REVENTS(osfd) & POLLOUT) == 0)) { + memset(&kev, 0, sizeof(kev)); + kev.ident = osfd; + kev.filter = EVFILT_WRITE; + kev.flags = EV_DELETE; + _st_kq_dellist_add(&kev); + } + } + + if (pq->thread->flags & _ST_FL_ON_SLEEPQ) + _ST_DEL_SLEEPQ(pq->thread); + pq->thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(pq->thread); + } + } + + if (_st_kq_data->dellist_cnt > 0) { + int rv; + do { + /* This kevent() won't block since result list size is 0 */ + rv = kevent(_st_kq_data->kq, _st_kq_data->dellist, _st_kq_data->dellist_cnt, NULL, 0, NULL); + } while (rv < 0 && errno == EINTR); + } + + for (i = 0; i < nfd; i++) { + osfd = _st_kq_data->evtlist[i].ident; + _ST_KQ_REVENTS(osfd) = 0; + } + + } else if (nfd < 0) { + if (errno == EBADF && _st_kq_data->pid != getpid()) { + /* We probably forked, reinitialize kqueue */ + if ((_st_kq_data->kq = kqueue()) < 0) { + /* There is nothing we can do here, will retry later */ + return; + } + fcntl(_st_kq_data->kq, F_SETFD, FD_CLOEXEC); + _st_kq_data->pid = getpid(); + /* Re-register all descriptors on ioq with new kqueue */ + memset(_st_kq_data->fd_data, 0, _st_kq_data->fd_data_size * sizeof(_kq_fd_data_t)); + for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { + pq = _ST_POLLQUEUE_PTR(q); + _st_kq_pollset_add(pq->pds, pq->npds); + } + goto retry_kevent; + } + } +} + +ST_HIDDEN int _st_kq_fd_new(int osfd) +{ + if (osfd >= _st_kq_data->fd_data_size && _st_kq_fd_data_expand(osfd) < 0) + return -1; + + return 0; +} + +ST_HIDDEN int _st_kq_fd_close(int osfd) +{ + if (_ST_KQ_READ_CNT(osfd) || _ST_KQ_WRITE_CNT(osfd)) { + errno = EBUSY; + return -1; + } + + return 0; +} + +ST_HIDDEN int _st_kq_fd_getlimit(void) +{ + /* zero means no specific limit */ + return 0; +} + +static _st_eventsys_t _st_kq_eventsys = { + "kqueue", + ST_EVENTSYS_ALT, + _st_kq_init, + _st_kq_dispatch, + _st_kq_pollset_add, + _st_kq_pollset_del, + _st_kq_fd_new, + _st_kq_fd_close, + _st_kq_fd_getlimit +}; +#endif /* MD_HAVE_KQUEUE */ + + +#ifdef MD_HAVE_EPOLL +/***************************************** + * epoll event system + */ + +ST_HIDDEN int _st_epoll_init(void) +{ + int fdlim; + int err = 0; + int rv = 0; + + _st_epoll_data = (struct _st_epolldata *) calloc(1, sizeof(*_st_epoll_data)); + if (!_st_epoll_data) + return -1; + + fdlim = st_getfdlimit(); + _st_epoll_data->fd_hint = (fdlim > 0 && fdlim < ST_EPOLL_EVTLIST_SIZE) ? fdlim : ST_EPOLL_EVTLIST_SIZE; + + if ((_st_epoll_data->epfd = epoll_create(_st_epoll_data->fd_hint)) < 0) { + err = errno; + rv = -1; + goto cleanup_epoll; + } + fcntl(_st_epoll_data->epfd, F_SETFD, FD_CLOEXEC); + _st_epoll_data->pid = getpid(); + + /* Allocate file descriptor data array */ + _st_epoll_data->fd_data_size = _st_epoll_data->fd_hint; + _st_epoll_data->fd_data = (_epoll_fd_data_t *)calloc(_st_epoll_data->fd_data_size, sizeof(_epoll_fd_data_t)); + if (!_st_epoll_data->fd_data) { + err = errno; + rv = -1; + goto cleanup_epoll; + } + + /* Allocate event lists */ + _st_epoll_data->evtlist_size = _st_epoll_data->fd_hint; + _st_epoll_data->evtlist = (struct epoll_event *)malloc(_st_epoll_data->evtlist_size * sizeof(struct epoll_event)); + if (!_st_epoll_data->evtlist) { + err = errno; + rv = -1; + } + + cleanup_epoll: + if (rv < 0) { + if (_st_epoll_data->epfd >= 0) + close(_st_epoll_data->epfd); + free(_st_epoll_data->fd_data); + free(_st_epoll_data->evtlist); + free(_st_epoll_data); + _st_epoll_data = NULL; + errno = err; + } + + return rv; +} + +ST_HIDDEN int _st_epoll_fd_data_expand(int maxfd) +{ + _epoll_fd_data_t *ptr; + int n = _st_epoll_data->fd_data_size; + + while (maxfd >= n) + n <<= 1; + + ptr = (_epoll_fd_data_t *)realloc(_st_epoll_data->fd_data, n * sizeof(_epoll_fd_data_t)); + if (!ptr) + return -1; + + memset(ptr + _st_epoll_data->fd_data_size, 0, (n - _st_epoll_data->fd_data_size) * sizeof(_epoll_fd_data_t)); + + _st_epoll_data->fd_data = ptr; + _st_epoll_data->fd_data_size = n; + + return 0; +} + +ST_HIDDEN void _st_epoll_evtlist_expand(void) +{ + struct epoll_event *ptr; + int n = _st_epoll_data->evtlist_size; + + while (_st_epoll_data->evtlist_cnt > n) + n <<= 1; + + ptr = (struct epoll_event *)realloc(_st_epoll_data->evtlist, n * sizeof(struct epoll_event)); + if (ptr) { + _st_epoll_data->evtlist = ptr; + _st_epoll_data->evtlist_size = n; + } +} + +ST_HIDDEN void _st_epoll_pollset_del(struct pollfd *pds, int npds) +{ + struct epoll_event ev; + struct pollfd *pd; + struct pollfd *epd = pds + npds; + int old_events, events, op; + + /* + * It's more or less OK if deleting fails because a descriptor + * will either be closed or deleted in dispatch function after + * it fires. + */ + for (pd = pds; pd < epd; pd++) { + old_events = _ST_EPOLL_EVENTS(pd->fd); + + if (pd->events & POLLIN) + _ST_EPOLL_READ_CNT(pd->fd)--; + if (pd->events & POLLOUT) + _ST_EPOLL_WRITE_CNT(pd->fd)--; + if (pd->events & POLLPRI) + _ST_EPOLL_EXCEP_CNT(pd->fd)--; + + events = _ST_EPOLL_EVENTS(pd->fd); + /* + * The _ST_EPOLL_REVENTS check below is needed so we can use + * this function inside dispatch(). Outside of dispatch() + * _ST_EPOLL_REVENTS is always zero for all descriptors. + */ + if (events != old_events && _ST_EPOLL_REVENTS(pd->fd) == 0) { + op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; + ev.events = events; + ev.data.fd = pd->fd; + if (epoll_ctl(_st_epoll_data->epfd, op, pd->fd, &ev) == 0 && op == EPOLL_CTL_DEL) { + _st_epoll_data->evtlist_cnt--; + } + } + } +} + +ST_HIDDEN int _st_epoll_pollset_add(struct pollfd *pds, int npds) +{ + struct epoll_event ev; + int i, fd; + int old_events, events, op; + + /* Do as many checks as possible up front */ + for (i = 0; i < npds; i++) { + fd = pds[i].fd; + if (fd < 0 || !pds[i].events || + (pds[i].events & ~(POLLIN | POLLOUT | POLLPRI))) { + errno = EINVAL; + return -1; + } + if (fd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(fd) < 0) + return -1; + } + + for (i = 0; i < npds; i++) { + fd = pds[i].fd; + old_events = _ST_EPOLL_EVENTS(fd); + + if (pds[i].events & POLLIN) + _ST_EPOLL_READ_CNT(fd)++; + if (pds[i].events & POLLOUT) + _ST_EPOLL_WRITE_CNT(fd)++; + if (pds[i].events & POLLPRI) + _ST_EPOLL_EXCEP_CNT(fd)++; + + events = _ST_EPOLL_EVENTS(fd); + if (events != old_events) { + op = old_events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; + ev.events = events; + ev.data.fd = fd; + if (epoll_ctl(_st_epoll_data->epfd, op, fd, &ev) < 0 && (op != EPOLL_CTL_ADD || errno != EEXIST)) + break; + if (op == EPOLL_CTL_ADD) { + _st_epoll_data->evtlist_cnt++; + if (_st_epoll_data->evtlist_cnt > _st_epoll_data->evtlist_size) + _st_epoll_evtlist_expand(); + } + } + } + + if (i < npds) { + /* Error */ + int err = errno; + /* Unroll the state */ + _st_epoll_pollset_del(pds, i + 1); + errno = err; + return -1; + } + + return 0; +} + +ST_HIDDEN void _st_epoll_dispatch(void) +{ + st_utime_t min_timeout; + _st_clist_t *q; + _st_pollq_t *pq; + struct pollfd *pds, *epds; + struct epoll_event ev; + int timeout, nfd, i, osfd, notify; + int events, op; + short revents; + + if (_ST_SLEEPQ == NULL) { + timeout = -1; + } else { + min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : (_ST_SLEEPQ->due - _ST_LAST_CLOCK); + timeout = (int) (min_timeout / 1000); + } + + if (_st_epoll_data->pid != getpid()) { + /* We probably forked, reinitialize epoll set */ + close(_st_epoll_data->epfd); + _st_epoll_data->epfd = epoll_create(_st_epoll_data->fd_hint); + if (_st_epoll_data->epfd < 0) { + /* There is nothing we can do here, will retry later */ + return; + } + fcntl(_st_epoll_data->epfd, F_SETFD, FD_CLOEXEC); + _st_epoll_data->pid = getpid(); + + /* Put all descriptors on ioq into new epoll set */ + memset(_st_epoll_data->fd_data, 0, _st_epoll_data->fd_data_size * sizeof(_epoll_fd_data_t)); + _st_epoll_data->evtlist_cnt = 0; + for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { + pq = _ST_POLLQUEUE_PTR(q); + _st_epoll_pollset_add(pq->pds, pq->npds); + } + } + + /* Check for I/O operations */ + nfd = epoll_wait(_st_epoll_data->epfd, _st_epoll_data->evtlist, _st_epoll_data->evtlist_size, timeout); + + if (nfd > 0) { + for (i = 0; i < nfd; i++) { + osfd = _st_epoll_data->evtlist[i].data.fd; + _ST_EPOLL_REVENTS(osfd) = _st_epoll_data->evtlist[i].events; + if (_ST_EPOLL_REVENTS(osfd) & (EPOLLERR | EPOLLHUP)) { + /* Also set I/O bits on error */ + _ST_EPOLL_REVENTS(osfd) |= _ST_EPOLL_EVENTS(osfd); + } + } + + for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { + pq = _ST_POLLQUEUE_PTR(q); + notify = 0; + epds = pq->pds + pq->npds; + + for (pds = pq->pds; pds < epds; pds++) { + if (_ST_EPOLL_REVENTS(pds->fd) == 0) { + pds->revents = 0; + continue; + } + osfd = pds->fd; + events = pds->events; + revents = 0; + if ((events & POLLIN) && (_ST_EPOLL_REVENTS(osfd) & EPOLLIN)) + revents |= POLLIN; + if ((events & POLLOUT) && (_ST_EPOLL_REVENTS(osfd) & EPOLLOUT)) + revents |= POLLOUT; + if ((events & POLLPRI) && (_ST_EPOLL_REVENTS(osfd) & EPOLLPRI)) + revents |= POLLPRI; + if (_ST_EPOLL_REVENTS(osfd) & EPOLLERR) + revents |= POLLERR; + if (_ST_EPOLL_REVENTS(osfd) & EPOLLHUP) + revents |= POLLHUP; + + pds->revents = revents; + if (revents) { + notify = 1; + } + } + if (notify) { + ST_REMOVE_LINK(&pq->links); + pq->on_ioq = 0; + /* + * Here we will only delete/modify descriptors that + * didn't fire (see comments in _st_epoll_pollset_del()). + */ + _st_epoll_pollset_del(pq->pds, pq->npds); + + if (pq->thread->flags & _ST_FL_ON_SLEEPQ) + _ST_DEL_SLEEPQ(pq->thread); + pq->thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(pq->thread); + } + } + + for (i = 0; i < nfd; i++) { + /* Delete/modify descriptors that fired */ + osfd = _st_epoll_data->evtlist[i].data.fd; + _ST_EPOLL_REVENTS(osfd) = 0; + events = _ST_EPOLL_EVENTS(osfd); + op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; + ev.events = events; + ev.data.fd = osfd; + if (epoll_ctl(_st_epoll_data->epfd, op, osfd, &ev) == 0 && op == EPOLL_CTL_DEL) { + _st_epoll_data->evtlist_cnt--; + } + } + } +} + +ST_HIDDEN int _st_epoll_fd_new(int osfd) +{ + if (osfd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(osfd) < 0) + return -1; + + return 0; +} + +ST_HIDDEN int _st_epoll_fd_close(int osfd) +{ + if (_ST_EPOLL_READ_CNT(osfd) || _ST_EPOLL_WRITE_CNT(osfd) || _ST_EPOLL_EXCEP_CNT(osfd)) { + errno = EBUSY; + return -1; + } + + return 0; +} + +ST_HIDDEN int _st_epoll_fd_getlimit(void) +{ + /* zero means no specific limit */ + return 0; +} + +/* + * Check if epoll functions are just stubs. + */ +ST_HIDDEN int _st_epoll_is_supported(void) +{ + struct epoll_event ev; + + ev.events = EPOLLIN; + ev.data.ptr = NULL; + /* Guaranteed to fail */ + epoll_ctl(-1, EPOLL_CTL_ADD, -1, &ev); + + return (errno != ENOSYS); +} + +static _st_eventsys_t _st_epoll_eventsys = { + "epoll", + ST_EVENTSYS_ALT, + _st_epoll_init, + _st_epoll_dispatch, + _st_epoll_pollset_add, + _st_epoll_pollset_del, + _st_epoll_fd_new, + _st_epoll_fd_close, + _st_epoll_fd_getlimit +}; +#endif /* MD_HAVE_EPOLL */ + + +/***************************************** + * Public functions + */ + +int st_set_eventsys(int eventsys) +{ + if (_st_eventsys) { + errno = EBUSY; + return -1; + } + + switch (eventsys) { + case ST_EVENTSYS_DEFAULT: +#ifdef USE_POLL + _st_eventsys = &_st_poll_eventsys; +#else + _st_eventsys = &_st_select_eventsys; +#endif + break; + case ST_EVENTSYS_SELECT: + _st_eventsys = &_st_select_eventsys; + break; +#ifdef MD_HAVE_POLL + case ST_EVENTSYS_POLL: + _st_eventsys = &_st_poll_eventsys; + break; +#endif + case ST_EVENTSYS_ALT: +#if defined (MD_HAVE_KQUEUE) + _st_eventsys = &_st_kq_eventsys; +#elif defined (MD_HAVE_EPOLL) + if (_st_epoll_is_supported()) + _st_eventsys = &_st_epoll_eventsys; +#endif + break; + default: + errno = EINVAL; + return -1; + } + + return 0; +} + +int st_get_eventsys(void) +{ + return _st_eventsys ? _st_eventsys->val : -1; +} + +const char *st_get_eventsys_name(void) +{ + return _st_eventsys ? _st_eventsys->name : ""; +} + diff --git a/trunk/3rdparty/st-srs/examples/Makefile b/trunk/3rdparty/st-srs/examples/Makefile new file mode 100644 index 0000000000..31c0a6e240 --- /dev/null +++ b/trunk/3rdparty/st-srs/examples/Makefile @@ -0,0 +1,115 @@ +# +# Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. +# All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Silicon Graphics, Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +########################## +# Supported OSes: +# +# AIX +# FREEBSD +# HPUX +# HPUX_64 +# IRIX +# IRIX_64 +# LINUX +# LINUX_IA64 +# NETBSD +# OPENBSD +# OSF1 +# SOLARIS +# SOLARIS_64 + +########################## + +CC = cc + +SHELL = /bin/sh +ECHO = /bin/echo + +DEPTH = .. +BUILD = +TARGETDIR = + +DEFINES = +CFLAGS = +OTHER_FLAGS = + +OBJDIR = $(DEPTH)/$(TARGETDIR) +INCDIR = $(DEPTH)/$(TARGETDIR) +LIBST = $(OBJDIR)/libst.a +HEADER = $(INCDIR)/st.h + +LIBRESOLV = +EXTRALIBS = + +ifeq ($(OS),) +EXAMPLES = unknown +else +EXAMPLES = $(OBJDIR)/lookupdns $(OBJDIR)/proxy $(OBJDIR)/server +endif + + +########################## +# Platform section. +# + +ifeq (DARWIN, $(findstring DARWIN, $(OS))) +LIBRESOLV = -lresolv +endif + +ifeq (LINUX, $(findstring LINUX, $(OS))) +LIBRESOLV = -lresolv +endif + +ifeq (SOLARIS, $(findstring SOLARIS, $(OS))) +LIBRESOLV = -lresolv +EXTRALIBS = -lsocket -lnsl +endif + +# +# End of platform section. +########################## + + +all: $(EXAMPLES) + +$(OBJDIR)/lookupdns: lookupdns.c $(OBJDIR)/res.o $(LIBST) $(HEADER) + $(CC) $(CFLAGS) -I$(INCDIR) lookupdns.c $(OBJDIR)/res.o $(LIBST) $(LIBRESOLV) $(EXTRALIBS) -o $@ + +$(OBJDIR)/proxy: proxy.c $(LIBST) $(HEADER) + $(CC) $(CFLAGS) -I$(INCDIR) proxy.c $(LIBST) $(EXTRALIBS) -o $@ + +$(OBJDIR)/server: server.c $(OBJDIR)/error.o $(LIBST) $(HEADER) + $(CC) $(CFLAGS) -I$(INCDIR) server.c $(OBJDIR)/error.o $(LIBST) $(EXTRALIBS) -o $@ + +$(OBJDIR)/%.o: %.c + $(CC) $(CFLAGS) -I$(INCDIR) -c $< -o $@ + +.DEFAULT: + @cd $(DEPTH); $(MAKE) $@ + diff --git a/trunk/3rdparty/st-srs/examples/README b/trunk/3rdparty/st-srs/examples/README new file mode 100644 index 0000000000..646d4f6236 --- /dev/null +++ b/trunk/3rdparty/st-srs/examples/README @@ -0,0 +1,98 @@ +Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. +All Rights Reserved. + + +This directory contains three example programs. + + +--------------------------------------------------------------------------- + +PROGRAM + + lookupdns + +FILES + + lookupdns.c + res.c + +USAGE + + lookupdns [] ... + +DESCRIPTION + + This program performs asynchronous DNS host name resolution and reports + IP address for each specified as a command line argument. + One ST thread is created for each host name. All threads do host name + resolution concurrently. + + +--------------------------------------------------------------------------- + +PROGRAM + + proxy + +FILES + + proxy.c + +USAGE + + proxy -l -r [-p ] [-S] + + -l bind to local address specified as []: + -r connect to remote address specified as : + -p create specified number of processes + -S serialize accept() calls from different processes + on the same listening socket (if needed). + +DESCRIPTION + + This program acts as a generic gateway. It listens for connections to a + local address. Upon accepting a client connection, it connects to the + specified remote address and then just pumps the data through without any + modification. + + +--------------------------------------------------------------------------- + +PROGRAM + + server + +FILES + + server.c + error.c + +USAGE + + server -l [] + + -l open all log files in specified directory. + + Possible options: + + -b : bind to specified address (multiple addresses + are permitted) + -p create specified number of processes + -t : specify thread limits per listening socket + across all processes + -u change server's user id to specified value + -q set max length of pending connections queue + -a enable access logging + -i run in interactive mode (useful for debugging) + -S serialize accept() calls from different processes + on the same listening socket (if needed). + +DESCRIPTION + + This program is a general server example. It accepts a client connection + and outputs a short HTML page. It can be easily adapted to provide + other services. + + +--------------------------------------------------------------------------- + diff --git a/trunk/3rdparty/st-srs/examples/error.c b/trunk/3rdparty/st-srs/examples/error.c new file mode 100644 index 0000000000..0b2e772874 --- /dev/null +++ b/trunk/3rdparty/st-srs/examples/error.c @@ -0,0 +1,168 @@ +/* + * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Silicon Graphics, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include "st.h" + +/* + * Simple error reporting functions. + * Suggested in W. Richard Stevens' "Advanced Programming in UNIX + * Environment". + */ + +#define MAXLINE 4096 /* max line length */ + +static void err_doit(int, int, const char *, va_list); + + +/* + * Nonfatal error related to a system call. + * Print a message and return. + */ +void err_sys_report(int fd, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(fd, 1, fmt, ap); + va_end(ap); +} + + +/* + * Fatal error related to a system call. + * Print a message and terminate. + */ +void err_sys_quit(int fd, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(fd, 1, fmt, ap); + va_end(ap); + exit(1); +} + + +/* + * Fatal error related to a system call. + * Print a message, dump core, and terminate. + */ +void err_sys_dump(int fd, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(fd, 1, fmt, ap); + va_end(ap); + abort(); /* dump core and terminate */ + exit(1); /* shouldn't get here */ +} + + +/* + * Nonfatal error unrelated to a system call. + * Print a message and return. + */ +void err_report(int fd, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(fd, 0, fmt, ap); + va_end(ap); +} + + +/* + * Fatal error unrelated to a system call. + * Print a message and terminate. + */ +void err_quit(int fd, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + err_doit(fd, 0, fmt, ap); + va_end(ap); + exit(1); +} + + +/* + * Return a pointer to a string containing current time. + */ +char *err_tstamp(void) +{ + static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + static char str[32]; + static time_t lastt = 0; + struct tm *tmp; + time_t currt = st_time(); + + if (currt == lastt) + return str; + + tmp = localtime(&currt); + sprintf(str, "[%02d/%s/%d:%02d:%02d:%02d] ", tmp->tm_mday, + months[tmp->tm_mon], 1900 + tmp->tm_year, tmp->tm_hour, + tmp->tm_min, tmp->tm_sec); + lastt = currt; + + return str; +} + + +/* + * Print a message and return to caller. + * Caller specifies "errnoflag". + */ +static void err_doit(int fd, int errnoflag, const char *fmt, va_list ap) +{ + int errno_save; + char buf[MAXLINE]; + + errno_save = errno; /* value caller might want printed */ + strcpy(buf, err_tstamp()); /* prepend a message with time stamp */ + vsprintf(buf + strlen(buf), fmt, ap); + if (errnoflag) + sprintf(buf + strlen(buf), ": %s\n", strerror(errno_save)); + else + strcat(buf, "\n"); + write(fd, buf, strlen(buf)); + errno = errno_save; +} + diff --git a/trunk/3rdparty/st-srs/examples/lookupdns.c b/trunk/3rdparty/st-srs/examples/lookupdns.c new file mode 100644 index 0000000000..98f6ec5d82 --- /dev/null +++ b/trunk/3rdparty/st-srs/examples/lookupdns.c @@ -0,0 +1,103 @@ +/* + * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Silicon Graphics, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "st.h" + +#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL) +#define NETDB_INTERNAL h_NETDB_INTERNAL +#endif + +/* Resolution timeout (in microseconds) */ +#define TIMEOUT (2*1000000LL) + +/* External function defined in the res.c file */ +int dns_getaddr(const char *host, struct in_addr *addr, st_utime_t timeout); + + +void *do_resolve(void *host) +{ + struct in_addr addr; + + /* Use dns_getaddr() instead of gethostbyname(3) to get IP address */ + if (dns_getaddr(host, &addr, TIMEOUT) < 0) { + fprintf(stderr, "dns_getaddr: can't resolve %s: ", (char *)host); + if (h_errno == NETDB_INTERNAL) + perror(""); + else + herror(""); + } else + printf("%-40s %s\n", (char *)host, inet_ntoa(addr)); + + return NULL; +} + + +/* + * Asynchronous DNS host name resolution. This program creates one + * ST thread for each host name (specified as command line arguments). + * All threads do host name resolution concurrently. + */ +int main(int argc, char *argv[]) +{ + int i; + + if (argc < 2) { + fprintf(stderr, "Usage: %s [] ...\n", argv[0]); + exit(1); + } + + if (st_init() < 0) { + perror("st_init"); + exit(1); + } + + for (i = 1; i < argc; i++) { + /* Create a separate thread for each host name */ + if (st_thread_create(do_resolve, argv[i], 0, 0) == NULL) { + perror("st_thread_create"); + exit(1); + } + } + + st_thread_exit(NULL); + + /* NOTREACHED */ + return 1; +} + diff --git a/trunk/3rdparty/st-srs/examples/proxy.c b/trunk/3rdparty/st-srs/examples/proxy.c new file mode 100644 index 0000000000..2f4636d6b8 --- /dev/null +++ b/trunk/3rdparty/st-srs/examples/proxy.c @@ -0,0 +1,541 @@ +/* + * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Silicon Graphics, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "st.h" + +#define IOBUFSIZE (16*1024) + +#define IOV_LEN 256 +#define IOV_COUNT (IOBUFSIZE / IOV_LEN) + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +static char *prog; /* Program name */ +static struct sockaddr_in rmt_addr; /* Remote address */ + +static unsigned long testing; +#define TESTING_VERBOSE 0x1 +#define TESTING_READV 0x2 +#define TESTING_READ_RESID 0x4 +#define TESTING_WRITEV 0x8 +#define TESTING_WRITE_RESID 0x10 + +static void read_address(const char *str, struct sockaddr_in *sin); +static void start_daemon(void); +static int cpu_count(void); +static void set_concurrency(int nproc); +static void *handle_request(void *arg); +static void print_sys_error(const char *msg); + + +/* + * This program acts as a generic gateway. It listens for connections + * to a local address ('-l' option). Upon accepting a client connection, + * it connects to the specified remote address ('-r' option) and then + * just pumps the data through without any modification. + */ +int main(int argc, char *argv[]) +{ + extern char *optarg; + int opt, sock, n; + int laddr, raddr, num_procs, alt_ev, one_process; + int serialize_accept = 0; + struct sockaddr_in lcl_addr, cli_addr; + st_netfd_t cli_nfd, srv_nfd; + + prog = argv[0]; + num_procs = laddr = raddr = alt_ev = one_process = 0; + + /* Parse arguments */ + while((opt = getopt(argc, argv, "l:r:p:Saht:X")) != EOF) { + switch (opt) { + case 'a': + alt_ev = 1; + break; + case 'l': + read_address(optarg, &lcl_addr); + laddr = 1; + break; + case 'r': + read_address(optarg, &rmt_addr); + if (rmt_addr.sin_addr.s_addr == INADDR_ANY) { + fprintf(stderr, "%s: invalid remote address: %s\n", prog, optarg); + exit(1); + } + raddr = 1; + break; + case 'p': + num_procs = atoi(optarg); + if (num_procs < 1) { + fprintf(stderr, "%s: invalid number of processes: %s\n", prog, optarg); + exit(1); + } + break; + case 'S': + /* + * Serialization decision is tricky on some platforms. For example, + * Solaris 2.6 and above has kernel sockets implementation, so supposedly + * there is no need for serialization. The ST library may be compiled + * on one OS version, but used on another, so the need for serialization + * should be determined at run time by the application. Since it's just + * an example, the serialization decision is left up to user. + * Only on platforms where the serialization is never needed on any OS + * version st_netfd_serialize_accept() is a no-op. + */ + serialize_accept = 1; + break; + case 't': + testing = strtoul(optarg, NULL, 0); + break; + case 'X': + one_process = 1; + break; + case 'h': + case '?': + fprintf(stderr, "Usage: %s [options] -l <[host]:port> -r \n", + prog); + fprintf(stderr, "options are:\n"); + fprintf(stderr, " -p number of parallel processes\n"); + fprintf(stderr, " -S serialize accepts\n"); + fprintf(stderr, " -a use alternate event system\n"); +#ifdef DEBUG + fprintf(stderr, " -t mask testing/debugging mode\n"); + fprintf(stderr, " -X one process, don't daemonize\n"); +#endif + exit(1); + } + } + if (!laddr) { + fprintf(stderr, "%s: local address required\n", prog); + exit(1); + } + if (!raddr) { + fprintf(stderr, "%s: remote address required\n", prog); + exit(1); + } + if (num_procs == 0) + num_procs = cpu_count(); + + fprintf(stderr, "%s: starting proxy daemon on %s:%d\n", prog, + inet_ntoa(lcl_addr.sin_addr), ntohs(lcl_addr.sin_port)); + + /* Start the daemon */ + if (one_process) + num_procs = 1; + else + start_daemon(); + + if (alt_ev) + st_set_eventsys(ST_EVENTSYS_ALT); + + /* Initialize the ST library */ + if (st_init() < 0) { + print_sys_error("st_init"); + exit(1); + } + + /* Create and bind listening socket */ + if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + print_sys_error("socket"); + exit(1); + } + n = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof(n)) < 0) { + print_sys_error("setsockopt"); + exit(1); + } + if (bind(sock, (struct sockaddr *)&lcl_addr, sizeof(lcl_addr)) < 0) { + print_sys_error("bind"); + exit(1); + } + listen(sock, 128); + if ((srv_nfd = st_netfd_open_socket(sock)) == NULL) { + print_sys_error("st_netfd_open"); + exit(1); + } + /* See the comment regarding serialization decision above */ + if (num_procs > 1 && serialize_accept && st_netfd_serialize_accept(srv_nfd) + < 0) { + print_sys_error("st_netfd_serialize_accept"); + exit(1); + } + + /* Start server processes */ + if (!one_process) + set_concurrency(num_procs); + + for ( ; ; ) { + n = sizeof(cli_addr); + cli_nfd = st_accept(srv_nfd, (struct sockaddr *)&cli_addr, &n, + ST_UTIME_NO_TIMEOUT); + if (cli_nfd == NULL) { + print_sys_error("st_accept"); + exit(1); + } + if (st_thread_create(handle_request, cli_nfd, 0, 0) == NULL) { + print_sys_error("st_thread_create"); + exit(1); + } + } + + /* NOTREACHED */ + return 1; +} + + +static void read_address(const char *str, struct sockaddr_in *sin) +{ + char host[128], *p; + struct hostent *hp; + unsigned short port; + + strcpy(host, str); + if ((p = strchr(host, ':')) == NULL) { + fprintf(stderr, "%s: invalid address: %s\n", prog, host); + exit(1); + } + *p++ = '\0'; + port = (unsigned short) atoi(p); + if (port < 1) { + fprintf(stderr, "%s: invalid port: %s\n", prog, p); + exit(1); + } + + memset(sin, 0, sizeof(struct sockaddr_in)); + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + if (host[0] == '\0') { + sin->sin_addr.s_addr = INADDR_ANY; + return; + } + sin->sin_addr.s_addr = inet_addr(host); + if (sin->sin_addr.s_addr == INADDR_NONE) { + /* not dotted-decimal */ + if ((hp = gethostbyname(host)) == NULL) { + fprintf(stderr, "%s: can't resolve address: %s\n", prog, host); + exit(1); + } + memcpy(&sin->sin_addr, hp->h_addr, hp->h_length); + } +} + +#ifdef DEBUG +static void show_iov(const struct iovec *iov, int niov) +{ + int i; + size_t total; + + printf("iov %p has %d entries:\n", iov, niov); + total = 0; + for (i = 0; i < niov; i++) { + printf("iov[%3d] iov_base=%p iov_len=0x%lx(%lu)\n", + i, iov[i].iov_base, (unsigned long) iov[i].iov_len, + (unsigned long) iov[i].iov_len); + total += iov[i].iov_len; + } + printf("total 0x%lx(%ld)\n", (unsigned long) total, (unsigned long) total); +} + +/* + * This version is tricked out to test all the + * st_(read|write)v?(_resid)? variants. Use the non-DEBUG version for + * anything serious. st_(read|write) are all this function really + * needs. + */ +static int pass(st_netfd_t in, st_netfd_t out) +{ + char buf[IOBUFSIZE]; + struct iovec iov[IOV_COUNT]; + int ioviter, nw, nr; + + if (testing & TESTING_READV) { + for (ioviter = 0; ioviter < IOV_COUNT; ioviter++) { + iov[ioviter].iov_base = &buf[ioviter * IOV_LEN]; + iov[ioviter].iov_len = IOV_LEN; + } + if (testing & TESTING_VERBOSE) { + printf("readv(%p)...\n", in); + show_iov(iov, IOV_COUNT); + } + if (testing & TESTING_READ_RESID) { + struct iovec *riov = iov; + int riov_cnt = IOV_COUNT; + if (st_readv_resid(in, &riov, &riov_cnt, ST_UTIME_NO_TIMEOUT) == 0) { + if (testing & TESTING_VERBOSE) { + printf("resid\n"); + show_iov(riov, riov_cnt); + printf("full\n"); + show_iov(iov, IOV_COUNT); + } + nr = 0; + for (ioviter = 0; ioviter < IOV_COUNT; ioviter++) + nr += iov[ioviter].iov_len; + nr = IOBUFSIZE - nr; + } else + nr = -1; + } else + nr = (int) st_readv(in, iov, IOV_COUNT, ST_UTIME_NO_TIMEOUT); + } else { + if (testing & TESTING_READ_RESID) { + size_t resid = IOBUFSIZE; + if (st_read_resid(in, buf, &resid, ST_UTIME_NO_TIMEOUT) == 0) + nr = IOBUFSIZE - resid; + else + nr = -1; + } else + nr = (int) st_read(in, buf, IOBUFSIZE, ST_UTIME_NO_TIMEOUT); + } + if (testing & TESTING_VERBOSE) + printf("got 0x%x(%d) E=%d\n", nr, nr, errno); + + if (nr <= 0) + return 0; + + if (testing & TESTING_WRITEV) { + for (nw = 0, ioviter = 0; nw < nr; + nw += iov[ioviter].iov_len, ioviter++) { + iov[ioviter].iov_base = &buf[nw]; + iov[ioviter].iov_len = nr - nw; + if (iov[ioviter].iov_len > IOV_LEN) + iov[ioviter].iov_len = IOV_LEN; + } + if (testing & TESTING_VERBOSE) { + printf("writev(%p)...\n", out); + show_iov(iov, ioviter); + } + if (testing & TESTING_WRITE_RESID) { + struct iovec *riov = iov; + int riov_cnt = ioviter; + if (st_writev_resid(out, &riov, &riov_cnt, ST_UTIME_NO_TIMEOUT) == 0) { + if (testing & TESTING_VERBOSE) { + printf("resid\n"); + show_iov(riov, riov_cnt); + printf("full\n"); + show_iov(iov, ioviter); + } + nw = 0; + while (--ioviter >= 0) + nw += iov[ioviter].iov_len; + nw = nr - nw; + } else + nw = -1; + } else + nw = st_writev(out, iov, ioviter, ST_UTIME_NO_TIMEOUT); + } else { + if (testing & TESTING_WRITE_RESID) { + size_t resid = nr; + if (st_write_resid(out, buf, &resid, ST_UTIME_NO_TIMEOUT) == 0) + nw = nr - resid; + else + nw = -1; + } else + nw = st_write(out, buf, nr, ST_UTIME_NO_TIMEOUT); + } + if (testing & TESTING_VERBOSE) + printf("put 0x%x(%d) E=%d\n", nw, nw, errno); + + if (nw != nr) + return 0; + + return 1; +} +#else /* DEBUG */ +/* + * This version is the simple one suitable for serious use. + */ +static int pass(st_netfd_t in, st_netfd_t out) +{ + char buf[IOBUFSIZE]; + int nw, nr; + + nr = (int) st_read(in, buf, IOBUFSIZE, ST_UTIME_NO_TIMEOUT); + if (nr <= 0) + return 0; + + nw = st_write(out, buf, nr, ST_UTIME_NO_TIMEOUT); + if (nw != nr) + return 0; + + return 1; +} +#endif + +static void *handle_request(void *arg) +{ + struct pollfd pds[2]; + st_netfd_t cli_nfd, rmt_nfd; + int sock; + + cli_nfd = (st_netfd_t) arg; + pds[0].fd = st_netfd_fileno(cli_nfd); + pds[0].events = POLLIN; + + /* Connect to remote host */ + if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + print_sys_error("socket"); + goto done; + } + if ((rmt_nfd = st_netfd_open_socket(sock)) == NULL) { + print_sys_error("st_netfd_open_socket"); + close(sock); + goto done; + } + if (st_connect(rmt_nfd, (struct sockaddr *)&rmt_addr, + sizeof(rmt_addr), ST_UTIME_NO_TIMEOUT) < 0) { + print_sys_error("st_connect"); + st_netfd_close(rmt_nfd); + goto done; + } + pds[1].fd = sock; + pds[1].events = POLLIN; + + /* + * Now just pump the data through. + * XXX This should use one thread for each direction for true full-duplex. + */ + for ( ; ; ) { + pds[0].revents = 0; + pds[1].revents = 0; + + if (st_poll(pds, 2, ST_UTIME_NO_TIMEOUT) <= 0) { + print_sys_error("st_poll"); + break; + } + + if (pds[0].revents & POLLIN) { + if (!pass(cli_nfd, rmt_nfd)) + break; + } + + if (pds[1].revents & POLLIN) { + if (!pass(rmt_nfd, cli_nfd)) + break; + } + } + st_netfd_close(rmt_nfd); + +done: + + st_netfd_close(cli_nfd); + + return NULL; +} + +static void start_daemon(void) +{ + pid_t pid; + + /* Start forking */ + if ((pid = fork()) < 0) { + print_sys_error("fork"); + exit(1); + } + if (pid > 0) + exit(0); /* parent */ + + /* First child process */ + setsid(); /* become session leader */ + + if ((pid = fork()) < 0) { + print_sys_error("fork"); + exit(1); + } + if (pid > 0) /* first child */ + exit(0); + + chdir("/"); + umask(022); +} + +/* + * Create separate processes ("virtual processors"). Since it's just an + * example, there is no watchdog - the parent just exits leaving children + * on their own. + */ +static void set_concurrency(int nproc) +{ + pid_t pid; + int i; + + if (nproc < 1) + nproc = 1; + + for (i = 0; i < nproc; i++) { + if ((pid = fork()) < 0) { + print_sys_error("fork"); + exit(1); + } + /* Child returns */ + if (pid == 0) + return; + } + + /* Parent just exits */ + exit(0); +} + +static int cpu_count(void) +{ + int n; + +#if defined (_SC_NPROCESSORS_ONLN) + n = (int) sysconf(_SC_NPROCESSORS_ONLN); +#elif defined (_SC_NPROC_ONLN) + n = (int) sysconf(_SC_NPROC_ONLN); +#elif defined (HPUX) +#include + n = mpctl(MPC_GETNUMSPUS, 0, 0); +#else + n = -1; + errno = ENOSYS; +#endif + + return n; +} + +static void print_sys_error(const char *msg) +{ + fprintf(stderr, "%s: %s: %s\n", prog, msg, strerror(errno)); +} + diff --git a/trunk/3rdparty/st-srs/examples/res.c b/trunk/3rdparty/st-srs/examples/res.c new file mode 100644 index 0000000000..14ecd8c927 --- /dev/null +++ b/trunk/3rdparty/st-srs/examples/res.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Silicon Graphics, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined (DARWIN) +#define BIND_8_COMPAT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "st.h" + +#define MAXPACKET 1024 + +#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL) +#define NETDB_INTERNAL h_NETDB_INTERNAL +#endif + +/* New in Solaris 7 */ +#if !defined(_getshort) && defined(ns_get16) +#define _getshort(cp) ns_get16(cp) +#endif + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf_t; + + +static int parse_answer(querybuf_t *ans, int len, struct in_addr *addr) +{ + char buf[MAXPACKET]; + HEADER *ahp; + u_char *cp, *eoa; + int type, n; + + ahp = &ans->hdr; + eoa = ans->buf + len; + cp = ans->buf + sizeof(HEADER); + + while (ahp->qdcount > 0) { + ahp->qdcount--; + cp += dn_skipname(cp, eoa) + QFIXEDSZ; + } + while (ahp->ancount > 0 && cp < eoa) { + ahp->ancount--; + if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0) + break; + cp += n; + type = _getshort(cp); + cp += 8; + n = _getshort(cp); + cp += 2; + if (type == T_CNAME) { + cp += n; + continue; + } + memcpy(addr, cp, n); + return 0; + } + + h_errno = TRY_AGAIN; + return -1; +} + + +static int query_domain(st_netfd_t nfd, const char *name, struct in_addr *addr, + st_utime_t timeout) +{ + querybuf_t qbuf; + u_char *buf = qbuf.buf; + HEADER *hp = &qbuf.hdr; + int blen = sizeof(qbuf); + int i, len, id; + + for (i = 0; i < _res.nscount; i++) { + len = res_mkquery(QUERY, name, C_IN, T_A, NULL, 0, NULL, buf, blen); + if (len <= 0) { + h_errno = NO_RECOVERY; + return -1; + } + id = hp->id; + + if (st_sendto(nfd, buf, len, (struct sockaddr *)&(_res.nsaddr_list[i]), + sizeof(struct sockaddr), timeout) != len) { + h_errno = NETDB_INTERNAL; + /* EINTR means interrupt by other thread, NOT by a caught signal */ + if (errno == EINTR) + return -1; + continue; + } + + /* Wait for reply */ + do { + len = st_recvfrom(nfd, buf, blen, NULL, NULL, timeout); + if (len <= 0) + break; + } while (id != hp->id); + + if (len < HFIXEDSZ) { + h_errno = NETDB_INTERNAL; + if (len >= 0) + errno = EMSGSIZE; + else if (errno == EINTR) /* see the comment above */ + return -1; + continue; + } + + hp->ancount = ntohs(hp->ancount); + hp->qdcount = ntohs(hp->qdcount); + if ((hp->rcode != NOERROR) || (hp->ancount == 0)) { + switch (hp->rcode) { + case NXDOMAIN: + h_errno = HOST_NOT_FOUND; + break; + case SERVFAIL: + h_errno = TRY_AGAIN; + break; + case NOERROR: + h_errno = NO_DATA; + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + h_errno = NO_RECOVERY; + } + continue; + } + + if (parse_answer(&qbuf, len, addr) == 0) + return 0; + } + + return -1; +} + + +#define CLOSE_AND_RETURN(ret) \ + { \ + n = errno; \ + st_netfd_close(nfd); \ + errno = n; \ + return (ret); \ + } + + +int dns_getaddr(const char *host, struct in_addr *addr, st_utime_t timeout) +{ + char name[MAXDNAME], **domain; + const char *cp; + int s, n, maxlen, dots; + int trailing_dot, tried_as_is; + st_netfd_t nfd; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return -1; + } + if (_res.options & RES_USEVC) { + h_errno = NETDB_INTERNAL; + errno = ENOSYS; + return -1; + } + if (!host || *host == '\0') { + h_errno = HOST_NOT_FOUND; + return -1; + } + + /* Create UDP socket */ + if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + h_errno = NETDB_INTERNAL; + return -1; + } + if ((nfd = st_netfd_open_socket(s)) == NULL) { + h_errno = NETDB_INTERNAL; + n = errno; + close(s); + errno = n; + return -1; + } + + maxlen = sizeof(name) - 1; + n = 0; + dots = 0; + trailing_dot = 0; + tried_as_is = 0; + + for (cp = host; *cp && n < maxlen; cp++) { + dots += (*cp == '.'); + name[n++] = *cp; + } + if (name[n - 1] == '.') + trailing_dot = 1; + + /* + * If there are dots in the name already, let's just give it a try + * 'as is'. The threshold can be set with the "ndots" option. + */ + if (dots >= _res.ndots) { + if (query_domain(nfd, host, addr, timeout) == 0) + CLOSE_AND_RETURN(0); + if (h_errno == NETDB_INTERNAL && errno == EINTR) + CLOSE_AND_RETURN(-1); + tried_as_is = 1; + } + + /* + * We do at least one level of search if + * - there is no dot and RES_DEFNAME is set, or + * - there is at least one dot, there is no trailing dot, + * and RES_DNSRCH is set. + */ + if ((!dots && (_res.options & RES_DEFNAMES)) || + (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { + name[n++] = '.'; + for (domain = _res.dnsrch; *domain; domain++) { + strncpy(name + n, *domain, maxlen - n); + if (query_domain(nfd, name, addr, timeout) == 0) + CLOSE_AND_RETURN(0); + if (h_errno == NETDB_INTERNAL && errno == EINTR) + CLOSE_AND_RETURN(-1); + if (!(_res.options & RES_DNSRCH)) + break; + } + } + + /* + * If we have not already tried the name "as is", do that now. + * note that we do this regardless of how many dots were in the + * name or whether it ends with a dot. + */ + if (!tried_as_is) { + if (query_domain(nfd, host, addr, timeout) == 0) + CLOSE_AND_RETURN(0); + } + + CLOSE_AND_RETURN(-1); +} + diff --git a/trunk/3rdparty/st-srs/examples/server.c b/trunk/3rdparty/st-srs/examples/server.c new file mode 100644 index 0000000000..5d5aa6d726 --- /dev/null +++ b/trunk/3rdparty/st-srs/examples/server.c @@ -0,0 +1,1025 @@ +/* + * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Silicon Graphics, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "st.h" + + +/****************************************************************** + * Server configuration parameters + */ + +/* Log files */ +#define PID_FILE "pid" +#define ERRORS_FILE "errors" +#define ACCESS_FILE "access" + +/* Default server port */ +#define SERV_PORT_DEFAULT 8000 + +/* Socket listen queue size */ +#define LISTENQ_SIZE_DEFAULT 256 + +/* Max number of listening sockets ("hardware virtual servers") */ +#define MAX_BIND_ADDRS 16 + +/* Max number of "spare" threads per process per socket */ +#define MAX_WAIT_THREADS_DEFAULT 8 + +/* Number of file descriptors needed to handle one client session */ +#define FD_PER_THREAD 2 + +/* Access log buffer flushing interval (in seconds) */ +#define ACCLOG_FLUSH_INTERVAL 30 + +/* Request read timeout (in seconds) */ +#define REQUEST_TIMEOUT 30 + + +/****************************************************************** + * Global data + */ + +struct socket_info { + st_netfd_t nfd; /* Listening socket */ + char *addr; /* Bind address */ + unsigned int port; /* Port */ + int wait_threads; /* Number of threads waiting to accept */ + int busy_threads; /* Number of threads processing request */ + int rqst_count; /* Total number of processed requests */ +} srv_socket[MAX_BIND_ADDRS]; /* Array of listening sockets */ + +static int sk_count = 0; /* Number of listening sockets */ + +static int vp_count = 0; /* Number of server processes (VPs) */ +static pid_t *vp_pids; /* Array of VP pids */ + +static int my_index = -1; /* Current process index */ +static pid_t my_pid = -1; /* Current process pid */ + +static st_netfd_t sig_pipe[2]; /* Signal pipe */ + +/* + * Configuration flags/parameters + */ +static int interactive_mode = 0; +static int serialize_accept = 0; +static int log_access = 0; +static char *logdir = NULL; +static char *username = NULL; +static int listenq_size = LISTENQ_SIZE_DEFAULT; +static int errfd = STDERR_FILENO; + +/* + * Thread throttling parameters (all numbers are per listening socket). + * Zero values mean use default. + */ +static int max_threads = 0; /* Max number of threads */ +static int max_wait_threads = 0; /* Max number of "spare" threads */ +static int min_wait_threads = 2; /* Min number of "spare" threads */ + + +/****************************************************************** + * Useful macros + */ + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +#define SEC2USEC(s) ((s)*1000000LL) + +#define WAIT_THREADS(i) (srv_socket[i].wait_threads) +#define BUSY_THREADS(i) (srv_socket[i].busy_threads) +#define TOTAL_THREADS(i) (WAIT_THREADS(i) + BUSY_THREADS(i)) +#define RQST_COUNT(i) (srv_socket[i].rqst_count) + + +/****************************************************************** + * Forward declarations + */ + +static void usage(const char *progname); +static void parse_arguments(int argc, char *argv[]); +static void start_daemon(void); +static void set_thread_throttling(void); +static void create_listeners(void); +static void change_user(void); +static void open_log_files(void); +static void start_processes(void); +static void wdog_sighandler(int signo); +static void child_sighandler(int signo); +static void install_sighandlers(void); +static void start_threads(void); +static void *process_signals(void *arg); +static void *flush_acclog_buffer(void *arg); +static void *handle_connections(void *arg); +static void dump_server_info(void); + +static void Signal(int sig, void (*handler)(int)); +static int cpu_count(void); + +extern void handle_session(long srv_socket_index, st_netfd_t cli_nfd); +extern void load_configs(void); +extern void logbuf_open(void); +extern void logbuf_flush(void); +extern void logbuf_close(void); + +/* Error reporting functions defined in the error.c file */ +extern void err_sys_report(int fd, const char *fmt, ...); +extern void err_sys_quit(int fd, const char *fmt, ...); +extern void err_sys_dump(int fd, const char *fmt, ...); +extern void err_report(int fd, const char *fmt, ...); +extern void err_quit(int fd, const char *fmt, ...); + + +/* + * General server example: accept a client connection and do something. + * This program just outputs a short HTML page, but can be easily adapted + * to do other things. + * + * This server creates a constant number of processes ("virtual processors" + * or VPs) and replaces them when they die. Each virtual processor manages + * its own independent set of state threads (STs), the number of which varies + * with load against the server. Each state thread listens to exactly one + * listening socket. The initial process becomes the watchdog, waiting for + * children (VPs) to die or for a signal requesting termination or restart. + * Upon receiving a restart signal (SIGHUP), all VPs close and then reopen + * log files and reload configuration. All currently active connections remain + * active. It is assumed that new configuration affects only request + * processing and not the general server parameters such as number of VPs, + * thread limits, bind addresses, etc. Those are specified as command line + * arguments, so the server has to be stopped and then started again in order + * to change them. + * + * Each state thread loops processing connections from a single listening + * socket. Only one ST runs on a VP at a time, and VPs do not share memory, + * so no mutual exclusion locking is necessary on any data, and the entire + * server is free to use all the static variables and non-reentrant library + * functions it wants, greatly simplifying programming and debugging and + * increasing performance (for example, it is safe to ++ and -- all global + * counters or call inet_ntoa(3) without any mutexes). The current thread on + * each VP maintains equilibrium on that VP, starting a new thread or + * terminating itself if the number of spare threads exceeds the lower or + * upper limit. + * + * All I/O operations on sockets must use the State Thread library's I/O + * functions because only those functions prevent blocking of the entire VP + * process and perform state thread scheduling. + */ +int main(int argc, char *argv[]) +{ + /* Parse command-line options */ + parse_arguments(argc, argv); + + /* Allocate array of server pids */ + if ((vp_pids = calloc(vp_count, sizeof(pid_t))) == NULL) + err_sys_quit(errfd, "ERROR: calloc failed"); + + /* Start the daemon */ + if (!interactive_mode) + start_daemon(); + + /* Initialize the ST library */ + if (st_init() < 0) + err_sys_quit(errfd, "ERROR: initialization failed: st_init"); + + /* Set thread throttling parameters */ + set_thread_throttling(); + + /* Create listening sockets */ + create_listeners(); + + /* Change the user */ + if (username) + change_user(); + + /* Open log files */ + open_log_files(); + + /* Start server processes (VPs) */ + start_processes(); + + /* Turn time caching on */ + st_timecache_set(1); + + /* Install signal handlers */ + install_sighandlers(); + + /* Load configuration from config files */ + load_configs(); + + /* Start all threads */ + start_threads(); + + /* Become a signal processing thread */ + process_signals(NULL); + + /* NOTREACHED */ + return 1; +} + + +/******************************************************************/ + +static void usage(const char *progname) +{ + fprintf(stderr, "Usage: %s -l []\n\n" + "Possible options:\n\n" + "\t-b : Bind to specified address. Multiple" + " addresses\n" + "\t are permitted.\n" + "\t-p Create specified number of processes.\n" + "\t-t : Specify thread limits per listening" + " socket\n" + "\t across all processes.\n" + "\t-u Change server's user id to specified" + " value.\n" + "\t-q Set max length of pending connections" + " queue.\n" + "\t-a Enable access logging.\n" + "\t-i Run in interactive mode.\n" + "\t-S Serialize all accept() calls.\n" + "\t-h Print this message.\n", + progname); + exit(1); +} + + +/******************************************************************/ + +static void parse_arguments(int argc, char *argv[]) +{ + extern char *optarg; + int opt; + char *c; + + while ((opt = getopt(argc, argv, "b:p:l:t:u:q:aiSh")) != EOF) { + switch (opt) { + case 'b': + if (sk_count >= MAX_BIND_ADDRS) + err_quit(errfd, "ERROR: max number of bind addresses (%d) exceeded", + MAX_BIND_ADDRS); + if ((c = strdup(optarg)) == NULL) + err_sys_quit(errfd, "ERROR: strdup"); + srv_socket[sk_count++].addr = c; + break; + case 'p': + vp_count = atoi(optarg); + if (vp_count < 1) + err_quit(errfd, "ERROR: invalid number of processes: %s", optarg); + break; + case 'l': + logdir = optarg; + break; + case 't': + max_wait_threads = (int) strtol(optarg, &c, 10); + if (*c++ == ':') + max_threads = atoi(c); + if (max_wait_threads < 0 || max_threads < 0) + err_quit(errfd, "ERROR: invalid number of threads: %s", optarg); + break; + case 'u': + username = optarg; + break; + case 'q': + listenq_size = atoi(optarg); + if (listenq_size < 1) + err_quit(errfd, "ERROR: invalid listen queue size: %s", optarg); + break; + case 'a': + log_access = 1; + break; + case 'i': + interactive_mode = 1; + break; + case 'S': + /* + * Serialization decision is tricky on some platforms. For example, + * Solaris 2.6 and above has kernel sockets implementation, so supposedly + * there is no need for serialization. The ST library may be compiled + * on one OS version, but used on another, so the need for serialization + * should be determined at run time by the application. Since it's just + * an example, the serialization decision is left up to user. + * Only on platforms where the serialization is never needed on any OS + * version st_netfd_serialize_accept() is a no-op. + */ + serialize_accept = 1; + break; + case 'h': + case '?': + usage(argv[0]); + } + } + + if (logdir == NULL && !interactive_mode) { + err_report(errfd, "ERROR: logging directory is required\n"); + usage(argv[0]); + } + + if (getuid() == 0 && username == NULL) + err_report(errfd, "WARNING: running as super-user!"); + + if (vp_count == 0 && (vp_count = cpu_count()) < 1) + vp_count = 1; + + if (sk_count == 0) { + sk_count = 1; + srv_socket[0].addr = "0.0.0.0"; + } +} + + +/******************************************************************/ + +static void start_daemon(void) +{ + pid_t pid; + + /* Start forking */ + if ((pid = fork()) < 0) + err_sys_quit(errfd, "ERROR: fork"); + if (pid > 0) + exit(0); /* parent */ + + /* First child process */ + setsid(); /* become session leader */ + + if ((pid = fork()) < 0) + err_sys_quit(errfd, "ERROR: fork"); + if (pid > 0) /* first child */ + exit(0); + + umask(022); + + if (chdir(logdir) < 0) + err_sys_quit(errfd, "ERROR: can't change directory to %s: chdir", logdir); +} + + +/****************************************************************** + * For simplicity, the minimal size of thread pool is considered + * as a maximum number of spare threads (max_wait_threads) that + * will be created upon server startup. The pool size can grow up + * to the max_threads value. Note that this is a per listening + * socket limit. It is also possible to limit the total number of + * threads for all sockets rather than impose a per socket limit. + */ + +static void set_thread_throttling(void) +{ + /* + * Calculate total values across all processes. + * All numbers are per listening socket. + */ + if (max_wait_threads == 0) + max_wait_threads = MAX_WAIT_THREADS_DEFAULT * vp_count; + /* Assuming that each client session needs FD_PER_THREAD file descriptors */ + if (max_threads == 0) + max_threads = (st_getfdlimit() * vp_count) / FD_PER_THREAD / sk_count; + if (max_wait_threads > max_threads) + max_wait_threads = max_threads; + + /* + * Now calculate per-process values. + */ + if (max_wait_threads % vp_count) + max_wait_threads = max_wait_threads / vp_count + 1; + else + max_wait_threads = max_wait_threads / vp_count; + if (max_threads % vp_count) + max_threads = max_threads / vp_count + 1; + else + max_threads = max_threads / vp_count; + + if (min_wait_threads > max_wait_threads) + min_wait_threads = max_wait_threads; +} + + +/******************************************************************/ + +static void create_listeners(void) +{ + int i, n, sock; + char *c; + struct sockaddr_in serv_addr; + struct hostent *hp; + unsigned short port; + + for (i = 0; i < sk_count; i++) { + port = 0; + if ((c = strchr(srv_socket[i].addr, ':')) != NULL) { + *c++ = '\0'; + port = (unsigned short) atoi(c); + } + if (srv_socket[i].addr[0] == '\0') + srv_socket[i].addr = "0.0.0.0"; + if (port == 0) + port = SERV_PORT_DEFAULT; + + /* Create server socket */ + if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) + err_sys_quit(errfd, "ERROR: can't create socket: socket"); + n = 1; + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof(n)) < 0) + err_sys_quit(errfd, "ERROR: can't set SO_REUSEADDR: setsockopt"); + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(port); + serv_addr.sin_addr.s_addr = inet_addr(srv_socket[i].addr); + if (serv_addr.sin_addr.s_addr == INADDR_NONE) { + /* not dotted-decimal */ + if ((hp = gethostbyname(srv_socket[i].addr)) == NULL) + err_quit(errfd, "ERROR: can't resolve address: %s", + srv_socket[i].addr); + memcpy(&serv_addr.sin_addr, hp->h_addr, hp->h_length); + } + srv_socket[i].port = port; + + /* Do bind and listen */ + if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + err_sys_quit(errfd, "ERROR: can't bind to address %s, port %hu", + srv_socket[i].addr, port); + if (listen(sock, listenq_size) < 0) + err_sys_quit(errfd, "ERROR: listen"); + + /* Create file descriptor object from OS socket */ + if ((srv_socket[i].nfd = st_netfd_open_socket(sock)) == NULL) + err_sys_quit(errfd, "ERROR: st_netfd_open_socket"); + /* + * On some platforms (e.g. IRIX, Linux) accept() serialization is never + * needed for any OS version. In that case st_netfd_serialize_accept() + * is just a no-op. Also see the comment above. + */ + if (serialize_accept && st_netfd_serialize_accept(srv_socket[i].nfd) < 0) + err_sys_quit(errfd, "ERROR: st_netfd_serialize_accept"); + } +} + + +/******************************************************************/ + +static void change_user(void) +{ + struct passwd *pw; + + if ((pw = getpwnam(username)) == NULL) + err_quit(errfd, "ERROR: can't find user '%s': getpwnam failed", username); + + if (setgid(pw->pw_gid) < 0) + err_sys_quit(errfd, "ERROR: can't change group id: setgid"); + if (setuid(pw->pw_uid) < 0) + err_sys_quit(errfd, "ERROR: can't change user id: setuid"); + + err_report(errfd, "INFO: changed process user id to '%s'", username); +} + + +/******************************************************************/ + +static void open_log_files(void) +{ + int fd; + char str[32]; + + if (interactive_mode) + return; + + /* Open access log */ + if (log_access) + logbuf_open(); + + /* Open and write pid to pid file */ + if ((fd = open(PID_FILE, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0) + err_sys_quit(errfd, "ERROR: can't open pid file: open"); + sprintf(str, "%d\n", (int)getpid()); + if (write(fd, str, strlen(str)) != strlen(str)) + err_sys_quit(errfd, "ERROR: can't write to pid file: write"); + close(fd); + + /* Open error log file */ + if ((fd = open(ERRORS_FILE, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0) + err_sys_quit(errfd, "ERROR: can't open error log file: open"); + errfd = fd; + + err_report(errfd, "INFO: starting the server..."); +} + + +/******************************************************************/ + +static void start_processes(void) +{ + int i, status; + pid_t pid; + sigset_t mask, omask; + + if (interactive_mode) { + my_index = 0; + my_pid = getpid(); + return; + } + + for (i = 0; i < vp_count; i++) { + if ((pid = fork()) < 0) { + err_sys_report(errfd, "ERROR: can't create process: fork"); + if (i == 0) + exit(1); + err_report(errfd, "WARN: started only %d processes out of %d", i, + vp_count); + vp_count = i; + break; + } + if (pid == 0) { + my_index = i; + my_pid = getpid(); + /* Child returns to continue in main() */ + return; + } + vp_pids[i] = pid; + } + + /* + * Parent process becomes a "watchdog" and never returns to main(). + */ + + /* Install signal handlers */ + Signal(SIGTERM, wdog_sighandler); /* terminate */ + Signal(SIGHUP, wdog_sighandler); /* restart */ + Signal(SIGUSR1, wdog_sighandler); /* dump info */ + + /* Now go to sleep waiting for a child termination or a signal */ + for ( ; ; ) { + if ((pid = wait(&status)) < 0) { + if (errno == EINTR) + continue; + err_sys_quit(errfd, "ERROR: watchdog: wait"); + } + /* Find index of the exited child */ + for (i = 0; i < vp_count; i++) { + if (vp_pids[i] == pid) + break; + } + + /* Block signals while printing and forking */ + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGHUP); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_BLOCK, &mask, &omask); + + if (WIFEXITED(status)) + err_report(errfd, "WARN: watchdog: process %d (pid %d) exited" + " with status %d", i, pid, WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + err_report(errfd, "WARN: watchdog: process %d (pid %d) terminated" + " by signal %d", i, pid, WTERMSIG(status)); + else if (WIFSTOPPED(status)) + err_report(errfd, "WARN: watchdog: process %d (pid %d) stopped" + " by signal %d", i, pid, WSTOPSIG(status)); + else + err_report(errfd, "WARN: watchdog: process %d (pid %d) terminated:" + " unknown termination reason", i, pid); + + /* Fork another VP */ + if ((pid = fork()) < 0) { + err_sys_report(errfd, "ERROR: watchdog: can't create process: fork"); + } else if (pid == 0) { + my_index = i; + my_pid = getpid(); + /* Child returns to continue in main() */ + return; + } + vp_pids[i] = pid; + + /* Restore the signal mask */ + sigprocmask(SIG_SETMASK, &omask, NULL); + } +} + + +/******************************************************************/ + +static void wdog_sighandler(int signo) +{ + int i, err; + + /* Save errno */ + err = errno; + /* Forward the signal to all children */ + for (i = 0; i < vp_count; i++) { + if (vp_pids[i] > 0) + kill(vp_pids[i], signo); + } + /* + * It is safe to do pretty much everything here because process is + * sleeping in wait() which is async-safe. + */ + switch (signo) { + case SIGHUP: + err_report(errfd, "INFO: watchdog: caught SIGHUP"); + /* Reopen log files - needed for log rotation */ + if (log_access) { + logbuf_close(); + logbuf_open(); + } + close(errfd); + if ((errfd = open(ERRORS_FILE, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0) + err_sys_quit(STDERR_FILENO, "ERROR: watchdog: open"); + break; + case SIGTERM: + /* Non-graceful termination */ + err_report(errfd, "INFO: watchdog: caught SIGTERM, terminating"); + unlink(PID_FILE); + exit(0); + case SIGUSR1: + err_report(errfd, "INFO: watchdog: caught SIGUSR1"); + break; + default: + err_report(errfd, "INFO: watchdog: caught signal %d", signo); + } + /* Restore errno */ + errno = err; +} + + +/******************************************************************/ + +static void install_sighandlers(void) +{ + sigset_t mask; + int p[2]; + + /* Create signal pipe */ + if (pipe(p) < 0) + err_sys_quit(errfd, "ERROR: process %d (pid %d): can't create" + " signal pipe: pipe", my_index, my_pid); + if ((sig_pipe[0] = st_netfd_open(p[0])) == NULL || + (sig_pipe[1] = st_netfd_open(p[1])) == NULL) + err_sys_quit(errfd, "ERROR: process %d (pid %d): can't create" + " signal pipe: st_netfd_open", my_index, my_pid); + + /* Install signal handlers */ + Signal(SIGTERM, child_sighandler); /* terminate */ + Signal(SIGHUP, child_sighandler); /* restart */ + Signal(SIGUSR1, child_sighandler); /* dump info */ + + /* Unblock signals */ + sigemptyset(&mask); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGHUP); + sigaddset(&mask, SIGUSR1); + sigprocmask(SIG_UNBLOCK, &mask, NULL); +} + + +/******************************************************************/ + +static void child_sighandler(int signo) +{ + int err, fd; + + err = errno; + fd = st_netfd_fileno(sig_pipe[1]); + + /* write() is async-safe */ + if (write(fd, &signo, sizeof(int)) != sizeof(int)) + err_sys_quit(errfd, "ERROR: process %d (pid %d): child's signal" + " handler: write", my_index, my_pid); + errno = err; +} + + +/****************************************************************** + * The "main" function of the signal processing thread. + */ + +/* ARGSUSED */ +static void *process_signals(void *arg) +{ + int signo; + + for ( ; ; ) { + /* Read the next signal from the signal pipe */ + if (st_read(sig_pipe[0], &signo, sizeof(int), + ST_UTIME_NO_TIMEOUT) != sizeof(int)) + err_sys_quit(errfd, "ERROR: process %d (pid %d): signal processor:" + " st_read", my_index, my_pid); + + switch (signo) { + case SIGHUP: + err_report(errfd, "INFO: process %d (pid %d): caught SIGHUP," + " reloading configuration", my_index, my_pid); + if (interactive_mode) { + load_configs(); + break; + } + /* Reopen log files - needed for log rotation */ + if (log_access) { + logbuf_flush(); + logbuf_close(); + logbuf_open(); + } + close(errfd); + if ((errfd = open(ERRORS_FILE, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0) + err_sys_quit(STDERR_FILENO, "ERROR: process %d (pid %d): signal" + " processor: open", my_index, my_pid); + /* Reload configuration */ + load_configs(); + break; + case SIGTERM: + /* + * Terminate ungracefully since it is generally not known how long + * it will take to gracefully complete all client sessions. + */ + err_report(errfd, "INFO: process %d (pid %d): caught SIGTERM," + " terminating", my_index, my_pid); + if (log_access) + logbuf_flush(); + exit(0); + case SIGUSR1: + err_report(errfd, "INFO: process %d (pid %d): caught SIGUSR1", + my_index, my_pid); + /* Print server info to stderr */ + dump_server_info(); + break; + default: + err_report(errfd, "INFO: process %d (pid %d): caught signal %d", + my_index, my_pid, signo); + } + } + + /* NOTREACHED */ + return NULL; +} + + +/****************************************************************** + * The "main" function of the access log flushing thread. + */ + +/* ARGSUSED */ +static void *flush_acclog_buffer(void *arg) +{ + for ( ; ; ) { + st_sleep(ACCLOG_FLUSH_INTERVAL); + logbuf_flush(); + } + + /* NOTREACHED */ + return NULL; +} + + +/******************************************************************/ + +static void start_threads(void) +{ + long i, n; + + /* Create access log flushing thread */ + if (log_access && st_thread_create(flush_acclog_buffer, NULL, 0, 0) == NULL) + err_sys_quit(errfd, "ERROR: process %d (pid %d): can't create" + " log flushing thread", my_index, my_pid); + + /* Create connections handling threads */ + for (i = 0; i < sk_count; i++) { + err_report(errfd, "INFO: process %d (pid %d): starting %d threads" + " on %s:%u", my_index, my_pid, max_wait_threads, + srv_socket[i].addr, srv_socket[i].port); + WAIT_THREADS(i) = 0; + BUSY_THREADS(i) = 0; + RQST_COUNT(i) = 0; + for (n = 0; n < max_wait_threads; n++) { + if (st_thread_create(handle_connections, (void *)i, 0, 0) != NULL) + WAIT_THREADS(i)++; + else + err_sys_report(errfd, "ERROR: process %d (pid %d): can't create" + " thread", my_index, my_pid); + } + if (WAIT_THREADS(i) == 0) + exit(1); + } +} + + +/******************************************************************/ + +static void *handle_connections(void *arg) +{ + st_netfd_t srv_nfd, cli_nfd; + struct sockaddr_in from; + int fromlen; + long i = (long) arg; + + srv_nfd = srv_socket[i].nfd; + fromlen = sizeof(from); + + while (WAIT_THREADS(i) <= max_wait_threads) { + cli_nfd = st_accept(srv_nfd, (struct sockaddr *)&from, &fromlen, + ST_UTIME_NO_TIMEOUT); + if (cli_nfd == NULL) { + err_sys_report(errfd, "ERROR: can't accept connection: st_accept"); + continue; + } + /* Save peer address, so we can retrieve it later */ + st_netfd_setspecific(cli_nfd, &from.sin_addr, NULL); + + WAIT_THREADS(i)--; + BUSY_THREADS(i)++; + if (WAIT_THREADS(i) < min_wait_threads && TOTAL_THREADS(i) < max_threads) { + /* Create another spare thread */ + if (st_thread_create(handle_connections, (void *)i, 0, 0) != NULL) + WAIT_THREADS(i)++; + else + err_sys_report(errfd, "ERROR: process %d (pid %d): can't create" + " thread", my_index, my_pid); + } + + handle_session(i, cli_nfd); + + st_netfd_close(cli_nfd); + WAIT_THREADS(i)++; + BUSY_THREADS(i)--; + } + + WAIT_THREADS(i)--; + return NULL; +} + + +/******************************************************************/ + +static void dump_server_info(void) +{ + char *buf; + int i, len; + + if ((buf = malloc(sk_count * 512)) == NULL) { + err_sys_report(errfd, "ERROR: malloc failed"); + return; + } + + len = sprintf(buf, "\n\nProcess #%d (pid %d):\n", my_index, (int)my_pid); + for (i = 0; i < sk_count; i++) { + len += sprintf(buf + len, "\nListening Socket #%d:\n" + "-------------------------\n" + "Address %s:%u\n" + "Thread limits (min/max) %d/%d\n" + "Waiting threads %d\n" + "Busy threads %d\n" + "Requests served %d\n", + i, srv_socket[i].addr, srv_socket[i].port, + max_wait_threads, max_threads, + WAIT_THREADS(i), BUSY_THREADS(i), RQST_COUNT(i)); + } + + write(STDERR_FILENO, buf, len); + free(buf); +} + + +/****************************************************************** + * Stubs + */ + +/* + * Session handling function stub. Just dumps small HTML page. + */ +void handle_session(long srv_socket_index, st_netfd_t cli_nfd) +{ + static char resp[] = "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n" + "Connection: close\r\n\r\n

It worked!

\n"; + char buf[512]; + int n = sizeof(resp) - 1; + struct in_addr *from = st_netfd_getspecific(cli_nfd); + + if (st_read(cli_nfd, buf, sizeof(buf), SEC2USEC(REQUEST_TIMEOUT)) < 0) { + err_sys_report(errfd, "WARN: can't read request from %s: st_read", + inet_ntoa(*from)); + return; + } + if (st_write(cli_nfd, resp, n, ST_UTIME_NO_TIMEOUT) != n) { + err_sys_report(errfd, "WARN: can't write response to %s: st_write", + inet_ntoa(*from)); + return; + } + + RQST_COUNT(srv_socket_index)++; +} + + +/* + * Configuration loading function stub. + */ +void load_configs(void) +{ + err_report(errfd, "INFO: process %d (pid %d): configuration loaded", + my_index, my_pid); +} + + +/* + * Buffered access logging methods. + * Note that stdio functions (fopen(3), fprintf(3), fflush(3), etc.) cannot + * be used if multiple VPs are created since these functions can flush buffer + * at any point and thus write only partial log record to disk. + * Also, it is completely safe for all threads of the same VP to write to + * the same log buffer without any mutex protection (one buffer per VP, of + * course). + */ +void logbuf_open(void) +{ + +} + + +void logbuf_flush(void) +{ + +} + + +void logbuf_close(void) +{ + +} + + +/****************************************************************** + * Small utility functions + */ + +static void Signal(int sig, void (*handler)(int)) +{ + struct sigaction sa; + + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(sig, &sa, NULL); +} + +static int cpu_count(void) +{ + int n; + +#if defined (_SC_NPROCESSORS_ONLN) + n = (int) sysconf(_SC_NPROCESSORS_ONLN); +#elif defined (_SC_NPROC_ONLN) + n = (int) sysconf(_SC_NPROC_ONLN); +#elif defined (HPUX) +#include + n = mpctl(MPC_GETNUMSPUS, 0, 0); +#else + n = -1; + errno = ENOSYS; +#endif + + return n; +} + +/******************************************************************/ + diff --git a/trunk/3rdparty/st-srs/extensions/Makefile b/trunk/3rdparty/st-srs/extensions/Makefile new file mode 100644 index 0000000000..fc6634f93f --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/Makefile @@ -0,0 +1,91 @@ +# +# Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. +# All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Silicon Graphics, Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +CC = cc + +SHELL = /bin/sh +ECHO = /bin/echo + +DEPTH = .. +BUILD = +TARGETDIR = obj + +DEFINES = +OTHER_FLAGS = +CFLAGS = + +OBJDIR = $(DEPTH)/$(TARGETDIR) +INCDIR = $(DEPTH)/$(TARGETDIR) + +LIBRESOLV = +EXTRALIBS = + +SLIBRARY = $(OBJDIR)/libstx.a +OBJS = $(OBJDIR)/dnscache.o $(OBJDIR)/dnsres.o $(OBJDIR)/lrucache.o + + +CFLAGS += -Wall -I$(INCDIR) +AR = ar +ARFLAGS = rv +RANLIB = ranlib + + +########################## +# Platform section. +# + +ifeq (LINUX, $(findstring LINUX, $(OS))) +LIBRESOLV = -lresolv +endif + +ifeq ($(OS), SOLARIS) +LIBRESOLV = -lresolv +EXTRALIBS = -lsocket -lnsl +endif + +# +# End of platform section. +########################## + + +all: $(SLIBRARY) + +$(SLIBRARY): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + $(RANLIB) $@ + +$(OBJDIR)/%.o: %.c stx.h common.h + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -rf $(OBJS) $(SLIBRARY) + +#.DEFAULT: +# @cd $(DEPTH); $(MAKE) $@ + diff --git a/trunk/3rdparty/st-srs/extensions/README b/trunk/3rdparty/st-srs/extensions/README new file mode 100644 index 0000000000..f768aa7125 --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/README @@ -0,0 +1,42 @@ +This directory contains extensions to the core State Threads Library +that were contributed by users. All files hereunder are not part of the +State Threads Library itself. They are provided as-is, without warranty +or support, and under whatever license terms their authors provided. To +contribute your own extensions, just mail them to the project +administrators or to one of the project's mailing lists; see +state-threads.sourceforge.net. Please indicate the license terms under +which the project may distribute your contribution. + +======================================================================== + +stx_fileio +---------- +Contributed by Jeff , 4 Nov 2002. + +Provides non-blocking random access file reading capability for +programs using the State Threads library. There is one public function: + +ssize_t stx_file_read(st_netfd_t fd, off_t offset, + void *buf, size_t nbytes, st_utime_t timeout); + +The implementation is not optimal in that the data is copied at least once +more than should be necessary. Its usefulness is limited to cases where +random access to a file is required and where starvation of other threads +is unacceptable. + +The particular application which motivated this implementation was a UDP +file transfer protocol. Because the OS does very little buffering of UDP +traffic it is important that UDP transmission threads are not starved for +periods of time which are long relative to the interval required to +maintain a steady send rate. + +Licensed under the same dual MPL/GPL as core State Threads. + +======================================================================== + +stx_dns +------- + +Documentation coming. + +======================================================================== diff --git a/trunk/3rdparty/st-srs/extensions/common.h b/trunk/3rdparty/st-srs/extensions/common.h new file mode 100644 index 0000000000..f6298ba09e --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/common.h @@ -0,0 +1,77 @@ +#ifndef _STX_COMMON_H_ +#define _STX_COMMON_H_ + +#include +#include + + +#define STX_BEGIN_MACRO { +#define STX_END_MACRO } + + +/***************************************** + * Circular linked list definitions + */ + +typedef struct _stx_clist { + struct _stx_clist *next; + struct _stx_clist *prev; +} stx_clist_t; + +/* Insert element "_e" into the list, before "_l" */ +#define STX_CLIST_INSERT_BEFORE(_e,_l) \ + STX_BEGIN_MACRO \ + (_e)->next = (_l); \ + (_e)->prev = (_l)->prev; \ + (_l)->prev->next = (_e); \ + (_l)->prev = (_e); \ + STX_END_MACRO + +/* Insert element "_e" into the list, after "_l" */ +#define STX_CLIST_INSERT_AFTER(_e,_l) \ + STX_BEGIN_MACRO \ + (_e)->next = (_l)->next; \ + (_e)->prev = (_l); \ + (_l)->next->prev = (_e); \ + (_l)->next = (_e); \ + STX_END_MACRO + +/* Append an element "_e" to the end of the list "_l" */ +#define STX_CLIST_APPEND_LINK(_e,_l) STX_CLIST_INSERT_BEFORE(_e,_l) + +/* Remove the element "_e" from it's circular list */ +#define STX_CLIST_REMOVE_LINK(_e) \ + STX_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + STX_END_MACRO + +/* Return the head/tail of the list */ +#define STX_CLIST_HEAD(_l) (_l)->next +#define STX_CLIST_TAIL(_l) (_l)->prev + +/* Return non-zero if the given circular list "_l" is empty, */ +/* zero if the circular list is not empty */ +#define STX_CLIST_IS_EMPTY(_l) \ + ((_l)->next == (_l)) + +/* Initialize a circular list */ +#define STX_CLIST_INIT_CLIST(_l) \ + STX_BEGIN_MACRO \ + (_l)->next = (_l); \ + (_l)->prev = (_l); \ + STX_END_MACRO + + +/***************************************** + * Useful macros + */ + +#ifndef offsetof +#define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier)) +#endif + +#define STX_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#endif /* !_STX_COMMON_H_ */ + diff --git a/trunk/3rdparty/st-srs/extensions/dnscache.c b/trunk/3rdparty/st-srs/extensions/dnscache.c new file mode 100644 index 0000000000..ac49166a14 --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/dnscache.c @@ -0,0 +1,190 @@ +#include "stx.h" +#include "common.h" + + +/***************************************** + * Basic types definitions + */ + +typedef struct _stx_dns_data { + struct in_addr *addrs; + int num_addrs; + int cur; + time_t expires; +} stx_dns_data_t; + + +#define MAX_HOST_ADDRS 1024 + +static struct in_addr addr_list[MAX_HOST_ADDRS]; + +stx_cache_t *_stx_dns_cache = NULL; + +extern int _stx_dns_ttl; +extern int _stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs, + int *num_addrs, st_utime_t timeout); + + +static unsigned long hash_hostname(const void *key) +{ + const char *name = (const char *)key; + unsigned long hash = 0; + + while (*name) + hash = (hash << 4) - hash + *name++; /* hash = hash * 15 + *name++ */ + + return hash; +} + +static void cleanup_entry(void *key, void *data) +{ + if (key) + free(key); + + if (data) { + if (((stx_dns_data_t *)data)->addrs) + free(((stx_dns_data_t *)data)->addrs); + free(data); + } +} + +static int lookup_entry(const char *host, struct in_addr *addrs, + int *num_addrs, int rotate) +{ + stx_cache_entry_t *entry; + stx_dns_data_t *data; + int n; + + entry = stx_cache_entry_lookup(_stx_dns_cache, host); + if (entry) { + data = (stx_dns_data_t *)stx_cache_entry_getdata(entry); + if (st_time() <= data->expires) { + if (*num_addrs == 1) { + if (rotate) { + *addrs = data->addrs[data->cur++]; + if (data->cur >= data->num_addrs) + data->cur = 0; + } else { + *addrs = data->addrs[0]; + } + } else { + n = STX_MIN(*num_addrs, data->num_addrs); + memcpy(addrs, data->addrs, n * sizeof(*addrs)); + *num_addrs = n; + } + + stx_cache_entry_release(_stx_dns_cache, entry); + return 1; + } + + /* + * Cache entry expired: decrement its refcount and purge it from cache. + */ + stx_cache_entry_release(_stx_dns_cache, entry); + stx_cache_entry_delete(_stx_dns_cache, entry); + } + + return 0; +} + +static void insert_entry(const char *host, struct in_addr *addrs, int count) +{ + stx_cache_entry_t *entry; + stx_dns_data_t *data; + char *key; + size_t n; + + if (_stx_dns_ttl > 0) { + key = strdup(host); + data = (stx_dns_data_t *)malloc(sizeof(stx_dns_data_t)); + n = count * sizeof(*addrs); + if (data) { + data->addrs = (struct in_addr *)malloc(n); + if (data->addrs) + memcpy(data->addrs, addrs, n); + data->num_addrs = count; + data->cur = 0; + data->expires = st_time() + _stx_dns_ttl; + } + entry = stx_cache_entry_create(key, data, strlen(host) + 1 + + sizeof(stx_dns_data_t) + n + + stx_cache_entry_sizeof()); + if (key && data && data->addrs && entry && + stx_cache_entry_insert(_stx_dns_cache, entry) == 0) { + stx_cache_entry_release(_stx_dns_cache, entry); + return; + } + + if (entry) + stx_cache_entry_delete(_stx_dns_cache, entry); + else + cleanup_entry(key, data); + } +} + + + +int _stx_dns_cache_getaddrlist(const char *hostname, struct in_addr *addrs, + int *num_addrs, st_utime_t timeout, + int rotate) +{ + char host[128]; + int n, count; + + if (!_stx_dns_cache) + return _stx_dns_getaddrlist(hostname, addrs, num_addrs, timeout); + + for (n = 0; n < sizeof(host) - 1 && hostname[n]; n++) { + host[n] = tolower(hostname[n]); + } + host[n] = '\0'; + + if (lookup_entry(host, addrs, num_addrs, rotate)) + return 0; + + count = MAX_HOST_ADDRS; + if (_stx_dns_getaddrlist(host, addr_list, &count, timeout) < 0) + return -1; + n = STX_MIN(*num_addrs, count); + memcpy(addrs, addr_list, n * sizeof(*addrs)); + *num_addrs = n; + + insert_entry(host, addr_list, count); + return 0; +} + + +int stx_dns_cache_init(size_t max_size, size_t max_bytes, size_t hash_size) +{ + _stx_dns_cache = stx_cache_create(max_size, max_bytes, hash_size, + hash_hostname, + (long (*)(const void *, const void *))strcmp, + cleanup_entry); + if (!_stx_dns_cache) + return -1; + + return 0; +} + +void stx_dns_cache_getinfo(stx_cache_info_t *info) +{ + if (_stx_dns_cache) + stx_cache_getinfo(_stx_dns_cache, info); + else + memset(info, 0, sizeof(stx_cache_info_t)); +} + +int stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs, + int *num_addrs, st_utime_t timeout) +{ + return _stx_dns_cache_getaddrlist(hostname, addrs, num_addrs, timeout, 0); +} + +int stx_dns_getaddr(const char *hostname, struct in_addr *addr, + st_utime_t timeout) +{ + int n = 1; + + return _stx_dns_cache_getaddrlist(hostname, addr, &n, timeout, 1); +} + diff --git a/trunk/3rdparty/st-srs/extensions/dnsres.c b/trunk/3rdparty/st-srs/extensions/dnsres.c new file mode 100644 index 0000000000..04a91ccafa --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/dnsres.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 1985, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Silicon Graphics, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "stx.h" + +#define MAXPACKET 1024 + +#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL) +#define NETDB_INTERNAL h_NETDB_INTERNAL +#endif + +/* New in Solaris 7 */ +#if !defined(_getshort) && defined(ns_get16) +#define _getshort(cp) ns_get16(cp) +#define _getlong(cp) ns_get32(cp) +#endif + +typedef union { + HEADER hdr; + u_char buf[MAXPACKET]; +} querybuf_t; + +int _stx_dns_ttl; + + +static int parse_answer(querybuf_t *ans, int len, struct in_addr *addrs, + int *num_addrs) +{ + char buf[MAXPACKET]; + HEADER *ahp; + u_char *cp, *eoa; + int type, n, i; + + ahp = &ans->hdr; + eoa = ans->buf + len; + cp = ans->buf + sizeof(HEADER); + h_errno = TRY_AGAIN; + _stx_dns_ttl = -1; + i = 0; + + while (ahp->qdcount > 0) { + ahp->qdcount--; + cp += dn_skipname(cp, eoa) + QFIXEDSZ; + } + while (ahp->ancount > 0 && cp < eoa && i < *num_addrs) { + ahp->ancount--; + if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0) + return -1; + cp += n; + if (cp + 4 + 4 + 2 >= eoa) + return -1; + type = _getshort(cp); + cp += 4; + if (type == T_A) + _stx_dns_ttl = _getlong(cp); + cp += 4; + n = _getshort(cp); + cp += 2; + if (type == T_A) { + if (n > sizeof(*addrs) || cp + n > eoa) + return -1; + memcpy(&addrs[i++], cp, n); + } + cp += n; + } + + *num_addrs = i; + return 0; +} + + +static int query_domain(st_netfd_t nfd, const char *name, + struct in_addr *addrs, int *num_addrs, + st_utime_t timeout) +{ + querybuf_t qbuf; + u_char *buf = qbuf.buf; + HEADER *hp = &qbuf.hdr; + int blen = sizeof(qbuf); + int i, len, id; + + for (i = 0; i < _res.nscount; i++) { + len = res_mkquery(QUERY, name, C_IN, T_A, NULL, 0, NULL, buf, blen); + if (len <= 0) { + h_errno = NO_RECOVERY; + return -1; + } + id = hp->id; + + if (st_sendto(nfd, buf, len, (struct sockaddr *)&(_res.nsaddr_list[i]), + sizeof(struct sockaddr), timeout) != len) { + h_errno = NETDB_INTERNAL; + /* EINTR means interrupt by other thread, NOT by a caught signal */ + if (errno == EINTR) + return -1; + continue; + } + + /* Wait for reply */ + do { + len = st_recvfrom(nfd, buf, blen, NULL, NULL, timeout); + if (len <= 0) + break; + } while (id != hp->id); + + if (len < HFIXEDSZ) { + h_errno = NETDB_INTERNAL; + if (len >= 0) + errno = EMSGSIZE; + else if (errno == EINTR) /* see the comment above */ + return -1; + continue; + } + + hp->ancount = ntohs(hp->ancount); + hp->qdcount = ntohs(hp->qdcount); + if ((hp->rcode != NOERROR) || (hp->ancount == 0)) { + switch (hp->rcode) { + case NXDOMAIN: + h_errno = HOST_NOT_FOUND; + break; + case SERVFAIL: + h_errno = TRY_AGAIN; + break; + case NOERROR: + h_errno = NO_DATA; + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + h_errno = NO_RECOVERY; + } + continue; + } + + if (parse_answer(&qbuf, len, addrs, num_addrs) == 0) + return 0; + } + + return -1; +} + + +#define CLOSE_AND_RETURN(ret) \ + { \ + n = errno; \ + st_netfd_close(nfd); \ + errno = n; \ + return (ret); \ + } + + +int _stx_dns_getaddrlist(const char *host, struct in_addr *addrs, + int *num_addrs, st_utime_t timeout) +{ + char name[MAXDNAME], **domain; + const char *cp; + int s, n, maxlen, dots; + int trailing_dot, tried_as_is; + st_netfd_t nfd; + + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + h_errno = NETDB_INTERNAL; + return -1; + } + if (_res.options & RES_USEVC) { + h_errno = NETDB_INTERNAL; + errno = ENOSYS; + return -1; + } + if (!host || *host == '\0') { + h_errno = HOST_NOT_FOUND; + return -1; + } + + /* Create UDP socket */ + if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + h_errno = NETDB_INTERNAL; + return -1; + } + if ((nfd = st_netfd_open_socket(s)) == NULL) { + h_errno = NETDB_INTERNAL; + n = errno; + close(s); + errno = n; + return -1; + } + + maxlen = sizeof(name) - 1; + n = 0; + dots = 0; + trailing_dot = 0; + tried_as_is = 0; + + for (cp = host; *cp && n < maxlen; cp++) { + dots += (*cp == '.'); + name[n++] = *cp; + } + if (name[n - 1] == '.') + trailing_dot = 1; + + /* + * If there are dots in the name already, let's just give it a try + * 'as is'. The threshold can be set with the "ndots" option. + */ + if (dots >= _res.ndots) { + if (query_domain(nfd, host, addrs, num_addrs, timeout) == 0) + CLOSE_AND_RETURN(0); + if (h_errno == NETDB_INTERNAL && errno == EINTR) + CLOSE_AND_RETURN(-1); + tried_as_is = 1; + } + + /* + * We do at least one level of search if + * - there is no dot and RES_DEFNAME is set, or + * - there is at least one dot, there is no trailing dot, + * and RES_DNSRCH is set. + */ + if ((!dots && (_res.options & RES_DEFNAMES)) || + (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { + name[n++] = '.'; + for (domain = _res.dnsrch; *domain; domain++) { + strncpy(name + n, *domain, maxlen - n); + if (query_domain(nfd, name, addrs, num_addrs, timeout) == 0) + CLOSE_AND_RETURN(0); + if (h_errno == NETDB_INTERNAL && errno == EINTR) + CLOSE_AND_RETURN(-1); + if (!(_res.options & RES_DNSRCH)) + break; + } + } + + /* + * If we have not already tried the name "as is", do that now. + * note that we do this regardless of how many dots were in the + * name or whether it ends with a dot. + */ + if (!tried_as_is) { + if (query_domain(nfd, host, addrs, num_addrs, timeout) == 0) + CLOSE_AND_RETURN(0); + } + + CLOSE_AND_RETURN(-1); +} + diff --git a/trunk/3rdparty/st-srs/extensions/lrucache.c b/trunk/3rdparty/st-srs/extensions/lrucache.c new file mode 100644 index 0000000000..33494fee62 --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/lrucache.c @@ -0,0 +1,343 @@ +#include "stx.h" +#include "common.h" + + +/***************************************** + * Basic types definitions + */ + +struct _stx_centry { + void *key; /* key for doing lookups */ + void *data; /* data in the cache */ + size_t weight; /* "weight" of this entry */ + struct _stx_centry *next; /* next entry */ + struct _stx_centry **pthis; + stx_clist_t lru_link; /* for putting this entry on LRU list */ + int ref_count; /* use count for this entry */ + int delete_pending; /* pending delete flag */ +}; + +struct _stx_cache { + size_t max_size; /* max size of cache */ + size_t cur_size; /* current size of cache */ + + size_t max_weight; /* cache capacity */ + size_t cur_weight; /* current total "weight" of all entries */ + + size_t hash_size; /* size of hash table */ + stx_cache_entry_t **table; /* hash table for this cache */ + + stx_clist_t lru_list; /* least-recently-used list */ + + /* Cache stats */ + unsigned long hits; /* num cache hits */ + unsigned long lookups; /* num cache lookups */ + unsigned long inserts; /* num inserts */ + unsigned long deletes; /* num deletes */ + + /* Functions */ + unsigned long (*key_hash_fn)(const void *); + long (*key_cmp_fn)(const void *, const void *); + void (*cleanup_fn)(void *, void *); +}; + + +#define STX_CACHE_ENTRY_PTR(_qp) \ + ((stx_cache_entry_t *)((char *)(_qp) - offsetof(stx_cache_entry_t, lru_link))) + + +/***************************************** + * Cache methods + */ + +stx_cache_t *stx_cache_create(size_t max_size, size_t max_weight, + size_t hash_size, + unsigned long (*key_hash_fn)(const void *key), + long (*key_cmp_fn)(const void *key1, + const void *key2), + void (*cleanup_fn)(void *key, void *data)) +{ + stx_cache_t *newcache; + + newcache = (stx_cache_t *)calloc(1, sizeof(stx_cache_t)); + if (newcache == NULL) + return NULL; + newcache->table = (stx_cache_entry_t **)calloc(hash_size, + sizeof(stx_cache_entry_t *)); + if (newcache->table == NULL) { + free(newcache); + return NULL; + } + + newcache->max_size = max_size; + newcache->max_weight = max_weight; + newcache->hash_size = hash_size; + STX_CLIST_INIT_CLIST(&(newcache->lru_list)); + newcache->key_hash_fn = key_hash_fn; + newcache->key_cmp_fn = key_cmp_fn; + newcache->cleanup_fn = cleanup_fn; + + return newcache; +} + + +void stx_cache_empty(stx_cache_t *cache) +{ + size_t i; + stx_cache_entry_t *entry, *next_entry; + + for (i = 0; i < cache->hash_size; i++) { + entry = cache->table[i]; + while (entry) { + next_entry = entry->next; + stx_cache_entry_delete(cache, entry); + entry = next_entry; + } + } +} + + +void stx_cache_traverse(stx_cache_t *cache, + void (*callback)(void *key, void *data)) +{ + size_t i; + stx_cache_entry_t *entry; + + for (i = 0; i < cache->hash_size; i++) { + for (entry = cache->table[i]; entry; entry = entry->next) { + if (!entry->delete_pending) + (*callback)(entry->key, entry->data); + } + } +} + + +void stx_cache_traverse_lru(stx_cache_t *cache, + void (*callback)(void *key, void *data), + unsigned int n) +{ + stx_clist_t *q; + stx_cache_entry_t *entry; + + for (q = STX_CLIST_HEAD(&cache->lru_list); q != &cache->lru_list && n; + q = q->next, n--) { + entry = STX_CACHE_ENTRY_PTR(q); + (*callback)(entry->key, entry->data); + } +} + + +void stx_cache_traverse_mru(stx_cache_t *cache, + void (*callback)(void *key, void *data), + unsigned int n) +{ + stx_clist_t *q; + stx_cache_entry_t *entry; + + for (q = STX_CLIST_TAIL(&cache->lru_list); q != &cache->lru_list && n; + q = q->prev, n--) { + entry = STX_CACHE_ENTRY_PTR(q); + (*callback)(entry->key, entry->data); + } +} + + +size_t stx_cache_getsize(stx_cache_t *cache) +{ + return cache->cur_size; +} + + +size_t stx_cache_getweight(stx_cache_t *cache) +{ + return cache->cur_weight; +} + + +void stx_cache_getinfo(stx_cache_t *cache, stx_cache_info_t *info) +{ + info->max_size = cache->max_size; + info->max_weight = cache->max_weight; + info->hash_size = cache->hash_size; + info->cur_size = cache->cur_size; + info->cur_weight = cache->cur_weight; + info->hits = cache->hits; + info->lookups = cache->lookups; + info->inserts = cache->inserts; + info->deletes = cache->deletes; +} + + +/***************************************** + * Cache entry methods + */ + +stx_cache_entry_t *stx_cache_entry_create(void *key, void *data, + size_t weight) +{ + stx_cache_entry_t *newentry; + + newentry = (stx_cache_entry_t *)calloc(1, sizeof(stx_cache_entry_t)); + if (newentry == NULL) + return NULL; + + newentry->key = key; + newentry->data = data; + newentry->weight = weight; + + return newentry; +} + + +void stx_cache_entry_delete(stx_cache_t *cache, stx_cache_entry_t *entry) +{ + entry->delete_pending = 1; + + if (entry->ref_count > 0) + return; + + if (entry->pthis) { + *entry->pthis = entry->next; + if (entry->next) + entry->next->pthis = entry->pthis; + + cache->cur_size--; + cache->cur_weight -= entry->weight; + cache->deletes++; + STX_CLIST_REMOVE_LINK(&(entry->lru_link)); + } + + if (cache->cleanup_fn) + cache->cleanup_fn(entry->key, entry->data); + + entry->pthis = NULL; + entry->key = NULL; + entry->data = NULL; + free(entry); +} + + +stx_cache_entry_t *stx_cache_entry_lookup(stx_cache_t *cache, const void *key) +{ + unsigned long bucket; + stx_cache_entry_t *entry; + + cache->lookups++; + bucket = cache->key_hash_fn(key) % cache->hash_size; + for (entry = cache->table[bucket]; entry; entry = entry->next) { + if (!entry->delete_pending && cache->key_cmp_fn(key, entry->key) == 0) + break; + } + if (entry) { + cache->hits++; + if (entry->ref_count == 0) + STX_CLIST_REMOVE_LINK(&(entry->lru_link)); + entry->ref_count++; + } + + return entry; +} + + +void stx_cache_entry_release(stx_cache_t *cache, stx_cache_entry_t *entry) +{ + if (entry->ref_count == 0) + return; + + entry->ref_count--; + + if (entry->ref_count == 0) { + STX_CLIST_APPEND_LINK(&(entry->lru_link), &(cache->lru_list)); + if (entry->delete_pending) + stx_cache_entry_delete(cache, entry); + } +} + + +int stx_cache_entry_insert(stx_cache_t *cache, stx_cache_entry_t *entry) +{ + stx_cache_entry_t *old_entry; + unsigned long bucket; + + /* + * If cache capacity is exceeded, try to remove LRU entries till there is + * enough room or LRU list is empty. + */ + while (cache->cur_weight + entry->weight > cache->max_weight) { + old_entry = stx_cache_entry_getlru(cache); + if (!old_entry) { + /* cache capacity is exceeded and all entries are in use */ + return -1; + } + stx_cache_entry_delete(cache, old_entry); + } + + /* If cache size is exceeded, remove LRU entry */ + if (cache->cur_size >= cache->max_size) { + old_entry = stx_cache_entry_getlru(cache); + if (!old_entry) { + /* cache size is exceeded and all entries are in use */ + return -1; + } + stx_cache_entry_delete(cache, old_entry); + } + + /* Don't add duplicate entries in the cache */ + bucket = cache->key_hash_fn(entry->key) % cache->hash_size; + for (old_entry = cache->table[bucket]; old_entry; + old_entry = old_entry->next) { + if (!old_entry->delete_pending && + cache->key_cmp_fn(entry->key, old_entry->key) == 0) + break; + } + if (old_entry) + stx_cache_entry_delete(cache, old_entry); + + /* Insert in the hash table */ + entry->next = cache->table[bucket]; + cache->table[bucket] = entry; + entry->pthis = &cache->table[bucket]; + if (entry->next) + entry->next->pthis = &entry->next; + entry->ref_count++; + + cache->inserts++; + cache->cur_size++; + cache->cur_weight += entry->weight; + + return 0; +} + + +stx_cache_entry_t *stx_cache_entry_getlru(stx_cache_t *cache) +{ + if (STX_CLIST_IS_EMPTY(&(cache->lru_list))) + return NULL; + + return STX_CACHE_ENTRY_PTR(STX_CLIST_HEAD(&(cache->lru_list))); +} + + +int stx_cache_entry_sizeof(void) +{ + return (int)sizeof(stx_cache_entry_t); +} + + +void *stx_cache_entry_getdata(stx_cache_entry_t *entry) +{ + return entry->data; +} + + +void *stx_cache_entry_getkey(stx_cache_entry_t *entry) +{ + return entry->key; +} + + +size_t stx_cache_entry_getweight(stx_cache_entry_t *entry) +{ + return entry->weight; +} + diff --git a/trunk/3rdparty/st-srs/extensions/print_stk.patch b/trunk/3rdparty/st-srs/extensions/print_stk.patch new file mode 100644 index 0000000000..f7451c7b07 --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/print_stk.patch @@ -0,0 +1,367 @@ +Michael Abd-El-Malek contributed this patch. He wrote: +---------------------------------------- +Hello, + +This is a patch that enables programmatically dumping the stack of +every thread. This has been useful in debugging deadlocks, etc... +Our usage model is that the SIGUSR2 handler calls the new +_st_print_thread_stacks function, which dumps the stack for all +threads. A convenient feature is that for thread stacks that are the +same (which is common for application with a lot of worker threads +waiting for work), only one stack trace is printed, along with a +count of how many threads have that same stack. + +I use the glibc backtrace function to get the backtrace, and then use +popen to execute addr2line and convert memory addresses to file +names, function names, and line numbers. If glibc isn't available, +_st_print_thread_stacks just prints a warning. And this feature is +only available if DEBUG is turned on. + +We've found this feature extremely helpful when debugging. + +The patch can be a bit more robust (it assumes addr2line exists). +But I didn't want to go through the hassle of doing this, if the +StateThreads community doesn't want to use this patch. (In our +environment, addr2line will always be there.) + +Cheers, +Mike +---------------------------------------- +Invoking complex functions from a signal handler is not recommended, +plus this patch changes the behavior of existing API hooks. It will +not become part of State Threads proper but you may find it useful +nonetheless. This patch applies to st-1.5.2. + +diff -Nur Makefile.1.5.2 Makefile +--- Makefile.1.5.2 Wed Sep 7 14:19:50 2005 ++++ Makefile Wed Sep 7 14:33:08 2005 +@@ -255,7 +255,8 @@ + $(TARGETDIR)/stk.o \ + $(TARGETDIR)/sync.o \ + $(TARGETDIR)/key.o \ +- $(TARGETDIR)/io.o ++ $(TARGETDIR)/io.o \ ++ $(TARGETDIR)/backtrace.o + OBJS += $(EXTRA_OBJS) + HEADER = $(TARGETDIR)/st.h + SLIBRARY = $(TARGETDIR)/libst.a +diff -Nur backtrace.c.1.5.2 backtrace.c +--- backtrace.c.1.5.2 Wed Dec 31 16:00:00 1969 ++++ backtrace.c Wed Sep 7 13:40:21 2005 +@@ -0,0 +1,211 @@ ++/* ++ * The contents of this file are subject to the Mozilla Public ++ * License Version 1.1 (the "License"); you may not use this file ++ * except in compliance with the License. You may obtain a copy of ++ * the License at http://www.mozilla.org/MPL/ ++ * ++ * Software distributed under the License is distributed on an "AS ++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ * implied. See the License for the specific language governing ++ * rights and limitations under the License. ++ * ++ * Contributor(s): Michael Abd-El-Malek (mabdelmalek@cmu.edu) ++ * Carnegie Mellon University ++ * ++ * Alternatively, the contents of this file may be used under the ++ * terms of the GNU General Public License Version 2 or later (the ++ * "GPL"), in which case the provisions of the GPL are applicable ++ * instead of those above. If you wish to allow use of your ++ * version of this file only under the terms of the GPL and not to ++ * allow others to use your version of this file under the MPL, ++ * indicate your decision by deleting the provisions above and ++ * replace them with the notice and other provisions required by ++ * the GPL. If you do not delete the provisions above, a recipient ++ * may use your version of this file under either the MPL or the ++ * GPL. ++ */ ++ ++ ++ ++/* ++ * This file contains routines for printing a stack trace of all threads. ++ * Only works when DEBUG is defined and where glibc is available, since it ++ * provides the backtrace() function. ++ */ ++ ++#define _GNU_SOURCE /* to get program_invocation_name */ ++ ++#include ++#include ++ ++ ++#if defined(DEBUG) && defined(__GLIBC__) ++ ++#include ++#include "common.h" ++#include ++#include ++#include ++ ++ ++/* The maximum number of frames to get a stack trace for. If a thread has more ++ * frames than this, then we only show the latest X frames. */ ++#define MAX_NUM_FRAMES 64 ++ ++ ++typedef struct thread_stack_s { ++ uint32_t num_frames; ++ void* addresses[MAX_NUM_FRAMES]; /* frame pointers */ ++ char* locations[MAX_NUM_FRAMES]; /* file/function/line numbers */ ++ uint32_t num_matches; ++ ++ struct thread_stack_s* next; ++} thread_stack_t; ++ ++static thread_stack_t* stacks = NULL; ++ ++ ++/* Converts the function's memory addresses to function names, file names, and ++ * line numbers. Calls binutil's addr2line program. */ ++static void get_symbol_names(thread_stack_t *stack) ++{ ++ char program_to_run[1024], function[256], filename_lineno[256], temp[19]; ++ FILE* output; ++ int num_bytes_left; ++ uint32_t i; ++ ++ /* Construct the arguments to addr2line */ ++ num_bytes_left = sizeof(program_to_run); ++ num_bytes_left -= snprintf(program_to_run, sizeof(program_to_run), ++ "addr2line -fCe %s", program_invocation_name); ++ for (i = 0; i < stack->num_frames && num_bytes_left > 0; ++i) { ++ num_bytes_left -= snprintf(temp, sizeof(temp), " %p", stack->addresses[i]); ++ strncat(program_to_run, temp, num_bytes_left); ++ } ++ ++ /* Use popen to execute addr2line and read its ouput */ ++ output = popen(program_to_run, "r"); ++ for (i = 0; i < stack->num_frames; ++i) { ++ char* function_listing = (char*) malloc(512); ++ fscanf(output, "%255s\n", function); ++ fscanf(output, "%255s\n", filename_lineno); ++ snprintf(function_listing, 512, "%s at %s", function, filename_lineno); ++ stack->locations[i] = function_listing; ++ } ++ pclose(output); ++} ++ ++ ++static void print_stack(thread_stack_t* stack) ++{ ++ int skip_offset = 0, cmp_len; ++ uint32_t i; ++ ++ /* Get the function names/filenames/line numbers */ ++ get_symbol_names(stack); ++ ++ cmp_len = strlen("_st_iterate_threads_helper"); ++ ++ /* Print the backtrace */ ++ for (i = 0; i < stack->num_frames; ++i) { ++ /* Skip frames we don't have location info for */ ++ if (!strncmp(stack->locations[i], "??", 2)) { ++ continue; ++ } ++ ++ /* Skip the frames that are used for printing the stack trace */ ++ if (skip_offset) { ++ printf("\t#%2d %s %p\n", i - skip_offset, stack->locations[i], ++ stack->addresses[i]); ++ } else if (!strncmp(stack->locations[i], "_st_iterate_threads_helper", ++ cmp_len)) { ++ skip_offset = i + 1; ++ } ++ } ++} ++ ++ ++static void add_current_thread_stack(void) ++{ ++ thread_stack_t *new_stack = malloc(sizeof(thread_stack_t)); ++ thread_stack_t *search; ++ ++ /* Call glibc function to get the backtrace */ ++ new_stack->num_frames = backtrace(new_stack->addresses, MAX_NUM_FRAMES); ++ ++ /* Check if we have another stacks that is equivalent. If so, then coaelsce ++ * two stacks into one, to minimize output to user. */ ++ search = stacks; ++ while (search) { ++ if (search->num_frames == new_stack->num_frames && ++ !memcmp(search->addresses, new_stack->addresses, ++ search->num_frames * sizeof(void*))) { ++ /* Found an existing stack that is the same as this thread's stack */ ++ ++search->num_matches; ++ free(new_stack); ++ return; ++ } else { ++ search = search->next; ++ } ++ } ++ ++ /* This is a new stack. Add it to the list of stacks. */ ++ new_stack->num_matches = 1; ++ new_stack->next = stacks; ++ stacks = new_stack; ++} ++ ++static void print_stack_frames(void) ++{ ++ while (stacks) { ++ printf("\n%u thread(s) with this backtrace:\n", stacks->num_matches); ++ print_stack(stacks); ++ stacks = stacks->next; ++ } ++ printf("\n"); ++} ++ ++static void free_stacks(void) ++{ ++ uint32_t i; ++ while (stacks) { ++ thread_stack_t *next = stacks->next; ++ for (i = 0; i < stacks->num_frames; ++i) { ++ free(stacks->locations[i]); ++ } ++ free(stacks); ++ stacks = next; ++ } ++ stacks = NULL; ++} ++ ++ ++static void st_print_thread_stack(_st_thread_t *thread, int start_flag, ++ int end_flag) ++{ ++ if (end_flag == 0) { ++ add_current_thread_stack(); ++ } else { ++ print_stack_frames(); ++ } ++} ++ ++ ++void _st_print_thread_stacks(int ignore) ++{ ++ _st_iterate_threads_flag = 1; ++ _st_iterate_threads_helper(st_print_thread_stack); ++ _st_iterate_threads_flag = 0; ++ ++ /* Deallocate memory */ ++ free_stacks(); ++} ++ ++#else /* defined(DEBUG) && defined(__GLIBC__) */ ++ ++void _st_print_thread_stacks(int ignore) ++{ ++ printf("%s: need DEBUG mode and glibc-specific functions to read stack.\n", ++ __FUNCTION__); ++} ++#endif /* defined(DEBUG) && defined(__GLIBC__) */ +diff -Nur common.h.1.5.2 common.h +--- common.h.1.5.2 Wed Sep 7 14:18:37 2005 ++++ common.h Wed Sep 7 14:35:36 2005 +@@ -371,8 +371,18 @@ + */ + + #ifdef DEBUG +-void _st_iterate_threads(void); +-#define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads() ++typedef void(*_st_func_ptr_t)(_st_thread_t *thread, ++ int start_flag, ++ int end_flag); ++/* Pointer to function that will be called on thread switch */ ++extern _st_func_ptr_t _st_iterate_func_ptr; ++extern int _st_iterate_threads_flag; ++/* Thread iteration function that will call an arbitrary function */ ++extern void _st_iterate_threads_helper(_st_func_ptr_t func); ++#define ST_DEBUG_ITERATE_THREADS() \ ++ if (_st_iterate_func_ptr) { \ ++ _st_iterate_threads_helper(_st_iterate_func_ptr); \ ++ } + #else + #define ST_DEBUG_ITERATE_THREADS() + #endif +diff -Nur public.h.1.5.2 public.h +--- public.h.1.5.2 Wed Sep 7 11:46:58 2005 ++++ public.h Wed Sep 7 13:38:46 2005 +@@ -171,8 +171,10 @@ + extern st_netfd_t st_open(const char *path, int oflags, mode_t mode); + + #ifdef DEBUG +-extern void _st_show_thread_stack(st_thread_t thread, const char *messg); ++extern void _st_show_thread_stack(st_thread_t thread, int start_flag, ++ int end_flag); + extern void _st_iterate_threads(void); ++extern void _st_print_thread_stacks(int ignore); + #endif + + #ifdef __cplusplus +diff -Nur sched.c.1.5.2 sched.c +--- sched.c.1.5.2 Wed Sep 7 10:48:05 2005 ++++ sched.c Wed Sep 7 13:38:46 2005 +@@ -919,16 +919,13 @@ + + + #ifdef DEBUG +-/* ARGSUSED */ +-void _st_show_thread_stack(_st_thread_t *thread, const char *messg) +-{ +- +-} +- + /* To be set from debugger */ + int _st_iterate_threads_flag = 0; ++/* Thread iteration function that will call an arbitrary function */ ++_st_func_ptr_t _st_iterate_func_ptr = NULL; + +-void _st_iterate_threads(void) ++/* This function iterates over all threads, calling "func" for each thread. */ ++void _st_iterate_threads_helper(_st_func_ptr_t func) + { + static _st_thread_t *thread = NULL; + static jmp_buf orig_jb, save_jb; +@@ -944,16 +941,20 @@ + + if (thread) { + memcpy(thread->context, save_jb, sizeof(jmp_buf)); +- _st_show_thread_stack(thread, NULL); ++ func(thread, 0, 0); + } else { + if (MD_SETJMP(orig_jb)) { + _st_iterate_threads_flag = 0; ++ _st_iterate_func_ptr = NULL; + thread = NULL; +- _st_show_thread_stack(thread, "Iteration completed"); ++ /* Last thread to iterate through */ ++ func(thread, 0, 1); + return; + } ++ /* First thread to iterate through */ + thread = _ST_CURRENT_THREAD(); +- _st_show_thread_stack(thread, "Iteration started"); ++ _st_iterate_func_ptr = func; ++ func(thread, 1, 0); + } + + q = thread->tlink.next; +@@ -966,5 +967,17 @@ + memcpy(save_jb, thread->context, sizeof(jmp_buf)); + MD_LONGJMP(thread->context, 1); + } ++ ++/* ARGSUSED */ ++void _st_show_thread_stack(_st_thread_t *thread, int start_flag, int end_flag) ++{ ++} ++ ++/* Iterate over threads inside debugger; see st/README */ ++void _st_iterate_threads(void) ++{ ++ _st_iterate_threads_helper(_st_show_thread_stack); ++} ++ + #endif /* DEBUG */ + diff --git a/trunk/3rdparty/st-srs/extensions/stx.h b/trunk/3rdparty/st-srs/extensions/stx.h new file mode 100644 index 0000000000..8371e0d93c --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/stx.h @@ -0,0 +1,91 @@ +#ifndef _STX_H_ +#define _STX_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "st.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************************** + * Basic types definitions + */ + +typedef struct _stx_centry stx_cache_entry_t; +typedef struct _stx_cache stx_cache_t; + +/* This is public type */ +typedef struct _stx_cache_info { + size_t max_size; + size_t max_weight; + size_t hash_size; + size_t cur_size; + size_t cur_weight; + unsigned long hits; + unsigned long lookups; + unsigned long inserts; + unsigned long deletes; +} stx_cache_info_t; + + +/***************************************** + * Cache and cache entry methods + */ + +stx_cache_t *stx_cache_create(size_t max_size, size_t max_weight, + size_t hash_size, + unsigned long (*key_hash_fn)(const void *key), + long (*key_cmp_fn)(const void *key1, + const void *key2), + void (*cleanup_fn)(void *key, void *data)); +void stx_cache_empty(stx_cache_t *cache); +void stx_cache_traverse(stx_cache_t *cache, + void (*callback)(void *key, void *data)); +void stx_cache_traverse_lru(stx_cache_t *, void (*)(void *, void *), + unsigned int); +void stx_cache_traverse_mru(stx_cache_t *, void (*)(void *, void *), + unsigned int); +void stx_cache_getinfo(stx_cache_t *cache, stx_cache_info_t *info); +size_t stx_cache_getsize(stx_cache_t *cache); +size_t stx_cache_getweight(stx_cache_t *cache); + + +stx_cache_entry_t *stx_cache_entry_create(void *key, void *data, + size_t weight); +void stx_cache_entry_delete(stx_cache_t *cache, stx_cache_entry_t *entry); +stx_cache_entry_t *stx_cache_entry_lookup(stx_cache_t *cache, const void *key); +void stx_cache_entry_release(stx_cache_t *, stx_cache_entry_t *); +int stx_cache_entry_insert(stx_cache_t *cache, stx_cache_entry_t *entry); +stx_cache_entry_t *stx_cache_entry_getlru(stx_cache_t *cache); +int stx_cache_entry_sizeof(void); +void *stx_cache_entry_getdata(stx_cache_entry_t *entry); +void *stx_cache_entry_getkey(stx_cache_entry_t *entry); +size_t stx_cache_entry_getweight(stx_cache_entry_t *entry); + + +int stx_dns_cache_init(size_t max_size, size_t max_bytes, size_t hash_size); +void stx_dns_cache_getinfo(stx_cache_info_t *info); +int stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs, + int *num_addrs, st_utime_t timeout); +int stx_dns_getaddr(const char *hostname, struct in_addr *addr, + st_utime_t timeout); + +#ifdef __cplusplus +} +#endif + +#endif /* !_STX_H_ */ + diff --git a/trunk/3rdparty/st-srs/extensions/stx_fileio.c b/trunk/3rdparty/st-srs/extensions/stx_fileio.c new file mode 100644 index 0000000000..cb24346e8a --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/stx_fileio.c @@ -0,0 +1,197 @@ +/* + * File I/O extension to the State Threads Library. + */ + +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the file I/O extension to the State Threads Library. + * + * The Initial Developer of the Original Code is Jeff + * . Portions created by the Initial + * Developer are Copyright (C) 2002 the Initial Developer. All Rights + * Reserved. + * + * Contributor(s): (none) + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include + +#include "stx_fileio.h" + +#define STX_FILEIO_SIGNUM SIGUSR2 + +typedef struct { + st_netfd_t data_fd; + st_netfd_t control_fd; + pid_t pid; +} fileio_data_t; + +#define FILEREADER_MAX_READ 1024 + +typedef struct { + off_t offset; + ssize_t nbytes; +} file_reader_cb_t; + +/** + * Fork a process to read a file and return its pid. Receives + * offset/length commands from control stream and sends corresponding data + * to out stream. A zero length on the control stream signals an end. + * + * @param fd stream from which to read + * @param control_out receives the file descriptor to which control commands can be sent + * @param fd_out receives the file descriptor from which the output of the command can be read. + * @return PID of the process created to execute the command + */ +pid_t +file_reader(int fd, int *fd_control, int *fd_out) +{ + pid_t pid; + int control_pipe[2], out_pipe[2]; + + if (pipe(control_pipe) < 0 || pipe(out_pipe) < 0) + return (pid_t)-1; + + pid = fork(); + if (pid == (pid_t) -1) + { + close(control_pipe[0]); + close(control_pipe[1]); + close(out_pipe[0]); + close(out_pipe[1]); + return pid; + } + else if (pid == (pid_t) 0) + { + // child + off_t pos = 0; + file_reader_cb_t cb; + char buf[FILEREADER_MAX_READ]; + if (fd == -1) + _exit(EXIT_FAILURE); + + while (sizeof(cb) == read(control_pipe[0], &cb, sizeof(cb))) { + ssize_t nb; + if (0 >= cb.nbytes) + goto clean_exit; + if (pos != cb.offset) { + pos = lseek(fd, cb.offset, SEEK_SET); + if (pos == (off_t)-1) + break; + } + nb = read(fd, buf, cb.nbytes); + if (nb == (ssize_t)-1) + break; + pos += nb; + write(out_pipe[1], (char *)&nb, sizeof(nb)); + write(out_pipe[1], buf, nb); + } + perror("ERROR: file_reader: "); + clean_exit: + close(control_pipe[0]); + close(control_pipe[1]); + close(out_pipe[0]); + close(out_pipe[1]); + _exit(EXIT_SUCCESS); + } + + // parent + close(out_pipe[1]); + close(control_pipe[0]); + *fd_out = out_pipe[0]; + *fd_control = control_pipe[1]; + return pid; +} + +/** + * fileio_data_t destructor callback + */ +static void +fileio_data_destructor(void *dat_in) +{ + if (dat_in) { + fileio_data_t *dat = (fileio_data_t *)dat_in; + file_reader_cb_t cb; + cb.offset = 0; + cb.nbytes = 0; + st_write(dat->control_fd, (char *)&cb, sizeof(cb), + ST_UTIME_NO_TIMEOUT); + waitpid(dat->pid, NULL, 0); + st_netfd_close(dat->control_fd); + st_netfd_close(dat->data_fd); + free(dat_in); + } +} + +/** + * Retrieve fileio_data_t struct from an st descriptor. Create and store + * a new one if needed. + */ +static fileio_data_t *get_fileio_data(st_netfd_t fd) +{ + fileio_data_t *dat = (fileio_data_t *)st_netfd_getspecific(fd); + if (!dat) { + int fd_control, fd_out; + pid_t pid = file_reader(st_netfd_fileno(fd), &fd_control, &fd_out); + if (pid != (pid_t)-1) { + dat = (fileio_data_t *)calloc(1, sizeof(fileio_data_t)); + dat->control_fd = st_netfd_open(fd_control); + dat->data_fd = st_netfd_open(fd_out); + dat->pid = pid; + st_netfd_setspecific(fd, dat, fileio_data_destructor); + } + } + return dat; +} + +/** + * Read data from the specified section of a file. Uses a forked + * file_reader process to do the actual reading so as to avoid causing all + * State Threads to block. + * + * @param fd must refer to a seekable file. + * @param offset absolute offset within the file + * @param buf output buffer + * @param nbytes size of the output buffer + * @param timeout + */ +ssize_t +stx_file_read(st_netfd_t fd, off_t offset, void *buf, size_t nbytes, st_utime_t timeout) +{ + fileio_data_t *dat = get_fileio_data(fd); + if (dat) { + file_reader_cb_t cb; + ssize_t ret = (ssize_t)-1; + cb.offset = offset; + cb.nbytes = nbytes; + st_write(dat->control_fd, (char *)&cb, sizeof(cb), timeout); + if (sizeof(ret) == st_read(dat->data_fd, (char *)&ret, sizeof(ret), timeout) && 0 < ret && ret <= nbytes) { + return st_read(dat->data_fd, buf, ret, timeout); + } else { + return ret; + } + } + + return (ssize_t)-1; +} diff --git a/trunk/3rdparty/st-srs/extensions/stx_fileio.h b/trunk/3rdparty/st-srs/extensions/stx_fileio.h new file mode 100644 index 0000000000..b6bec190b7 --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/stx_fileio.h @@ -0,0 +1,52 @@ +/* + * File I/O extension to the State Threads Library. + */ + +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the file I/O extension to the State Threads Library. + * + * The Initial Developer of the Original Code is Jeff + * . Portions created by the Initial + * Developer are Copyright (C) 2002 the Initial Developer. All Rights + * Reserved. + * + * Contributor(s): (none) + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef __STX_FILEIO_H__ +#define __STX_FILEIO_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern ssize_t stx_file_read(st_netfd_t fd, off_t offset, void *buf, size_t nbytes, st_utime_t timeout); + +#ifdef __cplusplus +} +#endif +#endif /* !__STX_FILEIO_H__ */ diff --git a/trunk/3rdparty/st-srs/extensions/testdns.c b/trunk/3rdparty/st-srs/extensions/testdns.c new file mode 100644 index 0000000000..aa896b25e5 --- /dev/null +++ b/trunk/3rdparty/st-srs/extensions/testdns.c @@ -0,0 +1,112 @@ +#include "stx.h" +#include +#include + + +#define MAX_ADDRS 128 +#define TIMEOUT (4*1000000LL) + +static void do_resolve(const char *host) +{ + struct in_addr addrs[MAX_ADDRS]; + int i, n = MAX_ADDRS; + + if (stx_dns_getaddrlist(host, addrs, &n, TIMEOUT) < 0) { + fprintf(stderr, "stx_dns_getaddrlist: can't resolve %s: ", host); + if (h_errno == NETDB_INTERNAL) + perror(""); + else + herror(""); + } else { + if (n > 0) + printf("%-40s %s\n", (char *)host, inet_ntoa(addrs[0])); + for (i = 1; i < n; i++) + printf("%-40s %s\n", "", inet_ntoa(addrs[i])); + } +} + +static void show_info(void) +{ + stx_cache_info_t info; + + stx_dns_cache_getinfo(&info); + printf("DNS cache info:\n\n"); + printf("max_size: %8d\n", (int)info.max_size); + printf("capacity: %8d bytes\n", (int)info.max_weight); + printf("hash_size: %8d\n", (int)info.hash_size); + printf("cur_size: %8d\n" + "cur_mem: %8d bytes\n" + "hits: %8d\n" + "lookups: %8d\n" + "inserts: %8d\n" + "deletes: %8d\n", + (int)info.cur_size, (int)info.cur_weight, (int)info.hits, + (int)info.lookups, (int)info.inserts, (int)info.deletes); +} + +extern stx_cache_t *_stx_dns_cache; + +static void printhost(void *host, void *data) +{ + printf("%s\n", (char *)host); +} + +static void show_lru(void) +{ + printf("LRU hosts:\n\n"); + stx_cache_traverse_lru(_stx_dns_cache, printhost, 10); +} + +static void show_mru(void) +{ + printf("MRU hosts:\n\n"); + stx_cache_traverse_mru(_stx_dns_cache, printhost, 10); +} + +static void flush_cache(void) +{ + stx_cache_empty(_stx_dns_cache); + printf("DNS cache is empty\n"); +} + + +int main() +{ + char line[256]; + char str[sizeof(line)]; + + st_init(); + stx_dns_cache_init(100, 10000, 101); + + for ( ; ; ) { + fputs("> ", stdout); + fflush(stdout); + if (!fgets(line, sizeof(line), stdin)) + break; + if (sscanf(line, "%s", str) != 1) + continue; + if (strcmp(str, "exit") == 0 || strcmp(str, "quit") == 0) + break; + if (strcmp(str, "info") == 0) { + show_info(); + continue; + } + if (strcmp(str, "lru") == 0) { + show_lru(); + continue; + } + if (strcmp(str, "mru") == 0) { + show_mru(); + continue; + } + if (strcmp(str, "flush") == 0) { + flush_cache(); + continue; + } + + do_resolve(str); + } + + return 0; +} + diff --git a/trunk/3rdparty/st-srs/io.c b/trunk/3rdparty/st-srs/io.c new file mode 100644 index 0000000000..912de0b286 --- /dev/null +++ b/trunk/3rdparty/st-srs/io.c @@ -0,0 +1,769 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + + +#if EAGAIN != EWOULDBLOCK + #define _IO_NOT_READY_ERROR ((errno == EAGAIN) || (errno == EWOULDBLOCK)) +#else + #define _IO_NOT_READY_ERROR (errno == EAGAIN) +#endif + +#define _LOCAL_MAXIOV 16 + +/* File descriptor object free list */ +static _st_netfd_t *_st_netfd_freelist = NULL; +/* Maximum number of file descriptors that the process can open */ +static int _st_osfd_limit = -1; + +static void _st_netfd_free_aux_data(_st_netfd_t *fd); + +int _st_io_init(void) +{ + struct sigaction sigact; + struct rlimit rlim; + int fdlim; + + /* Ignore SIGPIPE */ + sigact.sa_handler = SIG_IGN; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + if (sigaction(SIGPIPE, &sigact, NULL) < 0) + return -1; + + /* Set maximum number of open file descriptors */ + if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) + return -1; + + fdlim = (*_st_eventsys->fd_getlimit)(); + if (fdlim > 0 && rlim.rlim_max > (rlim_t) fdlim) { + rlim.rlim_max = fdlim; + } + + /** + * by SRS, for osx. + * when rlimit max is negative, for example, osx, use cur directly. + * @see https://github.com/winlinvip/simple-rtmp-server/issues/336 + */ + if ((int)rlim.rlim_max < 0) { + _st_osfd_limit = (int)(fdlim > 0? fdlim : rlim.rlim_cur); + return 0; + } + + rlim.rlim_cur = rlim.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) + return -1; + _st_osfd_limit = (int) rlim.rlim_max; + + return 0; +} + + +int st_getfdlimit(void) +{ + return _st_osfd_limit; +} + + +void st_netfd_free(_st_netfd_t *fd) +{ + if (!fd->inuse) + return; + + fd->inuse = 0; + if (fd->aux_data) + _st_netfd_free_aux_data(fd); + if (fd->private_data && fd->destructor) + (*(fd->destructor))(fd->private_data); + fd->private_data = NULL; + fd->destructor = NULL; + fd->next = _st_netfd_freelist; + _st_netfd_freelist = fd; +} + + +static _st_netfd_t *_st_netfd_new(int osfd, int nonblock, int is_socket) +{ + _st_netfd_t *fd; + int flags = 1; + + if ((*_st_eventsys->fd_new)(osfd) < 0) + return NULL; + + if (_st_netfd_freelist) { + fd = _st_netfd_freelist; + _st_netfd_freelist = _st_netfd_freelist->next; + } else { + fd = calloc(1, sizeof(_st_netfd_t)); + if (!fd) + return NULL; + } + + fd->osfd = osfd; + fd->inuse = 1; + fd->next = NULL; + + if (nonblock) { + /* Use just one system call */ + if (is_socket && ioctl(osfd, FIONBIO, &flags) != -1) + return fd; + /* Do it the Posix way */ + if ((flags = fcntl(osfd, F_GETFL, 0)) < 0 || + fcntl(osfd, F_SETFL, flags | O_NONBLOCK) < 0) { + st_netfd_free(fd); + return NULL; + } + } + + return fd; +} + + +_st_netfd_t *st_netfd_open(int osfd) +{ + return _st_netfd_new(osfd, 1, 0); +} + + +_st_netfd_t *st_netfd_open_socket(int osfd) +{ + return _st_netfd_new(osfd, 1, 1); +} + + +int st_netfd_close(_st_netfd_t *fd) +{ + if ((*_st_eventsys->fd_close)(fd->osfd) < 0) + return -1; + + st_netfd_free(fd); + return close(fd->osfd); +} + + +int st_netfd_fileno(_st_netfd_t *fd) +{ + return (fd->osfd); +} + + +void st_netfd_setspecific(_st_netfd_t *fd, void *value, _st_destructor_t destructor) +{ + if (value != fd->private_data) { + /* Free up previously set non-NULL data value */ + if (fd->private_data && fd->destructor) + (*(fd->destructor))(fd->private_data); + } + fd->private_data = value; + fd->destructor = destructor; +} + + +void *st_netfd_getspecific(_st_netfd_t *fd) +{ + return (fd->private_data); +} + + +/* + * Wait for I/O on a single descriptor. + */ +int st_netfd_poll(_st_netfd_t *fd, int how, st_utime_t timeout) +{ + struct pollfd pd; + int n; + + pd.fd = fd->osfd; + pd.events = (short) how; + pd.revents = 0; + + if ((n = st_poll(&pd, 1, timeout)) < 0) + return -1; + if (n == 0) { + /* Timed out */ + errno = ETIME; + return -1; + } + if (pd.revents & POLLNVAL) { + errno = EBADF; + return -1; + } + + return 0; +} + + +#ifdef MD_ALWAYS_UNSERIALIZED_ACCEPT +/* No-op */ +int st_netfd_serialize_accept(_st_netfd_t *fd) +{ + fd->aux_data = NULL; + return 0; +} + +/* No-op */ +static void _st_netfd_free_aux_data(_st_netfd_t *fd) +{ + fd->aux_data = NULL; +} + +_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout) +{ + int osfd, err; + _st_netfd_t *newfd; + + while ((osfd = accept(fd->osfd, addr, (socklen_t *)addrlen)) < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + return NULL; + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) + return NULL; + } + + /* On some platforms the new socket created by accept() inherits */ + /* the nonblocking attribute of the listening socket */ +#if defined (MD_ACCEPT_NB_INHERITED) + newfd = _st_netfd_new(osfd, 0, 1); +#elif defined (MD_ACCEPT_NB_NOT_INHERITED) + newfd = _st_netfd_new(osfd, 1, 1); +#else + #error Unknown OS +#endif + + if (!newfd) { + err = errno; + close(osfd); + errno = err; + } + + return newfd; +} + +#else /* MD_ALWAYS_UNSERIALIZED_ACCEPT */ +/* + * On some platforms accept() calls from different processes + * on the same listen socket must be serialized. + * The following code serializes accept()'s without process blocking. + * A pipe is used as an inter-process semaphore. + */ +int st_netfd_serialize_accept(_st_netfd_t *fd) +{ + _st_netfd_t **p; + int osfd[2], err; + + if (fd->aux_data) { + errno = EINVAL; + return -1; + } + if ((p = (_st_netfd_t **)calloc(2, sizeof(_st_netfd_t *))) == NULL) + return -1; + if (pipe(osfd) < 0) { + free(p); + return -1; + } + if ((p[0] = st_netfd_open(osfd[0])) != NULL && (p[1] = st_netfd_open(osfd[1])) != NULL && write(osfd[1], " ", 1) == 1) { + fd->aux_data = p; + return 0; + } + /* Error */ + err = errno; + if (p[0]) + st_netfd_free(p[0]); + if (p[1]) + st_netfd_free(p[1]); + close(osfd[0]); + close(osfd[1]); + free(p); + errno = err; + + return -1; +} + +static void _st_netfd_free_aux_data(_st_netfd_t *fd) +{ + _st_netfd_t **p = (_st_netfd_t **) fd->aux_data; + + st_netfd_close(p[0]); + st_netfd_close(p[1]); + free(p); + fd->aux_data = NULL; +} + +_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout) +{ + int osfd, err; + _st_netfd_t *newfd; + _st_netfd_t **p = (_st_netfd_t **) fd->aux_data; + ssize_t n; + char c; + + for ( ; ; ) { + if (p == NULL) { + osfd = accept(fd->osfd, addr, (socklen_t *)addrlen); + } else { + /* Get the lock */ + n = st_read(p[0], &c, 1, timeout); + if (n < 0) + return NULL; + ST_ASSERT(n == 1); + /* Got the lock */ + osfd = accept(fd->osfd, addr, (socklen_t *)addrlen); + /* Unlock */ + err = errno; + n = st_write(p[1], &c, 1, timeout); + ST_ASSERT(n == 1); + errno = err; + } + if (osfd >= 0) + break; + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + return NULL; + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) + return NULL; + } + + /* On some platforms the new socket created by accept() inherits */ + /* the nonblocking attribute of the listening socket */ +#if defined (MD_ACCEPT_NB_INHERITED) + newfd = _st_netfd_new(osfd, 0, 1); +#elif defined (MD_ACCEPT_NB_NOT_INHERITED) + newfd = _st_netfd_new(osfd, 1, 1); +#else +#error Unknown OS +#endif + + if (!newfd) { + err = errno; + close(osfd); + errno = err; + } + + return newfd; +} +#endif /* MD_ALWAYS_UNSERIALIZED_ACCEPT */ + + +int st_connect(_st_netfd_t *fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout) +{ + int n, err = 0; + + while (connect(fd->osfd, addr, addrlen) < 0) { + if (errno != EINTR) { + /* + * On some platforms, if connect() is interrupted (errno == EINTR) + * after the kernel binds the socket, a subsequent connect() + * attempt will fail with errno == EADDRINUSE. Ignore EADDRINUSE + * iff connect() was previously interrupted. See Rich Stevens' + * "UNIX Network Programming," Vol. 1, 2nd edition, p. 413 + * ("Interrupted connect"). + */ + if (errno != EINPROGRESS && (errno != EADDRINUSE || err == 0)) + return -1; + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) + return -1; + /* Try to find out whether the connection setup succeeded or failed */ + n = sizeof(int); + if (getsockopt(fd->osfd, SOL_SOCKET, SO_ERROR, (char *)&err, (socklen_t *)&n) < 0) + return -1; + if (err) { + errno = err; + return -1; + } + break; + } + err = 1; + } + + return 0; +} + + +ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout) +{ + ssize_t n; + + while ((n = read(fd->osfd, buf, nbyte)) < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + return -1; + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) + return -1; + } + + return n; +} + + +int st_read_resid(_st_netfd_t *fd, void *buf, size_t *resid, st_utime_t timeout) +{ + struct iovec iov, *riov; + int riov_size, rv; + + iov.iov_base = buf; + iov.iov_len = *resid; + riov = &iov; + riov_size = 1; + rv = st_readv_resid(fd, &riov, &riov_size, timeout); + *resid = iov.iov_len; + return rv; +} + + +ssize_t st_readv(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout) +{ + ssize_t n; + + while ((n = readv(fd->osfd, iov, iov_size)) < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + return -1; + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) + return -1; + } + + return n; +} + +int st_readv_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout) +{ + ssize_t n; + + while (*iov_size > 0) { + if (*iov_size == 1) + n = read(fd->osfd, (*iov)->iov_base, (*iov)->iov_len); + else + n = readv(fd->osfd, *iov, *iov_size); + if (n < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + return -1; + } else if (n == 0) + break; + else { + while ((size_t) n >= (*iov)->iov_len) { + n -= (*iov)->iov_len; + (*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len; + (*iov)->iov_len = 0; + (*iov)++; + (*iov_size)--; + if (n == 0) + break; + } + if (*iov_size == 0) + break; + (*iov)->iov_base = (char *) (*iov)->iov_base + n; + (*iov)->iov_len -= n; + } + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) + return -1; + } + + return 0; +} + + +ssize_t st_read_fully(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout) +{ + size_t resid = nbyte; + return st_read_resid(fd, buf, &resid, timeout) == 0 ? + (ssize_t) (nbyte - resid) : -1; +} + + +int st_write_resid(_st_netfd_t *fd, const void *buf, size_t *resid, st_utime_t timeout) +{ + struct iovec iov, *riov; + int riov_size, rv; + + iov.iov_base = (void *) buf; /* we promise not to modify buf */ + iov.iov_len = *resid; + riov = &iov; + riov_size = 1; + rv = st_writev_resid(fd, &riov, &riov_size, timeout); + *resid = iov.iov_len; + return rv; +} + + +ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout) +{ + size_t resid = nbyte; + return st_write_resid(fd, buf, &resid, timeout) == 0 ? + (ssize_t) (nbyte - resid) : -1; +} + + +ssize_t st_writev(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout) +{ + ssize_t n, rv; + size_t nleft, nbyte; + int index, iov_cnt; + struct iovec *tmp_iov; + struct iovec local_iov[_LOCAL_MAXIOV]; + + /* Calculate the total number of bytes to be sent */ + nbyte = 0; + for (index = 0; index < iov_size; index++) + nbyte += iov[index].iov_len; + + rv = (ssize_t)nbyte; + nleft = nbyte; + tmp_iov = (struct iovec *) iov; /* we promise not to modify iov */ + iov_cnt = iov_size; + + while (nleft > 0) { + if (iov_cnt == 1) { + if (st_write(fd, tmp_iov[0].iov_base, nleft, timeout) != (ssize_t) nleft) + rv = -1; + break; + } + if ((n = writev(fd->osfd, tmp_iov, iov_cnt)) < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) { + rv = -1; + break; + } + } else { + if ((size_t) n == nleft) + break; + nleft -= n; + /* Find the next unwritten vector */ + n = (ssize_t)(nbyte - nleft); + for (index = 0; (size_t) n >= iov[index].iov_len; index++) + n -= iov[index].iov_len; + + if (tmp_iov == iov) { + /* Must copy iov's around */ + if (iov_size - index <= _LOCAL_MAXIOV) { + tmp_iov = local_iov; + } else { + tmp_iov = calloc(1, (iov_size - index) * sizeof(struct iovec)); + if (tmp_iov == NULL) + return -1; + } + } + + /* Fill in the first partial read */ + tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[n]); + tmp_iov[0].iov_len = iov[index].iov_len - n; + index++; + /* Copy the remaining vectors */ + for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) { + tmp_iov[iov_cnt].iov_base = iov[index].iov_base; + tmp_iov[iov_cnt].iov_len = iov[index].iov_len; + } + } + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { + rv = -1; + break; + } + } + + if (tmp_iov != iov && tmp_iov != local_iov) + free(tmp_iov); + + return rv; +} + + +int st_writev_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout) +{ + ssize_t n; + + while (*iov_size > 0) { + if (*iov_size == 1) + n = write(fd->osfd, (*iov)->iov_base, (*iov)->iov_len); + else + n = writev(fd->osfd, *iov, *iov_size); + if (n < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + return -1; + } else { + while ((size_t) n >= (*iov)->iov_len) { + n -= (*iov)->iov_len; + (*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len; + (*iov)->iov_len = 0; + (*iov)++; + (*iov_size)--; + if (n == 0) + break; + } + if (*iov_size == 0) + break; + (*iov)->iov_base = (char *) (*iov)->iov_base + n; + (*iov)->iov_len -= n; + } + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) + return -1; + } + + return 0; +} + + +/* + * Simple I/O functions for UDP. + */ +int st_recvfrom(_st_netfd_t *fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout) +{ + int n; + + while ((n = recvfrom(fd->osfd, buf, len, 0, from, (socklen_t *)fromlen)) < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + return -1; + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) + return -1; + } + + return n; +} + + +int st_sendto(_st_netfd_t *fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout) +{ + int n; + + while ((n = sendto(fd->osfd, msg, len, 0, to, tolen)) < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + return -1; + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) + return -1; + } + + return n; +} + + +int st_recvmsg(_st_netfd_t *fd, struct msghdr *msg, int flags, st_utime_t timeout) +{ + int n; + + while ((n = recvmsg(fd->osfd, msg, flags)) < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + return -1; + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) + return -1; + } + + return n; +} + + +int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags, st_utime_t timeout) +{ + int n; + + while ((n = sendmsg(fd->osfd, msg, flags)) < 0) { + if (errno == EINTR) + continue; + if (!_IO_NOT_READY_ERROR) + return -1; + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) + return -1; + } + + return n; +} + + + +/* + * To open FIFOs or other special files. + */ +_st_netfd_t *st_open(const char *path, int oflags, mode_t mode) +{ + int osfd, err; + _st_netfd_t *newfd; + + while ((osfd = open(path, oflags | O_NONBLOCK, mode)) < 0) { + if (errno != EINTR) + return NULL; + } + + newfd = _st_netfd_new(osfd, 0, 0); + if (!newfd) { + err = errno; + close(osfd); + errno = err; + } + + return newfd; +} + diff --git a/trunk/3rdparty/st-srs/key.c b/trunk/3rdparty/st-srs/key.c new file mode 100644 index 0000000000..5e64022c04 --- /dev/null +++ b/trunk/3rdparty/st-srs/key.c @@ -0,0 +1,121 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#include +#include +#include "common.h" + + +/* + * Destructor table for per-thread private data + */ +static _st_destructor_t _st_destructors[ST_KEYS_MAX]; +static int key_max = 0; + + +/* + * Return a key to be used for thread specific data + */ +int st_key_create(int *keyp, _st_destructor_t destructor) +{ + if (key_max >= ST_KEYS_MAX) { + errno = EAGAIN; + return -1; + } + + *keyp = key_max++; + _st_destructors[*keyp] = destructor; + + return 0; +} + + +int st_key_getlimit(void) +{ + return ST_KEYS_MAX; +} + + +int st_thread_setspecific(int key, void *value) +{ + _st_thread_t *me = _ST_CURRENT_THREAD(); + + if (key < 0 || key >= key_max) { + errno = EINVAL; + return -1; + } + + if (value != me->private_data[key]) { + /* free up previously set non-NULL data value */ + if (me->private_data[key] && _st_destructors[key]) { + (*_st_destructors[key])(me->private_data[key]); + } + me->private_data[key] = value; + } + + return 0; +} + + +void *st_thread_getspecific(int key) +{ + if (key < 0 || key >= key_max) + return NULL; + + return ((_ST_CURRENT_THREAD())->private_data[key]); +} + + +/* + * Free up all per-thread private data + */ +void _st_thread_cleanup(_st_thread_t *thread) +{ + int key; + + for (key = 0; key < key_max; key++) { + if (thread->private_data[key] && _st_destructors[key]) { + (*_st_destructors[key])(thread->private_data[key]); + thread->private_data[key] = NULL; + } + } +} + diff --git a/trunk/3rdparty/st-srs/libst.def b/trunk/3rdparty/st-srs/libst.def new file mode 100644 index 0000000000..6eaf149a97 --- /dev/null +++ b/trunk/3rdparty/st-srs/libst.def @@ -0,0 +1,51 @@ +EXPORTS + st_accept @62 + st_cond_broadcast @63 + st_cond_destroy @64 + st_cond_new @65 + st_cond_signal @66 + st_cond_timedwait @67 + st_cond_wait @68 + st_connect @69 + st_getfdlimit @70 + st_init @71 + st_key_create @72 + st_key_getlimit @73 + st_mutex_destroy @74 + st_mutex_lock @75 + st_mutex_new @76 + st_mutex_trylock @77 + st_mutex_unlock @78 + st_netfd_close @79 + st_netfd_fileno @80 + st_netfd_free @81 + st_netfd_getspecific @82 + st_netfd_open @83 + st_netfd_open_socket @84 + st_netfd_poll @85 + st_netfd_serialize_accept @86 + st_netfd_setspecific @87 + st_open @88 + st_poll @89 + st_randomize_stacks @90 + st_read @91 + st_read_fully @92 + st_read_resid @93 + st_recvfrom @94 + st_sendto @95 + st_sleep @96 + st_thread_create @97 + st_thread_exit @98 + st_thread_getspecific @99 + st_thread_interrupt @100 + st_thread_join @101 + st_thread_self @102 + st_thread_setspecific @103 + st_time @104 + st_timecache_set @105 + st_usleep @106 + st_utime @107 + st_utime_last_clock @108 + st_write @109 + st_write_resid @110 + st_writev @111 diff --git a/trunk/3rdparty/st-srs/md.S b/trunk/3rdparty/st-srs/md.S new file mode 100644 index 0000000000..2ef9c41f75 --- /dev/null +++ b/trunk/3rdparty/st-srs/md.S @@ -0,0 +1,644 @@ + +/* If user disable the ASM, such as avoiding bugs in ASM, donot compile it. */ +#if !defined(MD_ST_NO_ASM) + +/* + * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. + * All Rights Reserved. + */ + +#if defined(__ia64__) + + /****************************************************************/ + + /* + * The internal __jmp_buf layout is different from one used + * by setjmp()/longjmp(). + * + * Offset Description + * ------ ----------- + * 0x000 stack pointer (r12) + * 0x008 gp (r1) + * 0x010 caller's unat + * 0x018 fpsr + * 0x020 r4 + * 0x028 r5 + * 0x030 r6 + * 0x038 r7 + * 0x040 rp (b0) + * 0x048 b1 + * 0x050 b2 + * 0x058 b3 + * 0x060 b4 + * 0x068 b5 + * 0x070 ar.pfs + * 0x078 ar.lc + * 0x080 pr + * 0x088 ar.bsp + * 0x090 ar.unat + * 0x098 &__jmp_buf + * 0x0a0 ar.rsc + * 0x0a8 ar.rnat + * 0x0b0 f2 + * 0x0c0 f3 + * 0x0d0 f4 + * 0x0e0 f5 + * 0x0f0 f16 + * 0x100 f17 + * 0x110 f18 + * 0x120 f19 + * 0x130 f20 + * 0x130 f21 + * 0x140 f22 + * 0x150 f23 + * 0x160 f24 + * 0x170 f25 + * 0x180 f26 + * 0x190 f27 + * 0x1a0 f28 + * 0x1b0 f29 + * 0x1c0 f30 + * 0x1d0 f31 + * + * Note that the address of __jmp_buf is saved but not used: we assume + * that the jmp_buf data structure is never moved around in memory. + */ + + /* + * Implemented according to "IA-64 Software Conventions and Runtime + * Architecture Guide", Chapter 10: "Context Management". + */ + + .text + .psr abi64 + .psr lsb + .lsb + + /* _st_md_cxt_save(__jmp_buf env) */ + .align 32 + .global _st_md_cxt_save + .proc _st_md_cxt_save + _st_md_cxt_save: + alloc r14 = ar.pfs,1,0,0,0 + mov r16 = ar.unat + ;; + mov r17 = ar.fpsr + mov r2 = in0 + add r3 = 8,in0 + ;; + st8.spill.nta [r2] = sp,16 // r12 (sp) + ;; + st8.spill.nta [r3] = gp,16 // r1 (gp) + ;; + st8.nta [r2] = r16,16 // save caller's unat + st8.nta [r3] = r17,16 // save fpsr + add r8 = 0xb0,in0 + ;; + st8.spill.nta [r2] = r4,16 // r4 + ;; + st8.spill.nta [r3] = r5,16 // r5 + add r9 = 0xc0,in0 + ;; + stf.spill.nta [r8] = f2,32 + stf.spill.nta [r9] = f3,32 + mov r15 = rp + ;; + stf.spill.nta [r8] = f4,32 + stf.spill.nta [r9] = f5,32 + mov r17 = b1 + ;; + stf.spill.nta [r8] = f16,32 + stf.spill.nta [r9] = f17,32 + mov r18 = b2 + ;; + stf.spill.nta [r8] = f18,32 + stf.spill.nta [r9] = f19,32 + mov r19 = b3 + ;; + stf.spill.nta [r8] = f20,32 + stf.spill.nta [r9] = f21,32 + mov r20 = b4 + ;; + stf.spill.nta [r8] = f22,32 + stf.spill.nta [r9] = f23,32 + mov r21 = b5 + ;; + stf.spill.nta [r8] = f24,32 + stf.spill.nta [r9] = f25,32 + mov r22 = ar.lc + ;; + stf.spill.nta [r8] = f26,32 + stf.spill.nta [r9] = f27,32 + mov r24 = pr + ;; + stf.spill.nta [r8] = f28,32 + stf.spill.nta [r9] = f29,32 + ;; + stf.spill.nta [r8] = f30 + stf.spill.nta [r9] = f31 + + st8.spill.nta [r2] = r6,16 // r6 + ;; + st8.spill.nta [r3] = r7,16 // r7 + ;; + mov r23 = ar.bsp + mov r25 = ar.unat + + st8.nta [r2] = r15,16 // b0 + st8.nta [r3] = r17,16 // b1 + ;; + st8.nta [r2] = r18,16 // b2 + st8.nta [r3] = r19,16 // b3 + mov r26 = ar.rsc + ;; + st8.nta [r2] = r20,16 // b4 + st8.nta [r3] = r21,16 // b5 + ;; + st8.nta [r2] = r14,16 // ar.pfs + st8.nta [r3] = r22,16 // ar.lc + ;; + st8.nta [r2] = r24,16 // pr + st8.nta [r3] = r23,16 // ar.bsp + ;; + st8.nta [r2] = r25,16 // ar.unat + st8.nta [r3] = in0,16 // &__jmp_buf (just in case) + ;; + st8.nta [r2] = r26 // ar.rsc + ;; + flushrs // flush dirty regs to backing store + ;; + and r27 = ~0x3,r26 // clear ar.rsc.mode + ;; + mov ar.rsc = r27 // put RSE in enforced lazy mode + ;; + mov r28 = ar.rnat + ;; + st8.nta [r3] = r28 // ar.rnat + mov ar.rsc = r26 // restore ar.rsc + ;; + mov r8 = 0 + br.ret.sptk.few b0 + .endp _st_md_cxt_save + + + /****************************************************************/ + + /* _st_md_cxt_restore(__jmp_buf env, int val) */ + .global _st_md_cxt_restore + .proc _st_md_cxt_restore + _st_md_cxt_restore: + alloc r8 = ar.pfs,2,0,0,0 + add r2 = 0x88,in0 // r2 <- &jmpbuf.ar_bsp + mov r16 = ar.rsc + ;; + flushrs // flush dirty regs to backing store + ;; + and r17 = ~0x3,r16 // clear ar.rsc.mode + ;; + mov ar.rsc = r17 // put RSE in enforced lazy mode + ;; + invala // invalidate the ALAT + ;; + ld8 r23 = [r2],8 // r23 <- jmpbuf.ar_bsp + ;; + mov ar.bspstore = r23 // write BSPSTORE + ld8 r25 = [r2],24 // r25 <- jmpbuf.ar_unat + ;; + ld8 r26 = [r2],-8 // r26 <- jmpbuf.ar_rnat + ;; + mov ar.rnat = r26 // write RNAT + ld8 r27 = [r2] // r27 <- jmpbuf.ar_rsc + ;; + mov ar.rsc = r27 // write RSE control + mov r2 = in0 + ;; + mov ar.unat = r25 // write ar.unat + add r3 = 8,in0 + ;; + ld8.fill.nta sp = [r2],16 // r12 (sp) + ld8.fill.nta gp = [r3],16 // r1 (gp) + ;; + ld8.nta r16 = [r2],16 // caller's unat + ld8.nta r17 = [r3],16 // fpsr + ;; + ld8.fill.nta r4 = [r2],16 // r4 + ld8.fill.nta r5 = [r3],16 // r5 + ;; + ld8.fill.nta r6 = [r2],16 // r6 + ld8.fill.nta r7 = [r3],16 // r7 + ;; + mov ar.unat = r16 // restore caller's unat + mov ar.fpsr = r17 // restore fpsr + ;; + ld8.nta r16 = [r2],16 // b0 + ld8.nta r17 = [r3],16 // b1 + ;; + ld8.nta r18 = [r2],16 // b2 + ld8.nta r19 = [r3],16 // b3 + ;; + ld8.nta r20 = [r2],16 // b4 + ld8.nta r21 = [r3],16 // b5 + ;; + ld8.nta r11 = [r2],16 // ar.pfs + ld8.nta r22 = [r3],72 // ar.lc + ;; + ld8.nta r24 = [r2],48 // pr + mov b0 = r16 + ;; + ldf.fill.nta f2 = [r2],32 + ldf.fill.nta f3 = [r3],32 + mov b1 = r17 + ;; + ldf.fill.nta f4 = [r2],32 + ldf.fill.nta f5 = [r3],32 + mov b2 = r18 + ;; + ldf.fill.nta f16 = [r2],32 + ldf.fill.nta f17 = [r3],32 + mov b3 = r19 + ;; + ldf.fill.nta f18 = [r2],32 + ldf.fill.nta f19 = [r3],32 + mov b4 = r20 + ;; + ldf.fill.nta f20 = [r2],32 + ldf.fill.nta f21 = [r3],32 + mov b5 = r21 + ;; + ldf.fill.nta f22 = [r2],32 + ldf.fill.nta f23 = [r3],32 + mov ar.lc = r22 + ;; + ldf.fill.nta f24 = [r2],32 + ldf.fill.nta f25 = [r3],32 + cmp.eq p6,p7 = 0,in1 + ;; + ldf.fill.nta f26 = [r2],32 + ldf.fill.nta f27 = [r3],32 + mov ar.pfs = r11 + ;; + ldf.fill.nta f28 = [r2],32 + ldf.fill.nta f29 = [r3],32 + ;; + ldf.fill.nta f30 = [r2] + ldf.fill.nta f31 = [r3] + (p6) mov r8 = 1 + (p7) mov r8 = in1 + + mov pr = r24,-1 + br.ret.sptk.few b0 + .endp _st_md_cxt_restore + + /****************************************************************/ + + + + + + + + + +#elif defined(__i386__) + + /****************************************************************/ + + /* + * Internal __jmp_buf layout + */ + #define JB_BX 0 + #define JB_SI 1 + #define JB_DI 2 + #define JB_BP 3 + #define JB_SP 4 + #define JB_PC 5 + + .file "md.S" + .text + + /* _st_md_cxt_save(__jmp_buf env) */ + .globl _st_md_cxt_save + .type _st_md_cxt_save, @function + .align 16 + _st_md_cxt_save: + movl 4(%esp), %eax + + /* + * Save registers. + */ + movl %ebx, (JB_BX*4)(%eax) + movl %esi, (JB_SI*4)(%eax) + movl %edi, (JB_DI*4)(%eax) + /* Save SP */ + leal 4(%esp), %ecx + movl %ecx, (JB_SP*4)(%eax) + /* Save PC we are returning to */ + movl 0(%esp), %ecx + movl %ecx, (JB_PC*4)(%eax) + /* Save caller frame pointer */ + movl %ebp, (JB_BP*4)(%eax) + xorl %eax, %eax + ret + .size _st_md_cxt_save, .-_st_md_cxt_save + + + /****************************************************************/ + + /* _st_md_cxt_restore(__jmp_buf env, int val) */ + .globl _st_md_cxt_restore + .type _st_md_cxt_restore, @function + .align 16 + _st_md_cxt_restore: + /* First argument is jmp_buf */ + movl 4(%esp), %ecx + /* Second argument is return value */ + movl 8(%esp), %eax + /* Set the return address */ + movl (JB_PC*4)(%ecx), %edx + /* + * Restore registers. + */ + movl (JB_BX*4)(%ecx), %ebx + movl (JB_SI*4)(%ecx), %esi + movl (JB_DI*4)(%ecx), %edi + movl (JB_BP*4)(%ecx), %ebp + movl (JB_SP*4)(%ecx), %esp + testl %eax, %eax + jnz 1f + incl %eax + /* Jump to saved PC */ + 1: jmp *%edx + .size _st_md_cxt_restore, .-_st_md_cxt_restore + + /****************************************************************/ + + + + + + + + + + +#elif defined(__amd64__) || defined(__x86_64__) + + /****************************************************************/ + + /* + * Internal __jmp_buf layout + */ + #define JB_RBX 0 + #define JB_RBP 1 + #define JB_R12 2 + #define JB_R13 3 + #define JB_R14 4 + #define JB_R15 5 + #define JB_RSP 6 + #define JB_PC 7 + + .file "md.S" + .text + + /* _st_md_cxt_save(__jmp_buf env) */ + .globl _st_md_cxt_save + .type _st_md_cxt_save, @function + .align 16 + _st_md_cxt_save: + /* + * Save registers. + */ + movq %rbx, (JB_RBX*8)(%rdi) + movq %rbp, (JB_RBP*8)(%rdi) + movq %r12, (JB_R12*8)(%rdi) + movq %r13, (JB_R13*8)(%rdi) + movq %r14, (JB_R14*8)(%rdi) + movq %r15, (JB_R15*8)(%rdi) + /* Save SP */ + leaq 8(%rsp), %rdx + movq %rdx, (JB_RSP*8)(%rdi) + /* Save PC we are returning to */ + movq (%rsp), %rax + movq %rax, (JB_PC*8)(%rdi) + xorq %rax, %rax + ret + .size _st_md_cxt_save, .-_st_md_cxt_save + + + /****************************************************************/ + + /* _st_md_cxt_restore(__jmp_buf env, int val) */ + .globl _st_md_cxt_restore + .type _st_md_cxt_restore, @function + .align 16 + _st_md_cxt_restore: + /* + * Restore registers. + */ + movq (JB_RBX*8)(%rdi), %rbx + movq (JB_RBP*8)(%rdi), %rbp + movq (JB_R12*8)(%rdi), %r12 + movq (JB_R13*8)(%rdi), %r13 + movq (JB_R14*8)(%rdi), %r14 + movq (JB_R15*8)(%rdi), %r15 + /* Set return value */ + test %esi, %esi + mov $01, %eax + cmove %eax, %esi + mov %esi, %eax + movq (JB_PC*8)(%rdi), %rdx + movq (JB_RSP*8)(%rdi), %rsp + /* Jump to saved PC */ + jmpq *%rdx + .size _st_md_cxt_restore, .-_st_md_cxt_restore + + /****************************************************************/ + + + + + + + + + + +#elif defined(__aarch64__) + + /****************************************************************/ + /* https://github.com/ossrs/srs/issues/1282#issuecomment-445539513 */ + + #define JB_X19 0 + #define JB_X20 1 + #define JB_X21 2 + #define JB_X22 3 + #define JB_X23 4 + #define JB_X24 5 + #define JB_X25 6 + #define JB_X26 7 + #define JB_X27 8 + #define JB_X28 9 + #define JB_X29 10 + #define JB_LR 11 + #define JB_SP 13 + + #define JB_D8 14 + #define JB_D9 15 + #define JB_D10 16 + #define JB_D11 17 + #define JB_D12 18 + #define JB_D13 19 + #define JB_D14 20 + #define JB_D15 21 + + .file "md.S" + .text + + /* _st_md_cxt_save(__jmp_buf env) */ + .globl _st_md_cxt_save + .type _st_md_cxt_save, %function + .align 4 + _st_md_cxt_save: + stp x19, x20, [x0, #JB_X19<<3] + stp x21, x22, [x0, #JB_X21<<3] + stp x23, x24, [x0, #JB_X23<<3] + stp x25, x26, [x0, #JB_X25<<3] + stp x27, x28, [x0, #JB_X27<<3] + stp x29, x30, [x0, #JB_X29<<3] + + stp d8, d9, [x0, #JB_D8<<3] + stp d10, d11, [x0, #JB_D10<<3] + stp d12, d13, [x0, #JB_D12<<3] + stp d14, d15, [x0, #JB_D14<<3] + mov x2, sp + str x2, [x0, #JB_SP<<3] + + mov x0, #0 + ret + .size _st_md_cxt_save, .-_st_md_cxt_save + + /****************************************************************/ + + /* _st_md_cxt_restore(__jmp_buf env, int val) */ + .globl _st_md_cxt_restore + .type _st_md_cxt_restore, %function + .align 4 + _st_md_cxt_restore: + ldp x19, x20, [x0, #JB_X19<<3] + ldp x21, x22, [x0, #JB_X21<<3] + ldp x23, x24, [x0, #JB_X23<<3] + ldp x25, x26, [x0, #JB_X25<<3] + ldp x27, x28, [x0, #JB_X27<<3] + + ldp x29, x30, [x0, #JB_X29<<3] + + ldp d8, d9, [x0, #JB_D8<<3] + ldp d10, d11, [x0, #JB_D10<<3] + ldp d12, d13, [x0, #JB_D12<<3] + ldp d14, d15, [x0, #JB_D14<<3] + + ldr x5, [x0, #JB_SP<<3] + mov sp, x5 + + cmp x1, #0 + mov x0, #1 + csel x0, x1, x0, ne + /* Use br instead of ret because ret is guaranteed to mispredict */ + br x30 + .size _st_md_cxt_restore, .-_st_md_cxt_restore + + /****************************************************************/ + + + + + + + + + + +#elif defined(__arm__) + + /****************************************************************/ + /* https://github.com/ossrs/srs/issues/1282#issuecomment-445539513 */ + + /* Register list for a ldm/stm instruction to load/store + the general registers from a __jmp_buf. */ + # define JMP_BUF_REGLIST {v1-v6, sl, fp, sp, lr} + + .file "md.S" + .text + + /* _st_md_cxt_save(__jmp_buf env) */ + .globl _st_md_cxt_save + .type _st_md_cxt_save, %function + .align 2 + _st_md_cxt_save: + mov ip, r0 + + /* Save registers */ + stmia ip!, JMP_BUF_REGLIST + + #ifdef __VFP_FP__ + /* Store the VFP registers. */ + /* Following instruction is vstmia ip!, {d8-d15}. */ + stc p11, cr8, [ip], #64 + #endif + + #ifdef __IWMMXT__ + /* Save the call-preserved iWMMXt registers. */ + /* Following instructions are wstrd wr10, [ip], #8 (etc.) */ + stcl p1, cr10, [r12], #8 + stcl p1, cr11, [r12], #8 + stcl p1, cr12, [r12], #8 + stcl p1, cr13, [r12], #8 + stcl p1, cr14, [r12], #8 + stcl p1, cr15, [r12], #8 + #endif + + mov r0, #0 + bx lr + + .size _st_md_cxt_save, .-_st_md_cxt_save + + /****************************************************************/ + + /* _st_md_cxt_restore(__jmp_buf env, int val) */ + .globl _st_md_cxt_restore + .type _st_md_cxt_restore, %function + .align 2 + _st_md_cxt_restore: + mov ip, r0 + + /* Restore registers */ + ldmia ip!, JMP_BUF_REGLIST + + #ifdef __VFP_FP__ + /* Restore the VFP registers. */ + /* Following instruction is vldmia ip!, {d8-d15}. */ + ldc p11, cr8, [r12], #64 + #endif + + #ifdef __IWMMXT__ + /* Restore the call-preserved iWMMXt registers. */ + /* Following instructions are wldrd wr10, [ip], #8 (etc.) */ + ldcl p1, cr10, [r12], #8 + ldcl p1, cr11, [r12], #8 + ldcl p1, cr12, [r12], #8 + ldcl p1, cr13, [r12], #8 + ldcl p1, cr14, [r12], #8 + ldcl p1, cr15, [r12], #8 + #endif + + movs r0, r1 /* get the return value in place */ + moveq r0, #1 /* can't let setjmp() return zero! */ + bx lr + + .size _st_md_cxt_restore, .-_st_md_cxt_restore + + /****************************************************************/ + +#endif + +#endif diff --git a/trunk/3rdparty/st-srs/md.h b/trunk/3rdparty/st-srs/md.h new file mode 100644 index 0000000000..dc4ef54c90 --- /dev/null +++ b/trunk/3rdparty/st-srs/md.h @@ -0,0 +1,641 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#ifndef __ST_MD_H__ +#define __ST_MD_H__ + +#if defined(ETIMEDOUT) && !defined(ETIME) + #define ETIME ETIMEDOUT +#endif + +#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON) + #define MAP_ANON MAP_ANONYMOUS +#endif + +#ifndef MAP_FAILED + #define MAP_FAILED -1 +#endif + +/***************************************** + * Platform specifics + */ + +#if defined (AIX) + + #define MD_STACK_GROWS_DOWN + #define MD_USE_SYSV_ANON_MMAP + #define MD_ACCEPT_NB_INHERITED + #define MD_ALWAYS_UNSERIALIZED_ACCEPT + + #ifndef MD_HAVE_SOCKLEN_T + #define MD_HAVE_SOCKLEN_T + #define socklen_t unsigned long + #endif + + #define MD_SETJMP(env) _setjmp(env) + #define MD_LONGJMP(env, val) _longjmp(env, val) + + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + (_thread)->context[3] = (long) (_sp); \ + ST_END_MACRO + + #define MD_GET_UTIME() \ + timebasestruct_t rt; \ + (void) read_real_time(&rt, TIMEBASE_SZ); \ + (void) time_base_to_time(&rt, TIMEBASE_SZ); \ + return (rt.tb_high * 1000000LL + rt.tb_low / 1000) + +#elif defined (CYGWIN) + + #define MD_STACK_GROWS_DOWN + #define MD_USE_BSD_ANON_MMAP + #define MD_ACCEPT_NB_NOT_INHERITED + #define MD_ALWAYS_UNSERIALIZED_ACCEPT + + #define MD_SETJMP(env) setjmp(env) + #define MD_LONGJMP(env, val) longjmp(env, val) + + #define MD_JB_SP 7 + + #define MD_GET_SP(_t) (_t)->context[MD_JB_SP] + + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + MD_GET_SP(_thread) = (long) (_sp); \ + ST_END_MACRO + + #define MD_GET_UTIME() \ + struct timeval tv; \ + (void) gettimeofday(&tv, NULL); \ + return (tv.tv_sec * 1000000LL + tv.tv_usec) + +#elif defined (DARWIN) + + #define MD_STACK_GROWS_DOWN + #define MD_USE_BSD_ANON_MMAP + #define MD_ACCEPT_NB_INHERITED + #define MD_ALWAYS_UNSERIALIZED_ACCEPT + #define MD_HAVE_SOCKLEN_T + + #define MD_SETJMP(env) _setjmp(env) + #define MD_LONGJMP(env, val) _longjmp(env, val) + + #if defined(__ppc__) + #define MD_JB_SP 0 + #elif defined(__i386__) + #define MD_JB_SP 9 + #elif defined(__x86_64__) + #define MD_JB_SP 4 + #else + #error Unknown CPU architecture + #endif + + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + *((long *)&((_thread)->context[MD_JB_SP])) = (long) (_sp); \ + ST_END_MACRO + + #define MD_GET_UTIME() \ + struct timeval tv; \ + (void) gettimeofday(&tv, NULL); \ + return (tv.tv_sec * 1000000LL + tv.tv_usec) + +#elif defined (FREEBSD) + + #define MD_STACK_GROWS_DOWN + #define MD_USE_BSD_ANON_MMAP + #define MD_ACCEPT_NB_INHERITED + #define MD_ALWAYS_UNSERIALIZED_ACCEPT + + #define MD_SETJMP(env) _setjmp(env) + #define MD_LONGJMP(env, val) _longjmp(env, val) + + #if defined(__i386__) + #define MD_JB_SP 2 + #elif defined(__alpha__) + #define MD_JB_SP 34 + #elif defined(__amd64__) + #define MD_JB_SP 2 + #else + #error Unknown CPU architecture + #endif + + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + (_thread)->context[0]._jb[MD_JB_SP] = (long) (_sp); \ + ST_END_MACRO + + #define MD_GET_UTIME() \ + struct timeval tv; \ + (void) gettimeofday(&tv, NULL); \ + return (tv.tv_sec * 1000000LL + tv.tv_usec) + +#elif defined (HPUX) + + #define MD_STACK_GROWS_UP + #define MD_USE_BSD_ANON_MMAP + #define MD_ACCEPT_NB_INHERITED + #define MD_ALWAYS_UNSERIALIZED_ACCEPT + + #define MD_SETJMP(env) _setjmp(env) + #define MD_LONGJMP(env, val) _longjmp(env, val) + + #ifndef __LP64__ + /* 32-bit mode (ILP32 data model) */ + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + ((long *)((_thread)->context))[1] = (long) (_sp); \ + ST_END_MACRO + #else + /* 64-bit mode (LP64 data model) */ + #define MD_STACK_PAD_SIZE 256 + /* Last stack frame must be preserved */ + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + memcpy((char *)(_sp) - MD_STACK_PAD_SIZE, \ + ((char **)((_thread)->context))[1] - MD_STACK_PAD_SIZE, \ + MD_STACK_PAD_SIZE); \ + ((long *)((_thread)->context))[1] = (long) (_sp); \ + ST_END_MACRO + #endif /* !__LP64__ */ + + #define MD_GET_UTIME() \ + struct timeval tv; \ + (void) gettimeofday(&tv, NULL); \ + return (tv.tv_sec * 1000000LL + tv.tv_usec) + +#elif defined (IRIX) + + #include + + #define MD_STACK_GROWS_DOWN + #define MD_USE_SYSV_ANON_MMAP + #define MD_ACCEPT_NB_INHERITED + #define MD_ALWAYS_UNSERIALIZED_ACCEPT + + #define MD_SETJMP(env) setjmp(env) + #define MD_LONGJMP(env, val) longjmp(env, val) + + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + (void) MD_SETJMP((_thread)->context); \ + (_thread)->context[JB_SP] = (long) (_sp); \ + (_thread)->context[JB_PC] = (long) _main; \ + ST_END_MACRO + + #define MD_GET_UTIME() \ + static int inited = 0; \ + static clockid_t clock_id = CLOCK_SGI_CYCLE; \ + struct timespec ts; \ + if (!inited) { \ + if (syssgi(SGI_CYCLECNTR_SIZE) < 64) \ + clock_id = CLOCK_REALTIME; \ + inited = 1; \ + } \ + (void) clock_gettime(clock_id, &ts); \ + return (ts.tv_sec * 1000000LL + ts.tv_nsec / 1000) + + /* + * Cap the stack by zeroing out the saved return address register + * value. This allows libexc, used by SpeedShop, to know when to stop + * backtracing since it won't find main, start, or any other known + * stack root function in a state thread's stack. Without this libexc + * traces right off the stack and crashes. + * The function preamble stores ra at 8(sp), this stores zero there. + * N.B. This macro is compiler/ABI dependent. It must change if ANY more + * automatic variables are added to the _st_thread_main() routine, because + * the address where ra is stored will change. + */ + #if !defined(__GNUC__) && defined(_MIPS_SIM) && _MIPS_SIM != _ABIO32 + #define MD_CAP_STACK(var_addr) \ + (((volatile __uint64_t *)(var_addr))[1] = 0) + #endif + +#elif defined (LINUX) + + /* + * These are properties of the linux kernel and are the same on every + * flavor and architecture. + */ + #define MD_USE_BSD_ANON_MMAP + #define MD_ACCEPT_NB_NOT_INHERITED + #define MD_ALWAYS_UNSERIALIZED_ACCEPT + /* + * Modern GNU/Linux is Posix.1g compliant. + */ + #define MD_HAVE_SOCKLEN_T + + /* + * All architectures and flavors of linux have the gettimeofday + * function but if you know of a faster way, use it. + */ + #define MD_GET_UTIME() \ + struct timeval tv; \ + (void) gettimeofday(&tv, NULL); \ + return (tv.tv_sec * 1000000LL + tv.tv_usec) + + #if defined(__ia64__) + #define MD_STACK_GROWS_DOWN + + /* + * IA-64 architecture. Besides traditional memory call stack, IA-64 + * uses general register stack. Thus each thread needs a backing store + * for register stack in addition to memory stack. Standard + * setjmp()/longjmp() cannot be used for thread context switching + * because their implementation implicitly assumes that only one + * register stack exists. + */ + #ifdef USE_LIBC_SETJMP + #undef USE_LIBC_SETJMP + #endif + #define MD_USE_BUILTIN_SETJMP + + #define MD_STACK_PAD_SIZE 128 + /* Last register stack frame must be preserved */ + #define MD_INIT_CONTEXT(_thread, _sp, _bsp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + memcpy((char *)(_bsp) - MD_STACK_PAD_SIZE, \ + (char *)(_thread)->context[0].__jmpbuf[17] - MD_STACK_PAD_SIZE, \ + MD_STACK_PAD_SIZE); \ + (_thread)->context[0].__jmpbuf[0] = (long) (_sp); \ + (_thread)->context[0].__jmpbuf[17] = (long) (_bsp); \ + ST_END_MACRO + + #elif defined(__mips__) + #define MD_STACK_GROWS_DOWN + + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + MD_SETJMP((_thread)->context); \ + _thread->context[0].__jmpbuf[0].__pc = (__ptr_t) _main; \ + _thread->context[0].__jmpbuf[0].__sp = _sp; \ + ST_END_MACRO + + #else /* Not IA-64 or mips */ + + /* + * On linux, there are a few styles of jmpbuf format. These vary based + * on architecture/glibc combination. + * + * Most of the glibc based toggles were lifted from: + * mozilla/nsprpub/pr/include/md/_linux.h + */ + + /* + * Starting with glibc 2.4, JB_SP definitions are not public anymore. + * They, however, can still be found in glibc source tree in + * architecture-specific "jmpbuf-offsets.h" files. + * Most importantly, the content of jmp_buf is mangled by setjmp to make + * it completely opaque (the mangling can be disabled by setting the + * LD_POINTER_GUARD environment variable before application execution). + * Therefore we will use built-in _st_md_cxt_save/_st_md_cxt_restore + * functions as a setjmp/longjmp replacement wherever they are available + * unless USE_LIBC_SETJMP is defined. + */ + + #if defined(__powerpc__) + #define MD_STACK_GROWS_DOWN + + #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) + #ifndef JB_GPR1 + #define JB_GPR1 0 + #endif + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_GPR1] + #else + /* not an error but certainly cause for caution */ + #error "Untested use of old glibc on powerpc" + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__misc[0] + #endif /* glibc 2.1 or later */ + + #elif defined(__alpha) + #define MD_STACK_GROWS_DOWN + + #if defined(__GLIBC__) && __GLIBC__ >= 2 + #ifndef JB_SP + #define JB_SP 8 + #endif + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP] + #else + /* not an error but certainly cause for caution */ + #error "Untested use of old glibc on alpha" + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp + #endif + + #elif defined(__mc68000__) + #define MD_STACK_GROWS_DOWN + + /* m68k still uses old style sigjmp_buf */ + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp + + #elif defined(__sparc__) + #define MD_STACK_GROWS_DOWN + + #if defined(__GLIBC__) && __GLIBC__ >= 2 + #ifndef JB_SP + #define JB_SP 0 + #endif + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP] + #else + /* not an error but certainly cause for caution */ + #error "Untested use of old glic on sparc -- also using odd mozilla derived __fp" + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__fp + #endif + + #elif defined(__i386__) + #define MD_STACK_GROWS_DOWN + #define MD_USE_BUILTIN_SETJMP + + #if defined(__GLIBC__) && __GLIBC__ >= 2 + #ifndef JB_SP + #define JB_SP 4 + #endif + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP] + #else + /* not an error but certainly cause for caution */ + #error "Untested use of old glibc on i386" + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp + #endif + + #elif defined(__amd64__) || defined(__x86_64__) + #define MD_STACK_GROWS_DOWN + #define MD_USE_BUILTIN_SETJMP + + #ifndef JB_RSP + #define JB_RSP 6 + #endif + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_RSP] + + #elif defined(__aarch64__) + /* https://github.com/ossrs/state-threads/issues/9 */ + #define MD_STACK_GROWS_DOWN + #define MD_USE_BUILTIN_SETJMP + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[13] + + #elif defined(__arm__) + #define MD_STACK_GROWS_DOWN + /* https://github.com/ossrs/state-threads/issues/1#issuecomment-244648573 */ + #define MD_USE_BUILTIN_SETJMP + + /* force to use glibc solution, hack the guard jmpbuf from michaeltalyansky */ + #ifdef USE_LIBC_SETJMP + #undef MD_USE_BUILTIN_SETJMP + #endif + + #if defined(__GLIBC__) && __GLIBC__ >= 2 + /* Merge from https://github.com/michaeltalyansky/state-threads/commit/56554a5c425aee8e7a73782eae23d74d83c4120a */ + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[8] + #else + #error "ARM/Linux pre-glibc2 not supported yet" + #endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + + #elif defined(__s390__) + #define MD_STACK_GROWS_DOWN + + /* There is no JB_SP in glibc at this time. (glibc 2.2.5) + */ + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__gregs[9] + + #elif defined(__hppa__) + #define MD_STACK_GROWS_UP + + /* yes, this is gross, unfortunately at the moment (2002/08/01) there is + * a bug in hppa's glibc header definition for JB_SP, so we can't + * use that... + */ + #define MD_GET_SP(_t) (*(long *)(((char *)&(_t)->context[0].__jmpbuf[0]) + 76)) + + #else + #error "Unknown CPU architecture" + #endif /* Cases with common MD_INIT_CONTEXT and different SP locations */ + + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + MD_GET_SP(_thread) = (long) (_sp); \ + ST_END_MACRO + + #endif /* Cases with different MD_INIT_CONTEXT */ + + #if defined(MD_USE_BUILTIN_SETJMP) && !defined(USE_LIBC_SETJMP) + #define MD_SETJMP(env) _st_md_cxt_save(env) + #define MD_LONGJMP(env, val) _st_md_cxt_restore(env, val) + + extern int _st_md_cxt_save(jmp_buf env); + extern void _st_md_cxt_restore(jmp_buf env, int val); + #else + #define MD_SETJMP(env) setjmp(env) + #define MD_LONGJMP(env, val) longjmp(env, val) + #endif + +#elif defined (NETBSD) + + #define MD_STACK_GROWS_DOWN + #define MD_USE_BSD_ANON_MMAP + #define MD_ACCEPT_NB_INHERITED + #define MD_ALWAYS_UNSERIALIZED_ACCEPT + #define MD_HAVE_SOCKLEN_T + + #define MD_SETJMP(env) _setjmp(env) + #define MD_LONGJMP(env, val) _longjmp(env, val) + + #if defined(__i386__) + #define MD_JB_SP 2 + #elif defined(__alpha__) + #define MD_JB_SP 34 + #elif defined(__sparc__) + #define MD_JB_SP 0 + #elif defined(__vax__) + #define MD_JB_SP 2 + #else + #error Unknown CPU architecture + #endif + + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + (_thread)->context[MD_JB_SP] = (long) (_sp); \ + ST_END_MACRO + + #define MD_GET_UTIME() \ + struct timeval tv; \ + (void) gettimeofday(&tv, NULL); \ + return (tv.tv_sec * 1000000LL + tv.tv_usec) + +#elif defined (OPENBSD) + + #define MD_STACK_GROWS_DOWN + #define MD_USE_BSD_ANON_MMAP + #define MD_ACCEPT_NB_INHERITED + #define MD_ALWAYS_UNSERIALIZED_ACCEPT + + #define MD_SETJMP(env) _setjmp(env) + #define MD_LONGJMP(env, val) _longjmp(env, val) + + #if defined(__i386__) + #define MD_JB_SP 2 + #elif defined(__alpha__) + #define MD_JB_SP 34 + #elif defined(__sparc__) + #define MD_JB_SP 0 + #elif defined(__amd64__) + #define MD_JB_SP 6 + #else + #error Unknown CPU architecture + #endif + + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + (_thread)->context[MD_JB_SP] = (long) (_sp); \ + ST_END_MACRO + + #define MD_GET_UTIME() \ + struct timeval tv; \ + (void) gettimeofday(&tv, NULL); \ + return (tv.tv_sec * 1000000LL + tv.tv_usec) + +#elif defined (OSF1) + + #include + + #define MD_STACK_GROWS_DOWN + #define MD_USE_SYSV_ANON_MMAP + #define MD_ACCEPT_NB_NOT_INHERITED + #define MD_ALWAYS_UNSERIALIZED_ACCEPT + + #define MD_SETJMP(env) _setjmp(env) + #define MD_LONGJMP(env, val) _longjmp(env, val) + + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + ((struct sigcontext *)((_thread)->context))->sc_sp = (long) (_sp); \ + ST_END_MACRO + + #define MD_GET_UTIME() \ + struct timeval tv; \ + (void) gettimeofday(&tv, NULL); \ + return (tv.tv_sec * 1000000LL + tv.tv_usec) + +#elif defined (SOLARIS) + + #include + extern int getpagesize(void); + + #define MD_STACK_GROWS_DOWN + #define MD_USE_SYSV_ANON_MMAP + #define MD_ACCEPT_NB_NOT_INHERITED + + #define MD_SETJMP(env) setjmp(env) + #define MD_LONGJMP(env, val) longjmp(env, val) + + #if defined(sparc) || defined(__sparc) + #ifdef _LP64 + #define MD_STACK_PAD_SIZE 4095 + #endif + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + (void) MD_SETJMP((_thread)->context); \ + (_thread)->context[1] = (long) (_sp); \ + (_thread)->context[2] = (long) _main; \ + ST_END_MACRO + #elif defined(i386) || defined(__i386) + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + (void) MD_SETJMP((_thread)->context); \ + (_thread)->context[4] = (long) (_sp); \ + (_thread)->context[5] = (long) _main; \ + ST_END_MACRO + #elif defined(__amd64__) + #define MD_INIT_CONTEXT(_thread, _sp, _main) \ + ST_BEGIN_MACRO \ + if (MD_SETJMP((_thread)->context)) \ + _main(); \ + (_thread)->context[6] = (long) (_sp); \ + ST_END_MACRO + #else + #error Unknown CPU architecture + #endif + + #define MD_GET_UTIME() \ + return (gethrtime() / 1000) + +#else + #error Unknown OS +#endif /* OS */ + +#if !defined(MD_HAVE_POLL) && !defined(MD_DONT_HAVE_POLL) + #define MD_HAVE_POLL +#endif + +#ifndef MD_STACK_PAD_SIZE + #define MD_STACK_PAD_SIZE 128 +#endif + +#if !defined(MD_HAVE_SOCKLEN_T) && !defined(socklen_t) + #define socklen_t int +#endif + +#ifndef MD_CAP_STACK + #define MD_CAP_STACK(var_addr) +#endif + +#endif /* !__ST_MD_H__ */ + diff --git a/trunk/3rdparty/st-srs/osguess.sh b/trunk/3rdparty/st-srs/osguess.sh new file mode 100644 index 0000000000..531681efe6 --- /dev/null +++ b/trunk/3rdparty/st-srs/osguess.sh @@ -0,0 +1,45 @@ +# +# This script can be used to automatically guess target OS. +# It requires the config.guess utility which is a part of GNU Autoconf. +# GNU Autoconf can be downloaded from ftp://ftp.gnu.org/gnu/autoconf/ +# +# Use "default" as a make target for automatic builds. +# + + +# Specify path to the config.guess utility (unless set via environment) +#CONFIG_GUESS_PATH= + + +if [ x"$CONFIG_GUESS_PATH" = x ]; then + echo "Error: CONFIG_GUESS_PATH variable is not set" + exit 1 +fi + +if [ ! -f "$CONFIG_GUESS_PATH/config.guess" ]; then + echo "Can't find $CONFIG_GUESS_PATH/config.guess utility. Wrong path?" + exit 1 +fi + +sys_info=`/bin/sh $CONFIG_GUESS_PATH/config.guess` + +echo "Building for $sys_info" + +case "$sys_info" in + *-ibm-aix4* ) OS=AIX ;; + *-freebsd* ) OS=FREEBSD ;; + hppa*-hp-hpux11*) OS=HPUX ;; + *-sgi-irix6* ) OS=IRIX ;; + *-linux* ) OS=LINUX ;; + *-netbsd* ) OS=NETBSD ;; + *-openbsd* ) OS=OPENBSD ;; + *-dec-osf* ) OS=OSF1 ;; + *-solaris2* ) OS=SOLARIS ;; + *-darwin* ) OS=DARWIN ;; + * ) OS= + echo "Sorry, unsupported OS" + exit 1 ;; +esac + +echo "Making with OS=$OS" + diff --git a/trunk/3rdparty/st-srs/public.h b/trunk/3rdparty/st-srs/public.h new file mode 100644 index 0000000000..20b09407b2 --- /dev/null +++ b/trunk/3rdparty/st-srs/public.h @@ -0,0 +1,166 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef __ST_THREAD_H__ +#define __ST_THREAD_H__ + +#include +#include +#include +#include +#include +#include +#include + +#define ST_VERSION "1.9" +#define ST_VERSION_MAJOR 1 +#define ST_VERSION_MINOR 9 + +/* Undefine this to remove the context switch callback feature. */ +#define ST_SWITCH_CB + +#ifndef ETIME + #define ETIME ETIMEDOUT +#endif + +#ifndef ST_UTIME_NO_TIMEOUT + #define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL) +#endif + +#ifndef ST_UTIME_NO_WAIT + #define ST_UTIME_NO_WAIT 0 +#endif + +#define ST_EVENTSYS_DEFAULT 0 +#define ST_EVENTSYS_SELECT 1 +#define ST_EVENTSYS_POLL 2 +#define ST_EVENTSYS_ALT 3 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long long st_utime_t; +typedef struct _st_thread * st_thread_t; +typedef struct _st_cond * st_cond_t; +typedef struct _st_mutex * st_mutex_t; +typedef struct _st_netfd * st_netfd_t; +#ifdef ST_SWITCH_CB +typedef void (*st_switch_cb_t)(void); +#endif + +extern int st_init(void); +extern int st_getfdlimit(void); + +extern int st_set_eventsys(int eventsys); +extern int st_get_eventsys(void); +extern const char *st_get_eventsys_name(void); + +#ifdef ST_SWITCH_CB +extern st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb); +extern st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb); +#endif + +extern st_thread_t st_thread_self(void); +extern void st_thread_exit(void *retval); +extern int st_thread_join(st_thread_t thread, void **retvalp); +extern void st_thread_interrupt(st_thread_t thread); +extern st_thread_t st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stack_size); +extern int st_randomize_stacks(int on); +extern int st_set_utime_function(st_utime_t (*func)(void)); + +extern st_utime_t st_utime(void); +extern st_utime_t st_utime_last_clock(void); +extern int st_timecache_set(int on); +extern time_t st_time(void); +extern int st_usleep(st_utime_t usecs); +extern int st_sleep(int secs); +extern st_cond_t st_cond_new(void); +extern int st_cond_destroy(st_cond_t cvar); +extern int st_cond_timedwait(st_cond_t cvar, st_utime_t timeout); +extern int st_cond_wait(st_cond_t cvar); +extern int st_cond_signal(st_cond_t cvar); +extern int st_cond_broadcast(st_cond_t cvar); +extern st_mutex_t st_mutex_new(void); +extern int st_mutex_destroy(st_mutex_t lock); +extern int st_mutex_lock(st_mutex_t lock); +extern int st_mutex_unlock(st_mutex_t lock); +extern int st_mutex_trylock(st_mutex_t lock); + +extern int st_key_create(int *keyp, void (*destructor)(void *)); +extern int st_key_getlimit(void); +extern int st_thread_setspecific(int key, void *value); +extern void *st_thread_getspecific(int key); + +extern st_netfd_t st_netfd_open(int osfd); +extern st_netfd_t st_netfd_open_socket(int osfd); +extern void st_netfd_free(st_netfd_t fd); +extern int st_netfd_close(st_netfd_t fd); +extern int st_netfd_fileno(st_netfd_t fd); +extern void st_netfd_setspecific(st_netfd_t fd, void *value, void (*destructor)(void *)); +extern void *st_netfd_getspecific(st_netfd_t fd); +extern int st_netfd_serialize_accept(st_netfd_t fd); +extern int st_netfd_poll(st_netfd_t fd, int how, st_utime_t timeout); + +extern int st_poll(struct pollfd *pds, int npds, st_utime_t timeout); +extern st_netfd_t st_accept(st_netfd_t fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout); +extern int st_connect(st_netfd_t fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout); +extern ssize_t st_read(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout); +extern ssize_t st_read_fully(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout); +extern int st_read_resid(st_netfd_t fd, void *buf, size_t *resid, st_utime_t timeout); +extern ssize_t st_readv(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout); +extern int st_readv_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout); +extern ssize_t st_write(st_netfd_t fd, const void *buf, size_t nbyte, st_utime_t timeout); +extern int st_write_resid(st_netfd_t fd, const void *buf, size_t *resid, st_utime_t timeout); +extern ssize_t st_writev(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout); +extern int st_writev_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout); +extern int st_recvfrom(st_netfd_t fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout); +extern int st_sendto(st_netfd_t fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout); +extern int st_recvmsg(st_netfd_t fd, struct msghdr *msg, int flags, st_utime_t timeout); +extern int st_sendmsg(st_netfd_t fd, const struct msghdr *msg, int flags, st_utime_t timeout); +extern st_netfd_t st_open(const char *path, int oflags, mode_t mode); + +#ifdef DEBUG +extern void _st_show_thread_stack(st_thread_t thread, const char *messg); +extern void _st_iterate_threads(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !__ST_THREAD_H__ */ + diff --git a/trunk/3rdparty/st-srs/sched.c b/trunk/3rdparty/st-srs/sched.c new file mode 100644 index 0000000000..87515827e9 --- /dev/null +++ b/trunk/3rdparty/st-srs/sched.c @@ -0,0 +1,705 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" + +/* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */ +#ifndef NVALGRIND +#include +#endif + + +/* Global data */ +_st_vp_t _st_this_vp; /* This VP */ +_st_thread_t *_st_this_thread; /* Current thread */ +int _st_active_count = 0; /* Active thread count */ + +time_t _st_curr_time = 0; /* Current time as returned by time(2) */ +st_utime_t _st_last_tset; /* Last time it was fetched */ + + +int st_poll(struct pollfd *pds, int npds, st_utime_t timeout) +{ + struct pollfd *pd; + struct pollfd *epd = pds + npds; + _st_pollq_t pq; + _st_thread_t *me = _ST_CURRENT_THREAD(); + int n; + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + if ((*_st_eventsys->pollset_add)(pds, npds) < 0) + return -1; + + pq.pds = pds; + pq.npds = npds; + pq.thread = me; + pq.on_ioq = 1; + _ST_ADD_IOQ(pq); + if (timeout != ST_UTIME_NO_TIMEOUT) + _ST_ADD_SLEEPQ(me, timeout); + me->state = _ST_ST_IO_WAIT; + + _ST_SWITCH_CONTEXT(me); + + n = 0; + if (pq.on_ioq) { + /* If we timed out, the pollq might still be on the ioq. Remove it */ + _ST_DEL_IOQ(pq); + (*_st_eventsys->pollset_del)(pds, npds); + } else { + /* Count the number of ready descriptors */ + for (pd = pds; pd < epd; pd++) { + if (pd->revents) + n++; + } + } + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + return n; +} + + +void _st_vp_schedule(void) +{ + _st_thread_t *thread; + + if (_ST_RUNQ.next != &_ST_RUNQ) { + /* Pull thread off of the run queue */ + thread = _ST_THREAD_PTR(_ST_RUNQ.next); + _ST_DEL_RUNQ(thread); + } else { + /* If there are no threads to run, switch to the idle thread */ + thread = _st_this_vp.idle_thread; + } + ST_ASSERT(thread->state == _ST_ST_RUNNABLE); + + /* Resume the thread */ + thread->state = _ST_ST_RUNNING; + _ST_RESTORE_CONTEXT(thread); +} + + +/* + * Initialize this Virtual Processor + */ +int st_init(void) +{ + _st_thread_t *thread; + + if (_st_active_count) { + /* Already initialized */ + return 0; + } + + /* We can ignore return value here */ + st_set_eventsys(ST_EVENTSYS_DEFAULT); + + if (_st_io_init() < 0) + return -1; + + memset(&_st_this_vp, 0, sizeof(_st_vp_t)); + + ST_INIT_CLIST(&_ST_RUNQ); + ST_INIT_CLIST(&_ST_IOQ); + ST_INIT_CLIST(&_ST_ZOMBIEQ); +#ifdef DEBUG + ST_INIT_CLIST(&_ST_THREADQ); +#endif + + if ((*_st_eventsys->init)() < 0) + return -1; + + _st_this_vp.pagesize = getpagesize(); + _st_this_vp.last_clock = st_utime(); + + /* + * Create idle thread + */ + _st_this_vp.idle_thread = st_thread_create(_st_idle_thread_start, NULL, 0, 0); + if (!_st_this_vp.idle_thread) + return -1; + _st_this_vp.idle_thread->flags = _ST_FL_IDLE_THREAD; + _st_active_count--; + _ST_DEL_RUNQ(_st_this_vp.idle_thread); + + /* + * Initialize primordial thread + */ + thread = (_st_thread_t *) calloc(1, sizeof(_st_thread_t) + (ST_KEYS_MAX * sizeof(void *))); + if (!thread) + return -1; + thread->private_data = (void **) (thread + 1); + thread->state = _ST_ST_RUNNING; + thread->flags = _ST_FL_PRIMORDIAL; + _ST_SET_CURRENT_THREAD(thread); + _st_active_count++; +#ifdef DEBUG + _ST_ADD_THREADQ(thread); +#endif + + return 0; +} + + +#ifdef ST_SWITCH_CB +st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb) +{ + st_switch_cb_t ocb = _st_this_vp.switch_in_cb; + _st_this_vp.switch_in_cb = cb; + return ocb; +} + +st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb) +{ + st_switch_cb_t ocb = _st_this_vp.switch_out_cb; + _st_this_vp.switch_out_cb = cb; + return ocb; +} +#endif + + +/* + * Start function for the idle thread + */ +/* ARGSUSED */ +void *_st_idle_thread_start(void *arg) +{ + _st_thread_t *me = _ST_CURRENT_THREAD(); + + while (_st_active_count > 0) { + /* Idle vp till I/O is ready or the smallest timeout expired */ + _ST_VP_IDLE(); + + /* Check sleep queue for expired threads */ + _st_vp_check_clock(); + + me->state = _ST_ST_RUNNABLE; + _ST_SWITCH_CONTEXT(me); + } + + /* No more threads */ + exit(0); + + /* NOTREACHED */ + return NULL; +} + + +void st_thread_exit(void *retval) +{ + _st_thread_t *thread = _ST_CURRENT_THREAD(); + + thread->retval = retval; + _st_thread_cleanup(thread); + _st_active_count--; + if (thread->term) { + /* Put thread on the zombie queue */ + thread->state = _ST_ST_ZOMBIE; + _ST_ADD_ZOMBIEQ(thread); + + /* Notify on our termination condition variable */ + st_cond_signal(thread->term); + + /* Switch context and come back later */ + _ST_SWITCH_CONTEXT(thread); + + /* Continue the cleanup */ + st_cond_destroy(thread->term); + thread->term = NULL; + } + +#ifdef DEBUG + _ST_DEL_THREADQ(thread); +#endif + + /* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */ +#ifndef NVALGRIND + if (!(thread->flags & _ST_FL_PRIMORDIAL)) { + VALGRIND_STACK_DEREGISTER(thread->stack->valgrind_stack_id); + } +#endif + + if (!(thread->flags & _ST_FL_PRIMORDIAL)) + _st_stack_free(thread->stack); + + /* Find another thread to run */ + _ST_SWITCH_CONTEXT(thread); + /* Not going to land here */ +} + + +int st_thread_join(_st_thread_t *thread, void **retvalp) +{ + _st_cond_t *term = thread->term; + + /* Can't join a non-joinable thread */ + if (term == NULL) { + errno = EINVAL; + return -1; + } + if (_ST_CURRENT_THREAD() == thread) { + errno = EDEADLK; + return -1; + } + + /* Multiple threads can't wait on the same joinable thread */ + if (term->wait_q.next != &term->wait_q) { + errno = EINVAL; + return -1; + } + + while (thread->state != _ST_ST_ZOMBIE) { + if (st_cond_timedwait(term, ST_UTIME_NO_TIMEOUT) != 0) + return -1; + } + + if (retvalp) + *retvalp = thread->retval; + + /* + * Remove target thread from the zombie queue and make it runnable. + * When it gets scheduled later, it will do the clean up. + */ + thread->state = _ST_ST_RUNNABLE; + _ST_DEL_ZOMBIEQ(thread); + _ST_ADD_RUNQ(thread); + + return 0; +} + + +void _st_thread_main(void) +{ + _st_thread_t *thread = _ST_CURRENT_THREAD(); + + /* + * Cap the stack by zeroing out the saved return address register + * value. This allows some debugging/profiling tools to know when + * to stop unwinding the stack. It's a no-op on most platforms. + */ + MD_CAP_STACK(&thread); + + /* Run thread main */ + thread->retval = (*thread->start)(thread->arg); + + /* All done, time to go away */ + st_thread_exit(thread->retval); +} + + +/* + * Insert "thread" into the timeout heap, in the position + * specified by thread->heap_index. See docs/timeout_heap.txt + * for details about the timeout heap. + */ +static _st_thread_t **heap_insert(_st_thread_t *thread) { + int target = thread->heap_index; + int s = target; + _st_thread_t **p = &_ST_SLEEPQ; + int bits = 0; + int bit; + int index = 1; + + while (s) { + s >>= 1; + bits++; + } + for (bit = bits - 2; bit >= 0; bit--) { + if (thread->due < (*p)->due) { + _st_thread_t *t = *p; + thread->left = t->left; + thread->right = t->right; + *p = thread; + thread->heap_index = index; + thread = t; + } + index <<= 1; + if (target & (1 << bit)) { + p = &((*p)->right); + index |= 1; + } else { + p = &((*p)->left); + } + } + thread->heap_index = index; + *p = thread; + thread->left = thread->right = NULL; + return p; +} + + +/* + * Delete "thread" from the timeout heap. + */ +static void heap_delete(_st_thread_t *thread) { + _st_thread_t *t, **p; + int bits = 0; + int s, bit; + + /* First find and unlink the last heap element */ + p = &_ST_SLEEPQ; + s = _ST_SLEEPQ_SIZE; + while (s) { + s >>= 1; + bits++; + } + for (bit = bits - 2; bit >= 0; bit--) { + if (_ST_SLEEPQ_SIZE & (1 << bit)) { + p = &((*p)->right); + } else { + p = &((*p)->left); + } + } + t = *p; + *p = NULL; + --_ST_SLEEPQ_SIZE; + if (t != thread) { + /* + * Insert the unlinked last element in place of the element we are deleting + */ + t->heap_index = thread->heap_index; + p = heap_insert(t); + t = *p; + t->left = thread->left; + t->right = thread->right; + + /* + * Reestablish the heap invariant. + */ + for (;;) { + _st_thread_t *y; /* The younger child */ + int index_tmp; + if (t->left == NULL) + break; + else if (t->right == NULL) + y = t->left; + else if (t->left->due < t->right->due) + y = t->left; + else + y = t->right; + if (t->due > y->due) { + _st_thread_t *tl = y->left; + _st_thread_t *tr = y->right; + *p = y; + if (y == t->left) { + y->left = t; + y->right = t->right; + p = &y->left; + } else { + y->left = t->left; + y->right = t; + p = &y->right; + } + t->left = tl; + t->right = tr; + index_tmp = t->heap_index; + t->heap_index = y->heap_index; + y->heap_index = index_tmp; + } else { + break; + } + } + } + thread->left = thread->right = NULL; +} + + +void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout) +{ + thread->due = _ST_LAST_CLOCK + timeout; + thread->flags |= _ST_FL_ON_SLEEPQ; + thread->heap_index = ++_ST_SLEEPQ_SIZE; + heap_insert(thread); +} + + +void _st_del_sleep_q(_st_thread_t *thread) +{ + heap_delete(thread); + thread->flags &= ~_ST_FL_ON_SLEEPQ; +} + + +void _st_vp_check_clock(void) +{ + _st_thread_t *thread; + st_utime_t elapsed, now; + + now = st_utime(); + elapsed = now - _ST_LAST_CLOCK; + _ST_LAST_CLOCK = now; + + if (_st_curr_time && now - _st_last_tset > 999000) { + _st_curr_time = time(NULL); + _st_last_tset = now; + } + + while (_ST_SLEEPQ != NULL) { + thread = _ST_SLEEPQ; + ST_ASSERT(thread->flags & _ST_FL_ON_SLEEPQ); + if (thread->due > now) + break; + _ST_DEL_SLEEPQ(thread); + + /* If thread is waiting on condition variable, set the time out flag */ + if (thread->state == _ST_ST_COND_WAIT) + thread->flags |= _ST_FL_TIMEDOUT; + + /* Make thread runnable */ + ST_ASSERT(!(thread->flags & _ST_FL_IDLE_THREAD)); + thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(thread); + } +} + + +void st_thread_interrupt(_st_thread_t *thread) +{ + /* If thread is already dead */ + if (thread->state == _ST_ST_ZOMBIE) + return; + + thread->flags |= _ST_FL_INTERRUPT; + + if (thread->state == _ST_ST_RUNNING || thread->state == _ST_ST_RUNNABLE) + return; + + if (thread->flags & _ST_FL_ON_SLEEPQ) + _ST_DEL_SLEEPQ(thread); + + /* Make thread runnable */ + thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(thread); +} + + +/* Merge from https://github.com/michaeltalyansky/state-threads/commit/cce736426c2320ffec7c9820df49ee7a18ae638c */ +#if defined(__arm__) && !defined(MD_USE_BUILTIN_SETJMP) && __GLIBC_MINOR__ >= 19 + extern unsigned long __pointer_chk_guard; + #define PTR_MANGLE(var) \ + (var) = (__typeof (var)) ((unsigned long) (var) ^ __pointer_chk_guard) + #define PTR_DEMANGLE(var) PTR_MANGLE (var) +#endif + + +_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size) +{ + _st_thread_t *thread; + _st_stack_t *stack; + void **ptds; + char *sp; +#ifdef __ia64__ + char *bsp; +#endif + + /* Adjust stack size */ + if (stk_size == 0) + stk_size = ST_DEFAULT_STACK_SIZE; + stk_size = ((stk_size + _ST_PAGE_SIZE - 1) / _ST_PAGE_SIZE) * _ST_PAGE_SIZE; + stack = _st_stack_new(stk_size); + if (!stack) + return NULL; + + /* Allocate thread object and per-thread data off the stack */ +#if defined (MD_STACK_GROWS_DOWN) + sp = stack->stk_top; +#ifdef __ia64__ + /* + * The stack segment is split in the middle. The upper half is used + * as backing store for the register stack which grows upward. + * The lower half is used for the traditional memory stack which + * grows downward. Both stacks start in the middle and grow outward + * from each other. + */ + sp -= (stk_size >> 1); + bsp = sp; + /* Make register stack 64-byte aligned */ + if ((unsigned long)bsp & 0x3f) + bsp = bsp + (0x40 - ((unsigned long)bsp & 0x3f)); + stack->bsp = bsp + _ST_STACK_PAD_SIZE; +#endif + sp = sp - (ST_KEYS_MAX * sizeof(void *)); + ptds = (void **) sp; + sp = sp - sizeof(_st_thread_t); + thread = (_st_thread_t *) sp; + + /* Make stack 64-byte aligned */ + if ((unsigned long)sp & 0x3f) + sp = sp - ((unsigned long)sp & 0x3f); + stack->sp = sp - _ST_STACK_PAD_SIZE; +#elif defined (MD_STACK_GROWS_UP) + sp = stack->stk_bottom; + thread = (_st_thread_t *) sp; + sp = sp + sizeof(_st_thread_t); + ptds = (void **) sp; + sp = sp + (ST_KEYS_MAX * sizeof(void *)); + + /* Make stack 64-byte aligned */ + if ((unsigned long)sp & 0x3f) + sp = sp + (0x40 - ((unsigned long)sp & 0x3f)); + stack->sp = sp + _ST_STACK_PAD_SIZE; +#else +#error Unknown OS +#endif + + memset(thread, 0, sizeof(_st_thread_t)); + memset(ptds, 0, ST_KEYS_MAX * sizeof(void *)); + + /* Initialize thread */ + thread->private_data = ptds; + thread->stack = stack; + thread->start = start; + thread->arg = arg; + +#ifndef __ia64__ + /* Merge from https://github.com/michaeltalyansky/state-threads/commit/cce736426c2320ffec7c9820df49ee7a18ae638c */ + #if defined(__arm__) && !defined(MD_USE_BUILTIN_SETJMP) && __GLIBC_MINOR__ >= 19 + volatile void * lsp = PTR_MANGLE(stack->sp); + if (_setjmp ((thread)->context)) + _st_thread_main(); + (thread)->context[0].__jmpbuf[8] = (long) (lsp); + #else + _ST_INIT_CONTEXT(thread, stack->sp, _st_thread_main); + #endif +#else + _ST_INIT_CONTEXT(thread, stack->sp, stack->bsp, _st_thread_main); +#endif + + /* If thread is joinable, allocate a termination condition variable */ + if (joinable) { + thread->term = st_cond_new(); + if (thread->term == NULL) { + _st_stack_free(thread->stack); + return NULL; + } + } + + /* Make thread runnable */ + thread->state = _ST_ST_RUNNABLE; + _st_active_count++; + _ST_ADD_RUNQ(thread); +#ifdef DEBUG + _ST_ADD_THREADQ(thread); +#endif + + /* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */ +#ifndef NVALGRIND + if (!(thread->flags & _ST_FL_PRIMORDIAL)) { + thread->stack->valgrind_stack_id = VALGRIND_STACK_REGISTER(thread->stack->stk_top, thread->stack->stk_bottom); + } +#endif + + return thread; +} + + +_st_thread_t *st_thread_self(void) +{ + return _ST_CURRENT_THREAD(); +} + + +#ifdef DEBUG +/* ARGSUSED */ +void _st_show_thread_stack(_st_thread_t *thread, const char *messg) +{ + +} + +/* To be set from debugger */ +int _st_iterate_threads_flag = 0; + +void _st_iterate_threads(void) +{ + static _st_thread_t *thread = NULL; + static jmp_buf orig_jb, save_jb; + _st_clist_t *q; + + if (!_st_iterate_threads_flag) { + if (thread) { + memcpy(thread->context, save_jb, sizeof(jmp_buf)); + MD_LONGJMP(orig_jb, 1); + } + return; + } + + if (thread) { + memcpy(thread->context, save_jb, sizeof(jmp_buf)); + _st_show_thread_stack(thread, NULL); + } else { + if (MD_SETJMP(orig_jb)) { + _st_iterate_threads_flag = 0; + thread = NULL; + _st_show_thread_stack(thread, "Iteration completed"); + return; + } + thread = _ST_CURRENT_THREAD(); + _st_show_thread_stack(thread, "Iteration started"); + } + + q = thread->tlink.next; + if (q == &_ST_THREADQ) + q = q->next; + ST_ASSERT(q != &_ST_THREADQ); + thread = _ST_THREAD_THREADQ_PTR(q); + if (thread == _ST_CURRENT_THREAD()) + MD_LONGJMP(orig_jb, 1); + memcpy(save_jb, thread->context, sizeof(jmp_buf)); + MD_LONGJMP(thread->context, 1); +} +#endif /* DEBUG */ + diff --git a/trunk/3rdparty/st-srs/st.pc.in b/trunk/3rdparty/st-srs/st.pc.in new file mode 100644 index 0000000000..46c39ec522 --- /dev/null +++ b/trunk/3rdparty/st-srs/st.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libst +Description: State Thread Library +Version: @VERSION@ +Libs: -L${libdir} -lst +Cflags: -I${includedir} diff --git a/trunk/3rdparty/st-srs/st.spec b/trunk/3rdparty/st-srs/st.spec new file mode 100644 index 0000000000..4914aa1961 --- /dev/null +++ b/trunk/3rdparty/st-srs/st.spec @@ -0,0 +1,79 @@ +Summary: State Threads Library +Name: st +Version: 1.9 +Release: 1 +Copyright: MPL 1.2 or GPL 2+ +Packager: Wesley W. Terpstra +Source: http://prdownloads.sourceforge.net/state-threads/st-%{version}.tar.gz +Prefix: /usr +BuildRoot: /tmp/%{name}-%{version}-build +Group: Development/Libraries + +%description +The State Threads library has an interface similar to POSIX threads. + +However, the threads are actually all run in-process. This type of +threading allows for controlled schedualing points. It is highly useful +for designing robust and extremely scalable internet applications since +there is no resource contention and locking is generally unnecessary. + +It can be combined with traditional threading or multiple process +parallelism to take advantage of multiple processors. + +See: for further +information about how state threads improve performance. + +%package -n libst-devel +Summary: State Threads Library - Development Files +Group: Development/Libraries +Requires: libst1 + +%description -n libst-devel +Development headers and documentation for libst + +%package -n libst1 +Summary: State Threads Library - Shared Libs Major 1 +Group: System/Libraries + +%description -n libst1 +Shared libraries for running applications linked against api version 1. + +%prep +%setup -q + +%build +make CONFIG_GUESS_PATH=/usr/share/automake default-optimized + +%install +if [ -d ${RPM_BUILD_ROOT} ]; then rm -rf ${RPM_BUILD_ROOT}; fi + +mkdir -m 0755 -p ${RPM_BUILD_ROOT}/%{prefix}/lib/pkgconfig +mkdir -m 0755 -p ${RPM_BUILD_ROOT}/%{prefix}/include +mkdir -m 0755 -p ${RPM_BUILD_ROOT}/%{prefix}/share/doc/libst-devel +cp -a obj/libst.* ${RPM_BUILD_ROOT}/%{prefix}/lib +cp -a obj/st.h ${RPM_BUILD_ROOT}/%{prefix}/include +sed "s*@prefix@*%{prefix}*g" ${RPM_BUILD_ROOT}/%{prefix}/lib/pkgconfig/st.pc +cp -a docs/* ${RPM_BUILD_ROOT}/%{prefix}/share/doc/libst-devel/ +cp -a examples ${RPM_BUILD_ROOT}/%{prefix}/share/doc/libst-devel/ + +%post -n libst1 +/sbin/ldconfig %{prefix}/lib + +%files -n libst1 +%defattr(-,root,root) +%{prefix}/lib/lib*.so.* + +%files -n libst-devel +%defattr(-,root,root) +%{prefix}/include/* +%{prefix}/lib/lib*.a +%{prefix}/lib/lib*.so +%{prefix}/lib/pkgconfig/st.pc +%{prefix}/share/doc/libst-devel/* + +%clean +if [ -d ${RPM_BUILD_ROOT} ]; then rm -rf ${RPM_BUILD_ROOT}; fi + +%changelog +* Wed Dec 26 2001 Wesley W. Terpstra +- first rpms for libst-1.3.tar.gz diff --git a/trunk/3rdparty/st-srs/stk.c b/trunk/3rdparty/st-srs/stk.c new file mode 100644 index 0000000000..3e681e5954 --- /dev/null +++ b/trunk/3rdparty/st-srs/stk.c @@ -0,0 +1,173 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#include +#include +#include +#include +#include +#include "common.h" + + +/* How much space to leave between the stacks, at each end */ +#define REDZONE _ST_PAGE_SIZE + +_st_clist_t _st_free_stacks = ST_INIT_STATIC_CLIST(&_st_free_stacks); +int _st_num_free_stacks = 0; +int _st_randomize_stacks = 0; + +static char *_st_new_stk_segment(int size); + +_st_stack_t *_st_stack_new(int stack_size) +{ + _st_clist_t *qp; + _st_stack_t *ts; + int extra; + + for (qp = _st_free_stacks.next; qp != &_st_free_stacks; qp = qp->next) { + ts = _ST_THREAD_STACK_PTR(qp); + if (ts->stk_size >= stack_size) { + /* Found a stack that is big enough */ + ST_REMOVE_LINK(&ts->links); + _st_num_free_stacks--; + ts->links.next = NULL; + ts->links.prev = NULL; + return ts; + } + } + + /* Make a new thread stack object. */ + if ((ts = (_st_stack_t *)calloc(1, sizeof(_st_stack_t))) == NULL) + return NULL; + extra = _st_randomize_stacks ? _ST_PAGE_SIZE : 0; + ts->vaddr_size = stack_size + 2*REDZONE + extra; + ts->vaddr = _st_new_stk_segment(ts->vaddr_size); + if (!ts->vaddr) { + free(ts); + return NULL; + } + ts->stk_size = stack_size; + ts->stk_bottom = ts->vaddr + REDZONE; + ts->stk_top = ts->stk_bottom + stack_size; + +#ifdef DEBUG + mprotect(ts->vaddr, REDZONE, PROT_NONE); + mprotect(ts->stk_top + extra, REDZONE, PROT_NONE); +#endif + + if (extra) { + long offset = (random() % extra) & ~0xf; + + ts->stk_bottom += offset; + ts->stk_top += offset; + } + + return ts; +} + + +/* + * Free the stack for the current thread + */ +void _st_stack_free(_st_stack_t *ts) +{ + if (!ts) + return; + + /* Put the stack on the free list */ + ST_APPEND_LINK(&ts->links, _st_free_stacks.prev); + _st_num_free_stacks++; +} + + +static char *_st_new_stk_segment(int size) +{ +#ifdef MALLOC_STACK + void *vaddr = malloc(size); +#else + static int zero_fd = -1; + int mmap_flags = MAP_PRIVATE; + void *vaddr; + +#if defined (MD_USE_SYSV_ANON_MMAP) + if (zero_fd < 0) { + if ((zero_fd = open("/dev/zero", O_RDWR, 0)) < 0) + return NULL; + fcntl(zero_fd, F_SETFD, FD_CLOEXEC); + } +#elif defined (MD_USE_BSD_ANON_MMAP) + mmap_flags |= MAP_ANON; +#else +#error Unknown OS +#endif + + vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, zero_fd, 0); + if (vaddr == (void *)MAP_FAILED) + return NULL; + +#endif /* MALLOC_STACK */ + + return (char *)vaddr; +} + + +/* Not used */ +#if 0 +void _st_delete_stk_segment(char *vaddr, int size) +{ +#ifdef MALLOC_STACK + free(vaddr); +#else + (void) munmap(vaddr, size); +#endif +} +#endif + +int st_randomize_stacks(int on) +{ + int wason = _st_randomize_stacks; + + _st_randomize_stacks = on; + if (on) + srandom((unsigned int) st_utime()); + + return wason; +} diff --git a/trunk/3rdparty/st-srs/sync.c b/trunk/3rdparty/st-srs/sync.c new file mode 100644 index 0000000000..907fdfac3c --- /dev/null +++ b/trunk/3rdparty/st-srs/sync.c @@ -0,0 +1,368 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#include +#include +#include +#include "common.h" + + +extern time_t _st_curr_time; +extern st_utime_t _st_last_tset; +extern int _st_active_count; + +static st_utime_t (*_st_utime)(void) = NULL; + + +/***************************************** + * Time functions + */ + +st_utime_t st_utime(void) +{ + if (_st_utime == NULL) { +#ifdef MD_GET_UTIME + MD_GET_UTIME(); +#else +#error Unknown OS +#endif + } + + return (*_st_utime)(); +} + + +int st_set_utime_function(st_utime_t (*func)(void)) +{ + if (_st_active_count) { + errno = EINVAL; + return -1; + } + + _st_utime = func; + + return 0; +} + + +st_utime_t st_utime_last_clock(void) +{ + return _ST_LAST_CLOCK; +} + + +int st_timecache_set(int on) +{ + int wason = (_st_curr_time) ? 1 : 0; + + if (on) { + _st_curr_time = time(NULL); + _st_last_tset = st_utime(); + } else + _st_curr_time = 0; + + return wason; +} + + +time_t st_time(void) +{ + if (_st_curr_time) + return _st_curr_time; + + return time(NULL); +} + + +int st_usleep(st_utime_t usecs) +{ + _st_thread_t *me = _ST_CURRENT_THREAD(); + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + if (usecs != ST_UTIME_NO_TIMEOUT) { + me->state = _ST_ST_SLEEPING; + _ST_ADD_SLEEPQ(me, usecs); + } else + me->state = _ST_ST_SUSPENDED; + + _ST_SWITCH_CONTEXT(me); + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + return 0; +} + + +int st_sleep(int secs) +{ + return st_usleep((secs >= 0) ? secs * (st_utime_t) 1000000LL : ST_UTIME_NO_TIMEOUT); +} + + +/***************************************** + * Condition variable functions + */ + +_st_cond_t *st_cond_new(void) +{ + _st_cond_t *cvar; + + cvar = (_st_cond_t *) calloc(1, sizeof(_st_cond_t)); + if (cvar) { + ST_INIT_CLIST(&cvar->wait_q); + } + + return cvar; +} + + +int st_cond_destroy(_st_cond_t *cvar) +{ + if (cvar->wait_q.next != &cvar->wait_q) { + errno = EBUSY; + return -1; + } + + free(cvar); + + return 0; +} + + +int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout) +{ + _st_thread_t *me = _ST_CURRENT_THREAD(); + int rv; + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + /* Put caller thread on the condition variable's wait queue */ + me->state = _ST_ST_COND_WAIT; + ST_APPEND_LINK(&me->wait_links, &cvar->wait_q); + + if (timeout != ST_UTIME_NO_TIMEOUT) + _ST_ADD_SLEEPQ(me, timeout); + + _ST_SWITCH_CONTEXT(me); + + ST_REMOVE_LINK(&me->wait_links); + rv = 0; + + if (me->flags & _ST_FL_TIMEDOUT) { + me->flags &= ~_ST_FL_TIMEDOUT; + errno = ETIME; + rv = -1; + } + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + rv = -1; + } + + return rv; +} + + +int st_cond_wait(_st_cond_t *cvar) +{ + return st_cond_timedwait(cvar, ST_UTIME_NO_TIMEOUT); +} + + +static int _st_cond_signal(_st_cond_t *cvar, int broadcast) +{ + _st_thread_t *thread; + _st_clist_t *q; + + for (q = cvar->wait_q.next; q != &cvar->wait_q; q = q->next) { + thread = _ST_THREAD_WAITQ_PTR(q); + if (thread->state == _ST_ST_COND_WAIT) { + if (thread->flags & _ST_FL_ON_SLEEPQ) + _ST_DEL_SLEEPQ(thread); + + /* Make thread runnable */ + thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(thread); + if (!broadcast) + break; + } + } + + return 0; +} + + +int st_cond_signal(_st_cond_t *cvar) +{ + return _st_cond_signal(cvar, 0); +} + + +int st_cond_broadcast(_st_cond_t *cvar) +{ + return _st_cond_signal(cvar, 1); +} + + +/***************************************** + * Mutex functions + */ + +_st_mutex_t *st_mutex_new(void) +{ + _st_mutex_t *lock; + + lock = (_st_mutex_t *) calloc(1, sizeof(_st_mutex_t)); + if (lock) { + ST_INIT_CLIST(&lock->wait_q); + lock->owner = NULL; + } + + return lock; +} + + +int st_mutex_destroy(_st_mutex_t *lock) +{ + if (lock->owner != NULL || lock->wait_q.next != &lock->wait_q) { + errno = EBUSY; + return -1; + } + + free(lock); + + return 0; +} + + +int st_mutex_lock(_st_mutex_t *lock) +{ + _st_thread_t *me = _ST_CURRENT_THREAD(); + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + if (lock->owner == NULL) { + /* Got the mutex */ + lock->owner = me; + return 0; + } + + if (lock->owner == me) { + errno = EDEADLK; + return -1; + } + + /* Put caller thread on the mutex's wait queue */ + me->state = _ST_ST_LOCK_WAIT; + ST_APPEND_LINK(&me->wait_links, &lock->wait_q); + + _ST_SWITCH_CONTEXT(me); + + ST_REMOVE_LINK(&me->wait_links); + + if ((me->flags & _ST_FL_INTERRUPT) && lock->owner != me) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + return 0; +} + + +int st_mutex_unlock(_st_mutex_t *lock) +{ + _st_thread_t *thread; + _st_clist_t *q; + + if (lock->owner != _ST_CURRENT_THREAD()) { + errno = EPERM; + return -1; + } + + for (q = lock->wait_q.next; q != &lock->wait_q; q = q->next) { + thread = _ST_THREAD_WAITQ_PTR(q); + if (thread->state == _ST_ST_LOCK_WAIT) { + lock->owner = thread; + /* Make thread runnable */ + thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(thread); + return 0; + } + } + + /* No threads waiting on this mutex */ + lock->owner = NULL; + + return 0; +} + + +int st_mutex_trylock(_st_mutex_t *lock) +{ + if (lock->owner != NULL) { + errno = EBUSY; + return -1; + } + + /* Got the mutex */ + lock->owner = _ST_CURRENT_THREAD(); + + return 0; +} + diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index 843439357e..a4c8730dfe 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -212,23 +212,34 @@ if [[ $OS_IS_UBUNTU = NO && $OS_IS_CENTOS = NO && $SRS_EXPORT_LIBRTMP_PROJECT = fi ##################################################################################### -# libco +# state-threads ##################################################################################### if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then - if [[ -f ${SRS_OBJS}/co/libcolib.a ]]; then - echo "The libco is ok."; + # check the cross build flag file, if flag changed, need to rebuild the st. + _ST_MAKE=linux-debug && _ST_EXTRA_CFLAGS="-DMD_HAVE_EPOLL" + if [[ $SRS_VALGRIND == YES ]]; then + _ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -DMD_VALGRIND" + fi + # Pass the global extra flags. + if [[ $SRS_EXTRA_FLAGS != '' ]]; then + _ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS $SRS_EXTRA_FLAGS" + fi + # Patched ST from https://github.com/ossrs/state-threads/tree/srs + if [[ -f ${SRS_OBJS}/st/libst.a ]]; then + echo "The state-threads is ok."; else - echo "Building libco."; + echo "Building state-threads."; ( - rm -rf ${SRS_OBJS}/co && cd ${SRS_OBJS} && - ln -sf ../3rdparty/libco && cd libco && - make clean && make colib && - cd .. && rm -f co && ln -sf libco/ co + rm -rf ${SRS_OBJS}/st-srs && cd ${SRS_OBJS} && + ln -sf ../3rdparty/st-srs && cd st-srs && + make clean && make ${_ST_MAKE} EXTRA_CFLAGS="${_ST_EXTRA_CFLAGS}" \ + CC=${SRS_TOOL_CC} AR=${SRS_TOOL_AR} LD=${SRS_TOOL_LD} RANDLIB=${SRS_TOOL_RANDLIB} && + cd .. && rm -f st && ln -sf st-srs/obj st ) fi # check status - ret=$?; if [[ $ret -ne 0 ]]; then echo "Build libco failed, ret=$ret"; exit $ret; fi - if [ ! -f ${SRS_OBJS}/co/lib/libcolib.a ]; then echo "Build libco static lib failed."; exit -1; fi + ret=$?; if [[ $ret -ne 0 ]]; then echo "Build state-threads failed, ret=$ret"; exit $ret; fi + if [ ! -f ${SRS_OBJS}/st/libst.a ]; then echo "Build state-threads static lib failed."; exit -1; fi fi ##################################################################################### diff --git a/trunk/configure b/trunk/configure index e67644a200..d233f66dbb 100755 --- a/trunk/configure +++ b/trunk/configure @@ -142,12 +142,12 @@ END ##################################################################################### # Libraries, external library to build in srs, -# header(.h): add to ModuleLibIncs if need the specified library. for example, LibCoRoot -# library(.a): add to ModuleLibFiles if binary need the specifeid library. for example, LibCofile +# header(.h): add to ModuleLibIncs if need the specified library. for example, LibSTRoot +# library(.a): add to ModuleLibFiles if binary need the specifeid library. for example, LibSTfile # -# libco the basic network library for SRS. -LibcoRoot="${SRS_OBJS_DIR}/co"; Libcofile="${LibcoRoot}/lib/libcolib.a -lpthread" -if [[ $SRS_SHARED_LIBCO == YES ]]; then Libcofile="-lcolib -lpthread"; fi +# st(state-threads) the basic network library for SRS. +LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a" +if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-lst"; fi # openssl-1.1.0e, for the RTMP complex handshake. LibSSLRoot="";LibSSLfile="" if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == NO ]]; then @@ -233,7 +233,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVICE" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL") - ModuleLibIncs=(${LibcoRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_service_log" "srs_service_st" "srs_service_http_client" "srs_service_http_conn" "srs_service_rtmp_conn" "srs_service_utility" "srs_service_conn") @@ -246,7 +246,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibcoRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -284,7 +284,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then if [[ $SRS_SRT == YES ]]; then MODULE_DEPENDS+=("SRT") fi - ModuleLibIncs=(${LibcoRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi @@ -297,7 +297,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="MAIN" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibcoRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) MODULE_FILES=() DEFINES="" # add each modules for main @@ -324,24 +324,24 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then done # # all depends libraries - ModuleLibFiles=(${Libcofile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi # all depends objects MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" - ModuleLibIncs=(${LibcoRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then MODULE_OBJS="${MODULE_OBJS} ${SRT_OBJS[@]}" fi LINK_OPTIONS="${SrsLinkOptions}${SrsGprofLink}${SrsGperfLink}" # - # srs: srs(simple rtmp server) over co(libco) + # srs: srs(simple rtmp server) over st(state-threads) BUILD_KEY="srs" APP_MAIN="srs_main_server" APP_NAME="srs" . auto/apps.sh # # For modules, without the app module. MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" - ModuleLibFiles=(${Libcofile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) # for SRS_MODULE in ${SRS_MODULES[*]}; do . $SRS_MODULE/config @@ -361,11 +361,11 @@ if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibcoRoot} ${LibSSLRoot}) + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi - ModuleLibFiles=(${Libcofile} ${LibSSLfile}) + ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi @@ -413,7 +413,7 @@ help: @echo "Usage: make |||||||" @echo " help display this help menu" @echo " clean cleanup project" - @echo " server build the srs(simple rtmp server) over co(libco)" + @echo " server build the srs(simple rtmp server) over st(state-threads)" @echo " librtmp build the client publish/play library, and samples" @echo " utest build the utest for srs" @echo " install install srs to the prefix path" @@ -451,7 +451,7 @@ END else cat << END >> ${SRS_WORKDIR}/${SRS_MAKEFILE} server: _prepare_dir - @echo "Build the srs(simple rtmp server) over co(libco)" + @echo "Build the srs(simple rtmp server) over ST(state-threads)" \$(MAKE) -f ${SRS_OBJS_DIR}/${SRS_MAKEFILE} srs END diff --git a/trunk/research/st/Makefile b/trunk/research/st/Makefile new file mode 100755 index 0000000000..0b24bb80c2 --- /dev/null +++ b/trunk/research/st/Makefile @@ -0,0 +1,100 @@ +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Netscape Portable Runtime library. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1994-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): Silicon Graphics, Inc. +# +# Portions created by SGI are Copyright (C) 2000-2001 Silicon +# Graphics, Inc. All Rights Reserved. +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. + +########################## +# Target dir and cc: +CC = cc +TARGETDIR = objs + +########################## +# Supported OSes: +OS = LINUX + +ifneq ($(shell test -f /usr/include/sys/epoll.h && echo yes), yes) +default: + @echo "epoll not found" + @exit 1 +endif + +EXTRA_OBJS = $(TARGETDIR)/md.o + +CFLAGS = +OTHER_FLAGS += -Wall -g -O0 +DEFINES = -D$(OS) -DDEBUG -DMD_HAVE_EPOLL -DMALLOC_STACK + +########################## +# Other possible defines: +# To use malloc(3) instead of mmap(2) for stack allocation: +# DEFINES += -DMALLOC_STACK +# +# To provision more than the default 16 thread-specific-data keys +# (but not too many!): +# DEFINES += -DST_KEYS_MAX= +# +# Note that you can also add these defines by specifying them as +# make/gmake arguments (without editing this Makefile). For example: +# +# make EXTRA_CFLAGS=-UMD_HAVE_EPOLL +# +########################## + +CFLAGS += $(DEFINES) $(OTHER_FLAGS) $(EXTRA_CFLAGS) + +OBJS = $(TARGETDIR)/sched.o \ + $(TARGETDIR)/stk.o \ + $(TARGETDIR)/sync.o \ + $(TARGETDIR)/key.o \ + $(TARGETDIR)/io.o \ + $(TARGETDIR)/event.o \ + $(TARGETDIR)/srs.o +OBJS += $(EXTRA_OBJS) +SRS = $(TARGETDIR)/srs + +linux-debug: all +all: $(TARGETDIR) $(SRS) + +$(TARGETDIR): + if [ ! -d $(TARGETDIR) ]; then mkdir $(TARGETDIR); fi + +$(SRS): $(OBJS) + $(CC) $(CFLAGS) -o $@ $(OBJS) + +$(TARGETDIR)/md.o: md.S + $(CC) $(CFLAGS) -c $< -o $@ + +$(TARGETDIR)/%.o: %.c common.h md.h Makefile + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -rf $(TARGETDIR) diff --git a/trunk/research/st/common.h b/trunk/research/st/common.h new file mode 100644 index 0000000000..b83e575caf --- /dev/null +++ b/trunk/research/st/common.h @@ -0,0 +1,445 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#ifndef __ST_COMMON_H__ +#define __ST_COMMON_H__ + +#include +#include +#include +#include +#include + +/* Enable assertions only if DEBUG is defined */ +#ifndef DEBUG + #define NDEBUG +#endif +#include +#define ST_ASSERT(expr) assert(expr) + +#define ST_BEGIN_MACRO { +#define ST_END_MACRO } + +#ifdef DEBUG + #define ST_HIDDEN /*nothing*/ +#else + #define ST_HIDDEN static +#endif + +#include "public.h" +#include "md.h" + +/***************************************** + * Circular linked list definitions + */ + +typedef struct _st_clist { + struct _st_clist *next; + struct _st_clist *prev; +} _st_clist_t; + +/* Insert element "_e" into the list, before "_l" */ +#define ST_INSERT_BEFORE(_e,_l) \ + ST_BEGIN_MACRO \ + (_e)->next = (_l); \ + (_e)->prev = (_l)->prev; \ + (_l)->prev->next = (_e); \ + (_l)->prev = (_e); \ + ST_END_MACRO + +/* Insert element "_e" into the list, after "_l" */ +#define ST_INSERT_AFTER(_e,_l) \ + ST_BEGIN_MACRO \ + (_e)->next = (_l)->next; \ + (_e)->prev = (_l); \ + (_l)->next->prev = (_e); \ + (_l)->next = (_e); \ + ST_END_MACRO + +/* Return the element following element "_e" */ +#define ST_NEXT_LINK(_e) ((_e)->next) + +/* Append an element "_e" to the end of the list "_l" */ +#define ST_APPEND_LINK(_e,_l) ST_INSERT_BEFORE(_e,_l) + +/* Insert an element "_e" at the head of the list "_l" */ +#define ST_INSERT_LINK(_e,_l) ST_INSERT_AFTER(_e,_l) + +/* Return the head/tail of the list */ +#define ST_LIST_HEAD(_l) (_l)->next +#define ST_LIST_TAIL(_l) (_l)->prev + +/* Remove the element "_e" from it's circular list */ +#define ST_REMOVE_LINK(_e) \ + ST_BEGIN_MACRO \ + (_e)->prev->next = (_e)->next; \ + (_e)->next->prev = (_e)->prev; \ + ST_END_MACRO + +/* Return non-zero if the given circular list "_l" is empty, */ +/* zero if the circular list is not empty */ +#define ST_CLIST_IS_EMPTY(_l) \ + ((_l)->next == (_l)) + +/* Initialize a circular list */ +#define ST_INIT_CLIST(_l) \ + ST_BEGIN_MACRO \ + (_l)->next = (_l); \ + (_l)->prev = (_l); \ + ST_END_MACRO + +#define ST_INIT_STATIC_CLIST(_l) \ + {(_l), (_l)} + + +/***************************************** + * Basic types definitions + */ + +typedef void (*_st_destructor_t)(void *); + +typedef struct _st_stack { + _st_clist_t links; + char *vaddr; /* Base of stack's allocated memory */ + int vaddr_size; /* Size of stack's allocated memory */ + int stk_size; /* Size of usable portion of the stack */ + char *stk_bottom; /* Lowest address of stack's usable portion */ + char *stk_top; /* Highest address of stack's usable portion */ + void *sp; /* Stack pointer from C's point of view */ +} _st_stack_t; + + +typedef struct _st_cond { + _st_clist_t wait_q; /* Condition variable wait queue */ +} _st_cond_t; + + +typedef struct _st_thread _st_thread_t; + +struct _st_thread { + int state; /* Thread's state */ + int flags; /* Thread's flags */ + + void *(*start)(void *arg); /* The start function of the thread */ + void *arg; /* Argument of the start function */ + void *retval; /* Return value of the start function */ + + _st_stack_t *stack; /* Info about thread's stack */ + + _st_clist_t links; /* For putting on run/sleep/zombie queue */ + _st_clist_t wait_links; /* For putting on mutex/condvar wait queue */ + #ifdef DEBUG + _st_clist_t tlink; /* For putting on thread queue */ + #endif + + st_utime_t due; /* Wakeup time when thread is sleeping */ + _st_thread_t *left; /* For putting in timeout heap */ + _st_thread_t *right; /* -- see docs/timeout_heap.txt for details */ + int heap_index; + + void **private_data; /* Per thread private data */ + + _st_cond_t *term; /* Termination condition variable for join */ + + jmp_buf context; /* Thread's context */ +}; + + +typedef struct _st_mutex { + _st_thread_t *owner; /* Current mutex owner */ + _st_clist_t wait_q; /* Mutex wait queue */ +} _st_mutex_t; + + +typedef struct _st_pollq { + _st_clist_t links; /* For putting on io queue */ + _st_thread_t *thread; /* Polling thread */ + struct pollfd *pds; /* Array of poll descriptors */ + int npds; /* Length of the array */ + int on_ioq; /* Is it on ioq? */ +} _st_pollq_t; + + +typedef struct _st_eventsys_ops { + const char *name; /* Name of this event system */ + int val; /* Type of this event system */ + int (*init)(void); /* Initialization */ + void (*dispatch)(void); /* Dispatch function */ + int (*pollset_add)(struct pollfd *, int); /* Add descriptor set */ + void (*pollset_del)(struct pollfd *, int); /* Delete descriptor set */ + int (*fd_new)(int); /* New descriptor allocated */ + int (*fd_close)(int); /* Descriptor closed */ + int (*fd_getlimit)(void); /* Descriptor hard limit */ +} _st_eventsys_t; + + +typedef struct _st_vp { + _st_thread_t *idle_thread; /* Idle thread for this vp */ + st_utime_t last_clock; /* The last time we went into vp_check_clock() */ + + _st_clist_t run_q; /* run queue for this vp */ + _st_clist_t io_q; /* io queue for this vp */ + _st_clist_t zombie_q; /* zombie queue for this vp */ + #ifdef DEBUG + _st_clist_t thread_q; /* all threads of this vp */ + #endif + int pagesize; + + _st_thread_t *sleep_q; /* sleep queue for this vp */ + int sleepq_size; /* number of threads on sleep queue */ + + #ifdef ST_SWITCH_CB + st_switch_cb_t switch_out_cb; /* called when a thread is switched out */ + st_switch_cb_t switch_in_cb; /* called when a thread is switched in */ + #endif +} _st_vp_t; + + +typedef struct _st_netfd { + int osfd; /* Underlying OS file descriptor */ + int inuse; /* In-use flag */ + void *private_data; /* Per descriptor private data */ + _st_destructor_t destructor; /* Private data destructor function */ + void *aux_data; /* Auxiliary data for internal use */ + struct _st_netfd *next; /* For putting on the free list */ +} _st_netfd_t; + + +/***************************************** + * Current vp, thread, and event system + */ + +extern _st_vp_t _st_this_vp; +extern _st_thread_t *_st_this_thread; +extern _st_eventsys_t *_st_eventsys; + +#define _ST_CURRENT_THREAD() (_st_this_thread) +#define _ST_SET_CURRENT_THREAD(_thread) (_st_this_thread = (_thread)) + +#define _ST_LAST_CLOCK (_st_this_vp.last_clock) + +#define _ST_RUNQ (_st_this_vp.run_q) +#define _ST_IOQ (_st_this_vp.io_q) +#define _ST_ZOMBIEQ (_st_this_vp.zombie_q) +#ifdef DEBUG + #define _ST_THREADQ (_st_this_vp.thread_q) +#endif + +#define _ST_PAGE_SIZE (_st_this_vp.pagesize) + +#define _ST_SLEEPQ (_st_this_vp.sleep_q) +#define _ST_SLEEPQ_SIZE (_st_this_vp.sleepq_size) + +#define _ST_VP_IDLE() (*_st_eventsys->dispatch)() + + +/***************************************** + * vp queues operations + */ + +#define _ST_ADD_IOQ(_pq) ST_APPEND_LINK(&_pq.links, &_ST_IOQ) +#define _ST_DEL_IOQ(_pq) ST_REMOVE_LINK(&_pq.links) + +#define _ST_ADD_RUNQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_RUNQ) +#define _ST_DEL_RUNQ(_thr) ST_REMOVE_LINK(&(_thr)->links) + +#define _ST_ADD_SLEEPQ(_thr, _timeout) _st_add_sleep_q(_thr, _timeout) +#define _ST_DEL_SLEEPQ(_thr) _st_del_sleep_q(_thr) + +#define _ST_ADD_ZOMBIEQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_ZOMBIEQ) +#define _ST_DEL_ZOMBIEQ(_thr) ST_REMOVE_LINK(&(_thr)->links) + +#ifdef DEBUG + #define _ST_ADD_THREADQ(_thr) ST_APPEND_LINK(&(_thr)->tlink, &_ST_THREADQ) + #define _ST_DEL_THREADQ(_thr) ST_REMOVE_LINK(&(_thr)->tlink) +#endif + + +/***************************************** + * Thread states and flags + */ + +#define _ST_ST_RUNNING 0 +#define _ST_ST_RUNNABLE 1 +#define _ST_ST_IO_WAIT 2 +#define _ST_ST_LOCK_WAIT 3 +#define _ST_ST_COND_WAIT 4 +#define _ST_ST_SLEEPING 5 +#define _ST_ST_ZOMBIE 6 +#define _ST_ST_SUSPENDED 7 + +#define _ST_FL_PRIMORDIAL 0x01 +#define _ST_FL_IDLE_THREAD 0x02 +#define _ST_FL_ON_SLEEPQ 0x04 +#define _ST_FL_INTERRUPT 0x08 +#define _ST_FL_TIMEDOUT 0x10 + +/***************************************** + * Pointer conversion + */ + +#ifndef offsetof + #define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier)) +#endif + +#define _ST_THREAD_PTR(_qp) \ + ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, links))) + +#define _ST_THREAD_WAITQ_PTR(_qp) \ + ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, wait_links))) + +#define _ST_THREAD_STACK_PTR(_qp) \ + ((_st_stack_t *)((char*)(_qp) - offsetof(_st_stack_t, links))) + +#define _ST_POLLQUEUE_PTR(_qp) \ + ((_st_pollq_t *)((char *)(_qp) - offsetof(_st_pollq_t, links))) + +#ifdef DEBUG + #define _ST_THREAD_THREADQ_PTR(_qp) \ + ((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, tlink))) +#endif + + +/***************************************** + * Constants + */ + +#ifndef ST_UTIME_NO_TIMEOUT + #define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL) +#endif + +#define ST_DEFAULT_STACK_SIZE (64*1024) + +#ifndef ST_KEYS_MAX + #define ST_KEYS_MAX 16 +#endif + +#ifndef ST_MIN_POLLFDS_SIZE + #define ST_MIN_POLLFDS_SIZE 64 +#endif + + +/***************************************** + * Threads context switching + */ + +#ifdef DEBUG + void _st_iterate_threads(void); + #define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads() +#else + #define ST_DEBUG_ITERATE_THREADS() +#endif + +#ifdef ST_SWITCH_CB + #define ST_SWITCH_OUT_CB(_thread) \ + if (_st_this_vp.switch_out_cb != NULL && \ + _thread != _st_this_vp.idle_thread && \ + _thread->state != _ST_ST_ZOMBIE) { \ + _st_this_vp.switch_out_cb(); \ + } + #define ST_SWITCH_IN_CB(_thread) \ + if (_st_this_vp.switch_in_cb != NULL && \ + _thread != _st_this_vp.idle_thread && \ + _thread->state != _ST_ST_ZOMBIE) { \ + _st_this_vp.switch_in_cb(); \ + } +#else + #define ST_SWITCH_OUT_CB(_thread) + #define ST_SWITCH_IN_CB(_thread) +#endif + +/* + * Switch away from the current thread context by saving its state and + * calling the thread scheduler + */ +#define _ST_SWITCH_CONTEXT(_thread) \ + ST_BEGIN_MACRO \ + ST_SWITCH_OUT_CB(_thread); \ + if (!MD_SETJMP((_thread)->context)) { \ + _st_vp_schedule(); \ + } \ + ST_DEBUG_ITERATE_THREADS(); \ + ST_SWITCH_IN_CB(_thread); \ + ST_END_MACRO + +/* + * Restore a thread context that was saved by _ST_SWITCH_CONTEXT or + * initialized by _ST_INIT_CONTEXT + */ +#define _ST_RESTORE_CONTEXT(_thread) \ + ST_BEGIN_MACRO \ + _ST_SET_CURRENT_THREAD(_thread); \ + MD_LONGJMP((_thread)->context, 1); \ + ST_END_MACRO + +/* + * Number of bytes reserved under the stack "bottom" + */ +#define _ST_STACK_PAD_SIZE MD_STACK_PAD_SIZE + + +/***************************************** + * Forward declarations + */ + +void _st_vp_schedule(void); +void _st_vp_check_clock(void); +void *_st_idle_thread_start(void *arg); +void _st_thread_main(void); +void _st_thread_cleanup(_st_thread_t *thread); +void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout); +void _st_del_sleep_q(_st_thread_t *thread); +_st_stack_t *_st_stack_new(int stack_size); +void _st_stack_free(_st_stack_t *ts); +int _st_io_init(void); + +st_utime_t st_utime(void); +_st_cond_t *st_cond_new(void); +int st_cond_destroy(_st_cond_t *cvar); +int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout); +int st_cond_signal(_st_cond_t *cvar); +ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout); +ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout); +int st_poll(struct pollfd *pds, int npds, st_utime_t timeout); +_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size); + +#endif /* !__ST_COMMON_H__ */ + diff --git a/trunk/research/st/event.c b/trunk/research/st/event.c new file mode 100644 index 0000000000..5704f520a9 --- /dev/null +++ b/trunk/research/st/event.c @@ -0,0 +1,483 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * Yahoo! Inc. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" + +#ifdef USE_POLL + #error "Not support USE_POLL" +#endif +#ifdef MD_HAVE_KQUEUE + #error "Not support MD_HAVE_KQUEUE" +#endif +#ifdef MD_HAVE_POLL + #error "Not support MD_HAVE_POLL" +#endif +#ifndef MD_HAVE_EPOLL + #error "Only support MD_HAVE_EPOLL" +#endif + +#include + +typedef struct _epoll_fd_data { + int rd_ref_cnt; + int wr_ref_cnt; + int ex_ref_cnt; + int revents; +} _epoll_fd_data_t; + +static struct _st_epolldata { + _epoll_fd_data_t *fd_data; + struct epoll_event *evtlist; + int fd_data_size; + int evtlist_size; + int evtlist_cnt; + int fd_hint; + int epfd; + pid_t pid; +} *_st_epoll_data; + +#ifndef ST_EPOLL_EVTLIST_SIZE +/* Not a limit, just a hint */ +#define ST_EPOLL_EVTLIST_SIZE 4096 +#endif + +#define _ST_EPOLL_READ_CNT(fd) (_st_epoll_data->fd_data[fd].rd_ref_cnt) +#define _ST_EPOLL_WRITE_CNT(fd) (_st_epoll_data->fd_data[fd].wr_ref_cnt) +#define _ST_EPOLL_EXCEP_CNT(fd) (_st_epoll_data->fd_data[fd].ex_ref_cnt) +#define _ST_EPOLL_REVENTS(fd) (_st_epoll_data->fd_data[fd].revents) + +#define _ST_EPOLL_READ_BIT(fd) (_ST_EPOLL_READ_CNT(fd) ? EPOLLIN : 0) +#define _ST_EPOLL_WRITE_BIT(fd) (_ST_EPOLL_WRITE_CNT(fd) ? EPOLLOUT : 0) +#define _ST_EPOLL_EXCEP_BIT(fd) (_ST_EPOLL_EXCEP_CNT(fd) ? EPOLLPRI : 0) +#define _ST_EPOLL_EVENTS(fd) \ + (_ST_EPOLL_READ_BIT(fd)|_ST_EPOLL_WRITE_BIT(fd)|_ST_EPOLL_EXCEP_BIT(fd)) + +_st_eventsys_t *_st_eventsys = NULL; + +/***************************************** + * epoll event system + */ + +ST_HIDDEN int _st_epoll_init(void) +{ + int fdlim; + int err = 0; + int rv = 0; + + _st_epoll_data = (struct _st_epolldata *) calloc(1, sizeof(*_st_epoll_data)); + if (!_st_epoll_data) { + return -1; + } + + fdlim = st_getfdlimit(); + _st_epoll_data->fd_hint = (fdlim > 0 && fdlim < ST_EPOLL_EVTLIST_SIZE) ? fdlim : ST_EPOLL_EVTLIST_SIZE; + + if ((_st_epoll_data->epfd = epoll_create(_st_epoll_data->fd_hint)) < 0) { + err = errno; + rv = -1; + goto cleanup_epoll; + } + fcntl(_st_epoll_data->epfd, F_SETFD, FD_CLOEXEC); + _st_epoll_data->pid = getpid(); + + /* Allocate file descriptor data array */ + _st_epoll_data->fd_data_size = _st_epoll_data->fd_hint; + _st_epoll_data->fd_data = (_epoll_fd_data_t *)calloc(_st_epoll_data->fd_data_size, sizeof(_epoll_fd_data_t)); + if (!_st_epoll_data->fd_data) { + err = errno; + rv = -1; + goto cleanup_epoll; + } + + /* Allocate event lists */ + _st_epoll_data->evtlist_size = _st_epoll_data->fd_hint; + _st_epoll_data->evtlist = (struct epoll_event *)malloc(_st_epoll_data->evtlist_size * sizeof(struct epoll_event)); + if (!_st_epoll_data->evtlist) { + err = errno; + rv = -1; + } + + cleanup_epoll: + if (rv < 0) { + if (_st_epoll_data->epfd >= 0) { + close(_st_epoll_data->epfd); + } + free(_st_epoll_data->fd_data); + free(_st_epoll_data->evtlist); + free(_st_epoll_data); + _st_epoll_data = NULL; + errno = err; + } + + return rv; +} + +ST_HIDDEN int _st_epoll_fd_data_expand(int maxfd) +{ + _epoll_fd_data_t *ptr; + int n = _st_epoll_data->fd_data_size; + + while (maxfd >= n) { + n <<= 1; + } + + ptr = (_epoll_fd_data_t *)realloc(_st_epoll_data->fd_data, n * sizeof(_epoll_fd_data_t)); + if (!ptr) { + return -1; + } + + memset(ptr + _st_epoll_data->fd_data_size, 0, (n - _st_epoll_data->fd_data_size) * sizeof(_epoll_fd_data_t)); + + _st_epoll_data->fd_data = ptr; + _st_epoll_data->fd_data_size = n; + + return 0; +} + +ST_HIDDEN void _st_epoll_evtlist_expand(void) +{ + struct epoll_event *ptr; + int n = _st_epoll_data->evtlist_size; + + while (_st_epoll_data->evtlist_cnt > n) { + n <<= 1; + } + + ptr = (struct epoll_event *)realloc(_st_epoll_data->evtlist, n * sizeof(struct epoll_event)); + if (ptr) { + _st_epoll_data->evtlist = ptr; + _st_epoll_data->evtlist_size = n; + } +} + +ST_HIDDEN void _st_epoll_pollset_del(struct pollfd *pds, int npds) +{ + struct epoll_event ev; + struct pollfd *pd; + struct pollfd *epd = pds + npds; + int old_events, events, op; + + /* + * It's more or less OK if deleting fails because a descriptor + * will either be closed or deleted in dispatch function after + * it fires. + */ + for (pd = pds; pd < epd; pd++) { + old_events = _ST_EPOLL_EVENTS(pd->fd); + + if (pd->events & POLLIN) { + _ST_EPOLL_READ_CNT(pd->fd)--; + } + if (pd->events & POLLOUT) { + _ST_EPOLL_WRITE_CNT(pd->fd)--; + } + if (pd->events & POLLPRI) { + _ST_EPOLL_EXCEP_CNT(pd->fd)--; + } + + events = _ST_EPOLL_EVENTS(pd->fd); + /* + * The _ST_EPOLL_REVENTS check below is needed so we can use + * this function inside dispatch(). Outside of dispatch() + * _ST_EPOLL_REVENTS is always zero for all descriptors. + */ + if (events != old_events && _ST_EPOLL_REVENTS(pd->fd) == 0) { + op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; + ev.events = events; + ev.data.fd = pd->fd; + if (epoll_ctl(_st_epoll_data->epfd, op, pd->fd, &ev) == 0 && op == EPOLL_CTL_DEL) { + _st_epoll_data->evtlist_cnt--; + } + } + } +} + +ST_HIDDEN int _st_epoll_pollset_add(struct pollfd *pds, int npds) +{ + struct epoll_event ev; + int i, fd; + int old_events, events, op; + + /* Do as many checks as possible up front */ + for (i = 0; i < npds; i++) { + fd = pds[i].fd; + if (fd < 0 || !pds[i].events || (pds[i].events & ~(POLLIN | POLLOUT | POLLPRI))) { + errno = EINVAL; + return -1; + } + if (fd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(fd) < 0) { + return -1; + } + } + + for (i = 0; i < npds; i++) { + fd = pds[i].fd; + old_events = _ST_EPOLL_EVENTS(fd); + + if (pds[i].events & POLLIN) { + _ST_EPOLL_READ_CNT(fd)++; + } + if (pds[i].events & POLLOUT) { + _ST_EPOLL_WRITE_CNT(fd)++; + } + if (pds[i].events & POLLPRI) { + _ST_EPOLL_EXCEP_CNT(fd)++; + } + + events = _ST_EPOLL_EVENTS(fd); + if (events != old_events) { + op = old_events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; + ev.events = events; + ev.data.fd = fd; + if (epoll_ctl(_st_epoll_data->epfd, op, fd, &ev) < 0 && (op != EPOLL_CTL_ADD || errno != EEXIST)) { + break; + } + if (op == EPOLL_CTL_ADD) { + _st_epoll_data->evtlist_cnt++; + if (_st_epoll_data->evtlist_cnt > _st_epoll_data->evtlist_size) { + _st_epoll_evtlist_expand(); + } + } + } + } + + if (i < npds) { + /* Error */ + int err = errno; + /* Unroll the state */ + _st_epoll_pollset_del(pds, i + 1); + errno = err; + return -1; + } + + return 0; +} + +ST_HIDDEN void _st_epoll_dispatch(void) +{ + st_utime_t min_timeout; + _st_clist_t *q; + _st_pollq_t *pq; + struct pollfd *pds, *epds; + struct epoll_event ev; + int timeout, nfd, i, osfd, notify; + int events, op; + short revents; + + if (_ST_SLEEPQ == NULL) { + timeout = -1; + } else { + min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 : (_ST_SLEEPQ->due - _ST_LAST_CLOCK); + timeout = (int) (min_timeout / 1000); + } + + if (_st_epoll_data->pid != getpid()) { + // WINLIN: remove it for bug introduced. + // @see: https://github.com/ossrs/srs/issues/193 + exit(-1); + } + + /* Check for I/O operations */ + nfd = epoll_wait(_st_epoll_data->epfd, _st_epoll_data->evtlist, _st_epoll_data->evtlist_size, timeout); + + if (nfd > 0) { + for (i = 0; i < nfd; i++) { + osfd = _st_epoll_data->evtlist[i].data.fd; + _ST_EPOLL_REVENTS(osfd) = _st_epoll_data->evtlist[i].events; + if (_ST_EPOLL_REVENTS(osfd) & (EPOLLERR | EPOLLHUP)) { + /* Also set I/O bits on error */ + _ST_EPOLL_REVENTS(osfd) |= _ST_EPOLL_EVENTS(osfd); + } + } + + for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) { + pq = _ST_POLLQUEUE_PTR(q); + notify = 0; + epds = pq->pds + pq->npds; + + for (pds = pq->pds; pds < epds; pds++) { + if (_ST_EPOLL_REVENTS(pds->fd) == 0) { + pds->revents = 0; + continue; + } + osfd = pds->fd; + events = pds->events; + revents = 0; + if ((events & POLLIN) && (_ST_EPOLL_REVENTS(osfd) & EPOLLIN)) { + revents |= POLLIN; + } + if ((events & POLLOUT) && (_ST_EPOLL_REVENTS(osfd) & EPOLLOUT)) { + revents |= POLLOUT; + } + if ((events & POLLPRI) && (_ST_EPOLL_REVENTS(osfd) & EPOLLPRI)) { + revents |= POLLPRI; + } + if (_ST_EPOLL_REVENTS(osfd) & EPOLLERR) { + revents |= POLLERR; + } + if (_ST_EPOLL_REVENTS(osfd) & EPOLLHUP) { + revents |= POLLHUP; + } + + pds->revents = revents; + if (revents) { + notify = 1; + } + } + if (notify) { + ST_REMOVE_LINK(&pq->links); + pq->on_ioq = 0; + /* + * Here we will only delete/modify descriptors that + * didn't fire (see comments in _st_epoll_pollset_del()). + */ + _st_epoll_pollset_del(pq->pds, pq->npds); + + if (pq->thread->flags & _ST_FL_ON_SLEEPQ) { + _ST_DEL_SLEEPQ(pq->thread); + } + pq->thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(pq->thread); + } + } + + for (i = 0; i < nfd; i++) { + /* Delete/modify descriptors that fired */ + osfd = _st_epoll_data->evtlist[i].data.fd; + _ST_EPOLL_REVENTS(osfd) = 0; + events = _ST_EPOLL_EVENTS(osfd); + op = events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL; + ev.events = events; + ev.data.fd = osfd; + if (epoll_ctl(_st_epoll_data->epfd, op, osfd, &ev) == 0 && op == EPOLL_CTL_DEL) { + _st_epoll_data->evtlist_cnt--; + } + } + } +} + +ST_HIDDEN int _st_epoll_fd_new(int osfd) +{ + if (osfd >= _st_epoll_data->fd_data_size && _st_epoll_fd_data_expand(osfd) < 0) { + return -1; + } + + return 0; +} + +ST_HIDDEN int _st_epoll_fd_close(int osfd) +{ + if (_ST_EPOLL_READ_CNT(osfd) || _ST_EPOLL_WRITE_CNT(osfd) || _ST_EPOLL_EXCEP_CNT(osfd)) { + errno = EBUSY; + return -1; + } + + return 0; +} + +ST_HIDDEN int _st_epoll_fd_getlimit(void) +{ + /* zero means no specific limit */ + return 0; +} + +/* + * Check if epoll functions are just stubs. + */ +ST_HIDDEN int _st_epoll_is_supported(void) +{ + struct epoll_event ev; + + ev.events = EPOLLIN; + ev.data.ptr = NULL; + /* Guaranteed to fail */ + epoll_ctl(-1, EPOLL_CTL_ADD, -1, &ev); + + return (errno != ENOSYS); +} + +static _st_eventsys_t _st_epoll_eventsys = { + "epoll", + ST_EVENTSYS_ALT, + _st_epoll_init, + _st_epoll_dispatch, + _st_epoll_pollset_add, + _st_epoll_pollset_del, + _st_epoll_fd_new, + _st_epoll_fd_close, + _st_epoll_fd_getlimit +}; + +/***************************************** + * Public functions + */ + +int st_set_eventsys(int eventsys) +{ + if (_st_eventsys) { + errno = EBUSY; + return -1; + } + + switch (eventsys) { + case ST_EVENTSYS_DEFAULT: + case ST_EVENTSYS_ALT: + default: + if (_st_epoll_is_supported()) { + _st_eventsys = &_st_epoll_eventsys; + break; + } + errno = EINVAL; + return -1; + } + + return 0; +} + +int st_get_eventsys(void) +{ + return _st_eventsys ? _st_eventsys->val : -1; +} + +const char *st_get_eventsys_name(void) +{ + return _st_eventsys ? _st_eventsys->name : ""; +} + diff --git a/trunk/research/st/io.c b/trunk/research/st/io.c new file mode 100644 index 0000000000..bc77dc8e10 --- /dev/null +++ b/trunk/research/st/io.c @@ -0,0 +1,792 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +#if EAGAIN != EWOULDBLOCK + #define _IO_NOT_READY_ERROR ((errno == EAGAIN) || (errno == EWOULDBLOCK)) +#else + #define _IO_NOT_READY_ERROR (errno == EAGAIN) +#endif + +#define _LOCAL_MAXIOV 16 + +/* File descriptor object free list */ +static _st_netfd_t *_st_netfd_freelist = NULL; +/* Maximum number of file descriptors that the process can open */ +static int _st_osfd_limit = -1; + +static void _st_netfd_free_aux_data(_st_netfd_t *fd); + +int _st_io_init(void) +{ + struct sigaction sigact; + struct rlimit rlim; + int fdlim; + + /* Ignore SIGPIPE */ + sigact.sa_handler = SIG_IGN; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + if (sigaction(SIGPIPE, &sigact, NULL) < 0) { + return -1; + } + + /* Set maximum number of open file descriptors */ + if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { + return -1; + } + + fdlim = (*_st_eventsys->fd_getlimit)(); + if (fdlim > 0 && rlim.rlim_max > (rlim_t) fdlim) { + rlim.rlim_max = fdlim; + } + rlim.rlim_cur = rlim.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { + return -1; + } + _st_osfd_limit = (int) rlim.rlim_max; + + return 0; +} + +int st_getfdlimit(void) +{ + return _st_osfd_limit; +} + +void st_netfd_free(_st_netfd_t *fd) +{ + if (!fd->inuse) { + return; + } + + fd->inuse = 0; + if (fd->aux_data) { + _st_netfd_free_aux_data(fd); + } + if (fd->private_data && fd->destructor) { + (*(fd->destructor))(fd->private_data); + } + fd->private_data = NULL; + fd->destructor = NULL; + fd->next = _st_netfd_freelist; + _st_netfd_freelist = fd; +} + +static _st_netfd_t *_st_netfd_new(int osfd, int nonblock, int is_socket) +{ + _st_netfd_t *fd; + int flags = 1; + + if ((*_st_eventsys->fd_new)(osfd) < 0) { + return NULL; + } + + if (_st_netfd_freelist) { + fd = _st_netfd_freelist; + _st_netfd_freelist = _st_netfd_freelist->next; + } else { + fd = calloc(1, sizeof(_st_netfd_t)); + if (!fd) { + return NULL; + } + } + + fd->osfd = osfd; + fd->inuse = 1; + fd->next = NULL; + + if (nonblock) { + /* Use just one system call */ + if (is_socket && ioctl(osfd, FIONBIO, &flags) != -1) { + return fd; + } + /* Do it the Posix way */ + if ((flags = fcntl(osfd, F_GETFL, 0)) < 0 || fcntl(osfd, F_SETFL, flags | O_NONBLOCK) < 0) { + st_netfd_free(fd); + return NULL; + } + } + + return fd; +} + +_st_netfd_t *st_netfd_open(int osfd) +{ + return _st_netfd_new(osfd, 1, 0); +} + +_st_netfd_t *st_netfd_open_socket(int osfd) +{ + return _st_netfd_new(osfd, 1, 1); +} + +int st_netfd_close(_st_netfd_t *fd) +{ + if ((*_st_eventsys->fd_close)(fd->osfd) < 0) { + return -1; + } + + st_netfd_free(fd); + return close(fd->osfd); +} + +int st_netfd_fileno(_st_netfd_t *fd) +{ + return (fd->osfd); +} + +void st_netfd_setspecific(_st_netfd_t *fd, void *value, _st_destructor_t destructor) +{ + if (value != fd->private_data) { + /* Free up previously set non-NULL data value */ + if (fd->private_data && fd->destructor) { + (*(fd->destructor))(fd->private_data); + } + } + fd->private_data = value; + fd->destructor = destructor; +} + +void *st_netfd_getspecific(_st_netfd_t *fd) +{ + return (fd->private_data); +} + +/* + * Wait for I/O on a single descriptor. + */ +int st_netfd_poll(_st_netfd_t *fd, int how, st_utime_t timeout) +{ + struct pollfd pd; + int n; + + pd.fd = fd->osfd; + pd.events = (short) how; + pd.revents = 0; + + if ((n = st_poll(&pd, 1, timeout)) < 0) { + return -1; + } + if (n == 0) { + /* Timed out */ + errno = ETIME; + return -1; + } + if (pd.revents & POLLNVAL) { + errno = EBADF; + return -1; + } + + return 0; +} + +#ifdef MD_ALWAYS_UNSERIALIZED_ACCEPT +/* No-op */ +int st_netfd_serialize_accept(_st_netfd_t *fd) +{ + fd->aux_data = NULL; + return 0; +} + +/* No-op */ +static void _st_netfd_free_aux_data(_st_netfd_t *fd) +{ + fd->aux_data = NULL; +} + +_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout) +{ + int osfd, err; + _st_netfd_t *newfd; + + while ((osfd = accept(fd->osfd, addr, (socklen_t *)addrlen)) < 0) { + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + return NULL; + } + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) { + return NULL; + } + } + + /* On some platforms the new socket created by accept() inherits */ + /* the nonblocking attribute of the listening socket */ +#if defined (MD_ACCEPT_NB_INHERITED) + newfd = _st_netfd_new(osfd, 0, 1); +#elif defined (MD_ACCEPT_NB_NOT_INHERITED) + newfd = _st_netfd_new(osfd, 1, 1); +#else + #error Unknown OS +#endif + + if (!newfd) { + err = errno; + close(osfd); + errno = err; + } + + return newfd; +} + +#else /* MD_ALWAYS_UNSERIALIZED_ACCEPT */ +/* + * On some platforms accept() calls from different processes + * on the same listen socket must be serialized. + * The following code serializes accept()'s without process blocking. + * A pipe is used as an inter-process semaphore. + */ +int st_netfd_serialize_accept(_st_netfd_t *fd) +{ + _st_netfd_t **p; + int osfd[2], err; + + if (fd->aux_data) { + errno = EINVAL; + return -1; + } + if ((p = (_st_netfd_t **)calloc(2, sizeof(_st_netfd_t *))) == NULL) { + return -1; + } + if (pipe(osfd) < 0) { + free(p); + return -1; + } + if ((p[0] = st_netfd_open(osfd[0])) != NULL && (p[1] = st_netfd_open(osfd[1])) != NULL && write(osfd[1], " ", 1) == 1) { + fd->aux_data = p; + return 0; + } + /* Error */ + err = errno; + if (p[0]) { + st_netfd_free(p[0]); + } + if (p[1]) { + st_netfd_free(p[1]); + } + close(osfd[0]); + close(osfd[1]); + free(p); + errno = err; + + return -1; +} + +static void _st_netfd_free_aux_data(_st_netfd_t *fd) +{ + _st_netfd_t **p = (_st_netfd_t **) fd->aux_data; + + st_netfd_close(p[0]); + st_netfd_close(p[1]); + free(p); + fd->aux_data = NULL; +} + +_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout) +{ + int osfd, err; + _st_netfd_t *newfd; + _st_netfd_t **p = (_st_netfd_t **) fd->aux_data; + ssize_t n; + char c; + + for ( ; ; ) { + if (p == NULL) { + osfd = accept(fd->osfd, addr, (socklen_t *)addrlen); + } else { + /* Get the lock */ + n = st_read(p[0], &c, 1, timeout); + if (n < 0) { + return NULL; + } + ST_ASSERT(n == 1); + /* Got the lock */ + osfd = accept(fd->osfd, addr, (socklen_t *)addrlen); + /* Unlock */ + err = errno; + n = st_write(p[1], &c, 1, timeout); + ST_ASSERT(n == 1); + errno = err; + } + if (osfd >= 0) { + break; + } + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + return NULL; + } + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) { + return NULL; + } + } + + /* On some platforms the new socket created by accept() inherits */ + /* the nonblocking attribute of the listening socket */ +#if defined (MD_ACCEPT_NB_INHERITED) + newfd = _st_netfd_new(osfd, 0, 1); +#elif defined (MD_ACCEPT_NB_NOT_INHERITED) + newfd = _st_netfd_new(osfd, 1, 1); +#else + #error Unknown OS +#endif + + if (!newfd) { + err = errno; + close(osfd); + errno = err; + } + + return newfd; +} +#endif /* MD_ALWAYS_UNSERIALIZED_ACCEPT */ + +int st_connect(_st_netfd_t *fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout) +{ + int n, err = 0; + + while (connect(fd->osfd, addr, addrlen) < 0) { + if (errno != EINTR) { + /* + * On some platforms, if connect() is interrupted (errno == EINTR) + * after the kernel binds the socket, a subsequent connect() + * attempt will fail with errno == EADDRINUSE. Ignore EADDRINUSE + * iff connect() was previously interrupted. See Rich Stevens' + * "UNIX Network Programming," Vol. 1, 2nd edition, p. 413 + * ("Interrupted connect"). + */ + if (errno != EINPROGRESS && (errno != EADDRINUSE || err == 0)) { + return -1; + } + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { + return -1; + } + /* Try to find out whether the connection setup succeeded or failed */ + n = sizeof(int); + if (getsockopt(fd->osfd, SOL_SOCKET, SO_ERROR, (char *)&err, (socklen_t *)&n) < 0) { + return -1; + } + if (err) { + errno = err; + return -1; + } + break; + } + err = 1; + } + + return 0; +} + +ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout) +{ + ssize_t n; + + while ((n = read(fd->osfd, buf, nbyte)) < 0) { + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + return -1; + } + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) { + return -1; + } + } + + return n; +} + +int st_read_resid(_st_netfd_t *fd, void *buf, size_t *resid, st_utime_t timeout) +{ + struct iovec iov, *riov; + int riov_size, rv; + + iov.iov_base = buf; + iov.iov_len = *resid; + riov = &iov; + riov_size = 1; + rv = st_readv_resid(fd, &riov, &riov_size, timeout); + *resid = iov.iov_len; + return rv; +} + +ssize_t st_readv(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout) +{ + ssize_t n; + + while ((n = readv(fd->osfd, iov, iov_size)) < 0) { + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + return -1; + } + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) { + return -1; + } + } + + return n; +} + +int st_readv_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout) +{ + ssize_t n; + + while (*iov_size > 0) { + if (*iov_size == 1) { + n = read(fd->osfd, (*iov)->iov_base, (*iov)->iov_len); + } else { + n = readv(fd->osfd, *iov, *iov_size); + } + if (n < 0) { + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + return -1; + } + } else if (n == 0) { + break; + } else { + while ((size_t) n >= (*iov)->iov_len) { + n -= (*iov)->iov_len; + (*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len; + (*iov)->iov_len = 0; + (*iov)++; + (*iov_size)--; + if (n == 0) { + break; + } + } + if (*iov_size == 0) { + break; + } + (*iov)->iov_base = (char *) (*iov)->iov_base + n; + (*iov)->iov_len -= n; + } + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) { + return -1; + } + } + + return 0; +} + +ssize_t st_read_fully(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout) +{ + size_t resid = nbyte; + return st_read_resid(fd, buf, &resid, timeout) == 0 ? (ssize_t) (nbyte - resid) : -1; +} + +int st_write_resid(_st_netfd_t *fd, const void *buf, size_t *resid, st_utime_t timeout) +{ + struct iovec iov, *riov; + int riov_size, rv; + + iov.iov_base = (void *) buf; /* we promise not to modify buf */ + iov.iov_len = *resid; + riov = &iov; + riov_size = 1; + rv = st_writev_resid(fd, &riov, &riov_size, timeout); + *resid = iov.iov_len; + return rv; +} + +ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte, st_utime_t timeout) +{ + size_t resid = nbyte; + return st_write_resid(fd, buf, &resid, timeout) == 0 ? (ssize_t) (nbyte - resid) : -1; +} + +ssize_t st_writev(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout) +{ + ssize_t n, rv; + size_t nleft, nbyte; + int index, iov_cnt; + struct iovec *tmp_iov; + struct iovec local_iov[_LOCAL_MAXIOV]; + + /* Calculate the total number of bytes to be sent */ + nbyte = 0; + for (index = 0; index < iov_size; index++) { + nbyte += iov[index].iov_len; + } + + rv = (ssize_t)nbyte; + nleft = nbyte; + tmp_iov = (struct iovec *) iov; /* we promise not to modify iov */ + iov_cnt = iov_size; + + while (nleft > 0) { + if (iov_cnt == 1) { + if (st_write(fd, tmp_iov[0].iov_base, nleft, timeout) != (ssize_t) nleft) { + rv = -1; + } + break; + } + if ((n = writev(fd->osfd, tmp_iov, iov_cnt)) < 0) { + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + rv = -1; + break; + } + } else { + if ((size_t) n == nleft) { + break; + } + nleft -= n; + /* Find the next unwritten vector */ + n = (ssize_t)(nbyte - nleft); + for (index = 0; (size_t) n >= iov[index].iov_len; index++) { + n -= iov[index].iov_len; + } + + if (tmp_iov == iov) { + /* Must copy iov's around */ + if (iov_size - index <= _LOCAL_MAXIOV) { + tmp_iov = local_iov; + } else { + tmp_iov = calloc(1, (iov_size - index) * sizeof(struct iovec)); + if (tmp_iov == NULL) { + return -1; + } + } + } + + /* Fill in the first partial read */ + tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[n]); + tmp_iov[0].iov_len = iov[index].iov_len - n; + index++; + /* Copy the remaining vectors */ + for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) { + tmp_iov[iov_cnt].iov_base = iov[index].iov_base; + tmp_iov[iov_cnt].iov_len = iov[index].iov_len; + } + } + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { + rv = -1; + break; + } + } + + if (tmp_iov != iov && tmp_iov != local_iov) { + free(tmp_iov); + } + + return rv; +} + +int st_writev_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size, st_utime_t timeout) +{ + ssize_t n; + + while (*iov_size > 0) { + if (*iov_size == 1) { + n = write(fd->osfd, (*iov)->iov_base, (*iov)->iov_len); + } else { + n = writev(fd->osfd, *iov, *iov_size); + } + if (n < 0) { + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + return -1; + } + } else { + while ((size_t) n >= (*iov)->iov_len) { + n -= (*iov)->iov_len; + (*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len; + (*iov)->iov_len = 0; + (*iov)++; + (*iov_size)--; + if (n == 0) { + break; + } + } + if (*iov_size == 0) { + break; + } + (*iov)->iov_base = (char *) (*iov)->iov_base + n; + (*iov)->iov_len -= n; + } + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { + return -1; + } + } + + return 0; +} + +/* + * Simple I/O functions for UDP. + */ +int st_recvfrom(_st_netfd_t *fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout) +{ + int n; + + while ((n = recvfrom(fd->osfd, buf, len, 0, from, (socklen_t *)fromlen)) < 0) { + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + return -1; + } + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) { + return -1; + } + } + + return n; +} + +int st_sendto(_st_netfd_t *fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout) +{ + int n; + + while ((n = sendto(fd->osfd, msg, len, 0, to, tolen)) < 0) { + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + return -1; + } + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { + return -1; + } + } + + return n; +} + +int st_recvmsg(_st_netfd_t *fd, struct msghdr *msg, int flags, st_utime_t timeout) +{ + int n; + + while ((n = recvmsg(fd->osfd, msg, flags)) < 0) { + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + return -1; + } + /* Wait until the socket becomes readable */ + if (st_netfd_poll(fd, POLLIN, timeout) < 0) { + return -1; + } + } + + return n; +} + +int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags, st_utime_t timeout) +{ + int n; + + while ((n = sendmsg(fd->osfd, msg, flags)) < 0) { + if (errno == EINTR) { + continue; + } + if (!_IO_NOT_READY_ERROR) { + return -1; + } + /* Wait until the socket becomes writable */ + if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { + return -1; + } + } + + return n; +} + +/* + * To open FIFOs or other special files. + */ +_st_netfd_t *st_open(const char *path, int oflags, mode_t mode) +{ + int osfd, err; + _st_netfd_t *newfd; + + while ((osfd = open(path, oflags | O_NONBLOCK, mode)) < 0) { + if (errno != EINTR) { + return NULL; + } + } + + newfd = _st_netfd_new(osfd, 0, 0); + if (!newfd) { + err = errno; + close(osfd); + errno = err; + } + + return newfd; +} + diff --git a/trunk/research/st/key.c b/trunk/research/st/key.c new file mode 100644 index 0000000000..49d778a187 --- /dev/null +++ b/trunk/research/st/key.c @@ -0,0 +1,116 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#include +#include +#include "common.h" + +/* + * Destructor table for per-thread private data + */ +static _st_destructor_t _st_destructors[ST_KEYS_MAX]; +static int key_max = 0; + +/* + * Return a key to be used for thread specific data + */ +int st_key_create(int *keyp, _st_destructor_t destructor) +{ + if (key_max >= ST_KEYS_MAX) { + errno = EAGAIN; + return -1; + } + + *keyp = key_max++; + _st_destructors[*keyp] = destructor; + + return 0; +} + +int st_key_getlimit(void) +{ + return ST_KEYS_MAX; +} + +int st_thread_setspecific(int key, void *value) +{ + _st_thread_t *me = _ST_CURRENT_THREAD(); + + if (key < 0 || key >= key_max) { + errno = EINVAL; + return -1; + } + + if (value != me->private_data[key]) { + /* free up previously set non-NULL data value */ + if (me->private_data[key] && _st_destructors[key]) { + (*_st_destructors[key])(me->private_data[key]); + } + me->private_data[key] = value; + } + + return 0; +} + +void *st_thread_getspecific(int key) +{ + if (key < 0 || key >= key_max) { + return NULL; + } + + return ((_ST_CURRENT_THREAD())->private_data[key]); +} + +/* + * Free up all per-thread private data + */ +void _st_thread_cleanup(_st_thread_t *thread) +{ + int key; + + for (key = 0; key < key_max; key++) { + if (thread->private_data[key] && _st_destructors[key]) { + (*_st_destructors[key])(thread->private_data[key]); + thread->private_data[key] = NULL; + } + } +} + diff --git a/trunk/research/st/md.S b/trunk/research/st/md.S new file mode 100755 index 0000000000..883da302b2 --- /dev/null +++ b/trunk/research/st/md.S @@ -0,0 +1,151 @@ +/* + * Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc. + * All Rights Reserved. + */ + +/****************************************************************/ + +#if defined(__i386__) + +/* + * Internal __jmp_buf layout + */ +#define JB_BX 0 +#define JB_SI 1 +#define JB_DI 2 +#define JB_BP 3 +#define JB_SP 4 +#define JB_PC 5 + + .file "md.S" + .text + + /* _st_md_cxt_save(__jmp_buf env) */ +.globl _st_md_cxt_save + .type _st_md_cxt_save, @function + .align 16 +_st_md_cxt_save: + movl 4(%esp), %eax + + /* + * Save registers. + */ + movl %ebx, (JB_BX*4)(%eax) + movl %esi, (JB_SI*4)(%eax) + movl %edi, (JB_DI*4)(%eax) + /* Save SP */ + leal 4(%esp), %ecx + movl %ecx, (JB_SP*4)(%eax) + /* Save PC we are returning to */ + movl 0(%esp), %ecx + movl %ecx, (JB_PC*4)(%eax) + /* Save caller frame pointer */ + movl %ebp, (JB_BP*4)(%eax) + xorl %eax, %eax + ret + .size _st_md_cxt_save, .-_st_md_cxt_save + + +/****************************************************************/ + + /* _st_md_cxt_restore(__jmp_buf env, int val) */ +.globl _st_md_cxt_restore + .type _st_md_cxt_restore, @function + .align 16 +_st_md_cxt_restore: + /* First argument is jmp_buf */ + movl 4(%esp), %ecx + /* Second argument is return value */ + movl 8(%esp), %eax + /* Set the return address */ + movl (JB_PC*4)(%ecx), %edx + /* + * Restore registers. + */ + movl (JB_BX*4)(%ecx), %ebx + movl (JB_SI*4)(%ecx), %esi + movl (JB_DI*4)(%ecx), %edi + movl (JB_BP*4)(%ecx), %ebp + movl (JB_SP*4)(%ecx), %esp + testl %eax, %eax + jnz 1f + incl %eax + /* Jump to saved PC */ +1: jmp *%edx + .size _st_md_cxt_restore, .-_st_md_cxt_restore + +/****************************************************************/ + +#elif defined(__amd64__) || defined(__x86_64__) + +/* + * Internal __jmp_buf layout + */ +#define JB_RBX 0 +#define JB_RBP 1 +#define JB_R12 2 +#define JB_R13 3 +#define JB_R14 4 +#define JB_R15 5 +#define JB_RSP 6 +#define JB_PC 7 + + .file "md.S" + .text + + /* _st_md_cxt_save(__jmp_buf env) */ +.globl _st_md_cxt_save + .type _st_md_cxt_save, @function + .align 16 +_st_md_cxt_save: + /* + * Save registers. + */ + movq %rbx, (JB_RBX*8)(%rdi) + movq %rbp, (JB_RBP*8)(%rdi) + movq %r12, (JB_R12*8)(%rdi) + movq %r13, (JB_R13*8)(%rdi) + movq %r14, (JB_R14*8)(%rdi) + movq %r15, (JB_R15*8)(%rdi) + /* Save SP */ + leaq 8(%rsp), %rdx + movq %rdx, (JB_RSP*8)(%rdi) + /* Save PC we are returning to */ + movq (%rsp), %rax + movq %rax, (JB_PC*8)(%rdi) + xorq %rax, %rax + ret + .size _st_md_cxt_save, .-_st_md_cxt_save + + +/****************************************************************/ + + /* _st_md_cxt_restore(__jmp_buf env, int val) */ +.globl _st_md_cxt_restore + .type _st_md_cxt_restore, @function + .align 16 +_st_md_cxt_restore: + /* + * Restore registers. + */ + movq (JB_RBX*8)(%rdi), %rbx + movq (JB_RBP*8)(%rdi), %rbp + movq (JB_R12*8)(%rdi), %r12 + movq (JB_R13*8)(%rdi), %r13 + movq (JB_R14*8)(%rdi), %r14 + movq (JB_R15*8)(%rdi), %r15 + /* Set return value */ + test %esi, %esi + mov $01, %eax + cmove %eax, %esi + mov %esi, %eax + movq (JB_PC*8)(%rdi), %rdx + movq (JB_RSP*8)(%rdi), %rsp + /* Jump to saved PC */ + jmpq *%rdx + .size _st_md_cxt_restore, .-_st_md_cxt_restore + +/****************************************************************/ + +#endif + diff --git a/trunk/research/st/md.h b/trunk/research/st/md.h new file mode 100644 index 0000000000..bf82f4d55c --- /dev/null +++ b/trunk/research/st/md.h @@ -0,0 +1,193 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#ifndef __ST_MD_H__ +#define __ST_MD_H__ + +#if defined(ETIMEDOUT) && !defined(ETIME) + #define ETIME ETIMEDOUT +#endif + +#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON) + #define MAP_ANON MAP_ANONYMOUS +#endif + +#ifndef MAP_FAILED + #define MAP_FAILED -1 +#endif + +/***************************************** + * Platform specifics + */ +#if defined (LINUX) + /* linux ok, defined bellow */ +#elif defined (AIX) + #error "AIX not supported" +#elif defined (CYGWIN) + #error "CYGWIN not supported" +#elif defined (DARWIN) + #error "DARWIN not supported" +#elif defined (FREEBSD) + #error "FREEBSD not supported" +#elif defined (HPUX) + #error "HPUX not supported" +#elif defined (IRIX) + #error "IRIX not supported" +#elif defined (NETBSD) + #error "NETBSD not supported" +#elif defined (OPENBSD) + #error "OPENBSD not supported" +#elif defined (OSF1) + #error "OSF1 not supported" +#elif defined (SOLARIS) + #error "SOLARIS not supported" +#else + #error "Unknown OS" +#endif /* OS */ + +/* linux only, defined bellow */ +/* + * These are properties of the linux kernel and are the same on every + * flavor and architecture. + */ +#define MD_USE_BSD_ANON_MMAP +#define MD_ACCEPT_NB_NOT_INHERITED +#define MD_ALWAYS_UNSERIALIZED_ACCEPT +/* + * Modern GNU/Linux is Posix.1g compliant. + */ +#define MD_HAVE_SOCKLEN_T + +/* + * All architectures and flavors of linux have the gettimeofday + * function but if you know of a faster way, use it. + */ +#define MD_GET_UTIME() \ + struct timeval tv; \ + (void) gettimeofday(&tv, NULL); \ + return (tv.tv_sec * 1000000LL + tv.tv_usec) + +#if defined(__mips__) + #define MD_STACK_GROWS_DOWN +#else /* Not or mips */ + /* + * On linux, there are a few styles of jmpbuf format. These vary based + * on architecture/glibc combination. + * + * Most of the glibc based toggles were lifted from: + * mozilla/nsprpub/pr/include/md/_linux.h + */ + /* + * Starting with glibc 2.4, JB_SP definitions are not public anymore. + * They, however, can still be found in glibc source tree in + * architecture-specific "jmpbuf-offsets.h" files. + * Most importantly, the content of jmp_buf is mangled by setjmp to make + * it completely opaque (the mangling can be disabled by setting the + * LD_POINTER_GUARD environment variable before application execution). + * Therefore we will use built-in _st_md_cxt_save/_st_md_cxt_restore + * functions as a setjmp/longjmp replacement wherever they are available + * unless USE_LIBC_SETJMP is defined. + */ + #if defined(__i386__) + #define MD_STACK_GROWS_DOWN + #define MD_USE_BUILTIN_SETJMP + + #if defined(__GLIBC__) && __GLIBC__ >= 2 + #ifndef JB_SP + #define JB_SP 4 + #endif + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP] + #else + /* not an error but certainly cause for caution */ + #error "Untested use of old glibc on i386" + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp + #endif + #elif defined(__amd64__) || defined(__x86_64__) + #define MD_STACK_GROWS_DOWN + #define MD_USE_BUILTIN_SETJMP + + #ifndef JB_RSP + #define JB_RSP 6 + #endif + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_RSP] + #elif defined(__arm__) + #define MD_STACK_GROWS_DOWN + + #if defined(__GLIBC__) && __GLIBC__ >= 2 + #define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[8] + #else + #error "ARM/Linux pre-glibc2 not supported yet" + #endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */ + #else + #error "Unknown CPU architecture" + #endif /* Cases with common MD_INIT_CONTEXT and different SP locations */ +#endif /* Cases with different MD_INIT_CONTEXT */ + +#if defined(MD_USE_BUILTIN_SETJMP) && !defined(USE_LIBC_SETJMP) + /* i386/x86_64 */ + #define MD_SETJMP(env) _st_md_cxt_save(env) + #define MD_LONGJMP(env, val) _st_md_cxt_restore(env, val) + + extern int _st_md_cxt_save(jmp_buf env); + extern void _st_md_cxt_restore(jmp_buf env, int val); +#else + /* arm/mips */ + #define MD_SETJMP(env) setjmp(env) + #define MD_LONGJMP(env, val) longjmp(env, val) +#endif + +/***************************************** + * Other defines + */ +#ifndef MD_STACK_PAD_SIZE + #define MD_STACK_PAD_SIZE 128 +#endif + +#if !defined(MD_HAVE_SOCKLEN_T) && !defined(socklen_t) + #define socklen_t int +#endif + +#ifndef MD_CAP_STACK + #define MD_CAP_STACK(var_addr) +#endif + +#endif /* !__ST_MD_H__ */ + diff --git a/trunk/research/st/public.h b/trunk/research/st/public.h new file mode 100644 index 0000000000..3275191bc7 --- /dev/null +++ b/trunk/research/st/public.h @@ -0,0 +1,164 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef __ST_THREAD_H__ +#define __ST_THREAD_H__ + +#include +#include +#include +#include +#include +#include +#include + +#define ST_VERSION "1.9" +#define ST_VERSION_MAJOR 1 +#define ST_VERSION_MINOR 9 + +/* Undefine this to remove the context switch callback feature. */ +#define ST_SWITCH_CB + +#ifndef ETIME + #define ETIME ETIMEDOUT +#endif + +#ifndef ST_UTIME_NO_TIMEOUT + #define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL) +#endif + +#ifndef ST_UTIME_NO_WAIT + #define ST_UTIME_NO_WAIT 0 +#endif + +#define ST_EVENTSYS_DEFAULT 0 +#define ST_EVENTSYS_SELECT 1 +#define ST_EVENTSYS_POLL 2 +#define ST_EVENTSYS_ALT 3 + +#ifdef __cplusplus +extern "C" { +#endif + typedef unsigned long long st_utime_t; + typedef struct _st_thread * st_thread_t; + typedef struct _st_cond * st_cond_t; + typedef struct _st_mutex * st_mutex_t; + typedef struct _st_netfd * st_netfd_t; + #ifdef ST_SWITCH_CB + typedef void (*st_switch_cb_t)(void); + #endif + + extern int st_init(void); + extern int st_getfdlimit(void); + + extern int st_set_eventsys(int eventsys); + extern int st_get_eventsys(void); + extern const char *st_get_eventsys_name(void); + + #ifdef ST_SWITCH_CB + extern st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb); + extern st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb); + #endif + + extern st_thread_t st_thread_self(void); + extern void st_thread_exit(void *retval); + extern int st_thread_join(st_thread_t trd, void **retvalp); + extern void st_thread_interrupt(st_thread_t trd); + extern st_thread_t st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stack_size); + extern int st_randomize_stacks(int on); + extern int st_set_utime_function(st_utime_t (*func)(void)); + + extern st_utime_t st_utime(void); + extern st_utime_t st_utime_last_clock(void); + extern int st_timecache_set(int on); + extern time_t st_time(void); + extern int st_usleep(st_utime_t usecs); + extern int st_sleep(int secs); + extern st_cond_t st_cond_new(void); + extern int st_cond_destroy(st_cond_t cvar); + extern int st_cond_timedwait(st_cond_t cvar, st_utime_t timeout); + extern int st_cond_wait(st_cond_t cvar); + extern int st_cond_signal(st_cond_t cvar); + extern int st_cond_broadcast(st_cond_t cvar); + extern st_mutex_t st_mutex_new(void); + extern int st_mutex_destroy(st_mutex_t lock); + extern int st_mutex_lock(st_mutex_t lock); + extern int st_mutex_unlock(st_mutex_t lock); + extern int st_mutex_trylock(st_mutex_t lock); + + extern int st_key_create(int *keyp, void (*destructor)(void *)); + extern int st_key_getlimit(void); + extern int st_thread_setspecific(int key, void *value); + extern void *st_thread_getspecific(int key); + + extern st_netfd_t st_netfd_open(int osfd); + extern st_netfd_t st_netfd_open_socket(int osfd); + extern void st_netfd_free(st_netfd_t fd); + extern int st_netfd_close(st_netfd_t fd); + extern int st_netfd_fileno(st_netfd_t fd); + extern void st_netfd_setspecific(st_netfd_t fd, void *value, void (*destructor)(void *)); + extern void *st_netfd_getspecific(st_netfd_t fd); + extern int st_netfd_serialize_accept(st_netfd_t fd); + extern int st_netfd_poll(st_netfd_t fd, int how, st_utime_t timeout); + + extern int st_poll(struct pollfd *pds, int npds, st_utime_t timeout); + extern st_netfd_t st_accept(st_netfd_t fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout); + extern int st_connect(st_netfd_t fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout); + extern ssize_t st_read(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout); + extern ssize_t st_read_fully(st_netfd_t fd, void *buf, size_t nbyte, st_utime_t timeout); + extern int st_read_resid(st_netfd_t fd, void *buf, size_t *resid, st_utime_t timeout); + extern ssize_t st_readv(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout); + extern int st_readv_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout); + extern ssize_t st_write(st_netfd_t fd, const void *buf, size_t nbyte, st_utime_t timeout); + extern int st_write_resid(st_netfd_t fd, const void *buf, size_t *resid, st_utime_t timeout); + extern ssize_t st_writev(st_netfd_t fd, const struct iovec *iov, int iov_size, st_utime_t timeout); + extern int st_writev_resid(st_netfd_t fd, struct iovec **iov, int *iov_size, st_utime_t timeout); + extern int st_recvfrom(st_netfd_t fd, void *buf, int len, struct sockaddr *from, int *fromlen, st_utime_t timeout); + extern int st_sendto(st_netfd_t fd, const void *msg, int len, const struct sockaddr *to, int tolen, st_utime_t timeout); + extern int st_recvmsg(st_netfd_t fd, struct msghdr *msg, int flags, st_utime_t timeout); + extern int st_sendmsg(st_netfd_t fd, const struct msghdr *msg, int flags, st_utime_t timeout); + extern st_netfd_t st_open(const char *path, int oflags, mode_t mode); + + #ifdef DEBUG + extern void _st_show_thread_stack(st_thread_t thread, const char *messg); + extern void _st_iterate_threads(void); + #endif +#ifdef __cplusplus +} +#endif + +#endif /* !__ST_THREAD_H__ */ + diff --git a/trunk/research/st/sched.c b/trunk/research/st/sched.c new file mode 100755 index 0000000000..66095cfd1b --- /dev/null +++ b/trunk/research/st/sched.c @@ -0,0 +1,680 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" + +/* Global data */ +_st_vp_t _st_this_vp; /* This VP */ +_st_thread_t *_st_this_thread; /* Current thread */ +int _st_active_count = 0; /* Active thread count */ + +time_t _st_curr_time = 0; /* Current time as returned by time(2) */ +st_utime_t _st_last_tset; /* Last time it was fetched */ + +int st_poll(struct pollfd *pds, int npds, st_utime_t timeout) +{ + struct pollfd *pd; + struct pollfd *epd = pds + npds; + _st_pollq_t pq; + _st_thread_t *me = _ST_CURRENT_THREAD(); + int n; + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + if ((*_st_eventsys->pollset_add)(pds, npds) < 0) { + return -1; + } + + pq.pds = pds; + pq.npds = npds; + pq.thread = me; + pq.on_ioq = 1; + _ST_ADD_IOQ(pq); + if (timeout != ST_UTIME_NO_TIMEOUT) { + _ST_ADD_SLEEPQ(me, timeout); + } + me->state = _ST_ST_IO_WAIT; + + _ST_SWITCH_CONTEXT(me); + + n = 0; + if (pq.on_ioq) { + /* If we timed out, the pollq might still be on the ioq. Remove it */ + _ST_DEL_IOQ(pq); + (*_st_eventsys->pollset_del)(pds, npds); + } else { + /* Count the number of ready descriptors */ + for (pd = pds; pd < epd; pd++) { + if (pd->revents) { + n++; + } + } + } + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + return n; +} + +void _st_vp_schedule(void) +{ + _st_thread_t *trd; + + if (_ST_RUNQ.next != &_ST_RUNQ) { + /* Pull thread off of the run queue */ + trd = _ST_THREAD_PTR(_ST_RUNQ.next); + _ST_DEL_RUNQ(trd); + } else { + /* If there are no threads to run, switch to the idle thread */ + trd = _st_this_vp.idle_thread; + } + ST_ASSERT(trd->state == _ST_ST_RUNNABLE); + + /* Resume the thread */ + trd->state = _ST_ST_RUNNING; + _ST_RESTORE_CONTEXT(trd); +} + +/* + * Initialize this Virtual Processor + */ +int st_init(void) +{ + _st_thread_t *trd; + + if (_st_active_count) { + /* Already initialized */ + return 0; + } + + /* We can ignore return value here */ + st_set_eventsys(ST_EVENTSYS_DEFAULT); + + if (_st_io_init() < 0) { + return -1; + } + + memset(&_st_this_vp, 0, sizeof(_st_vp_t)); + + ST_INIT_CLIST(&_ST_RUNQ); + ST_INIT_CLIST(&_ST_IOQ); + ST_INIT_CLIST(&_ST_ZOMBIEQ); +#ifdef DEBUG + ST_INIT_CLIST(&_ST_THREADQ); +#endif + + if ((*_st_eventsys->init)() < 0) { + return -1; + } + + _st_this_vp.pagesize = getpagesize(); + _st_this_vp.last_clock = st_utime(); + + /* + * Create idle thread + */ + _st_this_vp.idle_thread = st_thread_create(_st_idle_thread_start, NULL, 0, 0); + if (!_st_this_vp.idle_thread) { + return -1; + } + _st_this_vp.idle_thread->flags = _ST_FL_IDLE_THREAD; + _st_active_count--; + _ST_DEL_RUNQ(_st_this_vp.idle_thread); + + /* + * Initialize primordial thread + */ + trd = (_st_thread_t *) calloc(1, sizeof(_st_thread_t) + + (ST_KEYS_MAX * sizeof(void *))); + if (!trd) { + return -1; + } + trd->private_data = (void **) (trd + 1); + trd->state = _ST_ST_RUNNING; + trd->flags = _ST_FL_PRIMORDIAL; + _ST_SET_CURRENT_THREAD(trd); + _st_active_count++; +#ifdef DEBUG + _ST_ADD_THREADQ(trd); +#endif + + return 0; +} + +#ifdef ST_SWITCH_CB +st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb) +{ + st_switch_cb_t ocb = _st_this_vp.switch_in_cb; + _st_this_vp.switch_in_cb = cb; + return ocb; +} + +st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb) +{ + st_switch_cb_t ocb = _st_this_vp.switch_out_cb; + _st_this_vp.switch_out_cb = cb; + return ocb; +} +#endif + +/* + * Start function for the idle thread + */ +/* ARGSUSED */ +void *_st_idle_thread_start(void *arg) +{ + _st_thread_t *me = _ST_CURRENT_THREAD(); + + while (_st_active_count > 0) { + /* Idle vp till I/O is ready or the smallest timeout expired */ + _ST_VP_IDLE(); + + /* Check sleep queue for expired threads */ + _st_vp_check_clock(); + + me->state = _ST_ST_RUNNABLE; + _ST_SWITCH_CONTEXT(me); + } + + /* No more threads */ + exit(0); + + /* NOTREACHED */ + return NULL; +} + +void st_thread_exit(void *retval) +{ + _st_thread_t *trd = _ST_CURRENT_THREAD(); + + trd->retval = retval; + _st_thread_cleanup(trd); + _st_active_count--; + if (trd->term) { + /* Put thread on the zombie queue */ + trd->state = _ST_ST_ZOMBIE; + _ST_ADD_ZOMBIEQ(trd); + + /* Notify on our termination condition variable */ + st_cond_signal(trd->term); + + /* Switch context and come back later */ + _ST_SWITCH_CONTEXT(trd); + + /* Continue the cleanup */ + st_cond_destroy(trd->term); + trd->term = NULL; + } + +#ifdef DEBUG + _ST_DEL_THREADQ(trd); +#endif + + if (!(trd->flags & _ST_FL_PRIMORDIAL)) { + _st_stack_free(trd->stack); + } + + /* Find another thread to run */ + _ST_SWITCH_CONTEXT(trd); + /* Not going to land here */ +} + +int st_thread_join(_st_thread_t *trd, void **retvalp) +{ + _st_cond_t *term = trd->term; + + /* Can't join a non-joinable thread */ + if (term == NULL) { + errno = EINVAL; + return -1; + } + if (_ST_CURRENT_THREAD() == trd) { + errno = EDEADLK; + return -1; + } + + /* Multiple threads can't wait on the same joinable thread */ + if (term->wait_q.next != &term->wait_q) { + errno = EINVAL; + return -1; + } + + while (trd->state != _ST_ST_ZOMBIE) { + if (st_cond_timedwait(term, ST_UTIME_NO_TIMEOUT) != 0) { + return -1; + } + } + + if (retvalp) { + *retvalp = trd->retval; + } + + /* + * Remove target thread from the zombie queue and make it runnable. + * When it gets scheduled later, it will do the clean up. + */ + trd->state = _ST_ST_RUNNABLE; + _ST_DEL_ZOMBIEQ(trd); + _ST_ADD_RUNQ(trd); + + return 0; +} + +void _st_thread_main(void) +{ + _st_thread_t *trd = _ST_CURRENT_THREAD(); + + /* + * Cap the stack by zeroing out the saved return address register + * value. This allows some debugging/profiling tools to know when + * to stop unwinding the stack. It's a no-op on most platforms. + */ + MD_CAP_STACK(&trd); + + /* Run thread main */ + trd->retval = (*trd->start)(trd->arg); + + /* All done, time to go away */ + st_thread_exit(trd->retval); +} + +/* + * Insert "thread" into the timeout heap, in the position + * specified by thread->heap_index. See docs/timeout_heap.txt + * for details about the timeout heap. + */ +static _st_thread_t **heap_insert(_st_thread_t *trd) +{ + int target = trd->heap_index; + int s = target; + _st_thread_t **p = &_ST_SLEEPQ; + int bits = 0; + int bit; + int index = 1; + + while (s) { + s >>= 1; + bits++; + } + + for (bit = bits - 2; bit >= 0; bit--) { + if (trd->due < (*p)->due) { + _st_thread_t *t = *p; + trd->left = t->left; + trd->right = t->right; + *p = trd; + trd->heap_index = index; + trd = t; + } + index <<= 1; + if (target & (1 << bit)) { + p = &((*p)->right); + index |= 1; + } else { + p = &((*p)->left); + } + } + + trd->heap_index = index; + *p = trd; + trd->left = trd->right = NULL; + + return p; +} + +/* + * Delete "thread" from the timeout heap. + */ +static void heap_delete(_st_thread_t *trd) +{ + _st_thread_t *t, **p; + int bits = 0; + int s, bit; + + /* First find and unlink the last heap element */ + p = &_ST_SLEEPQ; + s = _ST_SLEEPQ_SIZE; + while (s) { + s >>= 1; + bits++; + } + + for (bit = bits - 2; bit >= 0; bit--) { + if (_ST_SLEEPQ_SIZE & (1 << bit)) { + p = &((*p)->right); + } else { + p = &((*p)->left); + } + } + + t = *p; + *p = NULL; + --_ST_SLEEPQ_SIZE; + if (t != trd) { + /* + * Insert the unlinked last element in place of the element we are deleting + */ + t->heap_index = trd->heap_index; + p = heap_insert(t); + t = *p; + t->left = trd->left; + t->right = trd->right; + + /* + * Reestablish the heap invariant. + */ + for (;;) { + _st_thread_t *y; /* The younger child */ + int index_tmp; + + if (t->left == NULL) { + break; + } else if (t->right == NULL) { + y = t->left; + } else if (t->left->due < t->right->due) { + y = t->left; + } else { + y = t->right; + } + + if (t->due > y->due) { + _st_thread_t *tl = y->left; + _st_thread_t *tr = y->right; + *p = y; + if (y == t->left) { + y->left = t; + y->right = t->right; + p = &y->left; + } else { + y->left = t->left; + y->right = t; + p = &y->right; + } + t->left = tl; + t->right = tr; + index_tmp = t->heap_index; + t->heap_index = y->heap_index; + y->heap_index = index_tmp; + } else { + break; + } + } + } + + trd->left = trd->right = NULL; +} + +void _st_add_sleep_q(_st_thread_t *trd, st_utime_t timeout) +{ + trd->due = _ST_LAST_CLOCK + timeout; + trd->flags |= _ST_FL_ON_SLEEPQ; + trd->heap_index = ++_ST_SLEEPQ_SIZE; + heap_insert(trd); +} + +void _st_del_sleep_q(_st_thread_t *trd) +{ + heap_delete(trd); + trd->flags &= ~_ST_FL_ON_SLEEPQ; +} + +void _st_vp_check_clock(void) +{ + _st_thread_t *trd; + st_utime_t elapsed, now; + + now = st_utime(); + elapsed = now - _ST_LAST_CLOCK; + _ST_LAST_CLOCK = now; + + if (_st_curr_time && now - _st_last_tset > 999000) { + _st_curr_time = time(NULL); + _st_last_tset = now; + } + + while (_ST_SLEEPQ != NULL) { + trd = _ST_SLEEPQ; + ST_ASSERT(trd->flags & _ST_FL_ON_SLEEPQ); + if (trd->due > now) { + break; + } + _ST_DEL_SLEEPQ(trd); + + /* If thread is waiting on condition variable, set the time out flag */ + if (trd->state == _ST_ST_COND_WAIT) { + trd->flags |= _ST_FL_TIMEDOUT; + } + + /* Make thread runnable */ + ST_ASSERT(!(trd->flags & _ST_FL_IDLE_THREAD)); + trd->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(trd); + } +} + +void st_thread_interrupt(_st_thread_t* trd) +{ + /* If thread is already dead */ + if (trd->state == _ST_ST_ZOMBIE) { + return; + } + + trd->flags |= _ST_FL_INTERRUPT; + + if (trd->state == _ST_ST_RUNNING || trd->state == _ST_ST_RUNNABLE) { + return; + } + + if (trd->flags & _ST_FL_ON_SLEEPQ) { + _ST_DEL_SLEEPQ(trd); + } + + /* Make thread runnable */ + trd->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(trd); +} + +_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stk_size) +{ + _st_thread_t *trd; + _st_stack_t *stack; + void **ptds; + char *sp; + + /* Adjust stack size */ + if (stk_size == 0) { + stk_size = ST_DEFAULT_STACK_SIZE; + } + stk_size = ((stk_size + _ST_PAGE_SIZE - 1) / _ST_PAGE_SIZE) * _ST_PAGE_SIZE; + stack = _st_stack_new(stk_size); + if (!stack) { + return NULL; + } + + /* Allocate thread object and per-thread data off the stack */ +#if defined (MD_STACK_GROWS_DOWN) + sp = stack->stk_top; + /* + * The stack segment is split in the middle. The upper half is used + * as backing store for the register stack which grows upward. + * The lower half is used for the traditional memory stack which + * grows downward. Both stacks start in the middle and grow outward + * from each other. + */ + /** + The below comments is by winlin: + The Stack public structure: + +--------------------------------------------------------------+ + | stack | + +--------------------------------------------------------------+ + bottom top + The code bellow use the stack as: + +-----------------+-----------------+-------------+------------+ + | stack of thread |pad+align(128B+) |thread(336B) | keys(128B) | + +-----------------+-----------------+-------------+------------+ + bottom sp trd ptds top + (context[0].__jmpbuf.sp) (private_data) + */ + sp = sp - (ST_KEYS_MAX * sizeof(void *)); + ptds = (void **) sp; + sp = sp - sizeof(_st_thread_t); + trd = (_st_thread_t *) sp; + + /* Make stack 64-byte aligned */ + if ((unsigned long)sp & 0x3f) { + sp = sp - ((unsigned long)sp & 0x3f); + } + stack->sp = sp - _ST_STACK_PAD_SIZE; +#else + #error "Only Supports Stack Grown Down" +#endif + + memset(trd, 0, sizeof(_st_thread_t)); + memset(ptds, 0, ST_KEYS_MAX * sizeof(void *)); + + /* Initialize thread */ + trd->private_data = ptds; + trd->stack = stack; + trd->start = start; + trd->arg = arg; + +// by winlin, expand macro MD_INIT_CONTEXT +#if defined(__mips__) + MD_SETJMP((trd)->context); + trd->context[0].__jmpbuf[0].__pc = (__ptr_t) _st_thread_main; + trd->context[0].__jmpbuf[0].__sp = stack->sp; +#else + if (MD_SETJMP((trd)->context)) { + _st_thread_main(); + } + MD_GET_SP(trd) = (long) (stack->sp); +#endif + + /* If thread is joinable, allocate a termination condition variable */ + if (joinable) { + trd->term = st_cond_new(); + if (trd->term == NULL) { + _st_stack_free(trd->stack); + return NULL; + } + } + + /* Make thread runnable */ + trd->state = _ST_ST_RUNNABLE; + _st_active_count++; + _ST_ADD_RUNQ(trd); +#ifdef DEBUG + _ST_ADD_THREADQ(trd); +#endif + + return trd; +} + +_st_thread_t *st_thread_self(void) +{ + return _ST_CURRENT_THREAD(); +} + +#ifdef DEBUG +/* ARGSUSED */ +void _st_show_thread_stack(_st_thread_t *trd, const char *messg) +{ +} + +/* To be set from debugger */ +int _st_iterate_threads_flag = 0; + +void _st_iterate_threads(void) +{ + static _st_thread_t *trd = NULL; + static jmp_buf orig_jb, save_jb; + _st_clist_t *q; + + if (!_st_iterate_threads_flag) { + if (trd) { + memcpy(trd->context, save_jb, sizeof(jmp_buf)); + MD_LONGJMP(orig_jb, 1); + } + return; + } + + if (trd) { + memcpy(trd->context, save_jb, sizeof(jmp_buf)); + _st_show_thread_stack(trd, NULL); + } else { + if (MD_SETJMP(orig_jb)) { + _st_iterate_threads_flag = 0; + trd = NULL; + _st_show_thread_stack(trd, "Iteration completed"); + return; + } + trd = _ST_CURRENT_THREAD(); + _st_show_thread_stack(trd, "Iteration started"); + } + + q = trd->tlink.next; + if (q == &_ST_THREADQ) { + q = q->next; + } + ST_ASSERT(q != &_ST_THREADQ); + trd = _ST_THREAD_THREADQ_PTR(q); + if (trd == _ST_CURRENT_THREAD()) { + MD_LONGJMP(orig_jb, 1); + } + memcpy(save_jb, trd->context, sizeof(jmp_buf)); + MD_LONGJMP(trd->context, 1); +} +#endif /* DEBUG */ + diff --git a/trunk/research/st/srs.c b/trunk/research/st/srs.c new file mode 100644 index 0000000000..09bc5eacca --- /dev/null +++ b/trunk/research/st/srs.c @@ -0,0 +1,497 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "public.h" + +#define srs_trace(msg, ...) printf(msg, ##__VA_ARGS__);printf("\n") + +int io_port = 1990; +int sleep_ms = 100; + +void stack_print(long int previous_sp, int level) +{ + if (level <= 0) { + return; + } + + register long int rsp asm("sp"); + char buf[level * 1024]; + + stack_print(rsp, level - 1); + + srs_trace("%d. psp=%#lx, sp=%#lx, size=%dB(%dB+%dKB)", + level, previous_sp, rsp, (int)(previous_sp - rsp), + (int)(previous_sp - rsp - sizeof(buf)), (int)(sizeof(buf) / 1024)); +} + +int huge_stack_test() +{ + srs_trace("==================================================="); + srs_trace("huge_stack test: start"); + + register long int rsp asm("sp"); + stack_print(rsp, 10); + + srs_trace("huge_stack test: end"); + + return 0; +} + +int sleep_test() +{ + srs_trace("==================================================="); + srs_trace("sleep test: start"); + + srs_trace("1. sleep..."); + st_utime_t start = st_utime(); + st_usleep(sleep_ms * 1000); + st_utime_t end = st_utime(); + + srs_trace("2. sleep ok, sleep=%dus, deviation=%dus", + (int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000)); + + srs_trace("sleep test: end"); + + return 0; +} + +void* sleep2_func0(void* arg) +{ + int sleep_ms = 100; + st_utime_t start = st_utime(); + st_usleep(sleep_ms * 1000); + st_utime_t end = st_utime(); + + srs_trace("sleep ok, sleep=%dus, deviation=%dus", + (int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000)); + + return NULL; +} + +void* sleep2_func1(void* arg) +{ + int sleep_ms = 250; + st_utime_t start = st_utime(); + st_usleep(sleep_ms * 1000); + st_utime_t end = st_utime(); + + srs_trace("sleep ok, sleep=%dus, deviation=%dus", + (int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000)); + + return NULL; +} + +int sleep2_test() +{ + srs_trace("==================================================="); + srs_trace("sleep2 test: start"); + + st_thread_t trd0 = st_thread_create(sleep2_func0, NULL, 1, 0); + st_thread_t trd1 = st_thread_create(sleep2_func1, NULL, 1, 0); + st_thread_join(trd0, NULL); + st_thread_join(trd1, NULL); + + srs_trace("sleep test: end"); + + return 0; +} + +st_mutex_t sleep_work_cond = NULL; +void* sleep_deviation_func(void* arg) +{ + st_mutex_lock(sleep_work_cond); + srs_trace("2. work thread start."); + + int64_t i; + for (i = 0; i < 3000000000ULL; i++) { + } + + st_mutex_unlock(sleep_work_cond); + srs_trace("3. work thread end."); + + return NULL; +} + +int sleep_deviation_test() +{ + srs_trace("==================================================="); + srs_trace("sleep deviation test: start"); + + sleep_work_cond = st_mutex_new(); + + st_thread_create(sleep_deviation_func, NULL, 0, 0); + st_mutex_lock(sleep_work_cond); + + srs_trace("1. sleep..."); + st_utime_t start = st_utime(); + + // other thread to do some complex work. + st_mutex_unlock(sleep_work_cond); + st_usleep(1000 * 1000); + + st_utime_t end = st_utime(); + + srs_trace("4. sleep ok, sleep=%dus, deviation=%dus", + (int)(sleep_ms * 1000), (int)(end - start - sleep_ms * 1000)); + + st_mutex_lock(sleep_work_cond); + srs_trace("sleep deviation test: end"); + + st_mutex_destroy(sleep_work_cond); + + return 0; +} + +void* thread_func(void* arg) +{ + srs_trace("1. thread run"); + st_usleep(sleep_ms * 1000); + srs_trace("2. thread completed"); + return NULL; +} + +int thread_test() +{ + srs_trace("==================================================="); + srs_trace("thread test: start"); + + st_thread_t trd = st_thread_create(thread_func, NULL, 1, 0); + if (trd == NULL) { + srs_trace("st_thread_create failed"); + return -1; + } + + st_thread_join(trd, NULL); + srs_trace("3. thread joined"); + + srs_trace("thread test: end"); + + return 0; +} + +st_mutex_t sync_start = NULL; +st_cond_t sync_cond = NULL; +st_mutex_t sync_mutex = NULL; +st_cond_t sync_end = NULL; + +void* sync_master(void* arg) +{ + // wait for main to sync_start this thread. + st_mutex_lock(sync_start); + st_mutex_unlock(sync_start); + + st_usleep(sleep_ms * 1000); + st_cond_signal(sync_cond); + + st_mutex_lock(sync_mutex); + srs_trace("2. st mutex is ok"); + st_mutex_unlock(sync_mutex); + + st_usleep(sleep_ms * 1000); + srs_trace("3. st thread is ok"); + st_cond_signal(sync_cond); + + return NULL; +} + +void* sync_slave(void* arg) +{ + // lock mutex to control thread. + st_mutex_lock(sync_mutex); + + // wait for main to sync_start this thread. + st_mutex_lock(sync_start); + st_mutex_unlock(sync_start); + + // wait thread to ready. + st_cond_wait(sync_cond); + srs_trace("1. st cond is ok"); + + // release mutex to control thread + st_usleep(sleep_ms * 1000); + st_mutex_unlock(sync_mutex); + + // wait thread to exit. + st_cond_wait(sync_cond); + srs_trace("4. st is ok"); + + st_cond_signal(sync_end); + + return NULL; +} + +int sync_test() +{ + srs_trace("==================================================="); + srs_trace("sync test: start"); + + if ((sync_start = st_mutex_new()) == NULL) { + srs_trace("st_mutex_new sync_start failed"); + return -1; + } + st_mutex_lock(sync_start); + + if ((sync_cond = st_cond_new()) == NULL) { + srs_trace("st_cond_new cond failed"); + return -1; + } + + if ((sync_end = st_cond_new()) == NULL) { + srs_trace("st_cond_new end failed"); + return -1; + } + + if ((sync_mutex = st_mutex_new()) == NULL) { + srs_trace("st_mutex_new mutex failed"); + return -1; + } + + if (!st_thread_create(sync_master, NULL, 0, 0)) { + srs_trace("st_thread_create failed"); + return -1; + } + + if (!st_thread_create(sync_slave, NULL, 0, 0)) { + srs_trace("st_thread_create failed"); + return -1; + } + + // run all threads. + st_mutex_unlock(sync_start); + + st_cond_wait(sync_end); + srs_trace("sync test: end"); + + return 0; +} + +void* io_client(void* arg) +{ + + int fd; + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + srs_trace("create linux socket error."); + return NULL; + } + srs_trace("6. client create linux socket success. fd=%d", fd); + + st_netfd_t stfd; + if ((stfd = st_netfd_open_socket(fd)) == NULL){ + srs_trace("st_netfd_open_socket open socket failed."); + return NULL; + } + srs_trace("7. client st open socket success. fd=%d", fd); + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(io_port); + addr.sin_addr.s_addr = INADDR_ANY; + if (st_connect(stfd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_in), ST_UTIME_NO_TIMEOUT) == -1) { + srs_trace("bind socket error."); + return NULL; + } + + char buf[1024]; + if (st_read_fully(stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) { + srs_trace("st_read_fully failed"); + return NULL; + } + if (st_write(stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) { + srs_trace("st_write failed"); + return NULL; + } + + st_netfd_close(stfd); + + return NULL; +} + +int io_test() +{ + srs_trace("==================================================="); + srs_trace("io test: start, port=%d", io_port); + + int fd; + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + srs_trace("create linux socket error."); + return -1; + } + srs_trace("1. server create linux socket success. fd=%d", fd); + + int reuse_socket = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) { + srs_trace("setsockopt reuse-addr error."); + return -1; + } + srs_trace("2. server setsockopt reuse-addr success. fd=%d", fd); + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(io_port); + addr.sin_addr.s_addr = INADDR_ANY; + if (bind(fd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) { + srs_trace("bind socket error."); + return -1; + } + srs_trace("3. server bind socket success. fd=%d", fd); + + if (listen(fd, 10) == -1) { + srs_trace("listen socket error."); + return -1; + } + srs_trace("4. server listen socket success. fd=%d", fd); + + st_netfd_t stfd; + if ((stfd = st_netfd_open_socket(fd)) == NULL){ + srs_trace("st_netfd_open_socket open socket failed."); + return -1; + } + srs_trace("5. server st open socket success. fd=%d", fd); + + if (!st_thread_create(io_client, NULL, 0, 0)) { + srs_trace("st_thread_create failed"); + return -1; + } + + st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT); + srs_trace("8. server get a client. fd=%d", st_netfd_fileno(client_stfd)); + + char buf[1024]; + if (st_write(client_stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) { + srs_trace("st_write failed"); + return -1; + } + if (st_read_fully(client_stfd, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) != sizeof(buf)) { + srs_trace("st_read_fully failed"); + return -1; + } + srs_trace("9. server io completed."); + + st_netfd_close(stfd); + st_netfd_close(client_stfd); + + srs_trace("io test: end"); + return 0; +} + +int pipe_test() +{ + srs_trace("==================================================="); + srs_trace("pipe test: start"); + + int fds[2]; + if (pipe(fds) < 0) { + srs_trace("pipe failed"); + return -1; + } + srs_trace("1. pipe ok, %d=>%d", fds[1], fds[0]); + + st_netfd_t fdw; + if ((fdw = st_netfd_open_socket(fds[1])) == NULL) { + srs_trace("st_netfd_open_socket open socket failed."); + return -1; + } + srs_trace("2. open write fd ok"); + + st_netfd_t fdr; + if ((fdr = st_netfd_open_socket(fds[0])) == NULL) { + srs_trace("st_netfd_open_socket open socket failed."); + return -1; + } + srs_trace("3. open read fd ok"); + + char buf[1024]; + if (st_write(fdw, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) < 0) { + srs_trace("st_write socket failed."); + return -1; + } + srs_trace("4. write to pipe ok"); + + if (st_read(fdr, buf, sizeof(buf), ST_UTIME_NO_TIMEOUT) < 0) { + srs_trace("st_read socket failed."); + return -1; + } + srs_trace("5. read from pipe ok"); + + st_netfd_close(fdw); + st_netfd_close(fdr); + + srs_trace("pipe test: end"); + return 0; +} + +int main(int argc, char** argv) +{ + srs_trace("ETIME=%d", ETIME); + + if (st_set_eventsys(ST_EVENTSYS_ALT) < 0) { + srs_trace("st_set_eventsys failed"); + return -1; + } + + if (st_init() < 0) { + srs_trace("st_init failed"); + return -1; + } + + if (sleep2_test() < 0) { + srs_trace("sleep2_test failed"); + return -1; + } + + if (sleep_test() < 0) { + srs_trace("sleep_test failed"); + return -1; + } + + if (sleep_deviation_test() < 0) { + srs_trace("sleep_deviation_test failed"); + return -1; + } + + if (huge_stack_test() < 0) { + srs_trace("huge_stack_test failed"); + return -1; + } + + if (thread_test() < 0) { + srs_trace("thread_test failed"); + return -1; + } + + if (sync_test() < 0) { + srs_trace("sync_test failed"); + return -1; + } + + if (io_test() < 0) { + srs_trace("io_test failed"); + return -1; + } + + if (pipe_test() < 0) { + srs_trace("pipe_test failed"); + return -1; + } + + // cleanup. + srs_trace("wait for all thread completed"); + st_thread_exit(NULL); + // the following never enter, + // the above code will exit when all thread exit, + // current is a primordial st-thread, when all thread exit, + // the st idle thread will exit(0), see _st_idle_thread_start() + srs_trace("all thread completed"); + + return 0; +} + diff --git a/trunk/research/st/st/init b/trunk/research/st/st/init new file mode 100644 index 0000000000..61604b75fb --- /dev/null +++ b/trunk/research/st/st/init @@ -0,0 +1,3 @@ +#ifndef _st_icpp_init_stub +#define _st_icpp_init_stub +#endif diff --git a/trunk/research/st/st/st.upp b/trunk/research/st/st/st.upp new file mode 100755 index 0000000000..dab6d49589 --- /dev/null +++ b/trunk/research/st/st/st.upp @@ -0,0 +1,18 @@ +file + main readonly separator, + ..\srs.c, + st readonly separator, + ..\common.h, + ..\event.c, + ..\io.c, + ..\key.c, + ..\md.h, + ..\md.S, + ..\public.h, + ..\sched.c, + ..\stk.c, + ..\sync.c; + +mainconfig + "" = "MAIN"; + diff --git a/trunk/research/st/stk.c b/trunk/research/st/stk.c new file mode 100644 index 0000000000..c26223ba5f --- /dev/null +++ b/trunk/research/st/stk.c @@ -0,0 +1,169 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#include +#include +#include +#include +#include +#include "common.h" + +/* How much space to leave between the stacks, at each end */ +#define REDZONE _ST_PAGE_SIZE + +_st_clist_t _st_free_stacks = ST_INIT_STATIC_CLIST(&_st_free_stacks); +int _st_num_free_stacks = 0; +int _st_randomize_stacks = 0; + +static char *_st_new_stk_segment(int size); + +/** +The below comments is by winlin: +The stack memory struct: + | REDZONE | stack | extra | REDZONE | + +---------+------------------------+---------+---------+ + | 4k | | 4k/0 | 4k | + +---------+------------------------+---------+---------+ + vaddr bottom top +When _st_randomize_stacks is on, by st_randomize_stacks(), +the bottom and top will random movided in the extra: + long offset = (random() % extra) & ~0xf; + ts->stk_bottom += offset; + ts->stk_top += offset; +Both REDZONE are protected by mprotect when DEBUG is on. +*/ +_st_stack_t *_st_stack_new(int stack_size) +{ + _st_clist_t *qp; + _st_stack_t *ts; + int extra; + + // TODO: WINLIN: remove the stack reuse. + for (qp = _st_free_stacks.next; qp != &_st_free_stacks; qp = qp->next) { + ts = _ST_THREAD_STACK_PTR(qp); + if (ts->stk_size >= stack_size) { + /* Found a stack that is big enough */ + ST_REMOVE_LINK(&ts->links); + _st_num_free_stacks--; + ts->links.next = NULL; + ts->links.prev = NULL; + return ts; + } + } + + /* Make a new thread stack object. */ + if ((ts = (_st_stack_t *)calloc(1, sizeof(_st_stack_t))) == NULL) { + return NULL; + } + extra = _st_randomize_stacks ? _ST_PAGE_SIZE : 0; + ts->vaddr_size = stack_size + 2*REDZONE + extra; + ts->vaddr = _st_new_stk_segment(ts->vaddr_size); + if (!ts->vaddr) { + free(ts); + return NULL; + } + ts->stk_size = stack_size; + ts->stk_bottom = ts->vaddr + REDZONE; + ts->stk_top = ts->stk_bottom + stack_size; + +#ifdef DEBUG + mprotect(ts->vaddr, REDZONE, PROT_NONE); + mprotect(ts->stk_top + extra, REDZONE, PROT_NONE); +#endif + + if (extra) { + long offset = (random() % extra) & ~0xf; + + ts->stk_bottom += offset; + ts->stk_top += offset; + } + + return ts; +} + +/* + * Free the stack for the current thread + */ +void _st_stack_free(_st_stack_t *ts) +{ + if (!ts) { + return; + } + + /* Put the stack on the free list */ + ST_APPEND_LINK(&ts->links, _st_free_stacks.prev); + _st_num_free_stacks++; +} + +static char *_st_new_stk_segment(int size) +{ +#ifdef MALLOC_STACK + void *vaddr = malloc(size); +#else + #error "Only Supports Malloc Stack" +#endif + + return (char *)vaddr; +} + +/* Not used */ +#if 0 +void _st_delete_stk_segment(char *vaddr, int size) +{ +#ifdef MALLOC_STACK + free(vaddr); +#else + #error Unknown Stack Malloc +#endif +} +#endif + +int st_randomize_stacks(int on) +{ + int wason = _st_randomize_stacks; + + _st_randomize_stacks = on; + if (on) { + srandom((unsigned int) st_utime()); + } + + return wason; +} diff --git a/trunk/research/st/sync.c b/trunk/research/st/sync.c new file mode 100644 index 0000000000..3e5324084a --- /dev/null +++ b/trunk/research/st/sync.c @@ -0,0 +1,352 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime library. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): Silicon Graphics, Inc. + * + * Portions created by SGI are Copyright (C) 2000-2001 Silicon + * Graphics, Inc. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * This file is derived directly from Netscape Communications Corporation, + * and consists of extensive modifications made during the year(s) 1999-2000. + */ + +#include +#include +#include +#include "common.h" + +extern time_t _st_curr_time; +extern st_utime_t _st_last_tset; +extern int _st_active_count; + +static st_utime_t (*_st_utime)(void) = NULL; + +/***************************************** + * Time functions + */ + +st_utime_t st_utime(void) +{ + if (_st_utime == NULL) { +#ifdef MD_GET_UTIME + MD_GET_UTIME(); +#else + #error Unknown OS +#endif + } + + return (*_st_utime)(); +} + +int st_set_utime_function(st_utime_t (*func)(void)) +{ + if (_st_active_count) { + errno = EINVAL; + return -1; + } + + _st_utime = func; + + return 0; +} + +st_utime_t st_utime_last_clock(void) +{ + return _ST_LAST_CLOCK; +} + +int st_timecache_set(int on) +{ + int wason = (_st_curr_time) ? 1 : 0; + + if (on) { + _st_curr_time = time(NULL); + _st_last_tset = st_utime(); + } else { + _st_curr_time = 0; + } + + return wason; +} + +time_t st_time(void) +{ + if (_st_curr_time) { + return _st_curr_time; + } + + return time(NULL); +} + +int st_usleep(st_utime_t usecs) +{ + _st_thread_t *me = _ST_CURRENT_THREAD(); + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + if (usecs != ST_UTIME_NO_TIMEOUT) { + me->state = _ST_ST_SLEEPING; + _ST_ADD_SLEEPQ(me, usecs); + } else { + me->state = _ST_ST_SUSPENDED; + } + + _ST_SWITCH_CONTEXT(me); + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + return 0; +} + +int st_sleep(int secs) +{ + return st_usleep((secs >= 0) ? secs * (st_utime_t) 1000000LL : ST_UTIME_NO_TIMEOUT); +} + +/***************************************** + * Condition variable functions + */ +_st_cond_t *st_cond_new(void) +{ + _st_cond_t *cvar; + + cvar = (_st_cond_t *) calloc(1, sizeof(_st_cond_t)); + if (cvar) { + ST_INIT_CLIST(&cvar->wait_q); + } + + return cvar; +} + +int st_cond_destroy(_st_cond_t *cvar) +{ + if (cvar->wait_q.next != &cvar->wait_q) { + errno = EBUSY; + return -1; + } + + free(cvar); + + return 0; +} + +int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout) +{ + _st_thread_t *me = _ST_CURRENT_THREAD(); + int rv; + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + /* Put caller thread on the condition variable's wait queue */ + me->state = _ST_ST_COND_WAIT; + ST_APPEND_LINK(&me->wait_links, &cvar->wait_q); + + if (timeout != ST_UTIME_NO_TIMEOUT) { + _ST_ADD_SLEEPQ(me, timeout); + } + + _ST_SWITCH_CONTEXT(me); + + ST_REMOVE_LINK(&me->wait_links); + rv = 0; + + if (me->flags & _ST_FL_TIMEDOUT) { + me->flags &= ~_ST_FL_TIMEDOUT; + errno = ETIME; + rv = -1; + } + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + rv = -1; + } + + return rv; +} + +int st_cond_wait(_st_cond_t *cvar) +{ + return st_cond_timedwait(cvar, ST_UTIME_NO_TIMEOUT); +} + +static int _st_cond_signal(_st_cond_t *cvar, int broadcast) +{ + _st_thread_t *thread; + _st_clist_t *q; + + for (q = cvar->wait_q.next; q != &cvar->wait_q; q = q->next) { + thread = _ST_THREAD_WAITQ_PTR(q); + if (thread->state == _ST_ST_COND_WAIT) { + if (thread->flags & _ST_FL_ON_SLEEPQ) { + _ST_DEL_SLEEPQ(thread); + } + + /* Make thread runnable */ + thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(thread); + if (!broadcast) { + break; + } + } + } + + return 0; +} + +int st_cond_signal(_st_cond_t *cvar) +{ + return _st_cond_signal(cvar, 0); +} + +int st_cond_broadcast(_st_cond_t *cvar) +{ + return _st_cond_signal(cvar, 1); +} + +/***************************************** + * Mutex functions + */ +_st_mutex_t *st_mutex_new(void) +{ + _st_mutex_t *lock; + + lock = (_st_mutex_t *) calloc(1, sizeof(_st_mutex_t)); + if (lock) { + ST_INIT_CLIST(&lock->wait_q); + lock->owner = NULL; + } + + return lock; +} + +int st_mutex_destroy(_st_mutex_t *lock) +{ + if (lock->owner != NULL || lock->wait_q.next != &lock->wait_q) { + errno = EBUSY; + return -1; + } + + free(lock); + + return 0; +} + +int st_mutex_lock(_st_mutex_t *lock) +{ + _st_thread_t *me = _ST_CURRENT_THREAD(); + + if (me->flags & _ST_FL_INTERRUPT) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + if (lock->owner == NULL) { + /* Got the mutex */ + lock->owner = me; + return 0; + } + + if (lock->owner == me) { + errno = EDEADLK; + return -1; + } + + /* Put caller thread on the mutex's wait queue */ + me->state = _ST_ST_LOCK_WAIT; + ST_APPEND_LINK(&me->wait_links, &lock->wait_q); + + _ST_SWITCH_CONTEXT(me); + + ST_REMOVE_LINK(&me->wait_links); + + if ((me->flags & _ST_FL_INTERRUPT) && lock->owner != me) { + me->flags &= ~_ST_FL_INTERRUPT; + errno = EINTR; + return -1; + } + + return 0; +} + +int st_mutex_unlock(_st_mutex_t *lock) +{ + _st_thread_t *thread; + _st_clist_t *q; + + if (lock->owner != _ST_CURRENT_THREAD()) { + errno = EPERM; + return -1; + } + + for (q = lock->wait_q.next; q != &lock->wait_q; q = q->next) { + thread = _ST_THREAD_WAITQ_PTR(q); + if (thread->state == _ST_ST_LOCK_WAIT) { + lock->owner = thread; + /* Make thread runnable */ + thread->state = _ST_ST_RUNNABLE; + _ST_ADD_RUNQ(thread); + return 0; + } + } + + /* No threads waiting on this mutex */ + lock->owner = NULL; + + return 0; +} + +int st_mutex_trylock(_st_mutex_t *lock) +{ + if (lock->owner != NULL) { + errno = EBUSY; + return -1; + } + + /* Got the mutex */ + lock->owner = _ST_CURRENT_THREAD(); + + return 0; +} + diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index 7ebb10b146..b33b4f6f8e 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -72,7 +72,7 @@ SrsUdpListener::SrsUdpListener(ISrsUdpHandler* h, string i, int p) handler = h; ip = i; port = p; - lfd = -1; + lfd = NULL; nb_buf = SRS_UDP_MAX_PACKET_SIZE; buf = new char[nb_buf]; @@ -148,7 +148,7 @@ SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p) ip = i; port = p; - lfd = -1; + lfd = NULL; trd = new SrsDummyCoroutine(); } @@ -161,7 +161,7 @@ SrsTcpListener::~SrsTcpListener() int SrsTcpListener::fd() { - return srs_netfd_fileno(lfd); + return srs_netfd_fileno(lfd);; } srs_error_t SrsTcpListener::listen() @@ -191,10 +191,10 @@ srs_error_t SrsTcpListener::cycle() } srs_netfd_t fd = srs_accept(lfd, NULL, NULL, SRS_UTIME_NO_TIMEOUT); - if(fd < 0){ + if(fd == NULL){ return srs_error_new(ERROR_SOCKET_ACCEPT, "accept at fd=%d", srs_netfd_fileno(lfd)); } - + if ((err = srs_fd_closeexec(srs_netfd_fileno(fd))) != srs_success) { return srs_error_wrap(err, "set closeexec"); } diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index e42f8314b2..61eeb23094 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -32,8 +32,6 @@ #include using namespace std; -#include - #include #include #include @@ -346,7 +344,7 @@ SrsSignalManager::SrsSignalManager(SrsServer* s) server = s; sig_pipe[0] = sig_pipe[1] = -1; trd = new SrsSTCoroutine("signal", this); - signal_read_stfd = -1; + signal_read_stfd = NULL; } SrsSignalManager::~SrsSignalManager() @@ -370,7 +368,7 @@ srs_error_t SrsSignalManager::initialize() return srs_error_new(ERROR_SYSTEM_CREATE_PIPE, "create pipe"); } - if ((signal_read_stfd = srs_netfd_open(sig_pipe[0])) < 0) { + if ((signal_read_stfd = srs_netfd_open(sig_pipe[0])) == NULL) { return srs_error_new(ERROR_SYSTEM_CREATE_PIPE, "open pipe"); } @@ -796,7 +794,7 @@ srs_error_t SrsServer::ingest() srs_error_t SrsServer::cycle() { srs_error_t err = do_cycle(); - + #ifdef SRS_AUTO_GPERF_MC destroy(); @@ -887,10 +885,6 @@ srs_error_t SrsServer::do_cycle() // the daemon thread, update the time cache // TODO: FIXME: use SrsHourGlass. - - // FIXME: libco will take over user's event loop - co_eventloop(co_get_epoll_ct(), NULL, NULL); - while (true) { if (handler && (err = handler->on_cycle()) != srs_success) { return srs_error_wrap(err, "handle callback"); diff --git a/trunk/src/app/srs_app_st.cpp b/trunk/src/app/srs_app_st.cpp index 5c4c7b87bf..831a0613a7 100755 --- a/trunk/src/app/srs_app_st.cpp +++ b/trunk/src/app/srs_app_st.cpp @@ -23,7 +23,7 @@ #include -#include +#include #include using namespace std; @@ -79,24 +79,13 @@ int SrsDummyCoroutine::cid() return 0; } -void* co_thread_create(void *(*start)(void *arg), void *arg, int joinable, int stack_size) { - (void)joinable; - (void)stack_size; - - stCoRoutine_t *co = NULL; - co_create(&co, NULL, start, arg); - co_resume(co); - return co; -} - -_ST_THREAD_CREATE_PFN _pfn_st_thread_create = (_ST_THREAD_CREATE_PFN)co_thread_create; +_ST_THREAD_CREATE_PFN _pfn_st_thread_create = (_ST_THREAD_CREATE_PFN)st_thread_create; SrsSTCoroutine::SrsSTCoroutine(string n, ISrsCoroutineHandler* h, int cid) { name = n; handler = h; context = cid; - term = co_cond_alloc(); trd = NULL; trd_err = srs_success; started = interrupted = disposed = cycle_done = false; @@ -105,8 +94,7 @@ SrsSTCoroutine::SrsSTCoroutine(string n, ISrsCoroutineHandler* h, int cid) SrsSTCoroutine::~SrsSTCoroutine() { stop(); - - co_cond_free(term); + srs_freep(trd_err); } @@ -154,8 +142,8 @@ void SrsSTCoroutine::stop() // When not started, the rd is NULL. if (trd) { void* res = NULL; - - co_cond_timedwait(term, -1); + int r0 = st_thread_join((st_thread_t)trd, &res); + srs_assert(!r0); srs_error_t err_res = (srs_error_t)res; if (err_res != srs_success) { @@ -183,6 +171,8 @@ void SrsSTCoroutine::interrupt() if (trd_err == srs_success) { trd_err = srs_error_new(ERROR_THREAD_INTERRUPED, "interrupted"); } + + st_thread_interrupt((st_thread_t)trd); } srs_error_t SrsSTCoroutine::pull() @@ -230,9 +220,6 @@ void* SrsSTCoroutine::pfn(void* arg) p->trd_err = err; } - // FIXME: - //co_cond_signal(term); - return (void*)err; } diff --git a/trunk/src/app/srs_app_st.hpp b/trunk/src/app/srs_app_st.hpp index f158d5ba63..956e00b42b 100644 --- a/trunk/src/app/srs_app_st.hpp +++ b/trunk/src/app/srs_app_st.hpp @@ -102,8 +102,6 @@ class SrsDummyCoroutine : public SrsCoroutine typedef void* (*_ST_THREAD_CREATE_PFN)(void *(*start)(void *arg), void *arg, int joinable, int stack_size); extern _ST_THREAD_CREATE_PFN _pfn_st_thread_create; -struct stCoCond_t; - // A ST-coroutine is a lightweight thread, just like the goroutine. // But the goroutine maybe run on different thread, while ST-coroutine only // run in single thread, because it use setjmp and longjmp, so it may cause @@ -122,7 +120,6 @@ class SrsSTCoroutine : public SrsCoroutine std::string name; ISrsCoroutineHandler* handler; private: - stCoCond_t* term; srs_thread_t trd; int context; srs_error_t trd_err; diff --git a/trunk/src/service/srs_service_st.cpp b/trunk/src/service/srs_service_st.cpp index dba7adbe8d..f63cd42794 100644 --- a/trunk/src/service/srs_service_st.cpp +++ b/trunk/src/service/srs_service_st.cpp @@ -23,11 +23,10 @@ #include -#include +#include #include #include #include -#include using namespace std; #include @@ -42,17 +41,6 @@ using namespace std; #ifdef __linux__ #include -static int set_fd_nonblock(int fd) -{ - int flags; - - flags = fcntl(fd, F_GETFL, 0); - flags |= O_NONBLOCK; - flags |= O_NDELAY; - int ret = fcntl(fd, F_SETFL, flags); - return ret; -} - bool srs_st_epoll_is_supported(void) { struct epoll_event ev; @@ -68,12 +56,37 @@ bool srs_st_epoll_is_supported(void) srs_error_t srs_st_init() { +#ifdef __linux__ + // check epoll, some old linux donot support epoll. + // @see https://github.com/ossrs/srs/issues/162 + if (!srs_st_epoll_is_supported()) { + return srs_error_new(ERROR_ST_SET_EPOLL, "linux epoll disabled"); + } +#endif + + // Select the best event system available on the OS. In Linux this is + // epoll(). On BSD it will be kqueue. + if (st_set_eventsys(ST_EVENTSYS_ALT) == -1) { + return srs_error_new(ERROR_ST_SET_EPOLL, "st enable st failed, current is %s", st_get_eventsys_name()); + } + + int r0 = 0; + if((r0 = st_init()) != 0){ + return srs_error_new(ERROR_ST_INITIALIZE, "st initialize failed, r0=%d", r0); + } + srs_trace("st_init success, use %s", st_get_eventsys_name()); + return srs_success; } void srs_close_stfd(srs_netfd_t& stfd) { - ::close(stfd); + if (stfd) { + // we must ensure the close is ok. + int err = st_netfd_close((st_netfd_t)stfd); + srs_assert(err != -1); + stfd = NULL; + } } srs_error_t srs_fd_closeexec(int fd) @@ -131,17 +144,18 @@ srs_error_t srs_fd_keepalive(int fd) srs_thread_t srs_thread_self() { - return (srs_thread_t)co_self(); + return (srs_thread_t)st_thread_self(); } srs_error_t srs_tcp_connect(string server, int port, srs_utime_t tm, srs_netfd_t* pstfd) { - srs_utime_t timeout = SRS_UTIME_NO_TIMEOUT; + st_utime_t timeout = ST_UTIME_NO_TIMEOUT; if (tm != SRS_UTIME_NO_TIMEOUT) { timeout = tm; } - - (void)timeout; + + *pstfd = NULL; + srs_netfd_t stfd = NULL; char sport[8]; snprintf(sport, sizeof(sport), "%d", port); @@ -161,15 +175,20 @@ srs_error_t srs_tcp_connect(string server, int port, srs_utime_t tm, srs_netfd_t if(sock == -1){ return srs_error_new(ERROR_SOCKET_CREATE, "create socket"); } - - *pstfd = sock; - // TODO: timeout - if (connect(sock, r->ai_addr, r->ai_addrlen) == -1) { - srs_close_stfd(sock); + srs_assert(!stfd); + stfd = st_netfd_open_socket(sock); + if(stfd == NULL){ + ::close(sock); + return srs_error_new(ERROR_ST_OPEN_SOCKET, "open socket"); + } + + if (st_connect((st_netfd_t)stfd, r->ai_addr, r->ai_addrlen, timeout) == -1){ + srs_close_stfd(stfd); return srs_error_new(ERROR_ST_CONNECT, "connect to %s:%d", server.c_str(), port); } + *pstfd = stfd; return srs_success; } @@ -195,7 +214,7 @@ srs_error_t do_srs_tcp_listen(int fd, addrinfo* r, srs_netfd_t* pfd) return srs_error_wrap(err, "set reuseport"); } - if (::bind(fd, r->ai_addr, r->ai_addrlen) == -1) { + if (bind(fd, r->ai_addr, r->ai_addrlen) == -1) { return srs_error_new(ERROR_SOCKET_BIND, "bind"); } @@ -203,6 +222,10 @@ srs_error_t do_srs_tcp_listen(int fd, addrinfo* r, srs_netfd_t* pfd) return srs_error_new(ERROR_SOCKET_LISTEN, "listen"); } + if ((*pfd = srs_netfd_open_socket(fd)) == NULL){ + return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open"); + } + return err; } @@ -232,15 +255,11 @@ srs_error_t srs_tcp_listen(std::string ip, int port, srs_netfd_t* pfd) r->ai_family, r->ai_socktype, r->ai_protocol); } - set_fd_nonblock(fd); - if ((err = do_srs_tcp_listen(fd, r, pfd)) != srs_success) { ::close(fd); return srs_error_wrap(err, "fd=%d", fd); } - *pfd = fd; - return err; } @@ -264,6 +283,10 @@ srs_error_t do_srs_udp_listen(int fd, addrinfo* r, srs_netfd_t* pfd) return srs_error_new(ERROR_SOCKET_BIND, "bind"); } + if ((*pfd = srs_netfd_open_socket(fd)) == NULL){ + return srs_error_new(ERROR_ST_OPEN_SOCKET, "st open"); + } + return err; } @@ -303,121 +326,85 @@ srs_error_t srs_udp_listen(std::string ip, int port, srs_netfd_t* pfd) srs_cond_t srs_cond_new() { - return (srs_cond_t)co_cond_alloc(); + return (srs_cond_t)st_cond_new(); } int srs_cond_destroy(srs_cond_t cond) { - return co_cond_free((stCoCond_t*)cond); + return st_cond_destroy((st_cond_t)cond); } int srs_cond_wait(srs_cond_t cond) { - return co_cond_timedwait((stCoCond_t*)cond, -1); + return st_cond_wait((st_cond_t)cond); } int srs_cond_timedwait(srs_cond_t cond, srs_utime_t timeout) { - return co_cond_timedwait((stCoCond_t*)cond, timeout); + return st_cond_timedwait((st_cond_t)cond, (st_utime_t)timeout); } int srs_cond_signal(srs_cond_t cond) { - return co_cond_signal((stCoCond_t*)cond); + return st_cond_signal((st_cond_t)cond); } srs_mutex_t srs_mutex_new() { - return NULL; + return (srs_mutex_t)st_mutex_new(); } int srs_mutex_destroy(srs_mutex_t mutex) { - return 0; + if (!mutex) { + return 0; + } + return st_mutex_destroy((st_mutex_t)mutex); } int srs_mutex_lock(srs_mutex_t mutex) { - return 0; + return st_mutex_lock((st_mutex_t)mutex); } int srs_mutex_unlock(srs_mutex_t mutex) { - return 0; + return st_mutex_unlock((st_mutex_t)mutex); } int srs_netfd_fileno(srs_netfd_t stfd) { - return stfd; + return st_netfd_fileno((st_netfd_t)stfd); } int srs_usleep(srs_utime_t usecs) { - // XXX: libco has no API like co_sleep, use co_cond_timedwait instead - stCoCond_t* cond = co_cond_alloc(); - co_cond_timedwait(cond, usecs/1000.0); - - return 0; + return st_usleep((st_utime_t)usecs); } srs_netfd_t srs_netfd_open_socket(int osfd) { - set_fd_nonblock(osfd); - return osfd; + return (srs_netfd_t)st_netfd_open_socket(osfd); } srs_netfd_t srs_netfd_open(int osfd) { - set_fd_nonblock(osfd); - return osfd; + return (srs_netfd_t)st_netfd_open(osfd); } int srs_recvfrom(srs_netfd_t stfd, void *buf, int len, struct sockaddr *from, int *fromlen, srs_utime_t timeout) { - // TODO: timeout - return recvfrom(stfd, buf, len, 0, from, (socklen_t*)fromlen); + return st_recvfrom((st_netfd_t)stfd, buf, len, from, fromlen, (st_utime_t)timeout); } srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout) { - struct pollfd pf = { 0 }; - pf.fd = stfd; - pf.events = (POLLIN | POLLERR | POLLHUP); - - srs_utime_t atm = timeout; - if (atm != SRS_UTIME_NO_TIMEOUT) - atm /= 1000; - - int client_fd; - while ((client_fd = accept(stfd, addr, (socklen_t*)addrlen)) < 0) { - if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { - return -1; - } - - co_poll(co_get_epoll_ct(), &pf, 1, atm); - } - - set_fd_nonblock(client_fd); - - return client_fd; + return (srs_netfd_t)st_accept((st_netfd_t)stfd, addr, addrlen, (st_utime_t)timeout); } ssize_t srs_read(srs_netfd_t stfd, void *buf, size_t nbyte, srs_utime_t timeout) { - struct pollfd pf = { 0 }; - pf.fd = stfd; - pf.events = (POLLIN | POLLERR | POLLHUP); - - int n; - while ((n = ::read(stfd, buf, nbyte)) < 0) { - if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { - return -1; - } - - co_poll(co_get_epoll_ct(), &pf, 1, timeout); - } - - return n; + return st_read((st_netfd_t)stfd, buf, nbyte, (st_utime_t)timeout); } bool srs_is_never_timeout(srs_utime_t tm) @@ -427,6 +414,7 @@ bool srs_is_never_timeout(srs_utime_t tm) SrsStSocket::SrsStSocket() { + stfd = NULL; stm = rtm = SRS_UTIME_NO_TIMEOUT; rbytes = sbytes = 0; } @@ -477,15 +465,15 @@ srs_error_t SrsStSocket::read(void* buf, size_t size, ssize_t* nread) ssize_t nb_read; if (rtm == SRS_UTIME_NO_TIMEOUT) { - nb_read = srs_read(stfd, buf, size, -1); + nb_read = st_read((st_netfd_t)stfd, buf, size, ST_UTIME_NO_TIMEOUT); } else { - nb_read = srs_read(stfd, buf, size, rtm / 1000); + nb_read = st_read((st_netfd_t)stfd, buf, size, rtm); } if (nread) { *nread = nb_read; } - + // On success a non-negative integer indicating the number of bytes actually read is returned // (a value of 0 means the network connection is closed or end of file is reached). // Otherwise, a value of -1 is returned and errno is set to indicate the error. @@ -511,25 +499,13 @@ srs_error_t SrsStSocket::read_fully(void* buf, size_t size, ssize_t* nread) { srs_error_t err = srs_success; - ssize_t nb_read = 0; - - int wait_read_bytes = size; - while (wait_read_bytes > 0) { - int bytes = ::read(stfd, buf, wait_read_bytes); - if (bytes > 0) { - nb_read += bytes; - wait_read_bytes -= bytes; - if (nb_read == (ssize_t)size) { - break; - } - } else if (bytes == 0) { - break; - } else { - if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR) - break; - } + ssize_t nb_read; + if (rtm == SRS_UTIME_NO_TIMEOUT) { + nb_read = st_read_fully((st_netfd_t)stfd, buf, size, ST_UTIME_NO_TIMEOUT); + } else { + nb_read = st_read_fully((st_netfd_t)stfd, buf, size, rtm); } - + if (nread) { *nread = nb_read; } @@ -559,30 +535,11 @@ srs_error_t SrsStSocket::write(void* buf, size_t size, ssize_t* nwrite) { srs_error_t err = srs_success; - ssize_t nb_write = 0; - - struct pollfd pf = { 0 }; - pf.fd = stfd; - pf.events = (POLLOUT | POLLERR | POLLHUP); - - srs_utime_t wtm = stm; - if (wtm != SRS_UTIME_NO_TIMEOUT) - wtm = stm / 1000; - - int wait_write_bytes = size; - while (wait_write_bytes > 0) { - int n = 0; - if ((n = ::write(stfd, buf, size)) < 0) { - if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { - break; - } - - co_poll(co_get_epoll_ct(), &pf, 1, wtm); - continue; - } - - wait_write_bytes -= n; - nb_write += n; + ssize_t nb_write; + if (stm == SRS_UTIME_NO_TIMEOUT) { + nb_write = st_write((st_netfd_t)stfd, buf, size, ST_UTIME_NO_TIMEOUT); + } else { + nb_write = st_write((st_netfd_t)stfd, buf, size, stm); } if (nwrite) { @@ -609,44 +566,11 @@ srs_error_t SrsStSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite) { srs_error_t err = srs_success; - srs_utime_t tm = stm; - if (tm != SRS_UTIME_NO_TIMEOUT) - tm = stm / 1000; - - int wait_write_bytes = 0; - for (int i = 0; i < iov_size; ++i) - wait_write_bytes += iov[i].iov_len; - - ssize_t nb_write = 0; - iovec* cur_iov = (iovec*)iov; - int cur_iov_size = iov_size; - - while (wait_write_bytes > 0) { - int n = 0; - if ((n = ::writev(stfd, cur_iov, cur_iov_size)) < 0) { - if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) { - break; - } - - struct pollfd pf = {0}; - pf.fd = stfd; - pf.events = (POLLOUT | POLLERR | POLLHUP); - - co_poll(co_get_epoll_ct(), &pf, 1, tm); - continue; - } - - wait_write_bytes -= n; - nb_write += n; - - while (n >= (int)cur_iov->iov_len) { - n -= cur_iov->iov_len; - --cur_iov_size; - ++cur_iov; - } - // FIXME: no modify iov - (*cur_iov).iov_base = (void*)((char*)(*cur_iov).iov_base + n); - (*cur_iov).iov_len -= n; + ssize_t nb_write; + if (stm == SRS_UTIME_NO_TIMEOUT) { + nb_write = st_writev((st_netfd_t)stfd, iov, iov_size, ST_UTIME_NO_TIMEOUT); + } else { + nb_write = st_writev((st_netfd_t)stfd, iov, iov_size, stm); } if (nwrite) { @@ -671,7 +595,7 @@ srs_error_t SrsStSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite) SrsTcpClient::SrsTcpClient(string h, int p, srs_utime_t tm) { - stfd = -1; + stfd = NULL; io = new SrsStSocket(); host = h; @@ -692,7 +616,7 @@ srs_error_t SrsTcpClient::connect() close(); - srs_assert(stfd == -1); + srs_assert(stfd == NULL); if ((err = srs_tcp_connect(host, port, timeout, &stfd)) != srs_success) { return srs_error_wrap(err, "tcp: connect %s:%d to=%dms", host.c_str(), port, srsu2msi(timeout)); } diff --git a/trunk/src/service/srs_service_st.hpp b/trunk/src/service/srs_service_st.hpp index ca6da3f7cc..510b9ba8ac 100644 --- a/trunk/src/service/srs_service_st.hpp +++ b/trunk/src/service/srs_service_st.hpp @@ -31,7 +31,7 @@ #include // Wrap for coroutine. -typedef int srs_netfd_t; +typedef void* srs_netfd_t; typedef void* srs_thread_t; typedef void* srs_cond_t; typedef void* srs_mutex_t; From bc22ebe94921046461e5f96184363695bebca78d Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Fri, 21 Feb 2020 23:50:22 +0800 Subject: [PATCH 03/69] add rtc http request and response, exchange sdp. --- trunk/configure | 2 +- trunk/research/players/srs_rtc_player.html | 90 ++++++++++++++++++ trunk/src/app/srs_app_config.cpp | 41 +++++++- trunk/src/app/srs_app_config.hpp | 7 ++ trunk/src/app/srs_app_http_api.cpp | 105 +++++++++++++++++++++ trunk/src/app/srs_app_http_api.hpp | 9 ++ trunk/src/app/srs_app_rtc_udp.cpp | 89 +++++++++++++++++ trunk/src/app/srs_app_rtc_udp.hpp | 52 ++++++++++ trunk/src/app/srs_app_server.cpp | 78 +++++++++++++++ trunk/src/app/srs_app_server.hpp | 16 ++++ trunk/src/kernel/srs_kernel_error.hpp | 1 + 11 files changed, 488 insertions(+), 2 deletions(-) create mode 100644 trunk/research/players/srs_rtc_player.html create mode 100644 trunk/src/app/srs_app_rtc_udp.cpp create mode 100644 trunk/src/app/srs_app_rtc_udp.hpp diff --git a/trunk/configure b/trunk/configure index d233f66dbb..5efe7eb592 100755 --- a/trunk/configure +++ b/trunk/configure @@ -254,7 +254,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" - "srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" + "srs_app_mpegts_udp" "srs_app_rtc_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" "srs_app_coworkers" "srs_app_hybrid") diff --git a/trunk/research/players/srs_rtc_player.html b/trunk/research/players/srs_rtc_player.html new file mode 100644 index 0000000000..bbb605ab51 --- /dev/null +++ b/trunk/research/players/srs_rtc_player.html @@ -0,0 +1,90 @@ + + + + + + + + +rtc_media_player:
+ + + + + + + diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 2a7b98bd3f..315ec58f7b 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3486,7 +3486,7 @@ srs_error_t SrsConfig::check_normal_config() && n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file" && n != "max_connections" && n != "daemon" && n != "heartbeat" && n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms" - && n != "http_server" && n != "stream_caster" && n != "srt_server" + && n != "http_server" && n != "stream_caster" && n != "rtc" && n != "srt_server" && n != "utc_time" && n != "work_dir" && n != "asprocess" && n != "ff_log_level" && n != "grace_final_wait" && n != "force_grace_quit" && n != "grace_start_wait" @@ -4216,6 +4216,45 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* conf) return ::atoi(conf->arg0().c_str()); } +int SrsConfig::get_rtc_enabled() +{ + SrsConfDirective* conf = root->get("rtc"); + return get_rtc_enabled(conf); +} + +bool SrsConfig::get_rtc_enabled(SrsConfDirective* conf) +{ + static bool DEFAULT = false; + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("enabled"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + +int SrsConfig::get_rtc_listen() +{ + static int DEFAULT = 9527; + + SrsConfDirective* conf = root->get("rtc"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("listen"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return ::atoi(conf->arg0().c_str()); +} + SrsConfDirective* SrsConfig::get_vhost(string vhost, bool try_default_vhost) { srs_assert(root); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 6a58f2ef83..1f85550f79 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -490,6 +490,13 @@ class SrsConfig virtual int get_stream_caster_rtp_port_min(SrsConfDirective* conf); // Get the max udp port for rtp of stream caster rtsp. virtual int get_stream_caster_rtp_port_max(SrsConfDirective* conf); + +// rtc section +public: + virtual int get_rtc_enabled(); + virtual bool get_rtc_enabled(SrsConfDirective* conf); + virtual int get_rtc_listen(); + // vhost specified section public: // Get the vhost directive by vhost name. diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 5355068eb3..634ba647c7 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -47,6 +47,73 @@ using namespace std; #include #include +string test_sdp = +"v=0\\r\\n" +"o=- 0 0 IN IP4 127.0.0.1\\r\\n" +"s=-\\r\\n" +"t=0 0\\r\\n" +"a=ice-lite\\r\\n" +"a=group:BUNDLE 0 1\\r\\n" +"a=msid-semantic: WMS 6VrfBKXrwK\\r\\n" +"m=audio 9 UDP/TLS/RTP/SAVPF 111\\r\\n" +"c=IN IP4 0.0.0.0\\r\\n" +"a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" +"a=rtcp:9 IN IP4 0.0.0.0\\r\\n" +"a=ice-ufrag:xiaozhihongjohn\\r\\n" +"a=ice-pwd:simple_rtmp_server__john\\r\\n" +"a=ice-options:trickle\\r\\n" +"a=fingerprint:sha-256 76:E8:6A:6D:48:F0:86:58:30:2E:69:56:0F:C6:A1:B8:69:98:5D:73:45:93:37:8E:C4:2B:C7:97:04:18:E4:24\\r\\n" +"a=sendrecv\\r\\n" +"a=mid:0\\r\\n" +"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\\r\\n" +"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" +"a=rtcp-mux\\r\\n" +"a=rtpmap:111 opus/48000/2\\r\\n" +"a=fmtp:111 minptime=10;useinbandfec=1\\r\\n" +"a=maxptime:60\\r\\n" +"a=ssrc:3233846890 cname:o/i14u9pJrxRKAsu\\r\\n" +"a=ssrc:3233846890 msid:6VrfBKXrwK a0\\r\\n" +"a=ssrc:3233846890 mslabel:6VrfBKXrwK\\r\\n" +"a=ssrc:3233846890 label:6VrfBKXrwKa0\\r\\n" +"m=video 9 UDP/TLS/RTP/SAVPF 96 98 102\\r\\n" +"c=IN IP4 0.0.0.0\\r\\n" +"a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" +"a=rtcp:9 IN IP4 0.0.0.0\\r\\n" +"b=as:2000000\\r\\n" +"a=ice-ufrag:xiaozhihongjohn\\r\\n" +"a=ice-pwd:simple_rtmp_server__john\\r\\n" +"a=ice-options:trickle\\r\\n" +"a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\\r\\n" +"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" +"a=extmap:4 urn:3gpp:video-orientation\\r\\n" +"a=fingerprint:sha-256 76:E8:6A:6D:48:F0:86:58:30:2E:69:56:0F:C6:A1:B8:69:98:5D:73:45:93:37:8E:C4:2B:C7:97:04:18:E4:24\\r\\n" +"a=sendrecv\\r\\n" +"a=mid:1\\r\\n" +"a=rtcp-mux\\r\\n" +"a=rtpmap:96 VP8/90000\\r\\n" +"a=rtcp-fb:96 ccm fir\\r\\n" +"a=rtcp-fb:96 nack\\r\\n" +"a=rtcp-fb:96 nack pli\\r\\n" +"a=rtcp-fb:96 goog-remb\\r\\n" +"a=rtcp-fb:96 transport-cc\\r\\n" +"a=rtpmap:98 VP9/90000\\r\\n" +"a=rtcp-fb:98 ccm fir\\r\\n" +"a=rtcp-fb:98 nack\\r\\n" +"a=rtcp-fb:98 nack pli\\r\\n" +"a=rtcp-fb:98 goog-remb\\r\\n" +"a=rtcp-fb:98 transport-cc\\r\\n" +"a=rtpmap:102 H264/90000\\r\\n" +"a=rtcp-fb:102 goog-remb\\r\\n" +"a=rtcp-fb:102 transport-cc\\r\\n" +"a=rtcp-fb:102 ccm fir \\r\\n" +"a=rtcp-fb:102 nack\\r\\n" +"a=rtcp-fb:102 nack pli \\r\\n" +"a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\\r\\n" +"a=ssrc:3233846889 cname:o/i14u9pJrxRKAsu\\r\\n" +"a=ssrc:3233846889 msid:6VrfBKXrwK v0\\r\\n" +"a=ssrc:3233846889 mslabel:6VrfBKXrwK\\r\\n" +"a=ssrc:3233846889 label:6VrfBKXrwKv0\\r\\n"; + srs_error_t srs_api_response_jsonp(ISrsHttpResponseWriter* w, string callback, string data) { srs_error_t err = srs_success; @@ -780,6 +847,44 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa return srs_api_response(w, r, obj->dumps()); } +SrsGoApiSdp::SrsGoApiSdp() +{ +} + +SrsGoApiSdp::~SrsGoApiSdp() +{ +} + +srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) +{ + srs_error_t err = srs_success; + + SrsStatistic* stat = SrsStatistic::instance(); + + // path: {pattern}{stream_id} + // e.g. /api/v1/streams/100 pattern= /api/v1/streams/, stream_id=100 + int sid = r->parse_rest_id(entry->pattern); + + SrsStatisticStream* stream = NULL; + if (sid >= 0 && (stream = stat->find_stream(sid)) == NULL) { + return srs_api_response_code(w, r, ERROR_RTMP_STREAM_NOT_FOUND); + } + + SrsJsonObject* obj = SrsJsonAny::object(); + SrsAutoFree(SrsJsonObject, obj); + + obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); + obj->set("server", SrsJsonAny::integer(stat->server_id())); + + if (r->is_http_post()) { + obj->set("sdp", SrsJsonAny::str(test_sdp.c_str())); + } else { + return srs_go_http_error(w, SRS_CONSTS_HTTP_MethodNotAllowed); + } + + return srs_api_response(w, r, obj->dumps()); +} + SrsGoApiClients::SrsGoApiClients() { } diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 5957ff2f3f..367edababd 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -164,6 +164,15 @@ class SrsGoApiStreams : public ISrsHttpHandler virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); }; +class SrsGoApiSdp : public ISrsHttpHandler +{ +public: + SrsGoApiSdp(); + virtual ~SrsGoApiSdp(); +public: + virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); +}; + class SrsGoApiClients : public ISrsHttpHandler { public: diff --git a/trunk/src/app/srs_app_rtc_udp.cpp b/trunk/src/app/srs_app_rtc_udp.cpp new file mode 100644 index 0000000000..4866c387a3 --- /dev/null +++ b/trunk/src/app/srs_app_rtc_udp.cpp @@ -0,0 +1,89 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +SrsRtcOverUdp::SrsRtcOverUdp() +{ +} + +SrsRtcOverUdp::~SrsRtcOverUdp() +{ +} + +srs_error_t SrsRtcOverUdp::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) +{ + char address_string[64]; + char port_string[16]; + if(getnameinfo(from, fromlen, + (char*)&address_string, sizeof(address_string), + (char*)&port_string, sizeof(port_string), + NI_NUMERICHOST|NI_NUMERICSERV)) { + return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); + } + std::string peer_ip = std::string(address_string); + int peer_port = atoi(port_string); + + srs_error_t err = on_udp_bytes(peer_ip, peer_port, buf, nb_buf); + if (err != srs_success) { + return srs_error_wrap(err, "process udp"); + } + return err; +} + +srs_error_t SrsRtcOverUdp::on_udp_bytes(string host, int port, char* buf, int nb_buf) +{ + srs_error_t err = srs_success; + + srs_trace("recv rtc udp packet from %s:%d, nb_buf=%d", host.c_str(), port, nb_buf); + + return err; +} diff --git a/trunk/src/app/srs_app_rtc_udp.hpp b/trunk/src/app/srs_app_rtc_udp.hpp new file mode 100644 index 0000000000..707b6b830e --- /dev/null +++ b/trunk/src/app/srs_app_rtc_udp.hpp @@ -0,0 +1,52 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_APP_RTC_UDP_HPP +#define SRS_APP_RTC_UDP_HPP + +#include + +struct sockaddr; +#include +#include + +#include +#include +#include + +// The rtc over udp stream receiver +class SrsRtcOverUdp : virtual public ISrsUdpHandler +{ +private: +public: + SrsRtcOverUdp(); + virtual ~SrsRtcOverUdp(); +// Interface ISrsUdpHandler +public: + virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); +private: + virtual srs_error_t on_udp_bytes(std::string host, int port, char* buf, int nb_buf); +}; + +#endif + diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index e95b4734e3..85483a5b9c 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -44,6 +44,7 @@ using namespace std; #include #include #include +#include #include #include #include @@ -108,6 +109,8 @@ std::string srs_listener_type2string(SrsListenerType type) return "RTSP"; case SrsListenerFlv: return "HTTP-FLV"; + case SrsListenerRtcOverUdp: + return "RTC over UDP"; default: return "UNKONWN"; } @@ -335,6 +338,45 @@ SrsUdpCasterListener::~SrsUdpCasterListener() srs_freep(caster); } +SrsRtcListener::SrsRtcListener(SrsServer* svr, SrsListenerType t) : SrsListener(svr, t) +{ + srs_assert(type == SrsListenerRtcOverUdp); + rtc = new SrsRtcOverUdp(); +} + +SrsRtcListener::~SrsRtcListener() +{ +} + +srs_error_t SrsRtcListener::listen(std::string i, int p) +{ + srs_error_t err = srs_success; + + // the caller already ensure the type is ok, + // we just assert here for unknown stream caster. + srs_assert(type == SrsListenerRtcOverUdp); + + ip = i; + port = p; + + srs_freep(listener); + listener = new SrsUdpListener(rtc, ip, port); + + if ((err = listener->listen()) != srs_success) { + return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); + } + + // notify the handler the fd changed. + if ((err = rtc->on_stfd_change(listener->stfd())) != srs_success) { + return srs_error_wrap(err, "notify fd change failed"); + } + + string v = srs_listener_type2string(type); + srs_trace("%s listen at udp://%s:%d, fd=%d", v.c_str(), ip.c_str(), port, listener->fd()); + + return err; +} + SrsSignalManager* SrsSignalManager::instance = NULL; SrsSignalManager::SrsSignalManager(SrsServer* s) @@ -728,6 +770,10 @@ srs_error_t SrsServer::listen() if ((err = listen_stream_caster()) != srs_success) { return srs_error_wrap(err, "stream caster listen"); } + + if ((err = listen_rtc()) != srs_success) { + return srs_error_wrap(err, "rtc listen"); + } if ((err = conn_manager->start()) != srs_success) { return srs_error_wrap(err, "connection manager"); @@ -790,6 +836,9 @@ srs_error_t SrsServer::http_handle() if ((err = http_api_mux->handle("/api/v1/streams/", new SrsGoApiStreams())) != srs_success) { return srs_error_wrap(err, "handle streams"); } + if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp())) != srs_success) { + return srs_error_wrap(err, "handle sdp"); + } if ((err = http_api_mux->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) { return srs_error_wrap(err, "handle clients"); } @@ -1188,6 +1237,35 @@ srs_error_t SrsServer::listen_stream_caster() return err; } +srs_error_t SrsServer::listen_rtc() +{ + srs_error_t err = srs_success; + + close_listeners(SrsListenerRtcOverUdp); + + if (!_srs_config->get_rtc_enabled()) { + return err; + } + + SrsListener* listener = NULL; + + listener = new SrsRtcListener(this, SrsListenerRtcOverUdp); + srs_assert(listener != NULL); + + listeners.push_back(listener); + + int port = _srs_config->get_rtc_listen(); + if (port <= 0) { + return srs_error_new(ERROR_RTC_PORT, "invalid port=%d", port); + } + + if ((err = listener->listen(srs_any_address_for_listener(), port)) != srs_success) { + return srs_error_wrap(err, "listen at %d", port); + } + + return err; +} + void SrsServer::close_listeners(SrsListenerType type) { std::vector::iterator it; diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 28154600e7..77b8964dfa 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -68,6 +68,8 @@ enum SrsListenerType SrsListenerRtsp = 4, // TCP stream, FLV stream over HTTP. SrsListenerFlv = 5, + // UDP sream, rtp over udp + SrsListenerRtcOverUdp = 6, }; // A common tcp listener, for RTMP/HTTP server. @@ -155,6 +157,19 @@ class SrsUdpCasterListener : public SrsUdpStreamListener virtual ~SrsUdpCasterListener(); }; +// A UDP listener, for udp stream caster server. +class SrsRtcListener : public SrsListener +{ +protected: + SrsUdpListener* listener; + ISrsUdpHandler* rtc; +public: + SrsRtcListener(SrsServer* svr, SrsListenerType t); + virtual ~SrsRtcListener(); +public: + virtual srs_error_t listen(std::string i, int p); +}; + // Convert signal to io, // @see: st-1.9/docs/notes.html class SrsSignalManager : public ISrsCoroutineHandler @@ -284,6 +299,7 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan virtual srs_error_t listen_http_api(); virtual srs_error_t listen_http_stream(); virtual srs_error_t listen_stream_caster(); + virtual srs_error_t listen_rtc(); // Close the listeners for specified type, // Remove the listen object from manager. virtual void close_listeners(SrsListenerType type); diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index f7375780a1..372a0196ae 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -321,6 +321,7 @@ #define ERROR_HTTP_302_INVALID 4038 #define ERROR_BASE64_DECODE 4039 #define ERROR_HTTP_STREAM_EOF 4040 +#define ERROR_RTC_PORT 4041 /////////////////////////////////////////////////////// // HTTP API error. From 51abb0844eac6b8d77d5e1b7749fc56e68729911 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Sun, 23 Feb 2020 23:19:40 +0800 Subject: [PATCH 04/69] rtp session manager, stun codding --- trunk/conf/rtc.conf | 38 ++++++ trunk/configure | 2 +- trunk/src/app/srs_app_http_api.cpp | 12 +- trunk/src/app/srs_app_http_api.hpp | 4 +- trunk/src/app/srs_app_rtc_udp.cpp | 167 ++++++++++++++++++++++++-- trunk/src/app/srs_app_rtc_udp.hpp | 46 ++++++- trunk/src/app/srs_app_server.cpp | 25 +++- trunk/src/app/srs_app_server.hpp | 6 + trunk/src/protocol/srs_stun_stack.cpp | 28 +++++ trunk/src/protocol/srs_stun_stack.hpp | 43 +++++++ 10 files changed, 354 insertions(+), 17 deletions(-) create mode 100644 trunk/conf/rtc.conf create mode 100644 trunk/src/protocol/srs_stun_stack.cpp create mode 100644 trunk/src/protocol/srs_stun_stack.hpp diff --git a/trunk/conf/rtc.conf b/trunk/conf/rtc.conf new file mode 100644 index 0000000000..5af4172b05 --- /dev/null +++ b/trunk/conf/rtc.conf @@ -0,0 +1,38 @@ +# main config for srs. +# @see full.conf for detail config. + +listen 1935; +max_connections 1000; +srs_log_tank file; +srs_log_file ./objs/srs.log; +http_api { + enabled on; + listen 1985; + raw_api { + enabled on; + allow_reload on; + allow_query on; + allow_update on; + } +} +http_server { + enabled on; + listen 8080; + dir ./objs/nginx/html; +} +rtc { + enabled on; + listen 9527; +} +stats { + network 0; + disk sda sdb xvda xvdb; +} +vhost __defaultVhost__ { + http_remux { + enabled on; + mount [vhost]/[app]/[stream].flv; + } +} + + diff --git a/trunk/configure b/trunk/configure index 5efe7eb592..5de5bc31df 100755 --- a/trunk/configure +++ b/trunk/configure @@ -214,7 +214,7 @@ ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_rtmp_stack" "srs_rtmp_handshake" "srs_protocol_utility" "srs_rtmp_msg_array" "srs_protocol_stream" "srs_raw_avc" "srs_rtsp_stack" "srs_http_stack" "srs_protocol_kbps" "srs_protocol_json" - "srs_protocol_format") + "srs_stun_stack" "srs_protocol_format") PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh PROTOCOL_OBJS="${MODULE_OBJS[@]}" # diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 634ba647c7..570d146621 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -46,6 +46,7 @@ using namespace std; #include #include #include +#include string test_sdp = "v=0\\r\\n" @@ -847,8 +848,9 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa return srs_api_response(w, r, obj->dumps()); } -SrsGoApiSdp::SrsGoApiSdp() +SrsGoApiSdp::SrsGoApiSdp(SrsServer* svr) { + server = svr; } SrsGoApiSdp::~SrsGoApiSdp() @@ -872,6 +874,14 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* SrsJsonObject* obj = SrsJsonAny::object(); SrsAutoFree(SrsJsonObject, obj); + + SrsRtcListener* rtc_listener = dynamic_cast(server->find_listener(SrsListenerRtcOverUdp)); + if (rtc_listener == NULL) { + return srs_go_http_error(w, SRS_CONSTS_HTTP_Unauthorized); + } + + SrsRtcOverUdp* rtc = rtc_listener->get_rtc(); + rtc->create_rtc_session("192.168.170.169", "xiaozhihongjohn", "ok"); obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); obj->set("server", SrsJsonAny::integer(stat->server_id())); diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 367edababd..d77ba517be 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -166,8 +166,10 @@ class SrsGoApiStreams : public ISrsHttpHandler class SrsGoApiSdp : public ISrsHttpHandler { +private: + SrsServer* server; public: - SrsGoApiSdp(); + SrsGoApiSdp(SrsServer* svr); virtual ~SrsGoApiSdp(); public: virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); diff --git a/trunk/src/app/srs_app_rtc_udp.cpp b/trunk/src/app/srs_app_rtc_udp.cpp index 4866c387a3..190c8b2c10 100644 --- a/trunk/src/app/srs_app_rtc_udp.cpp +++ b/trunk/src/app/srs_app_rtc_udp.cpp @@ -36,21 +36,39 @@ using namespace std; #include #include #include -#include #include -#include #include #include -#include #include #include +#include +#include #include -#include -#include #include -#include #include +static bool is_stun(const char* data, const int size) { + return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); +} + +static bool is_rtp_or_rtcp(const char* data, const int size) { + return data != NULL && size > 0 && (data[0] >= 128 && data[0] <= 191); +} + +static bool is_dtls(const char* data, const int size) { + return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); +} + +SrsRtcUserInfo::SrsRtcUserInfo(const std::string& u, const std::string& p) +{ + username = u; + password = p; +} + +SrsRtcUserInfo::~SrsRtcUserInfo() +{ +} + SrsRtcOverUdp::SrsRtcOverUdp() { } @@ -59,6 +77,30 @@ SrsRtcOverUdp::~SrsRtcOverUdp() { } +SrsRtcSession* SrsRtcOverUdp::create_rtc_session(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password) +{ + SrsRtcSession* rtc_session = new SrsRtcSession(); + // TODO: process exception when session already exist + user_session_map[peer_ip].insert(make_pair(SrsRtcUserInfo(remote_username, remote_password), rtc_session)).second; + + return rtc_session; +} + +SrsRtcSession* SrsRtcOverUdp::find_rtc_session_by_user_info(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password) +{ + std::map >::iterator iter = user_session_map.find(peer_ip); + if (iter == user_session_map.end()) { + return NULL; + } + + std::map::iterator sub_iter = iter->second.find(SrsRtcUserInfo(remote_username, remote_password)); + if (sub_iter == iter->second.end()) { + return NULL; + } + + return sub_iter->second; +} + srs_error_t SrsRtcOverUdp::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) { char address_string[64]; @@ -71,19 +113,120 @@ srs_error_t SrsRtcOverUdp::on_udp_packet(const sockaddr* from, const int fromlen } std::string peer_ip = std::string(address_string); int peer_port = atoi(port_string); - - srs_error_t err = on_udp_bytes(peer_ip, peer_port, buf, nb_buf); - if (err != srs_success) { - return srs_error_wrap(err, "process udp"); + + std::string peer_id = peer_ip + ":" + std::string(port_string); + + return on_udp_bytes(peer_ip, peer_port, peer_id, buf, nb_buf); +} + +SrsRtcSession* SrsRtcOverUdp::find_rtc_session_by_peer_id(const std::string& peer_id) +{ + map::iterator iter = id_session_map.find(peer_id); + if (iter == id_session_map.end()) { + return NULL; + } + + return iter->second; +} + +srs_error_t SrsRtcOverUdp::on_udp_bytes(const string& host, const int& port, const string& peer_id, char* buf, int nb_buf) +{ + srs_error_t err = srs_success; + + srs_trace("recv rtc udp packet from %s:%d, peer_id=%s, nb_buf=%d", host.c_str(), port, peer_id.c_str(), nb_buf); + + if (is_rtp_or_rtcp(buf, nb_buf)) { + err = on_rtp_or_rtcp(host, port, peer_id, buf, nb_buf); + } else if (is_stun(buf, nb_buf)) { + err = on_stun(host, port, peer_id, buf, nb_buf); + } else if (is_dtls(buf, nb_buf)) { + err = on_dtls(host, port, peer_id, buf, nb_buf); + } else { + return srs_error_wrap(err, "unknown udp packet"); + } + + return err; +} + +srs_error_t SrsRtcOverUdp::on_rtp_or_rtcp(const string& host, const int& port, const string& peer_id, const char* buf, int nb_buf) { + srs_error_t err = srs_success; + + SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(peer_id); + if (rtc_session == NULL) { + return srs_error_wrap(err, "can't find rtc session in rtp/rtcp host=%s, port=%d", + host.c_str(), port); } + + SrsRtpPacket rtp_packet; + SrsBuffer buffer(const_cast(buf), nb_buf); + rtp_packet.decode(&buffer); + + rtc_session->on_rtp_or_rtcp(&rtp_packet); + return err; } -srs_error_t SrsRtcOverUdp::on_udp_bytes(string host, int port, char* buf, int nb_buf) +srs_error_t SrsRtcOverUdp::on_stun(const string& host, const int& port, const string& peer_id, const char* buf, int nb_buf) { + srs_error_t err = srs_success; + + SrsStunPacket stun_packet; + stun_packet.decode(buf, nb_buf); + + SrsRtcSession* rtc_session = find_rtc_session_by_user_info(host, stun_packet.username(), stun_packet.password()); + if (rtc_session == NULL) { + return err; + return srs_error_wrap(err, "can't find rtc session in stun host=%s, port=%d, username=%s, password=%s", + host.c_str(), port, stun_packet.username().c_str(), stun_packet.password().c_str()); + } + + // TODO: process when session mismatch + id_session_map[peer_id] = rtc_session; + + rtc_session->on_stun(&stun_packet); + + return err; +} + +srs_error_t SrsRtcOverUdp::on_dtls(const string& host, const int& port, const string& peer_id, const char* buf, int nb_buf) { + srs_error_t err = srs_success; + + SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(peer_id); + if (rtc_session == NULL) { + return srs_error_wrap(err, "can't find rtc session in dtls host=%s, port=%d", + host.c_str(), port); + } + + rtc_session->on_dtls(); + + return err; +} + +SrsRtcSession::SrsRtcSession() +{ +} + +SrsRtcSession::~SrsRtcSession() +{ +} + +srs_error_t SrsRtcSession::on_rtp_or_rtcp(SrsRtpPacket* rtp_packet) +{ + srs_error_t err = srs_success; + + return err; +} + +srs_error_t SrsRtcSession::on_stun(SrsStunPacket* stun_packet) { srs_error_t err = srs_success; - srs_trace("recv rtc udp packet from %s:%d, nb_buf=%d", host.c_str(), port, nb_buf); + return err; +} + +srs_error_t SrsRtcSession::on_dtls() +{ + srs_error_t err = srs_success; return err; } + diff --git a/trunk/src/app/srs_app_rtc_udp.hpp b/trunk/src/app/srs_app_rtc_udp.hpp index 707b6b830e..405805549b 100644 --- a/trunk/src/app/srs_app_rtc_udp.hpp +++ b/trunk/src/app/srs_app_rtc_udp.hpp @@ -34,18 +34,62 @@ struct sockaddr; #include #include +class SrsRtcSession; + +class SrsRtcUserInfo { +private: + std::string username; + std::string password; +public: + SrsRtcUserInfo(const std::string& u, const std::string& p); + ~SrsRtcUserInfo(); + + bool operator<(const SrsRtcUserInfo& rhs) const + { + return username < rhs.username && password < rhs.password; + } +}; + // The rtc over udp stream receiver class SrsRtcOverUdp : virtual public ISrsUdpHandler { private: + std::map id_session_map; // ip:port => session + std::map > user_session_map; public: SrsRtcOverUdp(); virtual ~SrsRtcOverUdp(); + + SrsRtcSession* create_rtc_session(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password); + SrsRtcSession* find_rtc_session_by_user_info(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password); + SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id); // Interface ISrsUdpHandler public: virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); private: - virtual srs_error_t on_udp_bytes(std::string host, int port, char* buf, int nb_buf); + virtual srs_error_t on_udp_bytes(const std::string& host, const int& port, const std::string& peer_id, char* buf, int nb_buf); + srs_error_t on_rtp_or_rtcp(const std::string& host, const int& port, const std::string& peer_id, const char* buf, int nb_buf); + srs_error_t on_stun(const std::string& host, const int& port, const std::string& peer_id, const char* buf, int nb_buf); + srs_error_t on_dtls(const std::string& host, const int& port, const std::string& peer_id, const char* buf, int nb_buf); +}; + +class SrsRtpPacket; +class SrsStunPacket; + +class SrsRtcSession +{ +private: + std::string local_username; + std::string local_password; + std::string remote_username; + std::string remote_password; +public: + SrsRtcSession(); + virtual ~SrsRtcSession(); + + srs_error_t on_rtp_or_rtcp(SrsRtpPacket* rtp_packet); + srs_error_t on_stun(SrsStunPacket* stun_packet); + srs_error_t on_dtls(); }; #endif diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 85483a5b9c..b833803f2c 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -348,6 +348,12 @@ SrsRtcListener::~SrsRtcListener() { } + +SrsRtcOverUdp* SrsRtcListener::get_rtc() +{ + return dynamic_cast(rtc); +} + srs_error_t SrsRtcListener::listen(std::string i, int p) { srs_error_t err = srs_success; @@ -836,7 +842,7 @@ srs_error_t SrsServer::http_handle() if ((err = http_api_mux->handle("/api/v1/streams/", new SrsGoApiStreams())) != srs_success) { return srs_error_wrap(err, "handle streams"); } - if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp())) != srs_success) { + if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(this))) != srs_success) { return srs_error_wrap(err, "handle sdp"); } if ((err = http_api_mux->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) { @@ -1282,6 +1288,23 @@ void SrsServer::close_listeners(SrsListenerType type) } } +SrsListener* SrsServer::find_listener(SrsListenerType type) +{ + std::vector::iterator it; + for (it = listeners.begin(); it != listeners.end();) { + SrsListener* listener = *it; + + if (listener->listen_type() != type) { + ++it; + continue; + } + + return *it; + } + + return NULL; +} + void SrsServer::resample_kbps() { SrsStatistic* stat = SrsStatistic::instance(); diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 77b8964dfa..a8ac87d789 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -157,6 +157,8 @@ class SrsUdpCasterListener : public SrsUdpStreamListener virtual ~SrsUdpCasterListener(); }; +class SrsRtcOverUdp; + // A UDP listener, for udp stream caster server. class SrsRtcListener : public SrsListener { @@ -166,6 +168,8 @@ class SrsRtcListener : public SrsListener public: SrsRtcListener(SrsServer* svr, SrsListenerType t); virtual ~SrsRtcListener(); + + SrsRtcOverUdp* get_rtc(); public: virtual srs_error_t listen(std::string i, int p); }; @@ -335,6 +339,8 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan public: virtual srs_error_t on_publish(SrsSource* s, SrsRequest* r); virtual void on_unpublish(SrsSource* s, SrsRequest* r); +// listeners commuction + virtual SrsListener* find_listener(SrsListenerType type); }; #endif diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp new file mode 100644 index 0000000000..5273f5ee01 --- /dev/null +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -0,0 +1,28 @@ +#include + +using namespace std; + +SrsStunPacket::SrsStunPacket() +{ +} + +SrsStunPacket::~SrsStunPacket() +{ +} + +string SrsStunPacket::username() +{ + return ""; +} + +string SrsStunPacket::password() +{ + return ""; +} + +srs_error_t SrsStunPacket::decode(const char* buf, const int& nb_buf) +{ + srs_error_t err = srs_success; + + return err; +} diff --git a/trunk/src/protocol/srs_stun_stack.hpp b/trunk/src/protocol/srs_stun_stack.hpp new file mode 100644 index 0000000000..7f1522c2a0 --- /dev/null +++ b/trunk/src/protocol/srs_stun_stack.hpp @@ -0,0 +1,43 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_PROTOCOL_STUN_HPP +#define SRS_PROTOCOL_STUN_HPP + +#include + +#include +#include + +class SrsStunPacket { +public: + SrsStunPacket(); + virtual ~SrsStunPacket(); + + std::string username(); + std::string password(); + + srs_error_t decode(const char* buf, const int& nb_buf); +}; + +#endif From 62563bdd8196bf12acbb0f18152ecfd321cde4e8 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Fri, 28 Feb 2020 23:18:39 +0800 Subject: [PATCH 05/69] rtc framework --- trunk/configure | 2 +- trunk/src/app/srs_app_http_api.cpp | 10 +- trunk/src/app/srs_app_listener.cpp | 39 +++++ trunk/src/app/srs_app_listener.hpp | 15 +- trunk/src/app/srs_app_rtc.cpp | 86 ++++++++++ trunk/src/app/srs_app_rtc.hpp | 52 ++++++ trunk/src/app/srs_app_rtc_conn.cpp | 143 ++++++++++++++++ trunk/src/app/srs_app_rtc_conn.hpp | 88 ++++++++++ trunk/src/app/srs_app_rtc_udp.cpp | 232 -------------------------- trunk/src/app/srs_app_rtc_udp.hpp | 96 ----------- trunk/src/app/srs_app_server.cpp | 28 ++-- trunk/src/app/srs_app_server.hpp | 14 +- trunk/src/protocol/srs_stun_stack.cpp | 6 +- trunk/src/protocol/srs_stun_stack.hpp | 9 +- 14 files changed, 448 insertions(+), 372 deletions(-) create mode 100644 trunk/src/app/srs_app_rtc.cpp create mode 100644 trunk/src/app/srs_app_rtc.hpp create mode 100644 trunk/src/app/srs_app_rtc_conn.cpp create mode 100644 trunk/src/app/srs_app_rtc_conn.hpp delete mode 100644 trunk/src/app/srs_app_rtc_udp.cpp delete mode 100644 trunk/src/app/srs_app_rtc_udp.hpp diff --git a/trunk/configure b/trunk/configure index 5de5bc31df..a29047e723 100755 --- a/trunk/configure +++ b/trunk/configure @@ -254,7 +254,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" - "srs_app_mpegts_udp" "srs_app_rtc_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" + "srs_app_mpegts_udp" "srs_app_rtc" "srs_app_rtc_conn" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" "srs_app_coworkers" "srs_app_hybrid") diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 570d146621..fc54303b4f 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -46,7 +46,7 @@ using namespace std; #include #include #include -#include +#include string test_sdp = "v=0\\r\\n" @@ -875,14 +875,6 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* SrsJsonObject* obj = SrsJsonAny::object(); SrsAutoFree(SrsJsonObject, obj); - SrsRtcListener* rtc_listener = dynamic_cast(server->find_listener(SrsListenerRtcOverUdp)); - if (rtc_listener == NULL) { - return srs_go_http_error(w, SRS_CONSTS_HTTP_Unauthorized); - } - - SrsRtcOverUdp* rtc = rtc_listener->get_rtc(); - rtc->create_rtc_session("192.168.170.169", "xiaozhihongjohn", "ok"); - obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); obj->set("server", SrsJsonAny::integer(stat->server_id())); diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index b33b4f6f8e..0cd389df59 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -207,3 +207,42 @@ srs_error_t SrsTcpListener::cycle() return err; } +SrsUdpRemuxListener::SrsUdpRemuxListener(ISrsUdpHandler* h, std::string i, int p) : SrsUdpListener(h, i, p) +{ +} + +SrsUdpRemuxListener::~SrsUdpRemuxListener() +{ +} + +srs_error_t SrsUdpRemuxListener::cycle() +{ + srs_error_t err = srs_success; + + while (true) { + if ((err = trd->pull()) != srs_success) { + return srs_error_wrap(err, "udp listener"); + } + + int nread = 0; + sockaddr_storage from; + int nb_from = sizeof(from); + if ((nread = srs_recvfrom(lfd, buf, nb_buf, (sockaddr*)&from, &nb_from, SRS_UTIME_NO_TIMEOUT)) <= 0) { + srs_error("udp recv error"); + // remux udp never return + continue; + } + + if ((err = handler->on_udp_packet((const sockaddr*)&from, nb_from, buf, nread)) != srs_success) { + //srs_error("udp handle packet error"); + // remux udp never return + continue; + } + + if (SrsUdpPacketRecvCycleInterval > 0) { + srs_usleep(SrsUdpPacketRecvCycleInterval); + } + } + + return err; +} diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index d7d930e91c..a667af94dd 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -68,13 +68,13 @@ class ISrsTcpHandler // Bind udp port, start thread to recv packet and handler it. class SrsUdpListener : public ISrsCoroutineHandler { -private: +protected: srs_netfd_t lfd; SrsCoroutine* trd; -private: +protected: char* buf; int nb_buf; -private: +protected: ISrsUdpHandler* handler; std::string ip; int port; @@ -113,4 +113,13 @@ class SrsTcpListener : public ISrsCoroutineHandler virtual srs_error_t cycle(); }; +class SrsUdpRemuxListener : public SrsUdpListener +{ +public: + SrsUdpRemuxListener(ISrsUdpHandler* h, std::string i, int p); + virtual ~SrsUdpRemuxListener(); +public: + virtual srs_error_t cycle(); +}; + #endif diff --git a/trunk/src/app/srs_app_rtc.cpp b/trunk/src/app/srs_app_rtc.cpp new file mode 100644 index 0000000000..6f53781250 --- /dev/null +++ b/trunk/src/app/srs_app_rtc.cpp @@ -0,0 +1,86 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool is_stun(const char* data, const int size) { + return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); +} + +static bool is_rtp_or_rtcp(const char* data, const int size) { + return data != NULL && size > 0 && (data[0] >= 128 && data[0] <= 191); +} + +static bool is_dtls(const char* data, const int size) { + return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); +} + +SrsRtc::SrsRtc(SrsRtcServer* rtc_svr) +{ + rtc_server = rtc_svr; +} + +SrsRtc::~SrsRtc() +{ +} + +srs_error_t SrsRtc::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) +{ + char address_string[64]; + char port_string[16]; + if(getnameinfo(from, fromlen, + (char*)&address_string, sizeof(address_string), + (char*)&port_string, sizeof(port_string), + NI_NUMERICHOST|NI_NUMERICSERV)) { + return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); + } + std::string peer_ip = std::string(address_string); + int peer_port = atoi(port_string); + + return rtc_server->on_udp_packet(peer_ip, peer_port, buf, nb_buf); +} diff --git a/trunk/src/app/srs_app_rtc.hpp b/trunk/src/app/srs_app_rtc.hpp new file mode 100644 index 0000000000..6e1fb0651f --- /dev/null +++ b/trunk/src/app/srs_app_rtc.hpp @@ -0,0 +1,52 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_APP_RTC_HPP +#define SRS_APP_RTC_HPP + +#include + +struct sockaddr; +#include +#include + +#include +#include +#include + +class SrsRtcServer; + +// The rtc over udp stream receiver +class SrsRtc : virtual public ISrsUdpHandler +{ +private: + SrsRtcServer* rtc_server; +public: + SrsRtc(SrsRtcServer* rtc_svr); + virtual ~SrsRtc(); +// Interface ISrsUdpHandler +public: + virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); +}; + +#endif diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp new file mode 100644 index 0000000000..4f858da0a8 --- /dev/null +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -0,0 +1,143 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +using namespace std; + +#include +#include +#include + +static bool is_stun(const char* data, const int size) { + return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); +} + +static bool is_rtp_or_rtcp(const char* data, const int size) { + return data != NULL && size > 0 && (data[0] >= 128 && data[0] <= 191); +} + +static bool is_dtls(const char* data, const int size) { + return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); +} + +SrsSDP::SrsSDP() +{ +} + +SrsSDP::~SrsSDP() +{ +} + +SrsRtcSession::SrsRtcSession() +{ + session_state = INIT; +} + +SrsRtcSession::~SrsRtcSession() +{ +} + +srs_error_t SrsRtcSession::on_stun(const SrsStunPacket& stun_packet) +{ + srs_error_t err = srs_success; + + return err; +} + +srs_error_t SrsRtcSession::send_packet() +{ +} + +SrsRtcServer::SrsRtcServer(SrsServer* svr) +{ + server = svr; +} + +SrsRtcServer::~SrsRtcServer() +{ +} + +srs_error_t SrsRtcServer::initialize() +{ + srs_error_t err = srs_success; + + return err; +} + +srs_error_t SrsRtcServer::on_udp_packet(const string& peer_ip, const int peer_port, const char* data, const int size) +{ + srs_error_t err = srs_success; + + if (is_stun(data, size)) { + return on_stun(peer_ip, peer_port, data, size); + } else if (is_dtls(data, size)) { + return on_dtls(peer_ip, peer_port, data, size); + } else if (is_rtp_or_rtcp(data, size)) { + return on_rtp_or_rtcp(peer_ip, peer_port, data, size); + } + + return srs_error_wrap(err, "unknown packet type"); +} + +srs_error_t SrsRtcServer::on_stun(const string& peer_ip, const int peer_port, const char* data, const int size) +{ + srs_error_t err = srs_success; + + srs_trace("peer %s:%d stun", peer_ip.c_str(), peer_port); + + SrsStunPacket stun_packet; + if (stun_packet.decode(data, size) != srs_success) { + return srs_error_wrap(err, "decode stun failed"); + } + + std::string peer_ufrag = stun_packet.ufrag(); + SrsRtcSession* rtc_session = find_rtc_session(peer_ufrag); + if (rtc_session == NULL) { + return srs_error_wrap(err, "can not find rtc_session, ufrag=%s", peer_ufrag.c_str()); + } + + return rtc_session->on_stun(stun_packet); +} + +srs_error_t SrsRtcServer::on_dtls(const string& peer_ip, const int peer_port, const char* data, const int size) +{ + srs_error_t err = srs_success; + return err; +} + +srs_error_t SrsRtcServer::on_rtp_or_rtcp(const string& peer_ip, const int peer_port, const char* data, const int size) +{ + srs_error_t err = srs_success; + return err; +} + +SrsRtcSession* SrsRtcServer::find_rtc_session(const std::string& ufrag) +{ + map::iterator iter = map_sessions.find(ufrag); + if (iter == map_sessions.end()) { + return NULL; + } + + return iter->second; +} diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp new file mode 100644 index 0000000000..b5ba40235d --- /dev/null +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -0,0 +1,88 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_APP_RTC_CONN_HPP +#define SRS_APP_RTC_CONN_HPP + +#include + +#include +#include + +class SrsServer; +class SrsStunPacket; + +class SrsSDP +{ +private: +public: + SrsSDP(); + virtual ~SrsSDP(); +}; + +enum SrsRtcSessionStateType +{ + INIT = -1, + WAITING_STUN = 1, + DOING_DTLS_HANDSHAKE = 2, + ESTABLISHED = 3, + CLOSED = 4, +}; + +class SrsRtcSession +{ +public: +private: + SrsSDP peer_sdp; + SrsSDP offer_sdp; + SrsRtcSessionStateType session_state; +public: + SrsRtcSession(); + virtual ~SrsRtcSession(); + + srs_error_t on_udp_packet(const std::string& peer_ip, const int peer_port, const char* data, const int size); + srs_error_t on_stun(const SrsStunPacket& stun_packet); + srs_error_t send_packet(); +}; + +class SrsRtcServer +{ +private: + SrsServer* server; + std::map map_sessions; +public: + SrsRtcServer(SrsServer* svr); + virtual ~SrsRtcServer(); +public: + virtual srs_error_t initialize(); + virtual srs_error_t on_udp_packet(const std::string& peer_ip, const int peer_port, const char* data, const int size); +private: + srs_error_t on_stun(const std::string& peer_ip, const int peer_port, const char* data, const int size); + srs_error_t on_dtls(const std::string& peer_ip, const int peer_port, const char* data, const int size); + srs_error_t on_rtp_or_rtcp(const std::string& peer_ip, const int peer_port, const char* data, const int size); +private: + SrsRtcSession* find_rtc_session(const std::string& ufrag); +}; + +#endif + diff --git a/trunk/src/app/srs_app_rtc_udp.cpp b/trunk/src/app/srs_app_rtc_udp.cpp deleted file mode 100644 index 190c8b2c10..0000000000 --- a/trunk/src/app/srs_app_rtc_udp.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2020 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include - -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool is_stun(const char* data, const int size) { - return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); -} - -static bool is_rtp_or_rtcp(const char* data, const int size) { - return data != NULL && size > 0 && (data[0] >= 128 && data[0] <= 191); -} - -static bool is_dtls(const char* data, const int size) { - return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); -} - -SrsRtcUserInfo::SrsRtcUserInfo(const std::string& u, const std::string& p) -{ - username = u; - password = p; -} - -SrsRtcUserInfo::~SrsRtcUserInfo() -{ -} - -SrsRtcOverUdp::SrsRtcOverUdp() -{ -} - -SrsRtcOverUdp::~SrsRtcOverUdp() -{ -} - -SrsRtcSession* SrsRtcOverUdp::create_rtc_session(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password) -{ - SrsRtcSession* rtc_session = new SrsRtcSession(); - // TODO: process exception when session already exist - user_session_map[peer_ip].insert(make_pair(SrsRtcUserInfo(remote_username, remote_password), rtc_session)).second; - - return rtc_session; -} - -SrsRtcSession* SrsRtcOverUdp::find_rtc_session_by_user_info(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password) -{ - std::map >::iterator iter = user_session_map.find(peer_ip); - if (iter == user_session_map.end()) { - return NULL; - } - - std::map::iterator sub_iter = iter->second.find(SrsRtcUserInfo(remote_username, remote_password)); - if (sub_iter == iter->second.end()) { - return NULL; - } - - return sub_iter->second; -} - -srs_error_t SrsRtcOverUdp::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) -{ - char address_string[64]; - char port_string[16]; - if(getnameinfo(from, fromlen, - (char*)&address_string, sizeof(address_string), - (char*)&port_string, sizeof(port_string), - NI_NUMERICHOST|NI_NUMERICSERV)) { - return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); - } - std::string peer_ip = std::string(address_string); - int peer_port = atoi(port_string); - - std::string peer_id = peer_ip + ":" + std::string(port_string); - - return on_udp_bytes(peer_ip, peer_port, peer_id, buf, nb_buf); -} - -SrsRtcSession* SrsRtcOverUdp::find_rtc_session_by_peer_id(const std::string& peer_id) -{ - map::iterator iter = id_session_map.find(peer_id); - if (iter == id_session_map.end()) { - return NULL; - } - - return iter->second; -} - -srs_error_t SrsRtcOverUdp::on_udp_bytes(const string& host, const int& port, const string& peer_id, char* buf, int nb_buf) -{ - srs_error_t err = srs_success; - - srs_trace("recv rtc udp packet from %s:%d, peer_id=%s, nb_buf=%d", host.c_str(), port, peer_id.c_str(), nb_buf); - - if (is_rtp_or_rtcp(buf, nb_buf)) { - err = on_rtp_or_rtcp(host, port, peer_id, buf, nb_buf); - } else if (is_stun(buf, nb_buf)) { - err = on_stun(host, port, peer_id, buf, nb_buf); - } else if (is_dtls(buf, nb_buf)) { - err = on_dtls(host, port, peer_id, buf, nb_buf); - } else { - return srs_error_wrap(err, "unknown udp packet"); - } - - return err; -} - -srs_error_t SrsRtcOverUdp::on_rtp_or_rtcp(const string& host, const int& port, const string& peer_id, const char* buf, int nb_buf) { - srs_error_t err = srs_success; - - SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(peer_id); - if (rtc_session == NULL) { - return srs_error_wrap(err, "can't find rtc session in rtp/rtcp host=%s, port=%d", - host.c_str(), port); - } - - SrsRtpPacket rtp_packet; - SrsBuffer buffer(const_cast(buf), nb_buf); - rtp_packet.decode(&buffer); - - rtc_session->on_rtp_or_rtcp(&rtp_packet); - - return err; -} - -srs_error_t SrsRtcOverUdp::on_stun(const string& host, const int& port, const string& peer_id, const char* buf, int nb_buf) { - srs_error_t err = srs_success; - - SrsStunPacket stun_packet; - stun_packet.decode(buf, nb_buf); - - SrsRtcSession* rtc_session = find_rtc_session_by_user_info(host, stun_packet.username(), stun_packet.password()); - if (rtc_session == NULL) { - return err; - return srs_error_wrap(err, "can't find rtc session in stun host=%s, port=%d, username=%s, password=%s", - host.c_str(), port, stun_packet.username().c_str(), stun_packet.password().c_str()); - } - - // TODO: process when session mismatch - id_session_map[peer_id] = rtc_session; - - rtc_session->on_stun(&stun_packet); - - return err; -} - -srs_error_t SrsRtcOverUdp::on_dtls(const string& host, const int& port, const string& peer_id, const char* buf, int nb_buf) { - srs_error_t err = srs_success; - - SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(peer_id); - if (rtc_session == NULL) { - return srs_error_wrap(err, "can't find rtc session in dtls host=%s, port=%d", - host.c_str(), port); - } - - rtc_session->on_dtls(); - - return err; -} - -SrsRtcSession::SrsRtcSession() -{ -} - -SrsRtcSession::~SrsRtcSession() -{ -} - -srs_error_t SrsRtcSession::on_rtp_or_rtcp(SrsRtpPacket* rtp_packet) -{ - srs_error_t err = srs_success; - - return err; -} - -srs_error_t SrsRtcSession::on_stun(SrsStunPacket* stun_packet) -{ - srs_error_t err = srs_success; - - return err; -} - -srs_error_t SrsRtcSession::on_dtls() -{ - srs_error_t err = srs_success; - - return err; -} - diff --git a/trunk/src/app/srs_app_rtc_udp.hpp b/trunk/src/app/srs_app_rtc_udp.hpp deleted file mode 100644 index 405805549b..0000000000 --- a/trunk/src/app/srs_app_rtc_udp.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2020 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SRS_APP_RTC_UDP_HPP -#define SRS_APP_RTC_UDP_HPP - -#include - -struct sockaddr; -#include -#include - -#include -#include -#include - -class SrsRtcSession; - -class SrsRtcUserInfo { -private: - std::string username; - std::string password; -public: - SrsRtcUserInfo(const std::string& u, const std::string& p); - ~SrsRtcUserInfo(); - - bool operator<(const SrsRtcUserInfo& rhs) const - { - return username < rhs.username && password < rhs.password; - } -}; - -// The rtc over udp stream receiver -class SrsRtcOverUdp : virtual public ISrsUdpHandler -{ -private: - std::map id_session_map; // ip:port => session - std::map > user_session_map; -public: - SrsRtcOverUdp(); - virtual ~SrsRtcOverUdp(); - - SrsRtcSession* create_rtc_session(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password); - SrsRtcSession* find_rtc_session_by_user_info(const std::string& peer_ip, const std::string& remote_username, const std::string& remote_password); - SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id); -// Interface ISrsUdpHandler -public: - virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); -private: - virtual srs_error_t on_udp_bytes(const std::string& host, const int& port, const std::string& peer_id, char* buf, int nb_buf); - srs_error_t on_rtp_or_rtcp(const std::string& host, const int& port, const std::string& peer_id, const char* buf, int nb_buf); - srs_error_t on_stun(const std::string& host, const int& port, const std::string& peer_id, const char* buf, int nb_buf); - srs_error_t on_dtls(const std::string& host, const int& port, const std::string& peer_id, const char* buf, int nb_buf); -}; - -class SrsRtpPacket; -class SrsStunPacket; - -class SrsRtcSession -{ -private: - std::string local_username; - std::string local_password; - std::string remote_username; - std::string remote_password; -public: - SrsRtcSession(); - virtual ~SrsRtcSession(); - - srs_error_t on_rtp_or_rtcp(SrsRtpPacket* rtp_packet); - srs_error_t on_stun(SrsStunPacket* stun_packet); - srs_error_t on_dtls(); -}; - -#endif - diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index b833803f2c..548ee3cddf 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -44,7 +44,8 @@ using namespace std; #include #include #include -#include +#include +#include #include #include #include @@ -109,8 +110,8 @@ std::string srs_listener_type2string(SrsListenerType type) return "RTSP"; case SrsListenerFlv: return "HTTP-FLV"; - case SrsListenerRtcOverUdp: - return "RTC over UDP"; + case SrsListenerRtc: + return "RTC"; default: return "UNKONWN"; } @@ -338,35 +339,29 @@ SrsUdpCasterListener::~SrsUdpCasterListener() srs_freep(caster); } -SrsRtcListener::SrsRtcListener(SrsServer* svr, SrsListenerType t) : SrsListener(svr, t) +SrsRtcListener::SrsRtcListener(SrsServer* svr, SrsRtcServer* rtc_svr, SrsListenerType t) : SrsListener(svr, t) { - srs_assert(type == SrsListenerRtcOverUdp); - rtc = new SrsRtcOverUdp(); + srs_assert(type == SrsListenerRtc); + rtc = new SrsRtc(rtc_svr); } SrsRtcListener::~SrsRtcListener() { } - -SrsRtcOverUdp* SrsRtcListener::get_rtc() -{ - return dynamic_cast(rtc); -} - srs_error_t SrsRtcListener::listen(std::string i, int p) { srs_error_t err = srs_success; // the caller already ensure the type is ok, // we just assert here for unknown stream caster. - srs_assert(type == SrsListenerRtcOverUdp); + srs_assert(type == SrsListenerRtc); ip = i; port = p; srs_freep(listener); - listener = new SrsUdpListener(rtc, ip, port); + listener = new SrsUdpRemuxListener(rtc, ip, port); if ((err = listener->listen()) != srs_success) { return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); @@ -533,6 +528,7 @@ SrsServer::SrsServer() // new these objects in initialize instead. http_api_mux = new SrsHttpServeMux(); http_server = new SrsHttpServer(this); + rtc_server = new SrsRtcServer(this); http_heartbeat = new SrsHttpHeartbeat(); ingester = new SrsIngester(); } @@ -1247,7 +1243,7 @@ srs_error_t SrsServer::listen_rtc() { srs_error_t err = srs_success; - close_listeners(SrsListenerRtcOverUdp); + close_listeners(SrsListenerRtc); if (!_srs_config->get_rtc_enabled()) { return err; @@ -1255,7 +1251,7 @@ srs_error_t SrsServer::listen_rtc() SrsListener* listener = NULL; - listener = new SrsRtcListener(this, SrsListenerRtcOverUdp); + listener = new SrsRtcListener(this, rtc_server, SrsListenerRtc); srs_assert(listener != NULL); listeners.push_back(listener); diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index a8ac87d789..36e4c8b3f2 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -41,6 +41,7 @@ class SrsServer; class SrsConnection; class SrsHttpServeMux; class SrsHttpServer; +class SrsRtcServer; class SrsIngester; class SrsHttpHeartbeat; class SrsKbps; @@ -68,8 +69,8 @@ enum SrsListenerType SrsListenerRtsp = 4, // TCP stream, FLV stream over HTTP. SrsListenerFlv = 5, - // UDP sream, rtp over udp - SrsListenerRtcOverUdp = 6, + // UDP remux, rtp over udp + SrsListenerRtc = 6, }; // A common tcp listener, for RTMP/HTTP server. @@ -157,19 +158,15 @@ class SrsUdpCasterListener : public SrsUdpStreamListener virtual ~SrsUdpCasterListener(); }; -class SrsRtcOverUdp; - -// A UDP listener, for udp stream caster server. +// A UDP listener, for udp remux rtc server class SrsRtcListener : public SrsListener { protected: SrsUdpListener* listener; ISrsUdpHandler* rtc; public: - SrsRtcListener(SrsServer* svr, SrsListenerType t); + SrsRtcListener(SrsServer* svr, SrsRtcServer* rtc_svr, SrsListenerType t); virtual ~SrsRtcListener(); - - SrsRtcOverUdp* get_rtc(); public: virtual srs_error_t listen(std::string i, int p); }; @@ -225,6 +222,7 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan // TODO: FIXME: rename to http_api SrsHttpServeMux* http_api_mux; SrsHttpServer* http_server; + SrsRtcServer* rtc_server; SrsHttpHeartbeat* http_heartbeat; SrsIngester* ingester; SrsCoroutineManager* conn_manager; diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp index 5273f5ee01..38c8c00a24 100644 --- a/trunk/src/protocol/srs_stun_stack.cpp +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -10,17 +10,17 @@ SrsStunPacket::~SrsStunPacket() { } -string SrsStunPacket::username() +string SrsStunPacket::ufrag() { return ""; } -string SrsStunPacket::password() +string SrsStunPacket::pwd() { return ""; } -srs_error_t SrsStunPacket::decode(const char* buf, const int& nb_buf) +srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) { srs_error_t err = srs_success; diff --git a/trunk/src/protocol/srs_stun_stack.hpp b/trunk/src/protocol/srs_stun_stack.hpp index 7f1522c2a0..61269050a0 100644 --- a/trunk/src/protocol/srs_stun_stack.hpp +++ b/trunk/src/protocol/srs_stun_stack.hpp @@ -29,15 +29,16 @@ #include #include -class SrsStunPacket { +class SrsStunPacket +{ public: SrsStunPacket(); virtual ~SrsStunPacket(); - std::string username(); - std::string password(); + std::string ufrag(); + std::string pwd(); - srs_error_t decode(const char* buf, const int& nb_buf); + srs_error_t decode(const char* buf, const int nb_buf); }; #endif From 30d8b2209f0718ddaaae8a9921e5eac7f073eb23 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Mon, 2 Mar 2020 22:47:40 +0800 Subject: [PATCH 06/69] parse sdp --- trunk/src/app/srs_app_http_api.cpp | 31 +++++++++++++- trunk/src/app/srs_app_rtc_conn.cpp | 69 +++++++++++++++++++++++++++++- trunk/src/app/srs_app_rtc_conn.hpp | 30 ++++++++++--- 3 files changed, 122 insertions(+), 8 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index fc54303b4f..9273f4bd44 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -47,6 +47,7 @@ using namespace std; #include #include #include +#include string test_sdp = "v=0\\r\\n" @@ -871,7 +872,35 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* if (sid >= 0 && (stream = stat->find_stream(sid)) == NULL) { return srs_api_response_code(w, r, ERROR_RTMP_STREAM_NOT_FOUND); } - + + string req_json; + r->body_read_all(req_json); + srs_trace("req_json=%s", req_json.c_str()); + + SrsJsonAny* json = SrsJsonAny::loads(req_json); + SrsJsonObject* req_obj = json->to_object(); + + SrsJsonAny* remote_sdp_obj = req_obj->get_property("sdp"); + SrsJsonAny* app_obj = req_obj->get_property("app"); + SrsJsonAny* stream_name_obj = req_obj->get_property("stream"); + + if (remote_sdp_obj == NULL || app_obj == NULL || stream_name_obj == NULL) { + return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + } + + string remote_sdp = remote_sdp_obj->to_str(); + string app = app_obj->to_str(); + string stream_name = stream_name_obj->to_str(); + + srs_trace("remote_sdp=%s", remote_sdp.c_str()); + srs_trace("app=%s, stream=%s", app.c_str(), stream_name.c_str()); + + SrsSdp srs_sdp; + err = srs_sdp.parse(remote_sdp); + if (err != srs_success) { + return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + } + SrsJsonObject* obj = SrsJsonAny::object(); SrsAutoFree(SrsJsonObject, obj); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 4f858da0a8..93fca7f8ce 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -25,6 +25,8 @@ using namespace std; +#include + #include #include #include @@ -41,12 +43,75 @@ static bool is_dtls(const char* data, const int size) { return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); } -SrsSDP::SrsSDP() +SrsSdpMediaInfo::SrsSdpMediaInfo() +{ +} + +SrsSdpMediaInfo::~SrsSdpMediaInfo() +{ +} + +SrsSdp::SrsSdp() +{ +} + +SrsSdp::~SrsSdp() { } -SrsSDP::~SrsSDP() +srs_error_t SrsSdp::parse(const string& sdp) { + srs_error_t err = srs_success; + + if (sdp.size() < 2 || sdp[0] != 'v' || sdp[1] != '=') { + return srs_error_wrap(err, "invalid sdp"); + } + + string line; + istringstream is(sdp); + while (getline(is, line)) { + srs_trace("line=%s", line.c_str()); + + if (line.size() < 2 || line[1] != '=') { + return srs_error_wrap(err, "invalid sdp line=%s", line.c_str()); + } + + switch (line[1]) { + case 'v' :{ + break; + } + case 'o' :{ + break; + } + case 's' :{ + break; + } + case 't' :{ + break; + } + case 'c' :{ + break; + } + case 'a' :{ + if (parse_attr(line) != srs_success) { + return srs_error_wrap(err, "parse sdp line=%s failed", line.c_str()); + } + break; + } + case 'm' :{ + break; + } + } + } + + return err; +} + +srs_error_t SrsSdp::parse_attr(const string& line) +{ + srs_error_t err = srs_success; + + return err; } SrsRtcSession::SrsRtcSession() diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index b5ba40235d..df370d5853 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -28,16 +28,36 @@ #include #include +#include class SrsServer; class SrsStunPacket; -class SrsSDP +class SrsSdpMediaInfo { private: public: - SrsSDP(); - virtual ~SrsSDP(); + SrsSdpMediaInfo(); + virtual ~SrsSdpMediaInfo(); +}; + +class SrsSdp +{ +private: + std::string sdp; + int version; + std::string ice_ufrag; + std::string ice_pwd; + std::string fingerprint; + std::string setup; + std::vector media_infos; +public: + SrsSdp(); + virtual ~SrsSdp(); + + srs_error_t parse(const std::string& sdp); +private: + srs_error_t parse_attr(const std::string& line); }; enum SrsRtcSessionStateType @@ -53,8 +73,8 @@ class SrsRtcSession { public: private: - SrsSDP peer_sdp; - SrsSDP offer_sdp; + SrsSdp peer_sdp; + SrsSdp offer_sdp; SrsRtcSessionStateType session_state; public: SrsRtcSession(); From 9d5495c0c20fe8b499b6723b2c94e664b7a8b324 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Fri, 6 Mar 2020 23:01:48 +0800 Subject: [PATCH 07/69] "stun and dtls done" --- trunk/3rdparty/libsrtp-2.0.0.zip | Bin 0 -> 178 bytes trunk/auto/depends.sh | 21 ++ trunk/configure | 23 +- trunk/src/app/srs_app_dtls.cpp | 131 +++++++ trunk/src/app/srs_app_dtls.hpp | 52 +++ trunk/src/app/srs_app_http_api.cpp | 100 ++---- trunk/src/app/srs_app_http_api.hpp | 4 +- trunk/src/app/srs_app_listener.cpp | 57 ++- trunk/src/app/srs_app_listener.hpp | 30 +- trunk/src/app/srs_app_rtc.cpp | 4 +- trunk/src/app/srs_app_rtc.hpp | 4 +- trunk/src/app/srs_app_rtc_conn.cpp | 495 ++++++++++++++++++++++++-- trunk/src/app/srs_app_rtc_conn.hpp | 84 ++++- trunk/src/app/srs_app_server.cpp | 2 +- trunk/src/app/srs_app_server.hpp | 4 +- trunk/src/protocol/srs_stun_stack.cpp | 254 ++++++++++++- trunk/src/protocol/srs_stun_stack.hpp | 69 +++- trunk/src/service/srs_service_st.cpp | 5 + trunk/src/service/srs_service_st.hpp | 1 + 19 files changed, 1200 insertions(+), 140 deletions(-) create mode 100644 trunk/3rdparty/libsrtp-2.0.0.zip create mode 100644 trunk/src/app/srs_app_dtls.cpp create mode 100644 trunk/src/app/srs_app_dtls.hpp diff --git a/trunk/3rdparty/libsrtp-2.0.0.zip b/trunk/3rdparty/libsrtp-2.0.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..c149013ac25bd5e7e3d4714a6cdb3fa3035bf4e7 GIT binary patch literal 178 zcmWIWW@h1H0D+kb&K_U}l;C5KVaUl$DlRH1&^6LC&@<2v4dG;9e#E^ojPHM9TxkV2 x10%}|W(Ec@5#Y_pB*%=)BnhaQ0t|m0K}>XWSs~_Pn90fpQq2g2AwU}9JODC)96SI3 literal 0 HcmV?d00001 diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index a4c8730dfe..998a4fddb6 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -242,6 +242,27 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then if [ ! -f ${SRS_OBJS}/st/libst.a ]; then echo "Build state-threads static lib failed."; exit -1; fi fi +##################################################################################### +# srtp +##################################################################################### +if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then + # Patched ST from https://github.com/ossrs/state-threads/tree/srs + if [[ -f ${SRS_OBJS}/srtp2/lib/libsrtp2.a ]]; then + echo "The srtp2 is ok."; + else + echo "Building srtp2."; + ( + rm -rf ${SRS_OBJS}/srtp2 && cd ${SRS_OBJS} && + ln -sf ../3rdparty/libsrtp-2.0.0 && cd libsrtp-2.0.0 && + ./configure --prefix=`pwd`/_release && make ${SRS_JOBS} && make install && + cd .. && rm -f srtp2 && ln -sf libsrtp-2.0.0/_release srtp2 + ) + fi + # check status + ret=$?; if [[ $ret -ne 0 ]]; then echo "Build srtp2 failed, ret=$ret"; exit $ret; fi + if [ ! -f ${SRS_OBJS}/srtp2/lib/libsrtp2.a ]; then echo "Build srtp2 static lib failed."; exit -1; fi +fi + ##################################################################################### # nginx for HLS, nginx-1.5.0 ##################################################################################### diff --git a/trunk/configure b/trunk/configure index a29047e723..047f41883c 100755 --- a/trunk/configure +++ b/trunk/configure @@ -148,6 +148,9 @@ END # st(state-threads) the basic network library for SRS. LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a" if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-lst"; fi +# srtp +LibSrtpRoot="${SRS_OBJS_DIR}/srtp2"; LibSrtpFile="${LibSrtpRoot}/lib/libsrtp2.a" +if [[ $SRS_SHARED_SRTP == YES ]]; then LibSrtpFile="-lsrtp2"; fi # openssl-1.1.0e, for the RTMP complex handshake. LibSSLRoot="";LibSSLfile="" if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == NO ]]; then @@ -233,7 +236,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVICE" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_service_log" "srs_service_st" "srs_service_http_client" "srs_service_http_conn" "srs_service_rtmp_conn" "srs_service_utility" "srs_service_conn") @@ -246,7 +249,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -254,7 +257,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" - "srs_app_mpegts_udp" "srs_app_rtc" "srs_app_rtc_conn" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" + "srs_app_mpegts_udp" "srs_app_rtc" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" "srs_app_coworkers" "srs_app_hybrid") @@ -284,7 +287,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then if [[ $SRS_SRT == YES ]]; then MODULE_DEPENDS+=("SRT") fi - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi @@ -297,7 +300,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="MAIN" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) MODULE_FILES=() DEFINES="" # add each modules for main @@ -324,13 +327,13 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then done # # all depends libraries - ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibSSLfile} ${LibGperfFile}) if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi # all depends objects MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then MODULE_OBJS="${MODULE_OBJS} ${SRT_OBJS[@]}" fi @@ -341,7 +344,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then # # For modules, without the app module. MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" - ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibSSLfile} ${LibGperfFile}) # for SRS_MODULE in ${SRS_MODULES[*]}; do . $SRS_MODULE/config @@ -361,11 +364,11 @@ if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSrtpRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi - ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) + ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibSSLfile}) if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi diff --git a/trunk/src/app/srs_app_dtls.cpp b/trunk/src/app/srs_app_dtls.cpp new file mode 100644 index 0000000000..af09dcb2f7 --- /dev/null +++ b/trunk/src/app/srs_app_dtls.cpp @@ -0,0 +1,131 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +using namespace std; + +#include + +#include + +SrsDtls* SrsDtls::_instance = NULL; + +SrsDtls::SrsDtls() +{ +} + +SrsDtls::~SrsDtls() +{ +} + +SrsDtls* SrsDtls::instance() +{ + if (!_instance) { + _instance = new SrsDtls(); + _instance->init(); + } + return _instance; +} + +void SrsDtls::init() +{ + EVP_PKEY* dtls_private_key = EVP_PKEY_new(); + srs_assert(dtls_private_key); + + RSA* rsa = RSA_new(); + srs_assert(rsa); + + BIGNUM* exponent = BN_new(); + srs_assert(exponent); + + BN_set_word(exponent, RSA_F4); + + const std::string& aor = "www.hw.com"; + int expire_day = 365; + int private_key_len = 1024; + + RSA_generate_key_ex(rsa, private_key_len, exponent, NULL); + + srs_assert(EVP_PKEY_set1_RSA(dtls_private_key, rsa) == 1); + + X509* dtls_cert = X509_new(); + srs_assert(dtls_cert); + + X509_NAME* subject = X509_NAME_new(); + srs_assert(subject); + + int serial = rand(); + ASN1_INTEGER_set(X509_get_serialNumber(dtls_cert), serial); + + X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *) aor.data(), aor.size(), -1, 0); + + X509_set_issuer_name(dtls_cert, subject); + X509_set_subject_name(dtls_cert, subject); + + const long cert_duration = 60*60*24*expire_day; + + X509_gmtime_adj(X509_get_notBefore(dtls_cert), 0); + X509_gmtime_adj(X509_get_notAfter(dtls_cert), cert_duration); + + srs_assert(X509_set_pubkey(dtls_cert, dtls_private_key) == 1); + + srs_assert(X509_sign(dtls_cert, dtls_private_key, EVP_sha1()) != 0); + + // cleanup + RSA_free(rsa); + BN_free(exponent); + X509_NAME_free(subject); + + dtls_ctx = SSL_CTX_new(DTLSv1_2_method()); + srs_assert(SSL_CTX_use_certificate(dtls_ctx, dtls_cert) == 1); + + srs_assert(SSL_CTX_use_PrivateKey(dtls_ctx, dtls_private_key) == 1); + srs_assert(SSL_CTX_set_cipher_list(dtls_ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") == 1); + srs_assert(SSL_CTX_set_tlsext_use_srtp(dtls_ctx, "SRTP_AES128_CM_SHA1_80") == 0); + + SSL_CTX_set_verify_depth (dtls_ctx, 4); + SSL_CTX_set_read_ahead(dtls_ctx, 1); + + // dtls fingerprint + char fp[100] = {0}; + char *p = fp; + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int n = 0; + + int r = X509_digest(dtls_cert, EVP_sha256(), md, &n); + + for (unsigned int i = 0; i < n; i++, ++p) { + sprintf(p, "%02X", md[i]); + p += 2; + + if(i < (n-1)) { + *p = ':'; + } else { + *p = '\0'; + } + } + + fingerprint.assign(fp, strlen(fp)); + srs_trace("fingerprint=%s", fingerprint.c_str()); +} diff --git a/trunk/src/app/srs_app_dtls.hpp b/trunk/src/app/srs_app_dtls.hpp new file mode 100644 index 0000000000..5853f91b37 --- /dev/null +++ b/trunk/src/app/srs_app_dtls.hpp @@ -0,0 +1,52 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_APP_DTLS_HPP +#define SRS_APP_DTLS_HPP + +#include + +#include + +#include + +class SrsDtls +{ +private: + static SrsDtls* _instance; +private: + std::string fingerprint; + SSL_CTX* dtls_ctx; +private: + SrsDtls(); + virtual ~SrsDtls(); + + void init(); +public: + static SrsDtls* instance(); + SSL_CTX* get_dtls_ctx() { return dtls_ctx; } +public: + std::string get_fingerprint() const { return fingerprint; } +}; + +#endif diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 9273f4bd44..fb33382d21 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -49,73 +49,6 @@ using namespace std; #include #include -string test_sdp = -"v=0\\r\\n" -"o=- 0 0 IN IP4 127.0.0.1\\r\\n" -"s=-\\r\\n" -"t=0 0\\r\\n" -"a=ice-lite\\r\\n" -"a=group:BUNDLE 0 1\\r\\n" -"a=msid-semantic: WMS 6VrfBKXrwK\\r\\n" -"m=audio 9 UDP/TLS/RTP/SAVPF 111\\r\\n" -"c=IN IP4 0.0.0.0\\r\\n" -"a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" -"a=rtcp:9 IN IP4 0.0.0.0\\r\\n" -"a=ice-ufrag:xiaozhihongjohn\\r\\n" -"a=ice-pwd:simple_rtmp_server__john\\r\\n" -"a=ice-options:trickle\\r\\n" -"a=fingerprint:sha-256 76:E8:6A:6D:48:F0:86:58:30:2E:69:56:0F:C6:A1:B8:69:98:5D:73:45:93:37:8E:C4:2B:C7:97:04:18:E4:24\\r\\n" -"a=sendrecv\\r\\n" -"a=mid:0\\r\\n" -"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\\r\\n" -"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" -"a=rtcp-mux\\r\\n" -"a=rtpmap:111 opus/48000/2\\r\\n" -"a=fmtp:111 minptime=10;useinbandfec=1\\r\\n" -"a=maxptime:60\\r\\n" -"a=ssrc:3233846890 cname:o/i14u9pJrxRKAsu\\r\\n" -"a=ssrc:3233846890 msid:6VrfBKXrwK a0\\r\\n" -"a=ssrc:3233846890 mslabel:6VrfBKXrwK\\r\\n" -"a=ssrc:3233846890 label:6VrfBKXrwKa0\\r\\n" -"m=video 9 UDP/TLS/RTP/SAVPF 96 98 102\\r\\n" -"c=IN IP4 0.0.0.0\\r\\n" -"a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" -"a=rtcp:9 IN IP4 0.0.0.0\\r\\n" -"b=as:2000000\\r\\n" -"a=ice-ufrag:xiaozhihongjohn\\r\\n" -"a=ice-pwd:simple_rtmp_server__john\\r\\n" -"a=ice-options:trickle\\r\\n" -"a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\\r\\n" -"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" -"a=extmap:4 urn:3gpp:video-orientation\\r\\n" -"a=fingerprint:sha-256 76:E8:6A:6D:48:F0:86:58:30:2E:69:56:0F:C6:A1:B8:69:98:5D:73:45:93:37:8E:C4:2B:C7:97:04:18:E4:24\\r\\n" -"a=sendrecv\\r\\n" -"a=mid:1\\r\\n" -"a=rtcp-mux\\r\\n" -"a=rtpmap:96 VP8/90000\\r\\n" -"a=rtcp-fb:96 ccm fir\\r\\n" -"a=rtcp-fb:96 nack\\r\\n" -"a=rtcp-fb:96 nack pli\\r\\n" -"a=rtcp-fb:96 goog-remb\\r\\n" -"a=rtcp-fb:96 transport-cc\\r\\n" -"a=rtpmap:98 VP9/90000\\r\\n" -"a=rtcp-fb:98 ccm fir\\r\\n" -"a=rtcp-fb:98 nack\\r\\n" -"a=rtcp-fb:98 nack pli\\r\\n" -"a=rtcp-fb:98 goog-remb\\r\\n" -"a=rtcp-fb:98 transport-cc\\r\\n" -"a=rtpmap:102 H264/90000\\r\\n" -"a=rtcp-fb:102 goog-remb\\r\\n" -"a=rtcp-fb:102 transport-cc\\r\\n" -"a=rtcp-fb:102 ccm fir \\r\\n" -"a=rtcp-fb:102 nack\\r\\n" -"a=rtcp-fb:102 nack pli \\r\\n" -"a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\\r\\n" -"a=ssrc:3233846889 cname:o/i14u9pJrxRKAsu\\r\\n" -"a=ssrc:3233846889 msid:6VrfBKXrwK v0\\r\\n" -"a=ssrc:3233846889 mslabel:6VrfBKXrwK\\r\\n" -"a=ssrc:3233846889 label:6VrfBKXrwKv0\\r\\n"; - srs_error_t srs_api_response_jsonp(ISrsHttpResponseWriter* w, string callback, string data) { srs_error_t err = srs_success; @@ -849,9 +782,10 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa return srs_api_response(w, r, obj->dumps()); } -SrsGoApiSdp::SrsGoApiSdp(SrsServer* svr) +SrsGoApiSdp::SrsGoApiSdp(SrsServer* svr, SrsRtcServer* rtc_svr) { server = svr; + rtc_server = rtc_svr; } SrsGoApiSdp::~SrsGoApiSdp() @@ -888,15 +822,24 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); } - string remote_sdp = remote_sdp_obj->to_str(); + string remote_sdp_str = remote_sdp_obj->to_str(); string app = app_obj->to_str(); string stream_name = stream_name_obj->to_str(); - srs_trace("remote_sdp=%s", remote_sdp.c_str()); + srs_trace("remote_sdp_str=%s", remote_sdp_str.c_str()); srs_trace("app=%s, stream=%s", app.c_str(), stream_name.c_str()); - SrsSdp srs_sdp; - err = srs_sdp.parse(remote_sdp); + SrsSdp remote_sdp; + err = remote_sdp.decode(remote_sdp_str); + if (err != srs_success) { + return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + } + + SrsSdp local_sdp; + rtc_server->create_rtc_session(remote_sdp, local_sdp); + + string local_sdp_str = ""; + err = local_sdp.encode(local_sdp_str); if (err != srs_success) { return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); } @@ -906,9 +849,20 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); obj->set("server", SrsJsonAny::integer(stat->server_id())); + + string candidate_str = "candidate:1 1 udp 2115783679 192.168.170.129:9527 typ host generation 0 ufrag " + + local_sdp.get_ice_ufrag() + "netwrok-cost 50"; + + SrsJsonObject* candidate_obj = SrsJsonAny::object(); + //SrsAutoFree(SrsJsonObject, candidate_obj); + + candidate_obj->set("candidate", SrsJsonAny::str(candidate_str.c_str())); + candidate_obj->set("sdpMid", SrsJsonAny::str("0")); + candidate_obj->set("sdpMLineIndex", SrsJsonAny::str("0")); if (r->is_http_post()) { - obj->set("sdp", SrsJsonAny::str(test_sdp.c_str())); + obj->set("sdp", SrsJsonAny::str(local_sdp_str.c_str())); + obj->set("candidate", candidate_obj); } else { return srs_go_http_error(w, SRS_CONSTS_HTTP_MethodNotAllowed); } diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index d77ba517be..c4cf02a6c7 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -31,6 +31,7 @@ class ISrsHttpMessage; class SrsHttpParser; class SrsHttpHandler; class SrsServer; +class SrsRtcServer; #include #include @@ -168,8 +169,9 @@ class SrsGoApiSdp : public ISrsHttpHandler { private: SrsServer* server; + SrsRtcServer* rtc_server; public: - SrsGoApiSdp(SrsServer* svr); + SrsGoApiSdp(SrsServer* svr, SrsRtcServer* rtc_svr); virtual ~SrsGoApiSdp(); public: virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index 0cd389df59..2c1703250c 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -59,6 +59,19 @@ srs_error_t ISrsUdpHandler::on_stfd_change(srs_netfd_t /*fd*/) return srs_success; } +ISrsUdpRemuxHandler::ISrsUdpRemuxHandler() +{ +} + +ISrsUdpRemuxHandler::~ISrsUdpRemuxHandler() +{ +} + +srs_error_t ISrsUdpRemuxHandler::on_stfd_change(srs_netfd_t /*fd*/) +{ + return srs_success; +} + ISrsTcpHandler::ISrsTcpHandler() { } @@ -207,12 +220,51 @@ srs_error_t SrsTcpListener::cycle() return err; } -SrsUdpRemuxListener::SrsUdpRemuxListener(ISrsUdpHandler* h, std::string i, int p) : SrsUdpListener(h, i, p) +SrsUdpRemuxListener::SrsUdpRemuxListener(ISrsUdpRemuxHandler* h, std::string i, int p) { + handler = h; + ip = i; + port = p; + lfd = NULL; + + nb_buf = SRS_UDP_MAX_PACKET_SIZE; + buf = new char[nb_buf]; + + trd = new SrsDummyCoroutine(); } SrsUdpRemuxListener::~SrsUdpRemuxListener() { + srs_freep(trd); + srs_close_stfd(lfd); + srs_freepa(buf); +} + +int SrsUdpRemuxListener::fd() +{ + return srs_netfd_fileno(lfd); +} + +srs_netfd_t SrsUdpRemuxListener::stfd() +{ + return lfd; +} + +srs_error_t SrsUdpRemuxListener::listen() +{ + srs_error_t err = srs_success; + + if ((err = srs_udp_listen(ip, port, &lfd)) != srs_success) { + return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); + } + + srs_freep(trd); + trd = new SrsSTCoroutine("udp", this); + if ((err = trd->start()) != srs_success) { + return srs_error_wrap(err, "start thread"); + } + + return err; } srs_error_t SrsUdpRemuxListener::cycle() @@ -233,9 +285,10 @@ srs_error_t SrsUdpRemuxListener::cycle() continue; } - if ((err = handler->on_udp_packet((const sockaddr*)&from, nb_from, buf, nread)) != srs_success) { + if ((err = handler->on_udp_packet(lfd, (const sockaddr*)&from, nb_from, buf, nread)) != srs_success) { //srs_error("udp handle packet error"); // remux udp never return + srs_error("udp remux error:%s", srs_error_desc(err).c_str()); continue; } diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index a667af94dd..3b4d96b80f 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -54,6 +54,16 @@ class ISrsUdpHandler virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) = 0; }; +class ISrsUdpRemuxHandler +{ +public: + ISrsUdpRemuxHandler(); + virtual ~ISrsUdpRemuxHandler(); +public: + virtual srs_error_t on_stfd_change(srs_netfd_t fd); + virtual srs_error_t on_udp_packet(srs_netfd_t fd, const sockaddr* from, const int fromlen, char* buf, int nb_buf) = 0; +}; + // The tcp connection handler. class ISrsTcpHandler { @@ -113,11 +123,27 @@ class SrsTcpListener : public ISrsCoroutineHandler virtual srs_error_t cycle(); }; -class SrsUdpRemuxListener : public SrsUdpListener +class SrsUdpRemuxListener : public ISrsCoroutineHandler { +protected: + srs_netfd_t lfd; + SrsCoroutine* trd; +protected: + char* buf; + int nb_buf; +protected: + ISrsUdpRemuxHandler* handler; + std::string ip; + int port; public: - SrsUdpRemuxListener(ISrsUdpHandler* h, std::string i, int p); + SrsUdpRemuxListener(ISrsUdpRemuxHandler* h, std::string i, int p); virtual ~SrsUdpRemuxListener(); +public: + virtual int fd(); + virtual srs_netfd_t stfd(); +public: + virtual srs_error_t listen(); +// Interface ISrsReusableThreadHandler. public: virtual srs_error_t cycle(); }; diff --git a/trunk/src/app/srs_app_rtc.cpp b/trunk/src/app/srs_app_rtc.cpp index 6f53781250..e7fbf7fc23 100644 --- a/trunk/src/app/srs_app_rtc.cpp +++ b/trunk/src/app/srs_app_rtc.cpp @@ -69,7 +69,7 @@ SrsRtc::~SrsRtc() { } -srs_error_t SrsRtc::on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) +srs_error_t SrsRtc::on_udp_packet(srs_netfd_t fd, const sockaddr* from, const int fromlen, char* buf, int nb_buf) { char address_string[64]; char port_string[16]; @@ -82,5 +82,5 @@ srs_error_t SrsRtc::on_udp_packet(const sockaddr* from, const int fromlen, char* std::string peer_ip = std::string(address_string); int peer_port = atoi(port_string); - return rtc_server->on_udp_packet(peer_ip, peer_port, buf, nb_buf); + return rtc_server->on_udp_packet(fd, peer_ip, peer_port, from, fromlen, buf, nb_buf); } diff --git a/trunk/src/app/srs_app_rtc.hpp b/trunk/src/app/srs_app_rtc.hpp index 6e1fb0651f..8c15bbf163 100644 --- a/trunk/src/app/srs_app_rtc.hpp +++ b/trunk/src/app/srs_app_rtc.hpp @@ -37,7 +37,7 @@ struct sockaddr; class SrsRtcServer; // The rtc over udp stream receiver -class SrsRtc : virtual public ISrsUdpHandler +class SrsRtc : virtual public ISrsUdpRemuxHandler { private: SrsRtcServer* rtc_server; @@ -46,7 +46,7 @@ class SrsRtc : virtual public ISrsUdpHandler virtual ~SrsRtc(); // Interface ISrsUdpHandler public: - virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf); + virtual srs_error_t on_udp_packet(srs_netfd_t fd, const sockaddr* from, const int fromlen, char* buf, int nb_buf); }; #endif diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 93fca7f8ce..2a570b4a98 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -25,24 +25,52 @@ using namespace std; +#include +#include +#include + +#include + #include -#include +#include +#include #include +#include #include +#include -static bool is_stun(const char* data, const int size) { +static bool is_stun(const char* data, const int size) +{ return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); } -static bool is_rtp_or_rtcp(const char* data, const int size) { +static bool is_rtp_or_rtcp(const char* data, const int size) +{ return data != NULL && size > 0 && (data[0] >= 128 && data[0] <= 191); } -static bool is_dtls(const char* data, const int size) { +static bool is_dtls(const char* data, const int size) +{ return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); } +static string gen_random_str(int len) +{ + static string random_table = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + string ret; + ret.reserve(len); + for (int i = 0; i < len; ++i) { + ret.append(1, random_table[random() % random_table.size()]); + } + + return ret; +} + +const int SRTP_MASTER_KEY_KEY_LEN = 16; +const int SRTP_MASTER_KEY_SALT_LEN = 14; + SrsSdpMediaInfo::SrsSdpMediaInfo() { } @@ -59,16 +87,16 @@ SrsSdp::~SrsSdp() { } -srs_error_t SrsSdp::parse(const string& sdp) +srs_error_t SrsSdp::decode(const string& sdp_str) { srs_error_t err = srs_success; - if (sdp.size() < 2 || sdp[0] != 'v' || sdp[1] != '=') { - return srs_error_wrap(err, "invalid sdp"); + if (sdp_str.size() < 2 || sdp_str[0] != 'v' || sdp_str[1] != '=') { + return srs_error_wrap(err, "invalid sdp_str"); } string line; - istringstream is(sdp); + istringstream is(sdp_str); while (getline(is, line)) { srs_trace("line=%s", line.c_str()); @@ -76,7 +104,7 @@ srs_error_t SrsSdp::parse(const string& sdp) return srs_error_wrap(err, "invalid sdp line=%s", line.c_str()); } - switch (line[1]) { + switch (line[0]) { case 'v' :{ break; } @@ -94,7 +122,7 @@ srs_error_t SrsSdp::parse(const string& sdp) } case 'a' :{ if (parse_attr(line) != srs_success) { - return srs_error_wrap(err, "parse sdp line=%s failed", line.c_str()); + return srs_error_wrap(err, "decode sdp line=%s failed", line.c_str()); } break; } @@ -107,29 +135,354 @@ srs_error_t SrsSdp::parse(const string& sdp) return err; } +srs_error_t SrsSdp::encode(string& sdp_str) +{ + srs_error_t err = srs_success; + + // FIXME: + sdp_str = + "v=0\\r\\n" + "o=- 0 0 IN IP4 127.0.0.1\\r\\n" + "s=-\\r\\n" + "t=0 0\\r\\n" + "a=ice-lite\\r\\n" + "a=group:BUNDLE 0 1\\r\\n" + "a=msid-semantic: WMS 6VrfBKXrwK\\r\\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111\\r\\n" + "c=IN IP4 0.0.0.0\\r\\n" + "a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" + "a=rtcp:9 IN IP4 0.0.0.0\\r\\n" + "a=ice-ufrag:" + ice_ufrag + "\\r\\n" + "a=ice-pwd:" + ice_pwd + "\\r\\n" + "a=ice-options:trickle\\r\\n" + "a=fingerprint:sha-256 " + SrsDtls::instance()->get_fingerprint() + "\\r\\n" + "a=sendrecv\\r\\n" + "a=mid:0\\r\\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\\r\\n" + "a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" + "a=rtcp-mux\\r\\n" + "a=rtpmap:111 opus/48000/2\\r\\n" + "a=fmtp:111 minptime=10;useinbandfec=1\\r\\n" + "a=maxptime:60\\r\\n" + "a=ssrc:3233846890 cname:o/i14u9pJrxRKAsu\\r\\n" + "a=ssrc:3233846890 msid:6VrfBKXrwK a0\\r\\n" + "a=ssrc:3233846890 mslabel:6VrfBKXrwK\\r\\n" + "a=ssrc:3233846890 label:6VrfBKXrwKa0\\r\\n" + "m=video 9 UDP/TLS/RTP/SAVPF 96 98 102\\r\\n" + "c=IN IP4 0.0.0.0\\r\\n" + "a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" + "a=rtcp:9 IN IP4 0.0.0.0\\r\\n" + "b=as:2000000\\r\\n" + "a=ice-ufrag:" + ice_ufrag + "\\r\\n" + "a=ice-pwd:" + ice_pwd + "\\r\\n" + "a=ice-options:trickle\\r\\n" + "a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\\r\\n" + "a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\\r\\n" + "a=extmap:4 urn:3gpp:video-orientation\\r\\n" + "a=fingerprint:sha-256 " + SrsDtls::instance()->get_fingerprint() + "\\r\\n" + "a=sendrecv\\r\\n" + "a=mid:1\\r\\n" + "a=rtcp-mux\\r\\n" + "a=rtpmap:96 VP8/90000\\r\\n" + "a=rtcp-fb:96 ccm fir\\r\\n" + "a=rtcp-fb:96 nack\\r\\n" + "a=rtcp-fb:96 nack pli\\r\\n" + "a=rtcp-fb:96 goog-remb\\r\\n" + "a=rtcp-fb:96 transport-cc\\r\\n" + "a=rtpmap:98 VP9/90000\\r\\n" + "a=rtcp-fb:98 ccm fir\\r\\n" + "a=rtcp-fb:98 nack\\r\\n" + "a=rtcp-fb:98 nack pli\\r\\n" + "a=rtcp-fb:98 goog-remb\\r\\n" + "a=rtcp-fb:98 transport-cc\\r\\n" + "a=rtpmap:102 H264/90000\\r\\n" + "a=rtcp-fb:102 goog-remb\\r\\n" + "a=rtcp-fb:102 transport-cc\\r\\n" + "a=rtcp-fb:102 ccm fir \\r\\n" + "a=rtcp-fb:102 nack\\r\\n" + "a=rtcp-fb:102 nack pli \\r\\n" + "a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\\r\\n" + "a=ssrc:3233846889 cname:o/i14u9pJrxRKAsu\\r\\n" + "a=ssrc:3233846889 msid:6VrfBKXrwK v0\\r\\n" + "a=ssrc:3233846889 mslabel:6VrfBKXrwK\\r\\n" + "a=ssrc:3233846889 label:6VrfBKXrwKv0\\r\\n"; + + return err; +} + srs_error_t SrsSdp::parse_attr(const string& line) { srs_error_t err = srs_success; + string key = ""; + string val = ""; + string* p = &key; + for (int i = 2; i < line.size(); ++i) { + if (line[i] == ':' && p == &key) { + p = &val; + } else { + if (line[i] != '\r' && line[i] != '\n') { + p->append(1, line[i]); + } + } + } + + srs_trace("sdp attribute key=%s, val=%s", key.c_str(), val.c_str()); + + if (key == "ice-ufrag") { + ice_ufrag = val; + } else if (key == "ice-pwd") { + ice_pwd = val; + } else if (key == "fingerprint") { + + } else { + } + + return err; +} + +SrsDtlsSession::SrsDtlsSession(srs_netfd_t lfd, const sockaddr* f, int fl) +{ + dtls = NULL; + bio_in = NULL; + bio_out = NULL; + + client_key = ""; + server_key = ""; + + srtp_send = NULL; + srtp_recv = NULL; + + fd = lfd; + from = f; + fromlen = fl; + + handshake_done = false; +} + +SrsDtlsSession::~SrsDtlsSession() +{ +} + +srs_error_t SrsDtlsSession::handshake() +{ + srs_error_t err = srs_success; + + int ret = SSL_do_handshake(dtls); + + unsigned char *out_bio_data; + int out_bio_len = BIO_get_mem_data(bio_out, &out_bio_data); + + int ssl_err = SSL_get_error(dtls, ret); + switch(ssl_err) { + case SSL_ERROR_NONE: { + srs_trace("dtls handshake done"); + handshake_done = true; + srtp_init(); + srtp_sender_side_init(); + srtp_receiver_side_init(); + } + break; + + case SSL_ERROR_WANT_READ: { + break; + } + + case SSL_ERROR_WANT_WRITE: { + break; + } + + default: { + break; + } + } + + if (out_bio_len) { + srs_trace("send dtls handshake data"); + srs_sendto(fd, out_bio_data, out_bio_len, from, fromlen, 0); + } + + return err; +} + +srs_error_t SrsDtlsSession::on_dtls(const char* data, const int len) +{ + srs_error_t err = srs_success; + if (! handshake_done) { + BIO_reset(bio_in); + BIO_reset(bio_out); + BIO_write(bio_in, data, len); + + handshake(); + } else { + BIO_reset(bio_in); + BIO_reset(bio_out); + BIO_write(bio_in, data, len); + + while (BIO_ctrl_pending(bio_in) > 0) { + char dtls_read_buf[8092]; + int nb = SSL_read(dtls, dtls_read_buf, sizeof(dtls_read_buf)); + + if (nb > 0) { + on_dtls_application_data(dtls_read_buf, nb); + } + } + } + + return err; +} + +srs_error_t SrsDtlsSession::on_dtls_application_data(const char* buf, const int nb_buf) +{ + srs_error_t err = srs_success; + + return err; +} + + +void SrsDtlsSession::send_client_hello() +{ + if (dtls == NULL) { + srs_trace("send client hello"); + + dtls = SSL_new(SrsDtls::instance()->get_dtls_ctx()); + SSL_set_connect_state(dtls); + + bio_in = BIO_new(BIO_s_mem()); + bio_out = BIO_new(BIO_s_mem()); + + SSL_set_bio(dtls, bio_in, bio_out); + + handshake(); + } +} + +srs_error_t SrsDtlsSession::srtp_init() +{ + srs_error_t err = srs_success; + + unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server + char dtls_srtp_lable[] = "EXTRACTOR-dtls_srtp"; + if (! SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable, strlen(dtls_srtp_lable), NULL, 0, 0)) { + return srs_error_wrap(err, "SSL_export_keying_material failed"); + } + + size_t offset = 0; + + std::string sClientMasterKey(reinterpret_cast(material), SRTP_MASTER_KEY_KEY_LEN); + offset += SRTP_MASTER_KEY_KEY_LEN; + std::string sServerMasterKey(reinterpret_cast(material + offset), SRTP_MASTER_KEY_KEY_LEN); + offset += SRTP_MASTER_KEY_KEY_LEN; + std::string sClientMasterSalt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); + offset += SRTP_MASTER_KEY_SALT_LEN; + std::string sServerMasterSalt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); + + client_key = sClientMasterKey + sClientMasterSalt; + server_key = sServerMasterKey + sServerMasterSalt; + + srtp_sender_side_init(); + srtp_receiver_side_init(); +} + +srs_error_t SrsDtlsSession::srtp_sender_side_init() +{ + srs_error_t err = srs_success; + + srtp_policy_t policy; + bzero(&policy, sizeof(policy)); + + srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); + srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); + + policy.ssrc.type = ssrc_any_outbound; + + policy.ssrc.value = 0; + policy.window_size = 8192; // seq 鐩稿樊8192璁や负鏃犳晥 + policy.allow_repeat_tx = 1; + policy.next = NULL; + + uint8_t *key = new uint8_t[client_key.size()]; + memcpy(key, client_key.data(), client_key.size()); + policy.key = key; + + if (srtp_create(&srtp_send, &policy) != 0) { + return srs_error_wrap(err, "srtp_create failed"); + } + + delete [] key; + + return err; +} + +srs_error_t SrsDtlsSession::srtp_receiver_side_init() +{ + srs_error_t err = srs_success; + + srtp_policy_t policy; + bzero(&policy, sizeof(policy)); + + srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); + srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); + + policy.ssrc.type = ssrc_any_inbound; + + policy.ssrc.value = 0; + policy.window_size = 8192; // seq 鐩稿樊8192璁や负鏃犳晥 + policy.allow_repeat_tx = 1; + policy.next = NULL; + + uint8_t *key = new uint8_t[server_key.size()]; + memcpy(key, server_key.data(), server_key.size()); + policy.key = key; + + if (srtp_create(&srtp_recv, &policy) != 0) { + return srs_error_wrap(err, "srtp_create failed"); + } + + delete [] key; + return err; } SrsRtcSession::SrsRtcSession() { session_state = INIT; + dtls_session = NULL; } SrsRtcSession::~SrsRtcSession() { } -srs_error_t SrsRtcSession::on_stun(const SrsStunPacket& stun_packet) +srs_error_t SrsRtcSession::on_binding_request(const SrsStunPacket& stun_packet, const string& peer_ip, const uint16_t peer_port, + SrsStunPacket& stun_binding_response) { srs_error_t err = srs_success; + stun_binding_response.set_message_type(BindingResponse); + stun_binding_response.set_local_ufrag(stun_packet.get_remote_ufrag()); + stun_binding_response.set_remote_ufrag(stun_packet.get_local_ufrag()); + stun_binding_response.set_transcation_id(stun_packet.get_transcation_id()); + stun_binding_response.set_mapped_address(be32toh(inet_addr(peer_ip.c_str()))); + stun_binding_response.set_mapped_port(peer_port); + return err; } +srs_error_t SrsRtcSession::send_client_hello(srs_netfd_t fd, const sockaddr* from, int fromlen) +{ + if (dtls_session == NULL) { + dtls_session = new SrsDtlsSession(fd, from, fromlen); + } + + dtls_session->send_client_hello(); +} + +srs_error_t SrsRtcSession::on_dtls(const char* buf, const int nb_buf) +{ + dtls_session->on_dtls(buf, nb_buf); +} + srs_error_t SrsRtcSession::send_packet() { } @@ -150,59 +503,147 @@ srs_error_t SrsRtcServer::initialize() return err; } -srs_error_t SrsRtcServer::on_udp_packet(const string& peer_ip, const int peer_port, const char* data, const int size) +srs_error_t SrsRtcServer::on_udp_packet(srs_netfd_t fd, const string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size) { srs_error_t err = srs_success; if (is_stun(data, size)) { - return on_stun(peer_ip, peer_port, data, size); + return on_stun(fd, peer_ip, peer_port, from, fromlen, data, size); } else if (is_dtls(data, size)) { - return on_dtls(peer_ip, peer_port, data, size); + srs_trace("dtls"); + return on_dtls(fd, peer_ip, peer_port, from, fromlen, data, size); } else if (is_rtp_or_rtcp(data, size)) { - return on_rtp_or_rtcp(peer_ip, peer_port, data, size); + return on_rtp_or_rtcp(fd, peer_ip, peer_port, from, fromlen, data, size); } return srs_error_wrap(err, "unknown packet type"); } -srs_error_t SrsRtcServer::on_stun(const string& peer_ip, const int peer_port, const char* data, const int size) +SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp) +{ + SrsRtcSession* session = new SrsRtcSession(); + + std::string local_ufrag = gen_random_str(8); + std::string local_pwd = gen_random_str(32); + + while (true) { + bool ret = map_ufrag_sessions.insert(make_pair(remote_sdp.get_ice_ufrag(), session)).second; + if (ret) { + break; + } + } + + local_sdp.set_ice_ufrag(local_ufrag); + local_sdp.set_ice_pwd(local_pwd); + + session->set_remote_sdp(remote_sdp); + session->set_local_sdp(local_sdp); + + session->set_session_state(WAITING_STUN); + + return session; +} + +SrsRtcSession* SrsRtcServer::find_rtc_session_by_ip_port(const string& peer_ip, const uint16_t peer_port) +{ + ostringstream os; + os << peer_ip << ":" << peer_port; + string key = os.str(); + map::iterator iter = map_ip_port_sessions.find(key); + if (iter == map_ip_port_sessions.end()) { + return NULL; + } + + return iter->second; +} + +srs_error_t SrsRtcServer::on_stun(srs_netfd_t fd, const string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size) { srs_error_t err = srs_success; srs_trace("peer %s:%d stun", peer_ip.c_str(), peer_port); - SrsStunPacket stun_packet; - if (stun_packet.decode(data, size) != srs_success) { + SrsStunPacket stun_req; + if (stun_req.decode(data, size) != srs_success) { return srs_error_wrap(err, "decode stun failed"); } - std::string peer_ufrag = stun_packet.ufrag(); - SrsRtcSession* rtc_session = find_rtc_session(peer_ufrag); + std::string remote_ufrag = stun_req.get_remote_ufrag(); + SrsRtcSession* rtc_session = find_rtc_session_by_ufrag(remote_ufrag); if (rtc_session == NULL) { - return srs_error_wrap(err, "can not find rtc_session, ufrag=%s", peer_ufrag.c_str()); + return srs_error_wrap(err, "can not find rtc_session, ufrag=%s", remote_ufrag.c_str()); + } + + SrsStunPacket stun_rsp; + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + if (stun_req.is_binding_request()) { + if (rtc_session->on_binding_request(stun_req, peer_ip, peer_port, stun_rsp) != srs_success) { + return srs_error_wrap(err, "stun binding request failed"); + } + } + + if (stun_rsp.encode(rtc_session->get_local_sdp()->get_ice_pwd(), stream) != srs_success) { + return srs_error_wrap(err, "stun rsp encode failed"); } - return rtc_session->on_stun(stun_packet); + srs_sendto(fd, stream->data(), stream->pos(), from, fromlen, 0); + + if (rtc_session->get_session_state() == WAITING_STUN) { + rtc_session->set_session_state(DOING_DTLS_HANDSHAKE); + rtc_session->send_client_hello(fd, from, fromlen); + + insert_into_ip_port_sessions(peer_ip, peer_port, rtc_session); + } + + return err; } -srs_error_t SrsRtcServer::on_dtls(const string& peer_ip, const int peer_port, const char* data, const int size) +srs_error_t SrsRtcServer::on_dtls(srs_netfd_t fd, const string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size) { srs_error_t err = srs_success; + srs_trace("on dtls"); + + // FIXME + SrsRtcSession* rtc_session = find_rtc_session_by_ip_port(peer_ip, peer_port); + + if (rtc_session == NULL) { + return srs_error_wrap(err, "can not find rtc session by ip=%s, port=%u", peer_ip.c_str(), peer_port); + } + + rtc_session->on_dtls(data, size); + return err; } -srs_error_t SrsRtcServer::on_rtp_or_rtcp(const string& peer_ip, const int peer_port, const char* data, const int size) +srs_error_t SrsRtcServer::on_rtp_or_rtcp(srs_netfd_t fd, const string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size) { srs_error_t err = srs_success; + srs_trace("on rtp/rtcp"); return err; } -SrsRtcSession* SrsRtcServer::find_rtc_session(const std::string& ufrag) +SrsRtcSession* SrsRtcServer::find_rtc_session_by_ufrag(const std::string& ufrag) { - map::iterator iter = map_sessions.find(ufrag); - if (iter == map_sessions.end()) { + map::iterator iter = map_ufrag_sessions.find(ufrag); + if (iter == map_ufrag_sessions.end()) { return NULL; } return iter->second; } + +bool SrsRtcServer::insert_into_ip_port_sessions(const string& peer_ip, const uint16_t peer_port, SrsRtcSession* rtc_session) +{ + ostringstream os; + os << peer_ip << ":" << peer_port; + string key = os.str(); + + return map_ip_port_sessions.insert(make_pair(key, rtc_session)).second; +} diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index df370d5853..c400766864 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -25,11 +25,15 @@ #define SRS_APP_RTC_CONN_HPP #include +#include #include #include #include +#include +#include + class SrsServer; class SrsStunPacket; @@ -55,7 +59,14 @@ class SrsSdp SrsSdp(); virtual ~SrsSdp(); - srs_error_t parse(const std::string& sdp); + srs_error_t decode(const std::string& sdp_str); + srs_error_t encode(std::string& sdp_str); + + std::string get_ice_ufrag() const { return ice_ufrag; } + std::string get_ice_pwd() const { return ice_pwd; } + + void set_ice_ufrag(const std::string& u) { ice_ufrag = u; } + void set_ice_pwd(const std::string& p) { ice_pwd = p; } private: srs_error_t parse_attr(const std::string& line); }; @@ -69,19 +80,63 @@ enum SrsRtcSessionStateType CLOSED = 4, }; -class SrsRtcSession +class SrsDtlsSession { +private: + SSL* dtls; + BIO* bio_in; + BIO* bio_out; + + std::string client_key; + std::string server_key; + + srtp_t srtp_send; + srtp_t srtp_recv; + + srs_netfd_t fd; + const sockaddr* from; + int fromlen; + + bool handshake_done; + public: + SrsDtlsSession(srs_netfd_t lfd, const sockaddr* f, int fl); + virtual ~SrsDtlsSession(); + + srs_error_t on_dtls(const char* data, const int len); + srs_error_t on_dtls_application_data(const char* data, const int len); + + void send_client_hello(); + srs_error_t handshake(); + srs_error_t srtp_init(); + srs_error_t srtp_sender_side_init(); + srs_error_t srtp_receiver_side_init(); +}; + +class SrsRtcSession +{ private: - SrsSdp peer_sdp; - SrsSdp offer_sdp; + SrsSdp remote_sdp; + SrsSdp local_sdp; SrsRtcSessionStateType session_state; + SrsDtlsSession* dtls_session; public: SrsRtcSession(); virtual ~SrsRtcSession(); + SrsSdp* get_local_sdp() { return &local_sdp; } + SrsSdp* get_remote_sdp() { return &remote_sdp; } + SrsRtcSessionStateType get_session_state() { return session_state; } + + void set_local_sdp(const SrsSdp& sdp) { local_sdp = sdp; } + void set_remote_sdp(const SrsSdp& sdp) { remote_sdp = sdp; } + void set_session_state(SrsRtcSessionStateType state) { session_state = state; } + srs_error_t on_udp_packet(const std::string& peer_ip, const int peer_port, const char* data, const int size); - srs_error_t on_stun(const SrsStunPacket& stun_packet); + srs_error_t on_binding_request(const SrsStunPacket& stun_packet, const std::string& peer_ip, const uint16_t peer_port, + SrsStunPacket& stun_binding_response); + srs_error_t on_dtls(const char* buf, const int nb_buf); + srs_error_t send_client_hello(srs_netfd_t fd, const sockaddr* from, int fromlen); srs_error_t send_packet(); }; @@ -89,19 +144,26 @@ class SrsRtcServer { private: SrsServer* server; - std::map map_sessions; + std::map map_ufrag_sessions; + std::map map_ip_port_sessions; public: SrsRtcServer(SrsServer* svr); virtual ~SrsRtcServer(); public: virtual srs_error_t initialize(); - virtual srs_error_t on_udp_packet(const std::string& peer_ip, const int peer_port, const char* data, const int size); + virtual srs_error_t on_udp_packet(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size); + + SrsRtcSession* create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp); + bool insert_into_ip_port_sessions(const std::string& peer_ip, const uint16_t peer_port, SrsRtcSession* rtc_session); private: - srs_error_t on_stun(const std::string& peer_ip, const int peer_port, const char* data, const int size); - srs_error_t on_dtls(const std::string& peer_ip, const int peer_port, const char* data, const int size); - srs_error_t on_rtp_or_rtcp(const std::string& peer_ip, const int peer_port, const char* data, const int size); + srs_error_t on_stun(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, const sockaddr* from, const int fromlen, const char* data, const int size); + srs_error_t on_dtls(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, const sockaddr* from, const int fromlen, const char* data, const int size); + srs_error_t on_rtp_or_rtcp(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, + const sockaddr* from, const int fromlen, const char* data, const int size); private: - SrsRtcSession* find_rtc_session(const std::string& ufrag); + SrsRtcSession* find_rtc_session_by_ufrag(const std::string& ufrag); + SrsRtcSession* find_rtc_session_by_ip_port(const std::string& peer_ip, const uint16_t peer_port); }; #endif diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 548ee3cddf..cdd9394085 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -838,7 +838,7 @@ srs_error_t SrsServer::http_handle() if ((err = http_api_mux->handle("/api/v1/streams/", new SrsGoApiStreams())) != srs_success) { return srs_error_wrap(err, "handle streams"); } - if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(this))) != srs_success) { + if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(this, rtc_server))) != srs_success) { return srs_error_wrap(err, "handle sdp"); } if ((err = http_api_mux->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) { diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 36e4c8b3f2..8fa17ff9d1 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -162,8 +162,8 @@ class SrsUdpCasterListener : public SrsUdpStreamListener class SrsRtcListener : public SrsListener { protected: - SrsUdpListener* listener; - ISrsUdpHandler* rtc; + SrsUdpRemuxListener* listener; + ISrsUdpRemuxHandler* rtc; public: SrsRtcListener(SrsServer* svr, SrsRtcServer* rtc_svr, SrsListenerType t); virtual ~SrsRtcListener(); diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp index 38c8c00a24..50284c785e 100644 --- a/trunk/src/protocol/srs_stun_stack.cpp +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -2,27 +2,271 @@ using namespace std; +#include +#include +#include +#include + +#include +#include +#include +#include + +static string dump_string_hex(const std::string& str, const int& max_len = 128) +{ + char buf[1024*16]; + int len = 0; + + for (int i = 0; i < str.size() && i < max_len; ++i) { + int nb = snprintf(buf + len, sizeof(buf) - len - 1, "%02X ", (uint8_t)str[i]); + if (nb <= 0) + break; + + len += nb; + } + buf[len] = '\0'; + + return string(buf, len); +} + +static srs_error_t hmac_encode(const std::string& algo, const char* key, const int& key_length, + const char* input, const int input_length, char* output, unsigned int& output_length) +{ + srs_error_t err = srs_success; + + const EVP_MD* engine = NULL; + if (algo == "sha512") { + engine = EVP_sha512(); + } else if(algo == "sha256") { + engine = EVP_sha256(); + } else if(algo == "sha1") { + engine = EVP_sha1(); + } else if(algo == "md5") { + engine = EVP_md5(); + } else if(algo == "sha224") { + engine = EVP_sha224(); + } else if(algo == "sha384") { + engine = EVP_sha384(); + } else { + return srs_error_wrap(err, "unknown algo=%s", algo.c_str()); + } + + HMAC_CTX* ctx = HMAC_CTX_new(); + if (HMAC_Init_ex(ctx, key, key_length, engine, NULL) < 0) { + HMAC_CTX_free(ctx); + return srs_error_wrap(err, "hmac init faied"); + } + + if (HMAC_Update(ctx, (const unsigned char*)input, input_length) < 0) { + HMAC_CTX_free(ctx); + return srs_error_wrap(err, "hmac update faied"); + } + + if (HMAC_Final(ctx, (unsigned char*)output, &output_length) < 0) { + HMAC_CTX_free(ctx); + return srs_error_wrap(err, "hmac final faied"); + } + + HMAC_CTX_free(ctx); + + return err; +} + + SrsStunPacket::SrsStunPacket() { + message_type = 0; + local_ufrag = ""; + remote_ufrag = ""; } SrsStunPacket::~SrsStunPacket() { } -string SrsStunPacket::ufrag() +srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) { - return ""; + srs_error_t err = srs_success; + + SrsBuffer* stream = new SrsBuffer(const_cast(buf), nb_buf); + SrsAutoFree(SrsBuffer, stream); + + if (stream->left() < 20) { + return srs_error_wrap(err, "invalid stun packet, size=%d", stream->size()); + } + + srs_trace("stun packet, nb_buf=%d", nb_buf); + + message_type = stream->read_2bytes(); + uint16_t message_len = stream->read_2bytes(); + string magic_cookie = stream->read_string(4); + transcation_id = stream->read_string(12); + + srs_trace("message_type=%u, message_len=%u, magic_cookie=%s, transcation_id=%s", + message_type, message_len, magic_cookie.c_str(), transcation_id.c_str()); + + if (nb_buf != 20 + message_len) { + return srs_error_wrap(err, "invalid stun packet, message_len=%d, nb_buf=%d", message_len, nb_buf); + } + + while (stream->left() >= 4) { + uint16_t type = stream->read_2bytes(); + uint16_t len = stream->read_2bytes(); + + srs_trace("type=%u, len=%u", type, len); + + if (stream->left() < len) { + return srs_error_wrap(err, "invalid stun packet"); + } + + string val = stream->read_string(len); + // padding + if (len % 4 != 0) { + stream->read_string(4 - (len % 4)); + } + //srs_trace("val=%s", val.c_str()); + + switch (type) { + // FIXME: enum + case 6: { + size_t p = val.find(":"); + if (p != string::npos) { + local_ufrag = val.substr(0, p); + remote_ufrag = val.substr(p + 1); + srs_trace("stun packet local_ufrag=%s, remote_ufrag=%s", local_ufrag.c_str(), remote_ufrag.c_str()); + } + break; + } + + default: { + break; + } + } + } + + return err; } -string SrsStunPacket::pwd() +srs_error_t SrsStunPacket::encode(const string& pwd, SrsBuffer* stream) { - return ""; + srs_error_t err = srs_success; + if (is_binding_response()) { + return encode_binding_response(pwd, stream); + } + + return srs_error_wrap(err, "unknown stun type=%d", get_message_type()); } -srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) +// FIXME: make this function easy to read +srs_error_t SrsStunPacket::encode_binding_response(const string& pwd, SrsBuffer* stream) { srs_error_t err = srs_success; + string property_username = encode_username(); + string mapped_address = encode_mapped_address(); + + stream->write_2bytes(BindingResponse); + stream->write_2bytes(property_username.size() + mapped_address.size()); + stream->write_4bytes(0x2112A442); + stream->write_string(transcation_id); + stream->write_string(property_username); + stream->write_string(mapped_address); + + stream->data()[2] = ((stream->pos() - 20 + 20 + 4) & 0x0000FF00) >> 8; + stream->data()[3] = ((stream->pos() - 20 + 20 + 4) & 0x000000FF); + + char hmac_buf[20] = {0}; + unsigned int hmac_buf_len = 0; + if (hmac_encode("sha1", pwd.c_str(), pwd.size(), stream->data(), stream->pos(), hmac_buf, hmac_buf_len) != srs_success) { + return srs_error_wrap(err, "hmac encode failed"); + } + + string hmac = encode_hmac(hmac_buf, hmac_buf_len); + + stream->write_string(hmac); + stream->data()[2] = ((stream->pos() - 20 + 8) & 0x0000FF00) >> 8; + stream->data()[3] = ((stream->pos() - 20 + 8) & 0x000000FF); + + uint32_t crc32 = srs_crc32_ieee(stream->data(), stream->pos(), 0) ^ 0x5354554E; + + string fingerprint = encode_fingerprint(crc32); + + stream->write_string(fingerprint); + + stream->data()[2] = ((stream->pos() - 20) & 0x0000FF00) >> 8; + stream->data()[3] = ((stream->pos() - 20) & 0x000000FF); + return err; } + +string SrsStunPacket::encode_username() +{ + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + string username = remote_ufrag + ":" + local_ufrag; + + stream->write_2bytes(Username); + stream->write_2bytes(username.size()); + stream->write_string(username); + + if (stream->pos() % 4 != 0) { + static char padding[4] = {0}; + stream->write_bytes(padding, 4 - (stream->pos() % 4)); + } + + return string(stream->data(), stream->pos()); +} + +string SrsStunPacket::encode_mapped_address() +{ + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + uint32_t magic_cookie = 0x2112A442; +#if 1 + stream->write_2bytes(XorMappedAddress); + stream->write_2bytes(8); + stream->write_1bytes(0); // ignore this bytes + stream->write_1bytes(1); // ipv4 family + stream->write_2bytes(mapped_port ^ (magic_cookie >> 16)); + stream->write_4bytes(mapped_address ^ magic_cookie); +#else + stream->write_2bytes(MappedAddress); + stream->write_2bytes(8); + stream->write_1bytes(0); // ignore this bytes + stream->write_1bytes(1); // ipv4 family + stream->write_2bytes(mapped_port); + stream->write_4bytes(mapped_address); +#endif + + return string(stream->data(), stream->pos()); +} + +string SrsStunPacket::encode_hmac(char* hmac_buf, const int hmac_buf_len) +{ + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + stream->write_2bytes(MessageIntegrity); + stream->write_2bytes(hmac_buf_len); + stream->write_bytes(hmac_buf, hmac_buf_len); + + return string(stream->data(), stream->pos()); +} + +string SrsStunPacket::encode_fingerprint(uint32_t crc32) +{ + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + stream->write_2bytes(Fingerprint); + stream->write_2bytes(4); + stream->write_4bytes(crc32); + + return string(stream->data(), stream->pos()); +} diff --git a/trunk/src/protocol/srs_stun_stack.hpp b/trunk/src/protocol/srs_stun_stack.hpp index 61269050a0..80bba8a151 100644 --- a/trunk/src/protocol/srs_stun_stack.hpp +++ b/trunk/src/protocol/srs_stun_stack.hpp @@ -29,16 +29,81 @@ #include #include +class SrsBuffer; + +enum SrsStunMessageType +{ + // see @ https://tools.ietf.org/html/rfc3489#section-11.1 + BindingRequest = 0x0001, + BindingResponse = 0x0101, + BindingErrorResponse = 0x0111, + SharedSecretRequest = 0x0002, + SharedSecretResponse = 0x0102, + SharedSecretErrorResponse = 0x0112, +}; + +enum SrsStunMessageAttribute +{ + // see @ https://tools.ietf.org/html/rfc3489#section-11.2 + MappedAddress = 0x0001, + ResponseAddress = 0x0002, + ChangeRequest = 0x0003, + SourceAddress = 0x0004, + ChangedAddress = 0x0005, + Username = 0x0006, + Password = 0x0007, + MessageIntegrity = 0x0008, + ErrorCode = 0x0009, + UnknownAttributes = 0x000A, + ReflectedFrom = 0x000B, + + // see @ https://tools.ietf.org/html/rfc5389#section-18.2 + Realm = 0x0014, + Nonce = 0x0015, + XorMappedAddress = 0x0020, + Software = 0x8022, + AlternateServer = 0x8023, + Fingerprint = 0x8028, +}; + class SrsStunPacket { +private: + uint16_t message_type; + std::string local_ufrag; + std::string remote_ufrag; + std::string transcation_id; + uint32_t mapped_address; + uint16_t mapped_port; public: SrsStunPacket(); virtual ~SrsStunPacket(); - std::string ufrag(); - std::string pwd(); + bool is_binding_request() const { return message_type == BindingRequest; } + bool is_binding_response() const { return message_type == BindingResponse; } + + uint16_t get_message_type() const { return message_type; } + std::string get_local_ufrag() const { return local_ufrag; } + std::string get_remote_ufrag() const { return remote_ufrag; } + std::string get_transcation_id() const { return transcation_id; } + uint32_t get_mapped_address() const { return mapped_address; } + uint16_t get_mapped_port() const { return mapped_port; } + + void set_message_type(const uint16_t& m) { message_type = m; } + void set_local_ufrag(const std::string& u) { local_ufrag = u; } + void set_remote_ufrag(const std::string& u) { remote_ufrag = u; } + void set_transcation_id(const std::string& t) { transcation_id = t; } + void set_mapped_address(const uint32_t& addr) { mapped_address = addr; } + void set_mapped_port(const uint32_t& port) { mapped_port = port; } srs_error_t decode(const char* buf, const int nb_buf); + srs_error_t encode(const std::string& pwd, SrsBuffer* stream); +private: + srs_error_t encode_binding_response(const std::string& pwd, SrsBuffer* stream); + std::string encode_username(); + std::string encode_mapped_address(); + std::string encode_hmac(char* hamc_buf, const int hmac_buf_len); + std::string encode_fingerprint(uint32_t crc32); }; #endif diff --git a/trunk/src/service/srs_service_st.cpp b/trunk/src/service/srs_service_st.cpp index f63cd42794..555ff5a33f 100644 --- a/trunk/src/service/srs_service_st.cpp +++ b/trunk/src/service/srs_service_st.cpp @@ -397,6 +397,11 @@ int srs_recvfrom(srs_netfd_t stfd, void *buf, int len, struct sockaddr *from, in return st_recvfrom((st_netfd_t)stfd, buf, len, from, fromlen, (st_utime_t)timeout); } +int srs_sendto(srs_netfd_t stfd, void *buf, int len, const struct sockaddr * to, int tolen, srs_utime_t timeout) +{ + return st_sendto((st_netfd_t)stfd, buf, len, to, tolen, (st_utime_t)timeout); +} + srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout) { return (srs_netfd_t)st_accept((st_netfd_t)stfd, addr, addrlen, (st_utime_t)timeout); diff --git a/trunk/src/service/srs_service_st.hpp b/trunk/src/service/srs_service_st.hpp index 510b9ba8ac..4894e7049d 100644 --- a/trunk/src/service/srs_service_st.hpp +++ b/trunk/src/service/srs_service_st.hpp @@ -88,6 +88,7 @@ extern srs_netfd_t srs_netfd_open_socket(int osfd); extern srs_netfd_t srs_netfd_open(int osfd); extern int srs_recvfrom(srs_netfd_t stfd, void *buf, int len, struct sockaddr *from, int *fromlen, srs_utime_t timeout); +extern int srs_sendto(srs_netfd_t stfd, void *buf, int len, const struct sockaddr *to, int tolen, srs_utime_t timeout); extern srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout); From 936ba7583eefb0d54b0af54cfe9cc7f9eac27ecf Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Fri, 6 Mar 2020 23:40:20 +0800 Subject: [PATCH 08/69] modify depend.sh --- trunk/3rdparty/libsrtp-2.0.0.zip | Bin 178 -> 359773 bytes trunk/auto/depends.sh | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/3rdparty/libsrtp-2.0.0.zip b/trunk/3rdparty/libsrtp-2.0.0.zip index c149013ac25bd5e7e3d4714a6cdb3fa3035bf4e7..e0f7c414dc96b67f0c362936ee76038a5fd86bee 100644 GIT binary patch literal 359773 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[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%0D=)g$VMe zeY1->C3xsm#sWcY*Zt?NlSpBH!=()2Y+$}Ri>)7?y&lGXgxNtuXfBS29(&fHH$AU$ zqMj{O+VAC{$6iR>NUK#@YKUv}l*iiRzq6OK1D>Nm8cUnPsSrR<`&(H*Wi9(zx@H$z zQ6E$`o6oK+y15#BcR%|t4@BGhE7LYwuG#B1KQOE++$-WngPD{M343rhUkrN5h94N# zs}!sn==;DCK>B*G)ck8{y`nL*qfIAb1mHD;!@29LUyI`2#)LK1^d!6w3NT?|SIe@i=v$H}N~d$Gu_qIHMXzGr?c)-R^1DhchT;C03HxGyBJtpeuX%r?tW98g$;HWa)Yz(+LYf{c=oZJBDe z(aZBe@st}JH_K(CwychUq%kT336(F6@`VGp(`#Iwx3gYq#gkLnn!+Mc;BVgEzl&wK z*#c5AJB+JJ6(zp0UR__0Yt&{)wt?+q_B62#U#xO=xk?v>Sg7tFSV-OhT$R_m>9rO1 zsUCz5*;}>G3tAGa5H4>T%Uoj=2iGT<9h>tA8}lOLtN}QVTiVD`LbPhMw{3qKqWC-td1K{NIaf-I-72vnD0Vhekvl_lH$V5 z*!)A>lIJnc(&N9hC~T74w+dm=?6;U;wC&muOfrxLUkO%-or0EKtDMhISP$KDIoq1* z>p=fVyc@-5S=}{me_dA1ZxjD*HrLQ}YNa)#!Beae?_{=P*2J}1?mC$V7ay4Cuy%YA zV+^_CqBd_PI}SM^oTW3NgE$9IO2cvffCJAS9IbH*7=*7$yDegAD7K07kioZs->l=E z)t%8P@#>kOI57eR=rx>*;l*r~d6eTKR!|h3VCx>;~UdW9~Z5 zrd&@TdgCx*ROK$JqP8jp%q50>;Ol>T%>OfB4S(ry8}nlkD^mP79N~XGa<2d7l^asG zuvr(!{L0p0C`oe1CunIt!_9hd6bj8y6~~7v0T?KaiAykY67V~WFbkA_1c|eoq zEs0|(QA8eh?dTl4`ovr|P-FUVK;DLRgHZ2B5WDKi#e(nuwr>u<$Jp1g&lcv^SBsT) zi=Z*els>H&MYNk?LJc=czn|1?gSgrcZHifya!tEM!Ew^ZfMj)z<;a;pyK z7tFQxl}$2p<>qK8`{;%|!5uL&!Hr4* zH4lO9fLbCMZiH&@#2CGR@1ctnhoDSSJi7R;pN5p&7P=>f4Hj51* zIl)uNTF*0T3>0o`0RSTb%J{&b?1_~E$1hmr%NNG|Is|XSE9URLRnK!@&kgPBD;f8L zYKhBx*|m-~%$m~mTmLznYKMp4!d2~c&JK*nCt#l2GA_VNn)~vVxBhlci`NgPv5WWK z#=6F97ue6cgX^ISuyNs1b4TlCYXTJ*cKH(K*I1L!KAfGyss+XT&sxrN_D|X8G)i~# z%%_FVi&&iJHCzY2i0F2JVa8VTyFibF%hpxHM#qh+ZsK?S2Im@vP2l+-Mb-6k*ZOEdG>=l*MtEWL={&+6Ad@_!O`AKHh&TC_(> z;I?yc2hE@PnxNPHo@2N)`vsimy3KUl#UqD{!zthV(l}kbu7g`cJfvD`1} zS32;Me@*nB``mDC??!4pgNb{%0M~$W4m1I4z54(TL1g1RXUCim@)o^D%i}i_HSQVrKBCle!v+<+6VRQD^ zSG%}f>bP%3i^zBco)qxiAmd$j^W}1NlYZ5~jJt??-l5(U^Krs%$v+u=c`SFo05GEk z4sV7iKzr^BhzDd*82}(*l@ibFiw%-plz;YN@h3lj9iEuO#f@Z-n59z3Y3vZjlifa; zK3QLL0I_Am$GSa9F7>T7@F>JP_CD>ntXA}7Wv@SM3IBn1lO%z|i`}}D4B{k-Mn}1W zilA@;u|x>WajU*hIQZ7SV_pnn(wZLe4JJyX6wlQ>Vklx4ATjo-P5I{b3W#~W@V#oD zOhBo}7$KM!Wk*6(>pwt&rQ~=Y-Zcv;p?Q<}xMEBbU zAB)!r_XU#T5RXQ`C!4;99{rudm}8H?J?G}p1*Iz_4A&4ML|d#@n@Z3nhbu&;=jyx1 zBz=k-=J?SoIIc#t{1AC}!aI&nA%=LUD@H75nO^KtTTHl6=h`jms>Umu)Jk1R+Th9X z7B51ystrnp&1{hL_Gjg_^4XEero-&w+JPqlUJ8$hS z%uO2nz$cTfX*GKyf$AT@Q^at>x5yJzFY;c*@@EqZ5z?y6SVBW1_LnT6MI#OvMUvF{ z$@oEW1TlA*Z}ZtMP-<2lLKF!ySK(cl4+4h-22X+!X8hEzxIcM>cFbD+-BDbDd;0Chiuen1^4nk(bm!t&dJl=rSga39Hyg?hwRHpS7NfZX#|nk{-y>Svo~M*^tZg2S z9^3e^w;Ds*-*!3XU%6i> zMwl=@qBnC7RGf;D+!A>j9k615mys+oc!ClG`xFP!h)f((ba1 zRhJdPj1SGdZV~Y@DYQ_!v5$htUygTX9LNb4 zv}E43r3B_QjQ`znf2>$JKcI;n{rXoiwDh4(Dsbuzc{)*oP0_FU7c!)hXn1E>IgQkv zV7Igr{?)l+ER<4(6Urj5cy|?ExOmxOHgpRs=)|M5Qf1fxjhWTtJ&MqhciQTc6)cgg zqC7ExE9j5KiLQn!p~OdE&n-m&tLZP}7Hr(K^63Q81DH`~PN(RsQ@rHSbAmq50^^|n zQc_($ZTUVt?-Wz{=tGJ)ny1s%=*=)L2w`H4>|H6HadD~P{8l{nC6E8e2eUs1wztLQ z@B32#S7HN6xEmL`x?qgbhzRv~vG!9S#IWd0SWFPU>aNZp-hmY^SHf3_4lGxLE@haZ z&urSIPkF%+J_oB*k?O9GnJ){?9~+ZgXWv``M^-6U{zTId&3-J0T`2WbH4D0x7@BeS z)FEQM5JM$tb}QiQuH1GsNOxx#)UPK-@FM@m%cQVPtMpQQtglN&BCot;fMrY!r9;f; z26!ItW2bP3O3r*FeppMEqa#(=+vSA7t=nCU2AqT@@A*&jjl8zk=LSI&z3ATw;_smP z!>6x59d2?y5`^RT8clYmoAtLE_1ZK;s9ptmK!;NnAmV^qm4I}6B7Nui3SoKISDVU_ z*GH45(q)I{oxhdT`eaUidU#)`RzN4M^w9{F4T#TRh9SEKhiaG+sT50VQs)cv^K@O4 zqlkkCi?9zZ1|=hmYOfZ)tLj}zfTCW-mk`f4smQ^$GR}vDx1Hqo@%snkK<}CMsX<{^ zU$aBnMuk(+gdqI*pKh|uM4E1TE`$XM(53v@%VgEg^=Uwz=D90U&2S1{E>b7vlm}@V zq*%w;Eg6p;^4LaX(vHOx&<|LaYuo9Zlo|KTFGUI|!*bDxa;!}|sIE!9tn4@&o=ZG) zQDKME#Kc+37Nhr#6A1rwXab^o33oUwJxuv8(qi_Lq_ZREx-(bV0~?44ZS0}gbNo3+ z<06U^G;uHM4kxi$Itf;ta}8&sjM^|EvbjWqj55shdf^y3BPV*aRlGQyi{9g1N7ELtR968Ji8NxT^-uqQ!-rVa1ZF(V=1LPZuU|4Hif7LEHFc zYvn`oG!aqyC6tf!1!)t1iG@F!yaE?$i8Op!whEVTN8W~-Ys&z`U}ku72bTCPhb&fQ zj;J3$a#~=3jJW}{jdhjVgi_~I>^oNZ%$1+EO^7~Fzg9{jakGvcaWNvl( zBAm-;ICvEsWn6Ak#iRDqR0D*66FdvaEgR1_{0zNhuM#Jf8kK;$c^7qA6-u!Azg?)2 zZ?#WtqL-p;PwE@n#!?n1f<`|+g+zU%3ad@6&1}~h7}*RKx<%~M6RN0mw|-e}%<XZ=Cahac!_ij_$S-4bFJ?kBDE&d<5U&n$(PTb3YN-JJyoz!dKBJ$9e6Lb z`aiXQ<|nBxv>-a{|7AD3 z!GuZV&BeiCCxX_H>Qv$(9(hq?&sNb=X2G_M8b5s}0wZ`utmx39n&e#}Xm^NXNm7NX z=Pvxq@VIMPY(nj7{0&E`tz#>Cg)z)i+1i`!ac{2%v@8;B$fErFf3vs#=Uhir*@}Yj zlLL|esoNy}cLwl(&UH?XIu2%5|7EhvQqr>7U`6)I_8AfihjGqlmj=JcGvgXXwL+>T zk--xSXo4^dGY=h$r;-zE$ouvRNz9~_danfx6N>vM3i21l&6zvbzWWq>!rQ<9;6_tFxa{Y^F((3Uoa8X@&iye*m??OekF)P|{ zL?WE(@2nT;V#64-ENV)-niAuBX>mwga}wt!p-$1^R9-CTY376+Nzpc+(t{BVp#eid zIrZV#C+FPWBasdIvcfsJV`Pz2tZ8%mObjO zsTScS5yhO;joKw2^E(w%{K=9-_9vnT*d@Yhbw^b6JzWg?A|A$BWtPUwC0F`VYh$t+ zk4S}bsZTtO00B_zyb<8XOD#8_C=VxNi^d&!yVB#>+irHEhEFJ6p!HOU-UK&)24dzy$EZ&ZJ`W?^QpcZtQswrs2>E zx1iyPTJgiZUo+sv3PqDOy>%s25tyLc zUQfPSi?IUy6wRM}siT2o+4~g=A1Gvh(ey*t7`|x}lKJRko%$({WAR8u6kNbR&_iZa zcg-%Kut@ZMP4OJ|hf;U*v-`=61aanBjRS)&|0tSf$hKC5rXiEh1yZ9tE1CTg*O07! zl~I->=vQsRtl0M-7Eu+S^zV9eOYwT!D_~eF7t^T#VAK8H#O3`nwPeYf&8oMc4knT{ z?wBXx;FCACUbrXd+o(PDavY3zPA$F~To){jMo%d(nU=?h^wGhmdvnNu*Y2b2>>59H zjMg^Hn`8lKj1oe^67TU_zb7;4tdoH~Js$p`if!+DdPUiAB;bv-*nrdBoQ_M9Ia!Eo zp}2W~kgJsfZYS8c#8eQ}+g5KSwXR1SM7-5(AbbX3vNvRu<8Kz6+6vm3h1&GCscl?O zYe%2BaPpL>IC?X@FruF@!_YvL1s4m-g$`!AjYNs7vnP_d`2iYB?~D_o{wbKsUyz<9kcglhG^v8N<4bggAZyydvg8I_FX4H;QG6R4+kZD0 zBp3og&-|{MXlOQ0zI>hdh6cM>JFPldF(a_SwC^cZIQ^U|2sG1cCX#U zcly3J>OQ=@>*=OHQOHvCZu|xM@4cmeo6B%Ca&Y{2&Jt(s1N*>Fy&pN^e{(ti#{qgq z4mt*UmInXja;{RfvRVJx(CPdLS8Klv3WX1eZ6U2X@I|VW@U_S&l*1x0z(cCgCF+Sa zRQbGqPBY+QFI;n8szP@6oX#{c&c>L5zOYm>jj%+J!S=Xf#_`_cOVanL%Y>3=Nq8a8 z+7LsJ3+YLN5Huw7rcWp#w9Owe+6w`!x^Sb^-!uuW?z+>G&u~1|6x_>h;q<-;G~^u) zQyqkv2QCS_%n~;WvH2hs>OV9%n7KkM=WsHo7{6lWg~hDdByr*;qrg)j)<>uc+@Q{+ z4?G_cJCIQ@%fe|*9QOb4-J_4fCU7bC))k4lKp)tCAH(Sr`QnpA5>^YWzJ86KLWij* z;+H_6`5;E1r73`y){om<`^5`ldvt%3-DcO{`}itPO)=aRB)W~(JQwW55Tvb_jMNS< zy$?c5!a8ZB>w#JQLS8~P0MS3_A_xrRE$Q%MH>uY--n1#ro=#f%5ab`77ymX2OYTQz zKQE@g9!vizB@_GJOo!IBLOkql&r6^cj9nGlbcTx2|L8Ig>0NnfsQE!m>j}enLm#d;P9z0dg1iZNi`%-2lF37Fg+S`h zI2@Z!YpIP=?9M*L9xg!Fc04({5Vcoi%f4p2a7-P^KIKpScdzv#ZfQY^G30o;$=o#X zaTHzqRI5tDgpGZ%lnHwa{Y_{lf4g>P2|8hsAFTs;Vs>VDd6pidxIDd8Gs)y^H@H!T zNPtNS6SGh!`i=7@w^tTCxjHS^WcD%P_hzdK&67 z0jx!Fzc_9nef@hFzMsHpN#gNOg7u=d{6i#OU>Or@qeL@qVd_59!hBU-(cF;js!;;Q z&|)N2S3w%tB3^oYS6vxP?udMmd#*1hwt*Kbs}m`Lu|~RHq)0L^_98|RTPK**{~+ug zyEB2Jtijl>m=)W$ZQHi3iYvBl+qP|0Y&%b!Nl&kt^>+7~o-gMooV)Kn8w_g0S2ZL) z9C3C*_4$s2ZBt=U;z2du*w64}8Vx1KLutS3jFU<8(R{Q>%`NkEAD>`t=jLBr#spS7 z$|bo~gxNL4W|QdOlG)cHo;Tm8qnvkMp# z0>z4&l6Z@&FR39X@|}ussau#-afeld_XQ2yTbDOBty=*AL<9uH*qE4DTW>B`+*P!J z2Mcf2e9{S>xW8eCyyO1-9V+>?`;4iyb|2k%Xigub=l`_E`|B6cBfMP<2;`EV@zr9u zd3gqwEjQP9TB)&&?R{p^@Sm2bZ39npFEA4ILT-BRK+SUs2(t@bJin?u0rmF~%`<=( zB|kNA#p%v-uLBl29sZ<-;%X???{z&iQ?D5e>dHBHY9=|>lbIL`*k)(8Js6$RUIQo? zqd1S|3RF*ddt)wec7n6V@Wt3iPjA>pRbXJX8z8$lYDmQKM#9$rndMv&W8venoS)9C9 zAAIp~r-5)1{1gk*fouVkdyhl3$U3&|ELa)L7m8;!qKr@rN&*Q_ArwWH@Oi97Ow9HD zqJew-Q@syJc!=usOl#n_U1(54^K^L99f>JV399~PSdMKGR8aH! zDoL?tI~<*hN3sLX4BzLawlqaT_K4e364FQ+i#KBr{ib1J17jML#K@0 zxfe|F_w|HFw_C}{lRiyJHdZ2A;6M-PA-a9+A z3kI*)JK`Y@6dt3ubVH4CR%O=Iis3Z6V>)?iOl1thiY@Kb>!F}4qiv0~hYvl_LQNR@ zof22S*oIAd87l=^cq4ywsMel6LAef}1GfwEt{KY!R1o;($M1P2tZaEbeq44#L?%H-ruU(N^t!oRuyiV*f)^5S@MJQrCpiuZJq{ig5mPZ`yS4PRQOkJ9(;J z@%~wIoXuM;zh*z)UW-aS@6nLX9CA%qNwUwc<}R+!utU%NubsUa-~O$OGi8_XuIm)9 z;HK0U*s+bIt}!%Ucis*k$?cJb$&|C~s`T3Bh?q9jR2}BQr!GD-niGC38>`6W4LYGXU>$OdA!SBq{9{O>_aJmPDE^KfSOSq2&mD~py-FzUw@Bem!+ZJp;`2`IG^nm(P%J%>DRr^mg;Ob(bZ{lR>X8M0d zsuXM3I&Vn)0D?EP?rkX$gb@@r%>5^|@w~N)!QDg=T=j$k2+Lqq;P8atUpu;A@2-F- zkTp3v_Y*2&#zp$s#Vuyu!Mz^f_unf=TPzca-s$YZxVwxBph)JNumW9jgG}QKLeg+U zz9<1(!Iif}srnXWxu}K^U&4wLrt?7TKY~CX3(T;hJDf<9$}pbvon!^ri#aCQ3m|^3 zXoAzgZVjMGjJQdmV*t~>;~T&v3Dq=bY9$y}1iQZ@F0M$y77)N zZ0v8&dIt&hB#qQQ393mUFi~n7Y@{)?yMuY(u=6Dar%{3<)^R9Ioa%hgo1} z*_?SB(m0Cpt1-o?6EzJQDhWw~ybyCPhv5d6h(G`+%!k!F* zwBiKMf3#LyCL_z?Uf40N7jPs%UnELUr6lCdzcZVL@US^$r54dp)s!>k9DxgY{z)%N z5YoaLV;NACTn?H`(WDd&vv)L?K<(`a^xUBTl^_3>~o$a z?_YZupUSx^yvLtiFVuF}*7uIN8C(MeoO_)X@Ve}-7xuaOz|EHNXTklO7X_Vzh#CRL z!s<}B`;*Y$)?brrHSj{K!>RX;(z|hTJqK^Mex%Kgna|C1kFLAnVCx;QnG0u&SVO-3 zwC4Wj1zx9@ziErwd`<-J6eG)hh63n&0Uu$U+#XLJvvAyYz~TD0+Plvwh5eZOu9qCY zMO+8>g8pApF_d@&oLzlx-&DOU0K!5;_hu;D1-E~09+KQZUrz%)Zi%8dc0u-wLB`v! z*><8wOjLiTYe+i=Xxui;SV*w+s+SnR%oX<+CEO^Vxcxpi{Nt~+OZ;ksQwQvwS@Irf zL6Nn91JA^ZKD^j-lOrdeAVZ-#HY-Gq-2>#sk-yR1+6~foyFM(t#|!~5jjjeh za0dKqDI&F)vj&kgQCX4s-g{AR2-7j+bI}*vQG?Gqxh6VCA0uM3ze?nn1J{-=)CAc% zdUt!ky>Ahw;l`p;Mhk9rb%k;Jzl!AqlwI*J$wvqzvFTRYqQ5kg6cbo)z6L@d!`}bZ zI5-xY>QpA4#_STMQ%cglsP2lP@uBOKwhfDL2Rdt-RVqQ-kpRl**>0X@{67^_30 z`H8T|%ZFTyu1i2qe4H4Iaf2)|@2Txv*2?dlhG7=(4M|JaOj0I0-&e{FclCm~FR{xt z@No6fogaj6er5IZ!vj57k2Y<<`;4sAi_SjF+%_)%B8zpOGWHTv8yi%N#TRk`=au&o zPr18F;$rqmK}6rR6BPk{H}YbBu2Y!J8@3_n|GkGeN{)luu*gLiiDyWKt8@!!a~;ST zcvcJp*62p(rL`tIqa0T3>_;!qq&I>UN0uJJHpazg7PfRVpDHrF^PwPaaaph>poC31 zy_cv&YZRM}(j0`*o_ZU)Y?vLp9D2NL86ftWDY~S99d(SHci$(@IcpMDem}gcTQ-B` zy(rr>@a%UY&qt$%#glf(i;d~zO%D4dwh3RIbH8pDrO09om;W~=>B!DBzw)KE6M3}I z7QfNNx`btFMN+*!-7$EO12t=qLVFf{VV5eykUrChKOH@R%UL!V{c?x3?$rrR7K5p} zFvT&KG`^m0NM~h$JARO_rSUZ>!zkOiGIbt5vMT@s+~-da$`?2!;P%Y8WA#t;0OiDF zt)!-P^XALZX32ByC18>I+lXuEX`3mwGc-UgniS95Dp=ysIVuz6&kcZpkMai1At0G8 z11{{6P+ZT$N&|zVP|qT5iey<@g8rgO;+XRJiXt;*93_@$QOO7^H{jLdO^+r)0#C$a zWmhzIN=S1~(z4ks%14jVLUdR2kWN#gOcRD82U|h;1}Osm&Z1Axvv)K=(0~!&eeV(u zK_Ofm$gCYTciAQ2BO zuxQ}7u+}>d+2hOnqNobK1HFW|XZ&_bcgyH|ycU9{d~&PA;I{(~xF`MSnXI?t2@|)z zp-^Y6{Bv}{Qk>{Oh;auT7RlCvA=qQpIhC~;qHD-+ZqUx{<5x<(SZFoQ z_})3}Pk=-!o#p^{$g@817uK*Yk7R_>X|EVkDx27JP2uM2xWt9x7;*2tD_9hOiaZLa!%FBa| zcV|hwFAu~L!QBA9(2un2DCxn3uIywE4?<`f@Zr zwulP!ZnAy_yN&iEHvgDwMEVt5-t1To2S>K1#6zwnj8B8?(>7O-ksf6>QkDD*c&8%& z%4OdYJ*8nOs)xM+NzLdu@qGH{W7_)w(hSvjL?Xym`{C?gxSLF0Q zYerrW(2k@HOc#TDv+H3we8FJbW@TtsH2yInrJJoe_+hAO=2gr`-g2 z>x=3!N#3$dud}xMG%Fxb85xu}5M7e%^fg{Vbe&vsTutq^DU&7Ljz**#*^7y@72Pg? zgpUzrrQE5wxm1miHPF91XcJzF^J?L~`P+(zY5|XNSpMcq{!gEvYUhYQ*{6x$ok+XK^p$=U&@4yT8|!hw{$Z0e)fqt{2-E{Qtw({3jQ_hdmqA^h326 z{^XHU{;vSb*wVqm)aidhtSfG7=S7K@+`C$iL6tzftg!4preK954kE|udS_e6lu0Ez zQL9l9&3g%_-<_G?ezTlgw9O`*ju2*T1Z=8Mn&*5se6f7hTh%Z&0SD8iMA)72?z9DX zkOcFK=wpx!(8LlYAT=VtiDnfC3ER_QSs#abo^>p)`m|42Q1s6fHzTu=LfIXO%pCE! z0vdy2-KmpxGw%L|1wUktb!Lz$xLVEq+qAYhIP&anUtQB@B+%+XMDa|G9D)U{1I0kE2crMOp(7HrOP;D{AkIGYE8z2-R9WEp^xGjGDM|Cx>(^{O zv>4u{M4yfbGreRm>;r{}*d1B=2K1x}%A4QIGHgvBH0WxfB%@%yCv$w)Qj=gn2j)OH z*(9_sZr9&mCY1H@Iv_Usp{tKl;SvKsjEl1f9;6533sg*=$=~#T9@W2#ceeJSUb?a{ z1uR1al7ePi;0dWp#N?$Uyjj@LzlotyYwb>H%!njxs#|qcB-7&Jr!T>5XPysKo>8Ev zV@|NMFlnBHM;|OD3}(UN#Q>ycAwDJt8uWT7)_S1OJW)m@M-X)2>8K58flxX=RAXLo zO`2&?aVWxzF5uO;qUT^cQdq-#B(G8_`BU)w?G9sW4khAhnDOc03%mPkhZZg?SOaz6 zW{*9rbwD?>ke}|^zb?RH_;;mYf6^}ygJ#awp=RE;epxdFtKER*K8pp-+zprUW1^&u zRujtkP2Fg9BN}`j_!z*4%@GKkTzR$z-6HkpE#tUW5k{1*Uh8GKc$K;eV9s5{LP@kf zv@j3E7y4x@($5Be;dofXZSTR_#)OXSTL4lZA zfG~6RFVuBKM%9U+PsTa6)A`tPCi19r85=*HE7@_~ zq6u66j^;4qggIWGkS}IZKSbXe*Yha%C@l!$>iwR3oSPXTU%4Bmyi}!H%|B6ddL7_E zc4U$(QEY3=n8A=_jY)XbfR{9wEXPx$`j8Qs=MW?B{W~fNEJpJI4LUJ90v9Am0w!#R zpb+@s#F!3+;)Es+!W*%kKbbE-S4yAI9(8@Dp!VmNSiD1mz!0O(_8(@n84Rz{M8;r4 z8{`1z!FsPf4x(ohR2Q3_*y6LTQO$rprag)gvdF&pfW%*PS)-OAGA+0`;ldq6+&N79 z&9@thCOcJ2vQ%4KD)@T@nq(P2nqY7+25|`4BEKc*74Bz`NwSpwS*9hBslN~*BNCg! z*IDr82L*dd6Kzfa(+9>}44Jm0+?C{1(5tQzwbY6%r*9zJ7o*506`a{HC#7%PzN$%q;{PTH+^Z#cRnWtKaSxv`?P(O4mn^$4S zyu^Vd+dTn&8>(&W!+4;Wb{MPu5mtUj1cODR3LwKbLKpgtXeky<1EMHpr0_D9U9BP@;-Y|4-rjIhTr5POY} z%)No?B|_us4>cm^AVsQCA2%UhSQZrN#GyEZcNidARfm8sEL2jUH!NuWwQZH4waW0I z^*Cd0gyT^mEQqy~C6`w}QX@h%`Z&^&0|Pj;sQKjghfPe3iiK1%R*I}DlOK17)A{c! zyqj8nzXUdQoqh+f?npa;LhnQ-&CXosQYwRpo4fwd^k@)9F4CW-qi%a|Z`TgCmyN>< zK7GWOx2W3L*SFS=oQFXF?-BLP+EgFcm-BnoTi1dU7EJk|yZ;N37`RK%bP@__Y}Iz)M$o+EnLAAPN>nCD2!Rlah+KXOBioX;cY+B1_b@X~73F z%ie(RBSRnzrIhYD655!&{HFb=e=8px_qTQQ4x;v!Vt~ab`PPxVN&i?H9Qx@QsHVi# zK}&+?*py%?vYn`A@1d~@MZ0%bL)1n``qc)KCDsyxY@xnAHjJI^04(}ro@eNW43oVo z*+D2*X!*30=I%rrCWJIvFdQ3G^{_&7l9@BF7CIywUJST*69VvkGX6I?u{EU$oxLO9 z(fZWK#MwlKQ+$hv#_$$ISbh!5a8g;PdsLI2RCr>uIi+_^oRahPF1!FGjndRWkKiYBJqcB2boj4D^ zcawkRr_nItH?X|Dd;!fUk;6z&UUkc7NmV4(I=;elL%aK}(AC$_qQhRNi`G!6=ZmTx z7^%K+b9d5((EQ3g{`a`Z^qP_~=a-mGRXSHO@E^=t2Ie&feW%%>bwAk)gZE}?Bl7#> z`%4tQ;dCzmq-t(XB;||*I+88o3Y(HBpwe}6DBeFnA;t67E_U>q3L~Uq61Qt zyV=8u&W3V-adCBl=bPK%;J=j$>NAxmF4{Iv`RU%Sjm(gpb4b1M4{e{o(+5?cbw-&x zahzV|eW#r$m$q)oBvsKK=H_9C*@q(213FjPOmA5vw3_z_V#c{^IrKW|&*R5w=h5RU zY3(i%Glwe%Ms}n14$TkcMbtn23%8N;3Z34Z-$&7|zCihl7jyZUcXz{?HOqs|3p_8^ zCEhJF7q{&_U6{_c;MbwV4DAyShqnS?k05(eKHdZm#C*%kkt6q!wB`XuFb=Zz`8dpm zp4Y9h(I@{*63X>9Otl`~{zx_?H~A|l>ZY?|{CLxU%jT8&w|gyl31TQ5=bPB&WzFGt z;tQj_yq_sAsEEF*(IY@&NyH zN`keBBq65c-B&W3`Ya~W1Fh5=!&3Qe7vz!#gdVp91CiIS2k6Ewb08U ztto~)Q2+}u>KzyZ7d==t9e7e}kPm^4R5`9AdASwLe1%CMX9DWFuw~@Xb3@jb7GpXW z>_F{q*dDGBS4UI;hm=ZFl%phhPVEzdUKMFrqz-Zwx``Ry#43c{GgOY%!M=NiW0`qR zLH~vgspJd`+}WW(40bfKz#E#YlT9M`c%rcJ+te4)ob-J-L}qCaPDEOR+-Qk01gsv? zkUfcwIDTYulbM7>XvR<}+yUz^El-m9UtyaWpQ!J?Es1Zn(^C%jd)4=4BI-a`?k(Q7 ziOn;@P2hYeQC$|22ejB-v1;+yoNBO?%9O(5aTSBX(ZQG#CC%|vU3A(xhusuV^}|Up z7pD^A;}-GTB_lV%jhxx6^D$@n2;mG^a%UKe)bkWo3)8?BZP8%)&XH2*2o) zE+C`N;Ru$(k$yJ%$hGIhDj?!I<3N9~WvT-Ym}qlWk56m_tECD4xy%MjOZxX`3g4s3 zwX5@IKF}G~7i5R{VQemEIxFL-xH7nveLhc8O=#_*v^ z_Hm1{yBTL0di=-0a3!9cn<}-=XJ!bGgKYUrD2$qwmA{%zaby7GESA^eSVA1eSA|%1wW;n~@*!@Ut*RKD=SRb`;Nm3_`b_twR%hU!tzDQzn zjIA&bXFZ`no9aPKY+OKQMqd0$3-n(&s-rFC)vqFEaQF9S#J%guzvrWCZ?Gvpkk2jH zl7(+4{hcGDtRfqLIw5@X=FIMiJuA2NK&(OheN_A4z$ds@yQ5S-_NGnB*rp)~)`dYz zUE(08pzns#K6Y%~i-PMgYZ^&45Rl$V6`+?WJBE!GzmdM*+zAhAuQ zGh<5EE{72poniT94AOQ%g?@Y0vP|t8;_#b9iXJuy#vhI9579a9_^>sQJp`i zSD=jgG+a56_5iFCy9yNeu zeZ=u9D$Qe!S^iRluhRTb(cJm@yc2fdY|VhLWt*I9?Hq=ol7q&A(3#P;N$@njEUIpCaoLzDk)vb*6%-z44r8-pSF$n9n!X22}oo#-NR8%byDV&U@v&A{5h zoH+4wD@7|sWx(#5_FFT&*{jiM9w z%)Kx|GK%7F*?>fN`vPTIzA2 zOwlmD;*kU|Y50R&m>{G9UB@w`Dz+R{F8ga-fH|}ni;0U_v%)yZDn^7U1)zeZ*&dKq z|0e>TmQ&SG$`t(~@E1|+SZAHC!@K!*^O?qX zN+Sl=tTw2UceY+0Qg6p`Tz1`MzOBl{>;|HWzZQ4WHUH+1ujg{}JOPBmRF1he-NK@^ zJ0xDGyB*NmAH5x7a^3fZXNAQJ9ID3_(#P4|1*Z)R59^!_-OWx#!daWzu)VQytWcJ{ z2^XGD-qQ>O9r&!u9&6yei#5AW>y1>k(ojwVojN{kUc`T}jhn@36|OdfVyT{e4pxRW z$Cj%L^GNoiZdEPjaqU}^c2J~D;puMh4z*P+vKTA5=mSjIIK<8uTHm;NC@}fPdKo7v zfr{%TWqpWt%HF#gsY$#E`v`Knv(FGY;3uDcVM=85HAg-zn<<-tb~~z<@H&%y9699! zg&0K$!ydj|KXOpy#b=sPEFDj`UUgD>j8E$#=tS1}jzXv#0IH2i)y=;+{e9u9FyK`T z^crrFI-}{SzmD;JEvc(RWn-nOpg*^*F6&(F?iSGnKF*F7UFjo3t`=#o76d-i9VTCB!DiI>gfBVZW!6*YGGI&S1#vIyO-n z^Sh6S;y@#0tp~1%^JQ)BElupJt?hm60yR&EkBrz)up^pjS8jQ zHc+a4Bzih<1QEJDW|I110~_T@O1-UUlTwGYhXyt+2@V;hTP)0$y7oF(^xj@DFP!Vz zo(Dc;L0Q4V)M2v0erX+f#51wu&8(VOnQq2H)jahr=sFcLgpsX$E47VzYdL=ijW)15 zUrTwr-K7zJ7ze{xvqBqV`JB2g&jQ~{95DC!&K%s_*6G$*@A4Lh?DeO&O$Ez$l+ClD zz3je40Aq7vA4Y|H?1@uO1p;?OoijC|9gkNGsRL+F>+M_3JP)>%N1pYxAPjlldETXA zQ11|QAoCquZ`yT>OcPWz@Gt#vi|H5a)MoheMS;Ju%YSe0=7r_Z9fs3&%95?=)H|+& z50Od7Nuxe?^;t+j_z^UMw+k5uZisrC0eUl~qdr*-fS$fmFhMHTAWJ*Z&i zkt>Ok#=qlEu=V*>bpXre=5~<~0k8IZC8^HIhzii97`2|KgIL?&0g4uSfyKglfnTaA3D-5pdNcsdjioQz|saQAp{bc-hwr}d92 zK=dg9HM1x3KF{ava`LhKwA*@wg|)!%fimprSo#2Jql45xPeVo>9-*BhTGR$)2VPAuV`)S$hwdNeRPy4(ntWb$1VE?7<-nyQW) zGm5wg1W?&n4V@2?n@=5K&#jJ-FvO%h=7uH(bn$yeCmndj)rz3MFr-J46;+i>^J1+e zf2V&8SgPG#WzX6KcFEqdWHQ+QvRgl-Sec9Io$%?d6*oSDudF$tI{P)0#kGChJP2>Q zPgWY;%6VlVoX#>`k>7O}B9#0YPXO_iR!#7ru(H(PRp@#9HMlog*!x}x zr0?)0o7-%3zTx|nDC2#F>(GqdiMonYy0YC@%#BO5 za6QYr0}qiF3|u++Ha+tSRVpu=VrY7U@z|kH(}pjsC8_z<`GB(7s{?sGLsf@!E~`tP zvg-v4mP|;<8&v|5cx>Uwz|+C7!NFL9*qDwjp?7RXkqHOw^R>W_dJ{?nf7c)nq~*Vg zX(pIc$H`$ts@97XRG5{UJgZ2gYo(`^9eIHpq?n9ST98^MyeUWu;iya{AqP96lqBb{ zx&w8JLA?}LF!d6|{C#|*Ro zV}>F4U%`*5o!kE*wN6&swA&Oz@{Q>+%FFwcG?t1gh`(O~BwAApPNGCg$qfMlh1%YP zQ7jRFfg?8Wf0It?T2ITr6p+1qJ(bREZszWCS1z6_aTI&Ph~BlG!c|L6m61WDm8w;& zQemsOqH?IhPoc%mCA}t^D%zvyxy8vfUnpmRFE8~plxwRy3=Tf4TFtin*91S;_`Sfr ze}y1QwBDEQ=~GxX$U~x6U(b(oFxURZBO%$;WQv-hLglp#rE#{mN6JMt)oW`Bo2QT` zzeK6Xxgw$@DtTS=f`=-Xl2$6zci{;Xt@xE-ooS*(!lmNiFQXW0azsnTztaviXcx*j z0`w>XvD!*H|G2*ow~!t)z$yT=H;AzAmPeWCzIB!NLdJxG)Xf!`bxY zi*Y5}Q^+&C^^1Fn8?A!BEfe#(8 z))(ThO+@;Bufk%Pkex6Eo1R9?oVMm1>MrWMJfjj+*Jq92&IEU*7Ii$ zZAk4&WA^@wLNh8z@k5AP?0X_8njmdR4QlA2(F3<8*3xfJE25Y2*#48)NB_mM|GsPF0TvHV`vAe9|D zek)~i4t0h)bA%6Rc9uhKphgkvi=8g7Wd*dA-eXj(%wu0ZqiRHBqX8#hxL!Md*=lif zgn6`d=zlW&i)`otT^Pdtf=kPMHi=~dQ$f3`#HJMDTq%i`1~20A^+6K6N|VBVh?~eI zj6TiX`vxkLx#ps}#}{wXfwgtu4B1Kf4tJ&><>6yLF#Cfm@@xoHUBHCacvArqi(bs|9+&@)-nRivrE^`H- zUPz*33z|A($rK&PDITmOv`Hma$q8M*c`;DYE{bQ&lcjCf5!IQe!`v{SK4Xh{s>Xk(-D6aC0gt7Hs3+V3 z3O0sNSl(pco^H>6wN@4k@nmz92qc7(A`FMv`p;UuZV;NHfIk9x`d~y0{+CdkA82xb z@|d%xG9#b##hVFZARK+@qatQ_O+B z@X{!WP6wuZaG|~d<7sm#qg$jVTcZh{g8`$m;zIr(YgLXYvYzTc)@r=9V6u_Lw8rhA zlCo@_wq?=12)~p0(v_GMC6OJQht%~z;3iEawp{sDRABx=;*B2IYKr-<8uA?PqsJ@0 z>>Y!}k{s^#yR3eOynOES%^dlaw%BFIUCxumz9*m1^+q3#n{-}lAK~ZJaPxP*c6`p% z#CT91u-huf-8H^LEP&Wz4>P_C6ef!sCxDU2f zg_Vnk)r7IF@S?AknJo{zAk|^mXcJLA!nGt6*Yjd>f_ndJ^jtN~vmR}QN1Sx_X>qLB zT}3C7mwo$3yQ`*a$Lcb=l$r(G@TUIfj9JDuw&XUuBP=Sg+fet9o$DoTvsN{LDO^-Y z_+lc5Fdf#M0jK5ma^5>#)H3|_jXLK@WZV6uw|V%59N(%{sWVco6apx~n;r~AU?99U=P`div%jsJ2Skli zepa1Q3Z@HI;xZe+97_8J##hP@dtIjD4+i*2yz`Bx|cyztoujBanw2f zTo)p!Dmr$*d1;3ncH5gjiDu2J8B!fs-Db?1a~lU?t+aGLiQUcU1*-7fCC+N2DG1HB zY&OBa8SoB{do}DB+@POqJxoC9x^gXNZ+~IA$-AB@fI@e}Kr(`RpgNM{Mr>3OQ5r z_ghg(7Y^g}w^cz+o%|9Hx|STj(mnwv6@o9lIkY3h5H@kQh&SV=@pnZ+LdT^;*EjK+ zB&i4!$? zFn+g+am{o5SYxHAImRc5S&RSeby+;+m-WK|0xIPF|MNsRTNpC_&$p#G)7l<)wEI|J zJhvb=(E0ZngOckOH5Y<_bd#t6dNYaX=qbQx$RCGJ<)VB(slg zeNi{{`>1{CM}6VRz=M@?bKs#?gU-KNS(*;}sfDZN+K#=V9_HrBn$@-Oz3B0IHu>^U z0QW8*W`Dn`{*>x>Hf)qmAC{<}TItpE4+nw%UYU;H`*v5;e;;v?HkH7?TkGS|kCkU4 z7Ls!4h5XAD;Ksv!>HoqY1E3G9?5I-bUuDw0`Nmys(5R_FKU=hN^kf{0Wb)BkF?3|4 zq372<;?k9jjP!W2*7qfNP8~k~>=S$Qr{}MJqc}-5ok!<M%+CsPiIF|EOe|2}4ZnrJ?h~zCRMxd<;ubuJX9J1Y}spErVX2PYpn9oYQPJ<>45pGp{U53Z@_PQdC+5c~(^Fo_9r3@$R zA8hnJ6o6DuYrY|wtYhtGtE zjAPs1*~`O0$YZ<9fjxxGH_PHRD94f2RFu{+(oygXhHZL#;~r`!WWMgY&ZBh=eM_QjU)wfQ@M z??3!lN&@de_gaKDzki@SqPE{$4CG+9!)G6IW~4c#jnfGB2t9tjFHilM7?7Wfg?w}F zVdRjDT+gwH@^8Fh7vsH~=Ev@f&)&^-El;tHf!mq)+_-+Mm%Se;hI-G2H8-UcatO87 z77@FV>Z{Nm9cDjNe{7_h6^`DOzqiAPUJuvD+vPH-mi^1YK9TdjB0+Dhjk}a^wdT1Mrn1Rm27K7ZgM`~ZwEK&+1*}c5z)`@p(_Lh!Z}2#zJpCo&hoQdDOi<8DDLh*yc^$^3m<& zx{C2lI%>|U4f3zumqs4#m%<`d45{+GE70d4=6>I-C+_VpdV=5vbWC~4tX(SCCAy7MmW8y#sH<{pH3XMW$kdQr@|WBFIOt1*4=B$_|$m<>LM z`@Qg3ESCAMy}2v6xpv299{IA-1YJd(Cq}*jmX9YMAbYnuPhNu{0R)+-OUF_t;@8@G z)qFY2m6eU8HULY{mbZ^_jfukdAl|dsTwfjCD|p1O+prm#n}g-sL*LJL&DfRcW$*P~ ze{X{K?JIUHKc3~e&$H6?omGuc`q0f{o*l0X8iht^wG)C;7_YwJO>WFf9wPYr!lV7~ zrAasYomc{ZAiAvwi}!Kl-gM_`ErI-1wBDObNY^_}*INv*&CqXk~kXsh$*8U4?_pup$X3b|8b!$to0LF8*`Z)-;^^7O6wAnv4Xox}TNhh+(H zDdYY5jn7PPuD)11HT;X$La;w@Pabx>Fu-pGar4kHwKwQ$2*S<7QYUE5A?O|T_pbegICTh zzaM__>!&xb8gG!qU*Nk(QWTdB(ufbEWqjUC8^7E8*~^aQO0NKdjGXs}+uX@--@7_u zO7_{zC!595*qX?b(9#wbhuqKC73hZ}P7!c7y;;DG?8~bhH>DnR-X5S~ebWTf@1nd* zbL~cC_uK!QJ@I3v=KGWP8v%C+kzdy?tpIee8SeClrwg71Q`4%lGjI?(!AWVWwa*zN zxcSFAjz-(|vZ*G@Fb!*AcdWl?hdv06c+KDS! zW4L#IYqbOwo;!OFj{NT9AdJf=QfXkBPlw;%`(Hqsx3h;6mk3CsmhZ)g`h32EnJz7CT#}7YBg&~MRwbSpzogA!;|U*wu)OsxtR{YXT)+>ch2U;6+Vjv1tis>n*P$ zQHx9P##tUr8c5E%VQ4v-sWC1z>h8hT!>ClOR>n5K3|m!7@MRU~S{r;p-BOlM#Z5)X zl$B0U&5{d)%R3ZVw@3G*!)I_xohYMOv}v7cY9MS|?FZtw!!)f_#V!I>RMID0|H0V@ z#*McZ6|u@nEDK3#f@khy23f_chNx6*ZVNYlU?V@AHbM`J9TmWppJ|pj(=4+nmk|{# z3EA`)FBpv(OK`Rh;oHh=y6>5nBlJv|j54Apk4z=1otd#SN0T%cQw1wh#THa#odTVK z-7yzO*d$MRB|dWh3elXw>+WMpd`hlyDy%9w)p{_a5?5`bvM>`6Ow5Q2sp$8ZKYi3F zW>8G2E94Yoob)e~i)wBw5XTBiVw>QgQoOP;ms=yNaxQFd?4zmy6jT=CW& z(OryglxqcFgAH_i;_EM%2gHl?W^aA@l#){ym zN`a|AwOAuABzf}7gfjfR6&jVU5#NIGJq_dtrE;2Bk*sKY92JOK1R(gocrI565}2Xv5@0yhS@OT{g3THl~JvmjZ-NwTwJEP^P%ACR52s#!6g1t`e*5 zcuHYFIlKd!5hj_Lc8goic|M(SVtVLOqJsu@y+ovuAfGUQDlOPiYT-kxxfnP170r+mI7W7tUy1L^yh@PlEEc=5C z5?7!;MdZj$LLS_rRuTtXAQG%r3{oV@6r#8veXlVzJxDHJIb*qALMw{~<5Wg^Qp1m$ zC2GZ;0-ns07oEQJx2SDlkP^|FfG&Fn3Q{E2D}y!hnJy_LlMv*v1TvL+7Xh(IJ}Bm< zNQLFUdUJMa`dWeLsYm2uVqaJR5KIzp@p^|BVW7(Yi?DMF&NS-U^c&l@ZQHhOn;my- z+qP}nww-irCmsC#)znN))mKxq&!3}xu%BA%zOO63sjbOJ!l(%+V7fi+0-}~!u&ILsI zlei*>duFan6s@AjXg;kgaF>)uGcX-#P=pB@I{8jZBv$|X1?I3~gcc-CplB^JSS1XS zS(1C@B(UTdKu^b*alLyn4@BL?fJ1gohiL*k(FegB+6np zb%vn8i*i-XT18!QLUMMkgj4S79)1XAtCXiwLy|=5aik zgsczNa$gW&^nHD^489%d#e1M|d;=gFHLwJ#@q1lS#p*R-b{4U);N_aOOh~Wlgaqu{5?88oE{;@O2$oA|c%rt)> zTrf!He7UY@=S%9fSGqP9td(%DG;!5O_46;P2eKCW8MTRt6eaKGc*(A zv_u1m;IEiC>_LtRQ)+J7=oxpBb1Akrz0BrFTXb0>qaiotltS#*twvFrU?+8v6%t_P zni6Tqeq~+>&}WkQi!Mtnfifk(>GJrP{i*A7p#7t+JASb&N(@7Um5yek zxiFzZgCufnvj+}I0exT&qaPbekSYqkQynu^K%#d0Q|!=&uo(y6|z4+ z6A)cVE8arzE@Wo;!u^-4=sS6U0RXR6wRzJ`4rvho5+AeTGr0@&5dGP5Z|bTrF;8z+ ztUQ&_KhPa1k+50t%lQCH4t8CJYCELLw*$S1tJXh6ZKLFRPVi6n%+f(xw3(IQnTcwe z98iM9Y*fpt_aewBGErX5!BCkHh^9uR1(mo}$rHb9qybu@pGD7-lF9AP!Sk5i(_Mtt zH%^P|&y05FSrQzs;g-qZC%r&w9lv2|a^S{akYpBt=hx?D2jc)hc8iA4qzTy-Q?*1? za988udzVhGUmhZbZb%!J0F65_e)}4hOm7y%$k_v-0(MredMO4pUD9;Td6iZ`^!jvp z1p4GG@c=43kWL&y>0d8FmJyO6PJsv^QfoQg06IVm0Va?${>Y?TH{GZiB9k3QH{<$f zCFtG+Hx+93=#$j6h=X^t1b9P2AL^zg_88OoE;DvRTEiBY;pD$3jevhRzg*P^?75N9l; zp1AMNdF-};VK<+=K?BQZj)frkKAY?^IJ#m_f{Y4vN}hn0I@TGSKUd9UzOBF8G75*3 zoE?BnXDkLMG`2`6X-ewwr5L{3)WerJBlNpy9%`SixPO}sv>IXyNG*k8EF{$F@g)Y% zZ$4uJzzq&hk(%=xrh4PA4CVvd4f8a#fxAv*y>O|YD~)7N?IzOh8FCpOzxqp3C=x)0 z)#bvNRdU;vUNpGhu%#XxlK_{Fld5ZYaBF6^f*W5W4(uscT|5p)F}hl;#L8M2k7w?R z6Ia!1iCGew0F53LwuFLOUkjvaq%pl1D=Q>gp42q%wIUzaUn}H{)xQ*&R~zFooK!C0 z12z*vb(;28RcwHbwTuTQBswk#yeUXaSzL=1RxE}`9&~w|%MBK;T}L+=Y2iggAkzQ2 z&>+FO(RB%zPZ_KM35*F@k7Z02sGnie0uq*fq{$7Ry#sXW#(a$Bs~g=+h`BqIucAJB z7*Ov5LgAPNp9V>CqglPfstl&-7_KBl86t{(3Sx~VblwdR3`lB_K{-?w-9tC7a&<8J z*L8yw+NU{AW`vHFPfF+hV+cuq_C*>=bxQO1aj9EoQUj%LyEs$~`+YX}gy7~z z2#jKNo?2)vm|8IMi3`cmpK{h>$1%~n1CJ1?_q zC#$u{QpM_vNFm&@y+>ejN@(c@ibj}i=7lQpgwv!(;D2l!nXm@r4R127ClM9Tt!45T zb|?c0fO;|<24tb7cf6Rb8ZoJev#G{45>Ut!n*z0V11!BxT2x+o36ue-oWG|-L6-~s zzwu(4X8-tFjvg0I0{2L5GX`Q!{3(aS_)WK}h&DKTl1=HXD=adK1@+5lG}4XbMsAR5 z9%AqgQi*btRT>wE)buA5Dgr4G+hn`tMh->VEWTdr#iU$(aiQKZ@U}uc&M^5GJ<`si z05sBozR3AouH5-2J* zM)*uHXrBvjGS)r&{;VShqqdS7#HsbG9qOGII&{R1dkLBn{jU*9%%=CMW$rhPw36^p zX|iBKdo&8{+jj#EtJYs36Nz*G;d=Ngg~Q=$U1)h#s-c#`FU>8f+0X6Yu%Q=J#?97Atix1(q&Uo z=+Ml{e-R_FJQ8_T+~PnXXw7D$byDDjSptC$e1xN-j+$n}B@)Esf`YX*K)GuO@GuL) zdcrUmB8Vf>jU20x`wjWURIw}a6VxrKugZLxOs7m$kx2@03o77#E0T|LKq*?J~1 zhY<3|4;LfJeivJQA4qS3OG07V>r6AFsFK|;!a++OG8`tl;)Gvq5&=h-*g8o3*Z>j- z=Nc~0m_BqhKC6_!s6Ye0wh_;UxUY_vBZskUv|p*OZG3Xjl?X;7DG;|pBusIlw8S1? zNUr~=elr2Rfc4*vyVJ#}bMcf6*O53>k_@MTovOvN-E3WBp8`TxZ5zgOsBck4iUqs4 zg_Zsqq;~-}R}+e}r6N*#?~7~j<664Vod2rS%rN|2NhPXfc5{KL#N|a+@6IIkG!>nl zUY7?49iyEMuar4R-v0%^D~!IBTI{jLQDaV`-g7z1{zshO$l}~g4xOS}@i>{6v0UY+ zb)jr^0&Qh5xU`j-+IEbTUASIou~Uc`TvtF-@=kzHS+-nsP#Gt)mQiws`zIFxQaPV* zkr={jTBsFGTeUDgmhmLQ*%6b+jfv-Dejue^rG(U^)3^v)sn*hXyXIP5EAc$qvb;vA zT-?S~4fd;gT-v_OoX3h7lewe-&I`NG7?_+I#!mPG8c5FMESC_6+_rXfbeG!1@ULl) zADCJeu&kDxTu$E`@21|K%GtXW)KUd4%`uYAPcQ6u%-1;g{MfpsWQuRW`Mfdoo4a6J zIq$rXlzN#WpqC30G2Z-O)zX7Xuot<46sFkT-w0HVcoP$1e_~Fd$T-dfV~UAn@g8`Y zt({hJUMfR>>Iv7j&xFQzX}31-UvN4!5LIPc^e0mXtZv~F{!0aCn@Jk9nv$@b2nRIv z4 zHyvr}q)OFjzmw3FwM(DXQ>|)CznKyibWza7$fA@>m9TaqVG!zAp_=eQV$oCG< zCK{6vpJ;X$V!4g3{n`#7)ou5sjmf!0Qrq+u(o~L$MNc5Z>U?$~@~Th)=ZUmC$cqq@ zljvA*UhmUVx_eR&dw9AJ;Wb&PC{f6OM(IAfAfFc~2a6INl{xcdcmOimru0ummj77eE_9f zRBWhNBL)=MfaLbz_jsh>+~Grf>=VE>+)oAXf;m=JJhFp98nQbpn5THW=lt{*R;YTv zWD3mI{>x^5g2WmzmGBT5ECfzP_cqe+hrI`SOyG;*6Q8aZaV~7+P9TWw^R@5i@BMS^ z<;u!TRj<2&{!bkpL$3lu_K%VFJoQig+x>YC#@Z=?ZlBugw1dy_OU}SEP0|;i!s`7S zI~0cll5;{!Q|32?L{eDE6Mv z-eg40_;er>lL34m9yTyqvdwOgvRBJ0mVlxBRD{ z3K<*gM{`xz?3sNU7AjULV&{HPJl@e$f9x0;7)qfaFTC!w+DD&v1#n6PdVDWEzds+` ztkw`om;c`7UH=1~E{&sqXMaW(6^cnY z?G;3wIg@cX;arwFt-5VqJ16|vOmZV^An613`bRwdo82I{O&%QhGDIvm=xRQD`Ah#K z+MPYCS<33fLdS^slz0QazTYN8l7)KJ5|<)*2U6^`BE|_HEF-$8x%lSe7gl1goW+0@ zG5?*iM5&PMtX*b=Rb>Je*p}w56}x+SQGw*)h8=O81G6=l-R9oT&eq_O;$K*X^CT#$ zk7VS8NK<;@mf0UWq)AqpW3^eg1cH#{vOrT&t89t@MH&s}ha{bsuo2(*4Y&ceZ=6#s znT*i_+^K#GEbRA){0zxb<|$FhCeqL(j|uxv*#o9niln!o=vu1qqJMpU%HE1`eYMsF zkW1yru@o&K+(1r<(ui^I^r^tFDvwzmGTxAA%2`uFR>bjSa>OxZ^vIN;*P6gt!^0`6 z!4FTB{6=sYGw5u%U+J$CnSt*~QU(rkM21GlDZQai@d{$e?`r?yn_}`n$$iO^F6I^I z)iVT__fzd=Qm|n_2vhr#M|@ToF1`7PX%EDK`ER{NumkYvHU_sYrE-o{ z4a2=0?wPj>y5n!I`PF3Oa{h*#1@2mXP-2(+qI;qBRcpjkjL@lx*WT*M>rA(0#Dvoc zast;o*(p63$JdS(x-wXE;r7|# zW$E0i2lATWxOCSA?8cR22(c4g-)!n!!aiIQ+uZ}0+m1fmWKd77kLn5lipCPgveSmxLxXE z6FmSWdSzfo&0h!P4?AMhl}zfCN4bZk%K}TiJxf0{TMy_ckUw6VJXB5pQVo|3$WgOH zE_P7tKo>epCnKK7M!{C;5UY8?r*POwf^%LISSwmxOYo|y_XICd&u@4pJ#>{t5-QxL zX`&FrG7WIUE>2I!T;7Bu#psH%JRE#)E+&N@eUuUj1yfX6=jOG4Ry`BX9-qg&6BN~2 zTo#pZQ4>e z>+dboi+yp>TOFC{6ET3f^3Hhlk>FtuRco=kgtS7Bm%S5O%;KgO!pab z&P)~lCT)+Q3U@q9)a^GYyF;Jv6FVZFu@f1~p2;zjgzgPLr~02%v129bI+7<9^U+cc zq1WGXe;M4|J+m}Q#Bbm9yoZJSld}1!@}Drp-9pm56TFzy@zp8};bH=go(RS~@ML>> zzS8u0QIs;}@hf6GUJP*Q+b4$$|LQhl;jR#RFxc<$3V6dXz|6Y~+}v1yZmZ1sJo75f zonE{P^C7G}YQ*>&l8d>G8P0NP^ZJVhlp~W(mg%cUL)TTL3U>3qkR2}R7IUrvfkQ-l zqOhHm{>hHgb)XS0Awo-cHM#vEj?hs^VNQA5#@2p#zCn`usF74poXc%V@iB{(iM^{u z4lz$WR;mEcF*O29CBa|hhg(VKXZ(>R*HMb)YC|j`!eAmdl^ypzj-ag89nTn5@+MpWugPo$^C z<`uc>+fSywU!SQbE{GXy`Rj7Lz4163O2^D(+ZF?@)TmG)xKqoE7&>uFt5sf6YA~_V z*;5;z^cuQN>>219%+?8P>otMP%89^XhJ0|W1%x93%L~(9?pi~&c-(_`Vkrx~6sx^d zy>eG0%g6usGmMXrw4T`N;q|!oR+bP6f2Y3&)RFz?Y6x6+J^gm}! z*dL2qV7_y?XuR&$R}~|F(&{fJF3@B0s25aqY0PUvPkMMQ4}h;p;uAc?_)An&@#v#^ zomG7BHN9;rT!NYK4M{95*)2tk4_`Ou;@m)&XYRSA7{&nwtE}A&sWcJf7@Z(2jENLKyb+@V4*1AWibrO5# zY2|s^58DhN*!7E%8T(wiqsQ&JwSIE;QB3t3`loxwUm)sjknmPXd;8!ocrdDXNvrbn z`SR-kVO=HLiTrTbX2Y3!-g^r({>I`mfb=*zNJ|*~;Gg$c2gi0d6XI(;emDK`mF|6k zI}w_AoQ+J}zF~`2^g#ucSF+O zN`4Ko1WCivuCg+NrJYA!?iqr-RH@2B0asrSrD;FQmRyM?HD&Rq1L2fM;tnM<)f!dR z%1Y@*oi~y=d(~#T72;0M!aDSK?=E#MG!3a-u|FzW6>QPX{tFIj=y-g*ye`La^7`BO z5>wsbhn6bGKZ=i)&$zkQrBp#H(xWqTlo!2rak!zN#pzQn6jr`p2ancsE!()lMIz6VHsv6NPd z60qTrsT2B$m6YUYR?H+i<8>?O^4CG{4%4pACyW$0Az)uE8z9AgkIPS^@y@Qd-=Brb z-@jK00fzcvm8Eg_wa|37!BjmE#qf#%;8w|?K12=BB5&IY)S%ki|Cwaq$)N3D@pxME zb>PNvWB99tws(jQ_%Ojo~=O$(3=h^bL>>@LlS-!NB-8djNz{v?*4~ySCVCW&S~eNhEKI zTyU^RzU~#KbrhcM&g|=+&9V5}Qq|@8l?!8Nn8Xo6<|lTGbJ0nri$sVtQ0niH`e6>U zTzeW<+2A;td|Ta`!Z0-3t{#swzV;1u(UbvXN(=E)Awyr{3hid2qzsN}5dg+){K+qT zWbp&f7EsUd0Jh3@{|z2ap~_S>m!#1RydF-7TA_q`NodX5ZVzS^$a`$nh2g4%>p~vh zuAAKFS0y;}o}JM)LKi@-8nZz_vm^Z2VPs05}dimks1o8@2*-R5?NyBbCNAWf%v{ zx>J^1Y%m+bfIi(a4enuaxS#wY>FlNwL+xR*uNGMbb;|pnk>+p=C}5njJEH`U{ip3Y zYxtz>Q7k#P&YC-g-)-lX?S%6 zjEORYnLGzk_OX;Kvd_4!r2~*|CUv)&1{5LG z$;y&Z@kyE+lC}z#ICJpLr`ICZiS3P~*Tsy-JVEZPSJ6}zQun>*unszu2k8Qm(aT=9 z*3a)Op!zX?Uhm11uYl^a-iA1W%Lj^R3B;`dM>l5fFGi3_+(@gJWmQWK!l0Xe2C-8B zK*T-%qOxVKC4{bsC~NrmVF&W>@M9-=HmI>Tx`gf$&Zq^v`k8dR5yN;dwSEOjrhRk!_~auX{u2I3hlg#sLtc)J|h2p9GfPV>uf!iFQ-2_B!ZLq2hQ)qr_#X*OQM!W4D!@T$N}N)5!&3 zh*wy`9t{Jc7bBKRHnqAdAu`5fuad$at+FkN2fFeK;U%xhRNg8gwD|vSgNSx zGE1KU0YmBj7!pj~co=QNTg}pfJ=~2kccX@!*KuKnoH%r_Jb2soPy0v^eocs)sDd$- zWpLnnWaNLD1}Npl8-|}V+l!jTJN3yd)L?^HRUIvptaBCPyhN2aBlPyRErq=I`c*g- zy@TDMmh{~hA+Xqj^N2!?M{BPsw11N@FUZeV%S{DUX#lcP+IQ8&8i%k+!hy#>H&I9{ zsg9=~;IIU*6k~-3dPmf}Cff`Xc6GE8Z7j|MK(RmurZfB}CV@tyPYYKHncm3ojFR6J zCKOVjWoe8#qtq$9()=gB1*_wD!~pu+6u&ma!*fj7QLYWqu%F;?K$9L9JUVS;)|&kb zKD~GhBBqIW2QuIHy%{YUgS!oKy09S@*=Xx-Rrjk z$ixBbX1oqZ*iZ5X{i{PhXM~M9AxTzD=P|Wz&U%JzmiWs;z^b^h6jI0f zqH`xwFuD>nO2>L5{ixAjiAR^n1vAm>f|$+eH&<*HIFwh%yYBhzzcJR%Py#j{VVp)B z>8L9*aT5g=8RBk}!GR5PzBB_4fyUwft?3TD5=m;@&jNgg79_f>jqM zQ^X)U1d_hD%uLXo4SlT z_owaNU0JbZbjl_`lA=%f#hk4xtU&1d6Z%vuP*oHy~4VKyD;`$wLHMx;%* zmZ;8j;}USt6&T|Rig@kk5c*Rm0s@ibsibjb=`?>{eG+|C%AgaqW69$`JvKw#tE4uF z^ji^K*tZ$fo9bdD;>{&uU7mn)W1Y}zq*72#S)xG-D&wYgylvBjSP7Zboi_IT9H5t; zbZO=1#*VLNaIjDMnz@=U!5Y}9=hckHy2uP^@50Aw|L&(J)^|QW_c`p#2}3a> zR$c#!O?|w&^e)rV`?)DmWXv-DW!e^L>c2Tt}yPYnv&Tt z-*FhC-vRiPr7BL)kNHatvb>QS6KDk1lM@)boewfwH}4Dk&7rj|EHEz47yb#m(PuvI zrEc^K|I_WmCSH@05&i`9&ZxbgkRT@wUVH*#O-PD1^`kW9DPeu1HGRVnq4xw$=Jo-F zQFJGIuehi}I&r7af^x@T3Exi~7?8BNY!a=Fj{6LD_yId7`$l^CJO&s34wYN*bRP7u zGIo`528b4jFHl>cUmA^V4HDQiqKvxSyWSfUO5ZvRvI5g6Pm~>@MRbpHi1KLq=Ns|i z3ET=wTKEgtCyGI8kMj^Vk$+O0JipVfwh~h!QT=OKUFgg}rOtOI?=7)|kog?8g92r& z08w;cil8z3D0|w^8dpo2s^2!qslmrJlA=NvPRT()eB)` z%7_Pm|ADH+oJkVbjBEb=nO@yy6Lt;x8_z?Q8GtQl-k5+q#G)ijwFWb^k#?1q=qcK{ z&VmN)P0gM#9se0k#DE{x{D-@YgesI}HhcV^c)$WqjqeFjFAWuPzTY>@aXzAeMdm!a z4ih6JAckzI9v;Ix8Sv*eX(ZKh0CfKiD#_4dU9>64^tyyw1=VeW+V75>sxS_+>Td>G zq0wczVw+P#emZ)hi+F2#!~*7AxX4)Zu;qZUIlYtoTzF}4<2oaCNJm^FIj#{45W=Q$CKzWf zRPy|3fq`!H6dIz`KB0+%M}6{+J}chsy3%_k|F!XFu8u9 zsF?_gD4w@#Scb#(8O6RiSM>gT9(uo3?w(fQ4KXs2!?m&;2{gH$f*|*Xq6VRVsVrsG zkS040atkhkYmx?yx$k zRN8ckFTVWv2?+uCGZ8&AyewV(x&3|h`Z2q2%JlV5JN{G9iAD<@VED?cS2uERTyg#D zg05l4^IBBHb0UNHH5)4qL4_IDkPUa`(K8^)c9A7$>FtzT=Ci5yBD7#Jgzd3~*^QJ!c zSyA7h7F$Cw;;z1@cziFhpaE0-9Pfo*^sJ)x?Q1uresV>0%5;o3{63;X^6W?oH2ZVk(xZEgl-Ku$=WX9rzWni-Q{hcB|q z4OTAazAr{o|M5#FL(*69yK44jl#|ggXMPUy6F4`TZK?ce3GVhl@JeaZpu)+>Qt9Lj z#^))l3f<&B$hdr$L2w;0)}cIFhP0J21-%_^>7)S}x!d{SI{6sEnnIZB!Z+ymNH_9y zIU{(UzUrhe)w(yBQbT&sSl|S8dKwZQQqNC#Re}2^0Z)~QHvwhzWtxmjz}g$wl3tVt zOxlj0rA|6s`!tj0Kx3x4=~whUTT4DPdOFTe5kXuWF!bl=i_Y6SLi5JYx)k!K&>s1d zo$wyHR^+U^}8x`Fv{rH?z0E82TrnzX@zAbe>JLD0aF|A z7;A7AHjehYD)n?IdfdRqK{*V8YNqd|zY+h2nZH)PJGSB1t4m|I!|Cnbb08dE&mZFK9mH7DzZ?riz*#g;D9)F8*1PSf-hRE5&(os8X0pDwFD=`ymlnmOW&LM%Axh z^ClMk9;9g^OvZ7<&vvt@M0&xhn(l^P%7k|5!OAD8Yy$WB3UAd?bWQ7F{MHG4PI;uC z{~{gVAu+yv(AW^@DeVCU3WjfrAprxme5oqjS`MukK3zNzu{MJSi`KYh=9FIU^&!&z z^qrsG)rjR%d5JJLcM(bb=a@9U$w`&E1jLNMl{^wNdMr2)#3-jrm}W`z{0@xS;rkZ( z40C)#=|d%mQxNwnn!yyrS6(jN`VyUNlwRp#xeI5(5FP2rYadPZ!{OGj7!c+Yq_q3H z$#Iw3Yu@>Ohv79Pi_|jwV!-V6ipDm`G^V6Pt`-5D?W;!c-*jpqfRWZ*iqy!_9GiZp z6~DPX+!o^OLFTr3H}d8v-ZlEipHMgz#K`qT`GgcY^{T+$+C2 zdt2w>f7kGR+$;1ev9b*M)X|yDnMup8L`)rnf4FMxAUR(E zvXMtv)Z`h%#U?B&eBRzT5&H%V?}Ji%=?d~;#qG*{v><{%*g%qWo%a@}x%#J3U?QRW zA7H#b$mT{#B;f_Jvm@=BPf*%p{86XP<(@$9tln6jLM22oP+Y`#`Ip#hU)C-yo<>C| z?=0Xx_=Um|7rvL?4&=M>hrKVma_TKxC@exc%e|<%_0QtEB5w!#8h<@!L>~vROesg_ zaC#<0RvtHLytD2$9N?UUX?g&<6e5zytSG0E*K}y#oDqsplesT+t)qW@Vt;8vm$_dx>RG{pfrm^%V)!M%9LH z`DiUsbtkIo@kYvzyFc@O;I8?Hzu2Bqt{*5`&{-biUJz?azDClSR6~G;>PVTwA{HWp z+BPMKb(-c>wW=nrc@qikHZevlV_61@9?TG--3F-NPK$XEYN6XRsa-uS{>?TKKk8ZsOR^Y&4_0*Ax{+_(4~ z@t8)+szCk(OCq(DnmgQ&jato;gZGjq^Qa3vO$uJCHobZ7K`e>KnM!!mkMAadd~@qx z(Q*RaLTH*v(k5&X@A8-Gd!gjbd=!u7W-6PyLU`HT8(Z}(Hwt==v0y!6C+?qSHt+Cq zIk|j#_+)KH)?PMM$US)wBl^$x;4CPfgoj>8G`;v{f(=G)BVEqSiXA$90~4Yp%|S-Y17;xxmN2#?y=?n> zq6570KQU=6qUa${wvM@ETJFmkb*p2g0EHEf*;!lTAlLCho^W>4u^fZhZWG6sM)yc_ zJYr&$XlG}q3?zsM)B`D-D4COh7fLEgJud69=#=&$OOwzn+0sE|U4Ra$mri@py z0@I~M`Y0Seh!DWhJie;guieEGl+#G!@u=8s70}%xBane5JF+#YAkwJ)uxz`iOToJa zu3=@ccJ-{NZT}c|Vzk%RO8HWM5^8{xV$A&)p{E?R^I@Y53X+trf}9`N_o?bGfRpzGevC?M?3j*v46KKq0Z6UpL>Wk*uf6pDn5$NY7Oo7>i+&C zh$Cnz@h)C;B0W&|5q>iMYA|z9;{dk+U2vN0wA)1`vQc`xbNb3;z zHdk=Xi1+%};h!f&=ow3Cj`k`w!#ZZexe1?4UFf}Z7@R>;gxQHpy8-OyWW26&mc`7y zyGt*g0jlKJK1Y1GgCwhC0Ar;(HQ%UXmn7^`7%=$Y@+lPBP-~G2ZZY07xi@4hZTnJa z?bc{ahYLzE!(-mRo373-sO(4HEzbe2G*eB#L3_=W}ZhzdEV0b`S%dm^G(0Nr*5UgzU9@nJ*)T4)D`hdu6N)KzW zLg4P7ifg=His63Jd5J31`3IvOu06ZvD1K05cR`Sj04s>&v>k%K#TxLTz3^>Qe8y%0 zro^~7nubA;UgXhIm+$nZz=q7s=Avx^i)Rm!nYB0T(3$US>&l~n=C;#7jzh&dTq?wP zQSVu;a0td)wH+D^A&&3ia0J8&lf_gGMGz&wipmSq85FV#fA)c}n^kK&%LU2^YF|>- z9E@#egDcW~>-`blxH=V#J`9a_swlr%EH?#$_SNjpZ-RgNz>H{5B90-qt3DDRbX*}e z12#DZJRB)TthjGx{lNv?=05aqHew;0pCYv2|)6w}7WL?nBidHNcPSf15Hx zfal-nlxFeRVcF|Ar~N@7>>pN z%{MoyV}I>_O&1iq);A?`V$?2B$*u)_h9*391~ztScO=HfV>_k=Tc9|1+#lt)#lUMMLr4Dnt|`i8~d zAzIkvB!5h$P{%`cEGrJ?7n6b8M?LX4fWbI}22<(0>lL*}4Pp z`WNMRFrnnQl=VDLEm#qL)u=lL*^~CZ-XFoWQtF<<+ z@sv<<)vuc$%L0C6&gJ>@9E9+>hoh%>?1WW7F*I<@e2c=^T*YaBO$`2mrlR5p>3w4_ zK_qa>UD!y)?G=7YOg#!Hz4Z7vX=B!Ps@&<^#4tyv^~pW=CO$TxC<%{r_i&y1`NAm5 zWg3(Ka!PKXRI9v*h|^<)lwLr?t=)f=Ugon-FtkuzBOIj|q{ivxTE`w$^0m-uFHeQg z8id#Gl@9{~9$owXvu)=ECFYAWG-WW{nG}WTr)_~$NE9Q+y7FNT)~XdC4PlxfjbS$C zc#WZ2+oT)hi+9-hEb|a%Zu-U+~VYVOTNvpQ1#*tVNvpY^tR7#O3wTE^izd zY;NV7M)vB`YYSDK&7fWBSVHqsnd?Vh21ciKu2aV|g`OljAe-*H-&*yzeqGzOuLH}q zIfEeMu?~(Q9C@D(jF1f3wz2eA2XtgSTOj%zf7CxP3Xo%qQ3JDjWlZz@D-l7TAyXxV zZ;KbH4PNmV>E!oYT;(^16KrmGa9I>;d&Z{Yc0GR@yEqgF&r*Nw^YEV<1`YaTXMzU3 zNuys8_mr`;1j_3?K<;MmSpj5Lot#ATC8mO%VN%6i$0AtkT(97?@h zU&n7+C+F&|s!c{e#eai$Aq){TEg7Dk`23~-WyKRRf;UEMLDtNfXZ{0NPU25@MQ^J5`_t@)W+IJa=}hdBMA5mqI^e&YBu zrI4%h)*6zZQo;2CM3pN`$w2MTykCr%(=NsGd-CJcs$echa_-l62o`#fm+5^sp5^Vr zvN;DAC`ktXQ3qY5+M$T-(=48D)NouNNXAySsf73NV0rJX#X2|Coy0MO0aoOtV% zP$WZ0e>`~CHY9*=7Via#WH`PMh?SNga>de$>IQc<69lF8=_dI|l|8Wkj2L;z z(H^1*aA8C@n!o?q2KWab4vq0S>(>A3x015|ur4Y_tZ7A2tvJI?EC!jzHsudRYc z0Yinu{dLcs;3=`Nqww{YTesq(yy9?SEyJ3)0%GmSM88=Z2fh>j8mVsa$pAEP#!b_p zz1Mv=VcEjAy-5Lag~lbtjf%g+`x8!)bD+ufuBBQ&=wQ)@OlCYGWzJ2e_mZ;sL|f?` zId&2g8)sT>I#OBXjQCI#f+Q+)Fr?5!sW)-3nYAHkv6z40!R1Qx)+F)ZScrAuY6M39 zK=F~{5fWxt83F9yGG`llq1Bw}Yz9Pl?f^SMynegI+t}ZyANcV>nM*dMG&MT3y!j3& z1;Rd!Xb!5G0_)1Q_ND#rMRPe-8sU8n;?3Z4l80VNxSEq?XUIT`Uvpcg=zd$od{#nZTsuC!g8E%fDMPi z1uy)YA)$iGR#KsHR<_kABRA>}GA*L$tRsex?%(5H5A@F5Ly_n!CHS)=vAL3R(?0jR zYN>DAQ7S&=DxzKYjm)#R%zp?U}x-W)c%|mIgwDVv3LVZ1o@hX*te$f*POifGqpY~b}I4c(0QyN#qBW-X4LrQ(oKe) zwX?rV&{#8*g+82UeWCld;!x_f$JgXrB4HN8G|9>X-`fKSavo^T^P>@McfLzOl)SE9 zy6W+h=jk)EuOy@^1O1&TfI%O2^lNFkR=fvX=Z2z{J#>j6-`pb6Y$E^Sw;|3@YwntO zX`&ZIcTQ}JZ*ZN(J1KthMjr&6n`%&aGadP(olu|*{Gm{I`%z;mo5wN{ESADqWrLWp z8H@b!8fV6niqB3(j3Xnoa|_P%{y>sGKXd^#gU6pf&g>`$pI@}!Mope50C7AHhr}x~ z{*S+$QBmE6gMD>pl#3&`O-n+rw%a|Q&4=qK2`HnbfuUl^DnDe?M`OUb>|{LYcPIvW zrtT=aS5Y4UP2^K_dhC;XZr#2t@~1C!&$~Jq9rMFlp@Z)1I8oraG!)g2yFOcaIkBZ5 zL=TWxY^BalPsr?Za=d*@uRF@*fY+1+5$VcfNiNLr3vl#WycDQJ;Nb<76Ddg)ux@KK z5keO$$jS0eU{?0fHNM{KNW?-`wilpV=H7{rG>_x)T{(rUK|d26=T*qAmQol<&AjxJ zuz<`>I&0h9!o_5os^^kS@16FW73K<|*q2y&74~K~Y*4ir@&j9;kL@|qxLXs(2r56Z zFyeP)WBPzZh-W@(3(1hb$EWOi&LJ4h+Z1G_wBNS3FrgYZ$Pu<~Wj_{^u$?(YiabhG zCr`VQweVwKPwaBV#bS9(Lx!ez{@1i^(`W1XL*57RAn{5|CG`HEHhvLu{t~sbP_k*6 zMwcE6a2zP4%L`#>m{h>}rQMZV^seRz; zg6bsD1QeHX^mJVm#7z!+f8>rA+`*XJ=+5|m+3p8h!N6Z{ZY~)twV*S@Djco*lIL4Z z7Q7)L=S*k0QceiNB%DS;VRX)Fs4qn(;;8XaMpIO*TiI1B6JX{1iQ{ina z=~?Z1Ej(sks7k!1XZfx?LsOv16d*!6tsJ6o}(CNph=P`0D9 z|4(%ZH;79;z!`R%qM$gTVCZzq^%AZ&l-$x{C7p(GBVI`F+S#V3e9_zj&TOR00M1`KgK}xaglE& zm|LeEQup+$Om9W2^k^NDcvmIW+2||=dib089XQN4`j4H17qeSiAIypFbQ>1w{FNBt zhC;J!cJS8xFSD#lox5PsmyFnsTvV6R(Ice}G@V25!L?|QrWa*`e1pqqZAh706Yu(v zj_^dd8CLvh;eH3cR&x!%2;*af1Hc`jS#_CdV^F8|3WXLQL6A?k*ZP(%K9E^B2_WLm z9MaDg!$)KQ{#}w(bgxAwUdh&|K2HD@=c>7-!SNt0q&|ZIpr237iR;_q#q!z%DaqItYiRroca^Z3ATXN@54xcW7!5eS@t-zgLutO!?K8&98Q>1pIs zPYLC(VlU<8_e?>u1IHDR`ShDZ8S!k~Nql6fV{f6)UK)&7R4~V-i{<2yA+Z}YPg^y1 z4fJxT^k_;C73|In+Im2HWzTDW{!A^rwX{G#Uc`6kO!_po>RwmEdG$J=W;`m z+jZfvDO)Pin{3C#JJ|j{#7P~=$waxVbZF~~o+W9S+>)`IMF%f}RBt?G+yVJO_kCzS zlQb_`79Jz!L9Ih|(gmkA<3;vJ>A5U}7}A!{O7d1Vu&P@+W_oXZ9PA>#Sdt*sRGDp7 z4117@5OfFH&uT=m`M6mAL5|1Y0&RXF6!n-JN7W5Tww)w?9}G5$6+$;wp%tB2=AVhV z3NYC7XlqO3!fWTyW;gY5eKTWg=T!WO)Ayd}T4N4c1pCK>K2GKjV_D_w84^f4J9+B1 z=EB%tZNs71J(XY6dDP2?CdAqDtN_Q@wdG7``-+{;)9H;KzNL!M?XIV9IlfJUO~Y<* znD+!q-B9TuDB1>wXu$n4V6D0-2Fd3WZ_uQ*xNujUf1`7oGAV4vE$VIRDFTV4r@N#5 zn;HJenA!ll+?K{(r;@0A=-Ltnc?yk_jN%%98Y->If-BLqa<(X(L?#U)=*~Slq`rk4 zUahg=$}T`9eVsQ2x#cr}5{E25=H5LIELbmMR5>&u%R9#pZe(+c7n{IsBS%g`D{*pk z*xO&7i`;uvoP*?C;R^k1Zb>nAKA&tOhk2b~PwXsOF@YXpEh;%Be0<6HvQ9?KvL%N6 z3cF$FL~C5O{D5Y{D>P`Tt2dGFO6!{P`ZR9sOK_8+H^jD}grtFd+GhLc`VK_^8AZk< zI(R9(5DKzavi_!VThKApgb8oF7xYu4)a5jR6b$u{Cc@R_Q?o?u6ZAjV=qo;b4AZ|F z<@}d#O!{BesELz@gR{Ni|A;nbaCUe8pOspj{Qp&I=#3`~0q>wx4XCSS{go0N?-ekd zP60kigQ=8rq|It)T*E$vW#VAVyAf5il+Tai_(cWFv7@Ly;UL?zTYGA z2)!molfZenKwrX{Zb}x7G2>sBBu`^q| zSqcex<|OGy!xf0a!^Y@hKkDNl_4%8t0uXmJ*kQd(aw^vIr4~Z7N)b?L7g5j^9ys(Z ziZ;tb=y)m@bwBI`M(7wc?V8716N@BI-Dv@NdLm3pwbSzkt95LHHI(C8#Inl#mf2uJ z6<5eU0-vR??D@<=ZIYx?f8l()k+K>x1JOEYFmh2{4jx9`Quck|T&3kLKH{60LG%(S z6DHQ|aC~bG{Lm_yi?>Wnx=Pzv2+ky=K(-_pO%^6QopM=4LsfrYj-=0_fMS0vLJaB8 z-h!^>Om4{B-Awe$xzlK>0n8!{?P#HslSczjFCwozzDTy$39-BEd*(*GgBH)r%JwE( zSjzLBX_9zW5#AS=|aV)QInM7v)b)UqtcV7yO~mF1%V- zFT~gR$=TG>M)^e({)7ChV22lI;f$>V4Vv2+dbL1I8V};q)LW*lpL$_Xif%r<3<`AE z{Zk*@Cc*gB7w5wad0!#19E$=b%K1V(TA`=J%fc)eZRENXSBbvtn~3`pzIz&NZ^6Vz zk9!WX0#a{5bVkqj|3NB%?y0g6`$sC!f&~I1{x2)f0$^+kaAI%<*gDu4JO3}!L-#*c z0WK$!&rWSRW|2?ZSx^8^Y!*+rwWt#+nn6*1Tcgf^o|CW>eL3up*Njq{R4nLY zc_?wUS?F)>-)3!+i**%T(Ws13qysl$MErUb^8^la-!rM_HJ8d`Gnx;0y3kgBi#A>iUeLW<+^X*l zoun-6<%f^PdJ4KiN&V zmNp))DH;pd^3mu+!d@#fY~TcTYJLB!ItDA;jH&IWY}4z-W)-glIjbIm4Am2n2|L zbtF1kXOng@a<48!%Bb|g9++7$S$JM#IK8c?nr=P(%q%bk{p458187P(!zGgb>S^rw z6V?9ZRq4ar;kn%mJ^!3x48@7t2eA@z$xoP6zUVetPJZADZ`a1-mP|a}Jz? z=>!h|pq$JKu{`LS#b*aTMwW#da!4F#_IYqC)0#NBF4Ty0QI9pg<$J$n!!H{y1LN9yUX%pU zBAC8i38^}Fmd@}L<_`pr&hV#(ug(>{ujEkvV0QnO3d`xg)wkp$3P#(0piLSUqS}Y4Z*9D5{4wp6Q>!|nSRihi4{Lm#R51btia_gI<5^o9f zbs^b022osJgDkkF_8NeI9PBmwf0#sliHPff1y%N;w|Or^+3p6cW$X$ssLO2*BkObV z53dp>!-?E420W$*%aO!es*P^LGZU9MJ}Af9g5kxn7n==dHlg&YF7u~?vS6X=<80d4 zoRM;*M1(+01!g=s5f1lUcuT!GQXh&or-;pgHF*XTfFIpj0V zG;2Hkjd1Iyk~HL^SZ|d;u$xBymj#X1A+$7Z4CTCC8y;2U$KPkP{&;&yRp)+Ox;y>u zfrp8zHmzYL0uAYiM(>T}7YvcDFStUF$R%1o^|E-MC_wvy_*q`{19H5Ok)rHZ6L>m@ zm{LqVboQ3aFwKxBF(+h{s;dF8VJt~2U33DV8Ltjhpwj-$rLfuBR|NLn^Kn74dwZ6D zd&$yFzT0YYO#)HyHCDmMn1sh8!q?LmN#6k}GJJ7fc=UH^vJM6AWcZWsR*_fqjvQav zFNhbMAosr5L@;yXBRKK_E3ex{P_53@hBGIog+`NsgvzXs`k1wZ?j-LQEiq`c9JE(zQF{?4)@dDh@;+zDuL zV<2`KmQ7Ulxp#mq^kMxo_W~^3T-I8Qda;3R^~io&L}e!2WRNRa%qkQMRc20aysXuXvPFHa(fca&h2dPPPQui zV;mk9kAH)+HZ8h}m_6d{m-uEhJdrSsODH!A*(wWz&amL-g{mKH2q;6f`|M{U z7D5mjoe?4}u_2}P?4+aEvakz|0^wJOHkgRWX}iqInN2MNM-TZd@NJUl!oz_pajM1w zMbR&+fbvi)17e-BN6H<1o!zMtw?vOeH#5j|C#-cM${(dagAApd)XUqKegNysgbkmm zU><4aS?pZ9Ijy=->NS>BuhJ;?{2W5(I*?p#;##8 zz&p`T#LEW(bqp~ZoK=6!gxx#+M`v-NvhX%a>p3p+k~6k4J{dS($U@mYB@@m>0plw4 zc-r`CbfPRtS!k4lcJ1VaADW~FM4ZseF^k?w4Xd$xR)r_9D4}(C^L5;S;&3FK?epc5 ze?J@bBN}Qqz+(?eqQ?+6G8GNetED7EI4UzDNSLEY2BqseS?kQoMw|LU9Cz6!-t8(l z6^N%`7(jy})KZh6545{T@UhTMs+pjj>WJ>qhU4N`T4JcC>*sa_CY@|Pc!F4j`dMZb z(Vzbwj-@JU_UNarksvNla4oh{D9WqY?nfeYpqpZ#Ii99ao7b=N)XRl8jKk>Q$Z8Rf zfu}RA`p;l>0ZNRpuN`S_e_^BkCNd1B0QZvVcGU3Xz=30=5cR=0KsQ^+%^g@H2gXyb zN#3w$S!$!&6X0yZf*m32#t)FDn45cvcamn^XOrVtWdJBT5-V^_8ky$eCS zjLAIYL#%mbjYN^_NvkQffjz~@=lE#gR0_C|%qMAQ zvv_em5V;YitsZ6nOmX}Pm)c|R2(4mzTe+j$rtDz&Cjusu476utCN{xfnM=}caG?AyKU z?!(IaZQ|6~y+Tpo{OqHEK+nJjFK)X#@BAgrymatR?1fR`?(r87L5`jx;|S`LzF%O* z&Rx{^kR<=-$dWr(#_2>oL5^Wgj1b)7$XC>v1y_I*1BCfXX;G9LK0L_#zEj1t#7Pl# zs5~QY*XcK#&znXb;z-cTYoi|v53ao6y{En80&LZv?O*jhJ?C+yMg33OepR(KBbsTq z4rI$`7A#yBanoU?{8h2&Pq%4%Lu!iKFEi5?!p)52r%NG=ln$vy-(zb^4=P9x&TIq- zCHU+eb-hw7We9M&E{}&+Tv&5)dxD|yC4%3p^=y=bKOMtFU5lk(58s`8V$IJkg%>>i zC2%z(gTH^_M5gQI$(0nHJvo={=o{psG+MFX{eYATa4(yup=zu=nXdN3EC?{dq0FKi z9K4J@nTqLv4leAud;75C>l-vJeM}(E!n$9YoKsi6+y{z>L^6yJMo^vkH}A|5ZX@1# z%i#dzpQN!-Eo_*o5eGe$cGWal&ZG7^8|OOrhK!`_86(ES=1f;LzV0kUKqVS3!vvPQ z%o4_E`cgitGHk+HRpNk975#u?Q~{7C50s?VR8gfAN5h1(R1Q2Oasj3!-e=+ASey!{vGCcvJ#eAT!=p}Sxj-=wy%MQ#An84gwaC6>X zbkiZmRx;CL18ih0+0hH$+jd4Da_35+?YzO3%BvW70#`h0b8iij5|3siWEm><8p#* zWa(BH$zM13Xe)CC@dRk*0*5X#Pan*;C$B^e%U(`EdZ>{X$>-7SNU;(?Vu{`GQBje; zb*=^8je0LtKlH|}+mP#x$#A#PS9$mksr}g9SE&|Z3|o7?Jpb{+5-QT~3j*6q z0P!PMZU@4I7YUm&SUy9-`mGTLH#Uob`a8VJ3B}0os9RV_5BkTbX*DKXK1}Eh2Nh!Y zF9QW~7So8{vg;%ehPEB@42nV;l0^g}td7|&(&+92PT8Qx7TF)zuWv`;HD2JK;07a- zOVtppIsx&*hYbjCWUE|O5(+yX>uv8v& z7#1=lckP^mtPG~_RdZ%uAkgLEfGGachPSws0mNsaqiE0dXt84aSRCB9*~$isS5W2M&M0fa@JM1cKQD_iFZ9g;NNIdB4)H$+ zNn_tjzmA>zua2DtkDoym6G1At`~?RE{hQ-*rqY-k@gaxKH@&N)fhhIM6LP6oQ6O;3 z;tdfrz1sepQlXQC%O^Q1o=CJlscOC1;ARo>(h!BmBOKm6uVd?v^fISBMAvVGx^A`D z5+-=TjfW(o-%J_{F_Sip@oT0VraV2l$M+nuuvy7_8J_ot(8ChCSm-R=xjjU~unLTo z;Bw=Sm=xkw@SOqF`wlJ#7{p;XBvK4={a7>%8o=tsuBAa%iQ3;(4r4ofLx+K9Zl!6Y z5XAm_t2m+C^b^0ul+y9w2wH3}?XNxPxs@p4R6ze;Oq1dU1~C>&c{dgwP@g;)>AltS z-x)bSg5fVtEgiJNmAxozzh}U(tt7AG-g&tC(a~UJ&1&fCwHFe_hyo+kKb>qXZ?QLY z&lnC5(vq2uHVXK8@QR4wY6@)p5){blJ_45oDBlovm{+5V-=BSJ0Dv>Q}bR)5-aU zQ_^d&APnmS$A8Ih@Ahca*=N5M>F4|Q8R#O&RSUKHb3HyTb^M59gxwnwbmXx3?IzQ)r=I?ZXNj=|IL|HTi#WB9X@w0%FI>Znp$)KAYwSjwGjT-5Tt@>Z{$qW@ zc(8rw6bbpAV+^K-*Ya^~hd4y=O-HUS}>@FMif3Y>{TeO09(RWL3VS4A|0 z>)@IKPSVJHuh3(M8|p(BsJv)e>F?7vSYyNLK;YT89#XPdQ}rK^Y(%kgZs2c!z?_!) zOGXia#>YWDPCllM~=B={oOP?c&N$-*; zXwSO9=vP{AZ$VeG+S=vUGsB{R4(xzUgx{iB3*qU|k(PCe@VtrV zQ3p{!nuZF?zXtFoo7IdhDB;yQpG%I$qI-hn-n|Q=z(EqA6 z)1f}7ZG|aAqQ6^p*I8=VYptt+Gm0uH2+#yK8u&TKSi{{(yxGieeJL9x@ZI>UR@Arz zZT}YBej}gQ^l!`GUL2Ft310F8??bCPujkLG_PT$>5RMv)&tbKJtC+FG#mCaPc}NX@ z3IjFvhg04`MVrQeR<>fK5V&#{w-=jg7-y*(~DAv2Vh>AGL|~c^E%yW8(Z}w0aU{vG@}GaT0hGl zohwS7yvU9?gtgGE$a?{BwDQEQh+ za}$`7jBy71@W+y2d%sN#rVM-B0SJcp;4_GMkdll=nEiBop5OaQQa-f+?0ux`2!$nj zIG$NWuTQ}*m>@bKnt5)1YM^rU3ITt(tXI)Ux;GTm}cHVQwLlWwY$IsQ= z-tO+3!|OS{7GdC%fYuFRH=oa(AU4xQ4H17vG^E(o+CouUEkayw&#QETUxDT!jlsqD z^iKcv&Ie-R7o}s@i%oN)IH^#l})UOFjy`?`CM|n@;(+LC1}mwhkC z)uOTPDtsTsC4-Dzo!`GUn$3!n#3S>2926r+o8{Hyd3~;T?ir};HZj33A;#2^y~9;E zN{+IM>Aac5M>Hy-^>~#o`-gbe(AZV_uw@vUMjv>3Mi%YdTUl%mg%CSsvA_-U`P3^stI8S}#8c$o+G7Bcf4} zQXxLPQzLP5O;BHt?o23LjylLa{+gjrJHl){MW02*ZtvJ*%2_zr>UbR+6~+u5s7q4* zXHL1Mb#AH|9sgYJ7wZ8POjmX?v$&D*&W-aRT6bV&6pOl&XsCLecvqZtaS6;-vg#WB zQlzjGDyD3^nM?F&Ojzyj%_xS7YVvKZUq|Ul1mu&*?gwm5v&qdLRu?YRx1F5J@ikvnnt#>OqQ%3OO#zA9MUBMWujWEf-5!w z(r-vyGh=%cH}$J=rJ7xh-k`LxeUnF$o`Xa6?C6Rr_1{6-mneIEb0goY!G&4_mjxkA zGm+ywDWo@dZsEr97odPKwv^*F8sd6NgQSCa`R`G3TIzNV*4`@_$i8 z#w%nfB73r>CPh<6U?ZSDC`nm@&7EnpNS$n)&Z&|C=_jF;iL^+h!-x5T^+e>Fl%P+t zZ6cla^SiG$?87pL0>Ozk)6@tM1y&Hsswi1lhOK|kqBrb8@0{-;343^S+MIpbV&Px% zJ8XW)fJfSt4w+)Z2l017J^X{Lhbk%WL(pp-U^m%5m z)KrVj)a+Iu9E8wFAl^eh)#QdlsD-N+02yOBPSs&uRAYfbg`)%ME|XKx0@|jY_!|;? z&NB=tR>MrD!PItLB|a_Hh{Y}Trl0IMC`3Pq#cC|q$eXZJsw!N z1{XB!Akl>`tebfl1Vh8gcsKP+|wF%FFu}y~fa=5*u;z9Zo*5Z1TF^ zjYMTp&Ffo@kp^5fg~9Jw@SmN=+p!tsFT;#ZM#&PTg;Lj(Us{$sS^L-xCpvQRp0|`0 ztMQ9_dWMMMqds2bUp_DHd?s{_867x6HMIp0=3f^RvNX|>Ne-mas z8fIYzJZjaB(yoE=mx=yifot(5Q-uP{UMpDB#)@p026@jbP!m+oL+G3Ae6 z6;SlNn6J|m(O5Q%i#eDkwB$^lj{gPN~$?fGf|2P#Om4pYH_2}F~ zFw+iL*+gwYZC>1NBPot|wfE%`)p*w(yR@d3J_v$kE%&*&Q!GcHT2ZLBz}yXaPLd~t;8$hM1>K`^Cj3rPQZB*c6$HE62q*g|#hwX)v$w)fF z_~wxl#NyeIEpO8S!V2J7(y=Rb;3YBs1`}vqhWT-JbYnUkCdMWFKi7DVOPuV-T~67< zdIcZd2#b|7(5_HuC7&V~=ADQ--rbL@@pT*}1H#wV*?|-1&$&x>!b2JAbvZZe#jduq zMan9&2L=(I>Sfx00=qAlR8b((;eL0Jlc}y6|t=ZkI)r+5o)2zp1_TscqcH0M9 zLV{&c=Oz8WS1y%9oDW?D=AnYr6ch>?&d0 z5A?3DuX%`}t(>1q83KC_$G5h7Tz9N)fy^^gb5&dVDwOf3rT7wtmjTYKt7r~>}Ni#uL z!cZ4^Y%T;ZT`b$++5~r_R&Pqp74v$#xLX)GEs+_i6#A3J=`$HZR4uGdE;Z2B?VLzU zp99rEiP5Cg2i<0Te2NLFaiNzST&l8pwAWgL$;#Tr2d7SLx7VA{NuC7QJ)mjJ<1=4sl+hl4ly=Yk70 zu}Uc^R)!HZjVjkwiPeFvdG;tB(~4RD9B4i}TYVFtB=3iDI*Qq~HogZ!bRKDura?Np zXnaiusYmZm{rz8GK5_3PUPoKNQNiqgyRA#`IB&5FK@&92g6SY#Qhj%ahT$}De16Tc213*vL--wj zLgtI!fzZP!Y``DG>ZyH?u9ZPwpajN-`R6x}q=#{^0*0t%sTHlC( z>xv0Rdme=*o{bp~prJ654He_P+K6jdc)FPe8T&0j&>@hMC)9~iF^H^S!JN;ECA`GN zf&d>1e;K)7s&W!b(zGoH$`i``nxSI}XV1C}xr<=D9Po+OADou(MSfaOT6B2`m*j?A z5>6i$LXT)>>EhXH{}STrf~HS4flfLm5v#)8ofBe zqTHAjG0XPUDHZWCkog{~uTwNI#LhmAqU;Mv+Gg5{zQHlMduLUXLyNGkf;Zwv)n~A) zA^(#0Tjwa4!c3;;)+5yR(>zcnX2M8?z#w{-R5Zzh!zN)5LmO>W=M;)`h55cZh>2-> z$V3>FPT|{4zMW|2uNR#0uy@|TSdY)fErZ&X?0DPjK>%*m8cmAAPi&EgHs=&o-BdJu zn%s3Fy7=@=S0OU&2-maeV`jFhy3b~5&|qtmRSJmfsM2pC{`k&5WZn6?8?SjM7^(-5 z?~Wr(X_&%_=cH(!o(SKcWO%m*F}%6>ZkJJRS_OT3$JO01#H?ZA6Fz%#yC=l|IP?EI zH523iI&(`q6B`#(!2c^b(>XvOeijM{NF4pY+F$<1%K&R<28;itUeeN6Jdnchx&Dl# zeK!VfH_lv&HVX^WPr|C>A=BQl#HrTMFxCuTioJ4437E9_{>aq@P$GbtY3PvkIc|02 zl}>l3EF1viCwK*RLwRRgo`CIjL{}~>RV>aW44!+VT4qS>ns#jQNtB#cbbzC zG$z|6R_X}cofwxSCJr>uJN?1Ck2(aaRfH_1`|6iUUh0@8NXz7*i;^mEEJV>KxM@l0)Eur%Mod*48 ziBUG>7fG%90b>R_Jeo*0>kd!6_Ls*ovOk@i8vV=URwnWj#oA*cQ8jj@RMHVCnHnHO zlVUX-?X5C$dz0G+WZg)VEUX{e#YnVcHFpmLTEwx{+2yh&>X_EXDQV4twALMIaOKI0 z!E`EJDbWONEi}z!Sy;0v|iqquWJ_!#^+3g&JBelGZPPtJVzf$^JTQ1+C{yM~iRmPiem zpqzh?K^u=1u17yOV7r)#Erq_PY%WC!;lQrR?z@rBGT=rY5(L|wpm;1;VzkCqd+$i4 zBvePzeY=xN(wq;#2d%xG89(a@x3H7aeAxoHHJqT67^XIf?!zAHac6A^CQAw=@peWL z!%S9s?<6R1fnCQw&gDs9YPasvZE=p>(V5krK}%o}dpa;pW^_cmNCj_069zZFq(1_R z#3=U8Rtp@C;eC8>dpw{f;IFeaY)`*_BM{Tgk9IrO@}UmzU7%eZLIQB6L2p94B~=FA z#IfGy`0h`wc<}2ds>mM$YrkhP<)4oWPWluMaUNy^7mcxJFdt@5$Of)PVFTaj z?n{$Mm!0^##WQ!SqP9qrZqNP($3)8q@h(riF+Dk)KCcgc_@ml19JfS3C-fOFrUk1X zvYvy>qTX0t8hRuZj8v*>IA4V2-VMTk#sj>qKbJ#}+M)C2Kz1%o5NBh{8Q;g7+I{RtP8Mn6!LTPmE|0jPDLRENg$ThjZf{%I;zzZ`^8 zOj5)`if9vUPe|1-XzXCRmRaU3&}6e^g+sipI3Eb8tsJBplE>V}`xtXN{wU>emg|{@ z$l;5IVynWgD$r2KYiOyzt&jFAkvJX-uT`V|SQhU?`2y?apYaE@kh;>yoDhLLEmj} zk*hN4wQ8j9A#CsZ&_Etv-5dC@Y!>fEksGHA1VJD76Wq?GN04p(1bV42JdHo!E>Bi* z4L-TodUJ*hyE=g zjZ8b$D0HmQqrh2EcVI(0!ovoyrZKwts_}E&Rx#-&gHGnIo}lZ;|?v1c#> zE9T`~A*3P5aEEGJTeO#28J!Fy9u*KI9ssfkQnG&%UW5c%V@r>GfI3IRN3h z=@uaT>@mFezHP{-OMszwm9dgFf*_(R=wKh-i!^5}0j;6qohCEp!cW+cDNBT7?MfP6 zUd{z``u5zr8H-*cDvmt*4gQZjL2yhAO24tmmyoFm%k6>iCNlZjr*Mpl^KEBo?+;r-KKr$((v}-4lnnO*H|C^ zYD&j&DU10o6&Hf28IbTnDTr9Ssp(Vi+Ci9=qS zK~0G}qs}-cQDyCiYRtZ-sYvxtnhTbX<_+gQ;kz189a9#?PTETN%QEsP-Q2iIhriag zFz-3wY{1if$Xd7&3e-0thd~B79PW^Sst4rO@#`$;XtDX}=&-CrHH{k0;%E6u%Tx3U zms>>tuXWS%$Dctn-4nmfm5dxz=C5(ZZs_!0H5MR_BhUDdDskSq%uXgn(x?(CxfqY^ z7VeF$N5W$*iJ`um3vKRd+Cy4}#Zz+xMpYOo^-&FK}kI?@y5t##=?H!yAfB$b|QHn;t-2n#@|B4~= zYBw2db>me**fE)Gw7gKNUV_3eH1T|?CQ%_0_ykuDza4Cu*lu~<{II`d=EqZ6BX_f$ zh7`BpuHzfsc|E(CE$i+}_LVvTtxCeBG1nCs&aL+9rO~xrEfAL&pHVm_wKc|GOzhYs zf$mq$FXR4=r)nOz;~r(t9~vvf>+mCxrJ+OASm)zHenQToOv9PAl_Iy2tF0+J>pj0g zN3zD?eLlq$BDQ*;JYV+rDtbZA~C}yPYZo zD=4xT49jt@yle9i1LOdiLdvSdVFcg>N#?c{-|!$=PzKF@z#CzTUbn&XYZCS&BBW)W z;9g5^WKy6X+XOB_QNkE#4%QpXJywlD>zNXeE>I!+JV$=KjzPWkznwuztJgVBy@g`D zj%bTz`<5E{6D`%u`)lUVi zpZ+z2@-2P*S%U*Imtk67UwwD5lZWf(a*E2yl?a#`wdyMl~&a3p>%OpHSL{YR9q zJ-tG;H1sE|Wq@bech8{7tyE_U$j&QFZF^T+S(g2ANu{J;ReURGk>>&(F4EYVWAx3v zutWSJKcP|gM<$241-GrcqI``>MHMr4r*qa}T3>?EK^%iibASB$iW* zIW}&CaW^%iHpyW8!CPAajk2_9rZ|xX-CmPX9Na|Yggn~-%<~6M&McH=SM&*8vg4C- zA>m`cwahZPE{YeLc$N9TWnL=Wv3LRsKm@s}>jWCLH6ER$tQCW9fR6>?3>o~7C~J+m zb-%P&F}=2Sjb?rCf#kgEW>CR;uztt$u5K=)mEZbV~@F6A=Rs3erh(>QtJ*HuyBep6r)g5LCC(Gc zr!VSUh)kybpfNAkO`}|WeBm#ZC#a}};gF&OLO+QEJ0@cwdG5x}o*cPFH!*f|*!` zaBg4te#xpwg$iluoG+;0YB`z8IvI0sv*E~x4l!skW1}JzGSfjz;zDK`gH>Wv509V{ z3srTh&yETib*=*B7C>ve95l=I+x8Q+)Bi=4cPW-}g5s2k3UTr`m#*B*9_E4Q)`od1 z&lW~J2+53PUscS;CV(wa<3o3-F)wV&9KtDSSBf_mYE*1M!bA^7(WZfk`ZbboN+WbM zhFO5jPCuA+m?BM#LcFqEhSO^n?3WfZOzxAHPW5n962FiU`fvzRv)%i1i~9X>+Jz+0 z_Q0L~1+zu1TqV96F*TQbY^+1Z01;B5JbF6S#IucF1GU~ zgE~&4cqB$~?2H!<3oNTlSG-IT0!TRE-s?M+dY8X{>>TR+>Ov}=0aT&H0jXt( z0HTWSp^m>goGR)Lo;R{g1*%>%PPuns9u@1jGiWm!G&!!0%=kdyJY6GnsTzM_*~q^g zde-SSJl3u|)~j3BM8~XepEv}*-z(DXh5;CV?+!p1s%B+Kn-Rv{3++uWRSLhX8^Ot{>4KG1Mp4{glX|JG>F;=Es1+Iyr;pb6{; z0)p=J@pjJkK_HGGdIFcg<1|*tZuSqXC}+64`Jx*rR%~DaAxr*i2jAtRzJSpdhLccl z-*q~s@apdmpLE?n@d z=Ap*z{Xwb&p_enrb_3$49iT6%8BEiN~;o$uiSdKfaU>p_gf0&42RwK@N=V;Hdmjc1#ww~YUA9$iQd_X!* zh*|kI{ll8VbWdIwJP9&xsdfLsTbEJRnNMIpAvUk^2b`fxHshp`?^(j419J>KfU2*2 z=DCtkyJ{$q#0DK}9YaMkBJLwFEUQnp>+45I)EIGo$2}VZ%N)~I_4EQnib8slwXL7M z4&)|}!02SG;BVS7-*W_Oo~P<6=J?$JF?ILyw@#gWmCK4}*MtWX-F8z7xE~8_CfCBU zN$u$a2LcsD$Pl%JbmD5s$)6)=j9v4Ngp*>?LqlTSm`BriyMyRkbxOjBn==Q`r^9qQ zs8M`zQRRJw@^urdddmQQ3fD2?qK2CW1Xx0W@6QWHcZ9{1_+^S~Z5i8sS7&|QW$D^x#zaxt|g zaxWfwoZA|$+Bbx~v~9<}AK@HW>P3NbZ*K;YR*(o=qv;J7dL^sn<>e;D=~0)3W^wt} z9nLd(>}5-{%+Ir%>zs(dRWXyr0z%TuA&vaNkT{f-j51e!G^$QA;(xKqNZQ>oEVd?u zo4gEsC&TFJ&)c&!DqVot26AC&qiFnSZ1gugWxx>SUa(Rvk8O4cWvC|{Lf{deCF2HO zJ;J(>P{er#@^~0Z&FuYH(tWGHsjuh*Oyz8Qk*T$f2b-8@R>ObsnhSxoIJ5oHA%|b6 zPa)E+mb0`Rw`re0VEolcS|47|Ne6Vopw7q1?nu$2@w{|b-uhr_SipJ2ohhb~pVT@O zaFcNI52hvVqp+O{5zRG{=q0yl;FWj9o-qSxC>S@Al-y2M>wsy8nPL{6!Tk}d$?@!$SH#&#ao@RDmDsb105r-X; z*#K9tw2+R~WtZ@^XsH2g#xdlkc1m?QShwY#<3WjeEqsu+3_8!74%hsuBz!TeVNVJcIH%lJA01`Lf{ngRv zGOczh5ryKorw}s8=#*cxfw|!w)?iB`E6!h_w6)eIc(b`{c_`=d+-Ii!#uI3l%YUDHSyv9 z!#1>r#IEx*qE!(4!so}h{Nz?W1+?wTui_D6E=n5Gpu;2|qAa=)v^ZVO%ET2~6oDAt zy;V+d=X_gcA9o!>VS>kb%2-ltTr?70Qdh)m9U5@)QBKm045QXD??u7A%ae4bAjTJX z1dPZXZ0Q>Rt9!0a`XF2uoGyYX(}Fs+UEvQ&I%G-RYkyw-A<(BTMY~G84AKT2MtB%J znQYT8%$4*2SDaV_0uVEiG<(3`U$ksy=WMstf*K+nf%Iv65Un=UzX}k0j$}^3HjqbQ zbXi8z7fB{fD2OKjsWb@1j3_kG8LRgev3PZixA=-|W$;lZ=Vw3M0#p*CfOUiGp%!ri5aG1V_IC0 zyNvWbkI<5O<-xGd4bE0j1zCq3;zy(iDa2!D+hM)T_IhKZAGOs|fZ(}(f&B$ew@xf4 z#$+OZ5Q1_5=K(o5&AfcFn)>%4riF$2oQbH_eJ^mi~(}MW* zk#%j1GE4=|gi2`d75v}mI;ZYXq5#dtww)W>wr$(Cof|thwr$(CZQHgdqczjrGq3dn zYSpRp?Y)N%3bQr8{uA~bS>6YnPXz$*wE_Tu^Z&hVaQcrQr&oWi)HX$%Pt6{vEaRJG zdl&rrq7N7nyyioqx2U+iEy50*mU(aq$^=F%%fu9cc^d9_ZhV%6YJ3nr#le;xffOxP zs>{Esb(&i6YkmV*GZACUsGlLe!V-w4L^JRzapmmoy(#zSy&cg&OIwO!-xt)KePSO9 z*Cm$p6Os0rZpwUjExUKm>#RPvVVZ>r8fZGYsFqth@*Q&7m)8Bh*>0M=DqHNTi@a(Y zsiA8w7_&~FZdhOny2f+AwWE1q4~g7j4+!!K?krP3M&7nCB)W_;g>-_|jM7#`3(+6B z5>P?R5&`B2Z+HXe#FSu5B-4XZ@_v4qdX!;^9uzfQz#m9JS)39!1;?^aW=O(MaxwDP zEp}>M%S~m_4(%eMsN@{5S@(2w`oex-XT(~!INbxPG`x_wLXpEzTyumY`j1;s{yN+R zfC+Vh9G^>(1Nse1G0=ABVvz!%K-l8eSuE`D)!ar-R+!%WLgPw-bGZ=%MR(7wW&;UD z_k^-K@JBQc2ixOp|JnYzmTB=!0=!VfzcDgMb~uEVuU^0!eeBj;nkl8DPwL2E*`^%1 zj7sPP@ydRK_@sc`uyLLMO%9qt5oR#rOaPfREagP*6HbXG1^ZwWLZdQA3A18`fpkQL z{V-$H1_2XJZo+1E@4zhVZ+DkEFO4O;FD)fxd@t~x;O9$T?rTaPWOh3_&w4!^N_Mhv z@SY{WOFX=OB_n1fUuq|2WF^2L4=Qc|_`V`H?ISlTHz_S8U48snndRSe8w0$(fpD@N zBW7RQ0L3TnKewN`zMt&{03n>b972CWzY4xF8@aj8%xy;byS z{9JxkmgweW;`|whFq!50YU|m-zAPI^0G!%>%U$vJnQmX?;rA~KT)F+Ico4uRL!9Nk z$jZ*{;kn4cvHO$AMs}m04zNb+{g)rv$5DD91e1&7Z;ZVIuQ?Cr`BnxVH{TFsvBt&t zAdEiH%gko-EY;*m8k4%qrq|z9-z~1~o4pNWkjHAiQ$)P2g>Qh3$F>JIozu6>keEfF z*1H-w0XOr%DnDXNJg=C&IDarK;Ds4Zp<(A>u6yD@R}F_6x|*AxU6>^U>vlx&zq~i zXRyer6z%u`f+nc5WFgA2g1%AMF?~>^YbD0>=33_ zp+pYP*1k7rKmjCr;RG$Kd`1CQ$5_l;$vgApx9TR>o4L`&wg3^PZcDa5_6VfeM~RWV&oBmkVUXYk4U2h$m{3EJ-P-PJscW-N#$yBi zdaPgJ_xECZCS)6%gb_zfM()!S)$PgbIVgr@3A7T>;CwCam=D519KxuKHlfS)6%u?M zx~52vpw~Lj>YSq+#5DvvBKx<2a85u2scP~I31?>i5KsejHs6E@rd(ianK))|fCqvS zU;M#Jp316Re@sTJ+ql4k0pA*6axppOm_1jAO#+*vvM_2^5Q5vE2VODCY_l^}r=4!irNHXXzY)5)AD#?`UZ z61X>g9ZB#fLYe3EN6qdv`c_ef=}s-T9}K{ELkF+-x`ESg%Pxlwe)p_emoimK^QGbs zc6}EFn1|x6aCpWlN>@m9d%h~m@h%z}{G%d0& z!F~?N6-`|~5p%1)xUp+Q69o)Fh5P$K_qxa3zFj$2T5f8OO0E*!>T)O@U@Q=aOeKch zED&XZ>~>Zr9!yA${2cCM$B5_Q)BxHxkc7TD9fC7O;2O$sd0Dr^(=v`k^e8Lec zo|n}5Y~Ifmy1!*TGDRw-8sU6>`V0rGtxoXvs@s2`7lgWOc)&5ohyJX31y${(Sfu(% zk;FHyzn{@I(mL8|`-LW=Z@cHG3n(3M&v*+G=a77>B$LkZX()$VL00)Xjk>_2Xk!HS z0qBwcxgc10a+LCEY18q5R3l5^n%!5ta04fN6HLjh+9*a{h8S>+<`;!&5^E2|ePBFz zkU1z59V1tvc|{~%Uhq011sKzWC!DvN|2LS|Fle%A7fGB8s9tx$Hl~wmTt9TzM4C~Q z7;Uqi?NBqXW8IfJSOVa)aJp zLvo6ZhN)@f#4u6LC&NrtlboxwgLKmw4tje_2VtkjyEO+gF+mAN+a*jW-VZc-1x#+H ze$}H)3eXos=SDpSgt5D3%?gP9$+tB9!Zcg-2-zuaaW<)hCt%<{V+KDFR=ommgskv1`0$l%JU z3j%72cCw3K;2dbbGu0xZM%n_KwiShzHtJ%IaVttOI|Z_cs|I370knjD(uv00;@#r8 zj}o_JOcA;k$ElhUjTcqS>Pc!37)~zIY0E_CL@a^I8oGi0ACN-;(w$^4^$h!`kdMWo zoDs9fDRMw?jz!5|#KA%cItub@73NY<8U0r;pe=>HgeYQ9Ta6(}*FQhp$l!m=9n@0mClmeMX|r z3aW9x&;skl8e)_>&%H(*gsMuP1Av$d6p6BNf&=}%zCt6Mt2B@1MO zHN>(z!_*#8blM>lUccmiv`)1enNWL3>Ml*{=DbQ8F(hZEiu1% zAM+>Ep*E5z6@cL9$BjSufj4?}nR8>L+F4Q?`Hr=7v!n#OIPxle4-1x`3#fR`j#IK`O_3{b>i4C~QvsL+hIc~%1U%Fb z%+IiGLi+6WWCKeMI_PKe)7GDf*7}et?W9q90#+J|0LX^#(w0(jhY}WZ*p#B=j*6p} zdUMPnqT7(_Q{t}*Dvk}v41~Hiso$eU2UA?Ba;%`lC7*k_nt_??yTJd((SYh7l2;A< zRYy`+hce3yXa367t9Zq~#!NAD1mp#DC|3hN@-+TLL$g1cBNf9Re>MfHHI4drw_DLjtfq{7TRzVmGr4b>loT!R#f=g z^mQiD5>S#RgZ`_kTK0Szm&Jca$nKw`fjZ1Z%rh3Bqm~p??fNJH$iX0R0wbgzP#00t zxz6h!SSMnLIK3s*wU1PdTe;#J>4I{8L{MvFv&&gdSiFfkS!cR-d0A(6Q!rz3Yi zOiL6@71GzRL=E;3Be2Qilj*pbu1ySo4aIVOaQ!_9MKLKuXS2f-XM#*@HNmysbukRx zA%3cl`}>B$f-ci@#Q(8@ln_b!OSy#zW%$p>QOvAq6P&>zFYOGLDr3g33iq8MHidV#Tu+~Jw)4I7pn!5J6F>(J&1!R5akD#rvNUM>%w&y z*T7adJgQf61_e4IH?RAqoLBI(wXx0H$GPjNTPXf3;F4pqDhjQQt2VVEYY}i&1r<)%;JMBQW@IdgZNW zBPhGaed1$twsf*>dtRP*db@=oV{N6_d2F62thd1R`gt{@WpSU5z0%aE#^P;N0R+v{ zrAkyOV{lV2J1#X>M1EyYKoat+E}Az}jA4o&ctMe|eX%B7U~;Lkkmn+9`;Mj;bQn5H z68gyNUkk?vOZX?1^;|rF2n3k4@&~@8WWy2`vPW{FRGep2Q2oO=Q&p%JRkPCWlK?(u zS23rwRMNg)c&>=sm(rgjs>5X=#l{u zDooWOaHYZ8HWY^eVU3@QH?RO|lM$LK!*!kmDLr}Xfrx~yqXCC6J;KCnlc58bQ{s4a zh(H2*u+pkFhU~E86_I6VBIWx(mhuIFxf0{ni1jK71R5RpW*?dUjeYFt6sG4Jm58># zEZlWvX`qO)p6MoNPuvUN5V=7gw8ENt^75hfI0{& zR#w47PoREG2|>_y_7seEAoY4?#=v$c8iyA;+|sN-P~z@#X%?jWHh~$NgCwV)^3i~n zU3(^%+?9!u=1r@CUa`#4vw#*A)$qP8l<~u}u<4{~ zVbjtRZ)+$PGVuWfKlTFP{d7E52+q*+-14lq%M$TnOnT*GjZfS)UC^bN>9I*7|utE)VzDyeHgFdPX*$ zl9+Y%>7;^B-$HAK;`6Ezd^u)9zaiKdvQQHIW^LAk#&+!e!-;B(l@`@eC z&eXzhmoq5k!QbWPS8%2bp0=JKdk)pME*&p+RKyM{p#{8(J92D?`olpd#Va{_H8PAi zMJ9nLE?~tVD(W4+RB2I!aScxy7hN)5e`D}YTe7-7H`yBfZ$P)H>npUEc{Oi#c#CMOABYpJNil@geUCY4^U z8fWIu3l0E13Tt2RclgR6T`-JycX2Mo>!RmVHRQ4w>OeP4HBpR{+E7rNs`tq-)88lc zL{qYco@7##9tMxbMMb2EQo=-OU5SL<-`{%kbKZS36ag<UUuF4V2Xz&jUaRdq0z`<}aEFB%8ATtaFhty)Vq zoFXAY2S@Ut3Kt;S!yj+P{h-Kn7M7k%HWUy<3k50}daK=$rJsh3IWVkYU__RJ_t4_o zI|Pni4F)F5NxOy><#s5>FzB@(8PH1b1~A!$-=5EBhrTLY=T8;@7~(ZJ4Mg6wuE;E0 z(3W0+vRhnlT3)j9Z-hejO=Z~!0Ww3K#ootFU|q&3 z6AXF|#}A!zMg>G^numzFu+Z>pk@|Tc*iMUdN4z_X-(2mfbLh~OdJz%->VGiTFi*WR zVP&0eS?kEJ^w%0X#o72vGB_Z>vuG$a=p23hBSYpdP0#=tXx)H}XB8at^8)LR_6kQ? ziH$R`_ZvxrsUAUq-?Xb565D{ni3QF_z;>01%rDuq6aX;*?jASh$9oCWO!YBb*auYJ z4cYV}F@nanA!tW>1z@+Zqk=eOE1zg30C*`SyKB@&&Ag;z*%aV(Sx5tR*CHX219+g= zz+h$mx%s=1sEZ+?a_(I7e;lv-(^iQOS&uh)*OnecArY^xUQo?pTv3GH26PD_vGNm% zIOE<+Z~?G5alj!CI@J*$-Y(Lvi#1~W5qJGDJJEt^zIN^Q`WAfAH40~Bd$2%RYXbd2 z1Vu7qS!5$AC4w>-RaBtF9NIh zIl)avxoi!eO~jU4foHD2aKVdbjwq**x5V~<8tt8V*{R-k8ebFVLsI3T;=trQCKRM+ z1`+a+6O8(#p!MS%pqSaBvMP_6TLh&x4cECJ~Zd5NiPq?h%NxFZYFjuQqV| zBx&Q$W3%oBses8Qh!n6q<`GP6VV&4B$W#%MjKju-1H0l*z4{@db=4+HW? zKv+#2d`)OWc+?!ROYC-E`H3-M6?$B9VFeQNAdNNfq#?_IAeW)?i#|_cC!+m~NiUBw z5n{Y*BbG~~ybu=b$}Q)0b54h+7F&%i!+r6jI+xa(Eapbs+8~TAg)t&pmbzuflP#r2 z8}NA?tbua(=f&$Ok#Q+ypjdYq>(O|!Bt$=N-L<@ z85Ol!jVxz(B&e<(&7$Nc!BzhpenJ)2mc%V9Oe+*6MC=GLIKZ_QGN!PEI!L9J)_oF} zTv<=Bf?av#oWfA56Ikc$RZ@D(H3T};6Jp^tesA`mO&rHqoyWwPjwKo2e4LXDU~hyh zIA*`aIjPF;3-+Nc2#3q=yx3m&$|q#A3Zui5_;@^&NJ-a0!##2OcA2qf@w zkR2HQ+eOI?>BFI!LmJvb+M;=*$e=a?hfo#%E_{GQ}`C5(9gZtD&?}h~R3u zXX1vMyk}IT(=R;W6RYEPgo_$x|je|q8LUdctw~aac?DcVrLgvpRgsp`qGJxA3F1M}J zM<4hjlRfq>IGVdPqv)ooAkatU5M%rPM}OEMx~cSWBRooCiFl#-;?N;2qnw*_J=Gd_nq$`Y(Gl*FJMB`DAb^t*y`|bAFzUFqoL&SCwHTc(+O zu|KJ!^3K}T@ive_mdU>LgR#Ogqotgu=BG@engF97h!PfMgHaBvzg`oZFmkYI>_`Ld zJrw+iy9={~#{4C~ za01FhL3f%ilRQ>f;x7tI@qySBN@xM`XDi<3&93aF{^oI-_%1O>F&S1eNgp25jB|R% zS3g0nlYRIdSMTBfd}EA4KjiThW6#wLXY)v6L932d240zBkzA^vGWX0+;Fdmu-R@$H+)~K!G?0 zoiSVXKJN?@uFs~7)v&vxkVcAeu9mLq~p?29E08&iO z$)2Qt4Jo>(cR0e;eD3fOuDW0CAk=&TucEG1P?$#EHJj<5ntJ%vK?2-v@g8ptP~+s` zIN2HqlMQQAsjoF9^lNz|RT<1bwe2$lD!`WNK?p`_q&Gu<& z2>i2L6JdDo==E`YY)SI4fh`faov5IM4h7ZjxI@Vp_qk`)p*4Ihq1i-@+i1-OxAz z5TyqL0$Jr0Xl8 zpkSL}IV^*ec>Y!Vj+wxqpRMiK1WK454v|;9kxo9piS9vsCEH;o!#P98(TT8a&nsq{ zLJLylP@uk6L-emCpb3Y4wzH-rJ0f|T)fuf17(^)}m5(gJ5@%{hM#QouGL=l1yI`LQ z_sF(>Wl{TT*4SRTrWf@{W0FdHm6n#Xlu{FfZg+O?LQ&VFF0bjnj_NL7SP7jH_nL|@ z`2>w|$DcGZG0n8Y7g1_Uzq`JA$HHM~=k4}E&ZU3NGk@gFh279ej{qfy<)%{0!~rE} ziR#YRr$k1%41kJ9=PBel8)fetI-h#aeW6tCTDcx{+j7L;-7*jjGxeVaxikwtd#H9v;Wwy{28aqLVd{C)pc3{0V^f z$Vks}u_%OJrc;;(E+IDA76WjU$|}54sfKZnWyzUG)E+EGwd|xL6(-(F;6Su;#akEtEEVP1t*)g z`xDH-Xt)neE{*C0^j5ShP{(<|f5`k5IYfQzUD;QSCH{>OG4ebC9bdCQicn7X8>p;V zGU>}J=lABvD-H%5p)-56Pc#`|rxTQ<$U3U@3?q2Nn;xy~;F&5Krg1NtG1! zG)S2a@81}lH0u>{uXIbILgcS7IU^qM`Z^lN&U$j+J8}$mOgiUnDw6M349a$6hOJJA zA+f+DAx7V!C7iG7_rBi)oWd1?1)%NJA61@$ z{u98s&zSn=9Pm`5-yX#?NBEp_xPW#cNZy&Y&YE7HNwZVtOE+)uGl2yET@nlLbR+M9 zfB+A)zYQAX>jtTS2CvBEC+`{&EtyTdQsr8WhsGY%5QHEO_=yxGDZtWRv>Xo?k?M+%CACCAb1{!izAi{@DU%zbAc#@k zv)&U2cM31_@MuKEAmI-y#^27OetRt}bbhE^(|?Zf35>9oqQRLZ?xCmjH{|F8o<96BxlC4$E+KSbnW8i_UX@EXAFnmMT91bR zG_AGkRKUza`bvo}stFc~s(h%xZyeULeV;J-F#TLBx-S0`cHCtAydYwWSSxFO4OX|U zclp^5(k3oO}IRU2eon|IW+FMxi zRqgx;Tc>{;6TQkHeO2*KwjO22!$40e%tj>fIpC?55UyfHiX@6uVHxuRQV~*H#oH4S zNwji1dX0fwER-o*inK69Qh7M5q*j#d6kS$WZh8e-IY$xlZ{SFpmUTkah%&{{&``4r zOG)Z#kS-Tz@0;-n;$;Jh>hEPhkni8;4oM`ePCf$}!Hp7)qYoO%)0qlMbG7q=WRgs8 z@{mC~bL}d{)9@+$vPoq@w>Lq#!Jy)0r83UEf$NDxPeQTrs^`LM#fxzA$CngxW`pyL zWp$Senc-)x@|>$h9O^XZC_ZK}k|I6YfW|6lDB4o_Q+BE(#^7!(=rUnWo0c#&n=r88 zSHyBuPELjz3K0-_MiXsgEGslk!$vSB3CVJ;)ndjIWg2Vp%sS0BgN>@9&Gh9;@~L2~ z1kgvEqPE20!m}>6A`LD7h;2c3DO8ZkF_yfW;Ear9)cOrjpECcr5G1YsqI-fR3S z_T4Y@=suo`=u0>jAf3QR+lT?2-u4tue-gtUr96J>IbVf>#YfCzprn=HE1|6Yg(ByqgBXR$ zTQ~f6HGEGcxh5Zn8&|LwiW8Bg`9`Aru>t7iog2bj3+tC7ijV(Y#fTblk|+{pmfwf3 zvxJkRrH5Vnn_}smxO3z+>=;CLLFed;VmJT|9o zZ1AnQmfsEOks6*2sikdK?4INt%WkG{1si=Olw#g#^&j9wOYLP!lKXtb>ZmqverD++ zA?h!7X6I!ADeTn48><*R1%&W<^od4uM{=p+&NuxHzhT&8Zd`v8oT!3+Khm)2M5sN6 z@7c^}8<`iVVz4gE00F9#f3WL;0A7pRJks{Hf-kGuZGR6aRX)Uu5ouQ~Pm{}hG5llP zCvZK1@ji6hD$+zIRt6h8ILeOl zR<)k0t!uMLaNUSQ5Stn)rv**Nj^%Bsyc5ziPs0&eR})bAoY)JD*UuQ{hF{QX2rra1 z3-e5ec#Z_;SuWQBIbs`acS*fyQIV*|s|(?<_w^}qL#kS^mXk-g?fgv$L)qh8^P&`s zqU6p+Dc2X#R-(Go$MisYKvbowOw$b#{GPo%E|O=M&k6gpx9(_Zm}XqtL0t%mr915uJAGSsDUvBZMzlwjn1{2TwMxuBMIU9r!& z*2h;W+D3lUL^ecAN9#7VD2BxpwWigp%hK9TEtfR}KrC`Qfg=IbLvda3c~d0zCp}n^ z^Yp*H!Jril*~0@hIDO^5(>QZb+xx@$cDqG9S4-Uz*Wv=y%DDNmge;OaFHXI&#Qm;O zdS_dutyY-g!&7rTWnR4dkqdVC2d@HP*ti%tAUtSssF^LzI9(Q5*_$KE#iVPkcNSSW z1YK#m&;#bw;XTezyHvlkC5092bc(S4KuprS*9c9$_)M3wcg-q3f?+wag6Q=>VMlF zUEsb6Uhxwsijb8YOx4M_c;+QXC^YRY0V+}|km^^9w~8xJKE?v*FZ5N*F980+!qGJ@ zG|iJ&a$mygJ|3GC3_#vLN!(2S`?z3}BXFT(FT~B8^;$kzvy! z(Yo~g;#J-O3)X*$GjF>2^u4UIr#vnP}fViJs0FYcI5Mwur$ z#;MYTf=V)!iRKblUP(=jRrP12!%nMVJ&MLgE!Abv5m1fQ{Gr;uSHQ;{;LUT z1ixJxLS_2Qr5JxwHKmghNwEm+_IbNsh~TRrbBpuIW}!b zr&&B+M*R>{(U?#+AEl;3YBRaexYR061`&JRsaK^oQJMZ#gpg7X z21UNgPYCbD_+@g_?bPoF&)27#aWYc}zo`m-71TvVS5}m2Gn*D2;S9PI?Z!*$(?ZLd z9)&2da*B#7lvAU^LDWO_frA%bqFRB&R|QNn%he~vc0CmHn@~|lQP{ic4s>R*gm{?E z|JX$#*0P0H);us)spZQ{B(zW!7J`V*L!nYM5ZAcYu?afwGuurhBu5g(S@@7r#3$)5 zynY1M2jF{gW~E50MAZZ%>W)JdTU(H}7VfG__e{cO2emU6dg%)%a1LhY~*xivXa6qU}m9vF7mcu%U&K~*$El0W``H!C{Wlz~`gdI7K+E$s;F~AGrfU+@o-{Dm(=Q?(A!KS_m&VqN$iJf;3qiAD)Z)_}43>K|mdCD>&!wL7Xc#A~yI8 zb;?2B!`|#d7r1*b;Ie{~jlLjAEq)V49_rmc&FT5k4(xZg?a~_t*U5nF&)EgnR)2iP zD7!?ywps3_Yp14O)`vApbFq_@Pc29A7z8GLhGaYu#P{Y9XONE)K5zySRmoxq4uj8>&0>y+u2ti&sK^?J|2Q9^&!Rc>3Oev-E$p-2`H1MzoCUG+ z6-U3Z6rsE6iQe2jA)GDKR$ZfqO~Ai>#8z*BNs-k)j`l@LF}gH}D<;b0F|Jc>n~Vh- zX`29S3o2*j^EM-{GbTj{q;RCNd6h0&IE33wSq+GdU?qOB_d>%wp(^`uv`urg_@z0-WLx_E`uU+ zz0}!VF1HK$9wWu~ZFVX!cneI})~^E7a6tiRVQk8~T6)0`IrG(~P(DZwL6!qmK~&6G%NTl@k3tl*a~E0AkVs zdU)E8X|~2y$IU2Yk633cb5HxDiV-5P<8SaT>Qowwa+z`px$1q{JtoN9iqy08N2G1B zA}uzW7Ov8m!xiD#BUw3L0~Sh`#}&Gawo;`bM@q)|9Q`v&N_Gsw5U?9V`5@s={w0j6&#o^OtO622zB8G;`;hIuG@D705@G= z>+25ZSqJsbkv68Ra?iNzwRONjjg8$hnoFBxK6MARH=|%vf2@jkIXfG}Eti#N$!aNH zbpNw%`w@6Z+&a_DJuDSMQ4POZChGd!`(+AZI{u4fb6#Q4Dy~%hY74c-Qm>j_J7H>K zC#py#zQXt7ZO`-i58Rdk3Vhd`Z?%8NdAf=E&A!_gxDO}fR?O2seq5Ze0AI7tG z1y2iepH5}&gn4`9c?*G} zf~Tgi(kH{*bD9o>Tz0Wim`*wE#qd6)Yw?PmOn1!lKN)=>9yjb_Ej%^J5C*h{bpj2Y z%nLxiYUZUGf-bXT_nZG{WCYSTZ4sv;_HW;N(V+XaDyf6E@G16N)+i-R#vrcKUBA+E zJaQeC%oH;|O|ibz(aam8+Ou_JuHamkp-J3ynS1mQ#WAc*3rU+Z>jMQ`uS?oW+g8#e zg(hV7v`IC!r57rKd|V8N>tda#$+U~-)1arl=~5(6oa!ES`dqN0CVFZMr$ak?^0UL_ zg>x9@1j1g6zDPWz-lvvWJH36+i7_r%$02sY%wl^2#Hn?o~D=k|*0A#H% zIzlHoJCan@Ln!!PO^j&zDxGkxiu0a91wc}dYm{VLP%SoF3s_evMd1Ro9f7pai4{nV zzYc{qX4sVAG`1z9}6 zAr@J*OBle7!B~3`M^&}x?vqef$xVw<=cIfk0VMF&Yf1ujDlw0`YcOLqiQjw~fV)vh zmyN16Yi#4}Z9Oego$+XLoaTi}S;996uY^P{*g{`!_1j-N-c31 zWCRpI+Ov%}^VU4HAcZ(4Mo9JEp9wgGTU{|34)S9L?p7bhxvS+zBjzvz`X&8Z!`vCM zfercNk3o6p{7>vhS(MPSx!#;^}8yWBx zJ7-_w{ZHDDA&dl?gJxANq(0!%wlfg*G6pE{79n3BaWXZ<;dwis$oDqApU?=}Fs3-n zkkT<5og+{qT~s(t9%RDSeRL3Yu`%FzTprwjt)01L z;5@e9&u`lvoq>lI4zM}h-XK4Lby41ZFUG+27G4Kr+oH)kD6o^w13z9lH_g~0*7nSM z+*yXuR+ z2ZQ-*E{T90YW4V>7uzryXkxND{*^gL%k#t!4H|CDEeci?7g%K2u=?}^A0H6T_U~m& zOXhNit*0V4;}1ghqFwTT#-9@Jj+Wg_bEU)rkw5NApLh5|>O5{?kG!C~c0@-=e56gC zBb+pA&W@k6`2YNu^No`xc;&C(XZzQBi1Gh;wK+K(SXeg}Q*EuhH4VpDS16{Z2eu{y%m?;D<%_y_yT!7(rh;s=N8 zt`pv}F0+ZG>SS8E=XjnxsuL51Fpn3Ri1qZSq$BCp#q;% zD5Y&KhXAQ{HeJXDv=quIDy7t^=$js;=EZ3XB}h9E+R0qeu8i<`W6!7=X)e1bs1`Fp z)iiskXLrSww5A=&3U>`J@W#nPnKDW`9>8jYf=btXTWgz4q}Bwgid>@7($4Wg)sIbP z-AdG1fw`#Z+H_&@Mf1ZH6k-^J5m4k&V-R)Zug@6(TVe4_yhJ2Y6HdQzED--9(O)^ zUaAm4KQzerkSU$MnS=ZhC4m@II}0eG8pMPyRMOFNxmO3ZkL0q@R~N^v)y8xns&>7J z7YIRWu=&vf&s>`1QyaD8y1qbF8*LttF4j2VprGw_|ov4Gf3TF zlThNc@_zsI^6-A^ZH-PCr+$031bjdCFQ=Dvd09y=YRw5yUxf1O#XdM=lp!t!pqQq( z*fEzeFfQ#Q3;RPPG1EGJ6j@7E<=a;3(Mr?_j5>#s{1KoNhqF#(mIa|GZQS~wy23#9 zX7AJ3fKX?Jr76KpaVfAQHe=i|jxRPT3cEjKRU1n=+jo|l3zpIIOE#aLo~}60=4mZc z&F3vMK3>=@b(0&|8w20(6CT3FCe{gD?N^Z#4+*tX6RXW89d173*v*5M9$6L}n71_t z2@m?fG{`!5ko&PVN0Nkc3JTG~2R?T_^S0*xpP9*+^g!5i^R-`-zO_VI)9HuM<|@W9))M_M9d8^txZ(Y^xL5LR{QkP|-X0X! zura{T^nb@^-KQ$>wAf@soX3t`&wEyul*ZNtaPY|5W6vT~6C0vD4(*%hF^mjv6G9w0 zpbQ}Mj;v<^ha3E?AoKA&XM$%N{F~jUUCd`d*T0(ZxyZkBps)&VLmcpIpK|hi>Fp$N zG${)eWU;C*vF)keAhu7a_PzOyC*lI^QJ|rc>|uvuLI23dNx=;yP~pDuu7a_W4CTv8 zpYt7UqPo!L)4^CIBJjWO*eK;4E(NEyc9*R_OVn-pmfxk?>)8KElo}*S#)~Dwyw`0V zsGI7=%#u2b97RpISdUW%`Ywt+<^>X`_WDDEa&BVG{jCRaUPfn3P>^m`VBDvAke04p z%fV@~5H@{AlnVg1xZ*`mHU`=2^tb%XSlmP?D`KkKMRt-b?v%8Ei!?fLM z5mWY%w_^-I>5(W&f@%)YXJcgX4CTJ*uEHv0v}6Gn!y+Pj5upL(#Z?!dmW$|tE9{M5 zTsGX)|GXxY`Y$uJJ2n4NjB)?1%|Q2*%8>jX$x@hjue(K8 z@9k~hoKvzG@^7E8U(DNK^G;_$TJK|q8?%94?1nZR2?OW-t+L52SC*!uW`kawFI)_O zXf|&SDKqG_NZ}jnsT14b`_%o^16zj0=fQx}Cv19wHF6LcbMoA+7jxEgly5!RajJ%1 z#7n@(cPUqJ#??#5*cBjxXdb|bd*tO~=x|Wqk^3wP>DHq2&n3~>Q|svwJIXWN;;#BG z8S`L7_p<`G&x_7{O0X+qt6qml=gRf{kkGY$Kq4@ml?*>{COwWf9N8sr)WS4)%t2#^ zUV)rBVa~$ulZb^TH09>1bV6J-cm7qbi-L6R*tTukwr$(CZRf;JPHdgnwr$&X@@3}Mom=0XJ3n@K(e&!93W^X6!t?oHdNd)hqoAHUe_9DWQ7Az0M%!?yM@reQAd*HMChI>JPSRt^ zd2W>4Qa*e>B>Xvk1@zoEMiMDS!ZX_?^Zj3R=>NqM`+_uGrv(H6sQe{@Dvbxa%!RN+lQoY7dcv`2RxRMk*0T+2WLFD?=zFf3RLk%Ud(p;>{ zu#RMWsk*XjG~v!YU2jJHCl>ez<|q&@R{cp8T<-IFIUT1MDcsIB?*;%%uoZ ziNpmF5-!nTEhQ3+!KD7b$)%bWtH;#WWF>BRLX>|)TH2Ogq92{l#=vLcbnRbNax+Ce zic9!pqo+{#CS@=#Xlx2}>fNU!3-|}e&TTX_T~Nun46S@G5wLw1!pLbK-M5zaI=)R~ zR~xk=G~UyyH)qB}*vzVCGVOM~F}y{jH!$&=ONQSAweT))FPgc#l?U5@txWv?FL!nq zsHf^i004lG-{-#rGHfi3{zEorqH{2&v$Xp!q_%EcJygE{g2=~L6fMoax_Xq5SS%6@ zV~Ihv=?O8o>CJlgAfoRMEa)MtFm`4Jy;jy0%r`yA*YWq=pM2Jl;n5gADFZHBdf1oC z3&?y0^IW2oF{7NSdErDGr668uhMJGPkAD@7wt{ts`9rU(BW;{ff3Tb7>T29b;jEX@ z4XZTPET&_)6?Jdrh*J0eE=%|@by2VFe*1m| zkpKV1g1XxxI)mRU2L0PL`0o(%|HOfqn4109d3{y-Qa1=-IzO!2H-ua8XPrOR@w^TU z6KuDQ33zrUA?BLp$b>%<7XK$-$B-4sL5|&Adls-vTZaPV6Z3>j8%eP8Eu zsP*~@l4s)dXt%Qd5{%^B$WDOBkIe6;>ssw?Z8)oSV!vC209ed=tO&-y_=+^PdzH4& zS7pH7vsxrHYzsz{E7ZbH3qDLnw)fDn2N72cO%5U#?`gHQH-zwHTb2BBs9BTWiEy7( z=F$m^YjWAOU*OEL>#XSm(j{6pL!oC@gYvnjiZV?uuQf~D*(^V`c?5a3WR z#Ps~}+*VgFInbhWlbLdX(H0&J&O9S560{Ir5kg`WvwlL_1W+~ctbk*$?9MJ#Dx^`z z__&2?i#s-+S&U)q&$N|EFeALo%-z$MA9kpw;)rY>p=ybl5h{6PvnJ4;xT@$esBrB7Usy#{6tOvj|#;0d#!;Up zs7x)yw8nmqSJ64_G0Jhv^CGUan^;I4j76`0aVRNMRzN$eYdmC(*B!*#{-$=loo98o zb#`dJ-L`aJJJ9QZ#Pi^B?W`P2G0y!%Q(AOXx;G;JQD#> z{%O<~=r$S$@z!Mcc;{bdnSE^olqq25mxYn8LTs#%5Z&_G;(ej0+TF4)nfX_yyFCtc zWs@xa@AQp{O&Le)k5HiJnaFUGKovi`VK=9(`gmvme_B^U<*POrSE;(p~3Wzeh$mVfR%rf1OXXmJClMtBT{MV*&bQp@jgk1pK4|vT< zO%`57Q-{RopG0qS=!6{cYyJ(hYB79q)P)!w^QUX_u|Y#?z(-SgZV$pOl@hRbuv*YOR&l%1M4+LQAr zx#F$fQk+2C{dp!2J!bx|v?$|VFWm#iu|DaHL-uM2qmi{DX-?sxbS|Zj%J+nR+4_0s zln>S>R$+lixoFn0BGhU)@I%_@BwMb?pH6O8$f9xqz*PF9Ycv-ab_M>R_qkjFZrr&x zGak$J^6W^g@`_0KS8j1>Z!v$o9^H{9v?IVTYNQJR`?>19O4Y;wMdMiWB z7Orfn#$I4Fnva3(m4@z#?qiKMe`n@gh3qSvO`;7bR0|6uTO26#35cd)NFeVRb^KIMXefyv8 z{Ve~dvZ-w5RV{^n#@A}g=W5K^Bxfcd=jE1nKHpou$ zK?jpMiA-k*fD}lSz5h3njX!VgiQcwvA3J}a3A=)|4VkNIO7GkNc`d?$kkb%)IFC+j z4{i<+BrD~42c)t6W+$KsxIGj$pT7Ug*l6F@7^H(%Ur#vShuUx(=nR_1a54>RUC$iy zAwIOZh2w#KFaw-rS$ggFk0KP(Jklxh#Sk z$>#?)7D%f=-^<@GZ#0>6e1dnXIR?n2+gwEj3 zAW5rcl}LmTY1o18z5b-p9;wzaY?Qf(9|)6c&J<^Mjs$@>iT%JQMQq+!-R_XVOz)98 zx!}l)T$~8QoN9@>iS-cz9)09=Tpr~qpaB4XT2kv85&PLyqnk?cpiKD?Klqu;n_XFd z^0<)G1xj)5(Gd{U;}$q5JnWUV%a(pdjuf+-p~fYYO9#0`k%E9_dYI_)QK}w+VeK{>k8dBSTR&V7Ee7gJ!I&VKvK{U?4Uq)aZ(BDnPH8g0Dk52O{zeEOB$0az!Hl z1T>PnnsUQG)?xn`+B=BTEs5HQ|GjQrgT>T6wr76)F(;NK{JT$d#q@WPgLc@#;MuBN z(WOilTBt3Eu%xLx@UIR(?J&>f4Tz<i5jrw_P)LacJl-L^OVvJUy7Q0okSfK^l zg=>dGwmCig&@7f`(Ngin7bZ5(*gu!j)W0+ z|949u#{Ga@Qw#uM{ub=<`bO`=m%J_ezUHbnp12X=vtlOn&?Y=I7^o8RmO3KL% z4Ojp0OBuXkULy{+xc~vCj^yDx8~t0~1SUz`WW&t;cH>>CjRXru&OAovypQ-**6!M& zM+^6?^-p|X>ss7n*PJ`@-jr-8c{`f)%`+WEGgCUVnA5X{|Csf&7JqwCnJZq-*>PgW z+Yzz&kQSN}O*Ac=WPRjT@FJj?PlC8@B$GTH z5nAjk?+POgixftz{OTluL=P&sdq8Um!mV^Y*D=yuY$ntCWeNr~6hZgVfi@~3jiD3< zb%D>Km7^4423yMozLkV=4OAVMNtoZK@)kO=Q!yddHyWBx>ZLbkk*@DW_5T~?cjmbl zBmWkkXo8$Ec7Nis1aYTi=QjF;Tl2qKlGwGjyy7a zKxQ?EU`!xLL(J#e4=!>SpG-LNb|kIBZM^biRJoIE!zW zdiu&?;VN+6xXRh9biIVZ`Ds-0+8+?Akt!1yv zcJAnbhnbar2KPQqayNqot5P`kvsg4Ar5S46f|r|ljLQ zSJxiaV`tJc`eyx-@h@b5boY|}c_lX18gD$=dCNm{ZUsGYi~wm3jj_!e_~FE2T2FpJ zz~ock8vg;Dy4grcm`J$+y&9>?6R!|`1d@y@6EH^9ZDM@;++s=I zdvJ&0iemmJ6sTh+WE{s~(`E~wo}0@o_6$d}0j<~Vg}vH!Agp{p!TxA-5r|W+icWBt zi7)7(F@3c6ewvmFc_&?|>X3%sx5|k>6SYbMR{4rW=p8=Sl+gDJcT=`yF|weScKAS> zc&mWMjbGojv;&xm6>Dc>>^9b&4ODhCsBF6YNAfZ z7Q1qlLCvA1Vdz|`bz93Tor7=0Z(zG(5AUA)o+{fA6)|4X8(D0K4T8?{!@=CbTV^@Ow7qw_l9>3) zqB~XevZv4{T?jdtEKK{%g^Kc($<0z=3_w% z;B4Ct;d;BA{T&fO!>bQd#jf5mVBOXXY_{Y3qm7-O;JvwRRbtW}Zw_rK9x$wmh3Bj^^j+Bund6zo*b3U{8#+1H>qv zC6m6AqS-kp;VZDcLz?R9?R$brCqfhjv9Cp?>Vnb>Jw?vrD|%Cmg}c9jL!;bSuwZ(T zAjwU#DEFfMKlxt`w);%b6nzh6bk0T{M(Jo^y`WiF$E-eGo|U_DKD{U!qcU zkpG)Jh>*?-Bs3^r)!~s4AlLjMLI3KGx>Mv97L4?7zJ?V?EQa_uDkGEl+Gzh@1xR95 zao9O1+mC0exSG~Q0;y~Bh`48B8z}Yq@)m=FU3W`D!X3p9ne!anP{qB~3@lZ<&5J4v zVXsxkPSklitSvcT7T2qT#$V()h3)Nk^`$!Rdhp-?;^Q{WXeqioAWNAnY=u|Jgw-ON zo21RfB3yC5hi-DBlnl~_z{nex5~676kbmTN=1cj545YgXK^iHIyEEST7QY~Zqz`MoIBCqYi zzG@TuyQ^ZVuu_Mg`eHFTjlq&S?-|t|ZsQ$e2hLDc`|h2$2MAE1HP+mDH7l|Nfx^LT z?oe%4lJt=T6Rd`Sw`kW`t5UUOz|JDGh1HZOEAOXUo=8&c@}D3XYep!sA=j(u4*MAy zOk<4*(PY{UEwMBe9JUG|W;NWPi_aHO-Mzq)_$|8K$fcDG48IcgRBt4 zPg<_9*ji7b`E(`N$yZdxuB;o{bLF)F-c9RX0gde5j8aIJ_6+)f0X(W>$+YdnuWWyB zdaR3L?}zY-Bh<+MN~LS$zn$zPVdEvUJeU0d{qHLKf3;S+pYN)_)P7ql(}4ejL`DCf zI@SLvmalw2+>yl_Zf8zwPwUJhO-zijg*0HY4+4^2X#i`kNV2lBjrSG5~uBs$JRV++6Qvix3;&}LVmnAYfmel$&p2`nA4TeX6O$PedB((qr@ds zXOb2~bBmNwWyP%$ho~|tXmlsT8GW5HWeVS7u}Ymmyi*QOsB#v1&WOY*(9b9^$p;_| zA5}rD^M-y$5@rq%YcQ4}dJaz%Xj4gun5~6T3(9Y(e#&BkfIM_W@ zpO^P0OgEpF_Zo>qr{`wCy0a;3`TfGNQ$IaB-YpR1IqGXK@sKubN;1uJ%nbuyKShN7d_C^L!h{L*2NFKcx4!4b_9kxhZ}7|AcksKsy?yc>d~4z2^}DzEKd*O} z&?W(gRl)gjIyn_bcCLH;VvUi`D5^08+M(6-aeH-Mdc1sl3;VqEaq)0FdCrVq2H5Yx zYmnTK%--8;<92@c2KC{-9RViR`QOXw4dUUyFT5>4^efaqcCP%L1tv~YTShnVIZD!Y z@Ns>@8^dKezrQOFk_M7)9L(*uwU;7Z6OQ${c<^?Rqf%rJ$+xN`m)l%U$3-59uM~J z0H=(9PH!4k+Ly^zG>T#^ym5nV-?*0wsXoh#yox zpii^2h|Rmf(z$-#-A>(Yr1|gQ`fNCV^Z_Ro54?12MxOx0fbk>Uo$bSvwxoJ5Z2t6 z!~n8k)MA8m=gNnh9e;d|c!|rmDlBHu$^!i9oe1l+y*OdC%@kpAjs{W4#b}rU*292rTYN$8{^->z?}(ucu2v+B+}G&8rxBeg9P05D4Fz>#Zi|r;T zuz7PjP@$;J#{NDE8IaG$z}D0PiMslkPx4(HjU$LHoM1V8&bZszN7rd!o!$?SN-g&vlCT zB>fe-%R6G-Q1Bb+URB4S`>W{D{NumQAxjMgp;Xwyv)0NLPZ%9}{jIMHqv-FB4fPj` z^H=)mtnW}s>wh3D4845bHF*0+t-#J5z{nqr-#F>_uUM^j*%{te6}y~j@Kb|iccwgJ z&1EBd7{&M~zWbC9&m=5;<`hIC%038x2uEohc#=5Ajjr7W%|ji2=yOYN?QRt(5LS-` zPvWvI+_jIt1?`KrvC|p)C2ALu5jJ4&JJZh9^RIbsysbXo zFKWHd*O;5A(e?f1(@%YR9#+3{>yvu6o#{b|_Q3an;$ATv%CI#+v+d!e1E9re(1{G- z>D6&`5ol9NVRxwgrd~VxJn%+zUxE$&Vo8v`jjWBO62O-8$v>LJvuZ7{Oem^~nM$ zTjcsbJ*K7mTHY5}K0{1Uy%Gqb1Zs)l4(9aHwg!Vuz%oa#{1c_L6ro(BD5NXWNQw$Vk!CXq?=ZO;$d3Z#v=JcL1oqE9hGb&pmq`R0%1?`yg30uUB)gUN+V4<+0kq)fu6uf6#=oDtBvKz^Y&UjO zahLMVT0npp%Pm43fe`h0QPJ>?)+pAdqs5JkCc}O+=v4X}bp`aMk^Z2U9ynd-+0PKs zHMrP!`+v2k8j^SbZ^Co=tkR@oJzpPC>+#2liTGGM59nmEGUJ^diE^?ztKIYE${$3^ z1Z=pOy975MniZ67sRtZIoJeg^Z!(-v_u%iMIaz+~ueh8%oW^Lh@|wC)-AhJ^w>@~y zcoV#4jv`;wEDPVeMGw>I+S^?R-FT`<(hu9#tds-oRNH1qp`u~6wt62?RRTH1AOYy(v^#AX`FTFM()WrBc-BOX*6#47 zr36;y_d*VD%tA`qq_?rVyIF>&1WJvY3BHYqspDR_kXFm1JR~Fb8nocWw*A}A`D-_fT_FHrAfLL5l&p)U>4Me>^5Doe6hT>xd$*__ zyMZ{1t@+ApD6MLq(MW~V7NrbbNmxm4Gg7N++&uIhAmv;RY<|Co(@~ge#pi^0@Yse; zSaU=Mk8L3)iQG>1m$4Ic3BrE$&*Q*R_li&o!hYz!p&qFvLdMZ5l9WHahv1LtlDoRK@qmSdBw{_W`dv0n&-W<$_@_uP2;r$x|)~r_3rPB z=cJ46ExxHLbtU&7LX}U_;x0v-J(p+*R%t`?eb2BE$kwMxj-huQMM3&n723wmljnRx z6;t@nb!+`U^IEs`Z~!NcHNIJ2bWCII;g&ONqLl>VJph|R+dUMu>wGVojw-u^QG}QJ z`X)9L(Csr{Ju2w}S<(YHxxr9sxz&diG?-NLVKo2XyzuJfSFC_ zAy$8HIDe@bomuQ3Pac*6C=`ptLw2a*M-z*9K!DX$)RqaB+nTgM71u@=;Gdv$J5}{T zx5jA1{h*D2Y&mFMF6t@a;NFqp7W$kml=SGyIyABP2^%3uIDeff>-6u;ISRp9eU*BA z2H}|SfQ^tuWTYO4sHg-pR$T#j)sfvR&~}U~67`ZV$+S2Kt^J4!Le- zk+F$_oN{CptGu##&{J#g8~~cZ%V#d5aifkbA=>R6qP;ZWnHs6p`;H0zAl1#K#Q<&v zb(5`C=y5=bm)zF&5LP<1EiE70FX(F-14g|s+}|%E#E0SC zJFY$WUcj?2@X$Nlze_ySe=hp32hq}&j>#i^Y9P_wKMfCpJbuRqfKARmy*(R0BLQVI zJMex&?S;RAHfH*1nNlzN-J5~~jZawoM-OxHyRSa%*`ejLiOkXJB=Oz^zq~XLok*avyIF`48k;u{IpcQ z1y!>u4_NxclztJz{p)02s+e|y4V=FdyOYN!ynqq=?#Mp zy89HuX0Uw;WG}OQSOSe~BJXiGjhc~80MPKN#{<&6(r6~K=}NMj`Nj_}70{BjrZGaF z`$lJ+?G-0>h!te-l}<-5^t!0r^9{9`UG+Oezb$KhVR_C#-6!gLxW~qHtK-(-Sf6F&`3M{EuJ$S3?PALPu*`?lRf2^okzttjlqJ5Cy zlv+&h(oxShy5`SV2uktE9BG^Tz+3CeDYLK3lzYSg0@M8gxENMQq)Pz$Kj}u6K13#D zzFJsUjxL#<#?-5;-%mr!lT~JtvS-Va=EJiwIG}?ekdx955|s0gr@anixQ+f5tnYc; zaLR;z5+O5!zT0zuI)Ms|41t!Q6StUJ^jsjirb_nw+IF1x*$#D~;$8L_j@GsJpQBe7 z>(g@zH_O!%D`#>6v366{F-@sVq@Bd?=7`a3c|hnVADXsjbonA~5yqE__Q>mnixWu( zydef1@2z(Mi%`_>(8azo;9DY~NbZkEJ@1)PN!ti9ak`34`2%R>bOM1P(vO>$iW&FS zwsAz_itQJmrgEp{lACo-JC5Lc)A?lvyb64Wx?3OeabrjUomTMK9^dX-u~of&!iJ*=rl^?Mt@TY9%Ub+Vm1@=%ELES&lx%*5G+>*#T4>6H)(KB8O<%J zHi{ymjQ<%tT%y-ZM?#9BmCoJAf}uO+#1$xWmEGIQ}%&#$Ej^OxwPZTpv*-LUJ6 zhqYDTFA(~o=yLtbT|8U0Pxm1;iak-W{4Lym23}C%IiR@!{$p${UyQ^l5z;dQg zCVKV%6ybM#8=6#)ZS_Lz$37jB61pEPuA_g;m!~7X54Vfg@4y(x{g-U64LdOvX2-oO zj2}n&JD|!KW*T8|v_A~(tNURguA!6fhIWf}LvdVgVB={}b6`=Gu$4#t_9nWcdT5mz z@z?0h_(ks_<%$9lcA!^5YD(lXSY&t1z|9{@1cz2{x@o9Zsy=u+toeeM#^uEw)c~bj z)NyqR9mmJ8)Rq7fbjsOXF{@Zn1_`)y2^!q-ap0t2zHr3bg~7vzUOrA^QH1yBkgDDB zbNOh>5eRRS_g!K@{Qct8&T^xI8*YL(+_t@)zJ$4?1nzkr@o6> zSz>KyL7J$=8XUSP+J!$$XvH1wJ3EYxrg5^k^>HzHTILPO!`tZ7P{Xx$g4357XUobK zivwSx*|pZaS?EaH@9lj&Hc27erj+$TxW(bK!hfbu9w!aG{#_%MCuuo77>W zh{A-Wx{d#!z@y&p#5`LS*DTp=X3~!2vev$v2V9=ON&k(ENu3-@f>v5&YzB z=&;WM?$8pMe4T1<*-mV7gw)@;q?367!$7)cCOj;Zz> z8OBlp6=J@c9%POdKSRqd1*m38UFH;6@?)!TsXcDmX~L)y{RAVJ`<|b}IWO>XpS{Km zuQNQ&c~#;F46m!mWwxe@L%?=srP>BOz1xgK!4=tT5aCli!Du=gk{-O+QCoNw!Bwu> zSF2YdtxJ(OV|%%-!Ld09X1EfFeQAoc_GVjyz>Y_t&tDxON#Ruf`TVV0#@JiDrHdRgHC)=x@}EAZ$7?OR@0V1?S{uGnJ%X;f*^?_1|M3DPlXpUwV%|< z?{Ny5UEM=kC;;iXL96@ukhPZntK#yNEBOu|bR4~&FHsG@B`WAh;!QSXTR$xipqY9lc_#s| zh-8nwyQy=St1OvAXxE4 zPBX#dAVQHh1s|e@=04u#Zp_P{6c!1GgrwtL9#1eZlJ;ejU(s01jEGP4f; zkw)Pt0H&SCX?OMZg@xkRmAN|6 zt|~eyfCkAvoDfzu@y&4DS0d=1`(Ys3sE!HrAH1xErR!wFB_lV#UyNywYFCx9zqvT^k%omOn1+Qe_hF5MKAoN4_%NfXFO7DIeX+K%ky>%6XeJ z#Yj4crS+6%jP5D80LjB=G*Z`H{IfS8fvAnYMVnHZ;`o z`%J~Z>XPh_QaA*g`NiJySTR3yD)eu}$10>^dxKE~2RimL>(z4c4Jd#V4xRdSej^>6 zx~JR6w*id4-ODl!_~u7rw1&TrEB5C!N_t_*1}F!XqEIX5mLlJ)M{TmmIkZ4XypCVL zd72{Bm?RZ67%0oglu=i38l0jPa{XzT%^3!A57`Uis)iM9MlQ$})!0DTeravZ)@j7k zK2Z`vo`8`Z(Wr@8nXVFi$J=(qh@5vxaR=_+%XfAW=!q)NxSrBR_)DyvIqz{7M7Ilg z9gVgJWy}X3C~~fVhV({!h-hH#%dmAWc!w`Le~Ha1D|v)H$5pt;kb9JU06;=t(Ve3> zTtb;krYg2k1Z+CeOoB{t+)2r;q!PjazJ0_5r{IP2>I{3xGEB76JeWkIkPUa46kkeM zb}lf0`KA>&JH}Va=KXYo)}w{#8d*_uKO&n%;l! zwd6*`U>npAT-hq4y|P2!hY+8zdXdzi6b@wDI#9 zUAil0I7`28xXj+OQbeEf^i1|SqXQ{A(M!7qSx3)(;3C+SY$RZlUhnk&UuaO-iVX>@ z%Ld-T_w^;`fP$0GC8I!8Mdf)=mD>;3Z#yaBmTPpR<|fSMn^jwW(^T?6N@&zoG4@_; zV5n(;r<>xHsJ>kOxGmT_uaudf*}2F?iVkkpVkCY}n%%_CLsW$41h#C9V5bFQTm20d4d7N~TM(&M!!`P)w}_hK)w=g&92 zw_FR66~|65gACnM_e4)Ocm>tw&dK-?kF&-rUXQ$4Z&GZ8I?4P2j?=-DP*+IL@X5>< zF9iLN<3xSrWELdYc1zBk2ThT&xpzmP6VIj+xw@tHIN(Yv?$d3mjyOGAC*bwX<9b5m zmK0MUc-zMu(W*GrC<7c53a`C!RnYyv@M%{uj6+gy2mNH!WW<&z;5wB&*ptVD;2)%e&~A@%RMRE z_Do781k=#JOUbu@-67EY^7|7Uozg}6{fEHUE7)VCUmfM!Yl6pj48tsIe~r*O7!$y1 z&C!06yp7m!L=0K9385NM6_gaD^$Ks316DcG{3n3p=NmxbE6uDd)VOzUT%^#$qE)C!A! z!{H!J&v5X-EWYZqux?SSUeA+(5x8Gpa|o((#l?1%GfAdY@`M}G|bUQRXA-+?P zGiV2GS9-{mvM~+%d%7|Y%6>zCipy$hFd6Gz5DA~`HP5-p-QdHZT+tpvn1Vby@FNGa zLJuG%hYSg2Q>a&{4kT2?x=Jcc-G%y#`&fvD96i$-(Z)h0#!X*06(`ErP34$f-A83a z5SBK-+$}174_`wm2#s;YzqL0;Z1Zq$%SDva;;r9=8)Sol<7OsA#&KXwQevmLFFnyT z>L-xLgru=JYjstoYD_d*-sLd>hr+;2V(!LWfRgXORI~T;eAoWIAZ%3n3Wbw-=?y!s zx-+vVqLo22W_mMudKP-jxT(Imsy5ZM+P2NJgrzo4g_y9;TtlYI^EDLN)8fs`>QXbp z(8lhKS5c$yzsyOz$of<*!*TPcwNK2$EgF2}JNr(e%Rp{HBwR-0!76#u28vAx)H?)F zvNC^V=D`v?)r0Fy%#!9RMcg3#$P)3AaoO`ATdV^tasX6oQQ!-Bt&J`YU@7}D@+;2} z+J5b*qHqf7BLVJaH8F`UnOw1XJAYn68!#>+>W2}Mm~h4;3(h0?+Q@L*OEDY%6=~-) zWAjS?*m`s4e9TbWQop3kp-1VR0%rN-IfYG82nPoGi0#R;FJ;aQS>x18(C1b8>t+$G z#{FEjC9$Ws6yCmS^6FB<##T-HR(X1l`-mA2MBy8s(;9zkll)dWba6ilEc#LdG=<%Le&Q*M7fay9Ql1R{@ z-EBm}@uPC)jV}+tZBd$Rv>L0U#)>U*|9^~~W3wnxv|W#F+qR8+ zY}>YN+cxg8ZQHhO+sq9rd3i~y@&o!)SNG~(d(1hGYOaK0tS@+eI(3~p4I;FS-7DrQ z@qXP}^+rq(&GW5lYt>JNc6k#TsnUBK+j2&eAfrPeEg2cQlC!kcg~=4;X)fl)V_Kk=L4s`>&yswQY6y zw!S?+(G#J+;N8SU@`i0*Cr9Jnq)-5l4qK$CGJQ4au7&*D&Xg>SKoX&=0?yQ0kLk|2 z5AJcFWl1NxDTlAi9Vq5q$xDYEA181%Ml+S6T0hm3F+c6c7o`lss*n^s)U=N9P5!#0 z`ii1<7v_@>3IO`A_^*(NP3HB771bTsZd;@=d4*r-;2md4KrQrQGiYn*5ip!<0wL;i z+Nb3D=DE!pv20YefSP`q`Gg~FoTmHdC^PTsSI|Iyxh@a&own0}n_Zg-D6)uHcRrW< znhy#`LgYR)aJ%kq;=79p^FT6VP!kFRok~$kj4nn^I%Nw+(6Wko54?i`#9g_58Rl|+Om1_tMOgC zn7CNBQAXKZZu%yxV8zGAIo_a6e;Lk;w9$i4(+$-dE&Wx+%0+YZpQWXtgs6)7L|wSw zwC_zZKWZGZAx%mh5bGXN;C24O8&B>Yu?R~eb{MghHNzRC$$$z4VRBUwToN&Xesw%ni z*#5AnN~w{&T|fyI(70df-$OJD@gRjze^a&^SD~wa2Iu4w07h6Ic~GJk&NS1Z4+7Nb z0khHi5R6jt1D0W=4G#LYNYWB0QH3&EzGCk7(PV8;`l&f4h_(=X*5N=yl*B=5o1)74 zU{{6dfvPnP(JEAmcKr{PZb+_GJ&_7X2kSoqNo}xc%d!VQbB);LjZ7&$H_@)-icf1d zz{c^Jfciid<9MG{1=1aPH1-}0Rv-aa7VINM03S`5IGuNg5o|Sn*Pn!9Zf|l zJ(Dk&Qm|~O?ClYRP4A3_HJoIFVdE~JE(5G0LIquG_h2Vei0#VWh9vM6{}+v!GAr%_XYL@eT{wOk4pi2M=qRHN zl?}*sgx2*?bn`wY=Ob|}#<&f7+)50oR$1*hf||$xlE2N~>(6K{TFb$=<+BEp^J0)! zs!o-Dby=#<_7DN7?LZ0dU}}0(X5zFk$sy&i(W%p2W`|HAz9^OkvrcMi7>dXwVTz#5 z-sh5kc35ncrORQ`MN9`F<#t4siNpA~Ju=|NrI z52@=s%hO8tJdleIOAvJJ^#2z999i|JAiqgi z2FubCS9Q;iEPk>#kx}$&>@qcq4^uDX^K+8$@inOd`_4>ZSpEyU5g*U%d(FkOfyBd|Y%TG>rhtGC-sqZXV-PfOhVbEWy&b z?xIS$jHIqYU%pIHg~O*deRR*({_M_Vxt)A#^1P`!N-v~-M#{laXvhfb%u-KB#-mw4 z#`xN&!JoSXH1iZ}bJklf9wqmqrk%z={io!aMl>5V`P~E4A zTum)N2YmS`{0C&e*ol1NoYvd%p(gpphJnLY; z%vywL==^UP{W6^mjWQ&JQB81c*188vDU4XA8uMC^WANvbB&eIonkCLF&xG)caIoO! zMAhLI<@dpS)r?^dcg(xWAlDj?MQQ|b(FzQ(FRCGbywEFFi|GwslhIlBsh7o!xFv-$ zqqwNU`A!mdzE;6$ClPrQ4DnJTyeERVQU=|F(u5=;9w)`EaXO8wZeS;pm&&+KiZO-b zMDyyXajXR5x5+Q@L}ywDsxOuJ2#W|0v(SF;@Ko^f0lzIk#-3I2?qDA23IVUNg4oXHBOb&qz&im3%P) zmLD)I@?HiJo2N-`AAOO7)#E^BG<3BL^c0H2%h-!*2w7I3LMFR9vT`Xa6Sxc{PizH7 znYoDibfA4{&Uqg*PWm%;$NHH=ed1uq!|lBdvE>S)d?VSRYq5>jpzm~UL>U@UH6AZ_ zpF&&`q9wZj^LRana5i^~nZ(o?gR_XF@q*^A5?9VMKmZmL5=%v8i>gcUl@uadmD=XA z%2?e`7|h|j8|(pP_Yz%09ZOZ9MJ{FvE!HPhLyyFvZ3@N6tYcn|T?`xPVm6DUslSh= zMZ8B^Jknn+`<>~&-e}b{r^*tMW?TX&s(u^S>D06cinJYkGoa$lrc)LJk#IXi+I=iRYY~k^FjhDx`p7qdFGU#vQ9kORq}p zJJq-z!S%K0BN%SS8u|^YKfD;UfG-r0@b z+m`F8@bF9r{kCIa_*~v?hu}1AsCRkV8v%|sKS^#!rQ8jLdcs zHX~Ub(A?<;FEBf7FmZw~pMF=wl@ckg)ldbCLj{KQrH!II1csnVPM07`Gidh|aqI#0 ziX=5Uk5)C_lQUsca2Y^JZ&{S58F@zD=iXI}Qq*AEFGOFL zy&0>Y^a+yIfwq+!hDlcAwWPfg`U|ca z`0yfuyhEsA;ne1kF7A(5a*UdiF43QXVw{*sD0zAdTj@V%dLCo5w%I&rZHK+m)cB<7 z^{3_*a#R|%U&fFGY{)9p;eL#g>C|5q=W0`zCWm-vJTM`EbU+38h3=-NieE;>V!dpn z>!25f^fF4+XQ=crvE4O}X%>&D4@0$7KPPC;DV44%8jG@|g@#TX0kf8GD5SUwSva<7 z&K;Gm9U6;zW6)zY(W5mlu?yWGFM9{@zN8iDSNwU`f58@+e+~>H^*wv{#1}{6Oxxd< zch?g}bemLoELKj$8;kH|sM)cmNw+2=~t2d=Q=C*bMO4j{E<4d|< zrJEn6y>>B~b;~@0Ncs!14(WAO=GzY6hcMbpj35%x*49x;rtIw*>-|I3nV7XOs``*W zO7oznq*qa*_L8%=S}WK96H{F}O*Xa`o9$aa_ltB@C2T@0_;cI9Tmg*{i8MSY2;&R0 zDLMY6Pd9%u$=KZ7a54loD&r_9x-#VhF-L!+Ob4V{CU5-UotRn7+l;I${1k^gO6Ow* znC3>C^a}y7L5}`z4IJ(ks7+L&HQaPrd$LKJ3>I6gCUjLxzEsTwwzN1y36OqaIZ>XO z>C^r&UvHW55#D0*%Z1)b5n?JpeE%Cr8yO|zT81uWkcZ`ktkYe9cg}b}1TTtHZoH9Z z2cw~^koy)<3NuT9y9eb?vL3NTdqqA_m$GH+MGcW6B6`OZGd!JfkYrR=V}m8AD{Cib zEZ|RKl@?h}=hcfh1y6F_=Oz-9lch;i#@Ci!exf&7#KO9T;9c>|Pp|`-2ptcw42vTt zjuu~F1+PMnbjw9JlUy`(l^ELgktt+pC7WApyT!hC zb{QikuoBuUhsUbNM=b_DT{%%&ca)Zn_F7SXTE$+QjypD!WHAn+dS)Bxt~Zv)Ec6kS zTZ)XrjgOjMy{vMAQ13bKxf7QTTv}PP>ko8h)d`y}99A#vR=2jMarI5#sJ3Q+wTPJuw(eXQwzb8a2v93GW=G>hqhc@G%W!C3( zU{g`cLo!kFP3xX~lLr>3LC=d3Tu%4a7g*U{!2Z0y=(9@Pq%fld%8LL{otXuJD9a%G z%^B0FH}E(YO38e6iDisqekZ6b$$l#ab$UB2^jMd5CcfKbuFUG|13d-UePO$U@)viD zYG66j>DCAu>z0}Z3?^2V$5JX*-K3WkhdknMjJfSrk)1ILO0p;lb!`15e{iey*IC4s z7_3#JNwRKY9zWOR+iThN6JZbhHdH{tY`8_wC4QOT!dq^3Dc{P#5I08gzr);V*S}_c zB5CM2XxFQZCqHPKC1^@gCumgth6jBm9LMdl+%H!WTCJeEU`My1@V!5swXDQjmXj?j zO~UONr&k;q2bu{7d>yL;Bdnhh_Tfp3w3NuIn~&!$#|l(9GBRN_CpM22k(VHOa^YQFk<%mL%?|^3~ACEABOZ4x(%_?UC}jA>D_mqYt`ilL05!X-&;WEcGDkae}%8 zkqek~&}kJI`L0aM0WAhiub>#SQ{kJ*xdUnn+@43Nr3#BEV43~>O+JXtbM6NyuF%kt z(wdk98ZkR{V^G2+?xj6tF1mae>eQEUKVIGk>iq&2?C|OxkMRL>SQjhHapr4{8aQll zkAA4-;|K^wxU9v-8~d&Nu4mAL;gk(bXZizddnDQIyX%}%i$A+DQB4?TCp&1@m1G=| z8o)x;yqU==*S9Kyv3`zu=y2Fp&tF%TQ-PP=Kcg`Tr4co>-e|Ffs9Ql1b7=43DM!mk z)+or8#;&QnIM{BD33r%;Bx1A@!mH%DdILIb!i-99%xuU&IpMRmbL1&5uS(bch!K*x zNp$PFMG`Aj*``5_JUIbduEcOwCC&Do=zjuE*oWQ{EXnq=Out+pr62_S^X@n_dKvf< zr4cM5&jvnQaYo+Ib<^vKsFdr{Pri)VBas=RJ*`Ta;s~h=^0!q6ZLnhh*#tSefhmeK z5ep1ui+##;^g$60^R^v5@VSmt7|ivSuldH`TrVJ>H0$70(qP-ifk+qehI6>xa4z`& zTbzL&=XXU3c1jd6;vp)-0BXwuO6O(tY> z#-}5HJmbsMo>}{0cwLR*v0r;M#8ui->|n8XtfPECIQ>jaD;G@2f=yylqepPnf_eCa z`GQ4+MbZWb7wNnKO5zb?Fyt3k$Nms$u|~M-z!Vb;0u;reG1lXc2i7kdd#CL$ zpSjAIr5!L8{G8_C?Lepp#@AnPY(uz2;RNY+)NKUHT=mcBFKEKLroq;RsH_!ah!nYK z4}EJI{ms+jw~nee-Mp!aT{GOCfTWD$gKc;}j5vx6lUZ&>1L8eK@ln~v-26w7{9zi% zct%?5bWkcYwe%$!MSY2Jf1JidMkCtv{0OAIqq>yEgp$Mu=k_T&FBjoIz@WK=G5zXz zmqf^O`yP68HVvwG1bw7x#iXPM6mA362b zcN48yPxua~kFC)pn`+o+faesF*ede)r=gZBqC67AlHywJVtlyB(PSi`0ymK>GgmR` zi!_`m!lhoX=>Pj7~1t1x6|E^l$0YHp}PZRXe!(UdW3{XP7j{ z^fmsaSmaJ@@9mzSkz%!ND2I$U(WZZuYaJx;9M={sT|FrKA6q)sCd6GF94NL*KgjD& zQa)u!N&>eOXO)%^4v=6^wi$#)Z$*JA>6E5j6sJy-rl}_+CoNg<#v2-3a9zbMTfivj z2bvoaUXxw1l5s;IwpK=O8wAXcsU`KMnVj`CCMTCjBRt333KKy%XI$wEEbJIs=|Bd5MBUIEXdSD z*_mk_sYjs{YxfdW5z#$4!Pl&b^{#}_eIxt>Ih|81a=3@WWGe##GdDUsAPcF+`i^BEu+aC6Ud&3L9}K6G`dn<+K8gfdNp@T?0(T zp``@fk!fGAco|~_O+2(h?e%tuC+{kjolvi$obY-G6xYV?4$}&O4TmMhK>NtNjnPhv zv%V*MWd&Aph+=4yaMA;x!xVC<$8}MrugX?pgZh z(ksK2oDJ5ZLFVWh+8{`x!lF12poA_dUi6V$%^77I1XNOsm!IbBVh`hogK^UsY?gSi zPPMMqpZYk4{soX7@00~eIH1T&>^C|2KG;!Yga10ax&AF%BmpmA%IYIDo)7*KMg;M0 zZ=BRaIs-p44TDrZ#i447c$rJs@c82F)X3kgz_qeGNS!$-f9b)NL`s4yv0W-5Ln=Mq zFxUZIX<4*&0hYNll}t=tKY`XDGUVWW_QgVD&&gZWl|$a(--08@Jvv;#E@FVd0yf6; zZEqZW#maMNO2gZX{<(JhqzC_(W4?Wh&*3xmzG~Fs4;tN!VU9m@3T#n=zLvmcz%{J? zNKQ*z&`#dcz1)yR2*=nv>`O2I zdkgM?^=&zoG=m;1j!h+Uu~G7{mgAkV7i{T0?+P*A}O;CssQpPB^RI!d42 z{}EtbS2?nB#?s!|A;-BfHI!&ouDs?&{<)JNc3Nv{OvGrNMx}hg{QBN2JskYy!}xOV z`u!O43%$@~{iCx5;u#)VdikNJC8f=mzVw@EjE`k>eyuJ#eYKVnZ-QhRUgXy z<<_2f$K|=v962aGH<%%#RXlC(J@i>CAC(wUxw;RZXo72_f$rd&8|&-}mc-w8 zbT@7c@!@RdWfi7#=aYd1GUJXsn+YQICvf_jUZIVo&X^lV6nW~l=JD7vOF#LUF%+p} zw|mzp%Al&QiP-eActwtMQ()grs~or3^?zdl2)r-s7-X6om2RB-}>wzF7Ty|B0tLK=EO~1n@a@7U}^Lu7`3xha#T!zXOrHT;BGNY zGys80w`$pu$cVE3HNP0+!6U+K?jDm3K!owP@ea2`c^cwn{^Jo6<4s%v;!#K#72!{r z>^zL51b9OAr5e{kb0nHtV!~I*{O+j>4a2`I`v{Z=Oyac-$1d$xsv-9hBR#Oy2lE!e zQmPg?>9e2)VE(yUG~oyGZb=q-U*(#7!rhKUya8|ZUUiwSD{Z8~#rEU3WXY|TZR)hz zP+6r)w9>fax;s$koH#lK&YqTM=zUyfC7fT%TGjrs!pusRA>91Vmj=@1cq4Q^&fmwY zUxhd2k2n~;HP+BVVn(xrIz_X}3A9ng9WZ1yXeoLo7n^QxEPWM#fa#h)0Kh-2pMTGF zI9bV8X=xVziP&D=V??orTt+02!A^?qne&+&j5y9#j+1&EMgzf9T>Z>i`84QdlE5l+ zDFmUUpD&Fgb18icv+S;_hPBu;HlFt2Y1sOMRz-$LVGQTs!bIVj+q2C_g7KV9gVxMQ zb&kv^!MqNZ_UFIn+t&L?io$bEU!bD#>TUr5IR7x-nhad1aCtWPWh|)|a0j(2TiCJ4 zo~rvOQQMKP3M{A9-KxRRq6lAOv~C#WkyZRy7nb_bgJdRG6wv9QFN2a{mg2}Z1EsS# zqgMwktBI*hrifKj$5*7%CTQMfYS9sBMxPsS9W2O}TV1$@sIDw`l}xD;I(;aDwuX|W zsO>LE<|9qt7?%_UKjv58pDXjv1E^948oIKpuaT&)8ka$5U1h}5WhO7wbuJ6%^mt~i zx6hPo2!_xoR#7A5$Qss|am9@ufQWAZkQkx}UhWtcq&;FN%yGOIqccOvnOZa5#$&4L zg*cY4F1lk7_6o@JpZ=_$9@U`B)D&b*;eHr0jwfL*2=^I-C707>X!pDsYVq!DFj6u; zhwsq2bq+q7-=HzJ>#ePR4qLzY;)WPF9b<7>adYw4l5oPnf$8Dqjse>y#8cEyb;R?s zYYPth9wxy)qW0~cFp&=7SUZ-JKBJ9lql-AUzo*~mK;wNt)ZQKcXW^Kuvp!oOF)7NxI?V5=8&xk@g$8pC-IooVDQ`t z5yk;EmwVsuCei~@A_K|YV?GH{B7&J0{)a2h3TNPf22)<#@Z zNQc^nK$*di%&|01Fv5WSd~}V)tlZl?J!Czkt79&@QeQnv(e{huqU%eRlQ<@uv{ffh z%e$&pP=8>nk>)|f2^B9z>l-|dp(iG(qF7+Jl%bQa)-C6w%kczx&JMB@!7$R3(_sU)mW&k?shEi+Y-A2$^M11E*+Atkzph z@5D4+mC*7mt1()NL%Wb{DetJTE6Jw9lFKai|dHgQJTGE{SS%D#bF& z=gKh1Eh+#^idjmwOe&q8pTu;EyGkTalU+nIYG)xsoQ*txU*wuaF!Pbi zMUX1W^&$@4kBW@4s!7a=Q`4hr)xJtXxx(5ed0Hs#qG7kR*g*|Q5(eG`xf6nGMkPGT z6sr)gJP;WDP)DGSLK?*~k`u+g31qEzY>!3!E;SOtp}Ts9dzD%%G2Y@(8WTEw+IG2Q zjrweP*>2HUfp3&L_dJM)u$V!VL_37RC3&%;S#7~i0W#2}#n@kAz*wy!WXpO&l^!eV zSh&eL6!@x{`MkG)VR9%(Ugc0VM^0Dl3uj42{S-%9OnShzS{om!ltG!q7RN6JxmFCX z;wie4+Af$^$#|$JtdWp-)_~c^N~$cxl&M&ODU8V!0T?=H5`>KbD>23*LDWnJ4ecw} zfn5yC=lyuGhaYtN68GEFkQoU^WpQktV`8IGe~47k4&|b5{Q%IYc!jLw30eAFx^O91 zyh>j3RKPVhBj@H}xTBR+VU4Mi@yp^1HPOJ`x|rBLtjZsmTBYsG+V=2l-iMPoeF>{a z<@h~+WvJ0=q$klQAmE-rsw_}zziHB$iGXJSd&yeb<;dD6sxx}R)B*Qtyw!4cjWw}T zQ+;Qna;_Btrz7{i*^JU>Ll%a9CNMvU%S!tCpHlaopiG$ZU~>x@>Xl+HG^L-QMlkRhcqtf^m%0 zF+<1Xse0n1Qd>tGW#lZ{ibTX-570SE#s*0} z&7JQo706ykrxH!Yl7eF9886!I{zj=Tsg_O(gikb%hjgl-C3&d8kU=P%7=tXXEGAxjDz(fgS>lXD<7{vj_{-YQi89d5^O?@%Zlfm7Yj^=6ZN(% z0{a#-gIbo$lv(rz;~HGx6>>{e7=bmu-_3Pq(>kONoZ7h!M<#oA`Nzi{bhQoh)SeIP zH0w4pW0jck-NcGQ+}2MDnN zoz8Ps9I#Lsv0@f4+UPUUOAKyR7%hn_AvWVT2CX2v88BS3>Y&X~i=jJLAvJeYLe9Gt zL8~Z{$y^6fpf2`q$uslCkb+V$4JJMWnc@KRYW?*`m0_0j3B9+}RQ2dU>TA0);tj?< z!0L|x=H+^1Oi%&X5mlNw&sc?1Sca3WlcSQGBgic%4BHgH#C@K|EbEC)si%R324aC2 z3Mq2?W@y8kNyS8Jn39mxMpMC6`VnBR8)G9R*z`z{(5v!jGmOy2Wp16)cdesoDOaX_SU z1y9yOU|6An8x_fI|M@ zj4cGR&#x)5x`kljOEExs%CK-)PTiVIRST6xaAw#V%1Z7xI%F42qa}G~O&WPgEhv?Y z>ax43hF(EuYT>FxP&VtS+!td_2A)p*9PK-~z!bWoROeL_NDMy%=uF%!MExmzAnt#M z*jfT{r7$DmcV8}$(elGos&qWIPtMEmdA|engpa8Vd5mY**s|+(6ay6I%>U#2VuBl$ zp(0y<@{*shBbaY_QUG-|5XGrs?gI3lcE2f26Wmg$m_a1Xf_;qEKRL_b6Y}*51pR?_ zI;2ZIgSG)WrY6$tOR6_?{Vbiit6`Jj7kNsceqF~oT~>WaW0?^?(64C6rRo#&JYF+i ztv?I^l_AlbA*vXlreXO-5$In{rWICC_PMC}$gOF`Lhw`(V9Jji_O|`Q4@UmE3!{tQ z^=>k210o()<=v(dv_GoFFC#U@i9bvd$)Y(*m|Uvi5r#MQhWQmSg$>n*(C5PDUEJ4### z`d}bM{Z_%nvTMu58N~EYAEgCznk!`dh=OcE)*H8&e>i5BdRje9chP%gsNwSb8b7R& zpZH)p9{ti*n*_#R#nETH5K2cE%GiL(sFEUlLR47qUJRg#_}TH6q8Z`gk?>tB8qP2wS5S^l&7{zI_~k|dx;?&OrxCCm4VbV34*y&W zGwvhb25DwH=h_YXtxE4#yekufu^K57L@En8qe#v?H)Fsh3&C!*#RxxI8i)sqadCR& z2MR`5{I?h3!T?8w{5=p_@JK1_z1%#!$+iz}91)u~en%I9%3=qw3KQh_t(?AYl zBoj~k?w%L?b*&BI?AjCqx`J265Tz;GrXFZQ>>71#B#h`gFr^9Ls&-ek z>HxpLiIy@jfLphcIB)>)>>AQCr7z-J!2w*pB;)VIJSd-FUU^Zsw0D(QLa=Morz>RC zMcIPtV9HPHGS7kCn1G~Nb*dF0(Jc#ei<$)qOVU ztN++t7S4JbwJQnhP9xIC#E~K>p~PmG1pcT#Teg3NUBpIYij(S*#_7)(k-`U|kRn{4 zG*>gf4e_*%BtViH!zB*l>^hyQj{}Zztm?xYp++=7Q8&rPL2rLu?SODMZ61{6vItV{jg&0$y7|nAt&@ z+F@oYz!>Wp*@xoy^z7V4A1F1%sy{c2RIm?~qsx|%iRyI5G>6N(F|{^9{aK88?rnvY z?6vvhNrAzeZrj5tTtmoJ^Fe7ZE#oPt1{G_Ci?vF`AS-9woYxi^&*9^ltyH9Y2M^k2G#L|H zUli8I2%!-OZ!w$kMe#TO82?=}@)H<9o4WieOGSkwNxJ;c;z%DN48Rybri#jV(e7IF zj1*llzGz?oAKOz_+aOe=f(B=(eu~={A^WNzl;sgKZLzUE)!<_dutL4V4mMLHGs4Yk8scK7LvwhyH2mv*+spYm)b{0uvV4Y& z${Ofu*U4+57xhu|Yu9=FYDaXDPK+o}DeD&wYf&~VZ=w!%MhJ)l{=!3}iPX(E<@e}9$YCzi5q>T#nd)3^dyjmA*`+< zB9kNnxj`(n#*3ehqeaKx;!z*)gr<9ksrsSYIJd)0mj<+%}2Zxg|_A z>`!$`VH-x%o%flAaeHs{b zJ8$j~{`x#2yxW%46aZiZ2LJ%;|8Z0Pvvo_u#tw@U;U`=28-Bim>sk4} z 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 DD#8JG literal 178 zcmWIWW@h1H0D+kb&K_U}l;C5KVaUl$DlRH1&^6LC&@<2v4dG;9e#E^ojPHM9TxkV2 x10%}|W(Ec@5#Y_pB*%=)BnhaQ0t|m0K}>XWSs~_Pn90fpQq2g2AwU}9JODC)96SI3 diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index 998a4fddb6..b2c69bbdbc 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -253,7 +253,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then echo "Building srtp2."; ( rm -rf ${SRS_OBJS}/srtp2 && cd ${SRS_OBJS} && - ln -sf ../3rdparty/libsrtp-2.0.0 && cd libsrtp-2.0.0 && + unzip -q ../3rdparty/libsrtp-2.0.0.zip && cd libsrtp-2.0.0 && ./configure --prefix=`pwd`/_release && make ${SRS_JOBS} && make install && cd .. && rm -f srtp2 && ln -sf libsrtp-2.0.0/_release srtp2 ) From a36ed6954fc71652636bf3485eca494b48f0b966 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Fri, 6 Mar 2020 23:59:59 +0800 Subject: [PATCH 09/69] add rtc.html temp --- trunk/research/players/rtc.html | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 trunk/research/players/rtc.html diff --git a/trunk/research/players/rtc.html b/trunk/research/players/rtc.html new file mode 100644 index 0000000000..4dd8e44f25 --- /dev/null +++ b/trunk/research/players/rtc.html @@ -0,0 +1,90 @@ + + + + + + + + +rtc_media_player:
+ + + + + + + \ No newline at end of file From b730458d5145439123485916677ac43f6b5fc2cd Mon Sep 17 00:00:00 2001 From: HuyaJohn Date: Fri, 6 Mar 2020 23:28:15 -0800 Subject: [PATCH 10/69] add candidates ip list, add rtc_upload.html to test --- trunk/conf/rtc.conf | 2 + trunk/research/players/rtc_upload.html | 97 ++++++++++++++++++++++++++ trunk/src/app/srs_app_config.cpp | 17 +++++ trunk/src/app/srs_app_config.hpp | 1 + trunk/src/app/srs_app_http_api.cpp | 15 ++-- trunk/src/app/srs_app_rtc_conn.cpp | 42 ++++++++++- trunk/src/app/srs_app_rtc_conn.hpp | 11 +++ 7 files changed, 176 insertions(+), 9 deletions(-) create mode 100644 trunk/research/players/rtc_upload.html diff --git a/trunk/conf/rtc.conf b/trunk/conf/rtc.conf index 5af4172b05..fe8d545ec1 100644 --- a/trunk/conf/rtc.conf +++ b/trunk/conf/rtc.conf @@ -23,6 +23,8 @@ http_server { rtc { enabled on; listen 9527; + # candidate device ip: *(all interface), 192.168.1.1 ... + candidate *; } stats { network 0; diff --git a/trunk/research/players/rtc_upload.html b/trunk/research/players/rtc_upload.html new file mode 100644 index 0000000000..68c515d8eb --- /dev/null +++ b/trunk/research/players/rtc_upload.html @@ -0,0 +1,97 @@ + + + + + + + + +
local_media_player:
+ +
rtc_media_player:
+ + + + + + + diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 315ec58f7b..babb870cf2 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4255,6 +4255,23 @@ int SrsConfig::get_rtc_listen() return ::atoi(conf->arg0().c_str()); } +std::string SrsConfig::get_rtc_candidates() +{ + static string DEFAULT = "*"; + + SrsConfDirective* conf = root->get("rtc"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("candidate"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return (conf->arg0().c_str()); +} + SrsConfDirective* SrsConfig::get_vhost(string vhost, bool try_default_vhost) { srs_assert(root); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 1f85550f79..97d8f4851a 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -496,6 +496,7 @@ class SrsConfig virtual int get_rtc_enabled(); virtual bool get_rtc_enabled(SrsConfDirective* conf); virtual int get_rtc_listen(); + virtual std::string get_rtc_candidates(); // vhost specified section public: diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index fb33382d21..5e14860939 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -850,19 +850,20 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); obj->set("server", SrsJsonAny::integer(stat->server_id())); - string candidate_str = "candidate:1 1 udp 2115783679 192.168.170.129:9527 typ host generation 0 ufrag " - + local_sdp.get_ice_ufrag() + "netwrok-cost 50"; + // XXX: ice candidate + //string candidate_str = "candidate:1 1 udp 2115783679 192.168.170.129:9527 typ host generation 0 ufrag " + // + local_sdp.get_ice_ufrag() + "netwrok-cost 50"; - SrsJsonObject* candidate_obj = SrsJsonAny::object(); + //SrsJsonObject* candidate_obj = SrsJsonAny::object(); //SrsAutoFree(SrsJsonObject, candidate_obj); - candidate_obj->set("candidate", SrsJsonAny::str(candidate_str.c_str())); - candidate_obj->set("sdpMid", SrsJsonAny::str("0")); - candidate_obj->set("sdpMLineIndex", SrsJsonAny::str("0")); + //candidate_obj->set("candidate", SrsJsonAny::str(candidate_str.c_str())); + //candidate_obj->set("sdpMid", SrsJsonAny::str("0")); + //candidate_obj->set("sdpMLineIndex", SrsJsonAny::str("0")); if (r->is_http_post()) { obj->set("sdp", SrsJsonAny::str(local_sdp_str.c_str())); - obj->set("candidate", candidate_obj); + // obj->set("candidate", candidate_obj); } else { return srs_go_http_error(w, SRS_CONSTS_HTTP_MethodNotAllowed); } diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 2a570b4a98..65cd4fe105 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -39,6 +39,8 @@ using namespace std; #include #include #include +#include +#include static bool is_stun(const char* data, const int size) { @@ -71,6 +73,33 @@ static string gen_random_str(int len) const int SRTP_MASTER_KEY_KEY_LEN = 16; const int SRTP_MASTER_KEY_SALT_LEN = 14; +SrsCandidate::SrsCandidate() +{ +} + +SrsCandidate::~SrsCandidate() +{ +} + +std::vector SrsCandidate::get_candidate_ips() +{ + std::vector candidate_ips; + + string candidate = _srs_config->get_rtc_candidates(); + if (candidate == "*" || candidate == "0.0.0.0") { + std::vector tmp = srs_get_local_ips(); + for (int i = 0; i < tmp.size(); ++i) { + if (tmp[i] != "127.0.0.1") { + candidate_ips.push_back(tmp[i]); + } + } + } else { + candidate_ips.push_back(candidate); + } + + return candidate_ips; +} + SrsSdpMediaInfo::SrsSdpMediaInfo() { } @@ -139,6 +168,15 @@ srs_error_t SrsSdp::encode(string& sdp_str) { srs_error_t err = srs_success; + string candidate_lines = ""; + + std::vector candidate_ips = SrsCandidate::get_candidate_ips(); + for (int i = 0; i < candidate_ips.size(); ++i) { + ostringstream os; + os << "a=candidate:10 1 udp 2115783679 " << candidate_ips[i] << " " << _srs_config->get_rtc_listen() <<" typ host generation 0\\r\\n"; + candidate_lines += os.str(); + } + // FIXME: sdp_str = "v=0\\r\\n" @@ -150,7 +188,7 @@ srs_error_t SrsSdp::encode(string& sdp_str) "a=msid-semantic: WMS 6VrfBKXrwK\\r\\n" "m=audio 9 UDP/TLS/RTP/SAVPF 111\\r\\n" "c=IN IP4 0.0.0.0\\r\\n" - "a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" + + candidate_lines + "a=rtcp:9 IN IP4 0.0.0.0\\r\\n" "a=ice-ufrag:" + ice_ufrag + "\\r\\n" "a=ice-pwd:" + ice_pwd + "\\r\\n" @@ -170,7 +208,7 @@ srs_error_t SrsSdp::encode(string& sdp_str) "a=ssrc:3233846890 label:6VrfBKXrwKa0\\r\\n" "m=video 9 UDP/TLS/RTP/SAVPF 96 98 102\\r\\n" "c=IN IP4 0.0.0.0\\r\\n" - "a=candidate:10 1 udp 2115783679 192.168.170.129 9527 typ host generation 0\\r\\n" + + candidate_lines + "a=rtcp:9 IN IP4 0.0.0.0\\r\\n" "b=as:2000000\\r\\n" "a=ice-ufrag:" + ice_ufrag + "\\r\\n" diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index c400766864..b9d60d07e5 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -37,6 +37,16 @@ class SrsServer; class SrsStunPacket; +class SrsCandidate +{ +private: +public: + SrsCandidate(); + virtual ~SrsCandidate(); + + static std::vector get_candidate_ips(); +}; + class SrsSdpMediaInfo { private: @@ -151,6 +161,7 @@ class SrsRtcServer virtual ~SrsRtcServer(); public: virtual srs_error_t initialize(); + virtual srs_error_t on_udp_packet(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, const sockaddr* from, const int fromlen, const char* data, const int size); From c62901a3ac767110fada3449bfd2d478a5e91404 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Sun, 8 Mar 2020 00:30:31 +0800 Subject: [PATCH 11/69] make code easy, wrap udp remux socket --- trunk/configure | 2 +- trunk/src/app/srs_app_http_api.cpp | 1 - trunk/src/app/srs_app_listener.cpp | 64 ++++++- trunk/src/app/srs_app_listener.hpp | 31 +++- trunk/src/app/srs_app_rtc.cpp | 86 ---------- trunk/src/app/srs_app_rtc.hpp | 52 ------ trunk/src/app/srs_app_rtc_conn.cpp | 232 +++++++++++++------------- trunk/src/app/srs_app_rtc_conn.hpp | 63 +++---- trunk/src/app/srs_app_server.cpp | 5 +- trunk/src/protocol/srs_stun_stack.cpp | 1 + trunk/src/protocol/srs_stun_stack.hpp | 2 + 11 files changed, 245 insertions(+), 294 deletions(-) delete mode 100644 trunk/src/app/srs_app_rtc.cpp delete mode 100644 trunk/src/app/srs_app_rtc.hpp diff --git a/trunk/configure b/trunk/configure index 047f41883c..6d3da2bff2 100755 --- a/trunk/configure +++ b/trunk/configure @@ -257,7 +257,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" - "srs_app_mpegts_udp" "srs_app_rtc" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" + "srs_app_mpegts_udp" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" "srs_app_coworkers" "srs_app_hybrid") diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 5e14860939..bb892c57cb 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -46,7 +46,6 @@ using namespace std; #include #include #include -#include #include srs_error_t srs_api_response_jsonp(ISrsHttpResponseWriter* w, string callback, string data) diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index 2c1703250c..c8ecec2c67 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -220,6 +221,57 @@ srs_error_t SrsTcpListener::cycle() return err; } +SrsUdpRemuxSocket::SrsUdpRemuxSocket(srs_netfd_t fd) +{ + nb_buf = SRS_UDP_MAX_PACKET_SIZE; + buf = new char[nb_buf]; + nread = 0; + + lfd = fd; + + fromlen = 0; +} + +SrsUdpRemuxSocket::~SrsUdpRemuxSocket() +{ + srs_freepa(buf); +} + +int SrsUdpRemuxSocket::recvfrom(srs_utime_t timeout) +{ + fromlen = sizeof(from); + nread = srs_recvfrom(lfd, buf, nb_buf, (sockaddr*)&from, &fromlen, timeout); + + if (nread > 0) { + char address_string[64]; + char port_string[16]; + if (getnameinfo((sockaddr*)&from, fromlen, + (char*)&address_string, sizeof(address_string), + (char*)&port_string, sizeof(port_string), + NI_NUMERICHOST|NI_NUMERICSERV)) { + return -1; + } + + peer_ip = std::string(address_string); + peer_port = atoi(port_string); + } + + return nread; +} + +int SrsUdpRemuxSocket::sendto(void* data, int size, srs_utime_t timeout) +{ + return srs_sendto(lfd, data, size, (sockaddr*)&from, fromlen, timeout); +} + +std::string SrsUdpRemuxSocket::get_peer_id() +{ + char id_buf[1024]; + int len = snprintf(id_buf, sizeof(id_buf), "%s:%d", peer_ip.c_str(), peer_port); + + return string(id_buf, len); +} + SrsUdpRemuxListener::SrsUdpRemuxListener(ISrsUdpRemuxHandler* h, std::string i, int p) { handler = h; @@ -276,19 +328,17 @@ srs_error_t SrsUdpRemuxListener::cycle() return srs_error_wrap(err, "udp listener"); } - int nread = 0; - sockaddr_storage from; - int nb_from = sizeof(from); - if ((nread = srs_recvfrom(lfd, buf, nb_buf, (sockaddr*)&from, &nb_from, SRS_UTIME_NO_TIMEOUT)) <= 0) { + SrsUdpRemuxSocket udp_remux_socket(lfd); + + if (udp_remux_socket.recvfrom(SRS_UTIME_NO_TIMEOUT) <= 0) { srs_error("udp recv error"); // remux udp never return continue; } - if ((err = handler->on_udp_packet(lfd, (const sockaddr*)&from, nb_from, buf, nread)) != srs_success) { - //srs_error("udp handle packet error"); + if ((err = handler->on_udp_packet(&udp_remux_socket)) != srs_success) { // remux udp never return - srs_error("udp remux error:%s", srs_error_desc(err).c_str()); + srs_error("udp packet handler error:%s", srs_error_desc(err).c_str()); continue; } diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index 3b4d96b80f..fc25551e87 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -26,6 +26,8 @@ #include +#include + #include #include @@ -33,6 +35,8 @@ struct sockaddr; +class SrsUdpRemuxSocket; + // The udp packet handler. class ISrsUdpHandler { @@ -61,7 +65,7 @@ class ISrsUdpRemuxHandler virtual ~ISrsUdpRemuxHandler(); public: virtual srs_error_t on_stfd_change(srs_netfd_t fd); - virtual srs_error_t on_udp_packet(srs_netfd_t fd, const sockaddr* from, const int fromlen, char* buf, int nb_buf) = 0; + virtual srs_error_t on_udp_packet(SrsUdpRemuxSocket* udp_remux_socket) = 0; }; // The tcp connection handler. @@ -123,6 +127,31 @@ class SrsTcpListener : public ISrsCoroutineHandler virtual srs_error_t cycle(); }; +class SrsUdpRemuxSocket +{ +private: + char* buf; + int nb_buf; + int nread; + srs_netfd_t lfd; + sockaddr_storage from; + int fromlen; + std::string peer_ip; + int peer_port; +public: + SrsUdpRemuxSocket(srs_netfd_t fd); + virtual ~SrsUdpRemuxSocket(); + + int recvfrom(srs_utime_t timeout); + int sendto(void* data, int size, srs_utime_t timeout); + + char* data() { return buf; } + int size() { return nread; } + std::string get_peer_ip() const { return peer_ip; } + int get_peer_port() const { return peer_port; } + std::string get_peer_id(); +}; + class SrsUdpRemuxListener : public ISrsCoroutineHandler { protected: diff --git a/trunk/src/app/srs_app_rtc.cpp b/trunk/src/app/srs_app_rtc.cpp deleted file mode 100644 index e7fbf7fc23..0000000000 --- a/trunk/src/app/srs_app_rtc.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2020 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include - -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool is_stun(const char* data, const int size) { - return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); -} - -static bool is_rtp_or_rtcp(const char* data, const int size) { - return data != NULL && size > 0 && (data[0] >= 128 && data[0] <= 191); -} - -static bool is_dtls(const char* data, const int size) { - return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); -} - -SrsRtc::SrsRtc(SrsRtcServer* rtc_svr) -{ - rtc_server = rtc_svr; -} - -SrsRtc::~SrsRtc() -{ -} - -srs_error_t SrsRtc::on_udp_packet(srs_netfd_t fd, const sockaddr* from, const int fromlen, char* buf, int nb_buf) -{ - char address_string[64]; - char port_string[16]; - if(getnameinfo(from, fromlen, - (char*)&address_string, sizeof(address_string), - (char*)&port_string, sizeof(port_string), - NI_NUMERICHOST|NI_NUMERICSERV)) { - return srs_error_new(ERROR_SYSTEM_IP_INVALID, "bad address"); - } - std::string peer_ip = std::string(address_string); - int peer_port = atoi(port_string); - - return rtc_server->on_udp_packet(fd, peer_ip, peer_port, from, fromlen, buf, nb_buf); -} diff --git a/trunk/src/app/srs_app_rtc.hpp b/trunk/src/app/srs_app_rtc.hpp deleted file mode 100644 index 8c15bbf163..0000000000 --- a/trunk/src/app/srs_app_rtc.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2020 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SRS_APP_RTC_HPP -#define SRS_APP_RTC_HPP - -#include - -struct sockaddr; -#include -#include - -#include -#include -#include - -class SrsRtcServer; - -// The rtc over udp stream receiver -class SrsRtc : virtual public ISrsUdpRemuxHandler -{ -private: - SrsRtcServer* rtc_server; -public: - SrsRtc(SrsRtcServer* rtc_svr); - virtual ~SrsRtc(); -// Interface ISrsUdpHandler -public: - virtual srs_error_t on_udp_packet(srs_netfd_t fd, const sockaddr* from, const int fromlen, char* buf, int nb_buf); -}; - -#endif diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 65cd4fe105..bfc5c09f47 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -279,7 +279,7 @@ srs_error_t SrsSdp::parse_attr(const string& line) return err; } -SrsDtlsSession::SrsDtlsSession(srs_netfd_t lfd, const sockaddr* f, int fl) +SrsDtlsSession::SrsDtlsSession() { dtls = NULL; bio_in = NULL; @@ -291,10 +291,6 @@ SrsDtlsSession::SrsDtlsSession(srs_netfd_t lfd, const sockaddr* f, int fl) srtp_send = NULL; srtp_recv = NULL; - fd = lfd; - from = f; - fromlen = fl; - handshake_done = false; } @@ -302,7 +298,7 @@ SrsDtlsSession::~SrsDtlsSession() { } -srs_error_t SrsDtlsSession::handshake() +srs_error_t SrsDtlsSession::handshake(SrsUdpRemuxSocket* udp_remux_socket) { srs_error_t err = srs_success; @@ -314,11 +310,7 @@ srs_error_t SrsDtlsSession::handshake() int ssl_err = SSL_get_error(dtls, ret); switch(ssl_err) { case SSL_ERROR_NONE: { - srs_trace("dtls handshake done"); - handshake_done = true; - srtp_init(); - srtp_sender_side_init(); - srtp_receiver_side_init(); + err = on_dtls_handshake_done(); } break; @@ -337,25 +329,25 @@ srs_error_t SrsDtlsSession::handshake() if (out_bio_len) { srs_trace("send dtls handshake data"); - srs_sendto(fd, out_bio_data, out_bio_len, from, fromlen, 0); + udp_remux_socket->sendto(out_bio_data, out_bio_len, 0); } return err; } -srs_error_t SrsDtlsSession::on_dtls(const char* data, const int len) +srs_error_t SrsDtlsSession::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) { srs_error_t err = srs_success; if (! handshake_done) { BIO_reset(bio_in); BIO_reset(bio_out); - BIO_write(bio_in, data, len); + BIO_write(bio_in, udp_remux_socket->data(), udp_remux_socket->size()); - handshake(); + handshake(udp_remux_socket); } else { BIO_reset(bio_in); BIO_reset(bio_out); - BIO_write(bio_in, data, len); + BIO_write(bio_in, udp_remux_socket->data(), udp_remux_socket->size()); while (BIO_ctrl_pending(bio_in) > 0) { char dtls_read_buf[8092]; @@ -370,6 +362,14 @@ srs_error_t SrsDtlsSession::on_dtls(const char* data, const int len) return err; } +srs_error_t SrsDtlsSession::on_dtls_handshake_done() +{ + srs_trace("dtls handshake done"); + + handshake_done = true; + return srtp_init(); +} + srs_error_t SrsDtlsSession::on_dtls_application_data(const char* buf, const int nb_buf) { srs_error_t err = srs_success; @@ -377,8 +377,7 @@ srs_error_t SrsDtlsSession::on_dtls_application_data(const char* buf, const int return err; } - -void SrsDtlsSession::send_client_hello() +void SrsDtlsSession::send_client_hello(SrsUdpRemuxSocket* udp_remux_socket) { if (dtls == NULL) { srs_trace("send client hello"); @@ -391,7 +390,7 @@ void SrsDtlsSession::send_client_hello() SSL_set_bio(dtls, bio_in, bio_out); - handshake(); + handshake(udp_remux_socket); } } @@ -400,8 +399,8 @@ srs_error_t SrsDtlsSession::srtp_init() srs_error_t err = srs_success; unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server - char dtls_srtp_lable[] = "EXTRACTOR-dtls_srtp"; - if (! SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable, strlen(dtls_srtp_lable), NULL, 0, 0)) { + static string dtls_srtp_lable = "EXTRACTOR-dtls_srtp"; + if (! SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) { return srs_error_wrap(err, "SSL_export_keying_material failed"); } @@ -418,8 +417,15 @@ srs_error_t SrsDtlsSession::srtp_init() client_key = sClientMasterKey + sClientMasterSalt; server_key = sServerMasterKey + sServerMasterSalt; - srtp_sender_side_init(); - srtp_receiver_side_init(); + if (srtp_sender_side_init() != srs_success) { + return srs_error_wrap(err, "srtp sender size init failed"); + } + + if (srtp_receiver_side_init() != srs_success) { + return srs_error_wrap(err, "srtp receiver size init failed"); + } + + return err; } srs_error_t SrsDtlsSession::srtp_sender_side_init() @@ -435,7 +441,8 @@ srs_error_t SrsDtlsSession::srtp_sender_side_init() policy.ssrc.type = ssrc_any_outbound; policy.ssrc.value = 0; - policy.window_size = 8192; // seq 鐩稿樊8192璁や负鏃犳晥 + // TODO: adjust window_size + policy.window_size = 8192; policy.allow_repeat_tx = 1; policy.next = NULL; @@ -444,6 +451,7 @@ srs_error_t SrsDtlsSession::srtp_sender_side_init() policy.key = key; if (srtp_create(&srtp_send, &policy) != 0) { + delete [] key; return srs_error_wrap(err, "srtp_create failed"); } @@ -465,7 +473,8 @@ srs_error_t SrsDtlsSession::srtp_receiver_side_init() policy.ssrc.type = ssrc_any_inbound; policy.ssrc.value = 0; - policy.window_size = 8192; // seq 鐩稿樊8192璁や负鏃犳晥 + // TODO: adjust window_size + policy.window_size = 8192; policy.allow_repeat_tx = 1; policy.next = NULL; @@ -474,6 +483,7 @@ srs_error_t SrsDtlsSession::srtp_receiver_side_init() policy.key = key; if (srtp_create(&srtp_recv, &policy) != 0) { + delete [] key; return srs_error_wrap(err, "srtp_create failed"); } @@ -482,8 +492,9 @@ srs_error_t SrsDtlsSession::srtp_receiver_side_init() return err; } -SrsRtcSession::SrsRtcSession() +SrsRtcSession::SrsRtcSession(SrsRtcServer* svr) { + rtc_server = svr; session_state = INIT; dtls_session = NULL; } @@ -492,42 +503,73 @@ SrsRtcSession::~SrsRtcSession() { } -srs_error_t SrsRtcSession::on_binding_request(const SrsStunPacket& stun_packet, const string& peer_ip, const uint16_t peer_port, - SrsStunPacket& stun_binding_response) +srs_error_t SrsRtcSession::on_stun(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req) { srs_error_t err = srs_success; - stun_binding_response.set_message_type(BindingResponse); - stun_binding_response.set_local_ufrag(stun_packet.get_remote_ufrag()); - stun_binding_response.set_remote_ufrag(stun_packet.get_local_ufrag()); - stun_binding_response.set_transcation_id(stun_packet.get_transcation_id()); - stun_binding_response.set_mapped_address(be32toh(inet_addr(peer_ip.c_str()))); - stun_binding_response.set_mapped_port(peer_port); + if (stun_req->is_binding_request()) { + if (on_binding_request(udp_remux_socket, stun_req) != srs_success) { + return srs_error_wrap(err, "stun binding request failed"); + } + } return err; } -srs_error_t SrsRtcSession::send_client_hello(srs_netfd_t fd, const sockaddr* from, int fromlen) +srs_error_t SrsRtcSession::on_binding_request(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req) { - if (dtls_session == NULL) { - dtls_session = new SrsDtlsSession(fd, from, fromlen); + srs_error_t err = srs_success; + + SrsStunPacket stun_binding_response; + char buf[1460]; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); + SrsAutoFree(SrsBuffer, stream); + + stun_binding_response.set_message_type(BindingResponse); + stun_binding_response.set_local_ufrag(stun_req->get_remote_ufrag()); + stun_binding_response.set_remote_ufrag(stun_req->get_local_ufrag()); + stun_binding_response.set_transcation_id(stun_req->get_transcation_id()); + // FIXME: inet_addr is deprecated, IPV6 support + stun_binding_response.set_mapped_address(be32toh(inet_addr(udp_remux_socket->get_peer_ip().c_str()))); + stun_binding_response.set_mapped_port(udp_remux_socket->get_peer_port()); + + if (stun_binding_response.encode(get_local_sdp()->get_ice_pwd(), stream) != srs_success) { + return srs_error_wrap(err, "stun binding response encode failed"); } - dtls_session->send_client_hello(); + if (udp_remux_socket->sendto(stream->data(), stream->pos(), 0) <= 0) { + return srs_error_wrap(err, "stun binding response send failed"); + } + + if (get_session_state() == WAITING_STUN) { + set_session_state(DOING_DTLS_HANDSHAKE); + send_client_hello(udp_remux_socket); + + string peer_id = udp_remux_socket->get_peer_id(); + rtc_server->insert_into_id_sessions(peer_id, this); + } + + // TODO: dtls send client retry + + return err; } -srs_error_t SrsRtcSession::on_dtls(const char* buf, const int nb_buf) +srs_error_t SrsRtcSession::send_client_hello(SrsUdpRemuxSocket* udp_remux_socket) { - dtls_session->on_dtls(buf, nb_buf); + if (dtls_session == NULL) { + dtls_session = new SrsDtlsSession(); + } + + dtls_session->send_client_hello(udp_remux_socket); } -srs_error_t SrsRtcSession::send_packet() +srs_error_t SrsRtcSession::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) { + return dtls_session->on_dtls(udp_remux_socket); } -SrsRtcServer::SrsRtcServer(SrsServer* svr) +SrsRtcServer::SrsRtcServer() { - server = svr; } SrsRtcServer::~SrsRtcServer() @@ -541,32 +583,32 @@ srs_error_t SrsRtcServer::initialize() return err; } -srs_error_t SrsRtcServer::on_udp_packet(srs_netfd_t fd, const string& peer_ip, const int peer_port, - const sockaddr* from, const int fromlen, const char* data, const int size) +srs_error_t SrsRtcServer::on_udp_packet(SrsUdpRemuxSocket* udp_remux_socket) { srs_error_t err = srs_success; - if (is_stun(data, size)) { - return on_stun(fd, peer_ip, peer_port, from, fromlen, data, size); - } else if (is_dtls(data, size)) { - srs_trace("dtls"); - return on_dtls(fd, peer_ip, peer_port, from, fromlen, data, size); - } else if (is_rtp_or_rtcp(data, size)) { - return on_rtp_or_rtcp(fd, peer_ip, peer_port, from, fromlen, data, size); + if (is_stun(udp_remux_socket->data(), udp_remux_socket->size())) { + return on_stun(udp_remux_socket); + } else if (is_dtls(udp_remux_socket->data(), udp_remux_socket->size())) { + return on_dtls(udp_remux_socket); + } else if (is_rtp_or_rtcp(udp_remux_socket->data(), udp_remux_socket->size())) { + return on_rtp_or_rtcp(udp_remux_socket); } - return srs_error_wrap(err, "unknown packet type"); + return srs_error_wrap(err, "unknown udp packet type"); } SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp) { - SrsRtcSession* session = new SrsRtcSession(); + SrsRtcSession* session = new SrsRtcSession(this); - std::string local_ufrag = gen_random_str(8); std::string local_pwd = gen_random_str(32); - + std::string local_ufrag = ""; while (true) { - bool ret = map_ufrag_sessions.insert(make_pair(remote_sdp.get_ice_ufrag(), session)).second; + local_ufrag = gen_random_str(8); + std::string username = local_ufrag + ":" + remote_sdp.get_ice_ufrag(); + + bool ret = map_username_session.insert(make_pair(username, session)).second; if (ret) { break; } @@ -583,105 +625,71 @@ SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsSdp& remote_sdp, SrsSdp return session; } -SrsRtcSession* SrsRtcServer::find_rtc_session_by_ip_port(const string& peer_ip, const uint16_t peer_port) +SrsRtcSession* SrsRtcServer::find_rtc_session_by_peer_id(const string& peer_id) { - ostringstream os; - os << peer_ip << ":" << peer_port; - string key = os.str(); - map::iterator iter = map_ip_port_sessions.find(key); - if (iter == map_ip_port_sessions.end()) { + map::iterator iter = map_id_session.find(peer_id); + if (iter == map_id_session.end()) { return NULL; } return iter->second; } -srs_error_t SrsRtcServer::on_stun(srs_netfd_t fd, const string& peer_ip, const int peer_port, - const sockaddr* from, const int fromlen, const char* data, const int size) +srs_error_t SrsRtcServer::on_stun(SrsUdpRemuxSocket* udp_remux_socket) { srs_error_t err = srs_success; - srs_trace("peer %s:%d stun", peer_ip.c_str(), peer_port); + srs_trace("recv stun packet from %s", udp_remux_socket->get_peer_id().c_str()); SrsStunPacket stun_req; - if (stun_req.decode(data, size) != srs_success) { - return srs_error_wrap(err, "decode stun failed"); + if (stun_req.decode(udp_remux_socket->data(), udp_remux_socket->size()) != srs_success) { + return srs_error_wrap(err, "decode stun packet failed"); } - std::string remote_ufrag = stun_req.get_remote_ufrag(); - SrsRtcSession* rtc_session = find_rtc_session_by_ufrag(remote_ufrag); + std::string username = stun_req.get_username(); + SrsRtcSession* rtc_session = find_rtc_session_by_username(username); if (rtc_session == NULL) { - return srs_error_wrap(err, "can not find rtc_session, ufrag=%s", remote_ufrag.c_str()); + return srs_error_wrap(err, "can not find rtc_session, stun username=%s", username.c_str()); } - SrsStunPacket stun_rsp; - char buf[1460]; - SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); - SrsAutoFree(SrsBuffer, stream); - - if (stun_req.is_binding_request()) { - if (rtc_session->on_binding_request(stun_req, peer_ip, peer_port, stun_rsp) != srs_success) { - return srs_error_wrap(err, "stun binding request failed"); - } - } - - if (stun_rsp.encode(rtc_session->get_local_sdp()->get_ice_pwd(), stream) != srs_success) { - return srs_error_wrap(err, "stun rsp encode failed"); - } - - srs_sendto(fd, stream->data(), stream->pos(), from, fromlen, 0); - - if (rtc_session->get_session_state() == WAITING_STUN) { - rtc_session->set_session_state(DOING_DTLS_HANDSHAKE); - rtc_session->send_client_hello(fd, from, fromlen); - - insert_into_ip_port_sessions(peer_ip, peer_port, rtc_session); - } - - return err; + return rtc_session->on_stun(udp_remux_socket, &stun_req); } -srs_error_t SrsRtcServer::on_dtls(srs_netfd_t fd, const string& peer_ip, const int peer_port, - const sockaddr* from, const int fromlen, const char* data, const int size) +srs_error_t SrsRtcServer::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) { srs_error_t err = srs_success; srs_trace("on dtls"); // FIXME - SrsRtcSession* rtc_session = find_rtc_session_by_ip_port(peer_ip, peer_port); + SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_remux_socket->get_peer_id()); if (rtc_session == NULL) { - return srs_error_wrap(err, "can not find rtc session by ip=%s, port=%u", peer_ip.c_str(), peer_port); + return srs_error_wrap(err, "can not find rtc session by peer_id=%s", udp_remux_socket->get_peer_id().c_str()); } - rtc_session->on_dtls(data, size); + rtc_session->on_dtls(udp_remux_socket); return err; } -srs_error_t SrsRtcServer::on_rtp_or_rtcp(srs_netfd_t fd, const string& peer_ip, const int peer_port, - const sockaddr* from, const int fromlen, const char* data, const int size) +srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket) { srs_error_t err = srs_success; srs_trace("on rtp/rtcp"); return err; } -SrsRtcSession* SrsRtcServer::find_rtc_session_by_ufrag(const std::string& ufrag) +SrsRtcSession* SrsRtcServer::find_rtc_session_by_username(const std::string& username) { - map::iterator iter = map_ufrag_sessions.find(ufrag); - if (iter == map_ufrag_sessions.end()) { + map::iterator iter = map_username_session.find(username); + if (iter == map_username_session.end()) { return NULL; } return iter->second; } -bool SrsRtcServer::insert_into_ip_port_sessions(const string& peer_ip, const uint16_t peer_port, SrsRtcSession* rtc_session) +bool SrsRtcServer::insert_into_id_sessions(const string& peer_id, SrsRtcSession* rtc_session) { - ostringstream os; - os << peer_ip << ":" << peer_port; - string key = os.str(); - - return map_ip_port_sessions.insert(make_pair(key, rtc_session)).second; + return map_id_session.insert(make_pair(peer_id, rtc_session)).second; } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index b9d60d07e5..e715e81516 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -25,6 +25,7 @@ #define SRS_APP_RTC_CONN_HPP #include +#include #include #include @@ -34,6 +35,7 @@ #include #include +class SrsUdpRemuxSocket; class SrsServer; class SrsStunPacket; @@ -103,37 +105,39 @@ class SrsDtlsSession srtp_t srtp_send; srtp_t srtp_recv; - srs_netfd_t fd; - const sockaddr* from; - int fromlen; - bool handshake_done; public: - SrsDtlsSession(srs_netfd_t lfd, const sockaddr* f, int fl); + SrsDtlsSession(); virtual ~SrsDtlsSession(); - srs_error_t on_dtls(const char* data, const int len); + srs_error_t on_dtls(SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t on_dtls_handshake_done(); srs_error_t on_dtls_application_data(const char* data, const int len); - void send_client_hello(); - srs_error_t handshake(); + void send_client_hello(SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t handshake(SrsUdpRemuxSocket* udp_remux_socket); + +private: srs_error_t srtp_init(); srs_error_t srtp_sender_side_init(); srs_error_t srtp_receiver_side_init(); }; +class SrsRtcServer; + class SrsRtcSession { private: + SrsRtcServer* rtc_server; SrsSdp remote_sdp; SrsSdp local_sdp; SrsRtcSessionStateType session_state; SrsDtlsSession* dtls_session; public: - SrsRtcSession(); + SrsRtcSession(SrsRtcServer* svr); virtual ~SrsRtcSession(); - +public: SrsSdp* get_local_sdp() { return &local_sdp; } SrsSdp* get_remote_sdp() { return &remote_sdp; } SrsRtcSessionStateType get_session_state() { return session_state; } @@ -141,40 +145,37 @@ class SrsRtcSession void set_local_sdp(const SrsSdp& sdp) { local_sdp = sdp; } void set_remote_sdp(const SrsSdp& sdp) { remote_sdp = sdp; } void set_session_state(SrsRtcSessionStateType state) { session_state = state; } - - srs_error_t on_udp_packet(const std::string& peer_ip, const int peer_port, const char* data, const int size); - srs_error_t on_binding_request(const SrsStunPacket& stun_packet, const std::string& peer_ip, const uint16_t peer_port, - SrsStunPacket& stun_binding_response); - srs_error_t on_dtls(const char* buf, const int nb_buf); - srs_error_t send_client_hello(srs_netfd_t fd, const sockaddr* from, int fromlen); - srs_error_t send_packet(); +public: + srs_error_t on_stun(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req); + srs_error_t on_dtls(SrsUdpRemuxSocket* udp_remux_socket); +public: + srs_error_t send_client_hello(SrsUdpRemuxSocket* udp_remux_socket); +private: + srs_error_t on_binding_request(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req); }; -class SrsRtcServer +class SrsRtcServer : public ISrsUdpRemuxHandler { private: - SrsServer* server; - std::map map_ufrag_sessions; - std::map map_ip_port_sessions; + std::map map_username_session; // key: username(local_ufrag + ":" + remote_ufrag) + std::map map_id_session; // key: peerip(ip + ":" + port) public: - SrsRtcServer(SrsServer* svr); + SrsRtcServer(); virtual ~SrsRtcServer(); public: virtual srs_error_t initialize(); - virtual srs_error_t on_udp_packet(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, - const sockaddr* from, const int fromlen, const char* data, const int size); + virtual srs_error_t on_udp_packet(SrsUdpRemuxSocket* udp_remux_socket); SrsRtcSession* create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp); - bool insert_into_ip_port_sessions(const std::string& peer_ip, const uint16_t peer_port, SrsRtcSession* rtc_session); + bool insert_into_id_sessions(const std::string& peer_id, SrsRtcSession* rtc_session); private: - srs_error_t on_stun(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, const sockaddr* from, const int fromlen, const char* data, const int size); - srs_error_t on_dtls(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, const sockaddr* from, const int fromlen, const char* data, const int size); - srs_error_t on_rtp_or_rtcp(srs_netfd_t fd, const std::string& peer_ip, const int peer_port, - const sockaddr* from, const int fromlen, const char* data, const int size); + srs_error_t on_stun(SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t on_dtls(SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket); private: - SrsRtcSession* find_rtc_session_by_ufrag(const std::string& ufrag); - SrsRtcSession* find_rtc_session_by_ip_port(const std::string& peer_ip, const uint16_t peer_port); + SrsRtcSession* find_rtc_session_by_username(const std::string& ufrag); + SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id); }; #endif diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index cdd9394085..d630ca35d5 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -44,7 +44,6 @@ using namespace std; #include #include #include -#include #include #include #include @@ -342,7 +341,7 @@ SrsUdpCasterListener::~SrsUdpCasterListener() SrsRtcListener::SrsRtcListener(SrsServer* svr, SrsRtcServer* rtc_svr, SrsListenerType t) : SrsListener(svr, t) { srs_assert(type == SrsListenerRtc); - rtc = new SrsRtc(rtc_svr); + rtc = rtc_svr; } SrsRtcListener::~SrsRtcListener() @@ -528,7 +527,7 @@ SrsServer::SrsServer() // new these objects in initialize instead. http_api_mux = new SrsHttpServeMux(); http_server = new SrsHttpServer(this); - rtc_server = new SrsRtcServer(this); + rtc_server = new SrsRtcServer(); http_heartbeat = new SrsHttpHeartbeat(); ingester = new SrsIngester(); } diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp index 50284c785e..a057715d6f 100644 --- a/trunk/src/protocol/srs_stun_stack.cpp +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -129,6 +129,7 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) switch (type) { // FIXME: enum case 6: { + username = val; size_t p = val.find(":"); if (p != string::npos) { local_ufrag = val.substr(0, p); diff --git a/trunk/src/protocol/srs_stun_stack.hpp b/trunk/src/protocol/srs_stun_stack.hpp index 80bba8a151..aa2bc21925 100644 --- a/trunk/src/protocol/srs_stun_stack.hpp +++ b/trunk/src/protocol/srs_stun_stack.hpp @@ -70,6 +70,7 @@ class SrsStunPacket { private: uint16_t message_type; + std::string username; std::string local_ufrag; std::string remote_ufrag; std::string transcation_id; @@ -83,6 +84,7 @@ class SrsStunPacket bool is_binding_response() const { return message_type == BindingResponse; } uint16_t get_message_type() const { return message_type; } + std::string get_username() const { return username; } std::string get_local_ufrag() const { return local_ufrag; } std::string get_remote_ufrag() const { return remote_ufrag; } std::string get_transcation_id() const { return transcation_id; } From 2e68c375e34de1aaa5849c1bbd59aebe05f4d2fe Mon Sep 17 00:00:00 2001 From: HuyaJohn Date: Sun, 8 Mar 2020 04:20:46 -0700 Subject: [PATCH 12/69] start coding flv->rtp --- trunk/configure | 2 +- trunk/src/app/srs_app_rtc_conn.cpp | 8 +- trunk/src/app/srs_app_rtp.cpp | 285 +++++++++++++++++++++++++++++ trunk/src/app/srs_app_rtp.hpp | 87 +++++++++ trunk/src/app/srs_app_source.cpp | 25 ++- trunk/src/app/srs_app_source.hpp | 3 + 6 files changed, 404 insertions(+), 6 deletions(-) create mode 100644 trunk/src/app/srs_app_rtp.cpp create mode 100644 trunk/src/app/srs_app_rtp.hpp diff --git a/trunk/configure b/trunk/configure index 6d3da2bff2..c939a96c45 100755 --- a/trunk/configure +++ b/trunk/configure @@ -257,7 +257,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" - "srs_app_mpegts_udp" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" + "srs_app_mpegts_udp" "srs_app_rtp" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" "srs_app_coworkers" "srs_app_hybrid") diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index bfc5c09f47..97f640f333 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -47,14 +47,14 @@ static bool is_stun(const char* data, const int size) return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); } -static bool is_rtp_or_rtcp(const char* data, const int size) +static bool is_dtls(const char* data, size_t len) { - return data != NULL && size > 0 && (data[0] >= 128 && data[0] <= 191); + return (len >= 13 && (data[0] > 19 && data[0] < 64)); } -static bool is_dtls(const char* data, const int size) +static bool is_rtp_or_rtcp(const char* data, size_t len) { - return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); + return (len >= 12 && (data[0] & 0xC0) == 0x80); } static string gen_random_str(int len) diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp new file mode 100644 index 0000000000..015141f847 --- /dev/null +++ b/trunk/src/app/srs_app_rtp.cpp @@ -0,0 +1,285 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len); +static string dump_string_hex(const std::string& str, const int& max_len = 128) +{ + return dump_string_hex(str.c_str(), str.size(), max_len); +} + +static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = 128) +{ + char tmp_buf[1024*16]; + int len = 0; + + for (int i = 0; i < nb_buf && i < max_len; ++i) { + int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 1, "%02X ", (uint8_t)buf[i]); + if (nb <= 0) + break; + + len += nb; + } + tmp_buf[len] = '\0'; + + return string(tmp_buf, len); +} + + +SrsRtpRawFrame::SrsRtpRawFrame(char* buf, int len) +{ + if (buf && len > 0) { + payload = new char[len]; + size = len; + memcpy(payload, buf, len); + } else { + payload = NULL; + size = 0; + } +} + +SrsRtpRawFrame::~SrsRtpRawFrame() +{ + if (payload) { + delete [] payload; + payload = NULL; + size = 0; + } +} + +srs_error_t SrsRtpRawFrame::avcc_to_annexb() +{ + srs_error_t err = srs_success; + + if (! (payload[0] == 0x00 && payload[1] == 0x00 && payload[2] == 0x00 && payload[3] == 0x01)) { + } + + return err; +} + +srs_error_t SrsRtpRawFrame::frame_to_packet() +{ + srs_error_t err = srs_success; + if (payload == NULL || size <= 4) { + return srs_error_wrap(err, "invalid rtp raw frame"); + } + + avcc_to_annexb(); + + char buf[1500] = {0}; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); +} + +SrsRtpMuxer::SrsRtpMuxer() +{ +} + +SrsRtpMuxer::~SrsRtpMuxer() +{ +} + +srs_error_t SrsRtpMuxer::video_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format) +{ + srs_error_t err = srs_success; + + if (shared_video->size < 5) { + return srs_error_wrap(err, "invalid video size:%d", shared_video->size); + } + + SrsRtpRawFrame* rtp_raw_frame = new SrsRtpRawFrame(shared_video->payload + 5, shared_video->size - 5); + SrsAutoFree(SrsRtpRawFrame, rtp_raw_frame); + + rtp_raw_frame->frame_to_packet(); + + srs_trace("video dump=%s", dump_string_hex(shared_video->payload, shared_video->size).c_str()); + + //srs_avcc_to_annexb(raw, raw_len); + + return err; +} + +srs_error_t SrsRtpMuxer::audio_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format) +{ + srs_error_t err = srs_success; + + return err; +} + +SrsRtp::SrsRtp() +{ + req = NULL; + hub = NULL; + + enabled = false; + disposable = false; + last_update_time = 0; +} + +SrsRtp::~SrsRtp() +{ +} + +void SrsRtp::dispose() +{ + if (enabled) { + on_unpublish(); + } +} + +srs_error_t SrsRtp::cycle() +{ + srs_error_t err = srs_success; + + return err; +} + +srs_error_t SrsRtp::initialize(SrsOriginHub* h, SrsRequest* r) +{ + srs_error_t err = srs_success; + + hub = h; + req = r; + + rtp_muxer = new SrsRtpMuxer(); + + return err; +} + +srs_error_t SrsRtp::on_publish() +{ + srs_error_t err = srs_success; + + // update the hls time, for hls_dispose. + last_update_time = srs_get_system_time(); + + // support multiple publish. + if (enabled) { + return err; + } + + // if enabled, open the muxer. + enabled = true; + + // ok, the hls can be dispose, or need to be dispose. + disposable = true; + + return err; +} + +void SrsRtp::on_unpublish() +{ + srs_error_t err = srs_success; + + // support multiple unpublish. + if (!enabled) { + return; + } + + enabled = false; +} + +srs_error_t SrsRtp::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format) +{ + srs_error_t err = srs_success; + + if (!enabled) { + return err; + } + + // Ignore if no format->acodec, it means the codec is not parsed, or unknown codec. + // @issue https://github.com/ossrs/srs/issues/1506#issuecomment-562079474 + if (!format->acodec) { + return err; + } + + // update the hls time, for hls_dispose. + last_update_time = srs_get_system_time(); + + SrsSharedPtrMessage* audio = shared_audio->copy(); + SrsAutoFree(SrsSharedPtrMessage, audio); + + // ts support audio codec: aac/mp3 + SrsAudioCodecId acodec = format->acodec->id; + if (acodec != SrsAudioCodecIdAAC && acodec != SrsAudioCodecIdMP3) { + return err; + } + + // ignore sequence header + srs_assert(format->audio); + + return rtp_muxer->audio_frame_to_packet(audio, format); +} + +srs_error_t SrsRtp::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format) +{ + srs_error_t err = srs_success; + + if (!enabled) { + return err; + } + + // Ignore if no format->vcodec, it means the codec is not parsed, or unknown codec. + // @issue https://github.com/ossrs/srs/issues/1506#issuecomment-562079474 + if (!format->vcodec) { + return err; + } + + // update the hls time, for hls_dispose. + last_update_time = srs_get_system_time(); + + SrsSharedPtrMessage* video = shared_video->copy(); + SrsAutoFree(SrsSharedPtrMessage, video); + + // ignore info frame, + // @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909 + srs_assert(format->video); + return rtp_muxer->video_frame_to_packet(video, format); +} diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp new file mode 100644 index 0000000000..097d2a8a65 --- /dev/null +++ b/trunk/src/app/srs_app_rtp.hpp @@ -0,0 +1,87 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_APP_RTP_HPP +#define SRS_APP_RTP_HPP + +#include + +#include +#include +#include + +class SrsFormat; +class SrsSharedPtrMessage; +class SrsRequest; +class SrsOriginHub; + +class SrsRtpRawFrame +{ +public: + int64_t timestamp; + char* payload; + int size; +public: + SrsRtpRawFrame(char* buf, int len); + virtual ~SrsRtpRawFrame(); +public: + srs_error_t avcc_to_annexb(); + srs_error_t frame_to_packet(); +}; + +class SrsRtpMuxer +{ +private: + std::map packet_queue; +public: + SrsRtpMuxer(); + virtual ~SrsRtpMuxer(); +public: + srs_error_t video_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); + srs_error_t audio_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); +}; + +class SrsRtp +{ +private: + SrsRequest* req; + bool enabled; + bool disposable; + srs_utime_t last_update_time; + SrsRtpMuxer* rtp_muxer; + SrsOriginHub* hub; +public: + SrsRtp(); + virtual ~SrsRtp(); +public: + virtual void dispose(); + virtual srs_error_t cycle(); +public: + virtual srs_error_t initialize(SrsOriginHub* h, SrsRequest* r); + virtual srs_error_t on_publish(); + virtual void on_unpublish(); + virtual srs_error_t on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format); + virtual srs_error_t on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format); +}; + +#endif diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index f5acb05dad..f30eb0163c 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -32,6 +32,7 @@ using namespace std; #include #include #include +#include #include #include #include @@ -824,6 +825,7 @@ SrsOriginHub::SrsOriginHub() dash = new SrsDash(); dvr = new SrsDvr(); encoder = new SrsEncoder(); + rtp = new SrsRtp(); #ifdef SRS_AUTO_HDS hds = new SrsHds(); #endif @@ -868,6 +870,10 @@ srs_error_t SrsOriginHub::initialize(SrsSource* s, SrsRequest* r) return srs_error_wrap(err, "format initialize"); } + if ((err = rtp->initialize(this, req)) != srs_success) { + return srs_error_wrap(err, "rtp initialize"); + } + if ((err = hls->initialize(this, req)) != srs_success) { return srs_error_wrap(err, "hls initialize"); } @@ -965,6 +971,12 @@ srs_error_t SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio) flv_sample_sizes[c->sound_size], flv_sound_types[c->sound_type], srs_flv_srates[c->sound_rate]); } + + if ((err = rtp->on_audio(msg, format)) != srs_success) { + srs_warn("rtp: ignore audio error %s", srs_error_desc(err).c_str()); + srs_error_reset(err); + rtp->on_unpublish(); + } if ((err = hls->on_audio(msg, format)) != srs_success) { // apply the error strategy for hls. @@ -1058,6 +1070,12 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se if (format->vcodec && !format->vcodec->is_avc_codec_ok()) { return err; } + + if ((err = rtp->on_video(msg, format)) != srs_success) { + srs_warn("rtp: ignore video error %s", srs_error_desc(err).c_str()); + srs_error_reset(err); + rtp->on_unpublish(); + } if ((err = hls->on_video(msg, format)) != srs_success) { // apply the error strategy for hls. @@ -1126,6 +1144,10 @@ srs_error_t SrsOriginHub::on_publish() return srs_error_wrap(err, "encoder publish"); } + if ((err = rtp->on_publish()) != srs_success) { + return srs_error_wrap(err, "rtp publish"); + } + if ((err = hls->on_publish()) != srs_success) { return srs_error_wrap(err, "hls publish"); } @@ -1163,6 +1185,7 @@ void SrsOriginHub::on_unpublish() destroy_forwarders(); encoder->on_unpublish(); + rtp->on_unpublish(); hls->on_unpublish(); dash->on_unpublish(); dvr->on_unpublish(); @@ -2224,7 +2247,7 @@ srs_error_t SrsSource::on_video(SrsCommonMessage* shared_video) return srs_error_wrap(err, "create message"); } - // directly process the audio message. + // directly process the video message. if (!mix_correct) { return on_video_imp(&msg); } diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 8cb79f478c..674ffc99e4 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -54,6 +54,7 @@ class SrsNgExec; class SrsConnection; class SrsMessageHeader; class SrsHls; +class SrsRtp; class SrsDvr; class SrsDash; class SrsEncoder; @@ -335,6 +336,8 @@ class SrsOriginHub : public ISrsReloadHandler private: // The format, codec information. SrsRtmpFormat* format; + // rtp handler + SrsRtp* rtp; // hls handler. SrsHls* hls; // The DASH encoder. From 2f462775a020649d00403a4a7409be5ce024c0a1 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Mon, 9 Mar 2020 00:40:30 +0800 Subject: [PATCH 13/69] rtp support --- trunk/src/app/srs_app_rtp.cpp | 75 +++-------------------------- trunk/src/app/srs_app_rtp.hpp | 20 ++------ trunk/src/kernel/srs_kernel_flv.cpp | 6 ++- trunk/src/kernel/srs_kernel_flv.hpp | 6 +++ 4 files changed, 22 insertions(+), 85 deletions(-) diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index 015141f847..52574fd22e 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -73,83 +73,23 @@ static string dump_string_hex(const char* buf, const int nb_buf, const int& max_ return string(tmp_buf, len); } - -SrsRtpRawFrame::SrsRtpRawFrame(char* buf, int len) -{ - if (buf && len > 0) { - payload = new char[len]; - size = len; - memcpy(payload, buf, len); - } else { - payload = NULL; - size = 0; - } -} - -SrsRtpRawFrame::~SrsRtpRawFrame() -{ - if (payload) { - delete [] payload; - payload = NULL; - size = 0; - } -} - -srs_error_t SrsRtpRawFrame::avcc_to_annexb() -{ - srs_error_t err = srs_success; - - if (! (payload[0] == 0x00 && payload[1] == 0x00 && payload[2] == 0x00 && payload[3] == 0x01)) { - } - - return err; -} - -srs_error_t SrsRtpRawFrame::frame_to_packet() -{ - srs_error_t err = srs_success; - if (payload == NULL || size <= 4) { - return srs_error_wrap(err, "invalid rtp raw frame"); - } - - avcc_to_annexb(); - - char buf[1500] = {0}; - SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); -} - SrsRtpMuxer::SrsRtpMuxer() { + sequence = 0; } SrsRtpMuxer::~SrsRtpMuxer() { } -srs_error_t SrsRtpMuxer::video_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format) +srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsFormat* format) { srs_error_t err = srs_success; - if (shared_video->size < 5) { - return srs_error_wrap(err, "invalid video size:%d", shared_video->size); + for (int i = 0; i < format->video->nb_samples; ++i) { + SrsSample sample = format->video->samples[i]; } - SrsRtpRawFrame* rtp_raw_frame = new SrsRtpRawFrame(shared_video->payload + 5, shared_video->size - 5); - SrsAutoFree(SrsRtpRawFrame, rtp_raw_frame); - - rtp_raw_frame->frame_to_packet(); - - srs_trace("video dump=%s", dump_string_hex(shared_video->payload, shared_video->size).c_str()); - - //srs_avcc_to_annexb(raw, raw_len); - - return err; -} - -srs_error_t SrsRtpMuxer::audio_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format) -{ - srs_error_t err = srs_success; - return err; } @@ -188,7 +128,7 @@ srs_error_t SrsRtp::initialize(SrsOriginHub* h, SrsRequest* r) hub = h; req = r; - rtp_muxer = new SrsRtpMuxer(); + rtp_h264_muxer = new SrsRtpMuxer(); return err; } @@ -255,7 +195,8 @@ srs_error_t SrsRtp::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma // ignore sequence header srs_assert(format->audio); - return rtp_muxer->audio_frame_to_packet(audio, format); + // TODO: rtc no support aac + return err; } srs_error_t SrsRtp::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format) @@ -281,5 +222,5 @@ srs_error_t SrsRtp::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* forma // ignore info frame, // @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909 srs_assert(format->video); - return rtp_muxer->video_frame_to_packet(video, format); + return rtp_h264_muxer->frame_to_packet(video, format); } diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp index 097d2a8a65..a113179487 100644 --- a/trunk/src/app/srs_app_rtp.hpp +++ b/trunk/src/app/srs_app_rtp.hpp @@ -35,30 +35,16 @@ class SrsSharedPtrMessage; class SrsRequest; class SrsOriginHub; -class SrsRtpRawFrame -{ -public: - int64_t timestamp; - char* payload; - int size; -public: - SrsRtpRawFrame(char* buf, int len); - virtual ~SrsRtpRawFrame(); -public: - srs_error_t avcc_to_annexb(); - srs_error_t frame_to_packet(); -}; - class SrsRtpMuxer { private: + uint32_t sequence; std::map packet_queue; public: SrsRtpMuxer(); virtual ~SrsRtpMuxer(); public: - srs_error_t video_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); - srs_error_t audio_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); + srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); }; class SrsRtp @@ -68,7 +54,7 @@ class SrsRtp bool enabled; bool disposable; srs_utime_t last_update_time; - SrsRtpMuxer* rtp_muxer; + SrsRtpMuxer* rtp_h264_muxer; SrsOriginHub* hub; public: SrsRtp(); diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index 0259def066..4dc8f68da6 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -203,6 +203,8 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload() { payload = NULL; size = 0; + rtp_fragments = NULL; + nb_rtp_fragments = 0; shared_count = 0; } @@ -214,7 +216,7 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload() srs_freepa(payload); } -SrsSharedPtrMessage::SrsSharedPtrMessage() : timestamp(0), stream_id(0), size(0), payload(NULL) +SrsSharedPtrMessage::SrsSharedPtrMessage() : timestamp(0), stream_id(0), size(0), payload(NULL), rtp_fragments(NULL), nb_rtp_fragments(0) { ptr = NULL; } @@ -345,6 +347,8 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy() copy->stream_id = stream_id; copy->payload = ptr->payload; copy->size = ptr->size; + copy->rtp_fragments = ptr->rtp_fragments; + copy->nb_rtp_fragments = ptr->nb_rtp_fragments; return copy; } diff --git a/trunk/src/kernel/srs_kernel_flv.hpp b/trunk/src/kernel/srs_kernel_flv.hpp index ebc587f39d..30052b8810 100644 --- a/trunk/src/kernel/srs_kernel_flv.hpp +++ b/trunk/src/kernel/srs_kernel_flv.hpp @@ -38,6 +38,7 @@ class ISrsWriter; class ISrsReader; class SrsFileReader; class SrsPacket; +class SrsSample; #define SRS_FLV_TAG_HEADER_SIZE 11 #define SRS_FLV_PREVIOUS_TAG_SIZE 4 @@ -285,6 +286,9 @@ class SrsSharedPtrMessage // @remark, not all message payload can be decoded to packet. for example, // video/audio packet use raw bytes, no video/audio packet. char* payload; + + SrsSample* rtp_fragments; + int nb_rtp_fragments; private: class SrsSharedPtrPayload { @@ -298,6 +302,8 @@ class SrsSharedPtrMessage int size; // The reference count int shared_count; + SrsSample* rtp_fragments; + int nb_rtp_fragments; public: SrsSharedPtrPayload(); virtual ~SrsSharedPtrPayload(); From 3ae510b843c6b54c2e4a5d78c04eecfb036c9819 Mon Sep 17 00:00:00 2001 From: HuyaJohn Date: Mon, 9 Mar 2020 04:46:27 -0700 Subject: [PATCH 14/69] rtp dispatch done, but video can not play in chrome --- trunk/configure | 2 +- trunk/src/app/srs_app_http_api.cpp | 3 +- trunk/src/app/srs_app_rtc_conn.cpp | 214 +++++++++++++++++++++++++--- trunk/src/app/srs_app_rtc_conn.hpp | 52 ++++++- trunk/src/app/srs_app_rtp.cpp | 62 ++++++++ trunk/src/app/srs_app_server.cpp | 2 +- trunk/src/app/srs_app_source.cpp | 3 + trunk/src/kernel/srs_kernel_flv.cpp | 17 +++ trunk/src/kernel/srs_kernel_flv.hpp | 2 + 9 files changed, 325 insertions(+), 32 deletions(-) diff --git a/trunk/configure b/trunk/configure index c939a96c45..495400bb56 100755 --- a/trunk/configure +++ b/trunk/configure @@ -149,7 +149,7 @@ END LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a" if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-lst"; fi # srtp -LibSrtpRoot="${SRS_OBJS_DIR}/srtp2"; LibSrtpFile="${LibSrtpRoot}/lib/libsrtp2.a" +LibSrtpRoot="${SRS_OBJS_DIR}/srtp2/include"; LibSrtpFile="${SRS_OBJS_DIR}/srtp2/lib/libsrtp2.a" if [[ $SRS_SHARED_SRTP == YES ]]; then LibSrtpFile="-lsrtp2"; fi # openssl-1.1.0e, for the RTMP complex handshake. LibSSLRoot="";LibSSLfile="" diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index bb892c57cb..fd418bf86c 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -835,7 +835,8 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* } SrsSdp local_sdp; - rtc_server->create_rtc_session(remote_sdp, local_sdp); + SrsRtcSession* rtc_session = rtc_server->create_rtc_session(remote_sdp, local_sdp); + rtc_session->set_app_stream(app, stream_name); string local_sdp_str = ""; err = local_sdp.encode(local_sdp_str); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 97f640f333..b543c3cae4 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -38,8 +38,12 @@ using namespace std; #include #include #include +#include +#include #include #include +#include +#include #include static bool is_stun(const char* data, const int size) @@ -73,6 +77,29 @@ static string gen_random_str(int len) const int SRTP_MASTER_KEY_KEY_LEN = 16; const int SRTP_MASTER_KEY_SALT_LEN = 14; +static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len); +static string dump_string_hex(const std::string& str, const int& max_len = 128) +{ + return dump_string_hex(str.c_str(), str.size(), max_len); +} + +static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = 128) +{ + char tmp_buf[1024*16]; + int len = 0; + + for (int i = 0; i < nb_buf && i < max_len; ++i) { + int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 1, "%02X ", (uint8_t)buf[i]); + if (nb <= 0) + break; + + len += nb; + } + tmp_buf[len] = '\0'; + + return string(tmp_buf, len); +} + SrsCandidate::SrsCandidate() { } @@ -206,7 +233,7 @@ srs_error_t SrsSdp::encode(string& sdp_str) "a=ssrc:3233846890 msid:6VrfBKXrwK a0\\r\\n" "a=ssrc:3233846890 mslabel:6VrfBKXrwK\\r\\n" "a=ssrc:3233846890 label:6VrfBKXrwKa0\\r\\n" - "m=video 9 UDP/TLS/RTP/SAVPF 96 98 102\\r\\n" + "m=video 9 UDP/TLS/RTP/SAVPF 102\\r\\n" "c=IN IP4 0.0.0.0\\r\\n" + candidate_lines + "a=rtcp:9 IN IP4 0.0.0.0\\r\\n" @@ -221,18 +248,6 @@ srs_error_t SrsSdp::encode(string& sdp_str) "a=sendrecv\\r\\n" "a=mid:1\\r\\n" "a=rtcp-mux\\r\\n" - "a=rtpmap:96 VP8/90000\\r\\n" - "a=rtcp-fb:96 ccm fir\\r\\n" - "a=rtcp-fb:96 nack\\r\\n" - "a=rtcp-fb:96 nack pli\\r\\n" - "a=rtcp-fb:96 goog-remb\\r\\n" - "a=rtcp-fb:96 transport-cc\\r\\n" - "a=rtpmap:98 VP9/90000\\r\\n" - "a=rtcp-fb:98 ccm fir\\r\\n" - "a=rtcp-fb:98 nack\\r\\n" - "a=rtcp-fb:98 nack pli\\r\\n" - "a=rtcp-fb:98 goog-remb\\r\\n" - "a=rtcp-fb:98 transport-cc\\r\\n" "a=rtpmap:102 H264/90000\\r\\n" "a=rtcp-fb:102 goog-remb\\r\\n" "a=rtcp-fb:102 transport-cc\\r\\n" @@ -279,8 +294,10 @@ srs_error_t SrsSdp::parse_attr(const string& line) return err; } -SrsDtlsSession::SrsDtlsSession() +SrsDtlsSession::SrsDtlsSession(SrsRtcSession* s) { + rtc_session = s; + dtls = NULL; bio_in = NULL; bio_out = NULL; @@ -310,7 +327,7 @@ srs_error_t SrsDtlsSession::handshake(SrsUdpRemuxSocket* udp_remux_socket) int ssl_err = SSL_get_error(dtls, ret); switch(ssl_err) { case SSL_ERROR_NONE: { - err = on_dtls_handshake_done(); + err = on_dtls_handshake_done(udp_remux_socket); } break; @@ -362,12 +379,20 @@ srs_error_t SrsDtlsSession::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) return err; } -srs_error_t SrsDtlsSession::on_dtls_handshake_done() +srs_error_t SrsDtlsSession::on_dtls_handshake_done(SrsUdpRemuxSocket* udp_remux_socket) { + srs_error_t err = srs_success; srs_trace("dtls handshake done"); handshake_done = true; - return srtp_init(); + if ((err = srtp_initialize()) != srs_success) { + srs_error("srtp init failed, err=%s", srs_error_desc(err).c_str()); + return srs_error_wrap(err, "srtp init failed"); + } + + rtc_session->on_connection_established(udp_remux_socket); + + return err; } srs_error_t SrsDtlsSession::on_dtls_application_data(const char* buf, const int nb_buf) @@ -394,7 +419,7 @@ void SrsDtlsSession::send_client_hello(SrsUdpRemuxSocket* udp_remux_socket) } } -srs_error_t SrsDtlsSession::srtp_init() +srs_error_t SrsDtlsSession::srtp_initialize() { srs_error_t err = srs_success; @@ -417,6 +442,12 @@ srs_error_t SrsDtlsSession::srtp_init() client_key = sClientMasterKey + sClientMasterSalt; server_key = sServerMasterKey + sServerMasterSalt; + srs_trace("client_key size=%d, server_key=%d", client_key.size(), server_key.size()); + + if (srtp_init() != 0) { + return srs_error_wrap(err, "srtp init failed"); + } + if (srtp_sender_side_init() != srs_success) { return srs_error_wrap(err, "srtp sender size init failed"); } @@ -492,11 +523,132 @@ srs_error_t SrsDtlsSession::srtp_receiver_side_init() return err; } -SrsRtcSession::SrsRtcSession(SrsRtcServer* svr) +srs_error_t SrsDtlsSession::srtp_sender_protect(char* protected_buf, const char* ori_buf, int& nb_protected_buf) +{ + srs_error_t err = srs_success; + + if (srtp_send) { + memcpy(protected_buf, ori_buf, nb_protected_buf); + if (srtp_protect(srtp_send, protected_buf, &nb_protected_buf) != 0) { + srs_error("srtp sender protect failed"); + return srs_error_wrap(err, "srtp sender protect failed"); + } + + return err; + } + + return srs_error_wrap(err, "srtp sender protect failed"); +} + +SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpRemuxSocket* u, int parent_cid) + : ukt(NULL) +{ + _parent_cid = parent_cid; + trd = new SrsDummyCoroutine(); + + rtc_session = s; + ukt = *u; +} + +SrsRtcSenderThread::~SrsRtcSenderThread() +{ + srs_freep(trd); +} + +int SrsRtcSenderThread::cid() +{ + return trd->cid(); +} + +srs_error_t SrsRtcSenderThread::start() +{ + srs_error_t err = srs_success; + + srs_freep(trd); + trd = new SrsSTCoroutine("recv", this, _parent_cid); + + if ((err = trd->start()) != srs_success) { + return srs_error_wrap(err, "recv thread"); + } + + return err; +} + +void SrsRtcSenderThread::stop() +{ + trd->stop(); +} + +void SrsRtcSenderThread::stop_loop() { - rtc_server = svr; + trd->interrupt(); +} + + +srs_error_t SrsRtcSenderThread::cycle() +{ + srs_error_t err = srs_success; + + SrsSource* source = NULL; + SrsRequest req; + req.app = rtc_session->app; + req.stream = rtc_session->stream; + + if (_srs_sources->fetch_or_create(&req, rtc_session->server, &source) != srs_success) { + srs_error("rtc fetch source failed"); + return srs_error_wrap(err, "rtc fetch source failed"); + } + + srs_trace("rtc fetch source success, app=%s, stream=%s", rtc_session->app.c_str(), rtc_session->stream.c_str()); + + SrsConsumer* consumer = NULL; + if (source->create_consumer(NULL, consumer) != srs_success) { + srs_trace("rtc create consumer, app=%s, stream=%s", rtc_session->app.c_str(), rtc_session->stream.c_str()); + return srs_error_wrap(err, "rtc create consumer, app=%s, stream=%s", rtc_session->app.c_str(), rtc_session->stream.c_str()); + } + + SrsAutoFree(SrsConsumer, consumer); + + while (true) { + SrsMessageArray msgs(SRS_PERF_MW_MSGS); + + int msg_count = 0; + if (consumer->dump_packets(&msgs, msg_count) != srs_success) { + srs_trace("rtc pop no rtp packets"); + continue; + } + + srs_trace("rtc pop %d rtp packets", msg_count); + + for (int i = 0; i < msg_count; i++) { + SrsSharedPtrMessage* msg = msgs.msgs[i]; + + for (int i = 0; i < msg->nb_rtp_fragments; ++i) { + srs_trace("rtp fragment size=%d, payload=%s", msg->rtp_fragments[i].size, + dump_string_hex(msg->rtp_fragments[i].bytes, msg->rtp_fragments[i].size, 128).c_str()); + + if (rtc_session->dtls_session) { + char rtp_send_protected_buf[1500]; + int rtp_send_protected_len = msg->rtp_fragments[i].size; + rtc_session->dtls_session->srtp_sender_protect(rtp_send_protected_buf, msg->rtp_fragments[i].bytes, rtp_send_protected_len); + ukt.sendto(rtp_send_protected_buf, rtp_send_protected_len, 0); + } + } + } + + srs_usleep(16000); + } +} + + +SrsRtcSession::SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr) +{ + server = svr; + rtc_server = rtc_svr; session_state = INIT; dtls_session = NULL; + + strd = NULL; } SrsRtcSession::~SrsRtcSession() @@ -557,19 +709,35 @@ srs_error_t SrsRtcSession::on_binding_request(SrsUdpRemuxSocket* udp_remux_socke srs_error_t SrsRtcSession::send_client_hello(SrsUdpRemuxSocket* udp_remux_socket) { if (dtls_session == NULL) { - dtls_session = new SrsDtlsSession(); + dtls_session = new SrsDtlsSession(this); } dtls_session->send_client_hello(udp_remux_socket); } +void SrsRtcSession::on_connection_established(SrsUdpRemuxSocket* udp_remux_socket) +{ + start_play(udp_remux_socket); +} + +srs_error_t SrsRtcSession::start_play(SrsUdpRemuxSocket* udp_remux_socket) +{ + srs_error_t err = srs_success; + + strd = new SrsRtcSenderThread(this, udp_remux_socket, _srs_context->get_id()); + strd->start(); + + return err; +} + srs_error_t SrsRtcSession::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) { return dtls_session->on_dtls(udp_remux_socket); } -SrsRtcServer::SrsRtcServer() +SrsRtcServer::SrsRtcServer(SrsServer* svr) { + server = svr; } SrsRtcServer::~SrsRtcServer() @@ -600,7 +768,7 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpRemuxSocket* udp_remux_socket) SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp) { - SrsRtcSession* session = new SrsRtcSession(this); + SrsRtcSession* session = new SrsRtcSession(server, this); std::string local_pwd = gen_random_str(32); std::string local_ufrag = ""; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index e715e81516..4f06065717 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -37,7 +37,10 @@ class SrsUdpRemuxSocket; class SrsServer; +class SrsConsumer; class SrsStunPacket; +class SrsRtcServer; +class SrsRtcSession; class SrsCandidate { @@ -95,6 +98,8 @@ enum SrsRtcSessionStateType class SrsDtlsSession { private: + SrsRtcSession* rtc_session; + SSL* dtls; BIO* bio_in; BIO* bio_out; @@ -108,34 +113,62 @@ class SrsDtlsSession bool handshake_done; public: - SrsDtlsSession(); + SrsDtlsSession(SrsRtcSession* s); virtual ~SrsDtlsSession(); srs_error_t on_dtls(SrsUdpRemuxSocket* udp_remux_socket); - srs_error_t on_dtls_handshake_done(); + srs_error_t on_dtls_handshake_done(SrsUdpRemuxSocket* udp_remux_socket); srs_error_t on_dtls_application_data(const char* data, const int len); void send_client_hello(SrsUdpRemuxSocket* udp_remux_socket); srs_error_t handshake(SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t srtp_sender_protect(char* protected_buf, const char* ori_buf, int& nb_protected_buf); private: - srs_error_t srtp_init(); + srs_error_t srtp_initialize(); srs_error_t srtp_sender_side_init(); srs_error_t srtp_receiver_side_init(); }; -class SrsRtcServer; +class SrsRtcSenderThread : public ISrsCoroutineHandler +{ +protected: + SrsCoroutine* trd; + int _parent_cid; +private: + SrsRtcSession* rtc_session; + SrsUdpRemuxSocket ukt; +public: + // Constructor. + // @param tm The receive timeout in srs_utime_t. + SrsRtcSenderThread(SrsRtcSession* s, SrsUdpRemuxSocket* u, int parent_cid); + virtual ~SrsRtcSenderThread(); +public: + virtual int cid(); +public: + virtual srs_error_t start(); + virtual void stop(); + virtual void stop_loop(); +public: + virtual srs_error_t cycle(); +}; class SrsRtcSession { + friend class SrsRtcSenderThread; private: + SrsServer* server; SrsRtcServer* rtc_server; SrsSdp remote_sdp; SrsSdp local_sdp; SrsRtcSessionStateType session_state; SrsDtlsSession* dtls_session; + SrsRtcSenderThread* strd; public: - SrsRtcSession(SrsRtcServer* svr); + std::string app; + std::string stream; +public: + SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr); virtual ~SrsRtcSession(); public: SrsSdp* get_local_sdp() { return &local_sdp; } @@ -145,22 +178,29 @@ class SrsRtcSession void set_local_sdp(const SrsSdp& sdp) { local_sdp = sdp; } void set_remote_sdp(const SrsSdp& sdp) { remote_sdp = sdp; } void set_session_state(SrsRtcSessionStateType state) { session_state = state; } + void set_app_stream(const std::string& a, const std::string& s) { app = a; stream = s; } public: srs_error_t on_stun(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req); srs_error_t on_dtls(SrsUdpRemuxSocket* udp_remux_socket); public: srs_error_t send_client_hello(SrsUdpRemuxSocket* udp_remux_socket); + void on_connection_established(SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t start_play(SrsUdpRemuxSocket* udp_remux_socket); private: srs_error_t on_binding_request(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req); +private: + srs_error_t do_playing(SrsConsumer* consumer, SrsUdpRemuxSocket* udp_remux_socket); }; class SrsRtcServer : public ISrsUdpRemuxHandler { +private: + SrsServer* server; private: std::map map_username_session; // key: username(local_ufrag + ":" + remote_ufrag) std::map map_id_session; // key: peerip(ip + ":" + port) public: - SrsRtcServer(); + SrsRtcServer(SrsServer* svr); virtual ~SrsRtcServer(); public: virtual srs_error_t initialize(); diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index 52574fd22e..e4d005cf57 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -86,9 +86,71 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF { srs_error_t err = srs_success; + SrsSample* samples = new SrsSample[2000]; + int sample_index = 0; for (int i = 0; i < format->video->nb_samples; ++i) { SrsSample sample = format->video->samples[i]; + + srs_trace("nal size=%d, dump=%s", sample.size, dump_string_hex(sample.bytes, sample.size, 128).c_str()); + + static int max_packet_size = 900; + if (sample.size < max_packet_size) { + char* buf = new char[1460]; + SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsAutoFree(SrsBuffer, stream); + // write rtp header first + stream->write_1bytes(0x80); + stream->write_1bytes((1 << 7) | 102); + + stream->write_2bytes(sequence++); + stream->write_4bytes((int32_t)shared_frame->timestamp); + stream->write_4bytes((int32_t)3233846889); + stream->write_bytes(sample.bytes, sample.size); + + samples[sample_index].bytes = stream->data(); + samples[sample_index].size = stream->pos(); + ++sample_index; + } else { + int num_of_packet = (sample.size + max_packet_size) / max_packet_size; + char* p = sample.bytes + 1; + int left_bytes = sample.size - 1; + for (int n = 0; n < num_of_packet; ++n) { + char* buf = new char[1460]; + SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsAutoFree(SrsBuffer, stream); + // write rtp header first + stream->write_1bytes(0x80); + if (n == num_of_packet - 1) { + stream->write_1bytes((1 << 7) | 102); + } else { + stream->write_1bytes(102); + } + + stream->write_2bytes(sequence++); + stream->write_4bytes((int32_t)shared_frame->timestamp); + stream->write_4bytes((int32_t)3233846889); + + stream->write_1bytes(sample.bytes[0] & 0xE0 | 28); + if (n == 0) { + stream->write_1bytes(0x80 | sample.bytes[0] & 0x1F); + } else if (n == num_of_packet - 1) { + stream->write_1bytes(0x40 | sample.bytes[0] & 0x1F); + } else { + stream->write_1bytes(0x00 | sample.bytes[0] & 0x1F); + } + + int len = max_packet_size ? max_packet_size : left_bytes; + stream->write_bytes(p, len); + left_bytes -= len; + p += len; + + samples[sample_index].bytes = stream->data(); + samples[sample_index].size = stream->pos(); + ++sample_index; + } + } } + shared_frame->set_rtp_fragments(samples, sample_index); return err; } diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index d630ca35d5..eee3a9784b 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -527,7 +527,7 @@ SrsServer::SrsServer() // new these objects in initialize instead. http_api_mux = new SrsHttpServeMux(); http_server = new SrsHttpServer(this); - rtc_server = new SrsRtcServer(); + rtc_server = new SrsRtcServer(this); http_heartbeat = new SrsHttpHeartbeat(); ingester = new SrsIngester(); } diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index f30eb0163c..1452bf93da 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1696,6 +1696,7 @@ srs_error_t SrsSourceManager::fetch_or_create(SrsRequest* r, ISrsSourceHandler* SrsSource* source = NULL; if ((source = fetch(r)) != NULL) { + srs_trace("found source"); *pps = source; return err; } @@ -1705,6 +1706,8 @@ srs_error_t SrsSourceManager::fetch_or_create(SrsRequest* r, ISrsSourceHandler* // should always not exists for create a source. srs_assert (pool.find(stream_url) == pool.end()); + + srs_trace("new source, stream_url=%s", stream_url.c_str()); source = new SrsSource(); if ((err = source->initialize(r, h)) != srs_success) { diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index 4dc8f68da6..aa0d3a7ec0 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -214,6 +214,14 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload() srs_memory_unwatch(payload); #endif srs_freepa(payload); + + for (int i = 0; i < nb_rtp_fragments; ++i) { + srs_freep(rtp_fragments[i].bytes); + } + + if (nb_rtp_fragments) { + srs_freepa(rtp_fragments); + } } SrsSharedPtrMessage::SrsSharedPtrMessage() : timestamp(0), stream_id(0), size(0), payload(NULL), rtp_fragments(NULL), nb_rtp_fragments(0) @@ -307,6 +315,15 @@ bool SrsSharedPtrMessage::check(int stream_id) return false; } +void SrsSharedPtrMessage::set_rtp_fragments(SrsSample* samples, int nb_samples) +{ + ptr->rtp_fragments = samples; + ptr->nb_rtp_fragments = nb_samples; + + rtp_fragments = samples; + nb_rtp_fragments = nb_samples; +} + bool SrsSharedPtrMessage::is_av() { return ptr->header.message_type == RTMP_MSG_AudioMessage diff --git a/trunk/src/kernel/srs_kernel_flv.hpp b/trunk/src/kernel/srs_kernel_flv.hpp index 30052b8810..fe8fd9aa03 100644 --- a/trunk/src/kernel/srs_kernel_flv.hpp +++ b/trunk/src/kernel/srs_kernel_flv.hpp @@ -333,6 +333,8 @@ class SrsSharedPtrMessage // check perfer cid and stream id. // @return whether stream id already set. virtual bool check(int stream_id); + + virtual void set_rtp_fragments(SrsSample* samples, int nb_samples); public: virtual bool is_av(); virtual bool is_audio(); From e2675109fbfa61ba5269e5302f22c3119b71e65a Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Tue, 10 Mar 2020 00:45:40 +0800 Subject: [PATCH 15/69] fix rtp h264 packet bug --- trunk/src/app/srs_app_rtc_conn.cpp | 2 +- trunk/src/app/srs_app_rtp.cpp | 69 ++++++++++++++++++------------ trunk/src/app/srs_app_rtp.hpp | 2 +- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index b543c3cae4..f60172072b 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -625,7 +625,7 @@ srs_error_t SrsRtcSenderThread::cycle() for (int i = 0; i < msg->nb_rtp_fragments; ++i) { srs_trace("rtp fragment size=%d, payload=%s", msg->rtp_fragments[i].size, - dump_string_hex(msg->rtp_fragments[i].bytes, msg->rtp_fragments[i].size, 128).c_str()); + dump_string_hex(msg->rtp_fragments[i].bytes, msg->rtp_fragments[i].size, 1460).c_str()); if (rtc_session->dtls_session) { char rtp_send_protected_buf[1500]; diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index e4d005cf57..4081f4534e 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -58,19 +58,17 @@ static string dump_string_hex(const std::string& str, const int& max_len = 128) static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = 128) { - char tmp_buf[1024*16]; - int len = 0; + string ret; + ret.reserve(nb_buf > max_len ? nb_buf * 4 : max_len * 4); + char tmp[64]; for (int i = 0; i < nb_buf && i < max_len; ++i) { - int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 1, "%02X ", (uint8_t)buf[i]); - if (nb <= 0) - break; - - len += nb; + int nb = snprintf(tmp, sizeof(tmp), "%02X ", (uint8_t)buf[i]); + assert(nb == 3); + ret.append(tmp, nb); } - tmp_buf[len] = '\0'; - return string(tmp_buf, len); + return ret; } SrsRtpMuxer::SrsRtpMuxer() @@ -86,15 +84,29 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF { srs_error_t err = srs_success; - SrsSample* samples = new SrsSample[2000]; - int sample_index = 0; - for (int i = 0; i < format->video->nb_samples; ++i) { - SrsSample sample = format->video->samples[i]; + int nb_samples = format->video->nb_samples; + SrsSample* samples = format->video->samples; + + SrsSample sps_pps_samples[2]; + if (format->is_avc_sequence_header()) { + sps_pps_samples[0].bytes = format->vcodec->sequenceParameterSetNALUnit.data(); + sps_pps_samples[0].size = format->vcodec->sequenceParameterSetNALUnit.size(); + sps_pps_samples[1].bytes = format->vcodec->pictureParameterSetNALUnit.data(); + sps_pps_samples[1].size = format->vcodec->pictureParameterSetNALUnit.size(); + + nb_samples = 2; + samples = sps_pps_samples; + } + + SrsSample* rtp_fragment_samples = new SrsSample[2000]; + int rtp_fragment_samples_index = 0; + for (int i = 0; i < nb_samples; ++i) { + SrsSample sample = samples[i]; - srs_trace("nal size=%d, dump=%s", sample.size, dump_string_hex(sample.bytes, sample.size, 128).c_str()); + srs_trace("nal size=%d, dump=%s", sample.size, dump_string_hex(sample.bytes, sample.size, sample.size).c_str()); static int max_packet_size = 900; - if (sample.size < max_packet_size) { + if (sample.size <= max_packet_size) { char* buf = new char[1460]; SrsBuffer* stream = new SrsBuffer(buf, 1460); SrsAutoFree(SrsBuffer, stream); @@ -107,9 +119,10 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF stream->write_4bytes((int32_t)3233846889); stream->write_bytes(sample.bytes, sample.size); - samples[sample_index].bytes = stream->data(); - samples[sample_index].size = stream->pos(); - ++sample_index; + rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); + rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); + + ++rtp_fragment_samples_index; } else { int num_of_packet = (sample.size + max_packet_size) / max_packet_size; char* p = sample.bytes + 1; @@ -130,27 +143,29 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF stream->write_4bytes((int32_t)shared_frame->timestamp); stream->write_4bytes((int32_t)3233846889); - stream->write_1bytes(sample.bytes[0] & 0xE0 | 28); + stream->write_1bytes((sample.bytes[0] & 0xE0) | 28); if (n == 0) { - stream->write_1bytes(0x80 | sample.bytes[0] & 0x1F); + stream->write_1bytes(0x80 | (sample.bytes[0] & 0x1F)); } else if (n == num_of_packet - 1) { - stream->write_1bytes(0x40 | sample.bytes[0] & 0x1F); + stream->write_1bytes(0x40 | (sample.bytes[0] & 0x1F)); } else { - stream->write_1bytes(0x00 | sample.bytes[0] & 0x1F); + stream->write_1bytes(0x00 | (sample.bytes[0] & 0x1F)); } - int len = max_packet_size ? max_packet_size : left_bytes; + int len = left_bytes > max_packet_size ? max_packet_size : left_bytes; stream->write_bytes(p, len); left_bytes -= len; p += len; - samples[sample_index].bytes = stream->data(); - samples[sample_index].size = stream->pos(); - ++sample_index; + rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); + rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); + + ++rtp_fragment_samples_index; + } } } - shared_frame->set_rtp_fragments(samples, sample_index); + shared_frame->set_rtp_fragments(rtp_fragment_samples, rtp_fragment_samples_index); return err; } diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp index a113179487..15b206097c 100644 --- a/trunk/src/app/srs_app_rtp.hpp +++ b/trunk/src/app/srs_app_rtp.hpp @@ -38,7 +38,7 @@ class SrsOriginHub; class SrsRtpMuxer { private: - uint32_t sequence; + uint16_t sequence; std::map packet_queue; public: SrsRtpMuxer(); From ff0e03800d306f0cb0db311dd7eb6312f9a1faed Mon Sep 17 00:00:00 2001 From: HuyaJohn Date: Tue, 10 Mar 2020 04:47:49 -0700 Subject: [PATCH 16/69] h264 rtp debuging --- trunk/src/app/srs_app_rtc_conn.cpp | 93 +++++++++++- trunk/src/app/srs_app_rtc_conn.hpp | 2 + trunk/src/app/srs_app_rtp.cpp | 219 +++++++++++++++++++++++++++-- 3 files changed, 300 insertions(+), 14 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index f60172072b..a901efab90 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -86,14 +86,20 @@ static string dump_string_hex(const std::string& str, const int& max_len = 128) static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = 128) { char tmp_buf[1024*16]; - int len = 0; + tmp_buf[0] = '\n'; + int len = 1; for (int i = 0; i < nb_buf && i < max_len; ++i) { - int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 1, "%02X ", (uint8_t)buf[i]); + //int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "(%03d)%02X ", i, (uint8_t)buf[i]); + int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "%02X ", (uint8_t)buf[i]); if (nb <= 0) break; len += nb; + + if (i % 16 == 15) { + tmp_buf[len++] = '\n'; + } } tmp_buf[len] = '\0'; @@ -540,6 +546,23 @@ srs_error_t SrsDtlsSession::srtp_sender_protect(char* protected_buf, const char* return srs_error_wrap(err, "srtp sender protect failed"); } +srs_error_t SrsDtlsSession::srtp_receiver_unprotect(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf) +{ + srs_error_t err = srs_success; + + if (srtp_send) { + memcpy(unprotected_buf, ori_buf, nb_unprotected_buf); + if (srtp_unprotect(srtp_recv, unprotected_buf, &nb_unprotected_buf) != 0) { + srs_error("srtp receiver unprotect failed"); + return srs_error_wrap(err, "srtp receiver unprotect failed"); + } + + return err; + } + + return srs_error_wrap(err, "srtp receiver unprotect failed"); +} + SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpRemuxSocket* u, int parent_cid) : ukt(NULL) { @@ -627,6 +650,12 @@ srs_error_t SrsRtcSenderThread::cycle() srs_trace("rtp fragment size=%d, payload=%s", msg->rtp_fragments[i].size, dump_string_hex(msg->rtp_fragments[i].bytes, msg->rtp_fragments[i].size, 1460).c_str()); + SrsBuffer stream(msg->rtp_fragments[i].bytes + 2, 2); + static uint16_t seq = 0; + stream.write_2bytes(++seq); + + srs_trace("seq=%u", seq); + if (rtc_session->dtls_session) { char rtp_send_protected_buf[1500]; int rtp_send_protected_len = msg->rtp_fragments[i].size; @@ -735,6 +764,56 @@ srs_error_t SrsRtcSession::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) return dtls_session->on_dtls(udp_remux_socket); } +srs_error_t SrsRtcSession::on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket) +{ + srs_error_t err = srs_success; + if (dtls_session == NULL) { + return srs_error_wrap(err, "recv unexpect rtp/rtcp packet before dtls done"); + } + + char srtp_unprotect_buf[1460]; + int nb_srtp_unprotect_buf = udp_remux_socket->size(); + if (dtls_session->srtp_receiver_unprotect(srtp_unprotect_buf, udp_remux_socket->data(), nb_srtp_unprotect_buf) != srs_success) { + return srs_error_wrap(err, "srtp receiver unprotect failed"); + } + + //srs_trace("srtp unprotect success, %s", dump_string_hex(srtp_unprotect_buf, nb_srtp_unprotect_buf, nb_srtp_unprotect_buf).c_str()); + + SrsBuffer* stream = new SrsBuffer(srtp_unprotect_buf, nb_srtp_unprotect_buf); + uint8_t first = stream->read_1bytes(); + uint8_t second = stream->read_1bytes(); + bool marker = (second & 0x80) == 0x80; + uint8_t payload_type = second &0x7F; + + uint16_t sequence = stream->read_2bytes(); + uint32_t timestamp = stream->read_4bytes(); + uint32_t ssrc = stream->read_4bytes(); + + srs_trace("sequence=%u, timestamp=%u, ssrc=%u, marker=%d, payload_type=%u", sequence, timestamp, ssrc, marker, payload_type); + + if (first & 0x10) { + uint16_t extern_profile = stream->read_2bytes(); + uint16_t extern_length = stream->read_2bytes(); + + srs_trace("extern_profile=%u, extern_length=%u", extern_profile, extern_length); + + stream->read_string(extern_length * 4); + } + + if (payload_type == 102) { + char rtp_send_protected_buf[1500]; + int rtp_send_protected_len = nb_srtp_unprotect_buf; + SrsBuffer stream(srtp_unprotect_buf + 8, 4); + stream.write_4bytes(3233846889); + dtls_session->srtp_sender_protect(rtp_send_protected_buf, srtp_unprotect_buf, rtp_send_protected_len); + udp_remux_socket->sendto(rtp_send_protected_buf, rtp_send_protected_len, 0); + } + + srs_trace("rtp payload, %s", dump_string_hex(stream->data() + stream->pos(), stream->left(), stream->left()).c_str()); + + return err; +} + SrsRtcServer::SrsRtcServer(SrsServer* svr) { server = svr; @@ -828,7 +907,6 @@ srs_error_t SrsRtcServer::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) srs_error_t err = srs_success; srs_trace("on dtls"); - // FIXME SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_remux_socket->get_peer_id()); if (rtc_session == NULL) { @@ -844,6 +922,15 @@ srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket) { srs_error_t err = srs_success; srs_trace("on rtp/rtcp"); + + SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_remux_socket->get_peer_id()); + + if (rtc_session == NULL) { + return srs_error_wrap(err, "can not find rtc session by peer_id=%s", udp_remux_socket->get_peer_id().c_str()); + } + + rtc_session->on_rtp_or_rtcp(udp_remux_socket); + return err; } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 4f06065717..fab2afc4c5 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -123,6 +123,7 @@ class SrsDtlsSession void send_client_hello(SrsUdpRemuxSocket* udp_remux_socket); srs_error_t handshake(SrsUdpRemuxSocket* udp_remux_socket); srs_error_t srtp_sender_protect(char* protected_buf, const char* ori_buf, int& nb_protected_buf); + srs_error_t srtp_receiver_unprotect(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); private: srs_error_t srtp_initialize(); @@ -182,6 +183,7 @@ class SrsRtcSession public: srs_error_t on_stun(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req); srs_error_t on_dtls(SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket); public: srs_error_t send_client_hello(SrsUdpRemuxSocket* udp_remux_socket); void on_connection_established(SrsUdpRemuxSocket* udp_remux_socket); diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index 4081f4534e..d3bf6534f0 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -53,20 +53,34 @@ using namespace std; static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len); static string dump_string_hex(const std::string& str, const int& max_len = 128) { - return dump_string_hex(str.c_str(), str.size(), max_len); + return dump_string_hex(str.c_str(), str.size(), max_len); } static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = 128) { string ret; - ret.reserve(nb_buf > max_len ? nb_buf * 4 : max_len * 4); + ret.reserve((nb_buf > max_len ? nb_buf : max_len) * 8); + + char tmp_buf[1024*16]; + tmp_buf[0] = '\n'; + int len = 1; - char tmp[64]; for (int i = 0; i < nb_buf && i < max_len; ++i) { - int nb = snprintf(tmp, sizeof(tmp), "%02X ", (uint8_t)buf[i]); - assert(nb == 3); - ret.append(tmp, nb); + //int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "(%03d)%02X ", i, (uint8_t)buf[i]); + int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "%02X ", (uint8_t)buf[i]); + if (nb <= 0) + break; + + len += nb; + + if (i % 16 == 15) { + tmp_buf[len++] = '\n'; + ret.append(tmp_buf, len); + len = 0; + } } + tmp_buf[len] = '\0'; + ret.append(tmp_buf, len); return ret; } @@ -80,6 +94,7 @@ SrsRtpMuxer::~SrsRtpMuxer() { } +#if 0 srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsFormat* format) { srs_error_t err = srs_success; @@ -87,6 +102,15 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF int nb_samples = format->video->nb_samples; SrsSample* samples = format->video->samples; + SrsSample* rtp_fragment_samples = new SrsSample[2000]; + int rtp_fragment_samples_index = 0; + + static int debug_fd = -1; + static uint8_t start_code[4] = {0x00, 0x00, 0x00, 0x01}; + if (debug_fd < 0) { + debug_fd = open("./raw.264", O_CREAT|O_TRUNC|O_RDWR, 0664); + } + SrsSample sps_pps_samples[2]; if (format->is_avc_sequence_header()) { sps_pps_samples[0].bytes = format->vcodec->sequenceParameterSetNALUnit.data(); @@ -96,15 +120,181 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF nb_samples = 2; samples = sps_pps_samples; + + { + char* buf = new char[1460]; + SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsAutoFree(SrsBuffer, stream); + // write rtp header first + stream->write_1bytes(0x80); + stream->write_1bytes(102); + + stream->write_2bytes(sequence++); + stream->write_4bytes((int32_t)shared_frame->timestamp * 90); + stream->write_4bytes((int32_t)3233846889); + + stream->write_1bytes(24/*STAP-A*/); + // AUD + stream->write_2bytes(2); + stream->write_1bytes(0x09); + stream->write_1bytes(0x10); + + stream->write_2bytes(sps_pps_samples[0].size); + stream->write_bytes(sps_pps_samples[0].bytes, sps_pps_samples[0].size); + stream->write_2bytes(sps_pps_samples[1].size); + stream->write_bytes(sps_pps_samples[1].bytes, sps_pps_samples[1].size); + + if (debug_fd >= 0) { + write(debug_fd, start_code, sizeof(start_code)); + write(debug_fd, sps_pps_samples[0].bytes, sps_pps_samples[0].size); + write(debug_fd, start_code, sizeof(start_code)); + write(debug_fd, sps_pps_samples[1].bytes, sps_pps_samples[1].size); + } + + rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); + rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); + + ++rtp_fragment_samples_index; + } + shared_frame->set_rtp_fragments(rtp_fragment_samples, rtp_fragment_samples_index); + + return err; + } + + for (int i = 0; i < nb_samples; ++i) { + SrsSample sample = samples[i]; + + srs_trace("nal size=%d, dump=%s", sample.size, dump_string_hex(sample.bytes, sample.size, sample.size).c_str()); + + if ((sample.bytes[0] & 0x1F) == 0x06) { + srs_trace("ignore SEI"); + continue; + } + + if (debug_fd >= 0) { + write(debug_fd, start_code, sizeof(start_code)); + write(debug_fd, sample.bytes, sample.size); + } + + static int max_packet_size = 900; + if (sample.size <= max_packet_size) { + char* buf = new char[1460]; + SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsAutoFree(SrsBuffer, stream); + // write rtp header first + stream->write_1bytes(0x80); + if ((sample.bytes[0] & 0x1F) <= 5) { + stream->write_1bytes((1 << 7) | 102); + } else { + stream->write_1bytes(102); + } + + stream->write_2bytes(sequence++); + stream->write_4bytes((int32_t)shared_frame->timestamp * 90); + stream->write_4bytes((int32_t)3233846889); + +#if 0 // single nalu + stream->write_bytes(sample.bytes, sample.size); +#else + stream->write_1bytes((sample.bytes[0] & 0xE0) | 24/*STAP-A*/); + stream->write_2bytes(sample.size); + stream->write_bytes(sample.bytes, sample.size); +#endif + + rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); + rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); + + ++rtp_fragment_samples_index; + } else { + int num_of_packet = (sample.size + max_packet_size) / max_packet_size; + char* p = sample.bytes + 1; + int left_bytes = sample.size - 1; + for (int n = 0; n < num_of_packet; ++n) { + char* buf = new char[1460]; + SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsAutoFree(SrsBuffer, stream); + // write rtp header first + stream->write_1bytes(0x80); + if ((sample.bytes[0] & 0x1F) <= 5) { + stream->write_1bytes((1 << 7) | 102); + } else { + stream->write_1bytes(102); + } + + stream->write_2bytes(sequence++); + stream->write_4bytes((int32_t)shared_frame->timestamp * 90); + stream->write_4bytes((int32_t)3233846889); + + stream->write_1bytes((sample.bytes[0] & 0xE0) | 28); + if (n == 0) { + stream->write_1bytes(0x80 | (sample.bytes[0] & 0x1F)); + } else if (n == num_of_packet - 1) { + stream->write_1bytes(0x40 | (sample.bytes[0] & 0x1F)); + } else { + stream->write_1bytes(0x00 | (sample.bytes[0] & 0x1F)); + } + + int len = left_bytes > max_packet_size ? max_packet_size : left_bytes; + stream->write_bytes(p, len); + left_bytes -= len; + p += len; + + rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); + rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); + + ++rtp_fragment_samples_index; + + } + } } + shared_frame->set_rtp_fragments(rtp_fragment_samples, rtp_fragment_samples_index); + + return err; +} +#endif + +srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsFormat* format) +{ + srs_error_t err = srs_success; + + int nb_samples = format->video->nb_samples; + SrsSample* samples = format->video->samples; SrsSample* rtp_fragment_samples = new SrsSample[2000]; int rtp_fragment_samples_index = 0; + + static int debug_fd = -1; + static uint8_t start_code[4] = {0x00, 0x00, 0x00, 0x01}; + if (debug_fd < 0) { + debug_fd = open("./raw.264", O_CREAT|O_TRUNC|O_RDWR, 0664); + } + + SrsSample sps_pps_samples[2]; + if (format->is_avc_sequence_header()) { + sps_pps_samples[0].bytes = format->vcodec->sequenceParameterSetNALUnit.data(); + sps_pps_samples[0].size = format->vcodec->sequenceParameterSetNALUnit.size(); + sps_pps_samples[1].bytes = format->vcodec->pictureParameterSetNALUnit.data(); + sps_pps_samples[1].size = format->vcodec->pictureParameterSetNALUnit.size(); + + nb_samples = 2; + samples = sps_pps_samples; + } + for (int i = 0; i < nb_samples; ++i) { SrsSample sample = samples[i]; srs_trace("nal size=%d, dump=%s", sample.size, dump_string_hex(sample.bytes, sample.size, sample.size).c_str()); + if ((sample.bytes[0] & 0x1F) == 0x06) { + srs_trace("ignore SEI"); + continue; + } + + if (debug_fd >= 0) { + write(debug_fd, start_code, sizeof(start_code)); + write(debug_fd, sample.bytes, sample.size); + } + static int max_packet_size = 900; if (sample.size <= max_packet_size) { char* buf = new char[1460]; @@ -112,12 +302,19 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF SrsAutoFree(SrsBuffer, stream); // write rtp header first stream->write_1bytes(0x80); - stream->write_1bytes((1 << 7) | 102); + if ((sample.bytes[0] & 0x1F) <= 5) { + stream->write_1bytes((1 << 7) | 102); + } else { + stream->write_1bytes(102); + } stream->write_2bytes(sequence++); - stream->write_4bytes((int32_t)shared_frame->timestamp); + stream->write_4bytes((int32_t)shared_frame->timestamp * 90); stream->write_4bytes((int32_t)3233846889); - stream->write_bytes(sample.bytes, sample.size); + + stream->write_1bytes((sample.bytes[0] & 0xE0) | 28/*FU-A*/); + stream->write_1bytes(0xC0 | (sample.bytes[0] & 0x1F)); + stream->write_bytes(sample.bytes + 1, sample.size - 1); rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); @@ -133,14 +330,14 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF SrsAutoFree(SrsBuffer, stream); // write rtp header first stream->write_1bytes(0x80); - if (n == num_of_packet - 1) { + if ((sample.bytes[0] & 0x1F) <= 5) { stream->write_1bytes((1 << 7) | 102); } else { stream->write_1bytes(102); } stream->write_2bytes(sequence++); - stream->write_4bytes((int32_t)shared_frame->timestamp); + stream->write_4bytes((int32_t)shared_frame->timestamp * 90); stream->write_4bytes((int32_t)3233846889); stream->write_1bytes((sample.bytes[0] & 0xE0) | 28); From e831f3254a64d50a03458ec3788a71b36c691ca5 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Wed, 11 Mar 2020 00:04:12 +0800 Subject: [PATCH 17/69] some code --- trunk/src/app/srs_app_log.cpp | 2 +- trunk/src/app/srs_app_rtc_conn.cpp | 15 +- trunk/src/app/srs_app_rtp.cpp | 264 +++++++++++++++++++---------- trunk/src/app/srs_app_rtp.hpp | 8 +- 4 files changed, 197 insertions(+), 92 deletions(-) diff --git a/trunk/src/app/srs_app_log.cpp b/trunk/src/app/srs_app_log.cpp index 4d73ebf8e2..f743a056c6 100644 --- a/trunk/src/app/srs_app_log.cpp +++ b/trunk/src/app/srs_app_log.cpp @@ -37,7 +37,7 @@ #include // the max size of a line of log. -#define LOG_MAX_SIZE 4096 +#define LOG_MAX_SIZE 4096000 // the tail append to each log. #define LOG_TAIL '\n' diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index a901efab90..af9fad3227 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -85,10 +85,13 @@ static string dump_string_hex(const std::string& str, const int& max_len = 128) static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = 128) { + string ret; + ret.reserve(max_len * 4); + char tmp_buf[1024*16]; tmp_buf[0] = '\n'; int len = 1; - + for (int i = 0; i < nb_buf && i < max_len; ++i) { //int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "(%03d)%02X ", i, (uint8_t)buf[i]); int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "%02X ", (uint8_t)buf[i]); @@ -97,13 +100,17 @@ static string dump_string_hex(const char* buf, const int nb_buf, const int& max_ len += nb; - if (i % 16 == 15) { + if (i % 48 == 47) { tmp_buf[len++] = '\n'; - } + ret.append(tmp_buf, len); + len = 0; + } } tmp_buf[len] = '\0'; + ret.append(tmp_buf, len); + + return ret; - return string(tmp_buf, len); } SrsCandidate::SrsCandidate() diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index d3bf6534f0..3a00d3d341 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -59,7 +59,7 @@ static string dump_string_hex(const std::string& str, const int& max_len = 128) static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = 128) { string ret; - ret.reserve((nb_buf > max_len ? nb_buf : max_len) * 8); + ret.reserve(max_len * 4); char tmp_buf[1024*16]; tmp_buf[0] = '\n'; @@ -73,7 +73,7 @@ static string dump_string_hex(const char* buf, const int nb_buf, const int& max_ len += nb; - if (i % 16 == 15) { + if (i % 48 == 47) { tmp_buf[len++] = '\n'; ret.append(tmp_buf, len); len = 0; @@ -85,6 +85,7 @@ static string dump_string_hex(const char* buf, const int nb_buf, const int& max_ return ret; } + SrsRtpMuxer::SrsRtpMuxer() { sequence = 0; @@ -253,116 +254,207 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF } #endif -srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsFormat* format) -{ - srs_error_t err = srs_success; +const int max_payload_size = 1200; +const int kRtpPacketSize = 1500; - int nb_samples = format->video->nb_samples; - SrsSample* samples = format->video->samples; +const uint8_t kMarker = 0x80; +const uint8_t kH264PayloadType = 102; - SrsSample* rtp_fragment_samples = new SrsSample[2000]; - int rtp_fragment_samples_index = 0; +const uint8_t kNalTypeMask = 0x1F; - static int debug_fd = -1; - static uint8_t start_code[4] = {0x00, 0x00, 0x00, 0x01}; - if (debug_fd < 0) { - debug_fd = open("./raw.264", O_CREAT|O_TRUNC|O_RDWR, 0664); - } +const uint8_t kIdr = 5; +const uint8_t kStapA = 24; +const uint8_t kFua = 28; - SrsSample sps_pps_samples[2]; - if (format->is_avc_sequence_header()) { - sps_pps_samples[0].bytes = format->vcodec->sequenceParameterSetNALUnit.data(); - sps_pps_samples[0].size = format->vcodec->sequenceParameterSetNALUnit.size(); - sps_pps_samples[1].bytes = format->vcodec->pictureParameterSetNALUnit.data(); - sps_pps_samples[1].size = format->vcodec->pictureParameterSetNALUnit.size(); +const uint8_t kStart = 0x80; +const uint8_t kEnd = 0x40; - nb_samples = 2; - samples = sps_pps_samples; +const uint32_t kVideoSSRC = 3233846889; + +srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsFormat* format) +{ + srs_error_t err = srs_success; + + if (format->is_avc_sequence_header()) { + sps.assign(format->vcodec->sequenceParameterSetNALUnit.data(), format->vcodec->sequenceParameterSetNALUnit.size()); + pps.assign(format->vcodec->pictureParameterSetNALUnit.data(), format->vcodec->pictureParameterSetNALUnit.size()); } - for (int i = 0; i < nb_samples; ++i) { - SrsSample sample = samples[i]; + for (int i = 0; i < format->video->nb_samples; ++i) { + SrsSample sample = format->video->samples[i]; - srs_trace("nal size=%d, dump=%s", sample.size, dump_string_hex(sample.bytes, sample.size, sample.size).c_str()); + uint8_t header = sample.bytes[0]; + uint8_t nal_type = header & 0x1F; - if ((sample.bytes[0] & 0x1F) == 0x06) { + if (nal_type == 0x06) { srs_trace("ignore SEI"); continue; } - if (debug_fd >= 0) { - write(debug_fd, start_code, sizeof(start_code)); - write(debug_fd, sample.bytes, sample.size); + if (sample.size <= max_payload_size) { + packet_single_nalu(shared_frame, format, &sample); + } else { + packet_fu_a(shared_frame, format, &sample); } - static int max_packet_size = 900; - if (sample.size <= max_packet_size) { - char* buf = new char[1460]; - SrsBuffer* stream = new SrsBuffer(buf, 1460); - SrsAutoFree(SrsBuffer, stream); - // write rtp header first - stream->write_1bytes(0x80); - if ((sample.bytes[0] & 0x1F) <= 5) { - stream->write_1bytes((1 << 7) | 102); - } else { - stream->write_1bytes(102); - } + srs_trace("nal size=%d, nal=%s", sample.size, dump_string_hex(sample.bytes, sample.size, sample.size).c_str()); + for (int i = 0; i < shared_frame->nb_rtp_fragments; ++i) { + srs_trace("rtp=%s", dump_string_hex(shared_frame->rtp_fragments[i].bytes, shared_frame->rtp_fragments[i].size, kRtpPacketSize).c_str()); + } + } - stream->write_2bytes(sequence++); - stream->write_4bytes((int32_t)shared_frame->timestamp * 90); - stream->write_4bytes((int32_t)3233846889); + return err; +} - stream->write_1bytes((sample.bytes[0] & 0xE0) | 28/*FU-A*/); - stream->write_1bytes(0xC0 | (sample.bytes[0] & 0x1F)); - stream->write_bytes(sample.bytes + 1, sample.size - 1); +srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample) +{ + srs_error_t err = srs_success; - rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); - rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); + vector rtp_packet_vec; - ++rtp_fragment_samples_index; - } else { - int num_of_packet = (sample.size + max_packet_size) / max_packet_size; - char* p = sample.bytes + 1; - int left_bytes = sample.size - 1; - for (int n = 0; n < num_of_packet; ++n) { - char* buf = new char[1460]; - SrsBuffer* stream = new SrsBuffer(buf, 1460); - SrsAutoFree(SrsBuffer, stream); - // write rtp header first - stream->write_1bytes(0x80); - if ((sample.bytes[0] & 0x1F) <= 5) { - stream->write_1bytes((1 << 7) | 102); - } else { - stream->write_1bytes(102); - } + char* p = sample->bytes + 1; + int nb_left = sample->size - 1; + uint8_t header = sample->bytes[0]; + uint8_t nal_type = header & kNalTypeMask; - stream->write_2bytes(sequence++); - stream->write_4bytes((int32_t)shared_frame->timestamp * 90); - stream->write_4bytes((int32_t)3233846889); + if (nal_type == kIdr) { + packet_stap_a(sps, pps, shared_frame, rtp_packet_vec); + } - stream->write_1bytes((sample.bytes[0] & 0xE0) | 28); - if (n == 0) { - stream->write_1bytes(0x80 | (sample.bytes[0] & 0x1F)); - } else if (n == num_of_packet - 1) { - stream->write_1bytes(0x40 | (sample.bytes[0] & 0x1F)); - } else { - stream->write_1bytes(0x00 | (sample.bytes[0] & 0x1F)); - } + int num_of_packet = (sample->size - 1 + max_payload_size) / max_payload_size; + int avg_packet_size = sample->size / num_of_packet; + for (int i = 0; i < num_of_packet; ++i) { + char* buf = new char[kRtpPacketSize]; + SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsAutoFree(SrsBuffer, stream); + + int packet_size = min(nb_left, max_payload_size); + + // v=2,p=0,x=0,cc=0 + stream->write_1bytes(0x80); + // marker payloadtype + stream->write_1bytes(kMarker | kH264PayloadType); + // sequenct + stream->write_2bytes(sequence++); + // timestamp + stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); + // ssrc + stream->write_4bytes(int32_t(kVideoSSRC)); + + // fu-indicate + uint8_t fu_indicate = kFua; + fu_indicate |= (nal_type & (~kNalTypeMask)); + stream->write_1bytes(fu_indicate); + + uint8_t fu_header = nal_type & kNalTypeMask; + if (i == 0) + fu_header |= kStart; + if (i == num_of_packet - 1) + fu_header |= kEnd; + stream->write_1bytes(fu_header); + + stream->write_bytes(p, packet_size); + p += packet_size; + nb_left -= max_payload_size; + + + SrsSample rtp_packet; + rtp_packet.bytes = stream->data(); + rtp_packet.size = stream->pos(); + + rtp_packet_vec.push_back(rtp_packet); + } - int len = left_bytes > max_packet_size ? max_packet_size : left_bytes; - stream->write_bytes(p, len); - left_bytes -= len; - p += len; + SrsSample* rtp_samples = new SrsSample[rtp_packet_vec.size()]; + for (int i = 0; i < rtp_packet_vec.size(); ++i) { + rtp_samples[i] = rtp_packet_vec[i]; + } - rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); - rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); + shared_frame->set_rtp_fragments(rtp_samples, rtp_packet_vec.size()); +} - ++rtp_fragment_samples_index; +srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample) +{ + srs_error_t err = srs_success; - } - } + vector rtp_packet_vec; + + uint8_t header = sample->bytes[0]; + uint8_t nal_type = header & kNalTypeMask; + + char* buf = new char[kRtpPacketSize]; + SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsAutoFree(SrsBuffer, stream); + + if (nal_type == kIdr) { + packet_stap_a(sps, pps, shared_frame, rtp_packet_vec); } - shared_frame->set_rtp_fragments(rtp_fragment_samples, rtp_fragment_samples_index); + + // v=2,p=0,x=0,cc=0 + stream->write_1bytes(0x80); + // marker payloadtype + stream->write_1bytes(kMarker | kH264PayloadType); + // sequenct + stream->write_2bytes(sequence++); + // timestamp + stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); + // ssrc + stream->write_4bytes(int32_t(kVideoSSRC)); + + stream->write_bytes(sample->bytes, sample->size); + + SrsSample rtp_packet; + rtp_packet.bytes = stream->data(); + rtp_packet.size = stream->pos(); + + SrsSample* rtp_samples = new SrsSample[rtp_packet_vec.size()]; + for (int i = 0; i < rtp_packet_vec.size(); ++i) { + rtp_samples[i] = rtp_packet_vec[i]; + } + + shared_frame->set_rtp_fragments(rtp_samples, rtp_packet_vec.size()); + + return err; +} + +srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, SrsSharedPtrMessage* shared_frame, vector& rtp_packet_vec) +{ + srs_error_t err = srs_success; + + uint8_t header = sps[0]; + uint8_t nal_type = header & kNalTypeMask; + + char* buf = new char[kRtpPacketSize]; + SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsAutoFree(SrsBuffer, stream); + + // v=2,p=0,x=0,cc=0 + stream->write_1bytes(0x80); + // marker payloadtype + stream->write_1bytes(kMarker | kH264PayloadType); + // sequenct + stream->write_2bytes(sequence++); + // timestamp + stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); + // ssrc + stream->write_4bytes(int32_t(kVideoSSRC)); + + // stap-a header + uint8_t stap_a_header = kStapA; + stap_a_header |= (nal_type & (~kNalTypeMask)); + stream->write_1bytes(stap_a_header); + + stream->write_2bytes(sps.size()); + stream->write_bytes((char*)sps.data(), sps.size()); + + stream->write_2bytes(pps.size()); + stream->write_bytes((char*)pps.data(), pps.size()); + + SrsSample rtp_packet; + rtp_packet.bytes = stream->data(); + rtp_packet.size = stream->pos(); + + rtp_packet_vec.push_back(rtp_packet); return err; } diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp index 15b206097c..1d0f510ddd 100644 --- a/trunk/src/app/srs_app_rtp.hpp +++ b/trunk/src/app/srs_app_rtp.hpp @@ -31,6 +31,7 @@ #include class SrsFormat; +class SrsSample; class SrsSharedPtrMessage; class SrsRequest; class SrsOriginHub; @@ -39,12 +40,17 @@ class SrsRtpMuxer { private: uint16_t sequence; - std::map packet_queue; + std::string sps; + std::string pps; public: SrsRtpMuxer(); virtual ~SrsRtpMuxer(); public: srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); +private: + srs_error_t packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample); + srs_error_t packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample); + srs_error_t packet_stap_a(const std::string &sps, const std::string& pps, SrsSharedPtrMessage* shared_frame, std::vector& rtp_packet_vec); }; class SrsRtp From da72caf8b9e4b5a3fb5b944ad9f869bab37228f9 Mon Sep 17 00:00:00 2001 From: HuyaJohn Date: Wed, 11 Mar 2020 04:21:44 -0700 Subject: [PATCH 18/69] h264 packet done, chrome play well --- trunk/src/app/srs_app_rtc_conn.cpp | 129 ++++++++----- trunk/src/app/srs_app_rtp.cpp | 274 ++++------------------------ trunk/src/app/srs_app_rtp.hpp | 21 ++- trunk/src/app/srs_app_utility.cpp | 34 ++++ trunk/src/app/srs_app_utility.hpp | 4 + trunk/src/kernel/srs_kernel_flv.cpp | 4 +- 6 files changed, 169 insertions(+), 297 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index af9fad3227..a92a2b5f87 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -30,6 +30,8 @@ using namespace std; #include #include +#include +#include #include @@ -41,7 +43,9 @@ using namespace std; #include #include #include +#include #include +#include #include #include #include @@ -77,42 +81,6 @@ static string gen_random_str(int len) const int SRTP_MASTER_KEY_KEY_LEN = 16; const int SRTP_MASTER_KEY_SALT_LEN = 14; -static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len); -static string dump_string_hex(const std::string& str, const int& max_len = 128) -{ - return dump_string_hex(str.c_str(), str.size(), max_len); -} - -static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = 128) -{ - string ret; - ret.reserve(max_len * 4); - - char tmp_buf[1024*16]; - tmp_buf[0] = '\n'; - int len = 1; - - for (int i = 0; i < nb_buf && i < max_len; ++i) { - //int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "(%03d)%02X ", i, (uint8_t)buf[i]); - int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "%02X ", (uint8_t)buf[i]); - if (nb <= 0) - break; - - len += nb; - - if (i % 48 == 47) { - tmp_buf[len++] = '\n'; - ret.append(tmp_buf, len); - len = 0; - } - } - tmp_buf[len] = '\0'; - ret.append(tmp_buf, len); - - return ret; - -} - SrsCandidate::SrsCandidate() { } @@ -654,14 +622,10 @@ srs_error_t SrsRtcSenderThread::cycle() SrsSharedPtrMessage* msg = msgs.msgs[i]; for (int i = 0; i < msg->nb_rtp_fragments; ++i) { - srs_trace("rtp fragment size=%d, payload=%s", msg->rtp_fragments[i].size, - dump_string_hex(msg->rtp_fragments[i].bytes, msg->rtp_fragments[i].size, 1460).c_str()); - SrsBuffer stream(msg->rtp_fragments[i].bytes + 2, 2); - static uint16_t seq = 0; - stream.write_2bytes(++seq); - - srs_trace("seq=%u", seq); + uint16_t seq = stream.read_2bytes(); + srs_trace("rtp fragment size=%d, seq=%u, payload=%s", msg->rtp_fragments[i].size, seq, + dump_string_hex(msg->rtp_fragments[i].bytes, msg->rtp_fragments[i].size, 1460).c_str()); if (rtc_session->dtls_session) { char rtp_send_protected_buf[1500]; @@ -670,6 +634,8 @@ srs_error_t SrsRtcSenderThread::cycle() ukt.sendto(rtp_send_protected_buf, rtp_send_protected_len, 0); } } + + srs_freep(msg); } srs_usleep(16000); @@ -778,27 +744,40 @@ srs_error_t SrsRtcSession::on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket) return srs_error_wrap(err, "recv unexpect rtp/rtcp packet before dtls done"); } + uint8_t payload_type = udp_remux_socket->data()[1] & 0x7F; + char srtp_unprotect_buf[1460]; int nb_srtp_unprotect_buf = udp_remux_socket->size(); if (dtls_session->srtp_receiver_unprotect(srtp_unprotect_buf, udp_remux_socket->data(), nb_srtp_unprotect_buf) != srs_success) { - return srs_error_wrap(err, "srtp receiver unprotect failed"); + return srs_error_wrap(err, "srtp receiver unprotect failed, payload_type=%u", payload_type); } //srs_trace("srtp unprotect success, %s", dump_string_hex(srtp_unprotect_buf, nb_srtp_unprotect_buf, nb_srtp_unprotect_buf).c_str()); SrsBuffer* stream = new SrsBuffer(srtp_unprotect_buf, nb_srtp_unprotect_buf); + SrsAutoFree(SrsBuffer, stream); uint8_t first = stream->read_1bytes(); uint8_t second = stream->read_1bytes(); - bool marker = (second & 0x80) == 0x80; - uint8_t payload_type = second &0x7F; + + bool padding = (first & 0x20); + bool ext = (first & 0x10); + uint8_t cc = (first & 0x0F); + + bool marker = (second & 0x80); uint16_t sequence = stream->read_2bytes(); uint32_t timestamp = stream->read_4bytes(); uint32_t ssrc = stream->read_4bytes(); - srs_trace("sequence=%u, timestamp=%u, ssrc=%u, marker=%d, payload_type=%u", sequence, timestamp, ssrc, marker, payload_type); + srs_trace("sequence=%u, timestamp=%u, ssrc=%u, padding=%d, ext=%d, cc=%u, marker=%d, payload_type=%u", + sequence, timestamp, ssrc, padding, ext, cc, marker, payload_type); - if (first & 0x10) { + for (uint8_t i = 0; i < cc; ++i) { + uint32_t csrc = 0; + csrc = stream->read_4bytes(); + } + + if (ext) { uint16_t extern_profile = stream->read_2bytes(); uint16_t extern_length = stream->read_2bytes(); @@ -807,6 +786,58 @@ srs_error_t SrsRtcSession::on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket) stream->read_string(extern_length * 4); } + if (payload_type == 102) { + static uint32_t pre_seq = 0; + uint32_t seq = sequence; + + srs_assert(pre_seq == 0 || (pre_seq + 1 == seq)); + + pre_seq = seq; + + static uint8_t start_code[4] = {0x00, 0x00, 0x00, 0x01}; + static int fd = -1; + if (fd < 0) { + fd = open("rtc.264", O_CREAT|O_TRUNC|O_RDWR, 0664); + } + + const uint8_t* p = (const uint8_t*)stream->data() + stream->pos(); + int len = stream->left(); + uint8_t header = p[0]; + uint8_t nal_type = header & kNalTypeMask; + + srs_trace("nal_type=%u, seq=%u, rtp payload, %s", nal_type, sequence, dump_string_hex(stream->data() + stream->pos(), stream->left(), stream->left()).c_str()); + + if (nal_type >=1 && nal_type <= 23) { + srs_trace("single nalu"); + write(fd, start_code, sizeof(start_code)); + write(fd, p, len); + } else if (nal_type == kFuA) { + srs_trace("FuA"); + if (p[1] & 0x80) { + uint8_t nal_type = ((p[0] & (~kNalTypeMask)) | (p[1] & kNalTypeMask)); + write(fd, start_code, sizeof(start_code)); + write(fd, &nal_type, 1); + write(fd, p + 2, len - 2); + } else { + write(fd, p + 2, len - 2); + } + } else if (nal_type == kStapA) { + srs_trace("StapA"); + int pos = 1; + while (pos < len) { + int nal_len = p[pos] << 8 | p[pos + 1]; + srs_trace("nal_len=%d", nal_len); + write(fd, start_code, sizeof(start_code)); + write(fd, p + pos + 2, nal_len); + pos += nal_len + 2; + } + srs_assert(pos == len); + } else { + srs_assert(false); + } + } + + // XXX:send h264 back to client, for debug if (payload_type == 102) { char rtp_send_protected_buf[1500]; int rtp_send_protected_len = nb_srtp_unprotect_buf; @@ -816,8 +847,6 @@ srs_error_t SrsRtcSession::on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket) udp_remux_socket->sendto(rtp_send_protected_buf, rtp_send_protected_len, 0); } - srs_trace("rtp payload, %s", dump_string_hex(stream->data() + stream->pos(), stream->left(), stream->left()).c_str()); - return err; } diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index 3a00d3d341..dafdbd0b88 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -50,42 +50,6 @@ using namespace std; #include #include -static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len); -static string dump_string_hex(const std::string& str, const int& max_len = 128) -{ - return dump_string_hex(str.c_str(), str.size(), max_len); -} - -static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = 128) -{ - string ret; - ret.reserve(max_len * 4); - - char tmp_buf[1024*16]; - tmp_buf[0] = '\n'; - int len = 1; - - for (int i = 0; i < nb_buf && i < max_len; ++i) { - //int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "(%03d)%02X ", i, (uint8_t)buf[i]); - int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "%02X ", (uint8_t)buf[i]); - if (nb <= 0) - break; - - len += nb; - - if (i % 48 == 47) { - tmp_buf[len++] = '\n'; - ret.append(tmp_buf, len); - len = 0; - } - } - tmp_buf[len] = '\0'; - ret.append(tmp_buf, len); - - return ret; -} - - SrsRtpMuxer::SrsRtpMuxer() { sequence = 0; @@ -95,182 +59,6 @@ SrsRtpMuxer::~SrsRtpMuxer() { } -#if 0 -srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsFormat* format) -{ - srs_error_t err = srs_success; - - int nb_samples = format->video->nb_samples; - SrsSample* samples = format->video->samples; - - SrsSample* rtp_fragment_samples = new SrsSample[2000]; - int rtp_fragment_samples_index = 0; - - static int debug_fd = -1; - static uint8_t start_code[4] = {0x00, 0x00, 0x00, 0x01}; - if (debug_fd < 0) { - debug_fd = open("./raw.264", O_CREAT|O_TRUNC|O_RDWR, 0664); - } - - SrsSample sps_pps_samples[2]; - if (format->is_avc_sequence_header()) { - sps_pps_samples[0].bytes = format->vcodec->sequenceParameterSetNALUnit.data(); - sps_pps_samples[0].size = format->vcodec->sequenceParameterSetNALUnit.size(); - sps_pps_samples[1].bytes = format->vcodec->pictureParameterSetNALUnit.data(); - sps_pps_samples[1].size = format->vcodec->pictureParameterSetNALUnit.size(); - - nb_samples = 2; - samples = sps_pps_samples; - - { - char* buf = new char[1460]; - SrsBuffer* stream = new SrsBuffer(buf, 1460); - SrsAutoFree(SrsBuffer, stream); - // write rtp header first - stream->write_1bytes(0x80); - stream->write_1bytes(102); - - stream->write_2bytes(sequence++); - stream->write_4bytes((int32_t)shared_frame->timestamp * 90); - stream->write_4bytes((int32_t)3233846889); - - stream->write_1bytes(24/*STAP-A*/); - // AUD - stream->write_2bytes(2); - stream->write_1bytes(0x09); - stream->write_1bytes(0x10); - - stream->write_2bytes(sps_pps_samples[0].size); - stream->write_bytes(sps_pps_samples[0].bytes, sps_pps_samples[0].size); - stream->write_2bytes(sps_pps_samples[1].size); - stream->write_bytes(sps_pps_samples[1].bytes, sps_pps_samples[1].size); - - if (debug_fd >= 0) { - write(debug_fd, start_code, sizeof(start_code)); - write(debug_fd, sps_pps_samples[0].bytes, sps_pps_samples[0].size); - write(debug_fd, start_code, sizeof(start_code)); - write(debug_fd, sps_pps_samples[1].bytes, sps_pps_samples[1].size); - } - - rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); - rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); - - ++rtp_fragment_samples_index; - } - shared_frame->set_rtp_fragments(rtp_fragment_samples, rtp_fragment_samples_index); - - return err; - } - - for (int i = 0; i < nb_samples; ++i) { - SrsSample sample = samples[i]; - - srs_trace("nal size=%d, dump=%s", sample.size, dump_string_hex(sample.bytes, sample.size, sample.size).c_str()); - - if ((sample.bytes[0] & 0x1F) == 0x06) { - srs_trace("ignore SEI"); - continue; - } - - if (debug_fd >= 0) { - write(debug_fd, start_code, sizeof(start_code)); - write(debug_fd, sample.bytes, sample.size); - } - - static int max_packet_size = 900; - if (sample.size <= max_packet_size) { - char* buf = new char[1460]; - SrsBuffer* stream = new SrsBuffer(buf, 1460); - SrsAutoFree(SrsBuffer, stream); - // write rtp header first - stream->write_1bytes(0x80); - if ((sample.bytes[0] & 0x1F) <= 5) { - stream->write_1bytes((1 << 7) | 102); - } else { - stream->write_1bytes(102); - } - - stream->write_2bytes(sequence++); - stream->write_4bytes((int32_t)shared_frame->timestamp * 90); - stream->write_4bytes((int32_t)3233846889); - -#if 0 // single nalu - stream->write_bytes(sample.bytes, sample.size); -#else - stream->write_1bytes((sample.bytes[0] & 0xE0) | 24/*STAP-A*/); - stream->write_2bytes(sample.size); - stream->write_bytes(sample.bytes, sample.size); -#endif - - rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); - rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); - - ++rtp_fragment_samples_index; - } else { - int num_of_packet = (sample.size + max_packet_size) / max_packet_size; - char* p = sample.bytes + 1; - int left_bytes = sample.size - 1; - for (int n = 0; n < num_of_packet; ++n) { - char* buf = new char[1460]; - SrsBuffer* stream = new SrsBuffer(buf, 1460); - SrsAutoFree(SrsBuffer, stream); - // write rtp header first - stream->write_1bytes(0x80); - if ((sample.bytes[0] & 0x1F) <= 5) { - stream->write_1bytes((1 << 7) | 102); - } else { - stream->write_1bytes(102); - } - - stream->write_2bytes(sequence++); - stream->write_4bytes((int32_t)shared_frame->timestamp * 90); - stream->write_4bytes((int32_t)3233846889); - - stream->write_1bytes((sample.bytes[0] & 0xE0) | 28); - if (n == 0) { - stream->write_1bytes(0x80 | (sample.bytes[0] & 0x1F)); - } else if (n == num_of_packet - 1) { - stream->write_1bytes(0x40 | (sample.bytes[0] & 0x1F)); - } else { - stream->write_1bytes(0x00 | (sample.bytes[0] & 0x1F)); - } - - int len = left_bytes > max_packet_size ? max_packet_size : left_bytes; - stream->write_bytes(p, len); - left_bytes -= len; - p += len; - - rtp_fragment_samples[rtp_fragment_samples_index].bytes = stream->data(); - rtp_fragment_samples[rtp_fragment_samples_index].size = stream->pos(); - - ++rtp_fragment_samples_index; - - } - } - } - shared_frame->set_rtp_fragments(rtp_fragment_samples, rtp_fragment_samples_index); - - return err; -} -#endif - -const int max_payload_size = 1200; -const int kRtpPacketSize = 1500; - -const uint8_t kMarker = 0x80; -const uint8_t kH264PayloadType = 102; - -const uint8_t kNalTypeMask = 0x1F; - -const uint8_t kIdr = 5; -const uint8_t kStapA = 24; -const uint8_t kFua = 28; - -const uint8_t kStart = 0x80; -const uint8_t kEnd = 0x40; - -const uint32_t kVideoSSRC = 3233846889; - srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsFormat* format) { srs_error_t err = srs_success; @@ -280,11 +68,13 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF pps.assign(format->vcodec->pictureParameterSetNALUnit.data(), format->vcodec->pictureParameterSetNALUnit.size()); } + vector rtp_packet_vec; + for (int i = 0; i < format->video->nb_samples; ++i) { SrsSample sample = format->video->samples[i]; uint8_t header = sample.bytes[0]; - uint8_t nal_type = header & 0x1F; + uint8_t nal_type = header & kNalTypeMask; if (nal_type == 0x06) { srs_trace("ignore SEI"); @@ -292,9 +82,9 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF } if (sample.size <= max_payload_size) { - packet_single_nalu(shared_frame, format, &sample); + packet_single_nalu(shared_frame, format, &sample, rtp_packet_vec); } else { - packet_fu_a(shared_frame, format, &sample); + packet_fu_a(shared_frame, format, &sample, rtp_packet_vec); } srs_trace("nal size=%d, nal=%s", sample.size, dump_string_hex(sample.bytes, sample.size, sample.size).c_str()); @@ -303,15 +93,20 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF } } + SrsSample* rtp_samples = new SrsSample[rtp_packet_vec.size()]; + for (int i = 0; i < rtp_packet_vec.size(); ++i) { + rtp_samples[i] = rtp_packet_vec[i]; + } + + shared_frame->set_rtp_fragments(rtp_samples, rtp_packet_vec.size()); + return err; } -srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample) +srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector& rtp_packet_vec) { srs_error_t err = srs_success; - vector rtp_packet_vec; - char* p = sample->bytes + 1; int nb_left = sample->size - 1; uint8_t header = sample->bytes[0]; @@ -325,7 +120,7 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma int avg_packet_size = sample->size / num_of_packet; for (int i = 0; i < num_of_packet; ++i) { char* buf = new char[kRtpPacketSize]; - SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsBuffer* stream = new SrsBuffer(buf, kRtpPacketSize); SrsAutoFree(SrsBuffer, stream); int packet_size = min(nb_left, max_payload_size); @@ -333,8 +128,13 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma // v=2,p=0,x=0,cc=0 stream->write_1bytes(0x80); // marker payloadtype - stream->write_1bytes(kMarker | kH264PayloadType); - // sequenct + if (i == num_of_packet - 1) { + stream->write_1bytes(kMarker | kH264PayloadType); + } else { + stream->write_1bytes(kH264PayloadType); + } + // sequence + srs_trace("sequence=%u", sequence); stream->write_2bytes(sequence++); // timestamp stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); @@ -342,11 +142,11 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma stream->write_4bytes(int32_t(kVideoSSRC)); // fu-indicate - uint8_t fu_indicate = kFua; - fu_indicate |= (nal_type & (~kNalTypeMask)); + uint8_t fu_indicate = kFuA; + fu_indicate |= (header & (~kNalTypeMask)); stream->write_1bytes(fu_indicate); - uint8_t fu_header = nal_type & kNalTypeMask; + uint8_t fu_header = nal_type; if (i == 0) fu_header |= kStart; if (i == num_of_packet - 1) @@ -355,7 +155,7 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma stream->write_bytes(p, packet_size); p += packet_size; - nb_left -= max_payload_size; + nb_left -= packet_size; SrsSample rtp_packet; @@ -364,26 +164,17 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma rtp_packet_vec.push_back(rtp_packet); } - - SrsSample* rtp_samples = new SrsSample[rtp_packet_vec.size()]; - for (int i = 0; i < rtp_packet_vec.size(); ++i) { - rtp_samples[i] = rtp_packet_vec[i]; - } - - shared_frame->set_rtp_fragments(rtp_samples, rtp_packet_vec.size()); } -srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample) +srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector& rtp_packet_vec) { srs_error_t err = srs_success; - vector rtp_packet_vec; - uint8_t header = sample->bytes[0]; uint8_t nal_type = header & kNalTypeMask; char* buf = new char[kRtpPacketSize]; - SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsBuffer* stream = new SrsBuffer(buf, kRtpPacketSize); SrsAutoFree(SrsBuffer, stream); if (nal_type == kIdr) { @@ -395,6 +186,7 @@ srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, S // marker payloadtype stream->write_1bytes(kMarker | kH264PayloadType); // sequenct + srs_trace("sequence=%u", sequence); stream->write_2bytes(sequence++); // timestamp stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); @@ -407,12 +199,7 @@ srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, S rtp_packet.bytes = stream->data(); rtp_packet.size = stream->pos(); - SrsSample* rtp_samples = new SrsSample[rtp_packet_vec.size()]; - for (int i = 0; i < rtp_packet_vec.size(); ++i) { - rtp_samples[i] = rtp_packet_vec[i]; - } - - shared_frame->set_rtp_fragments(rtp_samples, rtp_packet_vec.size()); + rtp_packet_vec.push_back(rtp_packet); return err; } @@ -425,7 +212,7 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs uint8_t nal_type = header & kNalTypeMask; char* buf = new char[kRtpPacketSize]; - SrsBuffer* stream = new SrsBuffer(buf, 1460); + SrsBuffer* stream = new SrsBuffer(buf, kRtpPacketSize); SrsAutoFree(SrsBuffer, stream); // v=2,p=0,x=0,cc=0 @@ -433,6 +220,7 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs // marker payloadtype stream->write_1bytes(kMarker | kH264PayloadType); // sequenct + srs_trace("sequence=%u", sequence); stream->write_2bytes(sequence++); // timestamp stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp index 1d0f510ddd..9000fd8308 100644 --- a/trunk/src/app/srs_app_rtp.hpp +++ b/trunk/src/app/srs_app_rtp.hpp @@ -36,6 +36,23 @@ class SrsSharedPtrMessage; class SrsRequest; class SrsOriginHub; +const int max_payload_size = 1200; +const int kRtpPacketSize = 1500; + +const uint8_t kMarker = 0x80; +const uint8_t kH264PayloadType = 102; + +const uint8_t kNalTypeMask = 0x1F; + +const uint8_t kIdr = 5; +const uint8_t kStapA = 24; +const uint8_t kFuA = 28; + +const uint8_t kStart = 0x80; +const uint8_t kEnd = 0x40; + +const uint32_t kVideoSSRC = 3233846889; + class SrsRtpMuxer { private: @@ -48,8 +65,8 @@ class SrsRtpMuxer public: srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); private: - srs_error_t packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample); - srs_error_t packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample); + srs_error_t packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, std::vector& rtp_packet_vec); + srs_error_t packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, std::vector& rtp_packet_vec); srs_error_t packet_stap_a(const std::string &sps, const std::string& pps, SrsSharedPtrMessage* shared_frame, std::vector& rtp_packet_vec); }; diff --git a/trunk/src/app/srs_app_utility.cpp b/trunk/src/app/srs_app_utility.cpp index 04ece71840..66ae112696 100644 --- a/trunk/src/app/srs_app_utility.cpp +++ b/trunk/src/app/srs_app_utility.cpp @@ -1193,3 +1193,37 @@ void srs_api_dump_summaries(SrsJsonObject* obj) sys->set("conn_srs", SrsJsonAny::integer(nrs->nb_conn_srs)); } +string dump_string_hex(const std::string& str, const int& max_len) +{ + return dump_string_hex(str.c_str(), str.size(), max_len); +} + +string dump_string_hex(const char* buf, const int nb_buf, const int& max_len) +{ + string ret; + ret.reserve(max_len * 4); + + char tmp_buf[1024*16]; + tmp_buf[0] = '\n'; + int len = 1; + + for (int i = 0; i < nb_buf && i < max_len; ++i) { + //int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "(%03d)%02X ", i, (uint8_t)buf[i]); + int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "%02X ", (uint8_t)buf[i]); + if (nb <= 0) + break; + + len += nb; + + if (i % 48 == 47) { + tmp_buf[len++] = '\n'; + ret.append(tmp_buf, len); + len = 0; + } + } + tmp_buf[len] = '\0'; + ret.append(tmp_buf, len); + + return ret; + +} diff --git a/trunk/src/app/srs_app_utility.hpp b/trunk/src/app/srs_app_utility.hpp index be7cbced6f..77d28f802d 100644 --- a/trunk/src/app/srs_app_utility.hpp +++ b/trunk/src/app/srs_app_utility.hpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -649,5 +650,8 @@ extern bool srs_is_boolean(std::string str); // Dump summaries for /api/v1/summaries. extern void srs_api_dump_summaries(SrsJsonObject* obj); +extern std::string dump_string_hex(const std::string& str, const int& max_len = INT_MAX); +extern std::string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = INT_MAX); + #endif diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index aa0d3a7ec0..f2f7730491 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -216,10 +216,10 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload() srs_freepa(payload); for (int i = 0; i < nb_rtp_fragments; ++i) { - srs_freep(rtp_fragments[i].bytes); + srs_freepa(rtp_fragments[i].bytes); } - if (nb_rtp_fragments) { + if (rtp_fragments != NULL && nb_rtp_fragments > 0) { srs_freepa(rtp_fragments); } } From 6decdc7838e9f9a941e93611c206c55759fd3277 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Fri, 13 Mar 2020 00:24:56 +0800 Subject: [PATCH 19/69] adjust code style, fix some bug, add rtc session timeout --- trunk/src/app/srs_app_dtls.cpp | 6 + trunk/src/app/srs_app_listener.cpp | 97 +++++- trunk/src/app/srs_app_listener.hpp | 30 +- trunk/src/app/srs_app_rtc_conn.cpp | 484 +++++++++++++++++---------- trunk/src/app/srs_app_rtc_conn.hpp | 111 ++++-- trunk/src/app/srs_app_rtp.cpp | 5 +- trunk/src/app/srs_app_server.cpp | 6 +- trunk/src/app/srs_app_server.hpp | 4 +- trunk/src/service/srs_service_st.cpp | 5 + trunk/src/service/srs_service_st.hpp | 1 + 10 files changed, 503 insertions(+), 246 deletions(-) diff --git a/trunk/src/app/srs_app_dtls.cpp b/trunk/src/app/srs_app_dtls.cpp index af09dcb2f7..4a863fd924 100644 --- a/trunk/src/app/srs_app_dtls.cpp +++ b/trunk/src/app/srs_app_dtls.cpp @@ -29,6 +29,8 @@ using namespace std; #include +#include + SrsDtls* SrsDtls::_instance = NULL; SrsDtls::SrsDtls() @@ -50,6 +52,10 @@ SrsDtls* SrsDtls::instance() void SrsDtls::init() { + // srtp init first + srs_assert(srtp_init() == 0); + + // init dtls context EVP_PKEY* dtls_private_key = EVP_PKEY_new(); srs_assert(dtls_private_key); diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index c8ecec2c67..0ba7684cd5 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -60,15 +60,15 @@ srs_error_t ISrsUdpHandler::on_stfd_change(srs_netfd_t /*fd*/) return srs_success; } -ISrsUdpRemuxHandler::ISrsUdpRemuxHandler() +ISrsUdpMuxHandler::ISrsUdpMuxHandler() { } -ISrsUdpRemuxHandler::~ISrsUdpRemuxHandler() +ISrsUdpMuxHandler::~ISrsUdpMuxHandler() { } -srs_error_t ISrsUdpRemuxHandler::on_stfd_change(srs_netfd_t /*fd*/) +srs_error_t ISrsUdpMuxHandler::on_stfd_change(srs_netfd_t /*fd*/) { return srs_success; } @@ -221,7 +221,7 @@ srs_error_t SrsTcpListener::cycle() return err; } -SrsUdpRemuxSocket::SrsUdpRemuxSocket(srs_netfd_t fd) +SrsUdpMuxSocket::SrsUdpMuxSocket(srs_netfd_t fd) { nb_buf = SRS_UDP_MAX_PACKET_SIZE; buf = new char[nb_buf]; @@ -232,12 +232,31 @@ SrsUdpRemuxSocket::SrsUdpRemuxSocket(srs_netfd_t fd) fromlen = 0; } -SrsUdpRemuxSocket::~SrsUdpRemuxSocket() +SrsUdpMuxSocket::~SrsUdpMuxSocket() { srs_freepa(buf); } -int SrsUdpRemuxSocket::recvfrom(srs_utime_t timeout) +SrsUdpMuxSocket::SrsUdpMuxSocket(const SrsUdpMuxSocket& rhs) +{ + operator=(rhs); +} + +SrsUdpMuxSocket& SrsUdpMuxSocket::operator=(const SrsUdpMuxSocket& rhs) +{ + buf = NULL; + nb_buf = 0; + nread = 0; + lfd = rhs.lfd; + from = rhs.from; + fromlen = rhs.fromlen; + peer_ip = rhs.peer_ip; + peer_port = rhs.peer_port; + + return *this; +} + +int SrsUdpMuxSocket::recvfrom(srs_utime_t timeout) { fromlen = sizeof(from); nread = srs_recvfrom(lfd, buf, nb_buf, (sockaddr*)&from, &fromlen, timeout); @@ -259,12 +278,23 @@ int SrsUdpRemuxSocket::recvfrom(srs_utime_t timeout) return nread; } -int SrsUdpRemuxSocket::sendto(void* data, int size, srs_utime_t timeout) +int SrsUdpMuxSocket::sendto(void* data, int size, srs_utime_t timeout) { return srs_sendto(lfd, data, size, (sockaddr*)&from, fromlen, timeout); } -std::string SrsUdpRemuxSocket::get_peer_id() +int SrsUdpMuxSocket::sendtov(struct iovec* iov, size_t iovlen, srs_utime_t timeout) +{ + struct msghdr udphdr = {0}; + udphdr.msg_name = &from; + udphdr.msg_namelen = fromlen; + udphdr.msg_iov = iov; + udphdr.msg_iovlen = iovlen; + + return srs_sendmsg(lfd, &udphdr, 0, timeout); +} + +std::string SrsUdpMuxSocket::get_peer_id() { char id_buf[1024]; int len = snprintf(id_buf, sizeof(id_buf), "%s:%d", peer_ip.c_str(), peer_port); @@ -272,7 +302,7 @@ std::string SrsUdpRemuxSocket::get_peer_id() return string(id_buf, len); } -SrsUdpRemuxListener::SrsUdpRemuxListener(ISrsUdpRemuxHandler* h, std::string i, int p) +SrsUdpMuxListener::SrsUdpMuxListener(ISrsUdpMuxHandler* h, std::string i, int p) { handler = h; ip = i; @@ -285,30 +315,32 @@ SrsUdpRemuxListener::SrsUdpRemuxListener(ISrsUdpRemuxHandler* h, std::string i, trd = new SrsDummyCoroutine(); } -SrsUdpRemuxListener::~SrsUdpRemuxListener() +SrsUdpMuxListener::~SrsUdpMuxListener() { srs_freep(trd); srs_close_stfd(lfd); srs_freepa(buf); } -int SrsUdpRemuxListener::fd() +int SrsUdpMuxListener::fd() { return srs_netfd_fileno(lfd); } -srs_netfd_t SrsUdpRemuxListener::stfd() +srs_netfd_t SrsUdpMuxListener::stfd() { return lfd; } -srs_error_t SrsUdpRemuxListener::listen() +srs_error_t SrsUdpMuxListener::listen() { srs_error_t err = srs_success; if ((err = srs_udp_listen(ip, port, &lfd)) != srs_success) { return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); } + + set_socket_buffer(); srs_freep(trd); trd = new SrsSTCoroutine("udp", this); @@ -319,7 +351,38 @@ srs_error_t SrsUdpRemuxListener::listen() return err; } -srs_error_t SrsUdpRemuxListener::cycle() +void SrsUdpMuxListener::set_socket_buffer() +{ + int sndbuf_size = 0; + socklen_t opt_len = sizeof(sndbuf_size); + getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, &opt_len); + srs_trace("default udp remux socket sndbuf=%d", sndbuf_size); + + sndbuf_size = 1024*1024*10; // 10M + if (setsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, sizeof(sndbuf_size)) < 0) { + srs_warn("set sock opt SO_SNDBUFFORCE failed"); + } + + opt_len = sizeof(sndbuf_size); + getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&sndbuf_size, &opt_len); + srs_trace("udp remux socket sndbuf=%d", sndbuf_size); + + int rcvbuf_size = 0; + opt_len = sizeof(rcvbuf_size); + getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, &opt_len); + srs_trace("default udp remux socket rcvbuf=%d", rcvbuf_size); + + rcvbuf_size = 1024*1024*10; // 10M + if (setsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, sizeof(rcvbuf_size)) < 0) { + srs_warn("set sock opt SO_RCVBUFFORCE failed"); + } + + opt_len = sizeof(rcvbuf_size); + getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&rcvbuf_size, &opt_len); + srs_trace("udp remux socket rcvbuf=%d", rcvbuf_size); +} + +srs_error_t SrsUdpMuxListener::cycle() { srs_error_t err = srs_success; @@ -328,15 +391,15 @@ srs_error_t SrsUdpRemuxListener::cycle() return srs_error_wrap(err, "udp listener"); } - SrsUdpRemuxSocket udp_remux_socket(lfd); + SrsUdpMuxSocket udp_mux_skt(lfd); - if (udp_remux_socket.recvfrom(SRS_UTIME_NO_TIMEOUT) <= 0) { + if (udp_mux_skt.recvfrom(SRS_UTIME_NO_TIMEOUT) <= 0) { srs_error("udp recv error"); // remux udp never return continue; } - if ((err = handler->on_udp_packet(&udp_remux_socket)) != srs_success) { + if ((err = handler->on_udp_packet(&udp_mux_skt)) != srs_success) { // remux udp never return srs_error("udp packet handler error:%s", srs_error_desc(err).c_str()); continue; diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index fc25551e87..605929902f 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -35,7 +35,7 @@ struct sockaddr; -class SrsUdpRemuxSocket; +class SrsUdpMuxSocket; // The udp packet handler. class ISrsUdpHandler @@ -58,14 +58,14 @@ class ISrsUdpHandler virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) = 0; }; -class ISrsUdpRemuxHandler +class ISrsUdpMuxHandler { public: - ISrsUdpRemuxHandler(); - virtual ~ISrsUdpRemuxHandler(); + ISrsUdpMuxHandler(); + virtual ~ISrsUdpMuxHandler(); public: virtual srs_error_t on_stfd_change(srs_netfd_t fd); - virtual srs_error_t on_udp_packet(SrsUdpRemuxSocket* udp_remux_socket) = 0; + virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* udp_mux_skt) = 0; }; // The tcp connection handler. @@ -127,7 +127,7 @@ class SrsTcpListener : public ISrsCoroutineHandler virtual srs_error_t cycle(); }; -class SrsUdpRemuxSocket +class SrsUdpMuxSocket { private: char* buf; @@ -139,11 +139,15 @@ class SrsUdpRemuxSocket std::string peer_ip; int peer_port; public: - SrsUdpRemuxSocket(srs_netfd_t fd); - virtual ~SrsUdpRemuxSocket(); + SrsUdpMuxSocket(srs_netfd_t fd); + virtual ~SrsUdpMuxSocket(); + + SrsUdpMuxSocket(const SrsUdpMuxSocket& rhs); + SrsUdpMuxSocket& operator=(const SrsUdpMuxSocket& rhs); int recvfrom(srs_utime_t timeout); int sendto(void* data, int size, srs_utime_t timeout); + int sendtov(struct iovec* iov, size_t iovlen, srs_utime_t timeout); char* data() { return buf; } int size() { return nread; } @@ -152,7 +156,7 @@ class SrsUdpRemuxSocket std::string get_peer_id(); }; -class SrsUdpRemuxListener : public ISrsCoroutineHandler +class SrsUdpMuxListener : public ISrsCoroutineHandler { protected: srs_netfd_t lfd; @@ -161,12 +165,12 @@ class SrsUdpRemuxListener : public ISrsCoroutineHandler char* buf; int nb_buf; protected: - ISrsUdpRemuxHandler* handler; + ISrsUdpMuxHandler* handler; std::string ip; int port; public: - SrsUdpRemuxListener(ISrsUdpRemuxHandler* h, std::string i, int p); - virtual ~SrsUdpRemuxListener(); + SrsUdpMuxListener(ISrsUdpMuxHandler* h, std::string i, int p); + virtual ~SrsUdpMuxListener(); public: virtual int fd(); virtual srs_netfd_t stfd(); @@ -175,6 +179,8 @@ class SrsUdpRemuxListener : public ISrsCoroutineHandler // Interface ISrsReusableThreadHandler. public: virtual srs_error_t cycle(); +private: + void set_socket_buffer(); }; #endif diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index a92a2b5f87..07d0fc900f 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -65,6 +65,11 @@ static bool is_rtp_or_rtcp(const char* data, size_t len) return (len >= 12 && (data[0] & 0xC0) == 0x80); } +static bool is_rtcp(const char* data, size_t len) +{ + return (len >=12) && (data[0] & 0x80) && (data[1] >= 200 && data[1] <= 209); +} + static string gen_random_str(int len) { static string random_table = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -294,9 +299,22 @@ SrsDtlsSession::SrsDtlsSession(SrsRtcSession* s) SrsDtlsSession::~SrsDtlsSession() { + if (dtls) { + // this function will free bio_in and bio_out + SSL_free(dtls); + dtls = NULL; + } + + if (srtp_send) { + srtp_dealloc(srtp_send); + } + + if (srtp_recv) { + srtp_dealloc(srtp_recv); + } } -srs_error_t SrsDtlsSession::handshake(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsDtlsSession::handshake(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; @@ -308,7 +326,7 @@ srs_error_t SrsDtlsSession::handshake(SrsUdpRemuxSocket* udp_remux_socket) int ssl_err = SSL_get_error(dtls, ret); switch(ssl_err) { case SSL_ERROR_NONE: { - err = on_dtls_handshake_done(udp_remux_socket); + err = on_dtls_handshake_done(udp_mux_skt); } break; @@ -327,25 +345,25 @@ srs_error_t SrsDtlsSession::handshake(SrsUdpRemuxSocket* udp_remux_socket) if (out_bio_len) { srs_trace("send dtls handshake data"); - udp_remux_socket->sendto(out_bio_data, out_bio_len, 0); + udp_mux_skt->sendto(out_bio_data, out_bio_len, 0); } return err; } -srs_error_t SrsDtlsSession::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsDtlsSession::on_dtls(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; if (! handshake_done) { BIO_reset(bio_in); BIO_reset(bio_out); - BIO_write(bio_in, udp_remux_socket->data(), udp_remux_socket->size()); + BIO_write(bio_in, udp_mux_skt->data(), udp_mux_skt->size()); - handshake(udp_remux_socket); + handshake(udp_mux_skt); } else { BIO_reset(bio_in); BIO_reset(bio_out); - BIO_write(bio_in, udp_remux_socket->data(), udp_remux_socket->size()); + BIO_write(bio_in, udp_mux_skt->data(), udp_mux_skt->size()); while (BIO_ctrl_pending(bio_in) > 0) { char dtls_read_buf[8092]; @@ -360,7 +378,7 @@ srs_error_t SrsDtlsSession::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) return err; } -srs_error_t SrsDtlsSession::on_dtls_handshake_done(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsDtlsSession::on_dtls_handshake_done(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; srs_trace("dtls handshake done"); @@ -371,7 +389,7 @@ srs_error_t SrsDtlsSession::on_dtls_handshake_done(SrsUdpRemuxSocket* udp_remux_ return srs_error_wrap(err, "srtp init failed"); } - rtc_session->on_connection_established(udp_remux_socket); + rtc_session->on_connection_established(udp_mux_skt); return err; } @@ -383,7 +401,7 @@ srs_error_t SrsDtlsSession::on_dtls_application_data(const char* buf, const int return err; } -void SrsDtlsSession::send_client_hello(SrsUdpRemuxSocket* udp_remux_socket) +void SrsDtlsSession::send_client_hello(SrsUdpMuxSocket* udp_mux_skt) { if (dtls == NULL) { srs_trace("send client hello"); @@ -396,7 +414,7 @@ void SrsDtlsSession::send_client_hello(SrsUdpRemuxSocket* udp_remux_socket) SSL_set_bio(dtls, bio_in, bio_out); - handshake(udp_remux_socket); + handshake(udp_mux_skt); } } @@ -405,42 +423,36 @@ srs_error_t SrsDtlsSession::srtp_initialize() srs_error_t err = srs_success; unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server - static string dtls_srtp_lable = "EXTRACTOR-dtls_srtp"; + static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp"; if (! SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) { return srs_error_wrap(err, "SSL_export_keying_material failed"); } size_t offset = 0; - std::string sClientMasterKey(reinterpret_cast(material), SRTP_MASTER_KEY_KEY_LEN); + std::string client_master_key(reinterpret_cast(material), SRTP_MASTER_KEY_KEY_LEN); offset += SRTP_MASTER_KEY_KEY_LEN; - std::string sServerMasterKey(reinterpret_cast(material + offset), SRTP_MASTER_KEY_KEY_LEN); + std::string server_master_key(reinterpret_cast(material + offset), SRTP_MASTER_KEY_KEY_LEN); offset += SRTP_MASTER_KEY_KEY_LEN; - std::string sClientMasterSalt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); + std::string client_master_salt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); offset += SRTP_MASTER_KEY_SALT_LEN; - std::string sServerMasterSalt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); + std::string server_master_salt(reinterpret_cast(material + offset), SRTP_MASTER_KEY_SALT_LEN); - client_key = sClientMasterKey + sClientMasterSalt; - server_key = sServerMasterKey + sServerMasterSalt; + client_key = client_master_key + client_master_salt; + server_key = server_master_key + server_master_salt; - srs_trace("client_key size=%d, server_key=%d", client_key.size(), server_key.size()); - - if (srtp_init() != 0) { - return srs_error_wrap(err, "srtp init failed"); - } - - if (srtp_sender_side_init() != srs_success) { - return srs_error_wrap(err, "srtp sender size init failed"); + if (srtp_send_init() != srs_success) { + return srs_error_wrap(err, "srtp send init failed"); } - if (srtp_receiver_side_init() != srs_success) { - return srs_error_wrap(err, "srtp receiver size init failed"); + if (srtp_recv_init() != srs_success) { + return srs_error_wrap(err, "srtp recv init failed"); } return err; } -srs_error_t SrsDtlsSession::srtp_sender_side_init() +srs_error_t SrsDtlsSession::srtp_send_init() { srs_error_t err = srs_success; @@ -463,16 +475,16 @@ srs_error_t SrsDtlsSession::srtp_sender_side_init() policy.key = key; if (srtp_create(&srtp_send, &policy) != 0) { - delete [] key; + srs_freepa(key); return srs_error_wrap(err, "srtp_create failed"); } - delete [] key; + srs_freepa(key); return err; } -srs_error_t SrsDtlsSession::srtp_receiver_side_init() +srs_error_t SrsDtlsSession::srtp_recv_init() { srs_error_t err = srs_success; @@ -495,50 +507,80 @@ srs_error_t SrsDtlsSession::srtp_receiver_side_init() policy.key = key; if (srtp_create(&srtp_recv, &policy) != 0) { - delete [] key; + srs_freepa(key); return srs_error_wrap(err, "srtp_create failed"); } - delete [] key; + srs_freepa(key); return err; } -srs_error_t SrsDtlsSession::srtp_sender_protect(char* protected_buf, const char* ori_buf, int& nb_protected_buf) +srs_error_t SrsDtlsSession::protect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) { srs_error_t err = srs_success; if (srtp_send) { - memcpy(protected_buf, ori_buf, nb_protected_buf); - if (srtp_protect(srtp_send, protected_buf, &nb_protected_buf) != 0) { - srs_error("srtp sender protect failed"); - return srs_error_wrap(err, "srtp sender protect failed"); + memcpy(out_buf, in_buf, nb_out_buf); + if (srtp_protect(srtp_send, out_buf, &nb_out_buf) != 0) { + return srs_error_wrap(err, "rtp protect failed"); } return err; } - return srs_error_wrap(err, "srtp sender protect failed"); + return srs_error_wrap(err, "rtp protect failed"); } -srs_error_t SrsDtlsSession::srtp_receiver_unprotect(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf) +srs_error_t SrsDtlsSession::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) +{ + srs_error_t err = srs_success; + + if (srtp_recv) { + memcpy(out_buf, in_buf, nb_out_buf); + if (srtp_unprotect(srtp_recv, out_buf, &nb_out_buf) != 0) { + return srs_error_wrap(err, "rtp unprotect failed"); + } + + return err; + } + + return srs_error_wrap(err, "rtp unprotect failed"); +} + +srs_error_t SrsDtlsSession::protect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) { srs_error_t err = srs_success; if (srtp_send) { - memcpy(unprotected_buf, ori_buf, nb_unprotected_buf); - if (srtp_unprotect(srtp_recv, unprotected_buf, &nb_unprotected_buf) != 0) { - srs_error("srtp receiver unprotect failed"); - return srs_error_wrap(err, "srtp receiver unprotect failed"); + memcpy(out_buf, in_buf, nb_out_buf); + if (srtp_protect_rtcp(srtp_send, out_buf, &nb_out_buf) != 0) { + return srs_error_wrap(err, "rtcp protect failed"); + } + + return err; + } + + return srs_error_wrap(err, "rtcp protect failed"); +} + +srs_error_t SrsDtlsSession::unprotect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) +{ + srs_error_t err = srs_success; + + if (srtp_recv) { + memcpy(out_buf, in_buf, nb_out_buf); + if (srtp_unprotect_rtcp(srtp_recv, out_buf, &nb_out_buf) != 0) { + return srs_error_wrap(err, "rtcp unprotect failed"); } return err; } - return srs_error_wrap(err, "srtp receiver unprotect failed"); + return srs_error_wrap(err, "rtcp unprotect failed"); } -SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpRemuxSocket* u, int parent_cid) +SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid) : ukt(NULL) { _parent_cid = parent_cid; @@ -563,10 +605,10 @@ srs_error_t SrsRtcSenderThread::start() srs_error_t err = srs_success; srs_freep(trd); - trd = new SrsSTCoroutine("recv", this, _parent_cid); + trd = new SrsSTCoroutine("rtc_sender", this, _parent_cid); if ((err = trd->start()) != srs_success) { - return srs_error_wrap(err, "recv thread"); + return srs_error_wrap(err, "rtc_sender"); } return err; @@ -608,69 +650,91 @@ srs_error_t SrsRtcSenderThread::cycle() SrsAutoFree(SrsConsumer, consumer); while (true) { + if ((err = trd->pull()) != srs_success) { + return srs_error_wrap(err, "rtc sender thread"); + } + SrsMessageArray msgs(SRS_PERF_MW_MSGS); +#ifdef SRS_PERF_QUEUE_COND_WAIT + consumer->wait(0, SRS_PERF_MW_SLEEP); +#endif + int msg_count = 0; if (consumer->dump_packets(&msgs, msg_count) != srs_success) { - srs_trace("rtc pop no rtp packets"); continue; } - srs_trace("rtc pop %d rtp packets", msg_count); + if (msg_count <= 0) { +#ifndef SRS_PERF_QUEUE_COND_WAIT + srs_usleep(mw_sleep); +#endif + // ignore when nothing got. + continue; + } - for (int i = 0; i < msg_count; i++) { - SrsSharedPtrMessage* msg = msgs.msgs[i]; + send_and_free_messages(msgs.msgs, msg_count, &ukt); + } +} - for (int i = 0; i < msg->nb_rtp_fragments; ++i) { - SrsBuffer stream(msg->rtp_fragments[i].bytes + 2, 2); - uint16_t seq = stream.read_2bytes(); - srs_trace("rtp fragment size=%d, seq=%u, payload=%s", msg->rtp_fragments[i].size, seq, - dump_string_hex(msg->rtp_fragments[i].bytes, msg->rtp_fragments[i].size, 1460).c_str()); +void SrsRtcSenderThread::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* udp_mux_skt) +{ + for (int i = 0; i < nb_msgs; i++) { + SrsSharedPtrMessage* msg = msgs[i]; - if (rtc_session->dtls_session) { - char rtp_send_protected_buf[1500]; - int rtp_send_protected_len = msg->rtp_fragments[i].size; - rtc_session->dtls_session->srtp_sender_protect(rtp_send_protected_buf, msg->rtp_fragments[i].bytes, rtp_send_protected_len); - ukt.sendto(rtp_send_protected_buf, rtp_send_protected_len, 0); - } - } + for (int i = 0; i < msg->nb_rtp_fragments; ++i) { + if (rtc_session->dtls_session) { + char protected_buf[kRtpPacketSize]; + int nb_protected_buf = msg->rtp_fragments[i].size; - srs_freep(msg); + rtc_session->dtls_session->protect_rtp(protected_buf, msg->rtp_fragments[i].bytes, nb_protected_buf); + udp_mux_skt->sendto(protected_buf, nb_protected_buf, 0); + } } - srs_usleep(16000); + srs_freep(msg); } } - -SrsRtcSession::SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr) +SrsRtcSession::SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const string& un) { server = svr; rtc_server = rtc_svr; session_state = INIT; dtls_session = NULL; - strd = NULL; + + username = un; + + last_stun_time = srs_get_system_time(); } SrsRtcSession::~SrsRtcSession() { + srs_freep(dtls_session); + + if (strd) { + strd->stop(); + } + srs_freep(strd); } -srs_error_t SrsRtcSession::on_stun(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req) +srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req) { srs_error_t err = srs_success; if (stun_req->is_binding_request()) { - if (on_binding_request(udp_remux_socket, stun_req) != srs_success) { + if (on_binding_request(udp_mux_skt, stun_req) != srs_success) { return srs_error_wrap(err, "stun binding request failed"); } } + last_stun_time = srs_get_system_time(); + return err; } -srs_error_t SrsRtcSession::on_binding_request(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req) +srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req) { srs_error_t err = srs_success; @@ -684,77 +748,74 @@ srs_error_t SrsRtcSession::on_binding_request(SrsUdpRemuxSocket* udp_remux_socke stun_binding_response.set_remote_ufrag(stun_req->get_local_ufrag()); stun_binding_response.set_transcation_id(stun_req->get_transcation_id()); // FIXME: inet_addr is deprecated, IPV6 support - stun_binding_response.set_mapped_address(be32toh(inet_addr(udp_remux_socket->get_peer_ip().c_str()))); - stun_binding_response.set_mapped_port(udp_remux_socket->get_peer_port()); + stun_binding_response.set_mapped_address(be32toh(inet_addr(udp_mux_skt->get_peer_ip().c_str()))); + stun_binding_response.set_mapped_port(udp_mux_skt->get_peer_port()); if (stun_binding_response.encode(get_local_sdp()->get_ice_pwd(), stream) != srs_success) { return srs_error_wrap(err, "stun binding response encode failed"); } - if (udp_remux_socket->sendto(stream->data(), stream->pos(), 0) <= 0) { + if (udp_mux_skt->sendto(stream->data(), stream->pos(), 0) <= 0) { return srs_error_wrap(err, "stun binding response send failed"); } if (get_session_state() == WAITING_STUN) { set_session_state(DOING_DTLS_HANDSHAKE); - send_client_hello(udp_remux_socket); + send_client_hello(udp_mux_skt); - string peer_id = udp_remux_socket->get_peer_id(); + peer_id = udp_mux_skt->get_peer_id(); rtc_server->insert_into_id_sessions(peer_id, this); } - // TODO: dtls send client retry - return err; } -srs_error_t SrsRtcSession::send_client_hello(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsRtcSession::send_client_hello(SrsUdpMuxSocket* udp_mux_skt) { if (dtls_session == NULL) { dtls_session = new SrsDtlsSession(this); } - dtls_session->send_client_hello(udp_remux_socket); + dtls_session->send_client_hello(udp_mux_skt); } -void SrsRtcSession::on_connection_established(SrsUdpRemuxSocket* udp_remux_socket) +void SrsRtcSession::on_connection_established(SrsUdpMuxSocket* udp_mux_skt) { - start_play(udp_remux_socket); + srs_trace("rtc session=%s, connection established", id().c_str()); + start_play(udp_mux_skt); } -srs_error_t SrsRtcSession::start_play(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsRtcSession::start_play(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; - strd = new SrsRtcSenderThread(this, udp_remux_socket, _srs_context->get_id()); + srs_freep(strd); + strd = new SrsRtcSenderThread(this, udp_mux_skt, _srs_context->get_id()); strd->start(); return err; } -srs_error_t SrsRtcSession::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsRtcSession::on_dtls(SrsUdpMuxSocket* udp_mux_skt) { - return dtls_session->on_dtls(udp_remux_socket); + return dtls_session->on_dtls(udp_mux_skt); } -srs_error_t SrsRtcSession::on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsRtcSession::on_rtp(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; if (dtls_session == NULL) { - return srs_error_wrap(err, "recv unexpect rtp/rtcp packet before dtls done"); + return srs_error_wrap(err, "recv unexpect rtp packet before dtls done"); } - uint8_t payload_type = udp_remux_socket->data()[1] & 0x7F; - - char srtp_unprotect_buf[1460]; - int nb_srtp_unprotect_buf = udp_remux_socket->size(); - if (dtls_session->srtp_receiver_unprotect(srtp_unprotect_buf, udp_remux_socket->data(), nb_srtp_unprotect_buf) != srs_success) { - return srs_error_wrap(err, "srtp receiver unprotect failed, payload_type=%u", payload_type); + char unprotected_buf[1460]; + int nb_unprotected_buf = udp_mux_skt->size(); + if (dtls_session->unprotect_rtp(unprotected_buf, udp_mux_skt->data(), nb_unprotected_buf) != srs_success) { + return srs_error_wrap(err, "rtp unprotect failed"); } - //srs_trace("srtp unprotect success, %s", dump_string_hex(srtp_unprotect_buf, nb_srtp_unprotect_buf, nb_srtp_unprotect_buf).c_str()); - - SrsBuffer* stream = new SrsBuffer(srtp_unprotect_buf, nb_srtp_unprotect_buf); + // FIXME: use SrsRtpPacket + SrsBuffer* stream = new SrsBuffer(unprotected_buf, nb_unprotected_buf); SrsAutoFree(SrsBuffer, stream); uint8_t first = stream->read_1bytes(); uint8_t second = stream->read_1bytes(); @@ -769,7 +830,7 @@ srs_error_t SrsRtcSession::on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket) uint32_t timestamp = stream->read_4bytes(); uint32_t ssrc = stream->read_4bytes(); - srs_trace("sequence=%u, timestamp=%u, ssrc=%u, padding=%d, ext=%d, cc=%u, marker=%d, payload_type=%u", + srs_verbose("sequence=%u, timestamp=%u, ssrc=%u, padding=%d, ext=%d, cc=%u, marker=%d, payload_type=%u", sequence, timestamp, ssrc, padding, ext, cc, marker, payload_type); for (uint8_t i = 0; i < cc; ++i) { @@ -781,70 +842,40 @@ srs_error_t SrsRtcSession::on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket) uint16_t extern_profile = stream->read_2bytes(); uint16_t extern_length = stream->read_2bytes(); - srs_trace("extern_profile=%u, extern_length=%u", extern_profile, extern_length); + srs_verbose("extern_profile=%u, extern_length=%u", extern_profile, extern_length); stream->read_string(extern_length * 4); } - if (payload_type == 102) { - static uint32_t pre_seq = 0; - uint32_t seq = sequence; - - srs_assert(pre_seq == 0 || (pre_seq + 1 == seq)); - - pre_seq = seq; + return err; +} - static uint8_t start_code[4] = {0x00, 0x00, 0x00, 0x01}; - static int fd = -1; - if (fd < 0) { - fd = open("rtc.264", O_CREAT|O_TRUNC|O_RDWR, 0664); - } +srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) +{ + srs_error_t err = srs_success; + if (dtls_session == NULL) { + return srs_error_wrap(err, "recv unexpect rtcp packet before dtls done"); + } - const uint8_t* p = (const uint8_t*)stream->data() + stream->pos(); - int len = stream->left(); - uint8_t header = p[0]; - uint8_t nal_type = header & kNalTypeMask; - - srs_trace("nal_type=%u, seq=%u, rtp payload, %s", nal_type, sequence, dump_string_hex(stream->data() + stream->pos(), stream->left(), stream->left()).c_str()); - - if (nal_type >=1 && nal_type <= 23) { - srs_trace("single nalu"); - write(fd, start_code, sizeof(start_code)); - write(fd, p, len); - } else if (nal_type == kFuA) { - srs_trace("FuA"); - if (p[1] & 0x80) { - uint8_t nal_type = ((p[0] & (~kNalTypeMask)) | (p[1] & kNalTypeMask)); - write(fd, start_code, sizeof(start_code)); - write(fd, &nal_type, 1); - write(fd, p + 2, len - 2); - } else { - write(fd, p + 2, len - 2); - } - } else if (nal_type == kStapA) { - srs_trace("StapA"); - int pos = 1; - while (pos < len) { - int nal_len = p[pos] << 8 | p[pos + 1]; - srs_trace("nal_len=%d", nal_len); - write(fd, start_code, sizeof(start_code)); - write(fd, p + pos + 2, nal_len); - pos += nal_len + 2; - } - srs_assert(pos == len); - } else { - srs_assert(false); - } + char unprotected_buf[1460]; + int nb_unprotected_buf = udp_mux_skt->size(); + if (dtls_session->unprotect_rtcp(unprotected_buf, udp_mux_skt->data(), nb_unprotected_buf) != srs_success) { + return srs_error_wrap(err, "rtcp unprotect failed"); } - // XXX:send h264 back to client, for debug - if (payload_type == 102) { - char rtp_send_protected_buf[1500]; - int rtp_send_protected_len = nb_srtp_unprotect_buf; - SrsBuffer stream(srtp_unprotect_buf + 8, 4); - stream.write_4bytes(3233846889); - dtls_session->srtp_sender_protect(rtp_send_protected_buf, srtp_unprotect_buf, rtp_send_protected_len); - udp_remux_socket->sendto(rtp_send_protected_buf, rtp_send_protected_len, 0); + // FIXME: use SrsRtpPacket + SrsBuffer* stream = new SrsBuffer(unprotected_buf, nb_unprotected_buf); + SrsAutoFree(SrsBuffer, stream); + uint8_t first = stream->read_1bytes(); + uint8_t payload_type = stream->read_1bytes(); + + if (payload_type == kSR) { + } else if (payload_type == kRR) { + } else if (kSDES) { + } else if (kBye) { + } else if (kApp) { + } else { + return srs_error_wrap(err, "unknown rtcp type=%u", payload_type); } return err; @@ -857,25 +888,32 @@ SrsRtcServer::SrsRtcServer(SrsServer* svr) SrsRtcServer::~SrsRtcServer() { + rttrd->stop(); + srs_freep(rttrd); } srs_error_t SrsRtcServer::initialize() { srs_error_t err = srs_success; + rttrd = new SrsRtcTimerThread(this, _srs_context->get_id()); + if (rttrd->start() != srs_success) { + return srs_error_wrap(err, "rtc timer thread init failed"); + } + return err; } -srs_error_t SrsRtcServer::on_udp_packet(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; - if (is_stun(udp_remux_socket->data(), udp_remux_socket->size())) { - return on_stun(udp_remux_socket); - } else if (is_dtls(udp_remux_socket->data(), udp_remux_socket->size())) { - return on_dtls(udp_remux_socket); - } else if (is_rtp_or_rtcp(udp_remux_socket->data(), udp_remux_socket->size())) { - return on_rtp_or_rtcp(udp_remux_socket); + if (is_stun(udp_mux_skt->data(), udp_mux_skt->size())) { + return on_stun(udp_mux_skt); + } else if (is_dtls(udp_mux_skt->data(), udp_mux_skt->size())) { + return on_dtls(udp_mux_skt); + } else if (is_rtp_or_rtcp(udp_mux_skt->data(), udp_mux_skt->size())) { + return on_rtp_or_rtcp(udp_mux_skt); } return srs_error_wrap(err, "unknown udp packet type"); @@ -883,20 +921,20 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpRemuxSocket* udp_remux_socket) SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp) { - SrsRtcSession* session = new SrsRtcSession(server, this); - std::string local_pwd = gen_random_str(32); std::string local_ufrag = ""; + std::string username = ""; while (true) { local_ufrag = gen_random_str(8); - std::string username = local_ufrag + ":" + remote_sdp.get_ice_ufrag(); - bool ret = map_username_session.insert(make_pair(username, session)).second; - if (ret) { + username = local_ufrag + ":" + remote_sdp.get_ice_ufrag(); + if (! map_username_session.count(username)) break; - } } + SrsRtcSession* session = new SrsRtcSession(server, this, username); + map_username_session.insert(make_pair(username, session)); + local_sdp.set_ice_ufrag(local_ufrag); local_sdp.set_ice_pwd(local_pwd); @@ -918,14 +956,14 @@ SrsRtcSession* SrsRtcServer::find_rtc_session_by_peer_id(const string& peer_id) return iter->second; } -srs_error_t SrsRtcServer::on_stun(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsRtcServer::on_stun(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; - srs_trace("recv stun packet from %s", udp_remux_socket->get_peer_id().c_str()); + srs_trace("recv stun packet from %s", udp_mux_skt->get_peer_id().c_str()); SrsStunPacket stun_req; - if (stun_req.decode(udp_remux_socket->data(), udp_remux_socket->size()) != srs_success) { + if (stun_req.decode(udp_mux_skt->data(), udp_mux_skt->size()) != srs_success) { return srs_error_wrap(err, "decode stun packet failed"); } @@ -935,37 +973,40 @@ srs_error_t SrsRtcServer::on_stun(SrsUdpRemuxSocket* udp_remux_socket) return srs_error_wrap(err, "can not find rtc_session, stun username=%s", username.c_str()); } - return rtc_session->on_stun(udp_remux_socket, &stun_req); + return rtc_session->on_stun(udp_mux_skt, &stun_req); } -srs_error_t SrsRtcServer::on_dtls(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsRtcServer::on_dtls(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; srs_trace("on dtls"); - SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_remux_socket->get_peer_id()); + SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_mux_skt->get_peer_id()); if (rtc_session == NULL) { - return srs_error_wrap(err, "can not find rtc session by peer_id=%s", udp_remux_socket->get_peer_id().c_str()); + return srs_error_wrap(err, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); } - rtc_session->on_dtls(udp_remux_socket); + rtc_session->on_dtls(udp_mux_skt); return err; } -srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket) +srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; - srs_trace("on rtp/rtcp"); - SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_remux_socket->get_peer_id()); + SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_mux_skt->get_peer_id()); if (rtc_session == NULL) { - return srs_error_wrap(err, "can not find rtc session by peer_id=%s", udp_remux_socket->get_peer_id().c_str()); + return srs_error_wrap(err, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); } - rtc_session->on_rtp_or_rtcp(udp_remux_socket); + if (is_rtcp(udp_mux_skt->data(), udp_mux_skt->size())) { + rtc_session->on_rtcp(udp_mux_skt); + } else { + rtc_session->on_rtp(udp_mux_skt); + } return err; } @@ -984,3 +1025,82 @@ bool SrsRtcServer::insert_into_id_sessions(const string& peer_id, SrsRtcSession* { return map_id_session.insert(make_pair(peer_id, rtc_session)).second; } + +void SrsRtcServer::check_and_clean_timeout_session() +{ + map::iterator iter = map_username_session.begin(); + while (iter != map_username_session.end()) { + SrsRtcSession* session = iter->second; + if (session == NULL) { + map_username_session.erase(iter++); + continue; + } + + if (session->is_stun_timeout()) { + srs_trace("rtc session=%s, stun timeout", session->id().c_str()); + map_username_session.erase(iter++); + map_id_session.erase(session->get_peer_id()); + delete session; + continue; + } + + ++iter; + } +} + +SrsRtcTimerThread::SrsRtcTimerThread(SrsRtcServer* rtc_svr, int parent_cid) +{ + _parent_cid = parent_cid; + trd = new SrsDummyCoroutine(); + + rtc_server = rtc_svr; +} + +SrsRtcTimerThread::~SrsRtcTimerThread() +{ + srs_freep(trd); +} + +int SrsRtcTimerThread::cid() +{ + return trd->cid(); +} + +srs_error_t SrsRtcTimerThread::start() +{ + srs_error_t err = srs_success; + + srs_freep(trd); + trd = new SrsSTCoroutine("rtc_timer", this, _parent_cid); + + if ((err = trd->start()) != srs_success) { + return srs_error_wrap(err, "rtc_timer"); + } + + return err; +} + +void SrsRtcTimerThread::stop() +{ + trd->stop(); +} + +void SrsRtcTimerThread::stop_loop() +{ + trd->interrupt(); +} + +srs_error_t SrsRtcTimerThread::cycle() +{ + srs_error_t err = srs_success; + + while (true) { + if ((err = trd->pull()) != srs_success) { + srs_trace("rtc_timer cycle failed"); + return srs_error_wrap(err, "rtc timer thread"); + } + + srs_usleep(1*1000*1000LL); + rtc_server->check_and_clean_timeout_session(); + } +} diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index fab2afc4c5..fc67ba4311 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -35,12 +36,21 @@ #include #include -class SrsUdpRemuxSocket; +class SrsUdpMuxSocket; class SrsServer; class SrsConsumer; class SrsStunPacket; class SrsRtcServer; class SrsRtcSession; +class SrsSharedPtrMessage; + +const uint8_t kSR = 200; +const uint8_t kRR = 201; +const uint8_t kSDES = 202; +const uint8_t kBye = 203; +const uint8_t kApp = 204; + +const srs_utime_t kSrsRtcSessionStunTimeoutUs = 10*1000*1000LL; class SrsCandidate { @@ -116,19 +126,22 @@ class SrsDtlsSession SrsDtlsSession(SrsRtcSession* s); virtual ~SrsDtlsSession(); - srs_error_t on_dtls(SrsUdpRemuxSocket* udp_remux_socket); - srs_error_t on_dtls_handshake_done(SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_dtls_handshake_done(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_dtls_application_data(const char* data, const int len); - void send_client_hello(SrsUdpRemuxSocket* udp_remux_socket); - srs_error_t handshake(SrsUdpRemuxSocket* udp_remux_socket); - srs_error_t srtp_sender_protect(char* protected_buf, const char* ori_buf, int& nb_protected_buf); - srs_error_t srtp_receiver_unprotect(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); - + void send_client_hello(SrsUdpMuxSocket* udp_mux_skt); +public: + srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); + srs_error_t unprotect_rtp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); + srs_error_t protect_rtcp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); + srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); +private: + srs_error_t handshake(SrsUdpMuxSocket* udp_mux_skt); private: srs_error_t srtp_initialize(); - srs_error_t srtp_sender_side_init(); - srs_error_t srtp_receiver_side_init(); + srs_error_t srtp_send_init(); + srs_error_t srtp_recv_init(); }; class SrsRtcSenderThread : public ISrsCoroutineHandler @@ -138,11 +151,11 @@ class SrsRtcSenderThread : public ISrsCoroutineHandler int _parent_cid; private: SrsRtcSession* rtc_session; - SrsUdpRemuxSocket ukt; + SrsUdpMuxSocket ukt; public: // Constructor. // @param tm The receive timeout in srs_utime_t. - SrsRtcSenderThread(SrsRtcSession* s, SrsUdpRemuxSocket* u, int parent_cid); + SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid); virtual ~SrsRtcSenderThread(); public: virtual int cid(); @@ -152,6 +165,8 @@ class SrsRtcSenderThread : public ISrsCoroutineHandler virtual void stop_loop(); public: virtual srs_error_t cycle(); +private: + void send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* udp_mux_skt); }; class SrsRtcSession @@ -165,39 +180,76 @@ class SrsRtcSession SrsRtcSessionStateType session_state; SrsDtlsSession* dtls_session; SrsRtcSenderThread* strd; + std::string username; + std::string peer_id; + srs_utime_t last_stun_time; public: std::string app; std::string stream; public: - SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr); + SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const std::string& un); virtual ~SrsRtcSession(); public: SrsSdp* get_local_sdp() { return &local_sdp; } - SrsSdp* get_remote_sdp() { return &remote_sdp; } - SrsRtcSessionStateType get_session_state() { return session_state; } - void set_local_sdp(const SrsSdp& sdp) { local_sdp = sdp; } + + SrsSdp* get_remote_sdp() { return &remote_sdp; } void set_remote_sdp(const SrsSdp& sdp) { remote_sdp = sdp; } + + SrsRtcSessionStateType get_session_state() { return session_state; } void set_session_state(SrsRtcSessionStateType state) { session_state = state; } + + std::string id() const { return peer_id + "_" + username; } + void set_app_stream(const std::string& a, const std::string& s) { app = a; stream = s; } + + std::string get_peer_id() const { return peer_id; } + void set_peer_id(const std::string& id) { peer_id = id; } +public: + srs_error_t on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req); + srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_rtp(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_rtcp(SrsUdpMuxSocket* udp_mux_skt); public: - srs_error_t on_stun(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req); - srs_error_t on_dtls(SrsUdpRemuxSocket* udp_remux_socket); - srs_error_t on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t send_client_hello(SrsUdpMuxSocket* udp_mux_skt); + void on_connection_established(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t start_play(SrsUdpMuxSocket* udp_mux_skt); public: - srs_error_t send_client_hello(SrsUdpRemuxSocket* udp_remux_socket); - void on_connection_established(SrsUdpRemuxSocket* udp_remux_socket); - srs_error_t start_play(SrsUdpRemuxSocket* udp_remux_socket); + bool is_stun_timeout() { return last_stun_time + kSrsRtcSessionStunTimeoutUs < srs_get_system_time(); } private: - srs_error_t on_binding_request(SrsUdpRemuxSocket* udp_remux_socket, SrsStunPacket* stun_req); + srs_error_t on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req); private: - srs_error_t do_playing(SrsConsumer* consumer, SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t do_playing(SrsConsumer* consumer, SrsUdpMuxSocket* udp_mux_skt); +}; + +// XXX: is there any other timer thread? +class SrsRtcTimerThread : public ISrsCoroutineHandler +{ +protected: + SrsCoroutine* trd; + int _parent_cid; +private: + SrsRtcServer* rtc_server; +public: + // Constructor. + // @param tm The receive timeout in srs_utime_t. + SrsRtcTimerThread(SrsRtcServer* rtc_svr, int parent_cid); + virtual ~SrsRtcTimerThread(); +public: + virtual int cid(); +public: + virtual srs_error_t start(); + virtual void stop(); + virtual void stop_loop(); +public: + virtual srs_error_t cycle(); }; -class SrsRtcServer : public ISrsUdpRemuxHandler +class SrsRtcServer : public ISrsUdpMuxHandler { private: SrsServer* server; + SrsRtcTimerThread* rttrd; private: std::map map_username_session; // key: username(local_ufrag + ":" + remote_ufrag) std::map map_id_session; // key: peerip(ip + ":" + port) @@ -207,14 +259,15 @@ class SrsRtcServer : public ISrsUdpRemuxHandler public: virtual srs_error_t initialize(); - virtual srs_error_t on_udp_packet(SrsUdpRemuxSocket* udp_remux_socket); + virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* udp_mux_skt); SrsRtcSession* create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp); bool insert_into_id_sessions(const std::string& peer_id, SrsRtcSession* rtc_session); + void check_and_clean_timeout_session(); private: - srs_error_t on_stun(SrsUdpRemuxSocket* udp_remux_socket); - srs_error_t on_dtls(SrsUdpRemuxSocket* udp_remux_socket); - srs_error_t on_rtp_or_rtcp(SrsUdpRemuxSocket* udp_remux_socket); + srs_error_t on_stun(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt); private: SrsRtcSession* find_rtc_session_by_username(const std::string& ufrag); SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id); diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index dafdbd0b88..f3981babe7 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -87,10 +87,12 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF packet_fu_a(shared_frame, format, &sample, rtp_packet_vec); } +#if 0 srs_trace("nal size=%d, nal=%s", sample.size, dump_string_hex(sample.bytes, sample.size, sample.size).c_str()); for (int i = 0; i < shared_frame->nb_rtp_fragments; ++i) { srs_trace("rtp=%s", dump_string_hex(shared_frame->rtp_fragments[i].bytes, shared_frame->rtp_fragments[i].size, kRtpPacketSize).c_str()); } +#endif } SrsSample* rtp_samples = new SrsSample[rtp_packet_vec.size()]; @@ -134,7 +136,6 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma stream->write_1bytes(kH264PayloadType); } // sequence - srs_trace("sequence=%u", sequence); stream->write_2bytes(sequence++); // timestamp stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); @@ -186,7 +187,6 @@ srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, S // marker payloadtype stream->write_1bytes(kMarker | kH264PayloadType); // sequenct - srs_trace("sequence=%u", sequence); stream->write_2bytes(sequence++); // timestamp stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); @@ -220,7 +220,6 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs // marker payloadtype stream->write_1bytes(kMarker | kH264PayloadType); // sequenct - srs_trace("sequence=%u", sequence); stream->write_2bytes(sequence++); // timestamp stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index eee3a9784b..330fd8d105 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -360,7 +360,7 @@ srs_error_t SrsRtcListener::listen(std::string i, int p) port = p; srs_freep(listener); - listener = new SrsUdpRemuxListener(rtc, ip, port); + listener = new SrsUdpMuxListener(rtc, ip, port); if ((err = listener->listen()) != srs_success) { return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); @@ -649,6 +649,10 @@ srs_error_t SrsServer::initialize(ISrsServerCycle* ch) if ((err = http_server->initialize()) != srs_success) { return srs_error_wrap(err, "http server initialize"); } + + if ((err = rtc_server->initialize()) != srs_success) { + return srs_error_wrap(err, "rtc server initialize"); + } return err; } diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 8fa17ff9d1..cf677994d4 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -162,8 +162,8 @@ class SrsUdpCasterListener : public SrsUdpStreamListener class SrsRtcListener : public SrsListener { protected: - SrsUdpRemuxListener* listener; - ISrsUdpRemuxHandler* rtc; + SrsUdpMuxListener* listener; + ISrsUdpMuxHandler* rtc; public: SrsRtcListener(SrsServer* svr, SrsRtcServer* rtc_svr, SrsListenerType t); virtual ~SrsRtcListener(); diff --git a/trunk/src/service/srs_service_st.cpp b/trunk/src/service/srs_service_st.cpp index 555ff5a33f..947150f614 100644 --- a/trunk/src/service/srs_service_st.cpp +++ b/trunk/src/service/srs_service_st.cpp @@ -402,6 +402,11 @@ int srs_sendto(srs_netfd_t stfd, void *buf, int len, const struct sockaddr * to, return st_sendto((st_netfd_t)stfd, buf, len, to, tolen, (st_utime_t)timeout); } +int srs_sendmsg(srs_netfd_t stfd, const struct msghdr *msg, int flags, srs_utime_t timeout) +{ + return st_sendmsg((st_netfd_t)stfd, msg, flags, (st_utime_t)timeout); +} + srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout) { return (srs_netfd_t)st_accept((st_netfd_t)stfd, addr, addrlen, (st_utime_t)timeout); diff --git a/trunk/src/service/srs_service_st.hpp b/trunk/src/service/srs_service_st.hpp index 4894e7049d..947950e853 100644 --- a/trunk/src/service/srs_service_st.hpp +++ b/trunk/src/service/srs_service_st.hpp @@ -89,6 +89,7 @@ extern srs_netfd_t srs_netfd_open(int osfd); extern int srs_recvfrom(srs_netfd_t stfd, void *buf, int len, struct sockaddr *from, int *fromlen, srs_utime_t timeout); extern int srs_sendto(srs_netfd_t stfd, void *buf, int len, const struct sockaddr *to, int tolen, srs_utime_t timeout); +extern int srs_sendmsg(srs_netfd_t stfd, const struct msghdr *msg, int flags, srs_utime_t timeout); extern srs_netfd_t srs_accept(srs_netfd_t stfd, struct sockaddr *addr, int *addrlen, srs_utime_t timeout); From 027d34bbd304ce79b48603fa80b2f392d8668306 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Fri, 13 Mar 2020 20:34:40 +0800 Subject: [PATCH 20/69] add rtp shared packet --- trunk/configure | 2 +- trunk/src/app/srs_app_rtc_conn.cpp | 7 ++-- trunk/src/app/srs_app_rtp.cpp | 51 ++++++++++----------------- trunk/src/app/srs_app_rtp.hpp | 7 ++-- trunk/src/app/srs_app_source.cpp | 2 +- trunk/src/kernel/srs_kernel_error.hpp | 1 + trunk/src/kernel/srs_kernel_flv.cpp | 39 +++++++++----------- trunk/src/kernel/srs_kernel_flv.hpp | 11 +++--- 8 files changed, 51 insertions(+), 69 deletions(-) diff --git a/trunk/configure b/trunk/configure index 495400bb56..211bdbdffd 100755 --- a/trunk/configure +++ b/trunk/configure @@ -204,7 +204,7 @@ MODULE_ID="KERNEL" MODULE_DEPENDS=("CORE") ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_kernel_error" "srs_kernel_log" "srs_kernel_buffer" - "srs_kernel_utility" "srs_kernel_flv" "srs_kernel_codec" "srs_kernel_io" + "srs_kernel_utility" "srs_kernel_flv" "srs_kernel_rtp" "srs_kernel_codec" "srs_kernel_io" "srs_kernel_consts" "srs_kernel_aac" "srs_kernel_mp3" "srs_kernel_ts" "srs_kernel_stream" "srs_kernel_balance" "srs_kernel_mp4" "srs_kernel_file") KERNEL_INCS="src/kernel"; MODULE_DIR=${KERNEL_INCS} . auto/modules.sh diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 07d0fc900f..802e911c8c 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -37,6 +37,7 @@ using namespace std; #include #include +#include #include #include #include @@ -682,12 +683,12 @@ void SrsRtcSenderThread::send_and_free_messages(SrsSharedPtrMessage** msgs, int for (int i = 0; i < nb_msgs; i++) { SrsSharedPtrMessage* msg = msgs[i]; - for (int i = 0; i < msg->nb_rtp_fragments; ++i) { + for (int i = 0; i < msg->rtp_packets.size(); ++i) { if (rtc_session->dtls_session) { char protected_buf[kRtpPacketSize]; - int nb_protected_buf = msg->rtp_fragments[i].size; + int nb_protected_buf = msg->rtp_packets[i]->size; - rtc_session->dtls_session->protect_rtp(protected_buf, msg->rtp_fragments[i].bytes, nb_protected_buf); + rtc_session->dtls_session->protect_rtp(protected_buf, msg->rtp_packets[i]->payload, nb_protected_buf); udp_mux_skt->sendto(protected_buf, nb_protected_buf, 0); } } diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index f3981babe7..ee88f419d1 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -38,6 +38,7 @@ using namespace std; #include #include #include +#include #include #include #include @@ -68,7 +69,7 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF pps.assign(format->vcodec->pictureParameterSetNALUnit.data(), format->vcodec->pictureParameterSetNALUnit.size()); } - vector rtp_packet_vec; + vector rtp_packet_vec; for (int i = 0; i < format->video->nb_samples; ++i) { SrsSample sample = format->video->samples[i]; @@ -95,17 +96,12 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF #endif } - SrsSample* rtp_samples = new SrsSample[rtp_packet_vec.size()]; - for (int i = 0; i < rtp_packet_vec.size(); ++i) { - rtp_samples[i] = rtp_packet_vec[i]; - } - - shared_frame->set_rtp_fragments(rtp_samples, rtp_packet_vec.size()); + shared_frame->set_rtp_packets(rtp_packet_vec); return err; } -srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector& rtp_packet_vec) +srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector& rtp_packet_vec) { srs_error_t err = srs_success; @@ -136,7 +132,7 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma stream->write_1bytes(kH264PayloadType); } // sequence - stream->write_2bytes(sequence++); + stream->write_2bytes(sequence); // timestamp stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); // ssrc @@ -159,15 +155,14 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma nb_left -= packet_size; - SrsSample rtp_packet; - rtp_packet.bytes = stream->data(); - rtp_packet.size = stream->pos(); + SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); + rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos()); - rtp_packet_vec.push_back(rtp_packet); + rtp_packet_vec.push_back(rtp_shared_pkt); } } -srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector& rtp_packet_vec) +srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector& rtp_packet_vec) { srs_error_t err = srs_success; @@ -187,7 +182,7 @@ srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, S // marker payloadtype stream->write_1bytes(kMarker | kH264PayloadType); // sequenct - stream->write_2bytes(sequence++); + stream->write_2bytes(sequence); // timestamp stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); // ssrc @@ -195,16 +190,15 @@ srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, S stream->write_bytes(sample->bytes, sample->size); - SrsSample rtp_packet; - rtp_packet.bytes = stream->data(); - rtp_packet.size = stream->pos(); + SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); + rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos()); - rtp_packet_vec.push_back(rtp_packet); + rtp_packet_vec.push_back(rtp_shared_pkt); return err; } -srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, SrsSharedPtrMessage* shared_frame, vector& rtp_packet_vec) +srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, SrsSharedPtrMessage* shared_frame, vector& rtp_packet_vec) { srs_error_t err = srs_success; @@ -220,7 +214,7 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs // marker payloadtype stream->write_1bytes(kMarker | kH264PayloadType); // sequenct - stream->write_2bytes(sequence++); + stream->write_2bytes(sequence); // timestamp stream->write_4bytes(int32_t(shared_frame->timestamp * 90)); // ssrc @@ -237,11 +231,10 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs stream->write_2bytes(pps.size()); stream->write_bytes((char*)pps.data(), pps.size()); - SrsSample rtp_packet; - rtp_packet.bytes = stream->data(); - rtp_packet.size = stream->pos(); + SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); + rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos()); - rtp_packet_vec.push_back(rtp_packet); + rtp_packet_vec.push_back(rtp_shared_pkt); return err; } @@ -336,9 +329,6 @@ srs_error_t SrsRtp::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma // update the hls time, for hls_dispose. last_update_time = srs_get_system_time(); - SrsSharedPtrMessage* audio = shared_audio->copy(); - SrsAutoFree(SrsSharedPtrMessage, audio); - // ts support audio codec: aac/mp3 SrsAudioCodecId acodec = format->acodec->id; if (acodec != SrsAudioCodecIdAAC && acodec != SrsAudioCodecIdMP3) { @@ -369,11 +359,8 @@ srs_error_t SrsRtp::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* forma // update the hls time, for hls_dispose. last_update_time = srs_get_system_time(); - SrsSharedPtrMessage* video = shared_video->copy(); - SrsAutoFree(SrsSharedPtrMessage, video); - // ignore info frame, // @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909 srs_assert(format->video); - return rtp_h264_muxer->frame_to_packet(video, format); + return rtp_h264_muxer->frame_to_packet(shared_video, format); } diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp index 9000fd8308..2a23440cd5 100644 --- a/trunk/src/app/srs_app_rtp.hpp +++ b/trunk/src/app/srs_app_rtp.hpp @@ -33,6 +33,7 @@ class SrsFormat; class SrsSample; class SrsSharedPtrMessage; +class SrsRtpSharedPacket; class SrsRequest; class SrsOriginHub; @@ -65,9 +66,9 @@ class SrsRtpMuxer public: srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); private: - srs_error_t packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, std::vector& rtp_packet_vec); - srs_error_t packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, std::vector& rtp_packet_vec); - srs_error_t packet_stap_a(const std::string &sps, const std::string& pps, SrsSharedPtrMessage* shared_frame, std::vector& rtp_packet_vec); + srs_error_t packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, std::vector& rtp_packet_vec); + srs_error_t packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, std::vector& rtp_packet_vec); + srs_error_t packet_stap_a(const std::string &sps, const std::string& pps, SrsSharedPtrMessage* shared_frame, std::vector& rtp_packet_vec); }; class SrsRtp diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 1452bf93da..5f1de1149c 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -2300,7 +2300,7 @@ srs_error_t SrsSource::on_video_imp(SrsSharedPtrMessage* msg) if ((err = hub->on_video(msg, is_sequence_header)) != srs_success) { return srs_error_wrap(err, "hub consume video"); } - + // copy to all consumer if (!drop_for_reduce) { for (int i = 0; i < (int)consumers.size(); i++) { diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index 372a0196ae..264903e453 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -322,6 +322,7 @@ #define ERROR_BASE64_DECODE 4039 #define ERROR_HTTP_STREAM_EOF 4040 #define ERROR_RTC_PORT 4041 +#define ERROR_RTP_PACKET_CREATE 4042 /////////////////////////////////////////////////////// // HTTP API error. diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index f2f7730491..5996b60b5a 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -36,6 +36,7 @@ using namespace std; #include #include #include +#include #include #include #include @@ -203,8 +204,6 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::SrsSharedPtrPayload() { payload = NULL; size = 0; - rtp_fragments = NULL; - nb_rtp_fragments = 0; shared_count = 0; } @@ -214,17 +213,9 @@ SrsSharedPtrMessage::SrsSharedPtrPayload::~SrsSharedPtrPayload() srs_memory_unwatch(payload); #endif srs_freepa(payload); - - for (int i = 0; i < nb_rtp_fragments; ++i) { - srs_freepa(rtp_fragments[i].bytes); - } - - if (rtp_fragments != NULL && nb_rtp_fragments > 0) { - srs_freepa(rtp_fragments); - } } -SrsSharedPtrMessage::SrsSharedPtrMessage() : timestamp(0), stream_id(0), size(0), payload(NULL), rtp_fragments(NULL), nb_rtp_fragments(0) +SrsSharedPtrMessage::SrsSharedPtrMessage() : timestamp(0), stream_id(0), size(0), payload(NULL) { ptr = NULL; } @@ -238,6 +229,10 @@ SrsSharedPtrMessage::~SrsSharedPtrMessage() ptr->shared_count--; } } + + for (int i = 0; i < rtp_packets.size(); ++i) { + srs_freep(rtp_packets[i]); + } } srs_error_t SrsSharedPtrMessage::create(SrsCommonMessage* msg) @@ -315,15 +310,6 @@ bool SrsSharedPtrMessage::check(int stream_id) return false; } -void SrsSharedPtrMessage::set_rtp_fragments(SrsSample* samples, int nb_samples) -{ - ptr->rtp_fragments = samples; - ptr->nb_rtp_fragments = nb_samples; - - rtp_fragments = samples; - nb_rtp_fragments = nb_samples; -} - bool SrsSharedPtrMessage::is_av() { return ptr->header.message_type == RTMP_MSG_AudioMessage @@ -364,12 +350,19 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy() copy->stream_id = stream_id; copy->payload = ptr->payload; copy->size = ptr->size; - copy->rtp_fragments = ptr->rtp_fragments; - copy->nb_rtp_fragments = ptr->nb_rtp_fragments; - + + for (int i = 0; i < rtp_packets.size(); ++i) { + copy->rtp_packets.push_back(rtp_packets[i]->copy()); + } + return copy; } +void SrsSharedPtrMessage::set_rtp_packets(const std::vector& pkts) +{ + rtp_packets = pkts; +} + SrsFlvTransmuxer::SrsFlvTransmuxer() { writer = NULL; diff --git a/trunk/src/kernel/srs_kernel_flv.hpp b/trunk/src/kernel/srs_kernel_flv.hpp index fe8fd9aa03..3bf3afc69b 100644 --- a/trunk/src/kernel/srs_kernel_flv.hpp +++ b/trunk/src/kernel/srs_kernel_flv.hpp @@ -27,6 +27,7 @@ #include #include +#include // For srs-librtmp, @see https://github.com/ossrs/srs/issues/213 #ifndef _WIN32 @@ -39,6 +40,7 @@ class ISrsReader; class SrsFileReader; class SrsPacket; class SrsSample; +class SrsRtpSharedPacket; #define SRS_FLV_TAG_HEADER_SIZE 11 #define SRS_FLV_PREVIOUS_TAG_SIZE 4 @@ -287,8 +289,7 @@ class SrsSharedPtrMessage // video/audio packet use raw bytes, no video/audio packet. char* payload; - SrsSample* rtp_fragments; - int nb_rtp_fragments; + std::vector rtp_packets; private: class SrsSharedPtrPayload { @@ -302,8 +303,6 @@ class SrsSharedPtrMessage int size; // The reference count int shared_count; - SrsSample* rtp_fragments; - int nb_rtp_fragments; public: SrsSharedPtrPayload(); virtual ~SrsSharedPtrPayload(); @@ -333,8 +332,6 @@ class SrsSharedPtrMessage // check perfer cid and stream id. // @return whether stream id already set. virtual bool check(int stream_id); - - virtual void set_rtp_fragments(SrsSample* samples, int nb_samples); public: virtual bool is_av(); virtual bool is_audio(); @@ -347,6 +344,8 @@ class SrsSharedPtrMessage // copy current shared ptr message, use ref-count. // @remark, assert object is created. virtual SrsSharedPtrMessage* copy(); +public: + virtual void set_rtp_packets(const std::vector& pkts); }; // Transmux RTMP packets to FLV stream. From 768598a3bb2a0429a689008ca374d45ab2b16be7 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Fri, 13 Mar 2020 20:35:07 +0800 Subject: [PATCH 21/69] add kernel rtp packet --- trunk/src/kernel/srs_kernel_rtp.cpp | 112 ++++++++++++++++++++++++++++ trunk/src/kernel/srs_kernel_rtp.hpp | 62 +++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 trunk/src/kernel/srs_kernel_rtp.cpp create mode 100644 trunk/src/kernel/srs_kernel_rtp.hpp diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp new file mode 100644 index 0000000000..516ae89ff8 --- /dev/null +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -0,0 +1,112 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +using namespace std; + +#include +#include +#include +#include + +SrsRtpSharedPacket::SrsRtpSharedPacketPayload::SrsRtpSharedPacketPayload() +{ + payload = NULL; + size = 0; + shared_count = 0; +} + +SrsRtpSharedPacket::SrsRtpSharedPacketPayload::~SrsRtpSharedPacketPayload() +{ + srs_freepa(payload); +} + +SrsRtpSharedPacket::SrsRtpSharedPacket() +{ + payload_ptr = NULL; + + payload = NULL; + size = 0; + + timestamp = -1; + sequence = 0; + ssrc = 0; + payload_type = 0; +} + +SrsRtpSharedPacket::~SrsRtpSharedPacket() +{ + if (payload_ptr) { + if (payload_ptr->shared_count == 0) { + srs_freep(payload_ptr); + } else { + --payload_ptr->shared_count; + } + } +} + +srs_error_t SrsRtpSharedPacket::create(int64_t t, uint16_t seq, uint32_t sc, uint16_t pt, char* p, int s) +{ + srs_error_t err = srs_success; + + if (size < 0) { + return srs_error_new(ERROR_RTP_PACKET_CREATE, "create packet size=%d", size); + } + + srs_assert(!payload_ptr); + + timestamp = t; + sequence = seq; + ssrc = sc; + payload_type = pt; + + payload_ptr = new SrsRtpSharedPacketPayload(); + payload_ptr->payload = p; + payload_ptr->size = s; + + payload = payload_ptr->payload; + size = payload_ptr->size; + + return err; +} + +SrsRtpSharedPacket* SrsRtpSharedPacket::copy() +{ + SrsRtpSharedPacket* copy = new SrsRtpSharedPacket(); + + copy->payload_ptr = payload_ptr; + payload_ptr->shared_count++; + + copy->payload = payload; + copy->size = size; + + copy->timestamp = timestamp; + copy->sequence = sequence; + copy->ssrc = ssrc; + copy->payload_type = payload_type; + + return copy; +} diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp new file mode 100644 index 0000000000..b348946ec8 --- /dev/null +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -0,0 +1,62 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_KERNEL_RTP_HPP +#define SRS_KERNEL_RTP_HPP + +#include + +#include + +class SrsRtpSharedPacket +{ +private: + class SrsRtpSharedPacketPayload + { + public: + char* payload; + int size; + int shared_count; + public: + SrsRtpSharedPacketPayload(); + virtual ~SrsRtpSharedPacketPayload(); + }; +private: + SrsRtpSharedPacketPayload* payload_ptr; +public: + char* payload; + int size; +public: + int64_t timestamp; + uint16_t sequence; + uint32_t ssrc; + uint16_t payload_type; +public: + SrsRtpSharedPacket(); + virtual ~SrsRtpSharedPacket(); +public: + srs_error_t create(int64_t t, uint16_t seq, uint32_t sc, uint16_t pt, char* p, int s); + SrsRtpSharedPacket* copy(); +}; + +#endif From 6c88f5807933aab9d85d143ba1edcecfc6a57826 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Fri, 13 Mar 2020 22:50:34 +0800 Subject: [PATCH 22/69] remove debug code, fix rtc.html --- trunk/research/players/rtc.html | 90 -------------------- trunk/research/players/rtc_upload.html | 97 ---------------------- trunk/research/players/srs_rtc_player.html | 4 +- trunk/src/app/srs_app_http_api.cpp | 27 ++---- trunk/src/app/srs_app_log.cpp | 2 +- trunk/src/app/srs_app_rtc_conn.cpp | 1 + trunk/src/app/srs_app_rtc_conn.hpp | 4 - trunk/src/app/srs_app_rtp.cpp | 9 +- trunk/src/app/srs_app_rtp.hpp | 1 + trunk/src/protocol/srs_stun_stack.cpp | 41 +-------- trunk/src/protocol/srs_stun_stack.hpp | 4 + 11 files changed, 19 insertions(+), 261 deletions(-) delete mode 100644 trunk/research/players/rtc.html delete mode 100644 trunk/research/players/rtc_upload.html diff --git a/trunk/research/players/rtc.html b/trunk/research/players/rtc.html deleted file mode 100644 index 4dd8e44f25..0000000000 --- a/trunk/research/players/rtc.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - -rtc_media_player:
- - - - - - - \ No newline at end of file diff --git a/trunk/research/players/rtc_upload.html b/trunk/research/players/rtc_upload.html deleted file mode 100644 index 68c515d8eb..0000000000 --- a/trunk/research/players/rtc_upload.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - -
local_media_player:
- -
rtc_media_player:
- - - - - - - diff --git a/trunk/research/players/srs_rtc_player.html b/trunk/research/players/srs_rtc_player.html index bbb605ab51..1644684904 100644 --- a/trunk/research/players/srs_rtc_player.html +++ b/trunk/research/players/srs_rtc_player.html @@ -7,7 +7,7 @@ rtc_media_player:
- + @@ -16,7 +16,7 @@ var PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; var SessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription; -var url = "http://hw.com:1985/api/v1/sdp/"; +var url = document.location.protocol + "//" + document.domain + ":1985/api/v1/sdp/"; var method = "POST"; var shouldBeAsync = true; diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index fd418bf86c..76b8777428 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -794,18 +794,11 @@ SrsGoApiSdp::~SrsGoApiSdp() srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) { srs_error_t err = srs_success; - - SrsStatistic* stat = SrsStatistic::instance(); - - // path: {pattern}{stream_id} - // e.g. /api/v1/streams/100 pattern= /api/v1/streams/, stream_id=100 - int sid = r->parse_rest_id(entry->pattern); - - SrsStatisticStream* stream = NULL; - if (sid >= 0 && (stream = stat->find_stream(sid)) == NULL) { - return srs_api_response_code(w, r, ERROR_RTMP_STREAM_NOT_FOUND); - } + // path: {pattern} + // method: POST + // e.g. /api/v1/sdp/ args = json:{"sdp":"sdp...", "app":"webrtc", "stream":"test"} + string req_json; r->body_read_all(req_json); srs_trace("req_json=%s", req_json.c_str()); @@ -850,20 +843,10 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); obj->set("server", SrsJsonAny::integer(stat->server_id())); - // XXX: ice candidate - //string candidate_str = "candidate:1 1 udp 2115783679 192.168.170.129:9527 typ host generation 0 ufrag " - // + local_sdp.get_ice_ufrag() + "netwrok-cost 50"; - - //SrsJsonObject* candidate_obj = SrsJsonAny::object(); - //SrsAutoFree(SrsJsonObject, candidate_obj); - - //candidate_obj->set("candidate", SrsJsonAny::str(candidate_str.c_str())); - //candidate_obj->set("sdpMid", SrsJsonAny::str("0")); - //candidate_obj->set("sdpMLineIndex", SrsJsonAny::str("0")); + // TODO: add candidates in response json? if (r->is_http_post()) { obj->set("sdp", SrsJsonAny::str(local_sdp_str.c_str())); - // obj->set("candidate", candidate_obj); } else { return srs_go_http_error(w, SRS_CONSTS_HTTP_MethodNotAllowed); } diff --git a/trunk/src/app/srs_app_log.cpp b/trunk/src/app/srs_app_log.cpp index f743a056c6..4d73ebf8e2 100644 --- a/trunk/src/app/srs_app_log.cpp +++ b/trunk/src/app/srs_app_log.cpp @@ -37,7 +37,7 @@ #include // the max size of a line of log. -#define LOG_MAX_SIZE 4096000 +#define LOG_MAX_SIZE 4096 // the tail append to each log. #define LOG_TAIL '\n' diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 802e911c8c..e49a4c5569 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -689,6 +689,7 @@ void SrsRtcSenderThread::send_and_free_messages(SrsSharedPtrMessage** msgs, int int nb_protected_buf = msg->rtp_packets[i]->size; rtc_session->dtls_session->protect_rtp(protected_buf, msg->rtp_packets[i]->payload, nb_protected_buf); + // TODO: use sendmmsg to send multi packet one system call udp_mux_skt->sendto(protected_buf, nb_protected_buf, 0); } } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index fc67ba4311..c1b786af43 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -153,8 +153,6 @@ class SrsRtcSenderThread : public ISrsCoroutineHandler SrsRtcSession* rtc_session; SrsUdpMuxSocket ukt; public: - // Constructor. - // @param tm The receive timeout in srs_utime_t. SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid); virtual ~SrsRtcSenderThread(); public: @@ -231,8 +229,6 @@ class SrsRtcTimerThread : public ISrsCoroutineHandler private: SrsRtcServer* rtc_server; public: - // Constructor. - // @param tm The receive timeout in srs_utime_t. SrsRtcTimerThread(SrsRtcServer* rtc_svr, int parent_cid); virtual ~SrsRtcTimerThread(); public: diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index ee88f419d1..729251fc44 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -77,8 +77,8 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF uint8_t header = sample.bytes[0]; uint8_t nal_type = header & kNalTypeMask; + // ignore SEI nal if (nal_type == 0x06) { - srs_trace("ignore SEI"); continue; } @@ -87,13 +87,6 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF } else { packet_fu_a(shared_frame, format, &sample, rtp_packet_vec); } - -#if 0 - srs_trace("nal size=%d, nal=%s", sample.size, dump_string_hex(sample.bytes, sample.size, sample.size).c_str()); - for (int i = 0; i < shared_frame->nb_rtp_fragments; ++i) { - srs_trace("rtp=%s", dump_string_hex(shared_frame->rtp_fragments[i].bytes, shared_frame->rtp_fragments[i].size, kRtpPacketSize).c_str()); - } -#endif } shared_frame->set_rtp_packets(rtp_packet_vec); diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp index 2a23440cd5..badfea4435 100644 --- a/trunk/src/app/srs_app_rtp.hpp +++ b/trunk/src/app/srs_app_rtp.hpp @@ -52,6 +52,7 @@ const uint8_t kFuA = 28; const uint8_t kStart = 0x80; const uint8_t kEnd = 0x40; +// FIXME: ssrc can relate to source const uint32_t kVideoSSRC = 3233846889; class SrsRtpMuxer diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp index a057715d6f..146bb23f7f 100644 --- a/trunk/src/protocol/srs_stun_stack.cpp +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -12,23 +12,6 @@ using namespace std; #include #include -static string dump_string_hex(const std::string& str, const int& max_len = 128) -{ - char buf[1024*16]; - int len = 0; - - for (int i = 0; i < str.size() && i < max_len; ++i) { - int nb = snprintf(buf + len, sizeof(buf) - len - 1, "%02X ", (uint8_t)str[i]); - if (nb <= 0) - break; - - len += nb; - } - buf[len] = '\0'; - - return string(buf, len); -} - static srs_error_t hmac_encode(const std::string& algo, const char* key, const int& key_length, const char* input, const int input_length, char* output, unsigned int& output_length) { @@ -95,8 +78,6 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) return srs_error_wrap(err, "invalid stun packet, size=%d", stream->size()); } - srs_trace("stun packet, nb_buf=%d", nb_buf); - message_type = stream->read_2bytes(); uint16_t message_len = stream->read_2bytes(); string magic_cookie = stream->read_string(4); @@ -113,8 +94,6 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) uint16_t type = stream->read_2bytes(); uint16_t len = stream->read_2bytes(); - srs_trace("type=%u, len=%u", type, len); - if (stream->left() < len) { return srs_error_wrap(err, "invalid stun packet"); } @@ -124,11 +103,9 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) if (len % 4 != 0) { stream->read_string(4 - (len % 4)); } - //srs_trace("val=%s", val.c_str()); switch (type) { - // FIXME: enum - case 6: { + case Username: { username = val; size_t p = val.find(":"); if (p != string::npos) { @@ -168,7 +145,7 @@ srs_error_t SrsStunPacket::encode_binding_response(const string& pwd, SrsBuffer* stream->write_2bytes(BindingResponse); stream->write_2bytes(property_username.size() + mapped_address.size()); - stream->write_4bytes(0x2112A442); + stream->write_4bytes(kStunMagicCookie); stream->write_string(transcation_id); stream->write_string(property_username); stream->write_string(mapped_address); @@ -226,22 +203,12 @@ string SrsStunPacket::encode_mapped_address() SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); SrsAutoFree(SrsBuffer, stream); - uint32_t magic_cookie = 0x2112A442; -#if 1 stream->write_2bytes(XorMappedAddress); stream->write_2bytes(8); stream->write_1bytes(0); // ignore this bytes stream->write_1bytes(1); // ipv4 family - stream->write_2bytes(mapped_port ^ (magic_cookie >> 16)); - stream->write_4bytes(mapped_address ^ magic_cookie); -#else - stream->write_2bytes(MappedAddress); - stream->write_2bytes(8); - stream->write_1bytes(0); // ignore this bytes - stream->write_1bytes(1); // ipv4 family - stream->write_2bytes(mapped_port); - stream->write_4bytes(mapped_address); -#endif + stream->write_2bytes(mapped_port ^ (kStunMagicCookie >> 16)); + stream->write_4bytes(mapped_address ^ kStunMagicCookie); return string(stream->data(), stream->pos()); } diff --git a/trunk/src/protocol/srs_stun_stack.hpp b/trunk/src/protocol/srs_stun_stack.hpp index aa2bc21925..db74c90b3e 100644 --- a/trunk/src/protocol/srs_stun_stack.hpp +++ b/trunk/src/protocol/srs_stun_stack.hpp @@ -31,6 +31,10 @@ class SrsBuffer; +// @see: https://tools.ietf.org/html/rfc5389 +// The magic cookie field MUST contain the fixed value 0x2112A442 in network byte order +const uint32_t kStunMagicCookie = 0x2112A442; + enum SrsStunMessageType { // see @ https://tools.ietf.org/html/rfc3489#section-11.1 From 51af2b477992aeb0587cb49629492b5b8b3690fd Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 14 Mar 2020 17:15:46 +0800 Subject: [PATCH 23/69] For #1638, #307, rtc conf support ENV. --- trunk/conf/full.conf | 19 +++++ trunk/conf/rtc.conf | 38 ++++----- trunk/research/players/rtc.html | 6 +- trunk/research/players/rtc_upload.html | 97 ---------------------- trunk/research/players/srs_rtc_player.html | 90 -------------------- trunk/src/app/srs_app_config.cpp | 7 +- trunk/src/app/srs_app_http_api.cpp | 2 +- trunk/src/app/srs_app_utility.cpp | 20 +++++ trunk/src/app/srs_app_utility.hpp | 4 + trunk/src/main/srs_main_server.cpp | 12 --- 10 files changed, 68 insertions(+), 227 deletions(-) delete mode 100644 trunk/research/players/rtc_upload.html delete mode 100644 trunk/research/players/srs_rtc_player.html diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 1a23b87c96..3c8abe1c69 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -306,6 +306,25 @@ srt_server { default_app live; } +############################################################################################# +# WebRTC server section +############################################################################################# +rtc { + # Whether enable WebRTC server. + # default: off + enabled on; + # The udp listen port, we will reuse it for connections. + # default: 8080 + listen 8000; + # The exposed candidate IP, response in SDP candidate line. + # It can be: + # * Retrieve server IP automatically, specified by stats.network for multiple networks. + # $CANDIDATE Read the IP from ENV variable $EIP, see https://github.com/ossrs/srs/issues/307#issuecomment-599028124 + # x.x.x.x A specified IP address or DNS name, which can be access by client such as Chrome. + # default: * + candidate *; +} + ############################################################################################# # Kafka sections ############################################################################################# diff --git a/trunk/conf/rtc.conf b/trunk/conf/rtc.conf index fe8d545ec1..03b42c75d1 100644 --- a/trunk/conf/rtc.conf +++ b/trunk/conf/rtc.conf @@ -1,40 +1,32 @@ -# main config for srs. -# @see full.conf for detail config. listen 1935; max_connections 1000; -srs_log_tank file; +srs_log_tank console; srs_log_file ./objs/srs.log; -http_api { - enabled on; - listen 1985; - raw_api { - enabled on; - allow_reload on; - allow_query on; - allow_update on; - } -} + http_server { enabled on; listen 8080; dir ./objs/nginx/html; } -rtc { + +http_api { enabled on; - listen 9527; - # candidate device ip: *(all interface), 192.168.1.1 ... - candidate *; + listen 1985; } stats { network 0; - disk sda sdb xvda xvdb; } -vhost __defaultVhost__ { - http_remux { - enabled on; - mount [vhost]/[app]/[stream].flv; - } +rtc { + enabled on; + # Listen at udp://8000 + listen 8000; + # The * means using IP of network interface stats.network, + # For example, if stats.network=0, then use IP of eth0 as candidate. + # @see https://github.com/ossrs/srs/issues/307#issuecomment-599028124 + candidate *; } +vhost __defaultVhost__ { +} diff --git a/trunk/research/players/rtc.html b/trunk/research/players/rtc.html index 4dd8e44f25..80cd1a2c08 100644 --- a/trunk/research/players/rtc.html +++ b/trunk/research/players/rtc.html @@ -7,7 +7,7 @@ rtc_media_player:
- + @@ -16,7 +16,7 @@ var PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; var SessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription; -var url = "http://hw.com:1985/api/v1/sdp/"; +var url = "http://localhost:1985/api/v1/sdp/"; var method = "POST"; var shouldBeAsync = true; @@ -40,7 +40,7 @@ pc.setLocalDescription(desc); - var sdp_json = {"sdp":desc.sdp, "app":"webrtc", "stream":"test"}; + var sdp_json = {"sdp":desc.sdp, "app":"live", "stream":"livestream"}; request.send(JSON.stringify(sdp_json)); }; diff --git a/trunk/research/players/rtc_upload.html b/trunk/research/players/rtc_upload.html deleted file mode 100644 index 68c515d8eb..0000000000 --- a/trunk/research/players/rtc_upload.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - -
local_media_player:
- -
rtc_media_player:
- - - - - - - diff --git a/trunk/research/players/srs_rtc_player.html b/trunk/research/players/srs_rtc_player.html deleted file mode 100644 index bbb605ab51..0000000000 --- a/trunk/research/players/srs_rtc_player.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - -rtc_media_player:
- - - - - - - diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index a206dc6da1..cb47e12e01 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4290,7 +4290,7 @@ bool SrsConfig::get_rtc_enabled(SrsConfDirective* conf) int SrsConfig::get_rtc_listen() { - static int DEFAULT = 9527; + static int DEFAULT = 8000; SrsConfDirective* conf = root->get("rtc"); if (!conf) { @@ -4318,6 +4318,11 @@ std::string SrsConfig::get_rtc_candidates() if (!conf || conf->arg0().empty()) { return DEFAULT; } + + string eip = srs_getenv(conf->arg0()); + if (!eip.empty()) { + return eip; + } return (conf->arg0().c_str()); } diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index fd418bf86c..5cf5fe038b 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -851,7 +851,7 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* obj->set("server", SrsJsonAny::integer(stat->server_id())); // XXX: ice candidate - //string candidate_str = "candidate:1 1 udp 2115783679 192.168.170.129:9527 typ host generation 0 ufrag " + //string candidate_str = "candidate:1 1 udp 2115783679 192.168.170.129:8000 typ host generation 0 ufrag " // + local_sdp.get_ice_ufrag() + "netwrok-cost 50"; //SrsJsonObject* candidate_obj = SrsJsonAny::object(); diff --git a/trunk/src/app/srs_app_utility.cpp b/trunk/src/app/srs_app_utility.cpp index 66ae112696..f6da9502fa 100644 --- a/trunk/src/app/srs_app_utility.cpp +++ b/trunk/src/app/srs_app_utility.cpp @@ -1227,3 +1227,23 @@ string dump_string_hex(const char* buf, const int nb_buf, const int& max_len) return ret; } + +string srs_getenv(string key) +{ + string ekey = key; + if (srs_string_starts_with(key, "$")) { + ekey = key.substr(1); + } + + if (ekey.empty()) { + return ""; + } + + char* value = ::getenv(ekey.c_str()); + if (value) { + return value; + } + + return ""; +} + diff --git a/trunk/src/app/srs_app_utility.hpp b/trunk/src/app/srs_app_utility.hpp index 77d28f802d..0ae50687de 100644 --- a/trunk/src/app/srs_app_utility.hpp +++ b/trunk/src/app/srs_app_utility.hpp @@ -653,5 +653,9 @@ extern void srs_api_dump_summaries(SrsJsonObject* obj); extern std::string dump_string_hex(const std::string& str, const int& max_len = INT_MAX); extern std::string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = INT_MAX); +// Get ENV variable, which may starts with $. +// srs_getenv("EIP") === srs_getenv("$EIP") +extern std::string srs_getenv(std::string key); + #endif diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 61f4f1d0d3..0778c72f16 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -59,7 +59,6 @@ using namespace std; srs_error_t run_directly_or_daemon(); srs_error_t run_hybrid_server(); void show_macro_features(); -string srs_getenv(const char* name); // @global log and context. ISrsLog* _srs_log = new SrsFastLog(); @@ -344,17 +343,6 @@ void show_macro_features() #endif } -string srs_getenv(const char* name) -{ - char* cv = ::getenv(name); - - if (cv) { - return cv; - } - - return ""; -} - // Detect docker by https://stackoverflow.com/a/41559867 bool _srs_in_docker = false; srs_error_t srs_detect_docker() From a42cf3ae8db71414f754456fa62f20ccb26489d6 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 14 Mar 2020 18:05:58 +0800 Subject: [PATCH 24/69] For #1638, #307, refactor rtc config. --- trunk/conf/rtc.conf | 6 +++++- trunk/research/players/rtc.html | 2 +- trunk/src/app/srs_app_config.cpp | 5 +++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/trunk/conf/rtc.conf b/trunk/conf/rtc.conf index 03b42c75d1..300b81d6f4 100644 --- a/trunk/conf/rtc.conf +++ b/trunk/conf/rtc.conf @@ -3,6 +3,7 @@ listen 1935; max_connections 1000; srs_log_tank console; srs_log_file ./objs/srs.log; +daemon off; http_server { enabled on; @@ -21,10 +22,13 @@ rtc { enabled on; # Listen at udp://8000 listen 8000; + # + # The $CANDIDATE means fetch from env, if not configed, use default * as bellow. + # # The * means using IP of network interface stats.network, # For example, if stats.network=0, then use IP of eth0 as candidate. # @see https://github.com/ossrs/srs/issues/307#issuecomment-599028124 - candidate *; + candidate $CANDIDATE; } vhost __defaultVhost__ { diff --git a/trunk/research/players/rtc.html b/trunk/research/players/rtc.html index 80cd1a2c08..550467aa11 100644 --- a/trunk/research/players/rtc.html +++ b/trunk/research/players/rtc.html @@ -16,7 +16,7 @@ var PeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection; var SessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription; -var url = "http://localhost:1985/api/v1/sdp/"; +var url = document.location.protocol + "//" + document.location.hostname + ":1985/api/v1/sdp/"; var method = "POST"; var shouldBeAsync = true; diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index cb47e12e01..b79fdadd76 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4323,6 +4323,11 @@ std::string SrsConfig::get_rtc_candidates() if (!eip.empty()) { return eip; } + + // If configed as ENV, but no ENV set, use default value. + if (srs_string_starts_with(conf->arg0(), "$")) { + return DEFAULT; + } return (conf->arg0().c_str()); } From 12e99f1897bf2db5f790deeae3c8f6ddfbb97607 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 14 Mar 2020 21:14:17 +0800 Subject: [PATCH 25/69] For #1638, #307, use webrtc adapter.js for demo. --- trunk/research/players/js/adapter-7.4.0.js | 5551 +++++++++++++++++ .../research/players/js/adapter-7.4.0.min.js | 1 + trunk/research/players/js/srs.page.js | 46 +- trunk/research/players/rtc.html | 90 - trunk/research/players/rtc_player.html | 110 + trunk/research/players/srs_player.html | 3 + trunk/src/app/srs_app_http_api.cpp | 1 + 7 files changed, 5707 insertions(+), 95 deletions(-) create mode 100644 trunk/research/players/js/adapter-7.4.0.js create mode 100644 trunk/research/players/js/adapter-7.4.0.min.js delete mode 100644 trunk/research/players/rtc.html create mode 100644 trunk/research/players/rtc_player.html diff --git a/trunk/research/players/js/adapter-7.4.0.js b/trunk/research/players/js/adapter-7.4.0.js new file mode 100644 index 0000000000..bd8df9defb --- /dev/null +++ b/trunk/research/players/js/adapter-7.4.0.js @@ -0,0 +1,5551 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0 && arguments[0] !== undefined ? arguments[0] : {}, + window = _ref.window; + + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { + shimChrome: true, + shimFirefox: true, + shimEdge: true, + shimSafari: true + }; + + // Utils. + var logging = utils.log; + var browserDetails = utils.detectBrowser(window); + + var adapter = { + browserDetails: browserDetails, + commonShim: commonShim, + extractVersion: utils.extractVersion, + disableLog: utils.disableLog, + disableWarnings: utils.disableWarnings + }; + + // Shim browser if found. + switch (browserDetails.browser) { + case 'chrome': + if (!chromeShim || !chromeShim.shimPeerConnection || !options.shimChrome) { + logging('Chrome shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming chrome.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = chromeShim; + + chromeShim.shimGetUserMedia(window); + chromeShim.shimMediaStream(window); + chromeShim.shimPeerConnection(window); + chromeShim.shimOnTrack(window); + chromeShim.shimAddTrackRemoveTrack(window); + chromeShim.shimGetSendersWithDtmf(window); + chromeShim.shimGetStats(window); + chromeShim.shimSenderReceiverGetStats(window); + chromeShim.fixNegotiationNeeded(window); + + commonShim.shimRTCIceCandidate(window); + commonShim.shimConnectionState(window); + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + commonShim.removeAllowExtmapMixed(window); + break; + case 'firefox': + if (!firefoxShim || !firefoxShim.shimPeerConnection || !options.shimFirefox) { + logging('Firefox shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming firefox.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = firefoxShim; + + firefoxShim.shimGetUserMedia(window); + firefoxShim.shimPeerConnection(window); + firefoxShim.shimOnTrack(window); + firefoxShim.shimRemoveStream(window); + firefoxShim.shimSenderGetStats(window); + firefoxShim.shimReceiverGetStats(window); + firefoxShim.shimRTCDataChannel(window); + firefoxShim.shimAddTransceiver(window); + firefoxShim.shimCreateOffer(window); + firefoxShim.shimCreateAnswer(window); + + commonShim.shimRTCIceCandidate(window); + commonShim.shimConnectionState(window); + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + break; + case 'edge': + if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { + logging('MS edge shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming edge.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = edgeShim; + + edgeShim.shimGetUserMedia(window); + edgeShim.shimGetDisplayMedia(window); + edgeShim.shimPeerConnection(window); + edgeShim.shimReplaceTrack(window); + + // the edge shim implements the full RTCIceCandidate object. + + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + break; + case 'safari': + if (!safariShim || !options.shimSafari) { + logging('Safari shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming safari.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = safariShim; + + safariShim.shimRTCIceServerUrls(window); + safariShim.shimCreateOfferLegacy(window); + safariShim.shimCallbacksAPI(window); + safariShim.shimLocalStreamsAPI(window); + safariShim.shimRemoteStreamsAPI(window); + safariShim.shimTrackEventTransceiver(window); + safariShim.shimGetUserMedia(window); + + commonShim.shimRTCIceCandidate(window); + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + commonShim.removeAllowExtmapMixed(window); + break; + default: + logging('Unsupported browser!'); + break; + } + + return adapter; +} + +// Browser shims. + +},{"./chrome/chrome_shim":3,"./common_shim":6,"./edge/edge_shim":7,"./firefox/firefox_shim":11,"./safari/safari_shim":14,"./utils":15}],3:[function(require,module,exports){ + +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _getusermedia = require('./getusermedia'); + +Object.defineProperty(exports, 'shimGetUserMedia', { + enumerable: true, + get: function get() { + return _getusermedia.shimGetUserMedia; + } +}); + +var _getdisplaymedia = require('./getdisplaymedia'); + +Object.defineProperty(exports, 'shimGetDisplayMedia', { + enumerable: true, + get: function get() { + return _getdisplaymedia.shimGetDisplayMedia; + } +}); +exports.shimMediaStream = shimMediaStream; +exports.shimOnTrack = shimOnTrack; +exports.shimGetSendersWithDtmf = shimGetSendersWithDtmf; +exports.shimGetStats = shimGetStats; +exports.shimSenderReceiverGetStats = shimSenderReceiverGetStats; +exports.shimAddTrackRemoveTrackWithNative = shimAddTrackRemoveTrackWithNative; +exports.shimAddTrackRemoveTrack = shimAddTrackRemoveTrack; +exports.shimPeerConnection = shimPeerConnection; +exports.fixNegotiationNeeded = fixNegotiationNeeded; + +var _utils = require('../utils.js'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function shimMediaStream(window) { + window.MediaStream = window.MediaStream || window.webkitMediaStream; +} + +function shimOnTrack(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { + get: function get() { + return this._ontrack; + }, + set: function set(f) { + if (this._ontrack) { + this.removeEventListener('track', this._ontrack); + } + this.addEventListener('track', this._ontrack = f); + }, + + enumerable: true, + configurable: true + }); + var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { + var _this = this; + + if (!this._ontrackpoly) { + this._ontrackpoly = function (e) { + // onaddstream does not fire when a track is added to an existing + // stream. But stream.onaddtrack is implemented so we use that. + e.stream.addEventListener('addtrack', function (te) { + var receiver = void 0; + if (window.RTCPeerConnection.prototype.getReceivers) { + receiver = _this.getReceivers().find(function (r) { + return r.track && r.track.id === te.track.id; + }); + } else { + receiver = { track: te.track }; + } + + var event = new Event('track'); + event.track = te.track; + event.receiver = receiver; + event.transceiver = { receiver: receiver }; + event.streams = [e.stream]; + _this.dispatchEvent(event); + }); + e.stream.getTracks().forEach(function (track) { + var receiver = void 0; + if (window.RTCPeerConnection.prototype.getReceivers) { + receiver = _this.getReceivers().find(function (r) { + return r.track && r.track.id === track.id; + }); + } else { + receiver = { track: track }; + } + var event = new Event('track'); + event.track = track; + event.receiver = receiver; + event.transceiver = { receiver: receiver }; + event.streams = [e.stream]; + _this.dispatchEvent(event); + }); + }; + this.addEventListener('addstream', this._ontrackpoly); + } + return origSetRemoteDescription.apply(this, arguments); + }; + } else { + // even if RTCRtpTransceiver is in window, it is only used and + // emitted in unified-plan. Unfortunately this means we need + // to unconditionally wrap the event. + utils.wrapPeerConnectionEvent(window, 'track', function (e) { + if (!e.transceiver) { + Object.defineProperty(e, 'transceiver', { value: { receiver: e.receiver } }); + } + return e; + }); + } +} + +function shimGetSendersWithDtmf(window) { + // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('getSenders' in window.RTCPeerConnection.prototype) && 'createDTMFSender' in window.RTCPeerConnection.prototype) { + var shimSenderWithDtmf = function shimSenderWithDtmf(pc, track) { + return { + track: track, + get dtmf() { + if (this._dtmf === undefined) { + if (track.kind === 'audio') { + this._dtmf = pc.createDTMFSender(track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + }, + _pc: pc + }; + }; + + // augment addTrack when getSenders is not available. + if (!window.RTCPeerConnection.prototype.getSenders) { + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + this._senders = this._senders || []; + return this._senders.slice(); // return a copy of the internal state. + }; + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { + var sender = origAddTrack.apply(this, arguments); + if (!sender) { + sender = shimSenderWithDtmf(this, track); + this._senders.push(sender); + } + return sender; + }; + + var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { + origRemoveTrack.apply(this, arguments); + var idx = this._senders.indexOf(sender); + if (idx !== -1) { + this._senders.splice(idx, 1); + } + }; + } + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + var _this2 = this; + + this._senders = this._senders || []; + origAddStream.apply(this, [stream]); + stream.getTracks().forEach(function (track) { + _this2._senders.push(shimSenderWithDtmf(_this2, track)); + }); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + var _this3 = this; + + this._senders = this._senders || []; + origRemoveStream.apply(this, [stream]); + + stream.getTracks().forEach(function (track) { + var sender = _this3._senders.find(function (s) { + return s.track === track; + }); + if (sender) { + // remove sender + _this3._senders.splice(_this3._senders.indexOf(sender), 1); + } + }); + }; + } else if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && 'getSenders' in window.RTCPeerConnection.prototype && 'createDTMFSender' in window.RTCPeerConnection.prototype && window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { + var origGetSenders = window.RTCPeerConnection.prototype.getSenders; + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + var _this4 = this; + + var senders = origGetSenders.apply(this, []); + senders.forEach(function (sender) { + return sender._pc = _this4; + }); + return senders; + }; + + Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { + get: function get() { + if (this._dtmf === undefined) { + if (this.track.kind === 'audio') { + this._dtmf = this._pc.createDTMFSender(this.track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + } + }); + } +} + +function shimGetStats(window) { + if (!window.RTCPeerConnection) { + return; + } + + var origGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function getStats() { + var _this5 = this; + + var _arguments = Array.prototype.slice.call(arguments), + selector = _arguments[0], + onSucc = _arguments[1], + onErr = _arguments[2]; + + // If selector is a function then we are in the old style stats so just + // pass back the original getStats format to avoid breaking old users. + + + if (arguments.length > 0 && typeof selector === 'function') { + return origGetStats.apply(this, arguments); + } + + // When spec-style getStats is supported, return those when called with + // either no arguments or the selector argument is null. + if (origGetStats.length === 0 && (arguments.length === 0 || typeof selector !== 'function')) { + return origGetStats.apply(this, []); + } + + var fixChromeStats_ = function fixChromeStats_(response) { + var standardReport = {}; + var reports = response.result(); + reports.forEach(function (report) { + var standardStats = { + id: report.id, + timestamp: report.timestamp, + type: { + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }[report.type] || report.type + }; + report.names().forEach(function (name) { + standardStats[name] = report.stat(name); + }); + standardReport[standardStats.id] = standardStats; + }); + + return standardReport; + }; + + // shim getStats with maplike support + var makeMapStats = function makeMapStats(stats) { + return new Map(Object.keys(stats).map(function (key) { + return [key, stats[key]]; + })); + }; + + if (arguments.length >= 2) { + var successCallbackWrapper_ = function successCallbackWrapper_(response) { + onSucc(makeMapStats(fixChromeStats_(response))); + }; + + return origGetStats.apply(this, [successCallbackWrapper_, selector]); + } + + // promise-support + return new Promise(function (resolve, reject) { + origGetStats.apply(_this5, [function (response) { + resolve(makeMapStats(fixChromeStats_(response))); + }, reject]); + }).then(onSucc, onErr); + }; +} + +function shimSenderReceiverGetStats(window) { + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender && window.RTCRtpReceiver)) { + return; + } + + // shim sender stats. + if (!('getStats' in window.RTCRtpSender.prototype)) { + var origGetSenders = window.RTCPeerConnection.prototype.getSenders; + if (origGetSenders) { + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + var _this6 = this; + + var senders = origGetSenders.apply(this, []); + senders.forEach(function (sender) { + return sender._pc = _this6; + }); + return senders; + }; + } + + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + if (origAddTrack) { + window.RTCPeerConnection.prototype.addTrack = function addTrack() { + var sender = origAddTrack.apply(this, arguments); + sender._pc = this; + return sender; + }; + } + window.RTCRtpSender.prototype.getStats = function getStats() { + var sender = this; + return this._pc.getStats().then(function (result) { + return ( + /* Note: this will include stats of all senders that + * send a track with the same id as sender.track as + * it is not possible to identify the RTCRtpSender. + */ + utils.filterStats(result, sender.track, true) + ); + }); + }; + } + + // shim receiver stats. + if (!('getStats' in window.RTCRtpReceiver.prototype)) { + var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; + if (origGetReceivers) { + window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { + var _this7 = this; + + var receivers = origGetReceivers.apply(this, []); + receivers.forEach(function (receiver) { + return receiver._pc = _this7; + }); + return receivers; + }; + } + utils.wrapPeerConnectionEvent(window, 'track', function (e) { + e.receiver._pc = e.srcElement; + return e; + }); + window.RTCRtpReceiver.prototype.getStats = function getStats() { + var receiver = this; + return this._pc.getStats().then(function (result) { + return utils.filterStats(result, receiver.track, false); + }); + }; + } + + if (!('getStats' in window.RTCRtpSender.prototype && 'getStats' in window.RTCRtpReceiver.prototype)) { + return; + } + + // shim RTCPeerConnection.getStats(track). + var origGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function getStats() { + if (arguments.length > 0 && arguments[0] instanceof window.MediaStreamTrack) { + var track = arguments[0]; + var sender = void 0; + var receiver = void 0; + var err = void 0; + this.getSenders().forEach(function (s) { + if (s.track === track) { + if (sender) { + err = true; + } else { + sender = s; + } + } + }); + this.getReceivers().forEach(function (r) { + if (r.track === track) { + if (receiver) { + err = true; + } else { + receiver = r; + } + } + return r.track === track; + }); + if (err || sender && receiver) { + return Promise.reject(new DOMException('There are more than one sender or receiver for the track.', 'InvalidAccessError')); + } else if (sender) { + return sender.getStats(); + } else if (receiver) { + return receiver.getStats(); + } + return Promise.reject(new DOMException('There is no sender or receiver for the track.', 'InvalidAccessError')); + } + return origGetStats.apply(this, arguments); + }; +} + +function shimAddTrackRemoveTrackWithNative(window) { + // shim addTrack/removeTrack with native variants in order to make + // the interactions with legacy getLocalStreams behave as in other browsers. + // Keeps a mapping stream.id => [stream, rtpsenders...] + window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { + var _this8 = this; + + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + return Object.keys(this._shimmedLocalStreams).map(function (streamId) { + return _this8._shimmedLocalStreams[streamId][0]; + }); + }; + + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { + if (!stream) { + return origAddTrack.apply(this, arguments); + } + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + + var sender = origAddTrack.apply(this, arguments); + if (!this._shimmedLocalStreams[stream.id]) { + this._shimmedLocalStreams[stream.id] = [stream, sender]; + } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { + this._shimmedLocalStreams[stream.id].push(sender); + } + return sender; + }; + + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + var _this9 = this; + + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + + stream.getTracks().forEach(function (track) { + var alreadyExists = _this9.getSenders().find(function (s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + }); + var existingSenders = this.getSenders(); + origAddStream.apply(this, arguments); + var newSenders = this.getSenders().filter(function (newSender) { + return existingSenders.indexOf(newSender) === -1; + }); + this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + delete this._shimmedLocalStreams[stream.id]; + return origRemoveStream.apply(this, arguments); + }; + + var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { + var _this10 = this; + + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + if (sender) { + Object.keys(this._shimmedLocalStreams).forEach(function (streamId) { + var idx = _this10._shimmedLocalStreams[streamId].indexOf(sender); + if (idx !== -1) { + _this10._shimmedLocalStreams[streamId].splice(idx, 1); + } + if (_this10._shimmedLocalStreams[streamId].length === 1) { + delete _this10._shimmedLocalStreams[streamId]; + } + }); + } + return origRemoveTrack.apply(this, arguments); + }; +} + +function shimAddTrackRemoveTrack(window) { + if (!window.RTCPeerConnection) { + return; + } + var browserDetails = utils.detectBrowser(window); + // shim addTrack and removeTrack. + if (window.RTCPeerConnection.prototype.addTrack && browserDetails.version >= 65) { + return shimAddTrackRemoveTrackWithNative(window); + } + + // also shim pc.getLocalStreams when addTrack is shimmed + // to return the original streams. + var origGetLocalStreams = window.RTCPeerConnection.prototype.getLocalStreams; + window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { + var _this11 = this; + + var nativeStreams = origGetLocalStreams.apply(this); + this._reverseStreams = this._reverseStreams || {}; + return nativeStreams.map(function (stream) { + return _this11._reverseStreams[stream.id]; + }); + }; + + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + var _this12 = this; + + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + + stream.getTracks().forEach(function (track) { + var alreadyExists = _this12.getSenders().find(function (s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + }); + // Add identity mapping for consistency with addTrack. + // Unless this is being used with a stream from addTrack. + if (!this._reverseStreams[stream.id]) { + var newStream = new window.MediaStream(stream.getTracks()); + this._streams[stream.id] = newStream; + this._reverseStreams[newStream.id] = stream; + stream = newStream; + } + origAddStream.apply(this, [stream]); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + + origRemoveStream.apply(this, [this._streams[stream.id] || stream]); + delete this._reverseStreams[this._streams[stream.id] ? this._streams[stream.id].id : stream.id]; + delete this._streams[stream.id]; + }; + + window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { + var _this13 = this; + + if (this.signalingState === 'closed') { + throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); + } + var streams = [].slice.call(arguments, 1); + if (streams.length !== 1 || !streams[0].getTracks().find(function (t) { + return t === track; + })) { + // this is not fully correct but all we can manage without + // [[associated MediaStreams]] internal slot. + throw new DOMException('The adapter.js addTrack polyfill only supports a single ' + ' stream which is associated with the specified track.', 'NotSupportedError'); + } + + var alreadyExists = this.getSenders().find(function (s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + var oldStream = this._streams[stream.id]; + if (oldStream) { + // this is using odd Chrome behaviour, use with caution: + // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 + // Note: we rely on the high-level addTrack/dtmf shim to + // create the sender with a dtmf sender. + oldStream.addTrack(track); + + // Trigger ONN async. + Promise.resolve().then(function () { + _this13.dispatchEvent(new Event('negotiationneeded')); + }); + } else { + var newStream = new window.MediaStream([track]); + this._streams[stream.id] = newStream; + this._reverseStreams[newStream.id] = stream; + this.addStream(newStream); + } + return this.getSenders().find(function (s) { + return s.track === track; + }); + }; + + // replace the internal stream id with the external one and + // vice versa. + function replaceInternalStreamId(pc, description) { + var sdp = description.sdp; + Object.keys(pc._reverseStreams || []).forEach(function (internalId) { + var externalStream = pc._reverseStreams[internalId]; + var internalStream = pc._streams[externalStream.id]; + sdp = sdp.replace(new RegExp(internalStream.id, 'g'), externalStream.id); + }); + return new RTCSessionDescription({ + type: description.type, + sdp: sdp + }); + } + function replaceExternalStreamId(pc, description) { + var sdp = description.sdp; + Object.keys(pc._reverseStreams || []).forEach(function (internalId) { + var externalStream = pc._reverseStreams[internalId]; + var internalStream = pc._streams[externalStream.id]; + sdp = sdp.replace(new RegExp(externalStream.id, 'g'), internalStream.id); + }); + return new RTCSessionDescription({ + type: description.type, + sdp: sdp + }); + } + ['createOffer', 'createAnswer'].forEach(function (method) { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + var methodObj = _defineProperty({}, method, function () { + var _this14 = this; + + var args = arguments; + var isLegacyCall = arguments.length && typeof arguments[0] === 'function'; + if (isLegacyCall) { + return nativeMethod.apply(this, [function (description) { + var desc = replaceInternalStreamId(_this14, description); + args[0].apply(null, [desc]); + }, function (err) { + if (args[1]) { + args[1].apply(null, err); + } + }, arguments[2]]); + } + return nativeMethod.apply(this, arguments).then(function (description) { + return replaceInternalStreamId(_this14, description); + }); + }); + window.RTCPeerConnection.prototype[method] = methodObj[method]; + }); + + var origSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; + window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() { + if (!arguments.length || !arguments[0].type) { + return origSetLocalDescription.apply(this, arguments); + } + arguments[0] = replaceExternalStreamId(this, arguments[0]); + return origSetLocalDescription.apply(this, arguments); + }; + + // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier + + var origLocalDescription = Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype, 'localDescription'); + Object.defineProperty(window.RTCPeerConnection.prototype, 'localDescription', { + get: function get() { + var description = origLocalDescription.get.apply(this); + if (description.type === '') { + return description; + } + return replaceInternalStreamId(this, description); + } + }); + + window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { + var _this15 = this; + + if (this.signalingState === 'closed') { + throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); + } + // We can not yet check for sender instanceof RTCRtpSender + // since we shim RTPSender. So we check if sender._pc is set. + if (!sender._pc) { + throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.', 'TypeError'); + } + var isLocal = sender._pc === this; + if (!isLocal) { + throw new DOMException('Sender was not created by this connection.', 'InvalidAccessError'); + } + + // Search for the native stream the senders track belongs to. + this._streams = this._streams || {}; + var stream = void 0; + Object.keys(this._streams).forEach(function (streamid) { + var hasTrack = _this15._streams[streamid].getTracks().find(function (track) { + return sender.track === track; + }); + if (hasTrack) { + stream = _this15._streams[streamid]; + } + }); + + if (stream) { + if (stream.getTracks().length === 1) { + // if this is the last track of the stream, remove the stream. This + // takes care of any shimmed _senders. + this.removeStream(this._reverseStreams[stream.id]); + } else { + // relying on the same odd chrome behaviour as above. + stream.removeTrack(sender.track); + } + this.dispatchEvent(new Event('negotiationneeded')); + } + }; +} + +function shimPeerConnection(window) { + var browserDetails = utils.detectBrowser(window); + + if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { + // very basic support for old versions. + window.RTCPeerConnection = window.webkitRTCPeerConnection; + } + if (!window.RTCPeerConnection) { + return; + } + + // shim implicit creation of RTCSessionDescription/RTCIceCandidate + if (browserDetails.version < 53) { + ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + var methodObj = _defineProperty({}, method, function () { + arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); + return nativeMethod.apply(this, arguments); + }); + window.RTCPeerConnection.prototype[method] = methodObj[method]; + }); + } + + // support for addIceCandidate(null or undefined) + var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; + window.RTCPeerConnection.prototype.addIceCandidate = function addIceCandidate() { + if (!arguments[0]) { + if (arguments[1]) { + arguments[1].apply(null); + } + return Promise.resolve(); + } + // Firefox 68+ emits and processes {candidate: "", ...}, ignore + // in older versions. Native support planned for Chrome M77. + if (browserDetails.version < 78 && arguments[0] && arguments[0].candidate === '') { + return Promise.resolve(); + } + return nativeAddIceCandidate.apply(this, arguments); + }; +} + +function fixNegotiationNeeded(window) { + utils.wrapPeerConnectionEvent(window, 'negotiationneeded', function (e) { + var pc = e.target; + if (pc.signalingState !== 'stable') { + return; + } + return e; + }); +} + +},{"../utils.js":15,"./getdisplaymedia":4,"./getusermedia":5}],4:[function(require,module,exports){ +/* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = shimGetDisplayMedia; +function shimGetDisplayMedia(window, getSourceId) { + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + // getSourceId is a function that returns a promise resolving with + // the sourceId of the screen/window/tab to be shared. + if (typeof getSourceId !== 'function') { + console.error('shimGetDisplayMedia: getSourceId argument is not ' + 'a function'); + return; + } + window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { + return getSourceId(constraints).then(function (sourceId) { + var widthSpecified = constraints.video && constraints.video.width; + var heightSpecified = constraints.video && constraints.video.height; + var frameRateSpecified = constraints.video && constraints.video.frameRate; + constraints.video = { + mandatory: { + chromeMediaSource: 'desktop', + chromeMediaSourceId: sourceId, + maxFrameRate: frameRateSpecified || 3 + } + }; + if (widthSpecified) { + constraints.video.mandatory.maxWidth = widthSpecified; + } + if (heightSpecified) { + constraints.video.mandatory.maxHeight = heightSpecified; + } + return window.navigator.mediaDevices.getUserMedia(constraints); + }); + }; +} + +},{}],5:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimGetUserMedia = shimGetUserMedia; + +var _utils = require('../utils.js'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var logging = utils.log; + +function shimGetUserMedia(window) { + var navigator = window && window.navigator; + + if (!navigator.mediaDevices) { + return; + } + + var browserDetails = utils.detectBrowser(window); + + var constraintsToChrome_ = function constraintsToChrome_(c) { + if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) !== 'object' || c.mandatory || c.optional) { + return c; + } + var cc = {}; + Object.keys(c).forEach(function (key) { + if (key === 'require' || key === 'advanced' || key === 'mediaSource') { + return; + } + var r = _typeof(c[key]) === 'object' ? c[key] : { ideal: c[key] }; + if (r.exact !== undefined && typeof r.exact === 'number') { + r.min = r.max = r.exact; + } + var oldname_ = function oldname_(prefix, name) { + if (prefix) { + return prefix + name.charAt(0).toUpperCase() + name.slice(1); + } + return name === 'deviceId' ? 'sourceId' : name; + }; + if (r.ideal !== undefined) { + cc.optional = cc.optional || []; + var oc = {}; + if (typeof r.ideal === 'number') { + oc[oldname_('min', key)] = r.ideal; + cc.optional.push(oc); + oc = {}; + oc[oldname_('max', key)] = r.ideal; + cc.optional.push(oc); + } else { + oc[oldname_('', key)] = r.ideal; + cc.optional.push(oc); + } + } + if (r.exact !== undefined && typeof r.exact !== 'number') { + cc.mandatory = cc.mandatory || {}; + cc.mandatory[oldname_('', key)] = r.exact; + } else { + ['min', 'max'].forEach(function (mix) { + if (r[mix] !== undefined) { + cc.mandatory = cc.mandatory || {}; + cc.mandatory[oldname_(mix, key)] = r[mix]; + } + }); + } + }); + if (c.advanced) { + cc.optional = (cc.optional || []).concat(c.advanced); + } + return cc; + }; + + var shimConstraints_ = function shimConstraints_(constraints, func) { + if (browserDetails.version >= 61) { + return func(constraints); + } + constraints = JSON.parse(JSON.stringify(constraints)); + if (constraints && _typeof(constraints.audio) === 'object') { + var remap = function remap(obj, a, b) { + if (a in obj && !(b in obj)) { + obj[b] = obj[a]; + delete obj[a]; + } + }; + constraints = JSON.parse(JSON.stringify(constraints)); + remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); + remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); + constraints.audio = constraintsToChrome_(constraints.audio); + } + if (constraints && _typeof(constraints.video) === 'object') { + // Shim facingMode for mobile & surface pro. + var face = constraints.video.facingMode; + face = face && ((typeof face === 'undefined' ? 'undefined' : _typeof(face)) === 'object' ? face : { ideal: face }); + var getSupportedFacingModeLies = browserDetails.version < 66; + + if (face && (face.exact === 'user' || face.exact === 'environment' || face.ideal === 'user' || face.ideal === 'environment') && !(navigator.mediaDevices.getSupportedConstraints && navigator.mediaDevices.getSupportedConstraints().facingMode && !getSupportedFacingModeLies)) { + delete constraints.video.facingMode; + var matches = void 0; + if (face.exact === 'environment' || face.ideal === 'environment') { + matches = ['back', 'rear']; + } else if (face.exact === 'user' || face.ideal === 'user') { + matches = ['front']; + } + if (matches) { + // Look for matches in label, or use last cam for back (typical). + return navigator.mediaDevices.enumerateDevices().then(function (devices) { + devices = devices.filter(function (d) { + return d.kind === 'videoinput'; + }); + var dev = devices.find(function (d) { + return matches.some(function (match) { + return d.label.toLowerCase().includes(match); + }); + }); + if (!dev && devices.length && matches.includes('back')) { + dev = devices[devices.length - 1]; // more likely the back cam + } + if (dev) { + constraints.video.deviceId = face.exact ? { exact: dev.deviceId } : { ideal: dev.deviceId }; + } + constraints.video = constraintsToChrome_(constraints.video); + logging('chrome: ' + JSON.stringify(constraints)); + return func(constraints); + }); + } + } + constraints.video = constraintsToChrome_(constraints.video); + } + logging('chrome: ' + JSON.stringify(constraints)); + return func(constraints); + }; + + var shimError_ = function shimError_(e) { + if (browserDetails.version >= 64) { + return e; + } + return { + name: { + PermissionDeniedError: 'NotAllowedError', + PermissionDismissedError: 'NotAllowedError', + InvalidStateError: 'NotAllowedError', + DevicesNotFoundError: 'NotFoundError', + ConstraintNotSatisfiedError: 'OverconstrainedError', + TrackStartError: 'NotReadableError', + MediaDeviceFailedDueToShutdown: 'NotAllowedError', + MediaDeviceKillSwitchOn: 'NotAllowedError', + TabCaptureError: 'AbortError', + ScreenCaptureError: 'AbortError', + DeviceCaptureError: 'AbortError' + }[e.name] || e.name, + message: e.message, + constraint: e.constraint || e.constraintName, + toString: function toString() { + return this.name + (this.message && ': ') + this.message; + } + }; + }; + + var getUserMedia_ = function getUserMedia_(constraints, onSuccess, onError) { + shimConstraints_(constraints, function (c) { + navigator.webkitGetUserMedia(c, onSuccess, function (e) { + if (onError) { + onError(shimError_(e)); + } + }); + }); + }; + navigator.getUserMedia = getUserMedia_.bind(navigator); + + // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia + // function which returns a Promise, it does not accept spec-style + // constraints. + if (navigator.mediaDevices.getUserMedia) { + var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (cs) { + return shimConstraints_(cs, function (c) { + return origGetUserMedia(c).then(function (stream) { + if (c.audio && !stream.getAudioTracks().length || c.video && !stream.getVideoTracks().length) { + stream.getTracks().forEach(function (track) { + track.stop(); + }); + throw new DOMException('', 'NotFoundError'); + } + return stream; + }, function (e) { + return Promise.reject(shimError_(e)); + }); + }); + }; + } +} + +},{"../utils.js":15}],6:[function(require,module,exports){ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimRTCIceCandidate = shimRTCIceCandidate; +exports.shimMaxMessageSize = shimMaxMessageSize; +exports.shimSendThrowTypeError = shimSendThrowTypeError; +exports.shimConnectionState = shimConnectionState; +exports.removeAllowExtmapMixed = removeAllowExtmapMixed; + +var _sdp = require('sdp'); + +var _sdp2 = _interopRequireDefault(_sdp); + +var _utils = require('./utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function shimRTCIceCandidate(window) { + // foundation is arbitrarily chosen as an indicator for full support for + // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface + if (!window.RTCIceCandidate || window.RTCIceCandidate && 'foundation' in window.RTCIceCandidate.prototype) { + return; + } + + var NativeRTCIceCandidate = window.RTCIceCandidate; + window.RTCIceCandidate = function RTCIceCandidate(args) { + // Remove the a= which shouldn't be part of the candidate string. + if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) === 'object' && args.candidate && args.candidate.indexOf('a=') === 0) { + args = JSON.parse(JSON.stringify(args)); + args.candidate = args.candidate.substr(2); + } + + if (args.candidate && args.candidate.length) { + // Augment the native candidate with the parsed fields. + var nativeCandidate = new NativeRTCIceCandidate(args); + var parsedCandidate = _sdp2.default.parseCandidate(args.candidate); + var augmentedCandidate = Object.assign(nativeCandidate, parsedCandidate); + + // Add a serializer that does not serialize the extra attributes. + augmentedCandidate.toJSON = function toJSON() { + return { + candidate: augmentedCandidate.candidate, + sdpMid: augmentedCandidate.sdpMid, + sdpMLineIndex: augmentedCandidate.sdpMLineIndex, + usernameFragment: augmentedCandidate.usernameFragment + }; + }; + return augmentedCandidate; + } + return new NativeRTCIceCandidate(args); + }; + window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype; + + // Hook up the augmented candidate in onicecandidate and + // addEventListener('icecandidate', ...) + utils.wrapPeerConnectionEvent(window, 'icecandidate', function (e) { + if (e.candidate) { + Object.defineProperty(e, 'candidate', { + value: new window.RTCIceCandidate(e.candidate), + writable: 'false' + }); + } + return e; + }); +} + +function shimMaxMessageSize(window) { + if (!window.RTCPeerConnection) { + return; + } + var browserDetails = utils.detectBrowser(window); + + if (!('sctp' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { + get: function get() { + return typeof this._sctp === 'undefined' ? null : this._sctp; + } + }); + } + + var sctpInDescription = function sctpInDescription(description) { + if (!description || !description.sdp) { + return false; + } + var sections = _sdp2.default.splitSections(description.sdp); + sections.shift(); + return sections.some(function (mediaSection) { + var mLine = _sdp2.default.parseMLine(mediaSection); + return mLine && mLine.kind === 'application' && mLine.protocol.indexOf('SCTP') !== -1; + }); + }; + + var getRemoteFirefoxVersion = function getRemoteFirefoxVersion(description) { + // TODO: Is there a better solution for detecting Firefox? + var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); + if (match === null || match.length < 2) { + return -1; + } + var version = parseInt(match[1], 10); + // Test for NaN (yes, this is ugly) + return version !== version ? -1 : version; + }; + + var getCanSendMaxMessageSize = function getCanSendMaxMessageSize(remoteIsFirefox) { + // Every implementation we know can send at least 64 KiB. + // Note: Although Chrome is technically able to send up to 256 KiB, the + // data does not reach the other peer reliably. + // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 + var canSendMaxMessageSize = 65536; + if (browserDetails.browser === 'firefox') { + if (browserDetails.version < 57) { + if (remoteIsFirefox === -1) { + // FF < 57 will send in 16 KiB chunks using the deprecated PPID + // fragmentation. + canSendMaxMessageSize = 16384; + } else { + // However, other FF (and RAWRTC) can reassemble PPID-fragmented + // messages. Thus, supporting ~2 GiB when sending. + canSendMaxMessageSize = 2147483637; + } + } else if (browserDetails.version < 60) { + // Currently, all FF >= 57 will reset the remote maximum message size + // to the default value when a data channel is created at a later + // stage. :( + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 + canSendMaxMessageSize = browserDetails.version === 57 ? 65535 : 65536; + } else { + // FF >= 60 supports sending ~2 GiB + canSendMaxMessageSize = 2147483637; + } + } + return canSendMaxMessageSize; + }; + + var getMaxMessageSize = function getMaxMessageSize(description, remoteIsFirefox) { + // Note: 65536 bytes is the default value from the SDP spec. Also, + // every implementation we know supports receiving 65536 bytes. + var maxMessageSize = 65536; + + // FF 57 has a slightly incorrect default remote max message size, so + // we need to adjust it here to avoid a failure when sending. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 + if (browserDetails.browser === 'firefox' && browserDetails.version === 57) { + maxMessageSize = 65535; + } + + var match = _sdp2.default.matchPrefix(description.sdp, 'a=max-message-size:'); + if (match.length > 0) { + maxMessageSize = parseInt(match[0].substr(19), 10); + } else if (browserDetails.browser === 'firefox' && remoteIsFirefox !== -1) { + // If the maximum message size is not present in the remote SDP and + // both local and remote are Firefox, the remote peer can receive + // ~2 GiB. + maxMessageSize = 2147483637; + } + return maxMessageSize; + }; + + var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { + this._sctp = null; + // Chrome decided to not expose .sctp in plan-b mode. + // As usual, adapter.js has to do an 'ugly worakaround' + // to cover up the mess. + if (browserDetails.browser === 'chrome' && browserDetails.version >= 76) { + var _getConfiguration = this.getConfiguration(), + sdpSemantics = _getConfiguration.sdpSemantics; + + if (sdpSemantics === 'plan-b') { + Object.defineProperty(this, 'sctp', { + get: function get() { + return typeof this._sctp === 'undefined' ? null : this._sctp; + }, + + enumerable: true, + configurable: true + }); + } + } + + if (sctpInDescription(arguments[0])) { + // Check if the remote is FF. + var isFirefox = getRemoteFirefoxVersion(arguments[0]); + + // Get the maximum message size the local peer is capable of sending + var canSendMMS = getCanSendMaxMessageSize(isFirefox); + + // Get the maximum message size of the remote peer. + var remoteMMS = getMaxMessageSize(arguments[0], isFirefox); + + // Determine final maximum message size + var maxMessageSize = void 0; + if (canSendMMS === 0 && remoteMMS === 0) { + maxMessageSize = Number.POSITIVE_INFINITY; + } else if (canSendMMS === 0 || remoteMMS === 0) { + maxMessageSize = Math.max(canSendMMS, remoteMMS); + } else { + maxMessageSize = Math.min(canSendMMS, remoteMMS); + } + + // Create a dummy RTCSctpTransport object and the 'maxMessageSize' + // attribute. + var sctp = {}; + Object.defineProperty(sctp, 'maxMessageSize', { + get: function get() { + return maxMessageSize; + } + }); + this._sctp = sctp; + } + + return origSetRemoteDescription.apply(this, arguments); + }; +} + +function shimSendThrowTypeError(window) { + if (!(window.RTCPeerConnection && 'createDataChannel' in window.RTCPeerConnection.prototype)) { + return; + } + + // Note: Although Firefox >= 57 has a native implementation, the maximum + // message size can be reset for all data channels at a later stage. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 + + function wrapDcSend(dc, pc) { + var origDataChannelSend = dc.send; + dc.send = function send() { + var data = arguments[0]; + var length = data.length || data.size || data.byteLength; + if (dc.readyState === 'open' && pc.sctp && length > pc.sctp.maxMessageSize) { + throw new TypeError('Message too large (can send a maximum of ' + pc.sctp.maxMessageSize + ' bytes)'); + } + return origDataChannelSend.apply(dc, arguments); + }; + } + var origCreateDataChannel = window.RTCPeerConnection.prototype.createDataChannel; + window.RTCPeerConnection.prototype.createDataChannel = function createDataChannel() { + var dataChannel = origCreateDataChannel.apply(this, arguments); + wrapDcSend(dataChannel, this); + return dataChannel; + }; + utils.wrapPeerConnectionEvent(window, 'datachannel', function (e) { + wrapDcSend(e.channel, e.target); + return e; + }); +} + +/* shims RTCConnectionState by pretending it is the same as iceConnectionState. + * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12 + * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect + * since DTLS failures would be hidden. See + * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827 + * for the Firefox tracking bug. + */ +function shimConnectionState(window) { + if (!window.RTCPeerConnection || 'connectionState' in window.RTCPeerConnection.prototype) { + return; + } + var proto = window.RTCPeerConnection.prototype; + Object.defineProperty(proto, 'connectionState', { + get: function get() { + return { + completed: 'connected', + checking: 'connecting' + }[this.iceConnectionState] || this.iceConnectionState; + }, + + enumerable: true, + configurable: true + }); + Object.defineProperty(proto, 'onconnectionstatechange', { + get: function get() { + return this._onconnectionstatechange || null; + }, + set: function set(cb) { + if (this._onconnectionstatechange) { + this.removeEventListener('connectionstatechange', this._onconnectionstatechange); + delete this._onconnectionstatechange; + } + if (cb) { + this.addEventListener('connectionstatechange', this._onconnectionstatechange = cb); + } + }, + + enumerable: true, + configurable: true + }); + + ['setLocalDescription', 'setRemoteDescription'].forEach(function (method) { + var origMethod = proto[method]; + proto[method] = function () { + if (!this._connectionstatechangepoly) { + this._connectionstatechangepoly = function (e) { + var pc = e.target; + if (pc._lastConnectionState !== pc.connectionState) { + pc._lastConnectionState = pc.connectionState; + var newEvent = new Event('connectionstatechange', e); + pc.dispatchEvent(newEvent); + } + return e; + }; + this.addEventListener('iceconnectionstatechange', this._connectionstatechangepoly); + } + return origMethod.apply(this, arguments); + }; + }); +} + +function removeAllowExtmapMixed(window) { + /* remove a=extmap-allow-mixed for Chrome < M71 */ + if (!window.RTCPeerConnection) { + return; + } + var browserDetails = utils.detectBrowser(window); + if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) { + return; + } + var nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription(desc) { + if (desc && desc.sdp && desc.sdp.indexOf('\na=extmap-allow-mixed') !== -1) { + desc.sdp = desc.sdp.split('\n').filter(function (line) { + return line.trim() !== 'a=extmap-allow-mixed'; + }).join('\n'); + } + return nativeSRD.apply(this, arguments); + }; +} + +},{"./utils":15,"sdp":17}],7:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; + +var _getusermedia = require('./getusermedia'); + +Object.defineProperty(exports, 'shimGetUserMedia', { + enumerable: true, + get: function get() { + return _getusermedia.shimGetUserMedia; + } +}); + +var _getdisplaymedia = require('./getdisplaymedia'); + +Object.defineProperty(exports, 'shimGetDisplayMedia', { + enumerable: true, + get: function get() { + return _getdisplaymedia.shimGetDisplayMedia; + } +}); +exports.shimPeerConnection = shimPeerConnection; +exports.shimReplaceTrack = shimReplaceTrack; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +var _filtericeservers = require('./filtericeservers'); + +var _rtcpeerconnectionShim = require('rtcpeerconnection-shim'); + +var _rtcpeerconnectionShim2 = _interopRequireDefault(_rtcpeerconnectionShim); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function shimPeerConnection(window) { + var browserDetails = utils.detectBrowser(window); + + if (window.RTCIceGatherer) { + if (!window.RTCIceCandidate) { + window.RTCIceCandidate = function RTCIceCandidate(args) { + return args; + }; + } + if (!window.RTCSessionDescription) { + window.RTCSessionDescription = function RTCSessionDescription(args) { + return args; + }; + } + // this adds an additional event listener to MediaStrackTrack that signals + // when a tracks enabled property was changed. Workaround for a bug in + // addStream, see below. No longer required in 15025+ + if (browserDetails.version < 15025) { + var origMSTEnabled = Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype, 'enabled'); + Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { + set: function set(value) { + origMSTEnabled.set.call(this, value); + var ev = new Event('enabled'); + ev.enabled = value; + this.dispatchEvent(ev); + } + }); + } + } + + // ORTC defines the DTMF sender a bit different. + // https://github.com/w3c/ortc/issues/714 + if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { + Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { + get: function get() { + if (this._dtmf === undefined) { + if (this.track.kind === 'audio') { + this._dtmf = new window.RTCDtmfSender(this); + } else if (this.track.kind === 'video') { + this._dtmf = null; + } + } + return this._dtmf; + } + }); + } + // Edge currently only implements the RTCDtmfSender, not the + // RTCDTMFSender alias. See http://draft.ortc.org/#rtcdtmfsender2* + if (window.RTCDtmfSender && !window.RTCDTMFSender) { + window.RTCDTMFSender = window.RTCDtmfSender; + } + + var RTCPeerConnectionShim = (0, _rtcpeerconnectionShim2.default)(window, browserDetails.version); + window.RTCPeerConnection = function RTCPeerConnection(config) { + if (config && config.iceServers) { + config.iceServers = (0, _filtericeservers.filterIceServers)(config.iceServers, browserDetails.version); + utils.log('ICE servers after filtering:', config.iceServers); + } + return new RTCPeerConnectionShim(config); + }; + window.RTCPeerConnection.prototype = RTCPeerConnectionShim.prototype; +} + +function shimReplaceTrack(window) { + // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 + if (window.RTCRtpSender && !('replaceTrack' in window.RTCRtpSender.prototype)) { + window.RTCRtpSender.prototype.replaceTrack = window.RTCRtpSender.prototype.setTrack; + } +} + +},{"../utils":15,"./filtericeservers":8,"./getdisplaymedia":9,"./getusermedia":10,"rtcpeerconnection-shim":16}],8:[function(require,module,exports){ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.filterIceServers = filterIceServers; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +// Edge does not like +// 1) stun: filtered after 14393 unless ?transport=udp is present +// 2) turn: that does not have all of turn:host:port?transport=udp +// 3) turn: with ipv6 addresses +// 4) turn: occurring muliple times +function filterIceServers(iceServers, edgeVersion) { + var hasTurn = false; + iceServers = JSON.parse(JSON.stringify(iceServers)); + return iceServers.filter(function (server) { + if (server && (server.urls || server.url)) { + var urls = server.urls || server.url; + if (server.url && !server.urls) { + utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); + } + var isString = typeof urls === 'string'; + if (isString) { + urls = [urls]; + } + urls = urls.filter(function (url) { + // filter STUN unconditionally. + if (url.indexOf('stun:') === 0) { + return false; + } + + var validTurn = url.startsWith('turn') && !url.startsWith('turn:[') && url.includes('transport=udp'); + if (validTurn && !hasTurn) { + hasTurn = true; + return true; + } + return validTurn && !hasTurn; + }); + + delete server.url; + server.urls = isString ? urls[0] : urls; + return !!urls.length; + } + }); +} + +},{"../utils":15}],9:[function(require,module,exports){ +/* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = shimGetDisplayMedia; +function shimGetDisplayMedia(window) { + if (!('getDisplayMedia' in window.navigator)) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + window.navigator.mediaDevices.getDisplayMedia = window.navigator.getDisplayMedia.bind(window.navigator); +} + +},{}],10:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetUserMedia = shimGetUserMedia; +function shimGetUserMedia(window) { + var navigator = window && window.navigator; + + var shimError_ = function shimError_(e) { + return { + name: { PermissionDeniedError: 'NotAllowedError' }[e.name] || e.name, + message: e.message, + constraint: e.constraint, + toString: function toString() { + return this.name; + } + }; + }; + + // getUserMedia error shim. + var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (c) { + return origGetUserMedia(c).catch(function (e) { + return Promise.reject(shimError_(e)); + }); + }; +} + +},{}],11:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _getusermedia = require('./getusermedia'); + +Object.defineProperty(exports, 'shimGetUserMedia', { + enumerable: true, + get: function get() { + return _getusermedia.shimGetUserMedia; + } +}); + +var _getdisplaymedia = require('./getdisplaymedia'); + +Object.defineProperty(exports, 'shimGetDisplayMedia', { + enumerable: true, + get: function get() { + return _getdisplaymedia.shimGetDisplayMedia; + } +}); +exports.shimOnTrack = shimOnTrack; +exports.shimPeerConnection = shimPeerConnection; +exports.shimSenderGetStats = shimSenderGetStats; +exports.shimReceiverGetStats = shimReceiverGetStats; +exports.shimRemoveStream = shimRemoveStream; +exports.shimRTCDataChannel = shimRTCDataChannel; +exports.shimAddTransceiver = shimAddTransceiver; +exports.shimCreateOffer = shimCreateOffer; +exports.shimCreateAnswer = shimCreateAnswer; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function shimOnTrack(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { + Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { + get: function get() { + return { receiver: this.receiver }; + } + }); + } +} + +function shimPeerConnection(window) { + var browserDetails = utils.detectBrowser(window); + + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) { + return; // probably media.peerconnection.enabled=false in about:config + } + if (!window.RTCPeerConnection && window.mozRTCPeerConnection) { + // very basic support for old versions. + window.RTCPeerConnection = window.mozRTCPeerConnection; + } + + if (browserDetails.version < 53) { + // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. + ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + var methodObj = _defineProperty({}, method, function () { + arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); + return nativeMethod.apply(this, arguments); + }); + window.RTCPeerConnection.prototype[method] = methodObj[method]; + }); + } + + // support for addIceCandidate(null or undefined) + // as well as ignoring {sdpMid, candidate: ""} + if (browserDetails.version < 68) { + var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; + window.RTCPeerConnection.prototype.addIceCandidate = function addIceCandidate() { + if (!arguments[0]) { + if (arguments[1]) { + arguments[1].apply(null); + } + return Promise.resolve(); + } + // Firefox 68+ emits and processes {candidate: "", ...}, ignore + // in older versions. + if (arguments[0] && arguments[0].candidate === '') { + return Promise.resolve(); + } + return nativeAddIceCandidate.apply(this, arguments); + }; + } + + var modernStatsTypes = { + inboundrtp: 'inbound-rtp', + outboundrtp: 'outbound-rtp', + candidatepair: 'candidate-pair', + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }; + + var nativeGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function getStats() { + var _arguments = Array.prototype.slice.call(arguments), + selector = _arguments[0], + onSucc = _arguments[1], + onErr = _arguments[2]; + + return nativeGetStats.apply(this, [selector || null]).then(function (stats) { + if (browserDetails.version < 53 && !onSucc) { + // Shim only promise getStats with spec-hyphens in type names + // Leave callback version alone; misc old uses of forEach before Map + try { + stats.forEach(function (stat) { + stat.type = modernStatsTypes[stat.type] || stat.type; + }); + } catch (e) { + if (e.name !== 'TypeError') { + throw e; + } + // Avoid TypeError: "type" is read-only, in old versions. 34-43ish + stats.forEach(function (stat, i) { + stats.set(i, Object.assign({}, stat, { + type: modernStatsTypes[stat.type] || stat.type + })); + }); + } + } + return stats; + }).then(onSucc, onErr); + }; +} + +function shimSenderGetStats(window) { + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { + return; + } + if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) { + return; + } + var origGetSenders = window.RTCPeerConnection.prototype.getSenders; + if (origGetSenders) { + window.RTCPeerConnection.prototype.getSenders = function getSenders() { + var _this = this; + + var senders = origGetSenders.apply(this, []); + senders.forEach(function (sender) { + return sender._pc = _this; + }); + return senders; + }; + } + + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + if (origAddTrack) { + window.RTCPeerConnection.prototype.addTrack = function addTrack() { + var sender = origAddTrack.apply(this, arguments); + sender._pc = this; + return sender; + }; + } + window.RTCRtpSender.prototype.getStats = function getStats() { + return this.track ? this._pc.getStats(this.track) : Promise.resolve(new Map()); + }; +} + +function shimReceiverGetStats(window) { + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { + return; + } + if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) { + return; + } + var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; + if (origGetReceivers) { + window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { + var _this2 = this; + + var receivers = origGetReceivers.apply(this, []); + receivers.forEach(function (receiver) { + return receiver._pc = _this2; + }); + return receivers; + }; + } + utils.wrapPeerConnectionEvent(window, 'track', function (e) { + e.receiver._pc = e.srcElement; + return e; + }); + window.RTCRtpReceiver.prototype.getStats = function getStats() { + return this._pc.getStats(this.track); + }; +} + +function shimRemoveStream(window) { + if (!window.RTCPeerConnection || 'removeStream' in window.RTCPeerConnection.prototype) { + return; + } + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + var _this3 = this; + + utils.deprecated('removeStream', 'removeTrack'); + this.getSenders().forEach(function (sender) { + if (sender.track && stream.getTracks().includes(sender.track)) { + _this3.removeTrack(sender); + } + }); + }; +} + +function shimRTCDataChannel(window) { + // rename DataChannel to RTCDataChannel (native fix in FF60): + // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851 + if (window.DataChannel && !window.RTCDataChannel) { + window.RTCDataChannel = window.DataChannel; + } +} + +function shimAddTransceiver(window) { + // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 + // Firefox ignores the init sendEncodings options passed to addTransceiver + // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { + return; + } + var origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver; + if (origAddTransceiver) { + window.RTCPeerConnection.prototype.addTransceiver = function addTransceiver() { + this.setParametersPromises = []; + var initParameters = arguments[1]; + var shouldPerformCheck = initParameters && 'sendEncodings' in initParameters; + if (shouldPerformCheck) { + // If sendEncodings params are provided, validate grammar + initParameters.sendEncodings.forEach(function (encodingParam) { + if ('rid' in encodingParam) { + var ridRegex = /^[a-z0-9]{0,16}$/i; + if (!ridRegex.test(encodingParam.rid)) { + throw new TypeError('Invalid RID value provided.'); + } + } + if ('scaleResolutionDownBy' in encodingParam) { + if (!(parseFloat(encodingParam.scaleResolutionDownBy) >= 1.0)) { + throw new RangeError('scale_resolution_down_by must be >= 1.0'); + } + } + if ('maxFramerate' in encodingParam) { + if (!(parseFloat(encodingParam.maxFramerate) >= 0)) { + throw new RangeError('max_framerate must be >= 0.0'); + } + } + }); + } + var transceiver = origAddTransceiver.apply(this, arguments); + if (shouldPerformCheck) { + // Check if the init options were applied. If not we do this in an + // asynchronous way and save the promise reference in a global object. + // This is an ugly hack, but at the same time is way more robust than + // checking the sender parameters before and after the createOffer + // Also note that after the createoffer we are not 100% sure that + // the params were asynchronously applied so we might miss the + // opportunity to recreate offer. + var sender = transceiver.sender; + + var params = sender.getParameters(); + if (!('encodings' in params)) { + params.encodings = initParameters.sendEncodings; + this.setParametersPromises.push(sender.setParameters(params).catch(function () {})); + } + } + return transceiver; + }; + } +} + +function shimCreateOffer(window) { + // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 + // Firefox ignores the init sendEncodings options passed to addTransceiver + // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { + return; + } + var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; + window.RTCPeerConnection.prototype.createOffer = function createOffer() { + var _this4 = this, + _arguments2 = arguments; + + if (this.setParametersPromises && this.setParametersPromises.length) { + return Promise.all(this.setParametersPromises).then(function () { + return origCreateOffer.apply(_this4, _arguments2); + }).finally(function () { + _this4.setParametersPromises = []; + }); + } + return origCreateOffer.apply(this, arguments); + }; +} + +function shimCreateAnswer(window) { + // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 + // Firefox ignores the init sendEncodings options passed to addTransceiver + // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { + return; + } + var origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer; + window.RTCPeerConnection.prototype.createAnswer = function createAnswer() { + var _this5 = this, + _arguments3 = arguments; + + if (this.setParametersPromises && this.setParametersPromises.length) { + return Promise.all(this.setParametersPromises).then(function () { + return origCreateAnswer.apply(_this5, _arguments3); + }).finally(function () { + _this5.setParametersPromises = []; + }); + } + return origCreateAnswer.apply(this, arguments); + }; +} + +},{"../utils":15,"./getdisplaymedia":12,"./getusermedia":13}],12:[function(require,module,exports){ +/* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = shimGetDisplayMedia; +function shimGetDisplayMedia(window, preferredMediaSource) { + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { + if (!(constraints && constraints.video)) { + var err = new DOMException('getDisplayMedia without video ' + 'constraints is undefined'); + err.name = 'NotFoundError'; + // from https://heycam.github.io/webidl/#idl-DOMException-error-names + err.code = 8; + return Promise.reject(err); + } + if (constraints.video === true) { + constraints.video = { mediaSource: preferredMediaSource }; + } else { + constraints.video.mediaSource = preferredMediaSource; + } + return window.navigator.mediaDevices.getUserMedia(constraints); + }; +} + +},{}],13:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimGetUserMedia = shimGetUserMedia; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function shimGetUserMedia(window) { + var browserDetails = utils.detectBrowser(window); + var navigator = window && window.navigator; + var MediaStreamTrack = window && window.MediaStreamTrack; + + navigator.getUserMedia = function (constraints, onSuccess, onError) { + // Replace Firefox 44+'s deprecation warning with unprefixed version. + utils.deprecated('navigator.getUserMedia', 'navigator.mediaDevices.getUserMedia'); + navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); + }; + + if (!(browserDetails.version > 55 && 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { + var remap = function remap(obj, a, b) { + if (a in obj && !(b in obj)) { + obj[b] = obj[a]; + delete obj[a]; + } + }; + + var nativeGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (c) { + if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object' && _typeof(c.audio) === 'object') { + c = JSON.parse(JSON.stringify(c)); + remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); + remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); + } + return nativeGetUserMedia(c); + }; + + if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { + var nativeGetSettings = MediaStreamTrack.prototype.getSettings; + MediaStreamTrack.prototype.getSettings = function () { + var obj = nativeGetSettings.apply(this, arguments); + remap(obj, 'mozAutoGainControl', 'autoGainControl'); + remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); + return obj; + }; + } + + if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { + var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; + MediaStreamTrack.prototype.applyConstraints = function (c) { + if (this.kind === 'audio' && (typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object') { + c = JSON.parse(JSON.stringify(c)); + remap(c, 'autoGainControl', 'mozAutoGainControl'); + remap(c, 'noiseSuppression', 'mozNoiseSuppression'); + } + return nativeApplyConstraints.apply(this, [c]); + }; + } + } +} + +},{"../utils":15}],14:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimLocalStreamsAPI = shimLocalStreamsAPI; +exports.shimRemoteStreamsAPI = shimRemoteStreamsAPI; +exports.shimCallbacksAPI = shimCallbacksAPI; +exports.shimGetUserMedia = shimGetUserMedia; +exports.shimConstraints = shimConstraints; +exports.shimRTCIceServerUrls = shimRTCIceServerUrls; +exports.shimTrackEventTransceiver = shimTrackEventTransceiver; +exports.shimCreateOfferLegacy = shimCreateOfferLegacy; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function shimLocalStreamsAPI(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { + return; + } + if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { + if (!this._localStreams) { + this._localStreams = []; + } + return this._localStreams; + }; + } + if (!('addStream' in window.RTCPeerConnection.prototype)) { + var _addTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addStream = function addStream(stream) { + var _this = this; + + if (!this._localStreams) { + this._localStreams = []; + } + if (!this._localStreams.includes(stream)) { + this._localStreams.push(stream); + } + // Try to emulate Chrome's behaviour of adding in audio-video order. + // Safari orders by track id. + stream.getAudioTracks().forEach(function (track) { + return _addTrack.call(_this, track, stream); + }); + stream.getVideoTracks().forEach(function (track) { + return _addTrack.call(_this, track, stream); + }); + }; + + window.RTCPeerConnection.prototype.addTrack = function addTrack(track) { + var stream = arguments[1]; + if (stream) { + if (!this._localStreams) { + this._localStreams = [stream]; + } else if (!this._localStreams.includes(stream)) { + this._localStreams.push(stream); + } + } + return _addTrack.apply(this, arguments); + }; + } + if (!('removeStream' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { + var _this2 = this; + + if (!this._localStreams) { + this._localStreams = []; + } + var index = this._localStreams.indexOf(stream); + if (index === -1) { + return; + } + this._localStreams.splice(index, 1); + var tracks = stream.getTracks(); + this.getSenders().forEach(function (sender) { + if (tracks.includes(sender.track)) { + _this2.removeTrack(sender); + } + }); + }; + } +} + +function shimRemoteStreamsAPI(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { + return; + } + if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getRemoteStreams = function getRemoteStreams() { + return this._remoteStreams ? this._remoteStreams : []; + }; + } + if (!('onaddstream' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { + get: function get() { + return this._onaddstream; + }, + set: function set(f) { + var _this3 = this; + + if (this._onaddstream) { + this.removeEventListener('addstream', this._onaddstream); + this.removeEventListener('track', this._onaddstreampoly); + } + this.addEventListener('addstream', this._onaddstream = f); + this.addEventListener('track', this._onaddstreampoly = function (e) { + e.streams.forEach(function (stream) { + if (!_this3._remoteStreams) { + _this3._remoteStreams = []; + } + if (_this3._remoteStreams.includes(stream)) { + return; + } + _this3._remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = stream; + _this3.dispatchEvent(event); + }); + }); + } + }); + var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { + var pc = this; + if (!this._onaddstreampoly) { + this.addEventListener('track', this._onaddstreampoly = function (e) { + e.streams.forEach(function (stream) { + if (!pc._remoteStreams) { + pc._remoteStreams = []; + } + if (pc._remoteStreams.indexOf(stream) >= 0) { + return; + } + pc._remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = stream; + pc.dispatchEvent(event); + }); + }); + } + return origSetRemoteDescription.apply(pc, arguments); + }; + } +} + +function shimCallbacksAPI(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { + return; + } + var prototype = window.RTCPeerConnection.prototype; + var origCreateOffer = prototype.createOffer; + var origCreateAnswer = prototype.createAnswer; + var setLocalDescription = prototype.setLocalDescription; + var setRemoteDescription = prototype.setRemoteDescription; + var addIceCandidate = prototype.addIceCandidate; + + prototype.createOffer = function createOffer(successCallback, failureCallback) { + var options = arguments.length >= 2 ? arguments[2] : arguments[0]; + var promise = origCreateOffer.apply(this, [options]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + + prototype.createAnswer = function createAnswer(successCallback, failureCallback) { + var options = arguments.length >= 2 ? arguments[2] : arguments[0]; + var promise = origCreateAnswer.apply(this, [options]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + + var withCallback = function withCallback(description, successCallback, failureCallback) { + var promise = setLocalDescription.apply(this, [description]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.setLocalDescription = withCallback; + + withCallback = function withCallback(description, successCallback, failureCallback) { + var promise = setRemoteDescription.apply(this, [description]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.setRemoteDescription = withCallback; + + withCallback = function withCallback(candidate, successCallback, failureCallback) { + var promise = addIceCandidate.apply(this, [candidate]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.addIceCandidate = withCallback; +} + +function shimGetUserMedia(window) { + var navigator = window && window.navigator; + + if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + // shim not needed in Safari 12.1 + var mediaDevices = navigator.mediaDevices; + var _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices); + navigator.mediaDevices.getUserMedia = function (constraints) { + return _getUserMedia(shimConstraints(constraints)); + }; + } + + if (!navigator.getUserMedia && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + navigator.getUserMedia = function getUserMedia(constraints, cb, errcb) { + navigator.mediaDevices.getUserMedia(constraints).then(cb, errcb); + }.bind(navigator); + } +} + +function shimConstraints(constraints) { + if (constraints && constraints.video !== undefined) { + return Object.assign({}, constraints, { video: utils.compactObject(constraints.video) }); + } + + return constraints; +} + +function shimRTCIceServerUrls(window) { + // migrate from non-spec RTCIceServer.url to RTCIceServer.urls + var OrigPeerConnection = window.RTCPeerConnection; + window.RTCPeerConnection = function RTCPeerConnection(pcConfig, pcConstraints) { + if (pcConfig && pcConfig.iceServers) { + var newIceServers = []; + for (var i = 0; i < pcConfig.iceServers.length; i++) { + var server = pcConfig.iceServers[i]; + if (!server.hasOwnProperty('urls') && server.hasOwnProperty('url')) { + utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); + server = JSON.parse(JSON.stringify(server)); + server.urls = server.url; + delete server.url; + newIceServers.push(server); + } else { + newIceServers.push(pcConfig.iceServers[i]); + } + } + pcConfig.iceServers = newIceServers; + } + return new OrigPeerConnection(pcConfig, pcConstraints); + }; + window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; + // wrap static methods. Currently just generateCertificate. + if ('generateCertificate' in window.RTCPeerConnection) { + Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { + get: function get() { + return OrigPeerConnection.generateCertificate; + } + }); + } +} + +function shimTrackEventTransceiver(window) { + // Add event.transceiver member over deprecated event.receiver + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { + Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { + get: function get() { + return { receiver: this.receiver }; + } + }); + } +} + +function shimCreateOfferLegacy(window) { + var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; + window.RTCPeerConnection.prototype.createOffer = function createOffer(offerOptions) { + if (offerOptions) { + if (typeof offerOptions.offerToReceiveAudio !== 'undefined') { + // support bit values + offerOptions.offerToReceiveAudio = !!offerOptions.offerToReceiveAudio; + } + var audioTransceiver = this.getTransceivers().find(function (transceiver) { + return transceiver.receiver.track.kind === 'audio'; + }); + if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { + if (audioTransceiver.direction === 'sendrecv') { + if (audioTransceiver.setDirection) { + audioTransceiver.setDirection('sendonly'); + } else { + audioTransceiver.direction = 'sendonly'; + } + } else if (audioTransceiver.direction === 'recvonly') { + if (audioTransceiver.setDirection) { + audioTransceiver.setDirection('inactive'); + } else { + audioTransceiver.direction = 'inactive'; + } + } + } else if (offerOptions.offerToReceiveAudio === true && !audioTransceiver) { + this.addTransceiver('audio'); + } + + if (typeof offerOptions.offerToReceiveVideo !== 'undefined') { + // support bit values + offerOptions.offerToReceiveVideo = !!offerOptions.offerToReceiveVideo; + } + var videoTransceiver = this.getTransceivers().find(function (transceiver) { + return transceiver.receiver.track.kind === 'video'; + }); + if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { + if (videoTransceiver.direction === 'sendrecv') { + if (videoTransceiver.setDirection) { + videoTransceiver.setDirection('sendonly'); + } else { + videoTransceiver.direction = 'sendonly'; + } + } else if (videoTransceiver.direction === 'recvonly') { + if (videoTransceiver.setDirection) { + videoTransceiver.setDirection('inactive'); + } else { + videoTransceiver.direction = 'inactive'; + } + } + } else if (offerOptions.offerToReceiveVideo === true && !videoTransceiver) { + this.addTransceiver('video'); + } + } + return origCreateOffer.apply(this, arguments); + }; +} + +},{"../utils":15}],15:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.extractVersion = extractVersion; +exports.wrapPeerConnectionEvent = wrapPeerConnectionEvent; +exports.disableLog = disableLog; +exports.disableWarnings = disableWarnings; +exports.log = log; +exports.deprecated = deprecated; +exports.detectBrowser = detectBrowser; +exports.compactObject = compactObject; +exports.walkStats = walkStats; +exports.filterStats = filterStats; + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +var logDisabled_ = true; +var deprecationWarnings_ = true; + +/** + * Extract browser version out of the provided user agent string. + * + * @param {!string} uastring userAgent string. + * @param {!string} expr Regular expression used as match criteria. + * @param {!number} pos position in the version string to be returned. + * @return {!number} browser version. + */ +function extractVersion(uastring, expr, pos) { + var match = uastring.match(expr); + return match && match.length >= pos && parseInt(match[pos], 10); +} + +// Wraps the peerconnection event eventNameToWrap in a function +// which returns the modified event object (or false to prevent +// the event). +function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { + if (!window.RTCPeerConnection) { + return; + } + var proto = window.RTCPeerConnection.prototype; + var nativeAddEventListener = proto.addEventListener; + proto.addEventListener = function (nativeEventName, cb) { + if (nativeEventName !== eventNameToWrap) { + return nativeAddEventListener.apply(this, arguments); + } + var wrappedCallback = function wrappedCallback(e) { + var modifiedEvent = wrapper(e); + if (modifiedEvent) { + cb(modifiedEvent); + } + }; + this._eventMap = this._eventMap || {}; + this._eventMap[cb] = wrappedCallback; + return nativeAddEventListener.apply(this, [nativeEventName, wrappedCallback]); + }; + + var nativeRemoveEventListener = proto.removeEventListener; + proto.removeEventListener = function (nativeEventName, cb) { + if (nativeEventName !== eventNameToWrap || !this._eventMap || !this._eventMap[cb]) { + return nativeRemoveEventListener.apply(this, arguments); + } + var unwrappedCb = this._eventMap[cb]; + delete this._eventMap[cb]; + return nativeRemoveEventListener.apply(this, [nativeEventName, unwrappedCb]); + }; + + Object.defineProperty(proto, 'on' + eventNameToWrap, { + get: function get() { + return this['_on' + eventNameToWrap]; + }, + set: function set(cb) { + if (this['_on' + eventNameToWrap]) { + this.removeEventListener(eventNameToWrap, this['_on' + eventNameToWrap]); + delete this['_on' + eventNameToWrap]; + } + if (cb) { + this.addEventListener(eventNameToWrap, this['_on' + eventNameToWrap] = cb); + } + }, + + enumerable: true, + configurable: true + }); +} + +function disableLog(bool) { + if (typeof bool !== 'boolean') { + return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.'); + } + logDisabled_ = bool; + return bool ? 'adapter.js logging disabled' : 'adapter.js logging enabled'; +} + +/** + * Disable or enable deprecation warnings + * @param {!boolean} bool set to true to disable warnings. + */ +function disableWarnings(bool) { + if (typeof bool !== 'boolean') { + return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.'); + } + deprecationWarnings_ = !bool; + return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); +} + +function log() { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object') { + if (logDisabled_) { + return; + } + if (typeof console !== 'undefined' && typeof console.log === 'function') { + console.log.apply(console, arguments); + } + } +} + +/** + * Shows a deprecation warning suggesting the modern and spec-compatible API. + */ +function deprecated(oldMethod, newMethod) { + if (!deprecationWarnings_) { + return; + } + console.warn(oldMethod + ' is deprecated, please use ' + newMethod + ' instead.'); +} + +/** + * Browser detector. + * + * @return {object} result containing browser and version + * properties. + */ +function detectBrowser(window) { + var navigator = window.navigator; + + // Returned result object. + + var result = { browser: null, version: null }; + + // Fail early if it's not a browser + if (typeof window === 'undefined' || !window.navigator) { + result.browser = 'Not a browser.'; + return result; + } + + if (navigator.mozGetUserMedia) { + // Firefox. + result.browser = 'firefox'; + result.version = extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1); + } else if (navigator.webkitGetUserMedia || window.isSecureContext === false && window.webkitRTCPeerConnection && !window.RTCIceGatherer) { + // Chrome, Chromium, Webview, Opera. + // Version matches Chrome/WebRTC version. + // Chrome 74 removed webkitGetUserMedia on http as well so we need the + // more complicated fallback to webkitRTCPeerConnection. + result.browser = 'chrome'; + result.version = extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2); + } else if (navigator.mediaDevices && navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { + // Edge. + result.browser = 'edge'; + result.version = extractVersion(navigator.userAgent, /Edge\/(\d+).(\d+)$/, 2); + } else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { + // Safari. + result.browser = 'safari'; + result.version = extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1); + result.supportsUnifiedPlan = window.RTCRtpTransceiver && 'currentDirection' in window.RTCRtpTransceiver.prototype; + } else { + // Default fallthrough: not supported. + result.browser = 'Not a supported browser.'; + return result; + } + + return result; +} + +/** + * Checks if something is an object. + * + * @param {*} val The something you want to check. + * @return true if val is an object, false otherwise. + */ +function isObject(val) { + return Object.prototype.toString.call(val) === '[object Object]'; +} + +/** + * Remove all empty objects and undefined values + * from a nested object -- an enhanced and vanilla version + * of Lodash's `compact`. + */ +function compactObject(data) { + if (!isObject(data)) { + return data; + } + + return Object.keys(data).reduce(function (accumulator, key) { + var isObj = isObject(data[key]); + var value = isObj ? compactObject(data[key]) : data[key]; + var isEmptyObject = isObj && !Object.keys(value).length; + if (value === undefined || isEmptyObject) { + return accumulator; + } + return Object.assign(accumulator, _defineProperty({}, key, value)); + }, {}); +} + +/* iterates the stats graph recursively. */ +function walkStats(stats, base, resultSet) { + if (!base || resultSet.has(base.id)) { + return; + } + resultSet.set(base.id, base); + Object.keys(base).forEach(function (name) { + if (name.endsWith('Id')) { + walkStats(stats, stats.get(base[name]), resultSet); + } else if (name.endsWith('Ids')) { + base[name].forEach(function (id) { + walkStats(stats, stats.get(id), resultSet); + }); + } + }); +} + +/* filter getStats for a sender/receiver track. */ +function filterStats(result, track, outbound) { + var streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp'; + var filteredResult = new Map(); + if (track === null) { + return filteredResult; + } + var trackStats = []; + result.forEach(function (value) { + if (value.type === 'track' && value.trackIdentifier === track.id) { + trackStats.push(value); + } + }); + trackStats.forEach(function (trackStat) { + result.forEach(function (stats) { + if (stats.type === streamStatsType && stats.trackId === trackStat.id) { + walkStats(result, stats, filteredResult); + } + }); + }); + return filteredResult; +} + +},{}],16:[function(require,module,exports){ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ +'use strict'; + +var SDPUtils = require('sdp'); + +function fixStatsType(stat) { + return { + inboundrtp: 'inbound-rtp', + outboundrtp: 'outbound-rtp', + candidatepair: 'candidate-pair', + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }[stat.type] || stat.type; +} + +function writeMediaSection(transceiver, caps, type, stream, dtlsRole) { + var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); + + // Map ICE parameters (ufrag, pwd) to SDP. + sdp += SDPUtils.writeIceParameters( + transceiver.iceGatherer.getLocalParameters()); + + // Map DTLS parameters to SDP. + sdp += SDPUtils.writeDtlsParameters( + transceiver.dtlsTransport.getLocalParameters(), + type === 'offer' ? 'actpass' : dtlsRole || 'active'); + + sdp += 'a=mid:' + transceiver.mid + '\r\n'; + + if (transceiver.rtpSender && transceiver.rtpReceiver) { + sdp += 'a=sendrecv\r\n'; + } else if (transceiver.rtpSender) { + sdp += 'a=sendonly\r\n'; + } else if (transceiver.rtpReceiver) { + sdp += 'a=recvonly\r\n'; + } else { + sdp += 'a=inactive\r\n'; + } + + if (transceiver.rtpSender) { + var trackId = transceiver.rtpSender._initialTrackId || + transceiver.rtpSender.track.id; + transceiver.rtpSender._initialTrackId = trackId; + // spec. + var msid = 'msid:' + (stream ? stream.id : '-') + ' ' + + trackId + '\r\n'; + sdp += 'a=' + msid; + // for Chrome. Legacy should no longer be required. + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + + ' ' + msid; + + // RTX + if (transceiver.sendEncodingParameters[0].rtx) { + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + + ' ' + msid; + sdp += 'a=ssrc-group:FID ' + + transceiver.sendEncodingParameters[0].ssrc + ' ' + + transceiver.sendEncodingParameters[0].rtx.ssrc + + '\r\n'; + } + } + // FIXME: this should be written by writeRtpDescription. + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + + ' cname:' + SDPUtils.localCName + '\r\n'; + if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + + ' cname:' + SDPUtils.localCName + '\r\n'; + } + return sdp; +} + +// Edge does not like +// 1) stun: filtered after 14393 unless ?transport=udp is present +// 2) turn: that does not have all of turn:host:port?transport=udp +// 3) turn: with ipv6 addresses +// 4) turn: occurring muliple times +function filterIceServers(iceServers, edgeVersion) { + var hasTurn = false; + iceServers = JSON.parse(JSON.stringify(iceServers)); + return iceServers.filter(function(server) { + if (server && (server.urls || server.url)) { + var urls = server.urls || server.url; + if (server.url && !server.urls) { + console.warn('RTCIceServer.url is deprecated! Use urls instead.'); + } + var isString = typeof urls === 'string'; + if (isString) { + urls = [urls]; + } + urls = urls.filter(function(url) { + var validTurn = url.indexOf('turn:') === 0 && + url.indexOf('transport=udp') !== -1 && + url.indexOf('turn:[') === -1 && + !hasTurn; + + if (validTurn) { + hasTurn = true; + return true; + } + return url.indexOf('stun:') === 0 && edgeVersion >= 14393 && + url.indexOf('?transport=udp') === -1; + }); + + delete server.url; + server.urls = isString ? urls[0] : urls; + return !!urls.length; + } + }); +} + +// Determines the intersection of local and remote capabilities. +function getCommonCapabilities(localCapabilities, remoteCapabilities) { + var commonCapabilities = { + codecs: [], + headerExtensions: [], + fecMechanisms: [] + }; + + var findCodecByPayloadType = function(pt, codecs) { + pt = parseInt(pt, 10); + for (var i = 0; i < codecs.length; i++) { + if (codecs[i].payloadType === pt || + codecs[i].preferredPayloadType === pt) { + return codecs[i]; + } + } + }; + + var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { + var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); + var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); + return lCodec && rCodec && + lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); + }; + + localCapabilities.codecs.forEach(function(lCodec) { + for (var i = 0; i < remoteCapabilities.codecs.length; i++) { + var rCodec = remoteCapabilities.codecs[i]; + if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && + lCodec.clockRate === rCodec.clockRate) { + if (lCodec.name.toLowerCase() === 'rtx' && + lCodec.parameters && rCodec.parameters.apt) { + // for RTX we need to find the local rtx that has a apt + // which points to the same local codec as the remote one. + if (!rtxCapabilityMatches(lCodec, rCodec, + localCapabilities.codecs, remoteCapabilities.codecs)) { + continue; + } + } + rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy + // number of channels is the highest common number of channels + rCodec.numChannels = Math.min(lCodec.numChannels, + rCodec.numChannels); + // push rCodec so we reply with offerer payload type + commonCapabilities.codecs.push(rCodec); + + // determine common feedback mechanisms + rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { + for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { + if (lCodec.rtcpFeedback[j].type === fb.type && + lCodec.rtcpFeedback[j].parameter === fb.parameter) { + return true; + } + } + return false; + }); + // FIXME: also need to determine .parameters + // see https://github.com/openpeer/ortc/issues/569 + break; + } + } + }); + + localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { + for (var i = 0; i < remoteCapabilities.headerExtensions.length; + i++) { + var rHeaderExtension = remoteCapabilities.headerExtensions[i]; + if (lHeaderExtension.uri === rHeaderExtension.uri) { + commonCapabilities.headerExtensions.push(rHeaderExtension); + break; + } + } + }); + + // FIXME: fecMechanisms + return commonCapabilities; +} + +// is action=setLocalDescription with type allowed in signalingState +function isActionAllowedInSignalingState(action, type, signalingState) { + return { + offer: { + setLocalDescription: ['stable', 'have-local-offer'], + setRemoteDescription: ['stable', 'have-remote-offer'] + }, + answer: { + setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], + setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] + } + }[type][action].indexOf(signalingState) !== -1; +} + +function maybeAddCandidate(iceTransport, candidate) { + // Edge's internal representation adds some fields therefore + // not all field褧 are taken into account. + var alreadyAdded = iceTransport.getRemoteCandidates() + .find(function(remoteCandidate) { + return candidate.foundation === remoteCandidate.foundation && + candidate.ip === remoteCandidate.ip && + candidate.port === remoteCandidate.port && + candidate.priority === remoteCandidate.priority && + candidate.protocol === remoteCandidate.protocol && + candidate.type === remoteCandidate.type; + }); + if (!alreadyAdded) { + iceTransport.addRemoteCandidate(candidate); + } + return !alreadyAdded; +} + + +function makeError(name, description) { + var e = new Error(description); + e.name = name; + // legacy error codes from https://heycam.github.io/webidl/#idl-DOMException-error-names + e.code = { + NotSupportedError: 9, + InvalidStateError: 11, + InvalidAccessError: 15, + TypeError: undefined, + OperationError: undefined + }[name]; + return e; +} + +module.exports = function(window, edgeVersion) { + // https://w3c.github.io/mediacapture-main/#mediastream + // Helper function to add the track to the stream and + // dispatch the event ourselves. + function addTrackToStreamAndFireEvent(track, stream) { + stream.addTrack(track); + stream.dispatchEvent(new window.MediaStreamTrackEvent('addtrack', + {track: track})); + } + + function removeTrackFromStreamAndFireEvent(track, stream) { + stream.removeTrack(track); + stream.dispatchEvent(new window.MediaStreamTrackEvent('removetrack', + {track: track})); + } + + function fireAddTrack(pc, track, receiver, streams) { + var trackEvent = new Event('track'); + trackEvent.track = track; + trackEvent.receiver = receiver; + trackEvent.transceiver = {receiver: receiver}; + trackEvent.streams = streams; + window.setTimeout(function() { + pc._dispatchEvent('track', trackEvent); + }); + } + + var RTCPeerConnection = function(config) { + var pc = this; + + var _eventTarget = document.createDocumentFragment(); + ['addEventListener', 'removeEventListener', 'dispatchEvent'] + .forEach(function(method) { + pc[method] = _eventTarget[method].bind(_eventTarget); + }); + + this.canTrickleIceCandidates = null; + + this.needNegotiation = false; + + this.localStreams = []; + this.remoteStreams = []; + + this._localDescription = null; + this._remoteDescription = null; + + this.signalingState = 'stable'; + this.iceConnectionState = 'new'; + this.connectionState = 'new'; + this.iceGatheringState = 'new'; + + config = JSON.parse(JSON.stringify(config || {})); + + this.usingBundle = config.bundlePolicy === 'max-bundle'; + if (config.rtcpMuxPolicy === 'negotiate') { + throw(makeError('NotSupportedError', + 'rtcpMuxPolicy \'negotiate\' is not supported')); + } else if (!config.rtcpMuxPolicy) { + config.rtcpMuxPolicy = 'require'; + } + + switch (config.iceTransportPolicy) { + case 'all': + case 'relay': + break; + default: + config.iceTransportPolicy = 'all'; + break; + } + + switch (config.bundlePolicy) { + case 'balanced': + case 'max-compat': + case 'max-bundle': + break; + default: + config.bundlePolicy = 'balanced'; + break; + } + + config.iceServers = filterIceServers(config.iceServers || [], edgeVersion); + + this._iceGatherers = []; + if (config.iceCandidatePoolSize) { + for (var i = config.iceCandidatePoolSize; i > 0; i--) { + this._iceGatherers.push(new window.RTCIceGatherer({ + iceServers: config.iceServers, + gatherPolicy: config.iceTransportPolicy + })); + } + } else { + config.iceCandidatePoolSize = 0; + } + + this._config = config; + + // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... + // everything that is needed to describe a SDP m-line. + this.transceivers = []; + + this._sdpSessionId = SDPUtils.generateSessionId(); + this._sdpSessionVersion = 0; + + this._dtlsRole = undefined; // role for a=setup to use in answers. + + this._isClosed = false; + }; + + Object.defineProperty(RTCPeerConnection.prototype, 'localDescription', { + configurable: true, + get: function() { + return this._localDescription; + } + }); + Object.defineProperty(RTCPeerConnection.prototype, 'remoteDescription', { + configurable: true, + get: function() { + return this._remoteDescription; + } + }); + + // set up event handlers on prototype + RTCPeerConnection.prototype.onicecandidate = null; + RTCPeerConnection.prototype.onaddstream = null; + RTCPeerConnection.prototype.ontrack = null; + RTCPeerConnection.prototype.onremovestream = null; + RTCPeerConnection.prototype.onsignalingstatechange = null; + RTCPeerConnection.prototype.oniceconnectionstatechange = null; + RTCPeerConnection.prototype.onconnectionstatechange = null; + RTCPeerConnection.prototype.onicegatheringstatechange = null; + RTCPeerConnection.prototype.onnegotiationneeded = null; + RTCPeerConnection.prototype.ondatachannel = null; + + RTCPeerConnection.prototype._dispatchEvent = function(name, event) { + if (this._isClosed) { + return; + } + this.dispatchEvent(event); + if (typeof this['on' + name] === 'function') { + this['on' + name](event); + } + }; + + RTCPeerConnection.prototype._emitGatheringStateChange = function() { + var event = new Event('icegatheringstatechange'); + this._dispatchEvent('icegatheringstatechange', event); + }; + + RTCPeerConnection.prototype.getConfiguration = function() { + return this._config; + }; + + RTCPeerConnection.prototype.getLocalStreams = function() { + return this.localStreams; + }; + + RTCPeerConnection.prototype.getRemoteStreams = function() { + return this.remoteStreams; + }; + + // internal helper to create a transceiver object. + // (which is not yet the same as the WebRTC 1.0 transceiver) + RTCPeerConnection.prototype._createTransceiver = function(kind, doNotAdd) { + var hasBundleTransport = this.transceivers.length > 0; + var transceiver = { + track: null, + iceGatherer: null, + iceTransport: null, + dtlsTransport: null, + localCapabilities: null, + remoteCapabilities: null, + rtpSender: null, + rtpReceiver: null, + kind: kind, + mid: null, + sendEncodingParameters: null, + recvEncodingParameters: null, + stream: null, + associatedRemoteMediaStreams: [], + wantReceive: true + }; + if (this.usingBundle && hasBundleTransport) { + transceiver.iceTransport = this.transceivers[0].iceTransport; + transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; + } else { + var transports = this._createIceAndDtlsTransports(); + transceiver.iceTransport = transports.iceTransport; + transceiver.dtlsTransport = transports.dtlsTransport; + } + if (!doNotAdd) { + this.transceivers.push(transceiver); + } + return transceiver; + }; + + RTCPeerConnection.prototype.addTrack = function(track, stream) { + if (this._isClosed) { + throw makeError('InvalidStateError', + 'Attempted to call addTrack on a closed peerconnection.'); + } + + var alreadyExists = this.transceivers.find(function(s) { + return s.track === track; + }); + + if (alreadyExists) { + throw makeError('InvalidAccessError', 'Track already exists.'); + } + + var transceiver; + for (var i = 0; i < this.transceivers.length; i++) { + if (!this.transceivers[i].track && + this.transceivers[i].kind === track.kind) { + transceiver = this.transceivers[i]; + } + } + if (!transceiver) { + transceiver = this._createTransceiver(track.kind); + } + + this._maybeFireNegotiationNeeded(); + + if (this.localStreams.indexOf(stream) === -1) { + this.localStreams.push(stream); + } + + transceiver.track = track; + transceiver.stream = stream; + transceiver.rtpSender = new window.RTCRtpSender(track, + transceiver.dtlsTransport); + return transceiver.rtpSender; + }; + + RTCPeerConnection.prototype.addStream = function(stream) { + var pc = this; + if (edgeVersion >= 15025) { + stream.getTracks().forEach(function(track) { + pc.addTrack(track, stream); + }); + } else { + // Clone is necessary for local demos mostly, attaching directly + // to two different senders does not work (build 10547). + // Fixed in 15025 (or earlier) + var clonedStream = stream.clone(); + stream.getTracks().forEach(function(track, idx) { + var clonedTrack = clonedStream.getTracks()[idx]; + track.addEventListener('enabled', function(event) { + clonedTrack.enabled = event.enabled; + }); + }); + clonedStream.getTracks().forEach(function(track) { + pc.addTrack(track, clonedStream); + }); + } + }; + + RTCPeerConnection.prototype.removeTrack = function(sender) { + if (this._isClosed) { + throw makeError('InvalidStateError', + 'Attempted to call removeTrack on a closed peerconnection.'); + } + + if (!(sender instanceof window.RTCRtpSender)) { + throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' + + 'does not implement interface RTCRtpSender.'); + } + + var transceiver = this.transceivers.find(function(t) { + return t.rtpSender === sender; + }); + + if (!transceiver) { + throw makeError('InvalidAccessError', + 'Sender was not created by this connection.'); + } + var stream = transceiver.stream; + + transceiver.rtpSender.stop(); + transceiver.rtpSender = null; + transceiver.track = null; + transceiver.stream = null; + + // remove the stream from the set of local streams + var localStreams = this.transceivers.map(function(t) { + return t.stream; + }); + if (localStreams.indexOf(stream) === -1 && + this.localStreams.indexOf(stream) > -1) { + this.localStreams.splice(this.localStreams.indexOf(stream), 1); + } + + this._maybeFireNegotiationNeeded(); + }; + + RTCPeerConnection.prototype.removeStream = function(stream) { + var pc = this; + stream.getTracks().forEach(function(track) { + var sender = pc.getSenders().find(function(s) { + return s.track === track; + }); + if (sender) { + pc.removeTrack(sender); + } + }); + }; + + RTCPeerConnection.prototype.getSenders = function() { + return this.transceivers.filter(function(transceiver) { + return !!transceiver.rtpSender; + }) + .map(function(transceiver) { + return transceiver.rtpSender; + }); + }; + + RTCPeerConnection.prototype.getReceivers = function() { + return this.transceivers.filter(function(transceiver) { + return !!transceiver.rtpReceiver; + }) + .map(function(transceiver) { + return transceiver.rtpReceiver; + }); + }; + + + RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex, + usingBundle) { + var pc = this; + if (usingBundle && sdpMLineIndex > 0) { + return this.transceivers[0].iceGatherer; + } else if (this._iceGatherers.length) { + return this._iceGatherers.shift(); + } + var iceGatherer = new window.RTCIceGatherer({ + iceServers: this._config.iceServers, + gatherPolicy: this._config.iceTransportPolicy + }); + Object.defineProperty(iceGatherer, 'state', + {value: 'new', writable: true} + ); + + this.transceivers[sdpMLineIndex].bufferedCandidateEvents = []; + this.transceivers[sdpMLineIndex].bufferCandidates = function(event) { + var end = !event.candidate || Object.keys(event.candidate).length === 0; + // polyfill since RTCIceGatherer.state is not implemented in + // Edge 10547 yet. + iceGatherer.state = end ? 'completed' : 'gathering'; + if (pc.transceivers[sdpMLineIndex].bufferedCandidateEvents !== null) { + pc.transceivers[sdpMLineIndex].bufferedCandidateEvents.push(event); + } + }; + iceGatherer.addEventListener('localcandidate', + this.transceivers[sdpMLineIndex].bufferCandidates); + return iceGatherer; + }; + + // start gathering from an RTCIceGatherer. + RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) { + var pc = this; + var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; + if (iceGatherer.onlocalcandidate) { + return; + } + var bufferedCandidateEvents = + this.transceivers[sdpMLineIndex].bufferedCandidateEvents; + this.transceivers[sdpMLineIndex].bufferedCandidateEvents = null; + iceGatherer.removeEventListener('localcandidate', + this.transceivers[sdpMLineIndex].bufferCandidates); + iceGatherer.onlocalcandidate = function(evt) { + if (pc.usingBundle && sdpMLineIndex > 0) { + // if we know that we use bundle we can drop candidates with + // 褧dpMLineIndex > 0. If we don't do this then our state gets + // confused since we dispose the extra ice gatherer. + return; + } + var event = new Event('icecandidate'); + event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; + + var cand = evt.candidate; + // Edge emits an empty object for RTCIceCandidateComplete鈥 + var end = !cand || Object.keys(cand).length === 0; + if (end) { + // polyfill since RTCIceGatherer.state is not implemented in + // Edge 10547 yet. + if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') { + iceGatherer.state = 'completed'; + } + } else { + if (iceGatherer.state === 'new') { + iceGatherer.state = 'gathering'; + } + // RTCIceCandidate doesn't have a component, needs to be added + cand.component = 1; + // also the usernameFragment. TODO: update SDP to take both variants. + cand.ufrag = iceGatherer.getLocalParameters().usernameFragment; + + var serializedCandidate = SDPUtils.writeCandidate(cand); + event.candidate = Object.assign(event.candidate, + SDPUtils.parseCandidate(serializedCandidate)); + + event.candidate.candidate = serializedCandidate; + event.candidate.toJSON = function() { + return { + candidate: event.candidate.candidate, + sdpMid: event.candidate.sdpMid, + sdpMLineIndex: event.candidate.sdpMLineIndex, + usernameFragment: event.candidate.usernameFragment + }; + }; + } + + // update local description. + var sections = SDPUtils.getMediaSections(pc._localDescription.sdp); + if (!end) { + sections[event.candidate.sdpMLineIndex] += + 'a=' + event.candidate.candidate + '\r\n'; + } else { + sections[event.candidate.sdpMLineIndex] += + 'a=end-of-candidates\r\n'; + } + pc._localDescription.sdp = + SDPUtils.getDescription(pc._localDescription.sdp) + + sections.join(''); + var complete = pc.transceivers.every(function(transceiver) { + return transceiver.iceGatherer && + transceiver.iceGatherer.state === 'completed'; + }); + + if (pc.iceGatheringState !== 'gathering') { + pc.iceGatheringState = 'gathering'; + pc._emitGatheringStateChange(); + } + + // Emit candidate. Also emit null candidate when all gatherers are + // complete. + if (!end) { + pc._dispatchEvent('icecandidate', event); + } + if (complete) { + pc._dispatchEvent('icecandidate', new Event('icecandidate')); + pc.iceGatheringState = 'complete'; + pc._emitGatheringStateChange(); + } + }; + + // emit already gathered candidates. + window.setTimeout(function() { + bufferedCandidateEvents.forEach(function(e) { + iceGatherer.onlocalcandidate(e); + }); + }, 0); + }; + + // Create ICE transport and DTLS transport. + RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { + var pc = this; + var iceTransport = new window.RTCIceTransport(null); + iceTransport.onicestatechange = function() { + pc._updateIceConnectionState(); + pc._updateConnectionState(); + }; + + var dtlsTransport = new window.RTCDtlsTransport(iceTransport); + dtlsTransport.ondtlsstatechange = function() { + pc._updateConnectionState(); + }; + dtlsTransport.onerror = function() { + // onerror does not set state to failed by itself. + Object.defineProperty(dtlsTransport, 'state', + {value: 'failed', writable: true}); + pc._updateConnectionState(); + }; + + return { + iceTransport: iceTransport, + dtlsTransport: dtlsTransport + }; + }; + + // Destroy ICE gatherer, ICE transport and DTLS transport. + // Without triggering the callbacks. + RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( + sdpMLineIndex) { + var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; + if (iceGatherer) { + delete iceGatherer.onlocalcandidate; + delete this.transceivers[sdpMLineIndex].iceGatherer; + } + var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; + if (iceTransport) { + delete iceTransport.onicestatechange; + delete this.transceivers[sdpMLineIndex].iceTransport; + } + var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; + if (dtlsTransport) { + delete dtlsTransport.ondtlsstatechange; + delete dtlsTransport.onerror; + delete this.transceivers[sdpMLineIndex].dtlsTransport; + } + }; + + // Start the RTP Sender and Receiver for a transceiver. + RTCPeerConnection.prototype._transceive = function(transceiver, + send, recv) { + var params = getCommonCapabilities(transceiver.localCapabilities, + transceiver.remoteCapabilities); + if (send && transceiver.rtpSender) { + params.encodings = transceiver.sendEncodingParameters; + params.rtcp = { + cname: SDPUtils.localCName, + compound: transceiver.rtcpParameters.compound + }; + if (transceiver.recvEncodingParameters.length) { + params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; + } + transceiver.rtpSender.send(params); + } + if (recv && transceiver.rtpReceiver && params.codecs.length > 0) { + // remove RTX field in Edge 14942 + if (transceiver.kind === 'video' + && transceiver.recvEncodingParameters + && edgeVersion < 15019) { + transceiver.recvEncodingParameters.forEach(function(p) { + delete p.rtx; + }); + } + if (transceiver.recvEncodingParameters.length) { + params.encodings = transceiver.recvEncodingParameters; + } else { + params.encodings = [{}]; + } + params.rtcp = { + compound: transceiver.rtcpParameters.compound + }; + if (transceiver.rtcpParameters.cname) { + params.rtcp.cname = transceiver.rtcpParameters.cname; + } + if (transceiver.sendEncodingParameters.length) { + params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; + } + transceiver.rtpReceiver.receive(params); + } + }; + + RTCPeerConnection.prototype.setLocalDescription = function(description) { + var pc = this; + + // Note: pranswer is not supported. + if (['offer', 'answer'].indexOf(description.type) === -1) { + return Promise.reject(makeError('TypeError', + 'Unsupported type "' + description.type + '"')); + } + + if (!isActionAllowedInSignalingState('setLocalDescription', + description.type, pc.signalingState) || pc._isClosed) { + return Promise.reject(makeError('InvalidStateError', + 'Can not set local ' + description.type + + ' in state ' + pc.signalingState)); + } + + var sections; + var sessionpart; + if (description.type === 'offer') { + // VERY limited support for SDP munging. Limited to: + // * changing the order of codecs + sections = SDPUtils.splitSections(description.sdp); + sessionpart = sections.shift(); + sections.forEach(function(mediaSection, sdpMLineIndex) { + var caps = SDPUtils.parseRtpParameters(mediaSection); + pc.transceivers[sdpMLineIndex].localCapabilities = caps; + }); + + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { + pc._gather(transceiver.mid, sdpMLineIndex); + }); + } else if (description.type === 'answer') { + sections = SDPUtils.splitSections(pc._remoteDescription.sdp); + sessionpart = sections.shift(); + var isIceLite = SDPUtils.matchPrefix(sessionpart, + 'a=ice-lite').length > 0; + sections.forEach(function(mediaSection, sdpMLineIndex) { + var transceiver = pc.transceivers[sdpMLineIndex]; + var iceGatherer = transceiver.iceGatherer; + var iceTransport = transceiver.iceTransport; + var dtlsTransport = transceiver.dtlsTransport; + var localCapabilities = transceiver.localCapabilities; + var remoteCapabilities = transceiver.remoteCapabilities; + + // treat bundle-only as not-rejected. + var rejected = SDPUtils.isRejected(mediaSection) && + SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; + + if (!rejected && !transceiver.rejected) { + var remoteIceParameters = SDPUtils.getIceParameters( + mediaSection, sessionpart); + var remoteDtlsParameters = SDPUtils.getDtlsParameters( + mediaSection, sessionpart); + if (isIceLite) { + remoteDtlsParameters.role = 'server'; + } + + if (!pc.usingBundle || sdpMLineIndex === 0) { + pc._gather(transceiver.mid, sdpMLineIndex); + if (iceTransport.state === 'new') { + iceTransport.start(iceGatherer, remoteIceParameters, + isIceLite ? 'controlling' : 'controlled'); + } + if (dtlsTransport.state === 'new') { + dtlsTransport.start(remoteDtlsParameters); + } + } + + // Calculate intersection of capabilities. + var params = getCommonCapabilities(localCapabilities, + remoteCapabilities); + + // Start the RTCRtpSender. The RTCRtpReceiver for this + // transceiver has already been started in setRemoteDescription. + pc._transceive(transceiver, + params.codecs.length > 0, + false); + } + }); + } + + pc._localDescription = { + type: description.type, + sdp: description.sdp + }; + if (description.type === 'offer') { + pc._updateSignalingState('have-local-offer'); + } else { + pc._updateSignalingState('stable'); + } + + return Promise.resolve(); + }; + + RTCPeerConnection.prototype.setRemoteDescription = function(description) { + var pc = this; + + // Note: pranswer is not supported. + if (['offer', 'answer'].indexOf(description.type) === -1) { + return Promise.reject(makeError('TypeError', + 'Unsupported type "' + description.type + '"')); + } + + if (!isActionAllowedInSignalingState('setRemoteDescription', + description.type, pc.signalingState) || pc._isClosed) { + return Promise.reject(makeError('InvalidStateError', + 'Can not set remote ' + description.type + + ' in state ' + pc.signalingState)); + } + + var streams = {}; + pc.remoteStreams.forEach(function(stream) { + streams[stream.id] = stream; + }); + var receiverList = []; + var sections = SDPUtils.splitSections(description.sdp); + var sessionpart = sections.shift(); + var isIceLite = SDPUtils.matchPrefix(sessionpart, + 'a=ice-lite').length > 0; + var usingBundle = SDPUtils.matchPrefix(sessionpart, + 'a=group:BUNDLE ').length > 0; + pc.usingBundle = usingBundle; + var iceOptions = SDPUtils.matchPrefix(sessionpart, + 'a=ice-options:')[0]; + if (iceOptions) { + pc.canTrickleIceCandidates = iceOptions.substr(14).split(' ') + .indexOf('trickle') >= 0; + } else { + pc.canTrickleIceCandidates = false; + } + + sections.forEach(function(mediaSection, sdpMLineIndex) { + var lines = SDPUtils.splitLines(mediaSection); + var kind = SDPUtils.getKind(mediaSection); + // treat bundle-only as not-rejected. + var rejected = SDPUtils.isRejected(mediaSection) && + SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; + var protocol = lines[0].substr(2).split(' ')[2]; + + var direction = SDPUtils.getDirection(mediaSection, sessionpart); + var remoteMsid = SDPUtils.parseMsid(mediaSection); + + var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); + + // Reject datachannels which are not implemented yet. + if (rejected || (kind === 'application' && (protocol === 'DTLS/SCTP' || + protocol === 'UDP/DTLS/SCTP'))) { + // TODO: this is dangerous in the case where a non-rejected m-line + // becomes rejected. + pc.transceivers[sdpMLineIndex] = { + mid: mid, + kind: kind, + protocol: protocol, + rejected: true + }; + return; + } + + if (!rejected && pc.transceivers[sdpMLineIndex] && + pc.transceivers[sdpMLineIndex].rejected) { + // recycle a rejected transceiver. + pc.transceivers[sdpMLineIndex] = pc._createTransceiver(kind, true); + } + + var transceiver; + var iceGatherer; + var iceTransport; + var dtlsTransport; + var rtpReceiver; + var sendEncodingParameters; + var recvEncodingParameters; + var localCapabilities; + + var track; + // FIXME: ensure the mediaSection has rtcp-mux set. + var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); + var remoteIceParameters; + var remoteDtlsParameters; + if (!rejected) { + remoteIceParameters = SDPUtils.getIceParameters(mediaSection, + sessionpart); + remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, + sessionpart); + remoteDtlsParameters.role = 'client'; + } + recvEncodingParameters = + SDPUtils.parseRtpEncodingParameters(mediaSection); + + var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); + + var isComplete = SDPUtils.matchPrefix(mediaSection, + 'a=end-of-candidates', sessionpart).length > 0; + var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') + .map(function(cand) { + return SDPUtils.parseCandidate(cand); + }) + .filter(function(cand) { + return cand.component === 1; + }); + + // Check if we can use BUNDLE and dispose transports. + if ((description.type === 'offer' || description.type === 'answer') && + !rejected && usingBundle && sdpMLineIndex > 0 && + pc.transceivers[sdpMLineIndex]) { + pc._disposeIceAndDtlsTransports(sdpMLineIndex); + pc.transceivers[sdpMLineIndex].iceGatherer = + pc.transceivers[0].iceGatherer; + pc.transceivers[sdpMLineIndex].iceTransport = + pc.transceivers[0].iceTransport; + pc.transceivers[sdpMLineIndex].dtlsTransport = + pc.transceivers[0].dtlsTransport; + if (pc.transceivers[sdpMLineIndex].rtpSender) { + pc.transceivers[sdpMLineIndex].rtpSender.setTransport( + pc.transceivers[0].dtlsTransport); + } + if (pc.transceivers[sdpMLineIndex].rtpReceiver) { + pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport( + pc.transceivers[0].dtlsTransport); + } + } + if (description.type === 'offer' && !rejected) { + transceiver = pc.transceivers[sdpMLineIndex] || + pc._createTransceiver(kind); + transceiver.mid = mid; + + if (!transceiver.iceGatherer) { + transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, + usingBundle); + } + + if (cands.length && transceiver.iceTransport.state === 'new') { + if (isComplete && (!usingBundle || sdpMLineIndex === 0)) { + transceiver.iceTransport.setRemoteCandidates(cands); + } else { + cands.forEach(function(candidate) { + maybeAddCandidate(transceiver.iceTransport, candidate); + }); + } + } + + localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); + + // filter RTX until additional stuff needed for RTX is implemented + // in adapter.js + if (edgeVersion < 15019) { + localCapabilities.codecs = localCapabilities.codecs.filter( + function(codec) { + return codec.name !== 'rtx'; + }); + } + + sendEncodingParameters = transceiver.sendEncodingParameters || [{ + ssrc: (2 * sdpMLineIndex + 2) * 1001 + }]; + + // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams + var isNewTrack = false; + if (direction === 'sendrecv' || direction === 'sendonly') { + isNewTrack = !transceiver.rtpReceiver; + rtpReceiver = transceiver.rtpReceiver || + new window.RTCRtpReceiver(transceiver.dtlsTransport, kind); + + if (isNewTrack) { + var stream; + track = rtpReceiver.track; + // FIXME: does not work with Plan B. + if (remoteMsid && remoteMsid.stream === '-') { + // no-op. a stream id of '-' means: no associated stream. + } else if (remoteMsid) { + if (!streams[remoteMsid.stream]) { + streams[remoteMsid.stream] = new window.MediaStream(); + Object.defineProperty(streams[remoteMsid.stream], 'id', { + get: function() { + return remoteMsid.stream; + } + }); + } + Object.defineProperty(track, 'id', { + get: function() { + return remoteMsid.track; + } + }); + stream = streams[remoteMsid.stream]; + } else { + if (!streams.default) { + streams.default = new window.MediaStream(); + } + stream = streams.default; + } + if (stream) { + addTrackToStreamAndFireEvent(track, stream); + transceiver.associatedRemoteMediaStreams.push(stream); + } + receiverList.push([track, rtpReceiver, stream]); + } + } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) { + transceiver.associatedRemoteMediaStreams.forEach(function(s) { + var nativeTrack = s.getTracks().find(function(t) { + return t.id === transceiver.rtpReceiver.track.id; + }); + if (nativeTrack) { + removeTrackFromStreamAndFireEvent(nativeTrack, s); + } + }); + transceiver.associatedRemoteMediaStreams = []; + } + + transceiver.localCapabilities = localCapabilities; + transceiver.remoteCapabilities = remoteCapabilities; + transceiver.rtpReceiver = rtpReceiver; + transceiver.rtcpParameters = rtcpParameters; + transceiver.sendEncodingParameters = sendEncodingParameters; + transceiver.recvEncodingParameters = recvEncodingParameters; + + // Start the RTCRtpReceiver now. The RTPSender is started in + // setLocalDescription. + pc._transceive(pc.transceivers[sdpMLineIndex], + false, + isNewTrack); + } else if (description.type === 'answer' && !rejected) { + transceiver = pc.transceivers[sdpMLineIndex]; + iceGatherer = transceiver.iceGatherer; + iceTransport = transceiver.iceTransport; + dtlsTransport = transceiver.dtlsTransport; + rtpReceiver = transceiver.rtpReceiver; + sendEncodingParameters = transceiver.sendEncodingParameters; + localCapabilities = transceiver.localCapabilities; + + pc.transceivers[sdpMLineIndex].recvEncodingParameters = + recvEncodingParameters; + pc.transceivers[sdpMLineIndex].remoteCapabilities = + remoteCapabilities; + pc.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; + + if (cands.length && iceTransport.state === 'new') { + if ((isIceLite || isComplete) && + (!usingBundle || sdpMLineIndex === 0)) { + iceTransport.setRemoteCandidates(cands); + } else { + cands.forEach(function(candidate) { + maybeAddCandidate(transceiver.iceTransport, candidate); + }); + } + } + + if (!usingBundle || sdpMLineIndex === 0) { + if (iceTransport.state === 'new') { + iceTransport.start(iceGatherer, remoteIceParameters, + 'controlling'); + } + if (dtlsTransport.state === 'new') { + dtlsTransport.start(remoteDtlsParameters); + } + } + + // If the offer contained RTX but the answer did not, + // remove RTX from sendEncodingParameters. + var commonCapabilities = getCommonCapabilities( + transceiver.localCapabilities, + transceiver.remoteCapabilities); + + var hasRtx = commonCapabilities.codecs.filter(function(c) { + return c.name.toLowerCase() === 'rtx'; + }).length; + if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { + delete transceiver.sendEncodingParameters[0].rtx; + } + + pc._transceive(transceiver, + direction === 'sendrecv' || direction === 'recvonly', + direction === 'sendrecv' || direction === 'sendonly'); + + // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams + if (rtpReceiver && + (direction === 'sendrecv' || direction === 'sendonly')) { + track = rtpReceiver.track; + if (remoteMsid) { + if (!streams[remoteMsid.stream]) { + streams[remoteMsid.stream] = new window.MediaStream(); + } + addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]); + receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); + } else { + if (!streams.default) { + streams.default = new window.MediaStream(); + } + addTrackToStreamAndFireEvent(track, streams.default); + receiverList.push([track, rtpReceiver, streams.default]); + } + } else { + // FIXME: actually the receiver should be created later. + delete transceiver.rtpReceiver; + } + } + }); + + if (pc._dtlsRole === undefined) { + pc._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; + } + + pc._remoteDescription = { + type: description.type, + sdp: description.sdp + }; + if (description.type === 'offer') { + pc._updateSignalingState('have-remote-offer'); + } else { + pc._updateSignalingState('stable'); + } + Object.keys(streams).forEach(function(sid) { + var stream = streams[sid]; + if (stream.getTracks().length) { + if (pc.remoteStreams.indexOf(stream) === -1) { + pc.remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = stream; + window.setTimeout(function() { + pc._dispatchEvent('addstream', event); + }); + } + + receiverList.forEach(function(item) { + var track = item[0]; + var receiver = item[1]; + if (stream.id !== item[2].id) { + return; + } + fireAddTrack(pc, track, receiver, [stream]); + }); + } + }); + receiverList.forEach(function(item) { + if (item[2]) { + return; + } + fireAddTrack(pc, item[0], item[1], []); + }); + + // check whether addIceCandidate({}) was called within four seconds after + // setRemoteDescription. + window.setTimeout(function() { + if (!(pc && pc.transceivers)) { + return; + } + pc.transceivers.forEach(function(transceiver) { + if (transceiver.iceTransport && + transceiver.iceTransport.state === 'new' && + transceiver.iceTransport.getRemoteCandidates().length > 0) { + console.warn('Timeout for addRemoteCandidate. Consider sending ' + + 'an end-of-candidates notification'); + transceiver.iceTransport.addRemoteCandidate({}); + } + }); + }, 4000); + + return Promise.resolve(); + }; + + RTCPeerConnection.prototype.close = function() { + this.transceivers.forEach(function(transceiver) { + /* not yet + if (transceiver.iceGatherer) { + transceiver.iceGatherer.close(); + } + */ + if (transceiver.iceTransport) { + transceiver.iceTransport.stop(); + } + if (transceiver.dtlsTransport) { + transceiver.dtlsTransport.stop(); + } + if (transceiver.rtpSender) { + transceiver.rtpSender.stop(); + } + if (transceiver.rtpReceiver) { + transceiver.rtpReceiver.stop(); + } + }); + // FIXME: clean up tracks, local streams, remote streams, etc + this._isClosed = true; + this._updateSignalingState('closed'); + }; + + // Update the signaling state. + RTCPeerConnection.prototype._updateSignalingState = function(newState) { + this.signalingState = newState; + var event = new Event('signalingstatechange'); + this._dispatchEvent('signalingstatechange', event); + }; + + // Determine whether to fire the negotiationneeded event. + RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { + var pc = this; + if (this.signalingState !== 'stable' || this.needNegotiation === true) { + return; + } + this.needNegotiation = true; + window.setTimeout(function() { + if (pc.needNegotiation) { + pc.needNegotiation = false; + var event = new Event('negotiationneeded'); + pc._dispatchEvent('negotiationneeded', event); + } + }, 0); + }; + + // Update the ice connection state. + RTCPeerConnection.prototype._updateIceConnectionState = function() { + var newState; + var states = { + 'new': 0, + closed: 0, + checking: 0, + connected: 0, + completed: 0, + disconnected: 0, + failed: 0 + }; + this.transceivers.forEach(function(transceiver) { + if (transceiver.iceTransport && !transceiver.rejected) { + states[transceiver.iceTransport.state]++; + } + }); + + newState = 'new'; + if (states.failed > 0) { + newState = 'failed'; + } else if (states.checking > 0) { + newState = 'checking'; + } else if (states.disconnected > 0) { + newState = 'disconnected'; + } else if (states.new > 0) { + newState = 'new'; + } else if (states.connected > 0) { + newState = 'connected'; + } else if (states.completed > 0) { + newState = 'completed'; + } + + if (newState !== this.iceConnectionState) { + this.iceConnectionState = newState; + var event = new Event('iceconnectionstatechange'); + this._dispatchEvent('iceconnectionstatechange', event); + } + }; + + // Update the connection state. + RTCPeerConnection.prototype._updateConnectionState = function() { + var newState; + var states = { + 'new': 0, + closed: 0, + connecting: 0, + connected: 0, + completed: 0, + disconnected: 0, + failed: 0 + }; + this.transceivers.forEach(function(transceiver) { + if (transceiver.iceTransport && transceiver.dtlsTransport && + !transceiver.rejected) { + states[transceiver.iceTransport.state]++; + states[transceiver.dtlsTransport.state]++; + } + }); + // ICETransport.completed and connected are the same for this purpose. + states.connected += states.completed; + + newState = 'new'; + if (states.failed > 0) { + newState = 'failed'; + } else if (states.connecting > 0) { + newState = 'connecting'; + } else if (states.disconnected > 0) { + newState = 'disconnected'; + } else if (states.new > 0) { + newState = 'new'; + } else if (states.connected > 0) { + newState = 'connected'; + } + + if (newState !== this.connectionState) { + this.connectionState = newState; + var event = new Event('connectionstatechange'); + this._dispatchEvent('connectionstatechange', event); + } + }; + + RTCPeerConnection.prototype.createOffer = function() { + var pc = this; + + if (pc._isClosed) { + return Promise.reject(makeError('InvalidStateError', + 'Can not call createOffer after close')); + } + + var numAudioTracks = pc.transceivers.filter(function(t) { + return t.kind === 'audio'; + }).length; + var numVideoTracks = pc.transceivers.filter(function(t) { + return t.kind === 'video'; + }).length; + + // Determine number of audio and video tracks we need to send/recv. + var offerOptions = arguments[0]; + if (offerOptions) { + // Reject Chrome legacy constraints. + if (offerOptions.mandatory || offerOptions.optional) { + throw new TypeError( + 'Legacy mandatory/optional constraints not supported.'); + } + if (offerOptions.offerToReceiveAudio !== undefined) { + if (offerOptions.offerToReceiveAudio === true) { + numAudioTracks = 1; + } else if (offerOptions.offerToReceiveAudio === false) { + numAudioTracks = 0; + } else { + numAudioTracks = offerOptions.offerToReceiveAudio; + } + } + if (offerOptions.offerToReceiveVideo !== undefined) { + if (offerOptions.offerToReceiveVideo === true) { + numVideoTracks = 1; + } else if (offerOptions.offerToReceiveVideo === false) { + numVideoTracks = 0; + } else { + numVideoTracks = offerOptions.offerToReceiveVideo; + } + } + } + + pc.transceivers.forEach(function(transceiver) { + if (transceiver.kind === 'audio') { + numAudioTracks--; + if (numAudioTracks < 0) { + transceiver.wantReceive = false; + } + } else if (transceiver.kind === 'video') { + numVideoTracks--; + if (numVideoTracks < 0) { + transceiver.wantReceive = false; + } + } + }); + + // Create M-lines for recvonly streams. + while (numAudioTracks > 0 || numVideoTracks > 0) { + if (numAudioTracks > 0) { + pc._createTransceiver('audio'); + numAudioTracks--; + } + if (numVideoTracks > 0) { + pc._createTransceiver('video'); + numVideoTracks--; + } + } + + var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, + pc._sdpSessionVersion++); + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { + // For each track, create an ice gatherer, ice transport, + // dtls transport, potentially rtpsender and rtpreceiver. + var track = transceiver.track; + var kind = transceiver.kind; + var mid = transceiver.mid || SDPUtils.generateIdentifier(); + transceiver.mid = mid; + + if (!transceiver.iceGatherer) { + transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, + pc.usingBundle); + } + + var localCapabilities = window.RTCRtpSender.getCapabilities(kind); + // filter RTX until additional stuff needed for RTX is implemented + // in adapter.js + if (edgeVersion < 15019) { + localCapabilities.codecs = localCapabilities.codecs.filter( + function(codec) { + return codec.name !== 'rtx'; + }); + } + localCapabilities.codecs.forEach(function(codec) { + // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 + // by adding level-asymmetry-allowed=1 + if (codec.name === 'H264' && + codec.parameters['level-asymmetry-allowed'] === undefined) { + codec.parameters['level-asymmetry-allowed'] = '1'; + } + + // for subsequent offers, we might have to re-use the payload + // type of the last offer. + if (transceiver.remoteCapabilities && + transceiver.remoteCapabilities.codecs) { + transceiver.remoteCapabilities.codecs.forEach(function(remoteCodec) { + if (codec.name.toLowerCase() === remoteCodec.name.toLowerCase() && + codec.clockRate === remoteCodec.clockRate) { + codec.preferredPayloadType = remoteCodec.payloadType; + } + }); + } + }); + localCapabilities.headerExtensions.forEach(function(hdrExt) { + var remoteExtensions = transceiver.remoteCapabilities && + transceiver.remoteCapabilities.headerExtensions || []; + remoteExtensions.forEach(function(rHdrExt) { + if (hdrExt.uri === rHdrExt.uri) { + hdrExt.id = rHdrExt.id; + } + }); + }); + + // generate an ssrc now, to be used later in rtpSender.send + var sendEncodingParameters = transceiver.sendEncodingParameters || [{ + ssrc: (2 * sdpMLineIndex + 1) * 1001 + }]; + if (track) { + // add RTX + if (edgeVersion >= 15019 && kind === 'video' && + !sendEncodingParameters[0].rtx) { + sendEncodingParameters[0].rtx = { + ssrc: sendEncodingParameters[0].ssrc + 1 + }; + } + } + + if (transceiver.wantReceive) { + transceiver.rtpReceiver = new window.RTCRtpReceiver( + transceiver.dtlsTransport, kind); + } + + transceiver.localCapabilities = localCapabilities; + transceiver.sendEncodingParameters = sendEncodingParameters; + }); + + // always offer BUNDLE and dispose on return if not supported. + if (pc._config.bundlePolicy !== 'max-compat') { + sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) { + return t.mid; + }).join(' ') + '\r\n'; + } + sdp += 'a=ice-options:trickle\r\n'; + + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { + sdp += writeMediaSection(transceiver, transceiver.localCapabilities, + 'offer', transceiver.stream, pc._dtlsRole); + sdp += 'a=rtcp-rsize\r\n'; + + if (transceiver.iceGatherer && pc.iceGatheringState !== 'new' && + (sdpMLineIndex === 0 || !pc.usingBundle)) { + transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) { + cand.component = 1; + sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n'; + }); + + if (transceiver.iceGatherer.state === 'completed') { + sdp += 'a=end-of-candidates\r\n'; + } + } + }); + + var desc = new window.RTCSessionDescription({ + type: 'offer', + sdp: sdp + }); + return Promise.resolve(desc); + }; + + RTCPeerConnection.prototype.createAnswer = function() { + var pc = this; + + if (pc._isClosed) { + return Promise.reject(makeError('InvalidStateError', + 'Can not call createAnswer after close')); + } + + if (!(pc.signalingState === 'have-remote-offer' || + pc.signalingState === 'have-local-pranswer')) { + return Promise.reject(makeError('InvalidStateError', + 'Can not call createAnswer in signalingState ' + pc.signalingState)); + } + + var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, + pc._sdpSessionVersion++); + if (pc.usingBundle) { + sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) { + return t.mid; + }).join(' ') + '\r\n'; + } + sdp += 'a=ice-options:trickle\r\n'; + + var mediaSectionsInOffer = SDPUtils.getMediaSections( + pc._remoteDescription.sdp).length; + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { + if (sdpMLineIndex + 1 > mediaSectionsInOffer) { + return; + } + if (transceiver.rejected) { + if (transceiver.kind === 'application') { + if (transceiver.protocol === 'DTLS/SCTP') { // legacy fmt + sdp += 'm=application 0 DTLS/SCTP 5000\r\n'; + } else { + sdp += 'm=application 0 ' + transceiver.protocol + + ' webrtc-datachannel\r\n'; + } + } else if (transceiver.kind === 'audio') { + sdp += 'm=audio 0 UDP/TLS/RTP/SAVPF 0\r\n' + + 'a=rtpmap:0 PCMU/8000\r\n'; + } else if (transceiver.kind === 'video') { + sdp += 'm=video 0 UDP/TLS/RTP/SAVPF 120\r\n' + + 'a=rtpmap:120 VP8/90000\r\n'; + } + sdp += 'c=IN IP4 0.0.0.0\r\n' + + 'a=inactive\r\n' + + 'a=mid:' + transceiver.mid + '\r\n'; + return; + } + + // FIXME: look at direction. + if (transceiver.stream) { + var localTrack; + if (transceiver.kind === 'audio') { + localTrack = transceiver.stream.getAudioTracks()[0]; + } else if (transceiver.kind === 'video') { + localTrack = transceiver.stream.getVideoTracks()[0]; + } + if (localTrack) { + // add RTX + if (edgeVersion >= 15019 && transceiver.kind === 'video' && + !transceiver.sendEncodingParameters[0].rtx) { + transceiver.sendEncodingParameters[0].rtx = { + ssrc: transceiver.sendEncodingParameters[0].ssrc + 1 + }; + } + } + } + + // Calculate intersection of capabilities. + var commonCapabilities = getCommonCapabilities( + transceiver.localCapabilities, + transceiver.remoteCapabilities); + + var hasRtx = commonCapabilities.codecs.filter(function(c) { + return c.name.toLowerCase() === 'rtx'; + }).length; + if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { + delete transceiver.sendEncodingParameters[0].rtx; + } + + sdp += writeMediaSection(transceiver, commonCapabilities, + 'answer', transceiver.stream, pc._dtlsRole); + if (transceiver.rtcpParameters && + transceiver.rtcpParameters.reducedSize) { + sdp += 'a=rtcp-rsize\r\n'; + } + }); + + var desc = new window.RTCSessionDescription({ + type: 'answer', + sdp: sdp + }); + return Promise.resolve(desc); + }; + + RTCPeerConnection.prototype.addIceCandidate = function(candidate) { + var pc = this; + var sections; + if (candidate && !(candidate.sdpMLineIndex !== undefined || + candidate.sdpMid)) { + return Promise.reject(new TypeError('sdpMLineIndex or sdpMid required')); + } + + // TODO: needs to go into ops queue. + return new Promise(function(resolve, reject) { + if (!pc._remoteDescription) { + return reject(makeError('InvalidStateError', + 'Can not add ICE candidate without a remote description')); + } else if (!candidate || candidate.candidate === '') { + for (var j = 0; j < pc.transceivers.length; j++) { + if (pc.transceivers[j].rejected) { + continue; + } + pc.transceivers[j].iceTransport.addRemoteCandidate({}); + sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp); + sections[j] += 'a=end-of-candidates\r\n'; + pc._remoteDescription.sdp = + SDPUtils.getDescription(pc._remoteDescription.sdp) + + sections.join(''); + if (pc.usingBundle) { + break; + } + } + } else { + var sdpMLineIndex = candidate.sdpMLineIndex; + if (candidate.sdpMid) { + for (var i = 0; i < pc.transceivers.length; i++) { + if (pc.transceivers[i].mid === candidate.sdpMid) { + sdpMLineIndex = i; + break; + } + } + } + var transceiver = pc.transceivers[sdpMLineIndex]; + if (transceiver) { + if (transceiver.rejected) { + return resolve(); + } + var cand = Object.keys(candidate.candidate).length > 0 ? + SDPUtils.parseCandidate(candidate.candidate) : {}; + // Ignore Chrome's invalid candidates since Edge does not like them. + if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { + return resolve(); + } + // Ignore RTCP candidates, we assume RTCP-MUX. + if (cand.component && cand.component !== 1) { + return resolve(); + } + // when using bundle, avoid adding candidates to the wrong + // ice transport. And avoid adding candidates added in the SDP. + if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && + transceiver.iceTransport !== pc.transceivers[0].iceTransport)) { + if (!maybeAddCandidate(transceiver.iceTransport, cand)) { + return reject(makeError('OperationError', + 'Can not add ICE candidate')); + } + } + + // update the remoteDescription. + var candidateString = candidate.candidate.trim(); + if (candidateString.indexOf('a=') === 0) { + candidateString = candidateString.substr(2); + } + sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp); + sections[sdpMLineIndex] += 'a=' + + (cand.type ? candidateString : 'end-of-candidates') + + '\r\n'; + pc._remoteDescription.sdp = + SDPUtils.getDescription(pc._remoteDescription.sdp) + + sections.join(''); + } else { + return reject(makeError('OperationError', + 'Can not add ICE candidate')); + } + } + resolve(); + }); + }; + + RTCPeerConnection.prototype.getStats = function(selector) { + if (selector && selector instanceof window.MediaStreamTrack) { + var senderOrReceiver = null; + this.transceivers.forEach(function(transceiver) { + if (transceiver.rtpSender && + transceiver.rtpSender.track === selector) { + senderOrReceiver = transceiver.rtpSender; + } else if (transceiver.rtpReceiver && + transceiver.rtpReceiver.track === selector) { + senderOrReceiver = transceiver.rtpReceiver; + } + }); + if (!senderOrReceiver) { + throw makeError('InvalidAccessError', 'Invalid selector.'); + } + return senderOrReceiver.getStats(); + } + + var promises = []; + this.transceivers.forEach(function(transceiver) { + ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', + 'dtlsTransport'].forEach(function(method) { + if (transceiver[method]) { + promises.push(transceiver[method].getStats()); + } + }); + }); + return Promise.all(promises).then(function(allStats) { + var results = new Map(); + allStats.forEach(function(stats) { + stats.forEach(function(stat) { + results.set(stat.id, stat); + }); + }); + return results; + }); + }; + + // fix low-level stat names and return Map instead of object. + var ortcObjects = ['RTCRtpSender', 'RTCRtpReceiver', 'RTCIceGatherer', + 'RTCIceTransport', 'RTCDtlsTransport']; + ortcObjects.forEach(function(ortcObjectName) { + var obj = window[ortcObjectName]; + if (obj && obj.prototype && obj.prototype.getStats) { + var nativeGetstats = obj.prototype.getStats; + obj.prototype.getStats = function() { + return nativeGetstats.apply(this) + .then(function(nativeStats) { + var mapStats = new Map(); + Object.keys(nativeStats).forEach(function(id) { + nativeStats[id].type = fixStatsType(nativeStats[id]); + mapStats.set(id, nativeStats[id]); + }); + return mapStats; + }); + }; + } + }); + + // legacy callback shims. Should be moved to adapter.js some days. + var methods = ['createOffer', 'createAnswer']; + methods.forEach(function(method) { + var nativeMethod = RTCPeerConnection.prototype[method]; + RTCPeerConnection.prototype[method] = function() { + var args = arguments; + if (typeof args[0] === 'function' || + typeof args[1] === 'function') { // legacy + return nativeMethod.apply(this, [arguments[2]]) + .then(function(description) { + if (typeof args[0] === 'function') { + args[0].apply(null, [description]); + } + }, function(error) { + if (typeof args[1] === 'function') { + args[1].apply(null, [error]); + } + }); + } + return nativeMethod.apply(this, arguments); + }; + }); + + methods = ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']; + methods.forEach(function(method) { + var nativeMethod = RTCPeerConnection.prototype[method]; + RTCPeerConnection.prototype[method] = function() { + var args = arguments; + if (typeof args[1] === 'function' || + typeof args[2] === 'function') { // legacy + return nativeMethod.apply(this, arguments) + .then(function() { + if (typeof args[1] === 'function') { + args[1].apply(null); + } + }, function(error) { + if (typeof args[2] === 'function') { + args[2].apply(null, [error]); + } + }); + } + return nativeMethod.apply(this, arguments); + }; + }); + + // getStats is special. It doesn't have a spec legacy method yet we support + // getStats(something, cb) without error callbacks. + ['getStats'].forEach(function(method) { + var nativeMethod = RTCPeerConnection.prototype[method]; + RTCPeerConnection.prototype[method] = function() { + var args = arguments; + if (typeof args[1] === 'function') { + return nativeMethod.apply(this, arguments) + .then(function() { + if (typeof args[1] === 'function') { + args[1].apply(null); + } + }); + } + return nativeMethod.apply(this, arguments); + }; + }); + + return RTCPeerConnection; +}; + +},{"sdp":17}],17:[function(require,module,exports){ +/* eslint-env node */ +'use strict'; + +// SDP helpers. +var SDPUtils = {}; + +// Generate an alphanumeric identifier for cname or mids. +// TODO: use UUIDs instead? https://gist.github.com/jed/982883 +SDPUtils.generateIdentifier = function() { + return Math.random().toString(36).substr(2, 10); +}; + +// The RTCP CNAME used by all peerconnections from the same JS. +SDPUtils.localCName = SDPUtils.generateIdentifier(); + +// Splits SDP into lines, dealing with both CRLF and LF. +SDPUtils.splitLines = function(blob) { + return blob.trim().split('\n').map(function(line) { + return line.trim(); + }); +}; +// Splits SDP into sessionpart and mediasections. Ensures CRLF. +SDPUtils.splitSections = function(blob) { + var parts = blob.split('\nm='); + return parts.map(function(part, index) { + return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; + }); +}; + +// returns the session description. +SDPUtils.getDescription = function(blob) { + var sections = SDPUtils.splitSections(blob); + return sections && sections[0]; +}; + +// returns the individual media sections. +SDPUtils.getMediaSections = function(blob) { + var sections = SDPUtils.splitSections(blob); + sections.shift(); + return sections; +}; + +// Returns lines that start with a certain prefix. +SDPUtils.matchPrefix = function(blob, prefix) { + return SDPUtils.splitLines(blob).filter(function(line) { + return line.indexOf(prefix) === 0; + }); +}; + +// Parses an ICE candidate line. Sample input: +// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 +// rport 55996" +SDPUtils.parseCandidate = function(line) { + var parts; + // Parse both variants. + if (line.indexOf('a=candidate:') === 0) { + parts = line.substring(12).split(' '); + } else { + parts = line.substring(10).split(' '); + } + + var candidate = { + foundation: parts[0], + component: parseInt(parts[1], 10), + protocol: parts[2].toLowerCase(), + priority: parseInt(parts[3], 10), + ip: parts[4], + address: parts[4], // address is an alias for ip. + port: parseInt(parts[5], 10), + // skip parts[6] == 'typ' + type: parts[7] + }; + + for (var i = 8; i < parts.length; i += 2) { + switch (parts[i]) { + case 'raddr': + candidate.relatedAddress = parts[i + 1]; + break; + case 'rport': + candidate.relatedPort = parseInt(parts[i + 1], 10); + break; + case 'tcptype': + candidate.tcpType = parts[i + 1]; + break; + case 'ufrag': + candidate.ufrag = parts[i + 1]; // for backward compability. + candidate.usernameFragment = parts[i + 1]; + break; + default: // extension handling, in particular ufrag + candidate[parts[i]] = parts[i + 1]; + break; + } + } + return candidate; +}; + +// Translates a candidate object into SDP candidate attribute. +SDPUtils.writeCandidate = function(candidate) { + var sdp = []; + sdp.push(candidate.foundation); + sdp.push(candidate.component); + sdp.push(candidate.protocol.toUpperCase()); + sdp.push(candidate.priority); + sdp.push(candidate.address || candidate.ip); + sdp.push(candidate.port); + + var type = candidate.type; + sdp.push('typ'); + sdp.push(type); + if (type !== 'host' && candidate.relatedAddress && + candidate.relatedPort) { + sdp.push('raddr'); + sdp.push(candidate.relatedAddress); + sdp.push('rport'); + sdp.push(candidate.relatedPort); + } + if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { + sdp.push('tcptype'); + sdp.push(candidate.tcpType); + } + if (candidate.usernameFragment || candidate.ufrag) { + sdp.push('ufrag'); + sdp.push(candidate.usernameFragment || candidate.ufrag); + } + return 'candidate:' + sdp.join(' '); +}; + +// Parses an ice-options line, returns an array of option tags. +// a=ice-options:foo bar +SDPUtils.parseIceOptions = function(line) { + return line.substr(14).split(' '); +}; + +// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: +// a=rtpmap:111 opus/48000/2 +SDPUtils.parseRtpMap = function(line) { + var parts = line.substr(9).split(' '); + var parsed = { + payloadType: parseInt(parts.shift(), 10) // was: id + }; + + parts = parts[0].split('/'); + + parsed.name = parts[0]; + parsed.clockRate = parseInt(parts[1], 10); // was: clockrate + parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1; + // legacy alias, got renamed back to channels in ORTC. + parsed.numChannels = parsed.channels; + return parsed; +}; + +// Generate an a=rtpmap line from RTCRtpCodecCapability or +// RTCRtpCodecParameters. +SDPUtils.writeRtpMap = function(codec) { + var pt = codec.payloadType; + if (codec.preferredPayloadType !== undefined) { + pt = codec.preferredPayloadType; + } + var channels = codec.channels || codec.numChannels || 1; + return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + + (channels !== 1 ? '/' + channels : '') + '\r\n'; +}; + +// Parses an a=extmap line (headerextension from RFC 5285). Sample input: +// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset +// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset +SDPUtils.parseExtmap = function(line) { + var parts = line.substr(9).split(' '); + return { + id: parseInt(parts[0], 10), + direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', + uri: parts[1] + }; +}; + +// Generates a=extmap line from RTCRtpHeaderExtensionParameters or +// RTCRtpHeaderExtension. +SDPUtils.writeExtmap = function(headerExtension) { + return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + + (headerExtension.direction && headerExtension.direction !== 'sendrecv' + ? '/' + headerExtension.direction + : '') + + ' ' + headerExtension.uri + '\r\n'; +}; + +// Parses an ftmp line, returns dictionary. Sample input: +// a=fmtp:96 vbr=on;cng=on +// Also deals with vbr=on; cng=on +SDPUtils.parseFmtp = function(line) { + var parsed = {}; + var kv; + var parts = line.substr(line.indexOf(' ') + 1).split(';'); + for (var j = 0; j < parts.length; j++) { + kv = parts[j].trim().split('='); + parsed[kv[0].trim()] = kv[1]; + } + return parsed; +}; + +// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters. +SDPUtils.writeFmtp = function(codec) { + var line = ''; + var pt = codec.payloadType; + if (codec.preferredPayloadType !== undefined) { + pt = codec.preferredPayloadType; + } + if (codec.parameters && Object.keys(codec.parameters).length) { + var params = []; + Object.keys(codec.parameters).forEach(function(param) { + if (codec.parameters[param]) { + params.push(param + '=' + codec.parameters[param]); + } else { + params.push(param); + } + }); + line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; + } + return line; +}; + +// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: +// a=rtcp-fb:98 nack rpsi +SDPUtils.parseRtcpFb = function(line) { + var parts = line.substr(line.indexOf(' ') + 1).split(' '); + return { + type: parts.shift(), + parameter: parts.join(' ') + }; +}; +// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. +SDPUtils.writeRtcpFb = function(codec) { + var lines = ''; + var pt = codec.payloadType; + if (codec.preferredPayloadType !== undefined) { + pt = codec.preferredPayloadType; + } + if (codec.rtcpFeedback && codec.rtcpFeedback.length) { + // FIXME: special handling for trr-int? + codec.rtcpFeedback.forEach(function(fb) { + lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + + (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + + '\r\n'; + }); + } + return lines; +}; + +// Parses an RFC 5576 ssrc media attribute. Sample input: +// a=ssrc:3735928559 cname:something +SDPUtils.parseSsrcMedia = function(line) { + var sp = line.indexOf(' '); + var parts = { + ssrc: parseInt(line.substr(7, sp - 7), 10) + }; + var colon = line.indexOf(':', sp); + if (colon > -1) { + parts.attribute = line.substr(sp + 1, colon - sp - 1); + parts.value = line.substr(colon + 1); + } else { + parts.attribute = line.substr(sp + 1); + } + return parts; +}; + +SDPUtils.parseSsrcGroup = function(line) { + var parts = line.substr(13).split(' '); + return { + semantics: parts.shift(), + ssrcs: parts.map(function(ssrc) { + return parseInt(ssrc, 10); + }) + }; +}; + +// Extracts the MID (RFC 5888) from a media section. +// returns the MID or undefined if no mid line was found. +SDPUtils.getMid = function(mediaSection) { + var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; + if (mid) { + return mid.substr(6); + } +}; + +SDPUtils.parseFingerprint = function(line) { + var parts = line.substr(14).split(' '); + return { + algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. + value: parts[1] + }; +}; + +// Extracts DTLS parameters from SDP media section or sessionpart. +// FIXME: for consistency with other functions this should only +// get the fingerprint line as input. See also getIceParameters. +SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { + var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, + 'a=fingerprint:'); + // Note: a=setup line is ignored since we use the 'auto' role. + // Note2: 'algorithm' is not case sensitive except in Edge. + return { + role: 'auto', + fingerprints: lines.map(SDPUtils.parseFingerprint) + }; +}; + +// Serializes DTLS parameters to SDP. +SDPUtils.writeDtlsParameters = function(params, setupType) { + var sdp = 'a=setup:' + setupType + '\r\n'; + params.fingerprints.forEach(function(fp) { + sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; + }); + return sdp; +}; + +// Parses a=crypto lines into +// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members +SDPUtils.parseCryptoLine = function(line) { + var parts = line.substr(9).split(' '); + return { + tag: parseInt(parts[0], 10), + cryptoSuite: parts[1], + keyParams: parts[2], + sessionParams: parts.slice(3), + }; +}; + +SDPUtils.writeCryptoLine = function(parameters) { + return 'a=crypto:' + parameters.tag + ' ' + + parameters.cryptoSuite + ' ' + + (typeof parameters.keyParams === 'object' + ? SDPUtils.writeCryptoKeyParams(parameters.keyParams) + : parameters.keyParams) + + (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') + + '\r\n'; +}; + +// Parses the crypto key parameters into +// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam* +SDPUtils.parseCryptoKeyParams = function(keyParams) { + if (keyParams.indexOf('inline:') !== 0) { + return null; + } + var parts = keyParams.substr(7).split('|'); + return { + keyMethod: 'inline', + keySalt: parts[0], + lifeTime: parts[1], + mkiValue: parts[2] ? parts[2].split(':')[0] : undefined, + mkiLength: parts[2] ? parts[2].split(':')[1] : undefined, + }; +}; + +SDPUtils.writeCryptoKeyParams = function(keyParams) { + return keyParams.keyMethod + ':' + + keyParams.keySalt + + (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') + + (keyParams.mkiValue && keyParams.mkiLength + ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength + : ''); +}; + +// Extracts all SDES paramters. +SDPUtils.getCryptoParameters = function(mediaSection, sessionpart) { + var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, + 'a=crypto:'); + return lines.map(SDPUtils.parseCryptoLine); +}; + +// Parses ICE information from SDP media section or sessionpart. +// FIXME: for consistency with other functions this should only +// get the ice-ufrag and ice-pwd lines as input. +SDPUtils.getIceParameters = function(mediaSection, sessionpart) { + var ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart, + 'a=ice-ufrag:')[0]; + var pwd = SDPUtils.matchPrefix(mediaSection + sessionpart, + 'a=ice-pwd:')[0]; + if (!(ufrag && pwd)) { + return null; + } + return { + usernameFragment: ufrag.substr(12), + password: pwd.substr(10), + }; +}; + +// Serializes ICE parameters to SDP. +SDPUtils.writeIceParameters = function(params) { + return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + + 'a=ice-pwd:' + params.password + '\r\n'; +}; + +// Parses the SDP media section and returns RTCRtpParameters. +SDPUtils.parseRtpParameters = function(mediaSection) { + var description = { + codecs: [], + headerExtensions: [], + fecMechanisms: [], + rtcp: [] + }; + var lines = SDPUtils.splitLines(mediaSection); + var mline = lines[0].split(' '); + for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..] + var pt = mline[i]; + var rtpmapline = SDPUtils.matchPrefix( + mediaSection, 'a=rtpmap:' + pt + ' ')[0]; + if (rtpmapline) { + var codec = SDPUtils.parseRtpMap(rtpmapline); + var fmtps = SDPUtils.matchPrefix( + mediaSection, 'a=fmtp:' + pt + ' '); + // Only the first a=fmtp: is considered. + codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; + codec.rtcpFeedback = SDPUtils.matchPrefix( + mediaSection, 'a=rtcp-fb:' + pt + ' ') + .map(SDPUtils.parseRtcpFb); + description.codecs.push(codec); + // parse FEC mechanisms from rtpmap lines. + switch (codec.name.toUpperCase()) { + case 'RED': + case 'ULPFEC': + description.fecMechanisms.push(codec.name.toUpperCase()); + break; + default: // only RED and ULPFEC are recognized as FEC mechanisms. + break; + } + } + } + SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) { + description.headerExtensions.push(SDPUtils.parseExtmap(line)); + }); + // FIXME: parse rtcp. + return description; +}; + +// Generates parts of the SDP media section describing the capabilities / +// parameters. +SDPUtils.writeRtpDescription = function(kind, caps) { + var sdp = ''; + + // Build the mline. + sdp += 'm=' + kind + ' '; + sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. + sdp += ' UDP/TLS/RTP/SAVPF '; + sdp += caps.codecs.map(function(codec) { + if (codec.preferredPayloadType !== undefined) { + return codec.preferredPayloadType; + } + return codec.payloadType; + }).join(' ') + '\r\n'; + + sdp += 'c=IN IP4 0.0.0.0\r\n'; + sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; + + // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. + caps.codecs.forEach(function(codec) { + sdp += SDPUtils.writeRtpMap(codec); + sdp += SDPUtils.writeFmtp(codec); + sdp += SDPUtils.writeRtcpFb(codec); + }); + var maxptime = 0; + caps.codecs.forEach(function(codec) { + if (codec.maxptime > maxptime) { + maxptime = codec.maxptime; + } + }); + if (maxptime > 0) { + sdp += 'a=maxptime:' + maxptime + '\r\n'; + } + sdp += 'a=rtcp-mux\r\n'; + + if (caps.headerExtensions) { + caps.headerExtensions.forEach(function(extension) { + sdp += SDPUtils.writeExtmap(extension); + }); + } + // FIXME: write fecMechanisms. + return sdp; +}; + +// Parses the SDP media section and returns an array of +// RTCRtpEncodingParameters. +SDPUtils.parseRtpEncodingParameters = function(mediaSection) { + var encodingParameters = []; + var description = SDPUtils.parseRtpParameters(mediaSection); + var hasRed = description.fecMechanisms.indexOf('RED') !== -1; + var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; + + // filter a=ssrc:... cname:, ignore PlanB-msid + var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') + .map(function(line) { + return SDPUtils.parseSsrcMedia(line); + }) + .filter(function(parts) { + return parts.attribute === 'cname'; + }); + var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; + var secondarySsrc; + + var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID') + .map(function(line) { + var parts = line.substr(17).split(' '); + return parts.map(function(part) { + return parseInt(part, 10); + }); + }); + if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { + secondarySsrc = flows[0][1]; + } + + description.codecs.forEach(function(codec) { + if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { + var encParam = { + ssrc: primarySsrc, + codecPayloadType: parseInt(codec.parameters.apt, 10) + }; + if (primarySsrc && secondarySsrc) { + encParam.rtx = {ssrc: secondarySsrc}; + } + encodingParameters.push(encParam); + if (hasRed) { + encParam = JSON.parse(JSON.stringify(encParam)); + encParam.fec = { + ssrc: primarySsrc, + mechanism: hasUlpfec ? 'red+ulpfec' : 'red' + }; + encodingParameters.push(encParam); + } + } + }); + if (encodingParameters.length === 0 && primarySsrc) { + encodingParameters.push({ + ssrc: primarySsrc + }); + } + + // we support both b=AS and b=TIAS but interpret AS as TIAS. + var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); + if (bandwidth.length) { + if (bandwidth[0].indexOf('b=TIAS:') === 0) { + bandwidth = parseInt(bandwidth[0].substr(7), 10); + } else if (bandwidth[0].indexOf('b=AS:') === 0) { + // use formula from JSEP to convert b=AS to TIAS value. + bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 + - (50 * 40 * 8); + } else { + bandwidth = undefined; + } + encodingParameters.forEach(function(params) { + params.maxBitrate = bandwidth; + }); + } + return encodingParameters; +}; + +// parses http://draft.ortc.org/#rtcrtcpparameters* +SDPUtils.parseRtcpParameters = function(mediaSection) { + var rtcpParameters = {}; + + // Gets the first SSRC. Note tha with RTX there might be multiple + // SSRCs. + var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') + .map(function(line) { + return SDPUtils.parseSsrcMedia(line); + }) + .filter(function(obj) { + return obj.attribute === 'cname'; + })[0]; + if (remoteSsrc) { + rtcpParameters.cname = remoteSsrc.value; + rtcpParameters.ssrc = remoteSsrc.ssrc; + } + + // Edge uses the compound attribute instead of reducedSize + // compound is !reducedSize + var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); + rtcpParameters.reducedSize = rsize.length > 0; + rtcpParameters.compound = rsize.length === 0; + + // parses the rtcp-mux attr褨bute. + // Note that Edge does not support unmuxed RTCP. + var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); + rtcpParameters.mux = mux.length > 0; + + return rtcpParameters; +}; + +// parses either a=msid: or a=ssrc:... msid lines and returns +// the id of the MediaStream and MediaStreamTrack. +SDPUtils.parseMsid = function(mediaSection) { + var parts; + var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); + if (spec.length === 1) { + parts = spec[0].substr(7).split(' '); + return {stream: parts[0], track: parts[1]}; + } + var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') + .map(function(line) { + return SDPUtils.parseSsrcMedia(line); + }) + .filter(function(msidParts) { + return msidParts.attribute === 'msid'; + }); + if (planB.length > 0) { + parts = planB[0].value.split(' '); + return {stream: parts[0], track: parts[1]}; + } +}; + +// SCTP +// parses draft-ietf-mmusic-sctp-sdp-26 first and falls back +// to draft-ietf-mmusic-sctp-sdp-05 +SDPUtils.parseSctpDescription = function(mediaSection) { + var mline = SDPUtils.parseMLine(mediaSection); + var maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:'); + var maxMessageSize; + if (maxSizeLine.length > 0) { + maxMessageSize = parseInt(maxSizeLine[0].substr(19), 10); + } + if (isNaN(maxMessageSize)) { + maxMessageSize = 65536; + } + var sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:'); + if (sctpPort.length > 0) { + return { + port: parseInt(sctpPort[0].substr(12), 10), + protocol: mline.fmt, + maxMessageSize: maxMessageSize + }; + } + var sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:'); + if (sctpMapLines.length > 0) { + var parts = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:')[0] + .substr(10) + .split(' '); + return { + port: parseInt(parts[0], 10), + protocol: parts[1], + maxMessageSize: maxMessageSize + }; + } +}; + +// SCTP +// outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers +// support by now receiving in this format, unless we originally parsed +// as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line +// protocol of DTLS/SCTP -- without UDP/ or TCP/) +SDPUtils.writeSctpDescription = function(media, sctp) { + var output = []; + if (media.protocol !== 'DTLS/SCTP') { + output = [ + 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\r\n', + 'c=IN IP4 0.0.0.0\r\n', + 'a=sctp-port:' + sctp.port + '\r\n' + ]; + } else { + output = [ + 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\r\n', + 'c=IN IP4 0.0.0.0\r\n', + 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\r\n' + ]; + } + if (sctp.maxMessageSize !== undefined) { + output.push('a=max-message-size:' + sctp.maxMessageSize + '\r\n'); + } + return output.join(''); +}; + +// Generate a session ID for SDP. +// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 +// recommends using a cryptographically random +ve 64-bit value +// but right now this should be acceptable and within the right range +SDPUtils.generateSessionId = function() { + return Math.random().toString().substr(2, 21); +}; + +// Write boilder plate for start of SDP +// sessId argument is optional - if not supplied it will +// be generated randomly +// sessVersion is optional and defaults to 2 +// sessUser is optional and defaults to 'thisisadapterortc' +SDPUtils.writeSessionBoilerplate = function(sessId, sessVer, sessUser) { + var sessionId; + var version = sessVer !== undefined ? sessVer : 2; + if (sessId) { + sessionId = sessId; + } else { + sessionId = SDPUtils.generateSessionId(); + } + var user = sessUser || 'thisisadapterortc'; + // FIXME: sess-id should be an NTP timestamp. + return 'v=0\r\n' + + 'o=' + user + ' ' + sessionId + ' ' + version + + ' IN IP4 127.0.0.1\r\n' + + 's=-\r\n' + + 't=0 0\r\n'; +}; + +SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) { + var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); + + // Map ICE parameters (ufrag, pwd) to SDP. + sdp += SDPUtils.writeIceParameters( + transceiver.iceGatherer.getLocalParameters()); + + // Map DTLS parameters to SDP. + sdp += SDPUtils.writeDtlsParameters( + transceiver.dtlsTransport.getLocalParameters(), + type === 'offer' ? 'actpass' : 'active'); + + sdp += 'a=mid:' + transceiver.mid + '\r\n'; + + if (transceiver.direction) { + sdp += 'a=' + transceiver.direction + '\r\n'; + } else if (transceiver.rtpSender && transceiver.rtpReceiver) { + sdp += 'a=sendrecv\r\n'; + } else if (transceiver.rtpSender) { + sdp += 'a=sendonly\r\n'; + } else if (transceiver.rtpReceiver) { + sdp += 'a=recvonly\r\n'; + } else { + sdp += 'a=inactive\r\n'; + } + + if (transceiver.rtpSender) { + // spec. + var msid = 'msid:' + stream.id + ' ' + + transceiver.rtpSender.track.id + '\r\n'; + sdp += 'a=' + msid; + + // for Chrome. + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + + ' ' + msid; + if (transceiver.sendEncodingParameters[0].rtx) { + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + + ' ' + msid; + sdp += 'a=ssrc-group:FID ' + + transceiver.sendEncodingParameters[0].ssrc + ' ' + + transceiver.sendEncodingParameters[0].rtx.ssrc + + '\r\n'; + } + } + // FIXME: this should be written by writeRtpDescription. + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + + ' cname:' + SDPUtils.localCName + '\r\n'; + if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { + sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + + ' cname:' + SDPUtils.localCName + '\r\n'; + } + return sdp; +}; + +// Gets the direction from the mediaSection or the sessionpart. +SDPUtils.getDirection = function(mediaSection, sessionpart) { + // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. + var lines = SDPUtils.splitLines(mediaSection); + for (var i = 0; i < lines.length; i++) { + switch (lines[i]) { + case 'a=sendrecv': + case 'a=sendonly': + case 'a=recvonly': + case 'a=inactive': + return lines[i].substr(2); + default: + // FIXME: What should happen here? + } + } + if (sessionpart) { + return SDPUtils.getDirection(sessionpart); + } + return 'sendrecv'; +}; + +SDPUtils.getKind = function(mediaSection) { + var lines = SDPUtils.splitLines(mediaSection); + var mline = lines[0].split(' '); + return mline[0].substr(2); +}; + +SDPUtils.isRejected = function(mediaSection) { + return mediaSection.split(' ', 2)[1] === '0'; +}; + +SDPUtils.parseMLine = function(mediaSection) { + var lines = SDPUtils.splitLines(mediaSection); + var parts = lines[0].substr(2).split(' '); + return { + kind: parts[0], + port: parseInt(parts[1], 10), + protocol: parts[2], + fmt: parts.slice(3).join(' ') + }; +}; + +SDPUtils.parseOLine = function(mediaSection) { + var line = SDPUtils.matchPrefix(mediaSection, 'o=')[0]; + var parts = line.substr(2).split(' '); + return { + username: parts[0], + sessionId: parts[1], + sessionVersion: parseInt(parts[2], 10), + netType: parts[3], + addressType: parts[4], + address: parts[5] + }; +}; + +// a very naive interpretation of a valid SDP. +SDPUtils.isValidSDP = function(blob) { + if (typeof blob !== 'string' || blob.length === 0) { + return false; + } + var lines = SDPUtils.splitLines(blob); + for (var i = 0; i < lines.length; i++) { + if (lines[i].length < 2 || lines[i].charAt(1) !== '=') { + return false; + } + // TODO: check the modifier a bit more. + } + return true; +}; + +// Expose public methods. +if (typeof module === 'object') { + module.exports = SDPUtils; +} + +},{}]},{},[1])(1) +}); diff --git a/trunk/research/players/js/adapter-7.4.0.min.js b/trunk/research/players/js/adapter-7.4.0.min.js new file mode 100644 index 0000000000..7e76156cfe --- /dev/null +++ b/trunk/research/players/js/adapter-7.4.0.min.js @@ -0,0 +1 @@ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).adapter=e()}}((function(){return function e(t,r,n){function i(o,s){if(!r[o]){if(!t[o]){var c="function"==typeof require&&require;if(!s&&c)return c(o,!0);if(a)return a(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var p=r[o]={exports:{}};t[o][0].call(p.exports,(function(e){return i(t[o][1][e]||e)}),p,p.exports,e,t,r,n)}return r[o].exports}for(var a="function"==typeof require&&require,o=0;o0&&void 0!==arguments[0]?arguments[0]:{},t=e.window,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{shimChrome:!0,shimFirefox:!0,shimEdge:!0,shimSafari:!0},d=n.log,p=n.detectBrowser(t),u={browserDetails:p,commonShim:c,extractVersion:n.extractVersion,disableLog:n.disableLog,disableWarnings:n.disableWarnings};switch(p.browser){case"chrome":if(!i||!i.shimPeerConnection||!r.shimChrome)return d("Chrome shim is not included in this adapter release."),u;d("adapter.js shimming chrome."),u.browserShim=i,i.shimGetUserMedia(t),i.shimMediaStream(t),i.shimPeerConnection(t),i.shimOnTrack(t),i.shimAddTrackRemoveTrack(t),i.shimGetSendersWithDtmf(t),i.shimGetStats(t),i.shimSenderReceiverGetStats(t),i.fixNegotiationNeeded(t),c.shimRTCIceCandidate(t),c.shimConnectionState(t),c.shimMaxMessageSize(t),c.shimSendThrowTypeError(t),c.removeAllowExtmapMixed(t);break;case"firefox":if(!o||!o.shimPeerConnection||!r.shimFirefox)return d("Firefox shim is not included in this adapter release."),u;d("adapter.js shimming firefox."),u.browserShim=o,o.shimGetUserMedia(t),o.shimPeerConnection(t),o.shimOnTrack(t),o.shimRemoveStream(t),o.shimSenderGetStats(t),o.shimReceiverGetStats(t),o.shimRTCDataChannel(t),o.shimAddTransceiver(t),o.shimCreateOffer(t),o.shimCreateAnswer(t),c.shimRTCIceCandidate(t),c.shimConnectionState(t),c.shimMaxMessageSize(t),c.shimSendThrowTypeError(t);break;case"edge":if(!a||!a.shimPeerConnection||!r.shimEdge)return d("MS edge shim is not included in this adapter release."),u;d("adapter.js shimming edge."),u.browserShim=a,a.shimGetUserMedia(t),a.shimGetDisplayMedia(t),a.shimPeerConnection(t),a.shimReplaceTrack(t),c.shimMaxMessageSize(t),c.shimSendThrowTypeError(t);break;case"safari":if(!s||!r.shimSafari)return d("Safari shim is not included in this adapter release."),u;d("adapter.js shimming safari."),u.browserShim=s,s.shimRTCIceServerUrls(t),s.shimCreateOfferLegacy(t),s.shimCallbacksAPI(t),s.shimLocalStreamsAPI(t),s.shimRemoteStreamsAPI(t),s.shimTrackEventTransceiver(t),s.shimGetUserMedia(t),c.shimRTCIceCandidate(t),c.shimMaxMessageSize(t),c.shimSendThrowTypeError(t),c.removeAllowExtmapMixed(t);break;default:d("Unsupported browser!")}return u};var n=d(e("./utils")),i=d(e("./chrome/chrome_shim")),a=d(e("./edge/edge_shim")),o=d(e("./firefox/firefox_shim")),s=d(e("./safari/safari_shim")),c=d(e("./common_shim"));function d(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t}},{"./chrome/chrome_shim":3,"./common_shim":6,"./edge/edge_shim":7,"./firefox/firefox_shim":11,"./safari/safari_shim":14,"./utils":15}],3:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.shimGetDisplayMedia=r.shimGetUserMedia=void 0;var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},i=e("./getusermedia");Object.defineProperty(r,"shimGetUserMedia",{enumerable:!0,get:function(){return i.shimGetUserMedia}});var a=e("./getdisplaymedia");Object.defineProperty(r,"shimGetDisplayMedia",{enumerable:!0,get:function(){return a.shimGetDisplayMedia}}),r.shimMediaStream=function(e){e.MediaStream=e.MediaStream||e.webkitMediaStream},r.shimOnTrack=function(e){if("object"!==(void 0===e?"undefined":n(e))||!e.RTCPeerConnection||"ontrack"in e.RTCPeerConnection.prototype)o.wrapPeerConnectionEvent(e,"track",(function(e){return e.transceiver||Object.defineProperty(e,"transceiver",{value:{receiver:e.receiver}}),e}));else{Object.defineProperty(e.RTCPeerConnection.prototype,"ontrack",{get:function(){return this._ontrack},set:function(e){this._ontrack&&this.removeEventListener("track",this._ontrack),this.addEventListener("track",this._ontrack=e)},enumerable:!0,configurable:!0});var t=e.RTCPeerConnection.prototype.setRemoteDescription;e.RTCPeerConnection.prototype.setRemoteDescription=function(){var r=this;return this._ontrackpoly||(this._ontrackpoly=function(t){t.stream.addEventListener("addtrack",(function(n){var i=void 0;i=e.RTCPeerConnection.prototype.getReceivers?r.getReceivers().find((function(e){return e.track&&e.track.id===n.track.id})):{track:n.track};var a=new Event("track");a.track=n.track,a.receiver=i,a.transceiver={receiver:i},a.streams=[t.stream],r.dispatchEvent(a)})),t.stream.getTracks().forEach((function(n){var i=void 0;i=e.RTCPeerConnection.prototype.getReceivers?r.getReceivers().find((function(e){return e.track&&e.track.id===n.id})):{track:n};var a=new Event("track");a.track=n,a.receiver=i,a.transceiver={receiver:i},a.streams=[t.stream],r.dispatchEvent(a)}))},this.addEventListener("addstream",this._ontrackpoly)),t.apply(this,arguments)}}},r.shimGetSendersWithDtmf=function(e){if("object"===(void 0===e?"undefined":n(e))&&e.RTCPeerConnection&&!("getSenders"in e.RTCPeerConnection.prototype)&&"createDTMFSender"in e.RTCPeerConnection.prototype){var t=function(e,t){return{track:t,get dtmf(){return void 0===this._dtmf&&("audio"===t.kind?this._dtmf=e.createDTMFSender(t):this._dtmf=null),this._dtmf},_pc:e}};if(!e.RTCPeerConnection.prototype.getSenders){e.RTCPeerConnection.prototype.getSenders=function(){return this._senders=this._senders||[],this._senders.slice()};var r=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addTrack=function(e,n){var i=r.apply(this,arguments);return i||(i=t(this,e),this._senders.push(i)),i};var i=e.RTCPeerConnection.prototype.removeTrack;e.RTCPeerConnection.prototype.removeTrack=function(e){i.apply(this,arguments);var t=this._senders.indexOf(e);-1!==t&&this._senders.splice(t,1)}}var a=e.RTCPeerConnection.prototype.addStream;e.RTCPeerConnection.prototype.addStream=function(e){var r=this;this._senders=this._senders||[],a.apply(this,[e]),e.getTracks().forEach((function(e){r._senders.push(t(r,e))}))};var o=e.RTCPeerConnection.prototype.removeStream;e.RTCPeerConnection.prototype.removeStream=function(e){var t=this;this._senders=this._senders||[],o.apply(this,[e]),e.getTracks().forEach((function(e){var r=t._senders.find((function(t){return t.track===e}));r&&t._senders.splice(t._senders.indexOf(r),1)}))}}else if("object"===(void 0===e?"undefined":n(e))&&e.RTCPeerConnection&&"getSenders"in e.RTCPeerConnection.prototype&&"createDTMFSender"in e.RTCPeerConnection.prototype&&e.RTCRtpSender&&!("dtmf"in e.RTCRtpSender.prototype)){var s=e.RTCPeerConnection.prototype.getSenders;e.RTCPeerConnection.prototype.getSenders=function(){var e=this,t=s.apply(this,[]);return t.forEach((function(t){return t._pc=e})),t},Object.defineProperty(e.RTCRtpSender.prototype,"dtmf",{get:function(){return void 0===this._dtmf&&("audio"===this.track.kind?this._dtmf=this._pc.createDTMFSender(this.track):this._dtmf=null),this._dtmf}})}},r.shimGetStats=function(e){if(!e.RTCPeerConnection)return;var t=e.RTCPeerConnection.prototype.getStats;e.RTCPeerConnection.prototype.getStats=function(){var e=this,r=Array.prototype.slice.call(arguments),n=r[0],i=r[1],a=r[2];if(arguments.length>0&&"function"==typeof n)return t.apply(this,arguments);if(0===t.length&&(0===arguments.length||"function"!=typeof n))return t.apply(this,[]);var o=function(e){var t={};return e.result().forEach((function(e){var r={id:e.id,timestamp:e.timestamp,type:{localcandidate:"local-candidate",remotecandidate:"remote-candidate"}[e.type]||e.type};e.names().forEach((function(t){r[t]=e.stat(t)})),t[r.id]=r})),t},s=function(e){return new Map(Object.keys(e).map((function(t){return[t,e[t]]})))};if(arguments.length>=2){var c=function(e){i(s(o(e)))};return t.apply(this,[c,n])}return new Promise((function(r,n){t.apply(e,[function(e){r(s(o(e)))},n])})).then(i,a)}},r.shimSenderReceiverGetStats=function(e){if(!("object"===(void 0===e?"undefined":n(e))&&e.RTCPeerConnection&&e.RTCRtpSender&&e.RTCRtpReceiver))return;if(!("getStats"in e.RTCRtpSender.prototype)){var t=e.RTCPeerConnection.prototype.getSenders;t&&(e.RTCPeerConnection.prototype.getSenders=function(){var e=this,r=t.apply(this,[]);return r.forEach((function(t){return t._pc=e})),r});var r=e.RTCPeerConnection.prototype.addTrack;r&&(e.RTCPeerConnection.prototype.addTrack=function(){var e=r.apply(this,arguments);return e._pc=this,e}),e.RTCRtpSender.prototype.getStats=function(){var e=this;return this._pc.getStats().then((function(t){return o.filterStats(t,e.track,!0)}))}}if(!("getStats"in e.RTCRtpReceiver.prototype)){var i=e.RTCPeerConnection.prototype.getReceivers;i&&(e.RTCPeerConnection.prototype.getReceivers=function(){var e=this,t=i.apply(this,[]);return t.forEach((function(t){return t._pc=e})),t}),o.wrapPeerConnectionEvent(e,"track",(function(e){return e.receiver._pc=e.srcElement,e})),e.RTCRtpReceiver.prototype.getStats=function(){var e=this;return this._pc.getStats().then((function(t){return o.filterStats(t,e.track,!1)}))}}if(!("getStats"in e.RTCRtpSender.prototype&&"getStats"in e.RTCRtpReceiver.prototype))return;var a=e.RTCPeerConnection.prototype.getStats;e.RTCPeerConnection.prototype.getStats=function(){if(arguments.length>0&&arguments[0]instanceof e.MediaStreamTrack){var t=arguments[0],r=void 0,n=void 0,i=void 0;return this.getSenders().forEach((function(e){e.track===t&&(r?i=!0:r=e)})),this.getReceivers().forEach((function(e){return e.track===t&&(n?i=!0:n=e),e.track===t})),i||r&&n?Promise.reject(new DOMException("There are more than one sender or receiver for the track.","InvalidAccessError")):r?r.getStats():n?n.getStats():Promise.reject(new DOMException("There is no sender or receiver for the track.","InvalidAccessError"))}return a.apply(this,arguments)}},r.shimAddTrackRemoveTrackWithNative=c,r.shimAddTrackRemoveTrack=function(e){if(!e.RTCPeerConnection)return;var t=o.detectBrowser(e);if(e.RTCPeerConnection.prototype.addTrack&&t.version>=65)return c(e);var r=e.RTCPeerConnection.prototype.getLocalStreams;e.RTCPeerConnection.prototype.getLocalStreams=function(){var e=this,t=r.apply(this);return this._reverseStreams=this._reverseStreams||{},t.map((function(t){return e._reverseStreams[t.id]}))};var n=e.RTCPeerConnection.prototype.addStream;e.RTCPeerConnection.prototype.addStream=function(t){var r=this;if(this._streams=this._streams||{},this._reverseStreams=this._reverseStreams||{},t.getTracks().forEach((function(e){if(r.getSenders().find((function(t){return t.track===e})))throw new DOMException("Track already exists.","InvalidAccessError")})),!this._reverseStreams[t.id]){var i=new e.MediaStream(t.getTracks());this._streams[t.id]=i,this._reverseStreams[i.id]=t,t=i}n.apply(this,[t])};var i=e.RTCPeerConnection.prototype.removeStream;function a(e,t){var r=t.sdp;return Object.keys(e._reverseStreams||[]).forEach((function(t){var n=e._reverseStreams[t],i=e._streams[n.id];r=r.replace(new RegExp(i.id,"g"),n.id)})),new RTCSessionDescription({type:t.type,sdp:r})}function d(e,t){var r=t.sdp;return Object.keys(e._reverseStreams||[]).forEach((function(t){var n=e._reverseStreams[t],i=e._streams[n.id];r=r.replace(new RegExp(n.id,"g"),i.id)})),new RTCSessionDescription({type:t.type,sdp:r})}e.RTCPeerConnection.prototype.removeStream=function(e){this._streams=this._streams||{},this._reverseStreams=this._reverseStreams||{},i.apply(this,[this._streams[e.id]||e]),delete this._reverseStreams[this._streams[e.id]?this._streams[e.id].id:e.id],delete this._streams[e.id]},e.RTCPeerConnection.prototype.addTrack=function(t,r){var n=this;if("closed"===this.signalingState)throw new DOMException("The RTCPeerConnection's signalingState is 'closed'.","InvalidStateError");var i=[].slice.call(arguments,1);if(1!==i.length||!i[0].getTracks().find((function(e){return e===t})))throw new DOMException("The adapter.js addTrack polyfill only supports a single stream which is associated with the specified track.","NotSupportedError");var a=this.getSenders().find((function(e){return e.track===t}));if(a)throw new DOMException("Track already exists.","InvalidAccessError");this._streams=this._streams||{},this._reverseStreams=this._reverseStreams||{};var o=this._streams[r.id];if(o)o.addTrack(t),Promise.resolve().then((function(){n.dispatchEvent(new Event("negotiationneeded"))}));else{var s=new e.MediaStream([t]);this._streams[r.id]=s,this._reverseStreams[s.id]=r,this.addStream(s)}return this.getSenders().find((function(e){return e.track===t}))},["createOffer","createAnswer"].forEach((function(t){var r=e.RTCPeerConnection.prototype[t],n=s({},t,(function(){var e=this,t=arguments,n=arguments.length&&"function"==typeof arguments[0];return n?r.apply(this,[function(r){var n=a(e,r);t[0].apply(null,[n])},function(e){t[1]&&t[1].apply(null,e)},arguments[2]]):r.apply(this,arguments).then((function(t){return a(e,t)}))}));e.RTCPeerConnection.prototype[t]=n[t]}));var p=e.RTCPeerConnection.prototype.setLocalDescription;e.RTCPeerConnection.prototype.setLocalDescription=function(){return arguments.length&&arguments[0].type?(arguments[0]=d(this,arguments[0]),p.apply(this,arguments)):p.apply(this,arguments)};var u=Object.getOwnPropertyDescriptor(e.RTCPeerConnection.prototype,"localDescription");Object.defineProperty(e.RTCPeerConnection.prototype,"localDescription",{get:function(){var e=u.get.apply(this);return""===e.type?e:a(this,e)}}),e.RTCPeerConnection.prototype.removeTrack=function(e){var t=this;if("closed"===this.signalingState)throw new DOMException("The RTCPeerConnection's signalingState is 'closed'.","InvalidStateError");if(!e._pc)throw new DOMException("Argument 1 of RTCPeerConnection.removeTrack does not implement interface RTCRtpSender.","TypeError");if(!(e._pc===this))throw new DOMException("Sender was not created by this connection.","InvalidAccessError");this._streams=this._streams||{};var r=void 0;Object.keys(this._streams).forEach((function(n){t._streams[n].getTracks().find((function(t){return e.track===t}))&&(r=t._streams[n])})),r&&(1===r.getTracks().length?this.removeStream(this._reverseStreams[r.id]):r.removeTrack(e.track),this.dispatchEvent(new Event("negotiationneeded")))}},r.shimPeerConnection=function(e){var t=o.detectBrowser(e);!e.RTCPeerConnection&&e.webkitRTCPeerConnection&&(e.RTCPeerConnection=e.webkitRTCPeerConnection);if(!e.RTCPeerConnection)return;t.version<53&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach((function(t){var r=e.RTCPeerConnection.prototype[t],n=s({},t,(function(){return arguments[0]=new("addIceCandidate"===t?e.RTCIceCandidate:e.RTCSessionDescription)(arguments[0]),r.apply(this,arguments)}));e.RTCPeerConnection.prototype[t]=n[t]}));var r=e.RTCPeerConnection.prototype.addIceCandidate;e.RTCPeerConnection.prototype.addIceCandidate=function(){return arguments[0]?t.version<78&&arguments[0]&&""===arguments[0].candidate?Promise.resolve():r.apply(this,arguments):(arguments[1]&&arguments[1].apply(null),Promise.resolve())}},r.fixNegotiationNeeded=function(e){o.wrapPeerConnectionEvent(e,"negotiationneeded",(function(e){if("stable"===e.target.signalingState)return e}))};var o=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t}(e("../utils.js"));function s(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function c(e){e.RTCPeerConnection.prototype.getLocalStreams=function(){var e=this;return this._shimmedLocalStreams=this._shimmedLocalStreams||{},Object.keys(this._shimmedLocalStreams).map((function(t){return e._shimmedLocalStreams[t][0]}))};var t=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addTrack=function(e,r){if(!r)return t.apply(this,arguments);this._shimmedLocalStreams=this._shimmedLocalStreams||{};var n=t.apply(this,arguments);return this._shimmedLocalStreams[r.id]?-1===this._shimmedLocalStreams[r.id].indexOf(n)&&this._shimmedLocalStreams[r.id].push(n):this._shimmedLocalStreams[r.id]=[r,n],n};var r=e.RTCPeerConnection.prototype.addStream;e.RTCPeerConnection.prototype.addStream=function(e){var t=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{},e.getTracks().forEach((function(e){if(t.getSenders().find((function(t){return t.track===e})))throw new DOMException("Track already exists.","InvalidAccessError")}));var n=this.getSenders();r.apply(this,arguments);var i=this.getSenders().filter((function(e){return-1===n.indexOf(e)}));this._shimmedLocalStreams[e.id]=[e].concat(i)};var n=e.RTCPeerConnection.prototype.removeStream;e.RTCPeerConnection.prototype.removeStream=function(e){return this._shimmedLocalStreams=this._shimmedLocalStreams||{},delete this._shimmedLocalStreams[e.id],n.apply(this,arguments)};var i=e.RTCPeerConnection.prototype.removeTrack;e.RTCPeerConnection.prototype.removeTrack=function(e){var t=this;return this._shimmedLocalStreams=this._shimmedLocalStreams||{},e&&Object.keys(this._shimmedLocalStreams).forEach((function(r){var n=t._shimmedLocalStreams[r].indexOf(e);-1!==n&&t._shimmedLocalStreams[r].splice(n,1),1===t._shimmedLocalStreams[r].length&&delete t._shimmedLocalStreams[r]})),i.apply(this,arguments)}}},{"../utils.js":15,"./getdisplaymedia":4,"./getusermedia":5}],4:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.shimGetDisplayMedia=function(e,t){if(e.navigator.mediaDevices&&"getDisplayMedia"in e.navigator.mediaDevices)return;if(!e.navigator.mediaDevices)return;if("function"!=typeof t)return void console.error("shimGetDisplayMedia: getSourceId argument is not a function");e.navigator.mediaDevices.getDisplayMedia=function(r){return t(r).then((function(t){var n=r.video&&r.video.width,i=r.video&&r.video.height,a=r.video&&r.video.frameRate;return r.video={mandatory:{chromeMediaSource:"desktop",chromeMediaSourceId:t,maxFrameRate:a||3}},n&&(r.video.mandatory.maxWidth=n),i&&(r.video.mandatory.maxHeight=i),e.navigator.mediaDevices.getUserMedia(r)}))}}},{}],5:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};r.shimGetUserMedia=function(e){var t=e&&e.navigator;if(!t.mediaDevices)return;var r=i.detectBrowser(e),o=function(e){if("object"!==(void 0===e?"undefined":n(e))||e.mandatory||e.optional)return e;var t={};return Object.keys(e).forEach((function(r){if("require"!==r&&"advanced"!==r&&"mediaSource"!==r){var i="object"===n(e[r])?e[r]:{ideal:e[r]};void 0!==i.exact&&"number"==typeof i.exact&&(i.min=i.max=i.exact);var a=function(e,t){return e?e+t.charAt(0).toUpperCase()+t.slice(1):"deviceId"===t?"sourceId":t};if(void 0!==i.ideal){t.optional=t.optional||[];var o={};"number"==typeof i.ideal?(o[a("min",r)]=i.ideal,t.optional.push(o),(o={})[a("max",r)]=i.ideal,t.optional.push(o)):(o[a("",r)]=i.ideal,t.optional.push(o))}void 0!==i.exact&&"number"!=typeof i.exact?(t.mandatory=t.mandatory||{},t.mandatory[a("",r)]=i.exact):["min","max"].forEach((function(e){void 0!==i[e]&&(t.mandatory=t.mandatory||{},t.mandatory[a(e,r)]=i[e])}))}})),e.advanced&&(t.optional=(t.optional||[]).concat(e.advanced)),t},s=function(e,i){if(r.version>=61)return i(e);if((e=JSON.parse(JSON.stringify(e)))&&"object"===n(e.audio)){var s=function(e,t,r){t in e&&!(r in e)&&(e[r]=e[t],delete e[t])};s((e=JSON.parse(JSON.stringify(e))).audio,"autoGainControl","googAutoGainControl"),s(e.audio,"noiseSuppression","googNoiseSuppression"),e.audio=o(e.audio)}if(e&&"object"===n(e.video)){var c=e.video.facingMode;c=c&&("object"===(void 0===c?"undefined":n(c))?c:{ideal:c});var d=r.version<66;if(c&&("user"===c.exact||"environment"===c.exact||"user"===c.ideal||"environment"===c.ideal)&&(!t.mediaDevices.getSupportedConstraints||!t.mediaDevices.getSupportedConstraints().facingMode||d)){delete e.video.facingMode;var p=void 0;if("environment"===c.exact||"environment"===c.ideal?p=["back","rear"]:"user"!==c.exact&&"user"!==c.ideal||(p=["front"]),p)return t.mediaDevices.enumerateDevices().then((function(t){var r=(t=t.filter((function(e){return"videoinput"===e.kind}))).find((function(e){return p.some((function(t){return e.label.toLowerCase().includes(t)}))}));return!r&&t.length&&p.includes("back")&&(r=t[t.length-1]),r&&(e.video.deviceId=c.exact?{exact:r.deviceId}:{ideal:r.deviceId}),e.video=o(e.video),a("chrome: "+JSON.stringify(e)),i(e)}))}e.video=o(e.video)}return a("chrome: "+JSON.stringify(e)),i(e)},c=function(e){return r.version>=64?e:{name:{PermissionDeniedError:"NotAllowedError",PermissionDismissedError:"NotAllowedError",InvalidStateError:"NotAllowedError",DevicesNotFoundError:"NotFoundError",ConstraintNotSatisfiedError:"OverconstrainedError",TrackStartError:"NotReadableError",MediaDeviceFailedDueToShutdown:"NotAllowedError",MediaDeviceKillSwitchOn:"NotAllowedError",TabCaptureError:"AbortError",ScreenCaptureError:"AbortError",DeviceCaptureError:"AbortError"}[e.name]||e.name,message:e.message,constraint:e.constraint||e.constraintName,toString:function(){return this.name+(this.message&&": ")+this.message}}};if(t.getUserMedia=function(e,r,n){s(e,(function(e){t.webkitGetUserMedia(e,r,(function(e){n&&n(c(e))}))}))}.bind(t),t.mediaDevices.getUserMedia){var d=t.mediaDevices.getUserMedia.bind(t.mediaDevices);t.mediaDevices.getUserMedia=function(e){return s(e,(function(e){return d(e).then((function(t){if(e.audio&&!t.getAudioTracks().length||e.video&&!t.getVideoTracks().length)throw t.getTracks().forEach((function(e){e.stop()})),new DOMException("","NotFoundError");return t}),(function(e){return Promise.reject(c(e))}))}))}}};var i=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t}(e("../utils.js"));var a=i.log},{"../utils.js":15}],6:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};r.shimRTCIceCandidate=function(e){if(!e.RTCIceCandidate||e.RTCIceCandidate&&"foundation"in e.RTCIceCandidate.prototype)return;var t=e.RTCIceCandidate;e.RTCIceCandidate=function(e){if("object"===(void 0===e?"undefined":n(e))&&e.candidate&&0===e.candidate.indexOf("a=")&&((e=JSON.parse(JSON.stringify(e))).candidate=e.candidate.substr(2)),e.candidate&&e.candidate.length){var r=new t(e),i=o.default.parseCandidate(e.candidate),a=Object.assign(r,i);return a.toJSON=function(){return{candidate:a.candidate,sdpMid:a.sdpMid,sdpMLineIndex:a.sdpMLineIndex,usernameFragment:a.usernameFragment}},a}return new t(e)},e.RTCIceCandidate.prototype=t.prototype,s.wrapPeerConnectionEvent(e,"icecandidate",(function(t){return t.candidate&&Object.defineProperty(t,"candidate",{value:new e.RTCIceCandidate(t.candidate),writable:"false"}),t}))},r.shimMaxMessageSize=function(e){if(!e.RTCPeerConnection)return;var t=s.detectBrowser(e);"sctp"in e.RTCPeerConnection.prototype||Object.defineProperty(e.RTCPeerConnection.prototype,"sctp",{get:function(){return void 0===this._sctp?null:this._sctp}});var r=function(e){if(!e||!e.sdp)return!1;var t=o.default.splitSections(e.sdp);return t.shift(),t.some((function(e){var t=o.default.parseMLine(e);return t&&"application"===t.kind&&-1!==t.protocol.indexOf("SCTP")}))},n=function(e){var t=e.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/);if(null===t||t.length<2)return-1;var r=parseInt(t[1],10);return r!=r?-1:r},i=function(e){var r=65536;return"firefox"===t.browser&&(r=t.version<57?-1===e?16384:2147483637:t.version<60?57===t.version?65535:65536:2147483637),r},a=function(e,r){var n=65536;"firefox"===t.browser&&57===t.version&&(n=65535);var i=o.default.matchPrefix(e.sdp,"a=max-message-size:");return i.length>0?n=parseInt(i[0].substr(19),10):"firefox"===t.browser&&-1!==r&&(n=2147483637),n},c=e.RTCPeerConnection.prototype.setRemoteDescription;e.RTCPeerConnection.prototype.setRemoteDescription=function(){if(this._sctp=null,"chrome"===t.browser&&t.version>=76){var e=this.getConfiguration(),o=e.sdpSemantics;"plan-b"===o&&Object.defineProperty(this,"sctp",{get:function(){return void 0===this._sctp?null:this._sctp},enumerable:!0,configurable:!0})}if(r(arguments[0])){var s=n(arguments[0]),d=i(s),p=a(arguments[0],s),u=void 0;u=0===d&&0===p?Number.POSITIVE_INFINITY:0===d||0===p?Math.max(d,p):Math.min(d,p);var f={};Object.defineProperty(f,"maxMessageSize",{get:function(){return u}}),this._sctp=f}return c.apply(this,arguments)}},r.shimSendThrowTypeError=function(e){if(!(e.RTCPeerConnection&&"createDataChannel"in e.RTCPeerConnection.prototype))return;function t(e,t){var r=e.send;e.send=function(){var n=arguments[0],i=n.length||n.size||n.byteLength;if("open"===e.readyState&&t.sctp&&i>t.sctp.maxMessageSize)throw new TypeError("Message too large (can send a maximum of "+t.sctp.maxMessageSize+" bytes)");return r.apply(e,arguments)}}var r=e.RTCPeerConnection.prototype.createDataChannel;e.RTCPeerConnection.prototype.createDataChannel=function(){var e=r.apply(this,arguments);return t(e,this),e},s.wrapPeerConnectionEvent(e,"datachannel",(function(e){return t(e.channel,e.target),e}))},r.shimConnectionState=function(e){if(!e.RTCPeerConnection||"connectionState"in e.RTCPeerConnection.prototype)return;var t=e.RTCPeerConnection.prototype;Object.defineProperty(t,"connectionState",{get:function(){return{completed:"connected",checking:"connecting"}[this.iceConnectionState]||this.iceConnectionState},enumerable:!0,configurable:!0}),Object.defineProperty(t,"onconnectionstatechange",{get:function(){return this._onconnectionstatechange||null},set:function(e){this._onconnectionstatechange&&(this.removeEventListener("connectionstatechange",this._onconnectionstatechange),delete this._onconnectionstatechange),e&&this.addEventListener("connectionstatechange",this._onconnectionstatechange=e)},enumerable:!0,configurable:!0}),["setLocalDescription","setRemoteDescription"].forEach((function(e){var r=t[e];t[e]=function(){return this._connectionstatechangepoly||(this._connectionstatechangepoly=function(e){var t=e.target;if(t._lastConnectionState!==t.connectionState){t._lastConnectionState=t.connectionState;var r=new Event("connectionstatechange",e);t.dispatchEvent(r)}return e},this.addEventListener("iceconnectionstatechange",this._connectionstatechangepoly)),r.apply(this,arguments)}}))},r.removeAllowExtmapMixed=function(e){if(!e.RTCPeerConnection)return;var t=s.detectBrowser(e);if("chrome"===t.browser&&t.version>=71)return;var r=e.RTCPeerConnection.prototype.setRemoteDescription;e.RTCPeerConnection.prototype.setRemoteDescription=function(e){return e&&e.sdp&&-1!==e.sdp.indexOf("\na=extmap-allow-mixed")&&(e.sdp=e.sdp.split("\n").filter((function(e){return"a=extmap-allow-mixed"!==e.trim()})).join("\n")),r.apply(this,arguments)}};var i,a=e("sdp"),o=(i=a)&&i.__esModule?i:{default:i},s=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t}(e("./utils"))},{"./utils":15,sdp:17}],7:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.shimGetDisplayMedia=r.shimGetUserMedia=void 0;var n=e("./getusermedia");Object.defineProperty(r,"shimGetUserMedia",{enumerable:!0,get:function(){return n.shimGetUserMedia}});var i=e("./getdisplaymedia");Object.defineProperty(r,"shimGetDisplayMedia",{enumerable:!0,get:function(){return i.shimGetDisplayMedia}}),r.shimPeerConnection=function(e){var t=o.detectBrowser(e);if(e.RTCIceGatherer&&(e.RTCIceCandidate||(e.RTCIceCandidate=function(e){return e}),e.RTCSessionDescription||(e.RTCSessionDescription=function(e){return e}),t.version<15025)){var r=Object.getOwnPropertyDescriptor(e.MediaStreamTrack.prototype,"enabled");Object.defineProperty(e.MediaStreamTrack.prototype,"enabled",{set:function(e){r.set.call(this,e);var t=new Event("enabled");t.enabled=e,this.dispatchEvent(t)}})}!e.RTCRtpSender||"dtmf"in e.RTCRtpSender.prototype||Object.defineProperty(e.RTCRtpSender.prototype,"dtmf",{get:function(){return void 0===this._dtmf&&("audio"===this.track.kind?this._dtmf=new e.RTCDtmfSender(this):"video"===this.track.kind&&(this._dtmf=null)),this._dtmf}});e.RTCDtmfSender&&!e.RTCDTMFSender&&(e.RTCDTMFSender=e.RTCDtmfSender);var n=(0,d.default)(e,t.version);e.RTCPeerConnection=function(e){return e&&e.iceServers&&(e.iceServers=(0,s.filterIceServers)(e.iceServers,t.version),o.log("ICE servers after filtering:",e.iceServers)),new n(e)},e.RTCPeerConnection.prototype=n.prototype},r.shimReplaceTrack=function(e){!e.RTCRtpSender||"replaceTrack"in e.RTCRtpSender.prototype||(e.RTCRtpSender.prototype.replaceTrack=e.RTCRtpSender.prototype.setTrack)};var a,o=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t}(e("../utils")),s=e("./filtericeservers"),c=e("rtcpeerconnection-shim"),d=(a=c)&&a.__esModule?a:{default:a}},{"../utils":15,"./filtericeservers":8,"./getdisplaymedia":9,"./getusermedia":10,"rtcpeerconnection-shim":16}],8:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.filterIceServers=function(e,t){var r=!1;return(e=JSON.parse(JSON.stringify(e))).filter((function(e){if(e&&(e.urls||e.url)){var t=e.urls||e.url;e.url&&!e.urls&&n.deprecated("RTCIceServer.url","RTCIceServer.urls");var i="string"==typeof t;return i&&(t=[t]),t=t.filter((function(e){if(0===e.indexOf("stun:"))return!1;var t=e.startsWith("turn")&&!e.startsWith("turn:[")&&e.includes("transport=udp");return t&&!r?(r=!0,!0):t&&!r})),delete e.url,e.urls=i?t[0]:t,!!t.length}}))};var n=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t}(e("../utils"))},{"../utils":15}],9:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.shimGetDisplayMedia=function(e){if(!("getDisplayMedia"in e.navigator))return;if(!e.navigator.mediaDevices)return;if(e.navigator.mediaDevices&&"getDisplayMedia"in e.navigator.mediaDevices)return;e.navigator.mediaDevices.getDisplayMedia=e.navigator.getDisplayMedia.bind(e.navigator)}},{}],10:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.shimGetUserMedia=function(e){var t=e&&e.navigator,r=t.mediaDevices.getUserMedia.bind(t.mediaDevices);t.mediaDevices.getUserMedia=function(e){return r(e).catch((function(e){return Promise.reject(function(e){return{name:{PermissionDeniedError:"NotAllowedError"}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function(){return this.name}}}(e))}))}}},{}],11:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.shimGetDisplayMedia=r.shimGetUserMedia=void 0;var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},i=e("./getusermedia");Object.defineProperty(r,"shimGetUserMedia",{enumerable:!0,get:function(){return i.shimGetUserMedia}});var a=e("./getdisplaymedia");Object.defineProperty(r,"shimGetDisplayMedia",{enumerable:!0,get:function(){return a.shimGetDisplayMedia}}),r.shimOnTrack=function(e){"object"===(void 0===e?"undefined":n(e))&&e.RTCTrackEvent&&"receiver"in e.RTCTrackEvent.prototype&&!("transceiver"in e.RTCTrackEvent.prototype)&&Object.defineProperty(e.RTCTrackEvent.prototype,"transceiver",{get:function(){return{receiver:this.receiver}}})},r.shimPeerConnection=function(e){var t=o.detectBrowser(e);if("object"!==(void 0===e?"undefined":n(e))||!e.RTCPeerConnection&&!e.mozRTCPeerConnection)return;!e.RTCPeerConnection&&e.mozRTCPeerConnection&&(e.RTCPeerConnection=e.mozRTCPeerConnection);t.version<53&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach((function(t){var r=e.RTCPeerConnection.prototype[t],n=function(e,t,r){t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r;return e}({},t,(function(){return arguments[0]=new("addIceCandidate"===t?e.RTCIceCandidate:e.RTCSessionDescription)(arguments[0]),r.apply(this,arguments)}));e.RTCPeerConnection.prototype[t]=n[t]}));if(t.version<68){var r=e.RTCPeerConnection.prototype.addIceCandidate;e.RTCPeerConnection.prototype.addIceCandidate=function(){return arguments[0]?arguments[0]&&""===arguments[0].candidate?Promise.resolve():r.apply(this,arguments):(arguments[1]&&arguments[1].apply(null),Promise.resolve())}}var i={inboundrtp:"inbound-rtp",outboundrtp:"outbound-rtp",candidatepair:"candidate-pair",localcandidate:"local-candidate",remotecandidate:"remote-candidate"},a=e.RTCPeerConnection.prototype.getStats;e.RTCPeerConnection.prototype.getStats=function(){var e=Array.prototype.slice.call(arguments),r=e[0],n=e[1],o=e[2];return a.apply(this,[r||null]).then((function(e){if(t.version<53&&!n)try{e.forEach((function(e){e.type=i[e.type]||e.type}))}catch(t){if("TypeError"!==t.name)throw t;e.forEach((function(t,r){e.set(r,Object.assign({},t,{type:i[t.type]||t.type}))}))}return e})).then(n,o)}},r.shimSenderGetStats=function(e){if("object"!==(void 0===e?"undefined":n(e))||!e.RTCPeerConnection||!e.RTCRtpSender)return;if(e.RTCRtpSender&&"getStats"in e.RTCRtpSender.prototype)return;var t=e.RTCPeerConnection.prototype.getSenders;t&&(e.RTCPeerConnection.prototype.getSenders=function(){var e=this,r=t.apply(this,[]);return r.forEach((function(t){return t._pc=e})),r});var r=e.RTCPeerConnection.prototype.addTrack;r&&(e.RTCPeerConnection.prototype.addTrack=function(){var e=r.apply(this,arguments);return e._pc=this,e});e.RTCRtpSender.prototype.getStats=function(){return this.track?this._pc.getStats(this.track):Promise.resolve(new Map)}},r.shimReceiverGetStats=function(e){if("object"!==(void 0===e?"undefined":n(e))||!e.RTCPeerConnection||!e.RTCRtpSender)return;if(e.RTCRtpSender&&"getStats"in e.RTCRtpReceiver.prototype)return;var t=e.RTCPeerConnection.prototype.getReceivers;t&&(e.RTCPeerConnection.prototype.getReceivers=function(){var e=this,r=t.apply(this,[]);return r.forEach((function(t){return t._pc=e})),r});o.wrapPeerConnectionEvent(e,"track",(function(e){return e.receiver._pc=e.srcElement,e})),e.RTCRtpReceiver.prototype.getStats=function(){return this._pc.getStats(this.track)}},r.shimRemoveStream=function(e){if(!e.RTCPeerConnection||"removeStream"in e.RTCPeerConnection.prototype)return;e.RTCPeerConnection.prototype.removeStream=function(e){var t=this;o.deprecated("removeStream","removeTrack"),this.getSenders().forEach((function(r){r.track&&e.getTracks().includes(r.track)&&t.removeTrack(r)}))}},r.shimRTCDataChannel=function(e){e.DataChannel&&!e.RTCDataChannel&&(e.RTCDataChannel=e.DataChannel)},r.shimAddTransceiver=function(e){if("object"!==(void 0===e?"undefined":n(e))||!e.RTCPeerConnection)return;var t=e.RTCPeerConnection.prototype.addTransceiver;t&&(e.RTCPeerConnection.prototype.addTransceiver=function(){this.setParametersPromises=[];var e=arguments[1],r=e&&"sendEncodings"in e;r&&e.sendEncodings.forEach((function(e){if("rid"in e){if(!/^[a-z0-9]{0,16}$/i.test(e.rid))throw new TypeError("Invalid RID value provided.")}if("scaleResolutionDownBy"in e&&!(parseFloat(e.scaleResolutionDownBy)>=1))throw new RangeError("scale_resolution_down_by must be >= 1.0");if("maxFramerate"in e&&!(parseFloat(e.maxFramerate)>=0))throw new RangeError("max_framerate must be >= 0.0")}));var n=t.apply(this,arguments);if(r){var i=n.sender,a=i.getParameters();"encodings"in a||(a.encodings=e.sendEncodings,this.setParametersPromises.push(i.setParameters(a).catch((function(){}))))}return n})},r.shimCreateOffer=function(e){if("object"!==(void 0===e?"undefined":n(e))||!e.RTCPeerConnection)return;var t=e.RTCPeerConnection.prototype.createOffer;e.RTCPeerConnection.prototype.createOffer=function(){var e=this,r=arguments;return this.setParametersPromises&&this.setParametersPromises.length?Promise.all(this.setParametersPromises).then((function(){return t.apply(e,r)})).finally((function(){e.setParametersPromises=[]})):t.apply(this,arguments)}},r.shimCreateAnswer=function(e){if("object"!==(void 0===e?"undefined":n(e))||!e.RTCPeerConnection)return;var t=e.RTCPeerConnection.prototype.createAnswer;e.RTCPeerConnection.prototype.createAnswer=function(){var e=this,r=arguments;return this.setParametersPromises&&this.setParametersPromises.length?Promise.all(this.setParametersPromises).then((function(){return t.apply(e,r)})).finally((function(){e.setParametersPromises=[]})):t.apply(this,arguments)}};var o=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t}(e("../utils"))},{"../utils":15,"./getdisplaymedia":12,"./getusermedia":13}],12:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.shimGetDisplayMedia=function(e,t){if(e.navigator.mediaDevices&&"getDisplayMedia"in e.navigator.mediaDevices)return;if(!e.navigator.mediaDevices)return;e.navigator.mediaDevices.getDisplayMedia=function(r){if(!r||!r.video){var n=new DOMException("getDisplayMedia without video constraints is undefined");return n.name="NotFoundError",n.code=8,Promise.reject(n)}return!0===r.video?r.video={mediaSource:t}:r.video.mediaSource=t,e.navigator.mediaDevices.getUserMedia(r)}}},{}],13:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};r.shimGetUserMedia=function(e){var t=i.detectBrowser(e),r=e&&e.navigator,a=e&&e.MediaStreamTrack;if(r.getUserMedia=function(e,t,n){i.deprecated("navigator.getUserMedia","navigator.mediaDevices.getUserMedia"),r.mediaDevices.getUserMedia(e).then(t,n)},!(t.version>55&&"autoGainControl"in r.mediaDevices.getSupportedConstraints())){var o=function(e,t,r){t in e&&!(r in e)&&(e[r]=e[t],delete e[t])},s=r.mediaDevices.getUserMedia.bind(r.mediaDevices);if(r.mediaDevices.getUserMedia=function(e){return"object"===(void 0===e?"undefined":n(e))&&"object"===n(e.audio)&&(e=JSON.parse(JSON.stringify(e)),o(e.audio,"autoGainControl","mozAutoGainControl"),o(e.audio,"noiseSuppression","mozNoiseSuppression")),s(e)},a&&a.prototype.getSettings){var c=a.prototype.getSettings;a.prototype.getSettings=function(){var e=c.apply(this,arguments);return o(e,"mozAutoGainControl","autoGainControl"),o(e,"mozNoiseSuppression","noiseSuppression"),e}}if(a&&a.prototype.applyConstraints){var d=a.prototype.applyConstraints;a.prototype.applyConstraints=function(e){return"audio"===this.kind&&"object"===(void 0===e?"undefined":n(e))&&(e=JSON.parse(JSON.stringify(e)),o(e,"autoGainControl","mozAutoGainControl"),o(e,"noiseSuppression","mozNoiseSuppression")),d.apply(this,[e])}}}};var i=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t}(e("../utils"))},{"../utils":15}],14:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};r.shimLocalStreamsAPI=function(e){if("object"!==(void 0===e?"undefined":n(e))||!e.RTCPeerConnection)return;"getLocalStreams"in e.RTCPeerConnection.prototype||(e.RTCPeerConnection.prototype.getLocalStreams=function(){return this._localStreams||(this._localStreams=[]),this._localStreams});if(!("addStream"in e.RTCPeerConnection.prototype)){var t=e.RTCPeerConnection.prototype.addTrack;e.RTCPeerConnection.prototype.addStream=function(e){var r=this;this._localStreams||(this._localStreams=[]),this._localStreams.includes(e)||this._localStreams.push(e),e.getAudioTracks().forEach((function(n){return t.call(r,n,e)})),e.getVideoTracks().forEach((function(n){return t.call(r,n,e)}))},e.RTCPeerConnection.prototype.addTrack=function(e){var r=arguments[1];return r&&(this._localStreams?this._localStreams.includes(r)||this._localStreams.push(r):this._localStreams=[r]),t.apply(this,arguments)}}"removeStream"in e.RTCPeerConnection.prototype||(e.RTCPeerConnection.prototype.removeStream=function(e){var t=this;this._localStreams||(this._localStreams=[]);var r=this._localStreams.indexOf(e);if(-1!==r){this._localStreams.splice(r,1);var n=e.getTracks();this.getSenders().forEach((function(e){n.includes(e.track)&&t.removeTrack(e)}))}})},r.shimRemoteStreamsAPI=function(e){if("object"!==(void 0===e?"undefined":n(e))||!e.RTCPeerConnection)return;"getRemoteStreams"in e.RTCPeerConnection.prototype||(e.RTCPeerConnection.prototype.getRemoteStreams=function(){return this._remoteStreams?this._remoteStreams:[]});if(!("onaddstream"in e.RTCPeerConnection.prototype)){Object.defineProperty(e.RTCPeerConnection.prototype,"onaddstream",{get:function(){return this._onaddstream},set:function(e){var t=this;this._onaddstream&&(this.removeEventListener("addstream",this._onaddstream),this.removeEventListener("track",this._onaddstreampoly)),this.addEventListener("addstream",this._onaddstream=e),this.addEventListener("track",this._onaddstreampoly=function(e){e.streams.forEach((function(e){if(t._remoteStreams||(t._remoteStreams=[]),!t._remoteStreams.includes(e)){t._remoteStreams.push(e);var r=new Event("addstream");r.stream=e,t.dispatchEvent(r)}}))})}});var t=e.RTCPeerConnection.prototype.setRemoteDescription;e.RTCPeerConnection.prototype.setRemoteDescription=function(){var e=this;return this._onaddstreampoly||this.addEventListener("track",this._onaddstreampoly=function(t){t.streams.forEach((function(t){if(e._remoteStreams||(e._remoteStreams=[]),!(e._remoteStreams.indexOf(t)>=0)){e._remoteStreams.push(t);var r=new Event("addstream");r.stream=t,e.dispatchEvent(r)}}))}),t.apply(e,arguments)}}},r.shimCallbacksAPI=function(e){if("object"!==(void 0===e?"undefined":n(e))||!e.RTCPeerConnection)return;var t=e.RTCPeerConnection.prototype,r=t.createOffer,i=t.createAnswer,a=t.setLocalDescription,o=t.setRemoteDescription,s=t.addIceCandidate;t.createOffer=function(e,t){var n=arguments.length>=2?arguments[2]:arguments[0],i=r.apply(this,[n]);return t?(i.then(e,t),Promise.resolve()):i},t.createAnswer=function(e,t){var r=arguments.length>=2?arguments[2]:arguments[0],n=i.apply(this,[r]);return t?(n.then(e,t),Promise.resolve()):n};var c=function(e,t,r){var n=a.apply(this,[e]);return r?(n.then(t,r),Promise.resolve()):n};t.setLocalDescription=c,c=function(e,t,r){var n=o.apply(this,[e]);return r?(n.then(t,r),Promise.resolve()):n},t.setRemoteDescription=c,c=function(e,t,r){var n=s.apply(this,[e]);return r?(n.then(t,r),Promise.resolve()):n},t.addIceCandidate=c},r.shimGetUserMedia=function(e){var t=e&&e.navigator;if(t.mediaDevices&&t.mediaDevices.getUserMedia){var r=t.mediaDevices,n=r.getUserMedia.bind(r);t.mediaDevices.getUserMedia=function(e){return n(a(e))}}!t.getUserMedia&&t.mediaDevices&&t.mediaDevices.getUserMedia&&(t.getUserMedia=function(e,r,n){t.mediaDevices.getUserMedia(e).then(r,n)}.bind(t))},r.shimConstraints=a,r.shimRTCIceServerUrls=function(e){var t=e.RTCPeerConnection;e.RTCPeerConnection=function(e,r){if(e&&e.iceServers){for(var n=[],a=0;a=r&&parseInt(n[r],10)}function s(e){return"[object Object]"===Object.prototype.toString.call(e)}function c(e,t,r){t&&!r.has(t.id)&&(r.set(t.id,t),Object.keys(t).forEach((function(n){n.endsWith("Id")?c(e,e.get(t[n]),r):n.endsWith("Ids")&&t[n].forEach((function(t){c(e,e.get(t),r)}))})))}},{}],16:[function(e,t,r){"use strict";var n=e("sdp");function i(e,t,r,i,a){var o=n.writeRtpDescription(e.kind,t);if(o+=n.writeIceParameters(e.iceGatherer.getLocalParameters()),o+=n.writeDtlsParameters(e.dtlsTransport.getLocalParameters(),"offer"===r?"actpass":a||"active"),o+="a=mid:"+e.mid+"\r\n",e.rtpSender&&e.rtpReceiver?o+="a=sendrecv\r\n":e.rtpSender?o+="a=sendonly\r\n":e.rtpReceiver?o+="a=recvonly\r\n":o+="a=inactive\r\n",e.rtpSender){var s=e.rtpSender._initialTrackId||e.rtpSender.track.id;e.rtpSender._initialTrackId=s;var c="msid:"+(i?i.id:"-")+" "+s+"\r\n";o+="a="+c,o+="a=ssrc:"+e.sendEncodingParameters[0].ssrc+" "+c,e.sendEncodingParameters[0].rtx&&(o+="a=ssrc:"+e.sendEncodingParameters[0].rtx.ssrc+" "+c,o+="a=ssrc-group:FID "+e.sendEncodingParameters[0].ssrc+" "+e.sendEncodingParameters[0].rtx.ssrc+"\r\n")}return o+="a=ssrc:"+e.sendEncodingParameters[0].ssrc+" cname:"+n.localCName+"\r\n",e.rtpSender&&e.sendEncodingParameters[0].rtx&&(o+="a=ssrc:"+e.sendEncodingParameters[0].rtx.ssrc+" cname:"+n.localCName+"\r\n"),o}function a(e,t){var r={codecs:[],headerExtensions:[],fecMechanisms:[]},n=function(e,t){e=parseInt(e,10);for(var r=0;r=14393&&-1===e.indexOf("?transport=udp")})),delete e.url,e.urls=i?n[0]:n,!!n.length}}))}(r.iceServers||[],t),this._iceGatherers=[],r.iceCandidatePoolSize)for(var o=r.iceCandidatePoolSize;o>0;o--)this._iceGatherers.push(new e.RTCIceGatherer({iceServers:r.iceServers,gatherPolicy:r.iceTransportPolicy}));else r.iceCandidatePoolSize=0;this._config=r,this.transceivers=[],this._sdpSessionId=n.generateSessionId(),this._sdpSessionVersion=0,this._dtlsRole=void 0,this._isClosed=!1};Object.defineProperty(p.prototype,"localDescription",{configurable:!0,get:function(){return this._localDescription}}),Object.defineProperty(p.prototype,"remoteDescription",{configurable:!0,get:function(){return this._remoteDescription}}),p.prototype.onicecandidate=null,p.prototype.onaddstream=null,p.prototype.ontrack=null,p.prototype.onremovestream=null,p.prototype.onsignalingstatechange=null,p.prototype.oniceconnectionstatechange=null,p.prototype.onconnectionstatechange=null,p.prototype.onicegatheringstatechange=null,p.prototype.onnegotiationneeded=null,p.prototype.ondatachannel=null,p.prototype._dispatchEvent=function(e,t){this._isClosed||(this.dispatchEvent(t),"function"==typeof this["on"+e]&&this["on"+e](t))},p.prototype._emitGatheringStateChange=function(){var e=new Event("icegatheringstatechange");this._dispatchEvent("icegatheringstatechange",e)},p.prototype.getConfiguration=function(){return this._config},p.prototype.getLocalStreams=function(){return this.localStreams},p.prototype.getRemoteStreams=function(){return this.remoteStreams},p.prototype._createTransceiver=function(e,t){var r=this.transceivers.length>0,n={track:null,iceGatherer:null,iceTransport:null,dtlsTransport:null,localCapabilities:null,remoteCapabilities:null,rtpSender:null,rtpReceiver:null,kind:e,mid:null,sendEncodingParameters:null,recvEncodingParameters:null,stream:null,associatedRemoteMediaStreams:[],wantReceive:!0};if(this.usingBundle&&r)n.iceTransport=this.transceivers[0].iceTransport,n.dtlsTransport=this.transceivers[0].dtlsTransport;else{var i=this._createIceAndDtlsTransports();n.iceTransport=i.iceTransport,n.dtlsTransport=i.dtlsTransport}return t||this.transceivers.push(n),n},p.prototype.addTrack=function(t,r){if(this._isClosed)throw c("InvalidStateError","Attempted to call addTrack on a closed peerconnection.");var n;if(this.transceivers.find((function(e){return e.track===t})))throw c("InvalidAccessError","Track already exists.");for(var i=0;i=15025)e.getTracks().forEach((function(t){r.addTrack(t,e)}));else{var n=e.clone();e.getTracks().forEach((function(e,t){var r=n.getTracks()[t];e.addEventListener("enabled",(function(e){r.enabled=e.enabled}))})),n.getTracks().forEach((function(e){r.addTrack(e,n)}))}},p.prototype.removeTrack=function(t){if(this._isClosed)throw c("InvalidStateError","Attempted to call removeTrack on a closed peerconnection.");if(!(t instanceof e.RTCRtpSender))throw new TypeError("Argument 1 of RTCPeerConnection.removeTrack does not implement interface RTCRtpSender.");var r=this.transceivers.find((function(e){return e.rtpSender===t}));if(!r)throw c("InvalidAccessError","Sender was not created by this connection.");var n=r.stream;r.rtpSender.stop(),r.rtpSender=null,r.track=null,r.stream=null,-1===this.transceivers.map((function(e){return e.stream})).indexOf(n)&&this.localStreams.indexOf(n)>-1&&this.localStreams.splice(this.localStreams.indexOf(n),1),this._maybeFireNegotiationNeeded()},p.prototype.removeStream=function(e){var t=this;e.getTracks().forEach((function(e){var r=t.getSenders().find((function(t){return t.track===e}));r&&t.removeTrack(r)}))},p.prototype.getSenders=function(){return this.transceivers.filter((function(e){return!!e.rtpSender})).map((function(e){return e.rtpSender}))},p.prototype.getReceivers=function(){return this.transceivers.filter((function(e){return!!e.rtpReceiver})).map((function(e){return e.rtpReceiver}))},p.prototype._createIceGatherer=function(t,r){var n=this;if(r&&t>0)return this.transceivers[0].iceGatherer;if(this._iceGatherers.length)return this._iceGatherers.shift();var i=new e.RTCIceGatherer({iceServers:this._config.iceServers,gatherPolicy:this._config.iceTransportPolicy});return Object.defineProperty(i,"state",{value:"new",writable:!0}),this.transceivers[t].bufferedCandidateEvents=[],this.transceivers[t].bufferCandidates=function(e){var r=!e.candidate||0===Object.keys(e.candidate).length;i.state=r?"completed":"gathering",null!==n.transceivers[t].bufferedCandidateEvents&&n.transceivers[t].bufferedCandidateEvents.push(e)},i.addEventListener("localcandidate",this.transceivers[t].bufferCandidates),i},p.prototype._gather=function(t,r){var i=this,a=this.transceivers[r].iceGatherer;if(!a.onlocalcandidate){var o=this.transceivers[r].bufferedCandidateEvents;this.transceivers[r].bufferedCandidateEvents=null,a.removeEventListener("localcandidate",this.transceivers[r].bufferCandidates),a.onlocalcandidate=function(e){if(!(i.usingBundle&&r>0)){var o=new Event("icecandidate");o.candidate={sdpMid:t,sdpMLineIndex:r};var s=e.candidate,c=!s||0===Object.keys(s).length;if(c)"new"!==a.state&&"gathering"!==a.state||(a.state="completed");else{"new"===a.state&&(a.state="gathering"),s.component=1,s.ufrag=a.getLocalParameters().usernameFragment;var d=n.writeCandidate(s);o.candidate=Object.assign(o.candidate,n.parseCandidate(d)),o.candidate.candidate=d,o.candidate.toJSON=function(){return{candidate:o.candidate.candidate,sdpMid:o.candidate.sdpMid,sdpMLineIndex:o.candidate.sdpMLineIndex,usernameFragment:o.candidate.usernameFragment}}}var p=n.getMediaSections(i._localDescription.sdp);p[o.candidate.sdpMLineIndex]+=c?"a=end-of-candidates\r\n":"a="+o.candidate.candidate+"\r\n",i._localDescription.sdp=n.getDescription(i._localDescription.sdp)+p.join("");var u=i.transceivers.every((function(e){return e.iceGatherer&&"completed"===e.iceGatherer.state}));"gathering"!==i.iceGatheringState&&(i.iceGatheringState="gathering",i._emitGatheringStateChange()),c||i._dispatchEvent("icecandidate",o),u&&(i._dispatchEvent("icecandidate",new Event("icecandidate")),i.iceGatheringState="complete",i._emitGatheringStateChange())}},e.setTimeout((function(){o.forEach((function(e){a.onlocalcandidate(e)}))}),0)}},p.prototype._createIceAndDtlsTransports=function(){var t=this,r=new e.RTCIceTransport(null);r.onicestatechange=function(){t._updateIceConnectionState(),t._updateConnectionState()};var n=new e.RTCDtlsTransport(r);return n.ondtlsstatechange=function(){t._updateConnectionState()},n.onerror=function(){Object.defineProperty(n,"state",{value:"failed",writable:!0}),t._updateConnectionState()},{iceTransport:r,dtlsTransport:n}},p.prototype._disposeIceAndDtlsTransports=function(e){var t=this.transceivers[e].iceGatherer;t&&(delete t.onlocalcandidate,delete this.transceivers[e].iceGatherer);var r=this.transceivers[e].iceTransport;r&&(delete r.onicestatechange,delete this.transceivers[e].iceTransport);var n=this.transceivers[e].dtlsTransport;n&&(delete n.ondtlsstatechange,delete n.onerror,delete this.transceivers[e].dtlsTransport)},p.prototype._transceive=function(e,r,i){var o=a(e.localCapabilities,e.remoteCapabilities);r&&e.rtpSender&&(o.encodings=e.sendEncodingParameters,o.rtcp={cname:n.localCName,compound:e.rtcpParameters.compound},e.recvEncodingParameters.length&&(o.rtcp.ssrc=e.recvEncodingParameters[0].ssrc),e.rtpSender.send(o)),i&&e.rtpReceiver&&o.codecs.length>0&&("video"===e.kind&&e.recvEncodingParameters&&t<15019&&e.recvEncodingParameters.forEach((function(e){delete e.rtx})),e.recvEncodingParameters.length?o.encodings=e.recvEncodingParameters:o.encodings=[{}],o.rtcp={compound:e.rtcpParameters.compound},e.rtcpParameters.cname&&(o.rtcp.cname=e.rtcpParameters.cname),e.sendEncodingParameters.length&&(o.rtcp.ssrc=e.sendEncodingParameters[0].ssrc),e.rtpReceiver.receive(o))},p.prototype.setLocalDescription=function(e){var t,r,i=this;if(-1===["offer","answer"].indexOf(e.type))return Promise.reject(c("TypeError",'Unsupported type "'+e.type+'"'));if(!o("setLocalDescription",e.type,i.signalingState)||i._isClosed)return Promise.reject(c("InvalidStateError","Can not set local "+e.type+" in state "+i.signalingState));if("offer"===e.type)t=n.splitSections(e.sdp),r=t.shift(),t.forEach((function(e,t){var r=n.parseRtpParameters(e);i.transceivers[t].localCapabilities=r})),i.transceivers.forEach((function(e,t){i._gather(e.mid,t)}));else if("answer"===e.type){t=n.splitSections(i._remoteDescription.sdp),r=t.shift();var s=n.matchPrefix(r,"a=ice-lite").length>0;t.forEach((function(e,t){var o=i.transceivers[t],c=o.iceGatherer,d=o.iceTransport,p=o.dtlsTransport,u=o.localCapabilities,f=o.remoteCapabilities;if(!(n.isRejected(e)&&0===n.matchPrefix(e,"a=bundle-only").length)&&!o.rejected){var l=n.getIceParameters(e,r),m=n.getDtlsParameters(e,r);s&&(m.role="server"),i.usingBundle&&0!==t||(i._gather(o.mid,t),"new"===d.state&&d.start(c,l,s?"controlling":"controlled"),"new"===p.state&&p.start(m));var h=a(u,f);i._transceive(o,h.codecs.length>0,!1)}}))}return i._localDescription={type:e.type,sdp:e.sdp},"offer"===e.type?i._updateSignalingState("have-local-offer"):i._updateSignalingState("stable"),Promise.resolve()},p.prototype.setRemoteDescription=function(i){var p=this;if(-1===["offer","answer"].indexOf(i.type))return Promise.reject(c("TypeError",'Unsupported type "'+i.type+'"'));if(!o("setRemoteDescription",i.type,p.signalingState)||p._isClosed)return Promise.reject(c("InvalidStateError","Can not set remote "+i.type+" in state "+p.signalingState));var u={};p.remoteStreams.forEach((function(e){u[e.id]=e}));var f=[],l=n.splitSections(i.sdp),m=l.shift(),h=n.matchPrefix(m,"a=ice-lite").length>0,v=n.matchPrefix(m,"a=group:BUNDLE ").length>0;p.usingBundle=v;var y=n.matchPrefix(m,"a=ice-options:")[0];return p.canTrickleIceCandidates=!!y&&y.substr(14).split(" ").indexOf("trickle")>=0,l.forEach((function(o,c){var d=n.splitLines(o),l=n.getKind(o),y=n.isRejected(o)&&0===n.matchPrefix(o,"a=bundle-only").length,g=d[0].substr(2).split(" ")[2],C=n.getDirection(o,m),S=n.parseMsid(o),T=n.getMid(o)||n.generateIdentifier();if(y||"application"===l&&("DTLS/SCTP"===g||"UDP/DTLS/SCTP"===g))p.transceivers[c]={mid:T,kind:l,protocol:g,rejected:!0};else{var P,R,b,E,_,w,k,x,M;!y&&p.transceivers[c]&&p.transceivers[c].rejected&&(p.transceivers[c]=p._createTransceiver(l,!0));var D,O,I=n.parseRtpParameters(o);y||(D=n.getIceParameters(o,m),(O=n.getDtlsParameters(o,m)).role="client"),k=n.parseRtpEncodingParameters(o);var j=n.parseRtcpParameters(o),L=n.matchPrefix(o,"a=end-of-candidates",m).length>0,G=n.matchPrefix(o,"a=candidate:").map((function(e){return n.parseCandidate(e)})).filter((function(e){return 1===e.component}));if(("offer"===i.type||"answer"===i.type)&&!y&&v&&c>0&&p.transceivers[c]&&(p._disposeIceAndDtlsTransports(c),p.transceivers[c].iceGatherer=p.transceivers[0].iceGatherer,p.transceivers[c].iceTransport=p.transceivers[0].iceTransport,p.transceivers[c].dtlsTransport=p.transceivers[0].dtlsTransport,p.transceivers[c].rtpSender&&p.transceivers[c].rtpSender.setTransport(p.transceivers[0].dtlsTransport),p.transceivers[c].rtpReceiver&&p.transceivers[c].rtpReceiver.setTransport(p.transceivers[0].dtlsTransport)),"offer"!==i.type||y){if("answer"===i.type&&!y){R=(P=p.transceivers[c]).iceGatherer,b=P.iceTransport,E=P.dtlsTransport,_=P.rtpReceiver,w=P.sendEncodingParameters,x=P.localCapabilities,p.transceivers[c].recvEncodingParameters=k,p.transceivers[c].remoteCapabilities=I,p.transceivers[c].rtcpParameters=j,G.length&&"new"===b.state&&(!h&&!L||v&&0!==c?G.forEach((function(e){s(P.iceTransport,e)})):b.setRemoteCandidates(G)),v&&0!==c||("new"===b.state&&b.start(R,D,"controlling"),"new"===E.state&&E.start(O)),!a(P.localCapabilities,P.remoteCapabilities).codecs.filter((function(e){return"rtx"===e.name.toLowerCase()})).length&&P.sendEncodingParameters[0].rtx&&delete P.sendEncodingParameters[0].rtx,p._transceive(P,"sendrecv"===C||"recvonly"===C,"sendrecv"===C||"sendonly"===C),!_||"sendrecv"!==C&&"sendonly"!==C?delete P.rtpReceiver:(M=_.track,S?(u[S.stream]||(u[S.stream]=new e.MediaStream),r(M,u[S.stream]),f.push([M,_,u[S.stream]])):(u.default||(u.default=new e.MediaStream),r(M,u.default),f.push([M,_,u.default])))}}else{(P=p.transceivers[c]||p._createTransceiver(l)).mid=T,P.iceGatherer||(P.iceGatherer=p._createIceGatherer(c,v)),G.length&&"new"===P.iceTransport.state&&(!L||v&&0!==c?G.forEach((function(e){s(P.iceTransport,e)})):P.iceTransport.setRemoteCandidates(G)),x=e.RTCRtpReceiver.getCapabilities(l),t<15019&&(x.codecs=x.codecs.filter((function(e){return"rtx"!==e.name}))),w=P.sendEncodingParameters||[{ssrc:1001*(2*c+2)}];var A,N=!1;if("sendrecv"===C||"sendonly"===C){if(N=!P.rtpReceiver,_=P.rtpReceiver||new e.RTCRtpReceiver(P.dtlsTransport,l),N)M=_.track,S&&"-"===S.stream||(S?(u[S.stream]||(u[S.stream]=new e.MediaStream,Object.defineProperty(u[S.stream],"id",{get:function(){return S.stream}})),Object.defineProperty(M,"id",{get:function(){return S.track}}),A=u[S.stream]):(u.default||(u.default=new e.MediaStream),A=u.default)),A&&(r(M,A),P.associatedRemoteMediaStreams.push(A)),f.push([M,_,A])}else P.rtpReceiver&&P.rtpReceiver.track&&(P.associatedRemoteMediaStreams.forEach((function(t){var r=t.getTracks().find((function(e){return e.id===P.rtpReceiver.track.id}));r&&function(t,r){r.removeTrack(t),r.dispatchEvent(new e.MediaStreamTrackEvent("removetrack",{track:t}))}(r,t)})),P.associatedRemoteMediaStreams=[]);P.localCapabilities=x,P.remoteCapabilities=I,P.rtpReceiver=_,P.rtcpParameters=j,P.sendEncodingParameters=w,P.recvEncodingParameters=k,p._transceive(p.transceivers[c],!1,N)}}})),void 0===p._dtlsRole&&(p._dtlsRole="offer"===i.type?"active":"passive"),p._remoteDescription={type:i.type,sdp:i.sdp},"offer"===i.type?p._updateSignalingState("have-remote-offer"):p._updateSignalingState("stable"),Object.keys(u).forEach((function(t){var r=u[t];if(r.getTracks().length){if(-1===p.remoteStreams.indexOf(r)){p.remoteStreams.push(r);var n=new Event("addstream");n.stream=r,e.setTimeout((function(){p._dispatchEvent("addstream",n)}))}f.forEach((function(e){var t=e[0],n=e[1];r.id===e[2].id&&d(p,t,n,[r])}))}})),f.forEach((function(e){e[2]||d(p,e[0],e[1],[])})),e.setTimeout((function(){p&&p.transceivers&&p.transceivers.forEach((function(e){e.iceTransport&&"new"===e.iceTransport.state&&e.iceTransport.getRemoteCandidates().length>0&&(console.warn("Timeout for addRemoteCandidate. Consider sending an end-of-candidates notification"),e.iceTransport.addRemoteCandidate({}))}))}),4e3),Promise.resolve()},p.prototype.close=function(){this.transceivers.forEach((function(e){e.iceTransport&&e.iceTransport.stop(),e.dtlsTransport&&e.dtlsTransport.stop(),e.rtpSender&&e.rtpSender.stop(),e.rtpReceiver&&e.rtpReceiver.stop()})),this._isClosed=!0,this._updateSignalingState("closed")},p.prototype._updateSignalingState=function(e){this.signalingState=e;var t=new Event("signalingstatechange");this._dispatchEvent("signalingstatechange",t)},p.prototype._maybeFireNegotiationNeeded=function(){var t=this;"stable"===this.signalingState&&!0!==this.needNegotiation&&(this.needNegotiation=!0,e.setTimeout((function(){if(t.needNegotiation){t.needNegotiation=!1;var e=new Event("negotiationneeded");t._dispatchEvent("negotiationneeded",e)}}),0))},p.prototype._updateIceConnectionState=function(){var e,t={new:0,closed:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};if(this.transceivers.forEach((function(e){e.iceTransport&&!e.rejected&&t[e.iceTransport.state]++})),e="new",t.failed>0?e="failed":t.checking>0?e="checking":t.disconnected>0?e="disconnected":t.new>0?e="new":t.connected>0?e="connected":t.completed>0&&(e="completed"),e!==this.iceConnectionState){this.iceConnectionState=e;var r=new Event("iceconnectionstatechange");this._dispatchEvent("iceconnectionstatechange",r)}},p.prototype._updateConnectionState=function(){var e,t={new:0,closed:0,connecting:0,connected:0,completed:0,disconnected:0,failed:0};if(this.transceivers.forEach((function(e){e.iceTransport&&e.dtlsTransport&&!e.rejected&&(t[e.iceTransport.state]++,t[e.dtlsTransport.state]++)})),t.connected+=t.completed,e="new",t.failed>0?e="failed":t.connecting>0?e="connecting":t.disconnected>0?e="disconnected":t.new>0?e="new":t.connected>0&&(e="connected"),e!==this.connectionState){this.connectionState=e;var r=new Event("connectionstatechange");this._dispatchEvent("connectionstatechange",r)}},p.prototype.createOffer=function(){var r=this;if(r._isClosed)return Promise.reject(c("InvalidStateError","Can not call createOffer after close"));var a=r.transceivers.filter((function(e){return"audio"===e.kind})).length,o=r.transceivers.filter((function(e){return"video"===e.kind})).length,s=arguments[0];if(s){if(s.mandatory||s.optional)throw new TypeError("Legacy mandatory/optional constraints not supported.");void 0!==s.offerToReceiveAudio&&(a=!0===s.offerToReceiveAudio?1:!1===s.offerToReceiveAudio?0:s.offerToReceiveAudio),void 0!==s.offerToReceiveVideo&&(o=!0===s.offerToReceiveVideo?1:!1===s.offerToReceiveVideo?0:s.offerToReceiveVideo)}for(r.transceivers.forEach((function(e){"audio"===e.kind?--a<0&&(e.wantReceive=!1):"video"===e.kind&&--o<0&&(e.wantReceive=!1)}));a>0||o>0;)a>0&&(r._createTransceiver("audio"),a--),o>0&&(r._createTransceiver("video"),o--);var d=n.writeSessionBoilerplate(r._sdpSessionId,r._sdpSessionVersion++);r.transceivers.forEach((function(i,a){var o=i.track,s=i.kind,c=i.mid||n.generateIdentifier();i.mid=c,i.iceGatherer||(i.iceGatherer=r._createIceGatherer(a,r.usingBundle));var d=e.RTCRtpSender.getCapabilities(s);t<15019&&(d.codecs=d.codecs.filter((function(e){return"rtx"!==e.name}))),d.codecs.forEach((function(e){"H264"===e.name&&void 0===e.parameters["level-asymmetry-allowed"]&&(e.parameters["level-asymmetry-allowed"]="1"),i.remoteCapabilities&&i.remoteCapabilities.codecs&&i.remoteCapabilities.codecs.forEach((function(t){e.name.toLowerCase()===t.name.toLowerCase()&&e.clockRate===t.clockRate&&(e.preferredPayloadType=t.payloadType)}))})),d.headerExtensions.forEach((function(e){(i.remoteCapabilities&&i.remoteCapabilities.headerExtensions||[]).forEach((function(t){e.uri===t.uri&&(e.id=t.id)}))}));var p=i.sendEncodingParameters||[{ssrc:1001*(2*a+1)}];o&&t>=15019&&"video"===s&&!p[0].rtx&&(p[0].rtx={ssrc:p[0].ssrc+1}),i.wantReceive&&(i.rtpReceiver=new e.RTCRtpReceiver(i.dtlsTransport,s)),i.localCapabilities=d,i.sendEncodingParameters=p})),"max-compat"!==r._config.bundlePolicy&&(d+="a=group:BUNDLE "+r.transceivers.map((function(e){return e.mid})).join(" ")+"\r\n"),d+="a=ice-options:trickle\r\n",r.transceivers.forEach((function(e,t){d+=i(e,e.localCapabilities,"offer",e.stream,r._dtlsRole),d+="a=rtcp-rsize\r\n",!e.iceGatherer||"new"===r.iceGatheringState||0!==t&&r.usingBundle||(e.iceGatherer.getLocalCandidates().forEach((function(e){e.component=1,d+="a="+n.writeCandidate(e)+"\r\n"})),"completed"===e.iceGatherer.state&&(d+="a=end-of-candidates\r\n"))}));var p=new e.RTCSessionDescription({type:"offer",sdp:d});return Promise.resolve(p)},p.prototype.createAnswer=function(){var r=this;if(r._isClosed)return Promise.reject(c("InvalidStateError","Can not call createAnswer after close"));if("have-remote-offer"!==r.signalingState&&"have-local-pranswer"!==r.signalingState)return Promise.reject(c("InvalidStateError","Can not call createAnswer in signalingState "+r.signalingState));var o=n.writeSessionBoilerplate(r._sdpSessionId,r._sdpSessionVersion++);r.usingBundle&&(o+="a=group:BUNDLE "+r.transceivers.map((function(e){return e.mid})).join(" ")+"\r\n"),o+="a=ice-options:trickle\r\n";var s=n.getMediaSections(r._remoteDescription.sdp).length;r.transceivers.forEach((function(e,n){if(!(n+1>s)){if(e.rejected)return"application"===e.kind?"DTLS/SCTP"===e.protocol?o+="m=application 0 DTLS/SCTP 5000\r\n":o+="m=application 0 "+e.protocol+" webrtc-datachannel\r\n":"audio"===e.kind?o+="m=audio 0 UDP/TLS/RTP/SAVPF 0\r\na=rtpmap:0 PCMU/8000\r\n":"video"===e.kind&&(o+="m=video 0 UDP/TLS/RTP/SAVPF 120\r\na=rtpmap:120 VP8/90000\r\n"),void(o+="c=IN IP4 0.0.0.0\r\na=inactive\r\na=mid:"+e.mid+"\r\n");var c;if(e.stream)"audio"===e.kind?c=e.stream.getAudioTracks()[0]:"video"===e.kind&&(c=e.stream.getVideoTracks()[0]),c&&t>=15019&&"video"===e.kind&&!e.sendEncodingParameters[0].rtx&&(e.sendEncodingParameters[0].rtx={ssrc:e.sendEncodingParameters[0].ssrc+1});var d=a(e.localCapabilities,e.remoteCapabilities);!d.codecs.filter((function(e){return"rtx"===e.name.toLowerCase()})).length&&e.sendEncodingParameters[0].rtx&&delete e.sendEncodingParameters[0].rtx,o+=i(e,d,"answer",e.stream,r._dtlsRole),e.rtcpParameters&&e.rtcpParameters.reducedSize&&(o+="a=rtcp-rsize\r\n")}}));var d=new e.RTCSessionDescription({type:"answer",sdp:o});return Promise.resolve(d)},p.prototype.addIceCandidate=function(e){var t,r=this;return e&&void 0===e.sdpMLineIndex&&!e.sdpMid?Promise.reject(new TypeError("sdpMLineIndex or sdpMid required")):new Promise((function(i,a){if(!r._remoteDescription)return a(c("InvalidStateError","Can not add ICE candidate without a remote description"));if(e&&""!==e.candidate){var o=e.sdpMLineIndex;if(e.sdpMid)for(var d=0;d0?n.parseCandidate(e.candidate):{};if("tcp"===u.protocol&&(0===u.port||9===u.port))return i();if(u.component&&1!==u.component)return i();if((0===o||o>0&&p.iceTransport!==r.transceivers[0].iceTransport)&&!s(p.iceTransport,u))return a(c("OperationError","Can not add ICE candidate"));var f=e.candidate.trim();0===f.indexOf("a=")&&(f=f.substr(2)),(t=n.getMediaSections(r._remoteDescription.sdp))[o]+="a="+(u.type?f:"end-of-candidates")+"\r\n",r._remoteDescription.sdp=n.getDescription(r._remoteDescription.sdp)+t.join("")}else for(var l=0;l0?t[0].split("/")[1]:"sendrecv",uri:t[1]}},n.writeExtmap=function(e){return"a=extmap:"+(e.id||e.preferredId)+(e.direction&&"sendrecv"!==e.direction?"/"+e.direction:"")+" "+e.uri+"\r\n"},n.parseFmtp=function(e){for(var t,r={},n=e.substr(e.indexOf(" ")+1).split(";"),i=0;i-1?(r.attribute=e.substr(t+1,n-t-1),r.value=e.substr(n+1)):r.attribute=e.substr(t+1),r},n.parseSsrcGroup=function(e){var t=e.substr(13).split(" ");return{semantics:t.shift(),ssrcs:t.map((function(e){return parseInt(e,10)}))}},n.getMid=function(e){var t=n.matchPrefix(e,"a=mid:")[0];if(t)return t.substr(6)},n.parseFingerprint=function(e){var t=e.substr(14).split(" ");return{algorithm:t[0].toLowerCase(),value:t[1]}},n.getDtlsParameters=function(e,t){return{role:"auto",fingerprints:n.matchPrefix(e+t,"a=fingerprint:").map(n.parseFingerprint)}},n.writeDtlsParameters=function(e,t){var r="a=setup:"+t+"\r\n";return e.fingerprints.forEach((function(e){r+="a=fingerprint:"+e.algorithm+" "+e.value+"\r\n"})),r},n.parseCryptoLine=function(e){var t=e.substr(9).split(" ");return{tag:parseInt(t[0],10),cryptoSuite:t[1],keyParams:t[2],sessionParams:t.slice(3)}},n.writeCryptoLine=function(e){return"a=crypto:"+e.tag+" "+e.cryptoSuite+" "+("object"==typeof e.keyParams?n.writeCryptoKeyParams(e.keyParams):e.keyParams)+(e.sessionParams?" "+e.sessionParams.join(" "):"")+"\r\n"},n.parseCryptoKeyParams=function(e){if(0!==e.indexOf("inline:"))return null;var t=e.substr(7).split("|");return{keyMethod:"inline",keySalt:t[0],lifeTime:t[1],mkiValue:t[2]?t[2].split(":")[0]:void 0,mkiLength:t[2]?t[2].split(":")[1]:void 0}},n.writeCryptoKeyParams=function(e){return e.keyMethod+":"+e.keySalt+(e.lifeTime?"|"+e.lifeTime:"")+(e.mkiValue&&e.mkiLength?"|"+e.mkiValue+":"+e.mkiLength:"")},n.getCryptoParameters=function(e,t){return n.matchPrefix(e+t,"a=crypto:").map(n.parseCryptoLine)},n.getIceParameters=function(e,t){var r=n.matchPrefix(e+t,"a=ice-ufrag:")[0],i=n.matchPrefix(e+t,"a=ice-pwd:")[0];return r&&i?{usernameFragment:r.substr(12),password:i.substr(10)}:null},n.writeIceParameters=function(e){return"a=ice-ufrag:"+e.usernameFragment+"\r\na=ice-pwd:"+e.password+"\r\n"},n.parseRtpParameters=function(e){for(var t={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]},r=n.splitLines(e)[0].split(" "),i=3;i0?"9":"0",r+=" UDP/TLS/RTP/SAVPF ",r+=t.codecs.map((function(e){return void 0!==e.preferredPayloadType?e.preferredPayloadType:e.payloadType})).join(" ")+"\r\n",r+="c=IN IP4 0.0.0.0\r\n",r+="a=rtcp:9 IN IP4 0.0.0.0\r\n",t.codecs.forEach((function(e){r+=n.writeRtpMap(e),r+=n.writeFmtp(e),r+=n.writeRtcpFb(e)}));var i=0;return t.codecs.forEach((function(e){e.maxptime>i&&(i=e.maxptime)})),i>0&&(r+="a=maxptime:"+i+"\r\n"),r+="a=rtcp-mux\r\n",t.headerExtensions&&t.headerExtensions.forEach((function(e){r+=n.writeExtmap(e)})),r},n.parseRtpEncodingParameters=function(e){var t,r=[],i=n.parseRtpParameters(e),a=-1!==i.fecMechanisms.indexOf("RED"),o=-1!==i.fecMechanisms.indexOf("ULPFEC"),s=n.matchPrefix(e,"a=ssrc:").map((function(e){return n.parseSsrcMedia(e)})).filter((function(e){return"cname"===e.attribute})),c=s.length>0&&s[0].ssrc,d=n.matchPrefix(e,"a=ssrc-group:FID").map((function(e){return e.substr(17).split(" ").map((function(e){return parseInt(e,10)}))}));d.length>0&&d[0].length>1&&d[0][0]===c&&(t=d[0][1]),i.codecs.forEach((function(e){if("RTX"===e.name.toUpperCase()&&e.parameters.apt){var n={ssrc:c,codecPayloadType:parseInt(e.parameters.apt,10)};c&&t&&(n.rtx={ssrc:t}),r.push(n),a&&((n=JSON.parse(JSON.stringify(n))).fec={ssrc:c,mechanism:o?"red+ulpfec":"red"},r.push(n))}})),0===r.length&&c&&r.push({ssrc:c});var p=n.matchPrefix(e,"b=");return p.length&&(p=0===p[0].indexOf("b=TIAS:")?parseInt(p[0].substr(7),10):0===p[0].indexOf("b=AS:")?1e3*parseInt(p[0].substr(5),10)*.95-16e3:void 0,r.forEach((function(e){e.maxBitrate=p}))),r},n.parseRtcpParameters=function(e){var t={},r=n.matchPrefix(e,"a=ssrc:").map((function(e){return n.parseSsrcMedia(e)})).filter((function(e){return"cname"===e.attribute}))[0];r&&(t.cname=r.value,t.ssrc=r.ssrc);var i=n.matchPrefix(e,"a=rtcp-rsize");t.reducedSize=i.length>0,t.compound=0===i.length;var a=n.matchPrefix(e,"a=rtcp-mux");return t.mux=a.length>0,t},n.parseMsid=function(e){var t,r=n.matchPrefix(e,"a=msid:");if(1===r.length)return{stream:(t=r[0].substr(7).split(" "))[0],track:t[1]};var i=n.matchPrefix(e,"a=ssrc:").map((function(e){return n.parseSsrcMedia(e)})).filter((function(e){return"msid"===e.attribute}));return i.length>0?{stream:(t=i[0].value.split(" "))[0],track:t[1]}:void 0},n.parseSctpDescription=function(e){var t,r=n.parseMLine(e),i=n.matchPrefix(e,"a=max-message-size:");i.length>0&&(t=parseInt(i[0].substr(19),10)),isNaN(t)&&(t=65536);var a=n.matchPrefix(e,"a=sctp-port:");if(a.length>0)return{port:parseInt(a[0].substr(12),10),protocol:r.fmt,maxMessageSize:t};if(n.matchPrefix(e,"a=sctpmap:").length>0){var o=n.matchPrefix(e,"a=sctpmap:")[0].substr(10).split(" ");return{port:parseInt(o[0],10),protocol:o[1],maxMessageSize:t}}},n.writeSctpDescription=function(e,t){var r=[];return r="DTLS/SCTP"!==e.protocol?["m="+e.kind+" 9 "+e.protocol+" "+t.protocol+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctp-port:"+t.port+"\r\n"]:["m="+e.kind+" 9 "+e.protocol+" "+t.port+"\r\n","c=IN IP4 0.0.0.0\r\n","a=sctpmap:"+t.port+" "+t.protocol+" 65535\r\n"],void 0!==t.maxMessageSize&&r.push("a=max-message-size:"+t.maxMessageSize+"\r\n"),r.join("")},n.generateSessionId=function(){return Math.random().toString().substr(2,21)},n.writeSessionBoilerplate=function(e,t,r){var i=void 0!==t?t:2;return"v=0\r\no="+(r||"thisisadapterortc")+" "+(e||n.generateSessionId())+" "+i+" IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n"},n.writeMediaSection=function(e,t,r,i){var a=n.writeRtpDescription(e.kind,t);if(a+=n.writeIceParameters(e.iceGatherer.getLocalParameters()),a+=n.writeDtlsParameters(e.dtlsTransport.getLocalParameters(),"offer"===r?"actpass":"active"),a+="a=mid:"+e.mid+"\r\n",e.direction?a+="a="+e.direction+"\r\n":e.rtpSender&&e.rtpReceiver?a+="a=sendrecv\r\n":e.rtpSender?a+="a=sendonly\r\n":e.rtpReceiver?a+="a=recvonly\r\n":a+="a=inactive\r\n",e.rtpSender){var o="msid:"+i.id+" "+e.rtpSender.track.id+"\r\n";a+="a="+o,a+="a=ssrc:"+e.sendEncodingParameters[0].ssrc+" "+o,e.sendEncodingParameters[0].rtx&&(a+="a=ssrc:"+e.sendEncodingParameters[0].rtx.ssrc+" "+o,a+="a=ssrc-group:FID "+e.sendEncodingParameters[0].ssrc+" "+e.sendEncodingParameters[0].rtx.ssrc+"\r\n")}return a+="a=ssrc:"+e.sendEncodingParameters[0].ssrc+" cname:"+n.localCName+"\r\n",e.rtpSender&&e.sendEncodingParameters[0].rtx&&(a+="a=ssrc:"+e.sendEncodingParameters[0].rtx.ssrc+" cname:"+n.localCName+"\r\n"),a},n.getDirection=function(e,t){for(var r=n.splitLines(e),i=0;i - - - - - - - -rtc_media_player:
- - - - - - - \ No newline at end of file diff --git a/trunk/research/players/rtc_player.html b/trunk/research/players/rtc_player.html new file mode 100644 index 0000000000..1ff7899123 --- /dev/null +++ b/trunk/research/players/rtc_player.html @@ -0,0 +1,110 @@ + + + + SRS + + + + + + + + + + +

+
+
+ URL: + + +
+ + + + + +
+ + + diff --git a/trunk/research/players/srs_player.html b/trunk/research/players/srs_player.html index 014e8f6382..b55ed43b7c 100755 --- a/trunk/research/players/srs_player.html +++ b/trunk/research/players/srs_player.html @@ -550,6 +550,9 @@

SrsPlayer

if (query.buffer) { url += "&buffer=" + query.buffer; } + if (query.api_port) { + url += "&api_port=" + query.api_port; + } var queries = user_extra_params(query); if (queries && queries.length) { diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 5cf5fe038b..c6bc4a0069 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -791,6 +791,7 @@ SrsGoApiSdp::~SrsGoApiSdp() { } +// TODO: FIXME: Support query string http://localhost:1985/api/v1/sdp?app=live&stream=livestream srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) { srs_error_t err = srs_success; From 2b56f9ee5910a0d9f78f616643a5df389540da26 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Sat, 14 Mar 2020 22:11:01 +0800 Subject: [PATCH 26/69] add NACK suport, remove debug code, verbose log --- trunk/src/app/srs_app_http_api.cpp | 12 +- trunk/src/app/srs_app_rtc_conn.cpp | 323 +++++++++++++++++++++++--- trunk/src/app/srs_app_rtc_conn.hpp | 36 ++- trunk/src/app/srs_app_rtp.cpp | 2 +- trunk/src/app/srs_app_source.cpp | 60 ++++- trunk/src/app/srs_app_source.hpp | 28 +++ trunk/src/protocol/srs_stun_stack.cpp | 5 +- 7 files changed, 404 insertions(+), 62 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 76b8777428..d5a32658c0 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -801,7 +801,6 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* string req_json; r->body_read_all(req_json); - srs_trace("req_json=%s", req_json.c_str()); SrsJsonAny* json = SrsJsonAny::loads(req_json); SrsJsonObject* req_obj = json->to_object(); @@ -818,18 +817,17 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* string app = app_obj->to_str(); string stream_name = stream_name_obj->to_str(); - srs_trace("remote_sdp_str=%s", remote_sdp_str.c_str()); - srs_trace("app=%s, stream=%s", app.c_str(), stream_name.c_str()); - SrsSdp remote_sdp; err = remote_sdp.decode(remote_sdp_str); if (err != srs_success) { return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); } + SrsRequest request; + request.app = app; + request.stream = stream_name; SrsSdp local_sdp; - SrsRtcSession* rtc_session = rtc_server->create_rtc_session(remote_sdp, local_sdp); - rtc_session->set_app_stream(app, stream_name); + SrsRtcSession* rtc_session = rtc_server->create_rtc_session(request, remote_sdp, local_sdp); string local_sdp_str = ""; err = local_sdp.encode(local_sdp_str); @@ -841,7 +839,7 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* SrsAutoFree(SrsJsonObject, obj); obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); - obj->set("server", SrsJsonAny::integer(stat->server_id())); + obj->set("server", SrsJsonAny::integer(SrsStatistic::instance()->server_id())); // TODO: add candidates in response json? diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index e49a4c5569..62ed7bf03e 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -51,24 +51,24 @@ using namespace std; #include #include -static bool is_stun(const char* data, const int size) +static bool is_stun(const uint8_t* data, const int size) { return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); } -static bool is_dtls(const char* data, size_t len) +static bool is_dtls(const uint8_t* data, size_t len) { return (len >= 13 && (data[0] > 19 && data[0] < 64)); } -static bool is_rtp_or_rtcp(const char* data, size_t len) +static bool is_rtp_or_rtcp(const uint8_t* data, size_t len) { return (len >= 12 && (data[0] & 0xC0) == 0x80); } -static bool is_rtcp(const char* data, size_t len) +static bool is_rtcp(const uint8_t* data, size_t len) { - return (len >=12) && (data[0] & 0x80) && (data[1] >= 200 && data[1] <= 209); + return (len >= 12) && (data[0] & 0x80) && (data[1] >= 200 && data[1] <= 209); } static string gen_random_str(int len) @@ -141,7 +141,7 @@ srs_error_t SrsSdp::decode(const string& sdp_str) string line; istringstream is(sdp_str); while (getline(is, line)) { - srs_trace("line=%s", line.c_str()); + srs_verbose("line=%s", line.c_str()); if (line.size() < 2 || line[1] != '=') { return srs_error_wrap(err, "invalid sdp line=%s", line.c_str()); @@ -267,7 +267,7 @@ srs_error_t SrsSdp::parse_attr(const string& line) } } - srs_trace("sdp attribute key=%s, val=%s", key.c_str(), val.c_str()); + srs_verbose("sdp attribute key=%s, val=%s", key.c_str(), val.c_str()); if (key == "ice-ufrag") { ice_ufrag = val; @@ -345,7 +345,6 @@ srs_error_t SrsDtlsSession::handshake(SrsUdpMuxSocket* udp_mux_skt) } if (out_bio_len) { - srs_trace("send dtls handshake data"); udp_mux_skt->sendto(out_bio_data, out_bio_len, 0); } @@ -405,7 +404,7 @@ srs_error_t SrsDtlsSession::on_dtls_application_data(const char* buf, const int void SrsDtlsSession::send_client_hello(SrsUdpMuxSocket* udp_mux_skt) { if (dtls == NULL) { - srs_trace("send client hello"); + srs_verbose("send client hello"); dtls = SSL_new(SrsDtls::instance()->get_dtls_ctx()); SSL_set_connect_state(dtls); @@ -631,21 +630,17 @@ srs_error_t SrsRtcSenderThread::cycle() srs_error_t err = srs_success; SrsSource* source = NULL; - SrsRequest req; - req.app = rtc_session->app; - req.stream = rtc_session->stream; - if (_srs_sources->fetch_or_create(&req, rtc_session->server, &source) != srs_success) { - srs_error("rtc fetch source failed"); + if (_srs_sources->fetch_or_create(&rtc_session->request, rtc_session->server, &source) != srs_success) { return srs_error_wrap(err, "rtc fetch source failed"); } - srs_trace("rtc fetch source success, app=%s, stream=%s", rtc_session->app.c_str(), rtc_session->stream.c_str()); + srs_trace("source url=%s, source_id=%d[%d]", + rtc_session->request.get_stream_url().c_str(), source->source_id(), source->source_id()); SrsConsumer* consumer = NULL; if (source->create_consumer(NULL, consumer) != srs_success) { - srs_trace("rtc create consumer, app=%s, stream=%s", rtc_session->app.c_str(), rtc_session->stream.c_str()); - return srs_error_wrap(err, "rtc create consumer, app=%s, stream=%s", rtc_session->app.c_str(), rtc_session->stream.c_str()); + return srs_error_wrap(err, "rtc create consumer, source url=%s", rtc_session->request.get_stream_url().c_str()); } SrsAutoFree(SrsConsumer, consumer); @@ -698,7 +693,7 @@ void SrsRtcSenderThread::send_and_free_messages(SrsSharedPtrMessage** msgs, int } } -SrsRtcSession::SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const string& un) +SrsRtcSession::SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un) { server = svr; rtc_server = rtc_svr; @@ -709,6 +704,9 @@ SrsRtcSession::SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const string username = un; last_stun_time = srs_get_system_time(); + + request = req; + source = NULL; } SrsRtcSession::~SrsRtcSession() @@ -736,6 +734,13 @@ srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* return err; } +void SrsRtcSession::check_source() +{ + if (source == NULL) { + _srs_sources->fetch_or_create(&request, server, &source); + } +} + srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req) { srs_error_t err = srs_success; @@ -772,6 +777,210 @@ srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsS return err; } +srs_error_t SrsRtcSession::on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt) +{ + srs_error_t err = srs_success; + + if (nb_buf < 12) { + return srs_error_wrap(err, "invalid rtp feedback packet, nb_buf=%d", nb_buf); + } + + SrsBuffer* stream = new SrsBuffer(buf, nb_buf); + SrsAutoFree(SrsBuffer, stream); + + // @see: https://tools.ietf.org/html/rfc4585#section-6.1 + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P| FMT | PT | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SSRC of packet sender | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SSRC of media source | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + : Feedback Control Information (FCI) : + : : + */ + uint8_t first = stream->read_1bytes(); + uint8_t version = first & 0xC0; + uint8_t padding = first & 0x20; + uint8_t fmt = first & 0x1F; + + uint8_t payload_type = stream->read_1bytes(); + uint16_t length = stream->read_2bytes(); + uint32_t ssrc_of_sender = stream->read_4bytes(); + uint32_t ssrc_of_media_source = stream->read_4bytes(); + + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | PID | BLP | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + uint16_t pid = stream->read_2bytes(); + int blp = stream->read_2bytes(); + + srs_verbose("pid=%u, blp=%d", pid, blp); + + check_source(); + if (! source) { + return srs_error_wrap(err, "can not found source"); + } + + vector resend_pkts; + SrsRtpSharedPacket* pkt = source->find_rtp_packet(pid); + if (pkt) { + resend_pkts.push_back(pkt); + } + + uint16_t mask = 0x01; + for (int i = 0; i < 16 && blp; ++i, mask <<= 1) { + if (! (blp & mask)) { + continue; + } + + uint32_t loss_seq = pid + i; + + SrsRtpSharedPacket* pkt = source->find_rtp_packet(loss_seq); + if (! pkt) { + continue; + } + + resend_pkts.push_back(pkt); + } + + for (int i = 0; i < resend_pkts.size(); ++i) { + if (dtls_session) { + char protected_buf[kRtpPacketSize]; + int nb_protected_buf = resend_pkts[i]->size; + + srs_verbose("resend pkt sequence=%u", resend_pkts[i]->sequence); + + dtls_session->protect_rtp(protected_buf, resend_pkts[i]->payload, nb_protected_buf); + udp_mux_skt->sendto(protected_buf, nb_protected_buf, 0); + } + } + + return err; +} + +srs_error_t SrsRtcSession::on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt) +{ + srs_error_t err = srs_success; + + if (nb_buf < 12) { + return srs_error_wrap(err, "invalid rtp feedback packet, nb_buf=%d", nb_buf); + } + + SrsBuffer* stream = new SrsBuffer(buf, nb_buf); + SrsAutoFree(SrsBuffer, stream); + + uint8_t first = stream->read_1bytes(); + uint8_t version = first & 0xC0; + uint8_t padding = first & 0x20; + uint8_t fmt = first & 0x1F; + + uint8_t payload_type = stream->read_1bytes(); + uint16_t length = stream->read_2bytes(); + uint32_t ssrc_of_sender = stream->read_4bytes(); + uint32_t ssrc_of_media_source = stream->read_4bytes(); + + switch (fmt) { + case kPLI: { + srs_verbose("pli"); + break; + } + case kSLI: { + srs_verbose("sli"); + break; + } + case kRPSI: { + srs_verbose("rpsi"); + break; + } + case kAFB: { + srs_verbose("afb"); + break; + } + default: { + return srs_error_wrap(err, "unknown payload specific feedback=%u", fmt); + } + } + + return err; +} + +srs_error_t SrsRtcSession::on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt) +{ + srs_error_t err = srs_success; + + if (nb_buf < 8) { + return srs_error_wrap(err, "invalid rtp receiver report packet, nb_buf=%d", nb_buf); + } + + SrsBuffer* stream = new SrsBuffer(buf, nb_buf); + SrsAutoFree(SrsBuffer, stream); + + // @see: https://tools.ietf.org/html/rfc3550#section-6.4.2 + /* + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +header |V=2|P| RC | PT=RR=201 | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | SSRC of packet sender | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +report | SSRC_1 (SSRC of first source) | +block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 1 | fraction lost | cumulative number of packets lost | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | extended highest sequence number received | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | interarrival jitter | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | last SR (LSR) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | delay since last SR (DLSR) | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +report | SSRC_2 (SSRC of second source) | +block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 2 : ... : + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | profile-specific extensions | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + uint8_t first = stream->read_1bytes(); + uint8_t version = first & 0xC0; + uint8_t padding = first & 0x20; + uint8_t rc = first & 0x1F; + + uint8_t payload_type = stream->read_1bytes(); + uint16_t length = stream->read_2bytes(); + uint32_t ssrc_of_sender = stream->read_4bytes(); + + if (((length + 1) * 4) != (rc * 24 + 8)) { + return srs_error_wrap(err, "invalid rtcp receiver packet, length=%u, rc=%u", length, rc); + } + + for (int i = 0; i < rc; ++i) { + uint32_t ssrc = stream->read_4bytes(); + uint8_t fraction_lost = stream->read_1bytes(); + uint32_t cumulative_number_of_packets_lost = stream->read_3bytes(); + uint32_t highest_seq = stream->read_4bytes(); + uint32_t jitter = stream->read_4bytes(); + uint32_t lst = stream->read_4bytes(); + uint32_t dlsr = stream->read_4bytes(); + + srs_verbose("ssrc=%u, fraction_lost=%u, cumulative_number_of_packets_lost=%u, highest_seq=%u, jitter=%u, lst=%u, dlst=%u", + ssrc, fraction_lost, cumulative_number_of_packets_lost, highest_seq, jitter, lst, dlsr); + } + + return err; +} + srs_error_t SrsRtcSession::send_client_hello(SrsUdpMuxSocket* udp_mux_skt) { if (dtls_session == NULL) { @@ -855,6 +1064,7 @@ srs_error_t SrsRtcSession::on_rtp(SrsUdpMuxSocket* udp_mux_skt) srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; + if (dtls_session == NULL) { return srs_error_wrap(err, "recv unexpect rtcp packet before dtls done"); } @@ -865,19 +1075,57 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) return srs_error_wrap(err, "rtcp unprotect failed"); } - // FIXME: use SrsRtpPacket - SrsBuffer* stream = new SrsBuffer(unprotected_buf, nb_unprotected_buf); - SrsAutoFree(SrsBuffer, stream); - uint8_t first = stream->read_1bytes(); - uint8_t payload_type = stream->read_1bytes(); + char* ph = unprotected_buf; + int nb_left = nb_unprotected_buf; + while (nb_left) { + uint8_t payload_type = ph[1]; + uint16_t length_4bytes = (((uint16_t)ph[2]) << 8) | ph[3]; - if (payload_type == kSR) { - } else if (payload_type == kRR) { - } else if (kSDES) { - } else if (kBye) { - } else if (kApp) { - } else { - return srs_error_wrap(err, "unknown rtcp type=%u", payload_type); + int length = (length_4bytes + 1) * 4; + + if (length > nb_unprotected_buf) { + return srs_error_wrap(err, "invalid rtcp packet, length=%u", length); + } + + srs_verbose("on rtcp, payload_type=%u", payload_type); + + switch (payload_type) { + case kSR: { + break; + } + case kRR: { + err = on_rtcp_receiver_report(ph, length, udp_mux_skt); + break; + } + case kSDES: { + break; + } + case kBye: { + break; + } + case kApp: { + break; + } + case kRtpFb: { + err = on_rtcp_feedback(ph, length, udp_mux_skt); + break; + } + case kPsFb: { + err = on_rtcp_ps_feedback(ph, length, udp_mux_skt); + break; + } + default:{ + return srs_error_wrap(err, "unknown rtcp type=%u", payload_type); + break; + } + } + + if (err != srs_success) { + return err; + } + + ph += length; + nb_left -= length; } return err; @@ -910,18 +1158,18 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; - if (is_stun(udp_mux_skt->data(), udp_mux_skt->size())) { + if (is_stun(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { return on_stun(udp_mux_skt); - } else if (is_dtls(udp_mux_skt->data(), udp_mux_skt->size())) { + } else if (is_dtls(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { return on_dtls(udp_mux_skt); - } else if (is_rtp_or_rtcp(udp_mux_skt->data(), udp_mux_skt->size())) { + } else if (is_rtp_or_rtcp(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { return on_rtp_or_rtcp(udp_mux_skt); } return srs_error_wrap(err, "unknown udp packet type"); } -SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp) +SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsRequest& req, const SrsSdp& remote_sdp, SrsSdp& local_sdp) { std::string local_pwd = gen_random_str(32); std::string local_ufrag = ""; @@ -934,7 +1182,7 @@ SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsSdp& remote_sdp, SrsSdp break; } - SrsRtcSession* session = new SrsRtcSession(server, this, username); + SrsRtcSession* session = new SrsRtcSession(server, this, req, username); map_username_session.insert(make_pair(username, session)); local_sdp.set_ice_ufrag(local_ufrag); @@ -962,7 +1210,7 @@ srs_error_t SrsRtcServer::on_stun(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; - srs_trace("recv stun packet from %s", udp_mux_skt->get_peer_id().c_str()); + srs_verbose("recv stun packet from %s", udp_mux_skt->get_peer_id().c_str()); SrsStunPacket stun_req; if (stun_req.decode(udp_mux_skt->data(), udp_mux_skt->size()) != srs_success) { @@ -981,7 +1229,6 @@ srs_error_t SrsRtcServer::on_stun(SrsUdpMuxSocket* udp_mux_skt) srs_error_t SrsRtcServer::on_dtls(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; - srs_trace("on dtls"); SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_mux_skt->get_peer_id()); @@ -1004,7 +1251,7 @@ srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt) return srs_error_wrap(err, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); } - if (is_rtcp(udp_mux_skt->data(), udp_mux_skt->size())) { + if (is_rtcp(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { rtc_session->on_rtcp(udp_mux_skt); } else { rtc_session->on_rtp(udp_mux_skt); diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index c1b786af43..d0db07e36f 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -43,12 +44,23 @@ class SrsStunPacket; class SrsRtcServer; class SrsRtcSession; class SrsSharedPtrMessage; +class SrsSource; -const uint8_t kSR = 200; -const uint8_t kRR = 201; +const uint8_t kSR = 200; +const uint8_t kRR = 201; const uint8_t kSDES = 202; -const uint8_t kBye = 203; -const uint8_t kApp = 204; +const uint8_t kBye = 203; +const uint8_t kApp = 204; + +// @see: https://tools.ietf.org/html/rfc4585#section-6.1 +const uint8_t kRtpFb = 205; +const uint8_t kPsFb = 206; + +// @see: https://tools.ietf.org/html/rfc4585#section-6.3 +const uint8_t kPLI = 1; +const uint8_t kSLI = 2; +const uint8_t kRPSI = 3; +const uint8_t kAFB = 15; const srs_utime_t kSrsRtcSessionStunTimeoutUs = 10*1000*1000LL; @@ -182,10 +194,10 @@ class SrsRtcSession std::string peer_id; srs_utime_t last_stun_time; public: - std::string app; - std::string stream; + SrsRequest request; + SrsSource* source; public: - SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const std::string& un); + SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un); virtual ~SrsRtcSession(); public: SrsSdp* get_local_sdp() { return &local_sdp; } @@ -199,8 +211,6 @@ class SrsRtcSession std::string id() const { return peer_id + "_" + username; } - void set_app_stream(const std::string& a, const std::string& s) { app = a; stream = s; } - std::string get_peer_id() const { return peer_id; } void set_peer_id(const std::string& id) { peer_id = id; } public: @@ -214,10 +224,14 @@ class SrsRtcSession srs_error_t start_play(SrsUdpMuxSocket* udp_mux_skt); public: bool is_stun_timeout() { return last_stun_time + kSrsRtcSessionStunTimeoutUs < srs_get_system_time(); } +private: + void check_source(); private: srs_error_t on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req); private: - srs_error_t do_playing(SrsConsumer* consumer, SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt); }; // XXX: is there any other timer thread? @@ -257,7 +271,7 @@ class SrsRtcServer : public ISrsUdpMuxHandler virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* udp_mux_skt); - SrsRtcSession* create_rtc_session(const SrsSdp& remote_sdp, SrsSdp& local_sdp); + SrsRtcSession* create_rtc_session(const SrsRequest& req, const SrsSdp& remote_sdp, SrsSdp& local_sdp); bool insert_into_id_sessions(const std::string& peer_id, SrsRtcSession* rtc_session); void check_and_clean_timeout_session(); private: diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index 729251fc44..0101e30c52 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -78,7 +78,7 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF uint8_t nal_type = header & kNalTypeMask; // ignore SEI nal - if (nal_type == 0x06) { + if (nal_type == 0x06 || nal_type == 0x09) { continue; } diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 5f1de1149c..16e4110bcb 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -31,6 +31,7 @@ using namespace std; #include #include #include +#include #include #include #include @@ -326,6 +327,7 @@ srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** p return err; } + srs_error_t SrsMessageQueue::dump_packets(SrsConsumer* consumer, bool atc, SrsRtmpJitterAlgorithm ag) { srs_error_t err = srs_success; @@ -815,6 +817,55 @@ SrsSharedPtrMessage* SrsMixQueue::pop() return msg; } +SrsRtpPacketQueue::SrsRtpPacketQueue() +{ +} + +SrsRtpPacketQueue::~SrsRtpPacketQueue() +{ + clear(); +} + +void SrsRtpPacketQueue::clear() +{ + map::iterator iter = pkt_queue.begin(); + while (iter != pkt_queue.end()) { + srs_freep(iter->second); + pkt_queue.erase(iter++); + } +} + +void SrsRtpPacketQueue::push(std::vector& pkts) +{ + for (int i = 0; i < pkts.size(); ++i) { + insert(pkts[i]->sequence, pkts[i]); + } +} + +void SrsRtpPacketQueue::insert(const uint16_t& sequence, SrsRtpSharedPacket* pkt) +{ + pkt_queue.insert(make_pair(sequence, pkt->copy())); + if (pkt_queue.size() >= 3000) { + srs_freep(pkt_queue.begin()->second); + pkt_queue.erase(pkt_queue.begin()); + } +} + +SrsRtpSharedPacket* SrsRtpPacketQueue::find(const uint16_t& sequence) +{ + if (pkt_queue.empty()) { + return NULL; + } + + SrsRtpSharedPacket* pkt = NULL; + map::iterator iter = pkt_queue.find(sequence); + if (iter != pkt_queue.end()) { + pkt = iter->second->copy(); + } + + return pkt; +} + SrsOriginHub::SrsOriginHub() { source = NULL; @@ -1076,6 +1127,8 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se srs_error_reset(err); rtp->on_unpublish(); } + + source->rtp_queue->push(msg->rtp_packets); if ((err = hls->on_video(msg, format)) != srs_success) { // apply the error strategy for hls. @@ -1696,7 +1749,6 @@ srs_error_t SrsSourceManager::fetch_or_create(SrsRequest* r, ISrsSourceHandler* SrsSource* source = NULL; if ((source = fetch(r)) != NULL) { - srs_trace("found source"); *pps = source; return err; } @@ -1816,6 +1868,7 @@ SrsSource::SrsSource() jitter_algorithm = SrsRtmpJitterAlgorithmOFF; mix_correct = false; mix_queue = new SrsMixQueue(); + rtp_queue = new SrsRtpPacketQueue(); _can_publish = true; _pre_source_id = _source_id = -1; @@ -1845,6 +1898,7 @@ SrsSource::~SrsSource() srs_freep(hub); srs_freep(meta); srs_freep(mix_queue); + srs_freep(rtp_queue); srs_freep(play_edge); srs_freep(publish_edge); @@ -2593,3 +2647,7 @@ string SrsSource::get_curr_origin() return play_edge->get_curr_origin(); } +SrsRtpSharedPacket* SrsSource::find_rtp_packet(const uint16_t& seq) +{ + return rtp_queue->find(seq); +} diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 674ffc99e4..4f5d93669d 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -62,6 +62,7 @@ class SrsBuffer; #ifdef SRS_AUTO_HDS class SrsHds; #endif +class SrsRtpSharedPacket; // The time jitter algorithm: // 1. full, to ensure stream start at zero, and ensure stream monotonically increasing. @@ -324,6 +325,28 @@ class SrsMixQueue virtual SrsSharedPtrMessage* pop(); }; +class SrsRtpPacketQueue +{ +private: + struct SeqComp + { + bool operator()(const uint16_t& l, const uint16_t& r) const + { + return ((int16_t)(r - l)) > 0; + } + }; +private: + std::map pkt_queue; +public: + SrsRtpPacketQueue(); + virtual ~SrsRtpPacketQueue(); +public: + void clear(); + void push(std::vector& pkts); + void insert(const uint16_t& sequence, SrsRtpSharedPacket* pkt); + SrsRtpSharedPacket* find(const uint16_t& sequence); +}; + // The hub for origin is a collection of utilities for origin only, // For example, DVR, HLS, Forward and Transcode are only available for origin, // they are meanless for edge server. @@ -499,6 +522,8 @@ class SrsSource : public ISrsReloadHandler bool mix_correct; // The mix queue to implements the mix correct algorithm. SrsMixQueue* mix_queue; + // rtp packet queue + SrsRtpPacketQueue* rtp_queue; // For play, whether enabled atc. // The atc(use absolute time and donot adjust time), // directly use msg time and donot adjust if atc is true, @@ -587,6 +612,9 @@ class SrsSource : public ISrsReloadHandler virtual void on_edge_proxy_unpublish(); public: virtual std::string get_curr_origin(); +public: + // Find rtp packet by sequence + SrsRtpSharedPacket* find_rtp_packet(const uint16_t& seq); }; #endif diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp index 146bb23f7f..ae0f43dffe 100644 --- a/trunk/src/protocol/srs_stun_stack.cpp +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -83,9 +83,6 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) string magic_cookie = stream->read_string(4); transcation_id = stream->read_string(12); - srs_trace("message_type=%u, message_len=%u, magic_cookie=%s, transcation_id=%s", - message_type, message_len, magic_cookie.c_str(), transcation_id.c_str()); - if (nb_buf != 20 + message_len) { return srs_error_wrap(err, "invalid stun packet, message_len=%d, nb_buf=%d", message_len, nb_buf); } @@ -111,7 +108,7 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) if (p != string::npos) { local_ufrag = val.substr(0, p); remote_ufrag = val.substr(p + 1); - srs_trace("stun packet local_ufrag=%s, remote_ufrag=%s", local_ufrag.c_str(), remote_ufrag.c_str()); + srs_verbose("stun packet local_ufrag=%s, remote_ufrag=%s", local_ufrag.c_str(), remote_ufrag.c_str()); } break; } From c2916acd92546c7b248186bf6991212a609ecc45 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 14 Mar 2020 22:48:02 +0800 Subject: [PATCH 27/69] For #1638, #307, define webrtc:// url for play --- trunk/research/players/js/srs.page.js | 8 +++----- trunk/research/players/js/winlin.utility.js | 6 +++--- trunk/research/players/rtc_player.html | 20 ++++++++++++++++++-- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/trunk/research/players/js/srs.page.js b/trunk/research/players/js/srs.page.js index f675d17537..5e5d6c956b 100755 --- a/trunk/research/players/js/srs.page.js +++ b/trunk/research/players/js/srs.page.js @@ -58,7 +58,7 @@ function user_extra_params(query, params) { || key === 'filename' || key === 'host' || key === 'hostname' || key === 'http_port' || key === 'pathname' || key === 'port' || key === 'server' || key === 'stream' || key === 'buffer' - || key === 'schema' || key === 'vhost' || key === 'api_port' + || key === 'schema' || key === 'vhost' ) { continue; } @@ -207,9 +207,7 @@ function build_default_hls_url() { } function build_default_rtc_url(query) { - var schema = (!query.schema)? "http":query.schema; var server = (!query.server)? window.location.hostname:query.server; - var port = (!query.api_port)? 1985:query.api_port; var vhost = (!query.vhost)? window.location.hostname:query.vhost; var app = (!query.app)? "live":query.app; var stream = (!query.stream)? "livestream":query.stream; @@ -229,8 +227,8 @@ function build_default_rtc_url(query) { } queries = user_extra_params(query, queries); - var uri = schema + "://" + server + ":" + port + "/api/v1/sdp/?app=" + app + "&stream=" + stream + "&" + queries.join('&'); - while (uri.lastIndexOf("&") == uri.length - 1) { + var uri = "webrtc://" + server + "/" + app + "/" + stream + "?" + queries.join('&'); + while (uri.lastIndexOf("?") == uri.length - 1) { uri = uri.substr(0, uri.length - 1); } diff --git a/trunk/research/players/js/winlin.utility.js b/trunk/research/players/js/winlin.utility.js index 2d82ecc640..18fcdd60c2 100644 --- a/trunk/research/players/js/winlin.utility.js +++ b/trunk/research/players/js/winlin.utility.js @@ -3,9 +3,9 @@ /** * common utilities * depends: jquery1.10 - * https://code.csdn.net/snippets/147103 + * https://gitee.com/winlinvip/codes/rpn0c2ewbomj81augzk4y59 * @see: http://blog.csdn.net/win_lin/article/details/17994347 - * v 1.0.17 + * v 1.0.19 */ /** @@ -293,7 +293,7 @@ function __fill_query(query_string, obj) { function parse_rtmp_url(rtmp_url) { // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri var a = document.createElement("a"); - a.href = rtmp_url.replace("rtmp://", "http://"); + a.href = rtmp_url.replace("rtmp://", "http://").replace("webrtc://", "http://"); var vhost = a.hostname; var app = a.pathname.substr(1, a.pathname.lastIndexOf("/") - 1); diff --git a/trunk/research/players/rtc_player.html b/trunk/research/players/rtc_player.html index 1ff7899123..e0bbdd86fc 100644 --- a/trunk/research/players/rtc_player.html +++ b/trunk/research/players/rtc_player.html @@ -61,6 +61,7 @@ $("#btn_play").click(function(){ $('#rtc_media_player').show(); var urlObject = parse_rtmp_url($("#txt_url").val()); + var schame = window.location.protocol; var pc = new RTCPeerConnection(null); pc.onaddstream = function (event) { @@ -82,14 +83,29 @@ return pc.setLocalDescription(offer).then(function(){ return offer; }); }).then(function(offer) { return new Promise(function(resolve, reject) { + var port = urlObject.user_query.api || 1985; + var api = urlObject.user_query.play || '/api/v1/sdp/'; + if (api.lastIndexOf('/') != api.length - 1) { + api += '/'; + } + + var url = schame + '//' + urlObject.server + ':' + port + api + + '?app=' + urlObject.app + '&stream=' + urlObject.stream; + for (var key in urlObject.user_query) { + if (key != 'api' && key != 'play') { + url += '&' + key + '=' + urlObject.user_query[key]; + } + } + var data = { - "url": urlObject.url, "app": urlObject.app, "stream": urlObject.stream, + "url": url, "streamurl": urlObject.url, + "app": urlObject.app, "stream": urlObject.stream, "sdp": offer.sdp }; console.log("offer: " + JSON.stringify(data)); $.ajax({ - type: "POST", url: urlObject.url, data: JSON.stringify(data), + type: "POST", url: url, data: JSON.stringify(data), contentType:'application/json', dataType: 'json' }).done(function(data) { console.log("answer: " + JSON.stringify(data)); From 4b23d0463576c7d2afafe84e3e63107b5d06376f Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 14 Mar 2020 23:22:25 +0800 Subject: [PATCH 28/69] For #1638, #307, fix rtc player demo bug --- trunk/research/players/rtc_player.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/research/players/rtc_player.html b/trunk/research/players/rtc_player.html index e0bbdd86fc..56bc4be64f 100644 --- a/trunk/research/players/rtc_player.html +++ b/trunk/research/players/rtc_player.html @@ -115,7 +115,7 @@ }); }); }).then(function(answer) { - pc.setRemoteDescription(new RTCSessionDescription({type: 'answer', sdp: answer})); + return pc.setRemoteDescription(new RTCSessionDescription({type: 'answer', sdp: answer})); }).catch(function(reason) { throw reason; }); From 9e856c84e7aef5dd9c0117c04ee361acf193a04c Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 15 Mar 2020 15:58:28 +0800 Subject: [PATCH 29/69] For #1638, #307, remove unused bash variable. --- trunk/configure | 1 - 1 file changed, 1 deletion(-) diff --git a/trunk/configure b/trunk/configure index 9c54c092bd..ab94025064 100755 --- a/trunk/configure +++ b/trunk/configure @@ -150,7 +150,6 @@ LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a" if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-lst"; fi # srtp LibSrtpRoot="${SRS_OBJS_DIR}/srtp2/include"; LibSrtpFile="${SRS_OBJS_DIR}/srtp2/lib/libsrtp2.a" -if [[ $SRS_SHARED_SRTP == YES ]]; then LibSrtpFile="-lsrtp2"; fi # openssl-1.1.0e, for the RTMP complex handshake. LibSSLRoot="";LibSSLfile="" if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == NO ]]; then From e905fce847d2c617c22925cbfed5794af2809d05 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 16 Mar 2020 17:39:06 +0800 Subject: [PATCH 30/69] For #1638, #307, add comments in RTMP/RTP message for RTC. --- trunk/src/app/srs_app_rtp.cpp | 5 ++++- trunk/src/app/srs_app_source.cpp | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index 0101e30c52..58d5942489 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -77,6 +77,7 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF uint8_t header = sample.bytes[0]; uint8_t nal_type = header & kNalTypeMask; + // TODO: FIXME: Magic number? Doc? // ignore SEI nal if (nal_type == 0x06 || nal_type == 0x09) { continue; @@ -253,6 +254,7 @@ void SrsRtp::dispose() } } +// TODO: FIXME: Dead code? srs_error_t SrsRtp::cycle() { srs_error_t err = srs_success; @@ -338,7 +340,8 @@ srs_error_t SrsRtp::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma srs_error_t SrsRtp::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format) { srs_error_t err = srs_success; - + + // TODO: FIXME: Maybe it should config on vhost level. if (!enabled) { return err; } diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 3c3c07c67d..2ef7824a1a 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1122,15 +1122,20 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se return err; } + // Parse RTMP message to RTP packets, in FU-A if too large. if ((err = rtp->on_video(msg, format)) != srs_success) { + // TODO: We should support more strategies. srs_warn("rtp: ignore video error %s", srs_error_desc(err).c_str()); srs_error_reset(err); rtp->on_unpublish(); } + // TODO: FIXME: Refactor to move to rtp? + // Save the RTP packets for find_rtp_packet() to rtx or restore it. source->rtp_queue->push(msg->rtp_packets); if ((err = hls->on_video(msg, format)) != srs_success) { + // TODO: We should support more strategies. // apply the error strategy for hls. // @see https://github.com/ossrs/srs/issues/264 std::string hls_error_strategy = _srs_config->get_hls_on_error(req->vhost); From 2f0b150588ddd6334d36353538c701c8d7cc1413 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 16 Mar 2020 18:05:42 +0800 Subject: [PATCH 31/69] For #1638, #307, accept srs_string_dumps_hex to app utility. --- trunk/src/app/srs_app_utility.cpp | 11 +++++------ trunk/src/app/srs_app_utility.hpp | 5 +++-- trunk/src/kernel/srs_kernel_flv.hpp | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/trunk/src/app/srs_app_utility.cpp b/trunk/src/app/srs_app_utility.cpp index f6da9502fa..2cbd0aeeba 100644 --- a/trunk/src/app/srs_app_utility.cpp +++ b/trunk/src/app/srs_app_utility.cpp @@ -1193,22 +1193,21 @@ void srs_api_dump_summaries(SrsJsonObject* obj) sys->set("conn_srs", SrsJsonAny::integer(nrs->nb_conn_srs)); } -string dump_string_hex(const std::string& str, const int& max_len) +string srs_string_dumps_hex(const std::string& str, const int& limit) { - return dump_string_hex(str.c_str(), str.size(), max_len); + return srs_string_dumps_hex(str.c_str(), str.size(), limit); } -string dump_string_hex(const char* buf, const int nb_buf, const int& max_len) +string srs_string_dumps_hex(const char* buf, const int length, const int& limit) { string ret; - ret.reserve(max_len * 4); + ret.reserve(limit * 4); char tmp_buf[1024*16]; tmp_buf[0] = '\n'; int len = 1; - for (int i = 0; i < nb_buf && i < max_len; ++i) { - //int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "(%03d)%02X ", i, (uint8_t)buf[i]); + for (int i = 0; i < length && i < limit; ++i) { int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 2, "%02X ", (uint8_t)buf[i]); if (nb <= 0) break; diff --git a/trunk/src/app/srs_app_utility.hpp b/trunk/src/app/srs_app_utility.hpp index 0ae50687de..8618c3798a 100644 --- a/trunk/src/app/srs_app_utility.hpp +++ b/trunk/src/app/srs_app_utility.hpp @@ -650,8 +650,9 @@ extern bool srs_is_boolean(std::string str); // Dump summaries for /api/v1/summaries. extern void srs_api_dump_summaries(SrsJsonObject* obj); -extern std::string dump_string_hex(const std::string& str, const int& max_len = INT_MAX); -extern std::string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = INT_MAX); +// Dump string(str in length) to hex, it will process min(limit, length) chars. +extern std::string srs_string_dumps_hex(const std::string& str, const int& limit = INT_MAX); +extern std::string srs_string_dumps_hex(const char* str, const int length, const int& limit = INT_MAX); // Get ENV variable, which may starts with $. // srs_getenv("EIP") === srs_getenv("$EIP") diff --git a/trunk/src/kernel/srs_kernel_flv.hpp b/trunk/src/kernel/srs_kernel_flv.hpp index 3bf3afc69b..ec4545d968 100644 --- a/trunk/src/kernel/srs_kernel_flv.hpp +++ b/trunk/src/kernel/srs_kernel_flv.hpp @@ -39,7 +39,6 @@ class ISrsWriter; class ISrsReader; class SrsFileReader; class SrsPacket; -class SrsSample; class SrsRtpSharedPacket; #define SRS_FLV_TAG_HEADER_SIZE 11 From c2a667cc35c11d43a7b27e70d4a5cdc027202ff4 Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 16 Mar 2020 22:01:09 +0800 Subject: [PATCH 32/69] For #1638, #307, add comments for api and enum --- trunk/src/app/srs_app_http_api.cpp | 1 + trunk/src/app/srs_app_rtc_conn.hpp | 1 + trunk/src/app/srs_app_source.cpp | 1 - trunk/src/app/srs_app_source.hpp | 1 + 4 files changed, 3 insertions(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index c7b779556b..0d3a787ff8 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -818,6 +818,7 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* string app = app_obj->to_str(); string stream_name = stream_name_obj->to_str(); + // TODO: FIXME: It seems remote_sdp doesn't represents the full SDP information. SrsSdp remote_sdp; err = remote_sdp.decode(remote_sdp_str); if (err != srs_success) { diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index d0db07e36f..cf03ea3bdb 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -110,6 +110,7 @@ class SrsSdp enum SrsRtcSessionStateType { + // TODO: FIXME: Should prefixed by enum name. INIT = -1, WAITING_STUN = 1, DOING_DTLS_HANDSHAKE = 2, diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 2ef7824a1a..48716296d8 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -327,7 +327,6 @@ srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** p return err; } - srs_error_t SrsMessageQueue::dump_packets(SrsConsumer* consumer, bool atc, SrsRtmpJitterAlgorithm ag) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 8141195562..083bf3e02d 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -325,6 +325,7 @@ class SrsMixQueue virtual SrsSharedPtrMessage* pop(); }; +// To find the RTP packet for RTX or restore. class SrsRtpPacketQueue { private: From e8b2bb5d2864374f0fe068296042f62433736ead Mon Sep 17 00:00:00 2001 From: HuyaJohn Date: Mon, 16 Mar 2020 07:35:24 -0700 Subject: [PATCH 33/69] process err, do error check, add some error code --- trunk/src/app/srs_app_http_api.cpp | 11 ++- trunk/src/app/srs_app_listener.cpp | 23 ++--- trunk/src/app/srs_app_listener.hpp | 3 +- trunk/src/app/srs_app_rtc_conn.cpp | 122 ++++++++++++++++---------- trunk/src/app/srs_app_rtc_conn.hpp | 4 +- trunk/src/app/srs_app_rtp.cpp | 23 ++++- trunk/src/kernel/srs_kernel_error.hpp | 14 +++ trunk/src/protocol/srs_stun_stack.cpp | 22 +++-- 8 files changed, 144 insertions(+), 78 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 0d3a787ff8..1b4b37f45f 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -801,9 +801,15 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* // e.g. /api/v1/sdp/ args = json:{"sdp":"sdp...", "app":"webrtc", "stream":"test"} string req_json; - r->body_read_all(req_json); + if ((err = r->body_read_all(req_json)) != srs_success) { + return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + } SrsJsonAny* json = SrsJsonAny::loads(req_json); + if (json == NULL) { + return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + } + SrsJsonObject* req_obj = json->to_object(); SrsJsonAny* remote_sdp_obj = req_obj->get_property("sdp"); @@ -832,8 +838,7 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* SrsRtcSession* rtc_session = rtc_server->create_rtc_session(request, remote_sdp, local_sdp); string local_sdp_str = ""; - err = local_sdp.encode(local_sdp_str); - if (err != srs_success) { + if ((err = local_sdp.encode(local_sdp_str)) != srs_success) { return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); } diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index 0ba7684cd5..667dd50365 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -278,20 +278,21 @@ int SrsUdpMuxSocket::recvfrom(srs_utime_t timeout) return nread; } -int SrsUdpMuxSocket::sendto(void* data, int size, srs_utime_t timeout) +srs_error_t SrsUdpMuxSocket::sendto(void* data, int size, srs_utime_t timeout) { - return srs_sendto(lfd, data, size, (sockaddr*)&from, fromlen, timeout); -} + srs_error_t err = srs_success; -int SrsUdpMuxSocket::sendtov(struct iovec* iov, size_t iovlen, srs_utime_t timeout) -{ - struct msghdr udphdr = {0}; - udphdr.msg_name = &from; - udphdr.msg_namelen = fromlen; - udphdr.msg_iov = iov; - udphdr.msg_iovlen = iovlen; + int nb_write = srs_sendto(lfd, data, size, (sockaddr*)&from, fromlen, timeout); + + if (nb_write <= 0) { + if (nb_write < 0 && errno == ETIME) { + return srs_error_new(ERROR_SOCKET_TIMEOUT, "sendto timeout %d ms", srsu2msi(timeout)); + } + + return srs_error_new(ERROR_SOCKET_WRITE, "sendto"); + } - return srs_sendmsg(lfd, &udphdr, 0, timeout); + return err; } std::string SrsUdpMuxSocket::get_peer_id() diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index 605929902f..81cd8a580d 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -146,8 +146,7 @@ class SrsUdpMuxSocket SrsUdpMuxSocket& operator=(const SrsUdpMuxSocket& rhs); int recvfrom(srs_utime_t timeout); - int sendto(void* data, int size, srs_utime_t timeout); - int sendtov(struct iovec* iov, size_t iovlen, srs_utime_t timeout); + srs_error_t sendto(void* data, int size, srs_utime_t timeout); char* data() { return buf; } int size() { return nread; } diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 62ed7bf03e..b20af7ce95 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -327,9 +327,11 @@ srs_error_t SrsDtlsSession::handshake(SrsUdpMuxSocket* udp_mux_skt) int ssl_err = SSL_get_error(dtls, ret); switch(ssl_err) { case SSL_ERROR_NONE: { - err = on_dtls_handshake_done(udp_mux_skt); + if ((err = on_dtls_handshake_done(udp_mux_skt)) != srs_success) { + return srs_error_wrap(err, "dtls handshake done handle"); + } + break; } - break; case SSL_ERROR_WANT_READ: { break; @@ -345,7 +347,9 @@ srs_error_t SrsDtlsSession::handshake(SrsUdpMuxSocket* udp_mux_skt) } if (out_bio_len) { - udp_mux_skt->sendto(out_bio_data, out_bio_len, 0); + if ((err = udp_mux_skt->sendto(out_bio_data, out_bio_len, 0)) != srs_success) { + return srs_error_wrap(err, "send dtls packet"); + } } return err; @@ -354,23 +358,29 @@ srs_error_t SrsDtlsSession::handshake(SrsUdpMuxSocket* udp_mux_skt) srs_error_t SrsDtlsSession::on_dtls(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; - if (! handshake_done) { - BIO_reset(bio_in); - BIO_reset(bio_out); - BIO_write(bio_in, udp_mux_skt->data(), udp_mux_skt->size()); + if (BIO_reset(bio_in) != 1) { + return srs_error_new(ERROR_OpenSslBIOReset, "BIO_reset"); + } + if (BIO_reset(bio_out) != 1) { + return srs_error_new(ERROR_OpenSslBIOReset, "BIO_reset"); + } - handshake(udp_mux_skt); - } else { - BIO_reset(bio_in); - BIO_reset(bio_out); - BIO_write(bio_in, udp_mux_skt->data(), udp_mux_skt->size()); + if (BIO_write(bio_in, udp_mux_skt->data(), udp_mux_skt->size()) <= 0) { + // TODO: 0 or -1 maybe block, use BIO_should_retry to check. + return srs_error_new(ERROR_OpenSslBIOWrite, "BIO_write"); + } + if (! handshake_done) { + err = handshake(udp_mux_skt); + } else { while (BIO_ctrl_pending(bio_in) > 0) { char dtls_read_buf[8092]; int nb = SSL_read(dtls, dtls_read_buf, sizeof(dtls_read_buf)); if (nb > 0) { - on_dtls_application_data(dtls_read_buf, nb); + if ((err =on_dtls_application_data(dtls_read_buf, nb)) != srs_success) { + return srs_error_wrap(err, "dtls application data process"); + } } } } @@ -389,33 +399,46 @@ srs_error_t SrsDtlsSession::on_dtls_handshake_done(SrsUdpMuxSocket* udp_mux_skt) return srs_error_wrap(err, "srtp init failed"); } - rtc_session->on_connection_established(udp_mux_skt); - - return err; + return rtc_session->on_connection_established(udp_mux_skt); } srs_error_t SrsDtlsSession::on_dtls_application_data(const char* buf, const int nb_buf) { srs_error_t err = srs_success; + // TODO: process SCTP protocol(WebRTC datachannel support) + return err; } -void SrsDtlsSession::send_client_hello(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsDtlsSession::send_client_hello(SrsUdpMuxSocket* udp_mux_skt) { + srs_error_t err = srs_success; + if (dtls == NULL) { srs_verbose("send client hello"); - dtls = SSL_new(SrsDtls::instance()->get_dtls_ctx()); + if ((dtls = SSL_new(SrsDtls::instance()->get_dtls_ctx())) == NULL) { + return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls"); + } + SSL_set_connect_state(dtls); - bio_in = BIO_new(BIO_s_mem()); - bio_out = BIO_new(BIO_s_mem()); + if ((bio_in = BIO_new(BIO_s_mem())) == NULL) { + return srs_error_new(ERROR_OpenSslBIONew, "BIO_new in"); + } + + if ((bio_out = BIO_new(BIO_s_mem())) == NULL) { + BIO_free(bio_in); + return srs_error_new(ERROR_OpenSslBIONew, "BIO_new out"); + } SSL_set_bio(dtls, bio_in, bio_out); - handshake(udp_mux_skt); + return handshake(udp_mux_skt); } + + return err; } srs_error_t SrsDtlsSession::srtp_initialize() @@ -724,7 +747,7 @@ srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* srs_error_t err = srs_success; if (stun_req->is_binding_request()) { - if (on_binding_request(udp_mux_skt, stun_req) != srs_success) { + if ((err = on_binding_request(udp_mux_skt, stun_req)) != srs_success) { return srs_error_wrap(err, "stun binding request failed"); } } @@ -758,17 +781,20 @@ srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsS stun_binding_response.set_mapped_address(be32toh(inet_addr(udp_mux_skt->get_peer_ip().c_str()))); stun_binding_response.set_mapped_port(udp_mux_skt->get_peer_port()); - if (stun_binding_response.encode(get_local_sdp()->get_ice_pwd(), stream) != srs_success) { + if ((err = stun_binding_response.encode(get_local_sdp()->get_ice_pwd(), stream)) != srs_success) { return srs_error_wrap(err, "stun binding response encode failed"); } - if (udp_mux_skt->sendto(stream->data(), stream->pos(), 0) <= 0) { + if ((err = udp_mux_skt->sendto(stream->data(), stream->pos(), 0)) != srs_success) { return srs_error_wrap(err, "stun binding response send failed"); } if (get_session_state() == WAITING_STUN) { + if ((err = send_client_hello(udp_mux_skt)) != srs_success) { + return srs_error_wrap(err, "send client hello, failed"); + } + set_session_state(DOING_DTLS_HANDSHAKE); - send_client_hello(udp_mux_skt); peer_id = udp_mux_skt->get_peer_id(); rtc_server->insert_into_id_sessions(peer_id, this); @@ -983,17 +1009,21 @@ block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ srs_error_t SrsRtcSession::send_client_hello(SrsUdpMuxSocket* udp_mux_skt) { + srs_error_t err = srs_success; + if (dtls_session == NULL) { dtls_session = new SrsDtlsSession(this); } dtls_session->send_client_hello(udp_mux_skt); + + return err; } -void SrsRtcSession::on_connection_established(SrsUdpMuxSocket* udp_mux_skt) +srs_error_t SrsRtcSession::on_connection_established(SrsUdpMuxSocket* udp_mux_skt) { srs_trace("rtc session=%s, connection established", id().c_str()); - start_play(udp_mux_skt); + return start_play(udp_mux_skt); } srs_error_t SrsRtcSession::start_play(SrsUdpMuxSocket* udp_mux_skt) @@ -1002,7 +1032,9 @@ srs_error_t SrsRtcSession::start_play(SrsUdpMuxSocket* udp_mux_skt) srs_freep(strd); strd = new SrsRtcSenderThread(this, udp_mux_skt, _srs_context->get_id()); - strd->start(); + if ((err = strd->start()) != srs_success) { + return srs_error_wrap(err, "start SrsRtcSenderThread"); + } return err; } @@ -1016,12 +1048,12 @@ srs_error_t SrsRtcSession::on_rtp(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; if (dtls_session == NULL) { - return srs_error_wrap(err, "recv unexpect rtp packet before dtls done"); + return srs_error_new(ERROR_RTC_RTP, "recv unexpect rtp packet before dtls done"); } char unprotected_buf[1460]; int nb_unprotected_buf = udp_mux_skt->size(); - if (dtls_session->unprotect_rtp(unprotected_buf, udp_mux_skt->data(), nb_unprotected_buf) != srs_success) { + if ((err = dtls_session->unprotect_rtp(unprotected_buf, udp_mux_skt->data(), nb_unprotected_buf)) != srs_success) { return srs_error_wrap(err, "rtp unprotect failed"); } @@ -1066,12 +1098,12 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) srs_error_t err = srs_success; if (dtls_session == NULL) { - return srs_error_wrap(err, "recv unexpect rtcp packet before dtls done"); + return srs_error_new(ERROR_RTC_RTCP, "recv unexpect rtp packet before dtls done"); } char unprotected_buf[1460]; int nb_unprotected_buf = udp_mux_skt->size(); - if (dtls_session->unprotect_rtcp(unprotected_buf, udp_mux_skt->data(), nb_unprotected_buf) != srs_success) { + if ((err = dtls_session->unprotect_rtcp(unprotected_buf, udp_mux_skt->data(), nb_unprotected_buf)) != srs_success) { return srs_error_wrap(err, "rtcp unprotect failed"); } @@ -1084,7 +1116,7 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) int length = (length_4bytes + 1) * 4; if (length > nb_unprotected_buf) { - return srs_error_wrap(err, "invalid rtcp packet, length=%u", length); + return srs_error_new(ERROR_RTC_RTCP, "invalid rtcp packet, length=%u", length); } srs_verbose("on rtcp, payload_type=%u", payload_type); @@ -1120,8 +1152,8 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) } } - if (err != srs_success) { - return err; + if (err != srs_success) { + return srs_error_wrap(err, "rtcp"); } ph += length; @@ -1156,8 +1188,6 @@ srs_error_t SrsRtcServer::initialize() srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* udp_mux_skt) { - srs_error_t err = srs_success; - if (is_stun(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { return on_stun(udp_mux_skt); } else if (is_dtls(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { @@ -1166,7 +1196,7 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* udp_mux_skt) return on_rtp_or_rtcp(udp_mux_skt); } - return srs_error_wrap(err, "unknown udp packet type"); + return srs_error_new(ERROR_RTC_UDP, "unknown udp packet type"); } SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsRequest& req, const SrsSdp& remote_sdp, SrsSdp& local_sdp) @@ -1213,14 +1243,14 @@ srs_error_t SrsRtcServer::on_stun(SrsUdpMuxSocket* udp_mux_skt) srs_verbose("recv stun packet from %s", udp_mux_skt->get_peer_id().c_str()); SrsStunPacket stun_req; - if (stun_req.decode(udp_mux_skt->data(), udp_mux_skt->size()) != srs_success) { + if ((err = stun_req.decode(udp_mux_skt->data(), udp_mux_skt->size())) != srs_success) { return srs_error_wrap(err, "decode stun packet failed"); } std::string username = stun_req.get_username(); SrsRtcSession* rtc_session = find_rtc_session_by_username(username); if (rtc_session == NULL) { - return srs_error_wrap(err, "can not find rtc_session, stun username=%s", username.c_str()); + return srs_error_new(ERROR_RTC_STUN, "can not find rtc_session, stun username=%s", username.c_str()); } return rtc_session->on_stun(udp_mux_skt, &stun_req); @@ -1233,12 +1263,10 @@ srs_error_t SrsRtcServer::on_dtls(SrsUdpMuxSocket* udp_mux_skt) SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_mux_skt->get_peer_id()); if (rtc_session == NULL) { - return srs_error_wrap(err, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); + return srs_error_new(ERROR_RTC_DTLS, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); } - rtc_session->on_dtls(udp_mux_skt); - - return err; + return rtc_session->on_dtls(udp_mux_skt); } srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt) @@ -1248,13 +1276,13 @@ srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt) SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_mux_skt->get_peer_id()); if (rtc_session == NULL) { - return srs_error_wrap(err, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); + return srs_error_new(ERROR_RTC_RTP, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); } if (is_rtcp(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { - rtc_session->on_rtcp(udp_mux_skt); + err = rtc_session->on_rtcp(udp_mux_skt); } else { - rtc_session->on_rtp(udp_mux_skt); + err = rtc_session->on_rtp(udp_mux_skt); } return err; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index cf03ea3bdb..422e6ca9d6 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -143,7 +143,7 @@ class SrsDtlsSession srs_error_t on_dtls_handshake_done(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_dtls_application_data(const char* data, const int len); - void send_client_hello(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t send_client_hello(SrsUdpMuxSocket* udp_mux_skt); public: srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf); srs_error_t unprotect_rtp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf); @@ -221,7 +221,7 @@ class SrsRtcSession srs_error_t on_rtcp(SrsUdpMuxSocket* udp_mux_skt); public: srs_error_t send_client_hello(SrsUdpMuxSocket* udp_mux_skt); - void on_connection_established(SrsUdpMuxSocket* udp_mux_skt); + srs_error_t on_connection_established(SrsUdpMuxSocket* udp_mux_skt); srs_error_t start_play(SrsUdpMuxSocket* udp_mux_skt); public: bool is_stun_timeout() { return last_stun_time + kSrsRtcSessionStunTimeoutUs < srs_get_system_time(); } diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index 58d5942489..f8cf2e7c59 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -84,9 +84,13 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF } if (sample.size <= max_payload_size) { - packet_single_nalu(shared_frame, format, &sample, rtp_packet_vec); + if ((err = packet_single_nalu(shared_frame, format, &sample, rtp_packet_vec)) != srs_success) { + return srs_error_wrap(err, "packet single nalu"); + } } else { - packet_fu_a(shared_frame, format, &sample, rtp_packet_vec); + if ((err = packet_fu_a(shared_frame, format, &sample, rtp_packet_vec)) != srs_success) { + return srs_error_wrap(err, "packet fu-a"); + } } } @@ -105,7 +109,9 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma uint8_t nal_type = header & kNalTypeMask; if (nal_type == kIdr) { - packet_stap_a(sps, pps, shared_frame, rtp_packet_vec); + if ((err = packet_stap_a(sps, pps, shared_frame, rtp_packet_vec)) != srs_success) { + return srs_error_wrap(err, "packet stap-a"); + } } int num_of_packet = (sample->size - 1 + max_payload_size) / max_payload_size; @@ -154,6 +160,8 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma rtp_packet_vec.push_back(rtp_shared_pkt); } + + return err; } srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, SrsFormat* format, SrsSample* sample, vector& rtp_packet_vec) @@ -168,7 +176,9 @@ srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, S SrsAutoFree(SrsBuffer, stream); if (nal_type == kIdr) { - packet_stap_a(sps, pps, shared_frame, rtp_packet_vec); + if ((err = packet_stap_a(sps, pps, shared_frame, rtp_packet_vec)) != srs_success) { + return srs_error_wrap(err, "packet stap-a"); + } } // v=2,p=0,x=0,cc=0 @@ -196,6 +206,10 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs { srs_error_t err = srs_success; + if (sps.empty() || pps.empty()) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "sps/pps empty"); + } + uint8_t header = sps[0]; uint8_t nal_type = header & kNalTypeMask; @@ -245,6 +259,7 @@ SrsRtp::SrsRtp() SrsRtp::~SrsRtp() { + srs_freep(rtp_h264_muxer); } void SrsRtp::dispose() diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index 79e30ba692..7461ebbcc2 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -324,8 +324,22 @@ #define ERROR_HTTP_302_INVALID 4038 #define ERROR_BASE64_DECODE 4039 #define ERROR_HTTP_STREAM_EOF 4040 + +/////////////////////////////////////////////////////// +// RTC protocol error. +/////////////////////////////////////////////////////// #define ERROR_RTC_PORT 4041 #define ERROR_RTP_PACKET_CREATE 4042 +#define ERROR_OpenSslCreateSSL 4043 +#define ERROR_OpenSslBIOReset 4044 +#define ERROR_OpenSslBIOWrite 4045 +#define ERROR_OpenSslBIONew 4046 +#define ERROR_RTC_RTP 4047 +#define ERROR_RTC_RTCP 4048 +#define ERROR_RTC_STUN 4049 +#define ERROR_RTC_DTLS 4050 +#define ERROR_RTC_UDP 4051 +#define ERROR_RTC_RTP_MUXER 4052 /////////////////////////////////////////////////////// // HTTP API error. diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp index ae0f43dffe..ee81f5363d 100644 --- a/trunk/src/protocol/srs_stun_stack.cpp +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -31,23 +31,27 @@ static srs_error_t hmac_encode(const std::string& algo, const char* key, const i } else if(algo == "sha384") { engine = EVP_sha384(); } else { - return srs_error_wrap(err, "unknown algo=%s", algo.c_str()); + return srs_error_new(ERROR_RTC_STUN, "unknown algo=%s", algo.c_str()); } HMAC_CTX* ctx = HMAC_CTX_new(); + if (ctx == NULL) { + return srs_error_new(ERROR_RTC_STUN, "hmac init faied"); + } + if (HMAC_Init_ex(ctx, key, key_length, engine, NULL) < 0) { HMAC_CTX_free(ctx); - return srs_error_wrap(err, "hmac init faied"); + return srs_error_new(ERROR_RTC_STUN, "hmac init faied"); } if (HMAC_Update(ctx, (const unsigned char*)input, input_length) < 0) { HMAC_CTX_free(ctx); - return srs_error_wrap(err, "hmac update faied"); + return srs_error_new(ERROR_RTC_STUN, "hmac update faied"); } if (HMAC_Final(ctx, (unsigned char*)output, &output_length) < 0) { HMAC_CTX_free(ctx); - return srs_error_wrap(err, "hmac final faied"); + return srs_error_new(ERROR_RTC_STUN, "hmac final faied"); } HMAC_CTX_free(ctx); @@ -75,7 +79,7 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) SrsAutoFree(SrsBuffer, stream); if (stream->left() < 20) { - return srs_error_wrap(err, "invalid stun packet, size=%d", stream->size()); + return srs_error_new(ERROR_RTC_STUN, "invalid stun packet, size=%d", stream->size()); } message_type = stream->read_2bytes(); @@ -84,7 +88,7 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) transcation_id = stream->read_string(12); if (nb_buf != 20 + message_len) { - return srs_error_wrap(err, "invalid stun packet, message_len=%d, nb_buf=%d", message_len, nb_buf); + return srs_error_new(ERROR_RTC_STUN, "invalid stun packet, message_len=%d, nb_buf=%d", message_len, nb_buf); } while (stream->left() >= 4) { @@ -92,7 +96,7 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) uint16_t len = stream->read_2bytes(); if (stream->left() < len) { - return srs_error_wrap(err, "invalid stun packet"); + return srs_error_new(ERROR_RTC_STUN, "invalid stun packet"); } string val = stream->read_string(len); @@ -129,7 +133,7 @@ srs_error_t SrsStunPacket::encode(const string& pwd, SrsBuffer* stream) return encode_binding_response(pwd, stream); } - return srs_error_wrap(err, "unknown stun type=%d", get_message_type()); + return srs_error_new(ERROR_RTC_STUN, "unknown stun type=%d", get_message_type()); } // FIXME: make this function easy to read @@ -152,7 +156,7 @@ srs_error_t SrsStunPacket::encode_binding_response(const string& pwd, SrsBuffer* char hmac_buf[20] = {0}; unsigned int hmac_buf_len = 0; - if (hmac_encode("sha1", pwd.c_str(), pwd.size(), stream->data(), stream->pos(), hmac_buf, hmac_buf_len) != srs_success) { + if ((err = hmac_encode("sha1", pwd.c_str(), pwd.size(), stream->data(), stream->pos(), hmac_buf, hmac_buf_len)) != srs_success) { return srs_error_wrap(err, "hmac encode failed"); } From b5dd5021036fdf3597c5c7d2df3f17102bf39267 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 17 Mar 2020 09:16:52 +0800 Subject: [PATCH 34/69] For #1638, #307, fix build warnings --- trunk/src/app/srs_app_dtls.cpp | 5 ++- trunk/src/app/srs_app_http_api.cpp | 3 +- trunk/src/app/srs_app_rtc_conn.cpp | 55 ++++++++++++++------------- trunk/src/app/srs_app_rtp.cpp | 3 -- trunk/src/app/srs_app_source.cpp | 2 +- trunk/src/kernel/srs_kernel_flv.cpp | 4 +- trunk/src/protocol/srs_stun_stack.cpp | 1 - 7 files changed, 36 insertions(+), 37 deletions(-) diff --git a/trunk/src/app/srs_app_dtls.cpp b/trunk/src/app/srs_app_dtls.cpp index 4a863fd924..f4e50e1bfa 100644 --- a/trunk/src/app/srs_app_dtls.cpp +++ b/trunk/src/app/srs_app_dtls.cpp @@ -118,8 +118,9 @@ void SrsDtls::init() char *p = fp; unsigned char md[EVP_MAX_MD_SIZE]; unsigned int n = 0; - - int r = X509_digest(dtls_cert, EVP_sha256(), md, &n); + + // TODO: FIXME: Unused variable. + /*int r = */X509_digest(dtls_cert, EVP_sha256(), md, &n); for (unsigned int i = 0; i < n; i++, ++p) { sprintf(p, "%02X", md[i]); diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 1b4b37f45f..96cde96dd7 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -835,7 +835,8 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* request.app = app; request.stream = stream_name; SrsSdp local_sdp; - SrsRtcSession* rtc_session = rtc_server->create_rtc_session(request, remote_sdp, local_sdp); + // TODO: FIXME: Maybe need a better name? + /*SrsRtcSession* rtc_session = */rtc_server->create_rtc_session(request, remote_sdp, local_sdp); string local_sdp_str = ""; if ((err = local_sdp.encode(local_sdp_str)) != srs_success) { diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index b20af7ce95..2361b721b9 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -102,7 +102,7 @@ std::vector SrsCandidate::get_candidate_ips() string candidate = _srs_config->get_rtc_candidates(); if (candidate == "*" || candidate == "0.0.0.0") { std::vector tmp = srs_get_local_ips(); - for (int i = 0; i < tmp.size(); ++i) { + for (int i = 0; i < (int)tmp.size(); ++i) { if (tmp[i] != "127.0.0.1") { candidate_ips.push_back(tmp[i]); } @@ -185,7 +185,7 @@ srs_error_t SrsSdp::encode(string& sdp_str) string candidate_lines = ""; std::vector candidate_ips = SrsCandidate::get_candidate_ips(); - for (int i = 0; i < candidate_ips.size(); ++i) { + for (int i = 0; i < (int)candidate_ips.size(); ++i) { ostringstream os; os << "a=candidate:10 1 udp 2115783679 " << candidate_ips[i] << " " << _srs_config->get_rtc_listen() <<" typ host generation 0\\r\\n"; candidate_lines += os.str(); @@ -257,7 +257,7 @@ srs_error_t SrsSdp::parse_attr(const string& line) string key = ""; string val = ""; string* p = &key; - for (int i = 2; i < line.size(); ++i) { + for (int i = 2; i < (int)line.size(); ++i) { if (line[i] == ':' && p == &key) { p = &val; } else { @@ -701,7 +701,7 @@ void SrsRtcSenderThread::send_and_free_messages(SrsSharedPtrMessage** msgs, int for (int i = 0; i < nb_msgs; i++) { SrsSharedPtrMessage* msg = msgs[i]; - for (int i = 0; i < msg->rtp_packets.size(); ++i) { + for (int i = 0; i < (int)msg->rtp_packets.size(); ++i) { if (rtc_session->dtls_session) { char protected_buf[kRtpPacketSize]; int nb_protected_buf = msg->rtp_packets[i]->size; @@ -828,15 +828,15 @@ srs_error_t SrsRtcSession::on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSock : Feedback Control Information (FCI) : : : */ - uint8_t first = stream->read_1bytes(); - uint8_t version = first & 0xC0; - uint8_t padding = first & 0x20; - uint8_t fmt = first & 0x1F; + /*uint8_t first = */stream->read_1bytes(); + //uint8_t version = first & 0xC0; + //uint8_t padding = first & 0x20; + //uint8_t fmt = first & 0x1F; - uint8_t payload_type = stream->read_1bytes(); - uint16_t length = stream->read_2bytes(); - uint32_t ssrc_of_sender = stream->read_4bytes(); - uint32_t ssrc_of_media_source = stream->read_4bytes(); + /*uint8_t payload_type = */stream->read_1bytes(); + /*uint16_t length = */stream->read_2bytes(); + /*uint32_t ssrc_of_sender = */stream->read_4bytes(); + /*uint32_t ssrc_of_media_source = */stream->read_4bytes(); /* 0 1 2 3 @@ -878,7 +878,7 @@ srs_error_t SrsRtcSession::on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSock resend_pkts.push_back(pkt); } - for (int i = 0; i < resend_pkts.size(); ++i) { + for (int i = 0; i < (int)resend_pkts.size(); ++i) { if (dtls_session) { char protected_buf[kRtpPacketSize]; int nb_protected_buf = resend_pkts[i]->size; @@ -905,14 +905,15 @@ srs_error_t SrsRtcSession::on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxS SrsAutoFree(SrsBuffer, stream); uint8_t first = stream->read_1bytes(); - uint8_t version = first & 0xC0; - uint8_t padding = first & 0x20; + //uint8_t version = first & 0xC0; + //uint8_t padding = first & 0x20; uint8_t fmt = first & 0x1F; - uint8_t payload_type = stream->read_1bytes(); - uint16_t length = stream->read_2bytes(); - uint32_t ssrc_of_sender = stream->read_4bytes(); - uint32_t ssrc_of_media_source = stream->read_4bytes(); + // TODO: FIXME: Dead code? + /*uint8_t payload_type = */stream->read_1bytes(); + /*uint16_t length = */stream->read_2bytes(); + /*uint32_t ssrc_of_sender = */stream->read_4bytes(); + /*uint32_t ssrc_of_media_source = */stream->read_4bytes(); switch (fmt) { case kPLI: { @@ -979,13 +980,13 @@ block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ uint8_t first = stream->read_1bytes(); - uint8_t version = first & 0xC0; - uint8_t padding = first & 0x20; + //uint8_t version = first & 0xC0; + //uint8_t padding = first & 0x20; uint8_t rc = first & 0x1F; - uint8_t payload_type = stream->read_1bytes(); + /*uint8_t payload_type = */stream->read_1bytes(); uint16_t length = stream->read_2bytes(); - uint32_t ssrc_of_sender = stream->read_4bytes(); + /*uint32_t ssrc_of_sender = */stream->read_4bytes(); if (((length + 1) * 4) != (rc * 24 + 8)) { return srs_error_wrap(err, "invalid rtcp receiver packet, length=%u, rc=%u", length, rc); @@ -1000,6 +1001,7 @@ block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ uint32_t lst = stream->read_4bytes(); uint32_t dlsr = stream->read_4bytes(); + (void)ssrc; (void)fraction_lost; (void)cumulative_number_of_packets_lost; (void)highest_seq; (void)jitter; (void)lst; (void)dlsr; srs_verbose("ssrc=%u, fraction_lost=%u, cumulative_number_of_packets_lost=%u, highest_seq=%u, jitter=%u, lst=%u, dlst=%u", ssrc, fraction_lost, cumulative_number_of_packets_lost, highest_seq, jitter, lst, dlsr); } @@ -1073,18 +1075,19 @@ srs_error_t SrsRtcSession::on_rtp(SrsUdpMuxSocket* udp_mux_skt) uint32_t timestamp = stream->read_4bytes(); uint32_t ssrc = stream->read_4bytes(); + (void)padding; (void)marker; (void)sequence; (void)timestamp; (void)ssrc; srs_verbose("sequence=%u, timestamp=%u, ssrc=%u, padding=%d, ext=%d, cc=%u, marker=%d, payload_type=%u", sequence, timestamp, ssrc, padding, ext, cc, marker, payload_type); for (uint8_t i = 0; i < cc; ++i) { - uint32_t csrc = 0; - csrc = stream->read_4bytes(); + /*uint32_t csrc = */stream->read_4bytes(); } if (ext) { uint16_t extern_profile = stream->read_2bytes(); uint16_t extern_length = stream->read_2bytes(); + (void)extern_profile; (void)extern_length; srs_verbose("extern_profile=%u, extern_length=%u", extern_profile, extern_length); stream->read_string(extern_length * 4); @@ -1258,8 +1261,6 @@ srs_error_t SrsRtcServer::on_stun(SrsUdpMuxSocket* udp_mux_skt) srs_error_t SrsRtcServer::on_dtls(SrsUdpMuxSocket* udp_mux_skt) { - srs_error_t err = srs_success; - SrsRtcSession* rtc_session = find_rtc_session_by_peer_id(udp_mux_skt->get_peer_id()); if (rtc_session == NULL) { diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index f8cf2e7c59..7acbab24d0 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -115,7 +115,6 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma } int num_of_packet = (sample->size - 1 + max_payload_size) / max_payload_size; - int avg_packet_size = sample->size / num_of_packet; for (int i = 0; i < num_of_packet; ++i) { char* buf = new char[kRtpPacketSize]; SrsBuffer* stream = new SrsBuffer(buf, kRtpPacketSize); @@ -312,8 +311,6 @@ srs_error_t SrsRtp::on_publish() void SrsRtp::on_unpublish() { - srs_error_t err = srs_success; - // support multiple unpublish. if (!enabled) { return; diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 48716296d8..bccf5aae79 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -836,7 +836,7 @@ void SrsRtpPacketQueue::clear() void SrsRtpPacketQueue::push(std::vector& pkts) { - for (int i = 0; i < pkts.size(); ++i) { + for (int i = 0; i < (int)pkts.size(); ++i) { insert(pkts[i]->sequence, pkts[i]); } } diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index 5996b60b5a..be4e808e2c 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -230,7 +230,7 @@ SrsSharedPtrMessage::~SrsSharedPtrMessage() } } - for (int i = 0; i < rtp_packets.size(); ++i) { + for (int i = 0; i < (int)rtp_packets.size(); ++i) { srs_freep(rtp_packets[i]); } } @@ -351,7 +351,7 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy() copy->payload = ptr->payload; copy->size = ptr->size; - for (int i = 0; i < rtp_packets.size(); ++i) { + for (int i = 0; i < (int)rtp_packets.size(); ++i) { copy->rtp_packets.push_back(rtp_packets[i]->copy()); } diff --git a/trunk/src/protocol/srs_stun_stack.cpp b/trunk/src/protocol/srs_stun_stack.cpp index ee81f5363d..4330c92f79 100644 --- a/trunk/src/protocol/srs_stun_stack.cpp +++ b/trunk/src/protocol/srs_stun_stack.cpp @@ -128,7 +128,6 @@ srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf) srs_error_t SrsStunPacket::encode(const string& pwd, SrsBuffer* stream) { - srs_error_t err = srs_success; if (is_binding_response()) { return encode_binding_response(pwd, stream); } From 6118ca382a68b3e292939611a9a308002608873e Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 17 Mar 2020 11:40:05 +0800 Subject: [PATCH 35/69] For #1638, #307, http api success with message, timeout as such --- trunk/src/app/srs_app_conn.cpp | 7 +++++++ trunk/src/app/srs_app_http_api.cpp | 5 +++++ trunk/src/kernel/srs_kernel_error.cpp | 29 +++++++++++++++++++++++---- trunk/src/kernel/srs_kernel_error.hpp | 4 ++++ 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/trunk/src/app/srs_app_conn.cpp b/trunk/src/app/srs_app_conn.cpp index adfa17fe5e..aa3f8300a6 100644 --- a/trunk/src/app/srs_app_conn.cpp +++ b/trunk/src/app/srs_app_conn.cpp @@ -178,6 +178,13 @@ srs_error_t SrsConnection::cycle() srs_trace("client finished."); return err; } + + // It maybe success with message. + if (srs_error_code(err) == ERROR_SUCCESS) { + srs_trace("client finished%s.", srs_error_summary(err).c_str()); + srs_freep(err); + return err; + } // client close peer. // TODO: FIXME: Only reset the error when client closed it. diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 96cde96dd7..cb8615d684 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1431,6 +1431,11 @@ srs_error_t SrsHttpApi::do_cycle() // get a http message if ((err = parser->parse_message(skt, &req)) != srs_success) { + // For HTTP timeout, we think it's ok. + if (srs_error_code(err) == ERROR_SOCKET_TIMEOUT) { + srs_freep(err); + return srs_error_wrap(srs_success, "http api timeout"); + } return srs_error_wrap(err, "parse message"); } diff --git a/trunk/src/kernel/srs_kernel_error.cpp b/trunk/src/kernel/srs_kernel_error.cpp index 8b66f03d5c..dd5efc35a1 100644 --- a/trunk/src/kernel/srs_kernel_error.cpp +++ b/trunk/src/kernel/srs_kernel_error.cpp @@ -69,14 +69,14 @@ std::string SrsCplxError::description() { if (desc.empty()) { stringstream ss; ss << "code=" << code; - + SrsCplxError* next = this; while (next) { ss << " : " << next->msg; next = next->wrapped; } ss << endl; - + next = this; while (next) { ss << "thread [" << getpid() << "][" << next->cid << "]: " @@ -89,13 +89,29 @@ std::string SrsCplxError::description() { ss << endl; } } - + desc = ss.str(); } - + return desc; } +std::string SrsCplxError::summary() { + if (_summary.empty()) { + stringstream ss; + + SrsCplxError* next = this; + while (next) { + ss << " : " << next->msg; + next = next->wrapped; + } + + _summary = ss.str(); + } + + return _summary; +} + SrsCplxError* SrsCplxError::create(const char* func, const char* file, int line, int code, const char* fmt, ...) { int rerrno = (int)errno; @@ -178,6 +194,11 @@ string SrsCplxError::description(SrsCplxError* err) return err? err->description() : "Success"; } +string SrsCplxError::summary(SrsCplxError* err) +{ + return err? err->summary() : "Success"; +} + int SrsCplxError::error_code(SrsCplxError* err) { return err? err->code : ERROR_SUCCESS; diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index 7461ebbcc2..6f9aa934e2 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -380,18 +380,21 @@ class SrsCplxError int rerrno; std::string desc; + std::string _summary; private: SrsCplxError(); public: virtual ~SrsCplxError(); private: virtual std::string description(); + virtual std::string summary(); public: static SrsCplxError* create(const char* func, const char* file, int line, int code, const char* fmt, ...); static SrsCplxError* wrap(const char* func, const char* file, int line, SrsCplxError* err, const char* fmt, ...); static SrsCplxError* success(); static SrsCplxError* copy(SrsCplxError* from); static std::string description(SrsCplxError* err); + static std::string summary(SrsCplxError* err); static int error_code(SrsCplxError* err); }; @@ -401,6 +404,7 @@ class SrsCplxError #define srs_error_wrap(err, fmt, ...) SrsCplxError::wrap(__FUNCTION__, __FILE__, __LINE__, err, fmt, ##__VA_ARGS__) #define srs_error_copy(err) SrsCplxError::copy(err) #define srs_error_desc(err) SrsCplxError::description(err) +#define srs_error_summary(err) SrsCplxError::summary(err) #define srs_error_code(err) SrsCplxError::error_code(err) #define srs_error_reset(err) srs_freep(err); err = srs_success From 29b9203428c33898237539acfc2ac3d90c6bd8b0 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 17 Mar 2020 12:10:42 +0800 Subject: [PATCH 36/69] For #1638, #307, use short-term http connection for rtc to use new cid. --- trunk/src/app/srs_app_http_api.cpp | 4 ++++ trunk/src/service/srs_service_http_conn.cpp | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index cb8615d684..32ccf8e12d 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -799,6 +799,10 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* // path: {pattern} // method: POST // e.g. /api/v1/sdp/ args = json:{"sdp":"sdp...", "app":"webrtc", "stream":"test"} + + // For each RTC session, we use short-term HTTP connection. + SrsHttpHeader* hdr = w->header(); + hdr->set("Connection", "Close"); string req_json; if ((err = r->body_read_all(req_json)) != srs_success) { diff --git a/trunk/src/service/srs_service_http_conn.cpp b/trunk/src/service/srs_service_http_conn.cpp index cff5b26a3b..815fc8670a 100644 --- a/trunk/src/service/srs_service_http_conn.cpp +++ b/trunk/src/service/srs_service_http_conn.cpp @@ -907,7 +907,9 @@ srs_error_t SrsHttpResponseWriter::send_header(char* data, int size) } // keep alive to make vlc happy. - hdr->set("Connection", "Keep-Alive"); + if (hdr->get("Connection").empty()) { + hdr->set("Connection", "Keep-Alive"); + } // Filter the header before writing it. if (hf && ((err = hf->filter(hdr)) != srs_success)) { From 25fec76ea9b154c9e7269531641c32ec611f497a Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 17 Mar 2020 12:33:08 +0800 Subject: [PATCH 37/69] For #1638, #307, switch to RTC session context cid for reusing UDP ports --- trunk/src/app/srs_app_rtc_conn.cpp | 24 ++++++++++++++++++++++-- trunk/src/app/srs_app_rtc_conn.hpp | 7 ++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 2361b721b9..c3629db207 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -716,7 +716,7 @@ void SrsRtcSenderThread::send_and_free_messages(SrsSharedPtrMessage** msgs, int } } -SrsRtcSession::SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un) +SrsRtcSession::SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un, int context_id) { server = svr; rtc_server = rtc_svr; @@ -730,6 +730,8 @@ SrsRtcSession::SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const SrsReq request = req; source = NULL; + + cid = context_id; } SrsRtcSession::~SrsRtcSession() @@ -742,6 +744,11 @@ SrsRtcSession::~SrsRtcSession() srs_freep(strd); } +void SrsRtcSession::switch_to_context() +{ + _srs_context->set_id(cid); +} + srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req) { srs_error_t err = srs_success; @@ -1215,7 +1222,8 @@ SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsRequest& req, const Srs break; } - SrsRtcSession* session = new SrsRtcSession(server, this, req, username); + int cid = _srs_context->get_id(); + SrsRtcSession* session = new SrsRtcSession(server, this, req, username, cid); map_username_session.insert(make_pair(username, session)); local_sdp.set_ice_ufrag(local_ufrag); @@ -1256,6 +1264,10 @@ srs_error_t SrsRtcServer::on_stun(SrsUdpMuxSocket* udp_mux_skt) return srs_error_new(ERROR_RTC_STUN, "can not find rtc_session, stun username=%s", username.c_str()); } + // Now, we got the RTC session to handle the packet, switch to its context + // to make all logs write to the "correct" pid+cid. + rtc_session->switch_to_context(); + return rtc_session->on_stun(udp_mux_skt, &stun_req); } @@ -1267,6 +1279,10 @@ srs_error_t SrsRtcServer::on_dtls(SrsUdpMuxSocket* udp_mux_skt) return srs_error_new(ERROR_RTC_DTLS, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); } + // Now, we got the RTC session to handle the packet, switch to its context + // to make all logs write to the "correct" pid+cid. + rtc_session->switch_to_context(); + return rtc_session->on_dtls(udp_mux_skt); } @@ -1280,6 +1296,10 @@ srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt) return srs_error_new(ERROR_RTC_RTP, "can not find rtc session by peer_id=%s", udp_mux_skt->get_peer_id().c_str()); } + // Now, we got the RTC session to handle the packet, switch to its context + // to make all logs write to the "correct" pid+cid. + rtc_session->switch_to_context(); + if (is_rtcp(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { err = rtc_session->on_rtcp(udp_mux_skt); } else { diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 422e6ca9d6..57914dd7d4 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -194,11 +194,14 @@ class SrsRtcSession std::string username; std::string peer_id; srs_utime_t last_stun_time; +private: + // For each RTC session, we use a specified cid for debugging logs. + int cid; public: SrsRequest request; SrsSource* source; public: - SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un); + SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un, int context_id); virtual ~SrsRtcSession(); public: SrsSdp* get_local_sdp() { return &local_sdp; } @@ -214,6 +217,8 @@ class SrsRtcSession std::string get_peer_id() const { return peer_id; } void set_peer_id(const std::string& id) { peer_id = id; } + + void switch_to_context(); public: srs_error_t on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req); srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); From 4318d989a636990eed89dd845781f94788f36b01 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 17 Mar 2020 12:41:50 +0800 Subject: [PATCH 38/69] For #1638, #307, switch to RTC session context cid for cleanup --- trunk/src/app/srs_app_rtc_conn.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index c3629db207..60628b666a 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1335,6 +1335,10 @@ void SrsRtcServer::check_and_clean_timeout_session() } if (session->is_stun_timeout()) { + // Now, we got the RTC session to cleanup, switch to its context + // to make all logs write to the "correct" pid+cid. + session->switch_to_context(); + srs_trace("rtc session=%s, stun timeout", session->id().c_str()); map_username_session.erase(iter++); map_id_session.erase(session->get_peer_id()); @@ -1398,7 +1402,7 @@ srs_error_t SrsRtcTimerThread::cycle() return srs_error_wrap(err, "rtc timer thread"); } - srs_usleep(1*1000*1000LL); + srs_usleep(1 * SRS_UTIME_SECONDS); rtc_server->check_and_clean_timeout_session(); } } From 2c4dc0fb3d73da359c1afc33cef5666813037c93 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 17 Mar 2020 17:56:37 +0800 Subject: [PATCH 39/69] For #1638, #307, extract rtc server to hybrid manager. --- trunk/src/app/srs_app_http_api.cpp | 3 +- trunk/src/app/srs_app_http_api.hpp | 3 +- trunk/src/app/srs_app_hybrid.cpp | 15 +++++ trunk/src/app/srs_app_hybrid.hpp | 4 ++ trunk/src/app/srs_app_rtc_conn.cpp | 92 +++++++++++++++++++++++-- trunk/src/app/srs_app_rtc_conn.hpp | 29 ++++++-- trunk/src/app/srs_app_server.cpp | 104 ++--------------------------- trunk/src/app/srs_app_server.hpp | 22 +----- trunk/src/main/srs_main_server.cpp | 5 ++ 9 files changed, 141 insertions(+), 136 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 32ccf8e12d..822d9d35e1 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -781,9 +781,8 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa return srs_api_response(w, r, obj->dumps()); } -SrsGoApiSdp::SrsGoApiSdp(SrsServer* svr, SrsRtcServer* rtc_svr) +SrsGoApiSdp::SrsGoApiSdp(SrsRtcServer* rtc_svr) { - server = svr; rtc_server = rtc_svr; } diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index c4cf02a6c7..249ae7c31b 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -168,10 +168,9 @@ class SrsGoApiStreams : public ISrsHttpHandler class SrsGoApiSdp : public ISrsHttpHandler { private: - SrsServer* server; SrsRtcServer* rtc_server; public: - SrsGoApiSdp(SrsServer* svr, SrsRtcServer* rtc_svr); + SrsGoApiSdp(SrsRtcServer* rtc_svr); virtual ~SrsGoApiSdp(); public: virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); diff --git a/trunk/src/app/srs_app_hybrid.cpp b/trunk/src/app/srs_app_hybrid.cpp index cd8147327b..9094de4f28 100644 --- a/trunk/src/app/srs_app_hybrid.cpp +++ b/trunk/src/app/srs_app_hybrid.cpp @@ -102,6 +102,11 @@ void SrsServerAdapter::stop() { } +SrsServer* SrsServerAdapter::instance() +{ + return srs; +} + SrsHybridServer::SrsHybridServer() { } @@ -181,5 +186,15 @@ void SrsHybridServer::stop() } } +SrsServerAdapter* SrsHybridServer::srs() +{ + for (vector::iterator it = servers.begin(); it != servers.end(); ++it) { + if (dynamic_cast(*it)) { + return dynamic_cast(*it); + } + } + return NULL; +} + SrsHybridServer* _srs_hybrid = new SrsHybridServer(); diff --git a/trunk/src/app/srs_app_hybrid.hpp b/trunk/src/app/srs_app_hybrid.hpp index 3834566608..0f995afe4d 100644 --- a/trunk/src/app/srs_app_hybrid.hpp +++ b/trunk/src/app/srs_app_hybrid.hpp @@ -57,6 +57,8 @@ class SrsServerAdapter : public ISrsHybridServer virtual srs_error_t initialize(); virtual srs_error_t run(); virtual void stop(); +public: + virtual SrsServer* instance(); }; // The hybrid server manager. @@ -73,6 +75,8 @@ class SrsHybridServer virtual srs_error_t initialize(); virtual srs_error_t run(); virtual void stop(); +public: + virtual SrsServerAdapter* srs(); }; extern SrsHybridServer* _srs_hybrid; diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 60628b666a..a5a71440ec 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -50,6 +50,8 @@ using namespace std; #include #include #include +#include +#include static bool is_stun(const uint8_t* data, const int size) { @@ -654,7 +656,9 @@ srs_error_t SrsRtcSenderThread::cycle() SrsSource* source = NULL; - if (_srs_sources->fetch_or_create(&rtc_session->request, rtc_session->server, &source) != srs_success) { + // TODO: FIXME: Should refactor it, directly use http server as handler. + ISrsSourceHandler* handler = _srs_hybrid->srs()->instance(); + if (_srs_sources->fetch_or_create(&rtc_session->request, handler, &source) != srs_success) { return srs_error_wrap(err, "rtc fetch source failed"); } @@ -716,9 +720,8 @@ void SrsRtcSenderThread::send_and_free_messages(SrsSharedPtrMessage** msgs, int } } -SrsRtcSession::SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un, int context_id) +SrsRtcSession::SrsRtcSession(SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un, int context_id) { - server = svr; rtc_server = rtc_svr; session_state = INIT; dtls_session = NULL; @@ -766,8 +769,11 @@ srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* void SrsRtcSession::check_source() { + // TODO: FIXME: Check return error. if (source == NULL) { - _srs_sources->fetch_or_create(&request, server, &source); + // TODO: FIXME: Should refactor it, directly use http server as handler. + ISrsSourceHandler* handler = _srs_hybrid->srs()->instance(); + _srs_sources->fetch_or_create(&request, handler, &source); } } @@ -1173,13 +1179,15 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) return err; } -SrsRtcServer::SrsRtcServer(SrsServer* svr) +SrsRtcServer::SrsRtcServer() { - server = svr; + listener = NULL; } SrsRtcServer::~SrsRtcServer() { + srs_freep(listener); + rttrd->stop(); srs_freep(rttrd); } @@ -1196,6 +1204,33 @@ srs_error_t SrsRtcServer::initialize() return err; } +srs_error_t SrsRtcServer::listen_rtc() +{ + srs_error_t err = srs_success; + + if (!_srs_config->get_rtc_enabled()) { + return err; + } + + int port = _srs_config->get_rtc_listen(); + if (port <= 0) { + return srs_error_new(ERROR_RTC_PORT, "invalid port=%d", port); + } + + string ip = srs_any_address_for_listener(); + + srs_freep(listener); + listener = new SrsUdpMuxListener(this, ip, port); + + if ((err = listener->listen()) != srs_success) { + return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); + } + + srs_trace("rtc listen at udp://%s:%d, fd=%d", ip.c_str(), port, listener->fd()); + + return err; +} + srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* udp_mux_skt) { if (is_stun(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { @@ -1223,7 +1258,7 @@ SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsRequest& req, const Srs } int cid = _srs_context->get_id(); - SrsRtcSession* session = new SrsRtcSession(server, this, req, username, cid); + SrsRtcSession* session = new SrsRtcSession(this, req, username, cid); map_username_session.insert(make_pair(username, session)); local_sdp.set_ice_ufrag(local_ufrag); @@ -1406,3 +1441,46 @@ srs_error_t SrsRtcTimerThread::cycle() rtc_server->check_and_clean_timeout_session(); } } + +RtcServerAdapter::RtcServerAdapter() +{ + rtc = new SrsRtcServer(); +} + +RtcServerAdapter::~RtcServerAdapter() +{ + srs_freep(rtc); +} + +srs_error_t RtcServerAdapter::initialize() +{ + srs_error_t err = srs_success; + + if ((err = rtc->initialize()) != srs_success) { + return srs_error_wrap(err, "rtc server initialize"); + } + + return err; +} + +srs_error_t RtcServerAdapter::run() +{ + srs_error_t err = srs_success; + + if ((err = rtc->listen_rtc()) != srs_success) { + return srs_error_wrap(err, "rtc server initialize"); + } + + // TODO: FIXME: Fetch api from hybrid manager. + SrsHttpServeMux* http_api_mux = _srs_hybrid->srs()->instance()->api_server(); + if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(rtc))) != srs_success) { + return srs_error_wrap(err, "handle sdp"); + } + + return err; +} + +void RtcServerAdapter::stop() +{ +} + diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 57914dd7d4..0388ba31b0 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,6 @@ #include class SrsUdpMuxSocket; -class SrsServer; class SrsConsumer; class SrsStunPacket; class SrsRtcServer; @@ -184,7 +184,6 @@ class SrsRtcSession { friend class SrsRtcSenderThread; private: - SrsServer* server; SrsRtcServer* rtc_server; SrsSdp remote_sdp; SrsSdp local_sdp; @@ -201,7 +200,7 @@ class SrsRtcSession SrsRequest request; SrsSource* source; public: - SrsRtcSession(SrsServer* svr, SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un, int context_id); + SrsRtcSession(SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un, int context_id); virtual ~SrsRtcSession(); public: SrsSdp* get_local_sdp() { return &local_sdp; } @@ -240,7 +239,7 @@ class SrsRtcSession srs_error_t on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt); }; -// XXX: is there any other timer thread? +// TODO: FIXME: is there any other timer thread? class SrsRtcTimerThread : public ISrsCoroutineHandler { protected: @@ -264,17 +263,21 @@ class SrsRtcTimerThread : public ISrsCoroutineHandler class SrsRtcServer : public ISrsUdpMuxHandler { private: - SrsServer* server; + SrsUdpMuxListener* listener; SrsRtcTimerThread* rttrd; private: std::map map_username_session; // key: username(local_ufrag + ":" + remote_ufrag) std::map map_id_session; // key: peerip(ip + ":" + port) public: - SrsRtcServer(SrsServer* svr); + SrsRtcServer(); virtual ~SrsRtcServer(); public: virtual srs_error_t initialize(); + // TODO: FIXME: Support gracefully quit. + // TODO: FIXME: Support reload. + virtual srs_error_t listen_rtc(); + virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* udp_mux_skt); SrsRtcSession* create_rtc_session(const SrsRequest& req, const SrsSdp& remote_sdp, SrsSdp& local_sdp); @@ -289,5 +292,19 @@ class SrsRtcServer : public ISrsUdpMuxHandler SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id); }; +// The RTC server adapter. +class RtcServerAdapter : public ISrsHybridServer +{ +private: + SrsRtcServer* rtc; +public: + RtcServerAdapter(); + virtual ~RtcServerAdapter(); +public: + virtual srs_error_t initialize(); + virtual srs_error_t run(); + virtual void stop(); +}; + #endif diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 5e3294c0b5..d216ccd1dc 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -110,8 +110,6 @@ std::string srs_listener_type2string(SrsListenerType type) return "RTSP"; case SrsListenerFlv: return "HTTP-FLV"; - case SrsListenerRtc: - return "RTC"; default: return "UNKONWN"; } @@ -342,45 +340,6 @@ SrsUdpCasterListener::~SrsUdpCasterListener() srs_freep(caster); } -SrsRtcListener::SrsRtcListener(SrsServer* svr, SrsRtcServer* rtc_svr, SrsListenerType t) : SrsListener(svr, t) -{ - srs_assert(type == SrsListenerRtc); - rtc = rtc_svr; -} - -SrsRtcListener::~SrsRtcListener() -{ -} - -srs_error_t SrsRtcListener::listen(std::string i, int p) -{ - srs_error_t err = srs_success; - - // the caller already ensure the type is ok, - // we just assert here for unknown stream caster. - srs_assert(type == SrsListenerRtc); - - ip = i; - port = p; - - srs_freep(listener); - listener = new SrsUdpMuxListener(rtc, ip, port); - - if ((err = listener->listen()) != srs_success) { - return srs_error_wrap(err, "listen %s:%d", ip.c_str(), port); - } - - // notify the handler the fd changed. - if ((err = rtc->on_stfd_change(listener->stfd())) != srs_success) { - return srs_error_wrap(err, "notify fd change failed"); - } - - string v = srs_listener_type2string(type); - srs_trace("%s listen at udp://%s:%d, fd=%d", v.c_str(), ip.c_str(), port, listener->fd()); - - return err; -} - SrsSignalManager* SrsSignalManager::instance = NULL; SrsSignalManager::SrsSignalManager(SrsServer* s) @@ -672,7 +631,6 @@ SrsServer::SrsServer() // new these objects in initialize instead. http_api_mux = new SrsHttpServeMux(); http_server = new SrsHttpServer(this); - rtc_server = new SrsRtcServer(this); http_heartbeat = new SrsHttpHeartbeat(); ingester = new SrsIngester(); } @@ -797,10 +755,6 @@ srs_error_t SrsServer::initialize(ISrsServerCycle* ch) if ((err = http_server->initialize()) != srs_success) { return srs_error_wrap(err, "http server initialize"); } - - if ((err = rtc_server->initialize()) != srs_success) { - return srs_error_wrap(err, "rtc server initialize"); - } return err; } @@ -923,10 +877,6 @@ srs_error_t SrsServer::listen() if ((err = listen_stream_caster()) != srs_success) { return srs_error_wrap(err, "stream caster listen"); } - - if ((err = listen_rtc()) != srs_success) { - return srs_error_wrap(err, "rtc listen"); - } if ((err = conn_manager->start()) != srs_success) { return srs_error_wrap(err, "connection manager"); @@ -989,9 +939,6 @@ srs_error_t SrsServer::http_handle() if ((err = http_api_mux->handle("/api/v1/streams/", new SrsGoApiStreams())) != srs_success) { return srs_error_wrap(err, "handle streams"); } - if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(this, rtc_server))) != srs_success) { - return srs_error_wrap(err, "handle sdp"); - } if ((err = http_api_mux->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) { return srs_error_wrap(err, "handle clients"); } @@ -1400,35 +1347,6 @@ srs_error_t SrsServer::listen_stream_caster() return err; } -srs_error_t SrsServer::listen_rtc() -{ - srs_error_t err = srs_success; - - close_listeners(SrsListenerRtc); - - if (!_srs_config->get_rtc_enabled()) { - return err; - } - - SrsListener* listener = NULL; - - listener = new SrsRtcListener(this, rtc_server, SrsListenerRtc); - srs_assert(listener != NULL); - - listeners.push_back(listener); - - int port = _srs_config->get_rtc_listen(); - if (port <= 0) { - return srs_error_new(ERROR_RTC_PORT, "invalid port=%d", port); - } - - if ((err = listener->listen(srs_any_address_for_listener(), port)) != srs_success) { - return srs_error_wrap(err, "listen at %d", port); - } - - return err; -} - void SrsServer::close_listeners(SrsListenerType type) { std::vector::iterator it; @@ -1445,23 +1363,6 @@ void SrsServer::close_listeners(SrsListenerType type) } } -SrsListener* SrsServer::find_listener(SrsListenerType type) -{ - std::vector::iterator it; - for (it = listeners.begin(); it != listeners.end();) { - SrsListener* listener = *it; - - if (listener->listen_type() != type) { - ++it; - continue; - } - - return *it; - } - - return NULL; -} - void SrsServer::resample_kbps() { SrsStatistic* stat = SrsStatistic::instance(); @@ -1510,6 +1411,11 @@ srs_error_t SrsServer::accept_client(SrsListenerType type, srs_netfd_t stfd) return err; } +SrsHttpServeMux* SrsServer::api_server() +{ + return http_api_mux; +} + srs_error_t SrsServer::fd2conn(SrsListenerType type, srs_netfd_t stfd, SrsConnection** pconn) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 282e058a26..b702eb49e6 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -41,7 +41,6 @@ class SrsServer; class SrsConnection; class SrsHttpServeMux; class SrsHttpServer; -class SrsRtcServer; class SrsIngester; class SrsHttpHeartbeat; class SrsKbps; @@ -70,8 +69,6 @@ enum SrsListenerType SrsListenerRtsp = 4, // TCP stream, FLV stream over HTTP. SrsListenerFlv = 5, - // UDP remux, rtp over udp - SrsListenerRtc = 6, }; // A common tcp listener, for RTMP/HTTP server. @@ -159,19 +156,6 @@ class SrsUdpCasterListener : public SrsUdpStreamListener virtual ~SrsUdpCasterListener(); }; -// A UDP listener, for udp remux rtc server -class SrsRtcListener : public SrsListener -{ -protected: - SrsUdpMuxListener* listener; - ISrsUdpMuxHandler* rtc; -public: - SrsRtcListener(SrsServer* svr, SrsRtcServer* rtc_svr, SrsListenerType t); - virtual ~SrsRtcListener(); -public: - virtual srs_error_t listen(std::string i, int p); -}; - // Convert signal to io, // @see: st-1.9/docs/notes.html class SrsSignalManager : public ISrsCoroutineHandler @@ -241,7 +225,6 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan // TODO: FIXME: rename to http_api SrsHttpServeMux* http_api_mux; SrsHttpServer* http_server; - SrsRtcServer* rtc_server; SrsHttpHeartbeat* http_heartbeat; SrsIngester* ingester; SrsCoroutineManager* conn_manager; @@ -320,7 +303,6 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan virtual srs_error_t listen_http_api(); virtual srs_error_t listen_http_stream(); virtual srs_error_t listen_stream_caster(); - virtual srs_error_t listen_rtc(); // Close the listeners for specified type, // Remove the listen object from manager. virtual void close_listeners(SrsListenerType type); @@ -333,6 +315,8 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan // for instance RTMP connection to serve client. // @param stfd, the client fd in st boxed, the underlayer fd. virtual srs_error_t accept_client(SrsListenerType type, srs_netfd_t stfd); + // TODO: FIXME: Fetch from hybrid server manager. + virtual SrsHttpServeMux* api_server(); private: virtual srs_error_t fd2conn(SrsListenerType type, srs_netfd_t stfd, SrsConnection** pconn); // Interface IConnectionManager @@ -356,8 +340,6 @@ class SrsServer : virtual public ISrsReloadHandler, virtual public ISrsSourceHan public: virtual srs_error_t on_publish(SrsSource* s, SrsRequest* r); virtual void on_unpublish(SrsSource* s, SrsRequest* r); -// listeners commuction - virtual SrsListener* find_listener(SrsListenerType type); }; #endif diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 0778c72f16..1bec4c0ad3 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -50,6 +50,7 @@ using namespace std; #include #include #include +#include #ifdef SRS_AUTO_SRT #include @@ -441,11 +442,15 @@ srs_error_t run_hybrid_server() { srs_error_t err = srs_success; + // Create servers and register them. _srs_hybrid->register_server(new SrsServerAdapter()); + #ifdef SRS_AUTO_SRT _srs_hybrid->register_server(new SrtServerAdapter()); #endif + _srs_hybrid->register_server(new RtcServerAdapter()); + // Do some system initialize. if ((err = _srs_hybrid->initialize()) != srs_success) { return srs_error_wrap(err, "hybrid initialize"); From ed2996141c42fc8fa1d70952fd59e6ea37391b30 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 17 Mar 2020 18:11:03 +0800 Subject: [PATCH 40/69] For #1638, #307, refine api and udp for rtc. --- trunk/src/app/srs_app_rtc_conn.cpp | 25 ++++++++++++++++++------- trunk/src/app/srs_app_rtc_conn.hpp | 8 ++++---- trunk/src/app/srs_app_server.cpp | 1 - 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index a5a71440ec..620c6f5c75 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1204,7 +1204,7 @@ srs_error_t SrsRtcServer::initialize() return err; } -srs_error_t SrsRtcServer::listen_rtc() +srs_error_t SrsRtcServer::listen_udp() { srs_error_t err = srs_success; @@ -1244,6 +1244,19 @@ srs_error_t SrsRtcServer::on_udp_packet(SrsUdpMuxSocket* udp_mux_skt) return srs_error_new(ERROR_RTC_UDP, "unknown udp packet type"); } +srs_error_t SrsRtcServer::listen_api() +{ + srs_error_t err = srs_success; + + // TODO: FIXME: Fetch api from hybrid manager. + SrsHttpServeMux* http_api_mux = _srs_hybrid->srs()->instance()->api_server(); + if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(this))) != srs_success) { + return srs_error_wrap(err, "handle sdp"); + } + + return err; +} + SrsRtcSession* SrsRtcServer::create_rtc_session(const SrsRequest& req, const SrsSdp& remote_sdp, SrsSdp& local_sdp) { std::string local_pwd = gen_random_str(32); @@ -1467,14 +1480,12 @@ srs_error_t RtcServerAdapter::run() { srs_error_t err = srs_success; - if ((err = rtc->listen_rtc()) != srs_success) { - return srs_error_wrap(err, "rtc server initialize"); + if ((err = rtc->listen_udp()) != srs_success) { + return srs_error_wrap(err, "listen udp"); } - // TODO: FIXME: Fetch api from hybrid manager. - SrsHttpServeMux* http_api_mux = _srs_hybrid->srs()->instance()->api_server(); - if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(rtc))) != srs_success) { - return srs_error_wrap(err, "handle sdp"); + if ((err = rtc->listen_api()) != srs_success) { + return srs_error_wrap(err, "listen api"); } return err; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 0388ba31b0..72830bc91c 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -273,13 +273,13 @@ class SrsRtcServer : public ISrsUdpMuxHandler virtual ~SrsRtcServer(); public: virtual srs_error_t initialize(); - +public: // TODO: FIXME: Support gracefully quit. // TODO: FIXME: Support reload. - virtual srs_error_t listen_rtc(); - + virtual srs_error_t listen_udp(); virtual srs_error_t on_udp_packet(SrsUdpMuxSocket* udp_mux_skt); - +public: + virtual srs_error_t listen_api(); SrsRtcSession* create_rtc_session(const SrsRequest& req, const SrsSdp& remote_sdp, SrsSdp& local_sdp); bool insert_into_id_sessions(const std::string& peer_id, SrsRtcSession* rtc_session); void check_and_clean_timeout_session(); diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index d216ccd1dc..7c82310318 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -45,7 +45,6 @@ using namespace std; #include #include #include -#include #include #include #include From 0ff8a3761bef8f2a7d13b6967f85f2cb87cbbc7a Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 17 Mar 2020 18:24:28 +0800 Subject: [PATCH 41/69] For #1638, #307, should check error by fetch_or_create source --- trunk/src/app/srs_app_rtc_conn.cpp | 16 ++++++++++++---- trunk/src/app/srs_app_rtc_conn.hpp | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 620c6f5c75..bb556e9d25 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -668,7 +668,7 @@ srs_error_t SrsRtcSenderThread::cycle() SrsConsumer* consumer = NULL; if (source->create_consumer(NULL, consumer) != srs_success) { return srs_error_wrap(err, "rtc create consumer, source url=%s", rtc_session->request.get_stream_url().c_str()); - } + } SrsAutoFree(SrsConsumer, consumer); @@ -767,14 +767,20 @@ srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* return err; } -void SrsRtcSession::check_source() +srs_error_t SrsRtcSession::check_source() { + srs_error_t err = srs_success; + // TODO: FIXME: Check return error. if (source == NULL) { // TODO: FIXME: Should refactor it, directly use http server as handler. ISrsSourceHandler* handler = _srs_hybrid->srs()->instance(); - _srs_sources->fetch_or_create(&request, handler, &source); + if ((err = _srs_sources->fetch_or_create(&request, handler, &source)) != srs_success) { + return srs_error_wrap(err, "create source"); + } } + + return err; } srs_error_t SrsRtcSession::on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req) @@ -864,7 +870,9 @@ srs_error_t SrsRtcSession::on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSock srs_verbose("pid=%u, blp=%d", pid, blp); - check_source(); + if ((err = check_source()) != srs_success) { + return srs_error_wrap(err, "check"); + } if (! source) { return srs_error_wrap(err, "can not found source"); } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 72830bc91c..8164602444 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -230,7 +230,7 @@ class SrsRtcSession public: bool is_stun_timeout() { return last_stun_time + kSrsRtcSessionStunTimeoutUs < srs_get_system_time(); } private: - void check_source(); + srs_error_t check_source(); private: srs_error_t on_binding_request(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req); private: From 28c1c57854571fa53a75617dd3e29485865ec16e Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 17 Mar 2020 18:33:05 +0800 Subject: [PATCH 42/69] For #1638, #307, should set err in return value. --- trunk/src/app/srs_app_listener.hpp | 1 + trunk/src/app/srs_app_rtc_conn.cpp | 15 +++++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index 81cd8a580d..1a73b6fafb 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -58,6 +58,7 @@ class ISrsUdpHandler virtual srs_error_t on_udp_packet(const sockaddr* from, const int fromlen, char* buf, int nb_buf) = 0; }; +// TODO: FIXME: Add comments? class ISrsUdpMuxHandler { public: diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index bb556e9d25..ad09f51fbd 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -166,7 +166,7 @@ srs_error_t SrsSdp::decode(const string& sdp_str) break; } case 'a' :{ - if (parse_attr(line) != srs_success) { + if ((err = parse_attr(line)) != srs_success) { return srs_error_wrap(err, "decode sdp line=%s failed", line.c_str()); } break; @@ -466,11 +466,11 @@ srs_error_t SrsDtlsSession::srtp_initialize() client_key = client_master_key + client_master_salt; server_key = server_master_key + server_master_salt; - if (srtp_send_init() != srs_success) { + if ((err = srtp_send_init()) != srs_success) { return srs_error_wrap(err, "srtp send init failed"); } - if (srtp_recv_init() != srs_success) { + if ((err = srtp_recv_init()) != srs_success) { return srs_error_wrap(err, "srtp recv init failed"); } @@ -658,7 +658,7 @@ srs_error_t SrsRtcSenderThread::cycle() // TODO: FIXME: Should refactor it, directly use http server as handler. ISrsSourceHandler* handler = _srs_hybrid->srs()->instance(); - if (_srs_sources->fetch_or_create(&rtc_session->request, handler, &source) != srs_success) { + if ((err = _srs_sources->fetch_or_create(&rtc_session->request, handler, &source)) != srs_success) { return srs_error_wrap(err, "rtc fetch source failed"); } @@ -666,7 +666,7 @@ srs_error_t SrsRtcSenderThread::cycle() rtc_session->request.get_stream_url().c_str(), source->source_id(), source->source_id()); SrsConsumer* consumer = NULL; - if (source->create_consumer(NULL, consumer) != srs_success) { + if ((err = source->create_consumer(NULL, consumer)) != srs_success) { return srs_error_wrap(err, "rtc create consumer, source url=%s", rtc_session->request.get_stream_url().c_str()); } @@ -684,7 +684,7 @@ srs_error_t SrsRtcSenderThread::cycle() #endif int msg_count = 0; - if (consumer->dump_packets(&msgs, msg_count) != srs_success) { + if ((err = consumer->dump_packets(&msgs, msg_count)) != srs_success) { continue; } @@ -771,7 +771,6 @@ srs_error_t SrsRtcSession::check_source() { srs_error_t err = srs_success; - // TODO: FIXME: Check return error. if (source == NULL) { // TODO: FIXME: Should refactor it, directly use http server as handler. ISrsSourceHandler* handler = _srs_hybrid->srs()->instance(); @@ -1205,7 +1204,7 @@ srs_error_t SrsRtcServer::initialize() srs_error_t err = srs_success; rttrd = new SrsRtcTimerThread(this, _srs_context->get_id()); - if (rttrd->start() != srs_success) { + if ((err = rttrd->start()) != srs_success) { return srs_error_wrap(err, "rtc timer thread init failed"); } From fc84f1e5456b759af14a5af4c31f7da186055034 Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 17 Mar 2020 18:43:11 +0800 Subject: [PATCH 43/69] Refactor source cid with pid --- trunk/src/app/srs_app_http_stream.cpp | 5 +++-- trunk/src/app/srs_app_rtc_conn.cpp | 4 ++-- trunk/src/app/srs_app_rtmp_conn.cpp | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/trunk/src/app/srs_app_http_stream.cpp b/trunk/src/app/srs_app_http_stream.cpp index fb7bd54b36..3225aa8a4f 100755 --- a/trunk/src/app/srs_app_http_stream.cpp +++ b/trunk/src/app/srs_app_http_stream.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include using namespace std; @@ -1132,8 +1133,8 @@ srs_error_t SrsHttpStreamServer::hijack(ISrsHttpMessage* request, ISrsHttpHandle // trigger edge to fetch from origin. bool vhost_is_edge = _srs_config->get_vhost_is_edge(r->vhost); - srs_trace("flv: source url=%s, is_edge=%d, source_id=%d[%d]", - r->get_stream_url().c_str(), vhost_is_edge, s->source_id(), s->source_id()); + srs_trace("flv: source url=%s, is_edge=%d, source_id=[%d][%d]", + r->get_stream_url().c_str(), vhost_is_edge, ::getpid(), s->source_id()); return err; } diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index ad09f51fbd..13e74f636d 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -662,8 +662,8 @@ srs_error_t SrsRtcSenderThread::cycle() return srs_error_wrap(err, "rtc fetch source failed"); } - srs_trace("source url=%s, source_id=%d[%d]", - rtc_session->request.get_stream_url().c_str(), source->source_id(), source->source_id()); + srs_trace("source url=%s, source_id=[%d][%d]", + rtc_session->request.get_stream_url().c_str(), ::getpid(), source->source_id()); SrsConsumer* consumer = NULL; if ((err = source->create_consumer(NULL, consumer)) != srs_success) { diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index c7e943337e..bd70381e66 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -507,8 +507,8 @@ srs_error_t SrsRtmpConn::stream_service_cycle() } bool enabled_cache = _srs_config->get_gop_cache(req->vhost); - srs_trace("source url=%s, ip=%s, cache=%d, is_edge=%d, source_id=%d[%d]", - req->get_stream_url().c_str(), ip.c_str(), enabled_cache, info->edge, source->source_id(), source->source_id()); + srs_trace("source url=%s, ip=%s, cache=%d, is_edge=%d, source_id=[%d][%d]", + req->get_stream_url().c_str(), ip.c_str(), enabled_cache, info->edge, ::getpid(), source->source_id()); source->set_cache(enabled_cache); switch (info->type) { From e2233027b83c16818363e21401acb4049853a0ee Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Wed, 18 Mar 2020 08:45:20 +0800 Subject: [PATCH 44/69] fix h264 rtp packet error --- trunk/src/app/srs_app_rtp.cpp | 26 +++++++++++++------------- trunk/src/app/srs_app_rtp.hpp | 1 - trunk/src/app/srs_app_utility.cpp | 1 - trunk/src/kernel/srs_kernel_rtp.cpp | 16 ++++++++++++++++ trunk/src/kernel/srs_kernel_rtp.hpp | 5 +++++ 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index 7acbab24d0..de01bc54f7 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -67,6 +67,8 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF if (format->is_avc_sequence_header()) { sps.assign(format->vcodec->sequenceParameterSetNALUnit.data(), format->vcodec->sequenceParameterSetNALUnit.size()); pps.assign(format->vcodec->pictureParameterSetNALUnit.data(), format->vcodec->pictureParameterSetNALUnit.size()); + // only collect SPS/PPS. + return err; } vector rtp_packet_vec; @@ -77,12 +79,6 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF uint8_t header = sample.bytes[0]; uint8_t nal_type = header & kNalTypeMask; - // TODO: FIXME: Magic number? Doc? - // ignore SEI nal - if (nal_type == 0x06 || nal_type == 0x09) { - continue; - } - if (sample.size <= max_payload_size) { if ((err = packet_single_nalu(shared_frame, format, &sample, rtp_packet_vec)) != srs_success) { return srs_error_wrap(err, "packet single nalu"); @@ -94,6 +90,14 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF } } + if (! rtp_packet_vec.empty()) { + // At the end of the frame, set marker bit. + // One frame may have multi nals. Set the marker bit in the last nal end, no the end of the nal. + if ((err = rtp_packet_vec.back()->set_marker(true)) != srs_success) { + return srs_error_wrap(err, "set marker"); + } + } + shared_frame->set_rtp_packets(rtp_packet_vec); return err; @@ -125,11 +129,7 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma // v=2,p=0,x=0,cc=0 stream->write_1bytes(0x80); // marker payloadtype - if (i == num_of_packet - 1) { - stream->write_1bytes(kMarker | kH264PayloadType); - } else { - stream->write_1bytes(kH264PayloadType); - } + stream->write_1bytes(kH264PayloadType); // sequence stream->write_2bytes(sequence); // timestamp @@ -183,7 +183,7 @@ srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, S // v=2,p=0,x=0,cc=0 stream->write_1bytes(0x80); // marker payloadtype - stream->write_1bytes(kMarker | kH264PayloadType); + stream->write_1bytes(kH264PayloadType); // sequenct stream->write_2bytes(sequence); // timestamp @@ -219,7 +219,7 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs // v=2,p=0,x=0,cc=0 stream->write_1bytes(0x80); // marker payloadtype - stream->write_1bytes(kMarker | kH264PayloadType); + stream->write_1bytes(kH264PayloadType); // sequenct stream->write_2bytes(sequence); // timestamp diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp index badfea4435..212bf776c0 100644 --- a/trunk/src/app/srs_app_rtp.hpp +++ b/trunk/src/app/srs_app_rtp.hpp @@ -40,7 +40,6 @@ class SrsOriginHub; const int max_payload_size = 1200; const int kRtpPacketSize = 1500; -const uint8_t kMarker = 0x80; const uint8_t kH264PayloadType = 102; const uint8_t kNalTypeMask = 0x1F; diff --git a/trunk/src/app/srs_app_utility.cpp b/trunk/src/app/srs_app_utility.cpp index 2cbd0aeeba..754aa34f1c 100644 --- a/trunk/src/app/srs_app_utility.cpp +++ b/trunk/src/app/srs_app_utility.cpp @@ -1201,7 +1201,6 @@ string srs_string_dumps_hex(const std::string& str, const int& limit) string srs_string_dumps_hex(const char* buf, const int length, const int& limit) { string ret; - ret.reserve(limit * 4); char tmp_buf[1024*16]; tmp_buf[0] = '\n'; diff --git a/trunk/src/kernel/srs_kernel_rtp.cpp b/trunk/src/kernel/srs_kernel_rtp.cpp index 516ae89ff8..414b2aad1c 100644 --- a/trunk/src/kernel/srs_kernel_rtp.cpp +++ b/trunk/src/kernel/srs_kernel_rtp.cpp @@ -110,3 +110,19 @@ SrsRtpSharedPacket* SrsRtpSharedPacket::copy() return copy; } + +srs_error_t SrsRtpSharedPacket::set_marker(bool marker) +{ + srs_error_t err = srs_success; + if (payload_ptr == NULL || payload_ptr->payload == NULL || payload_ptr->size < 1) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "rtp payload incorrect"); + } + + if (marker) { + payload_ptr->payload[1] |= kMarker; + } else { + payload_ptr->payload[1] &= (~kMarker); + } + + return err; +} diff --git a/trunk/src/kernel/srs_kernel_rtp.hpp b/trunk/src/kernel/srs_kernel_rtp.hpp index b348946ec8..1de2269f38 100644 --- a/trunk/src/kernel/srs_kernel_rtp.hpp +++ b/trunk/src/kernel/srs_kernel_rtp.hpp @@ -28,6 +28,8 @@ #include +const uint8_t kMarker = 0x80; + class SrsRtpSharedPacket { private: @@ -57,6 +59,9 @@ class SrsRtpSharedPacket public: srs_error_t create(int64_t t, uint16_t seq, uint32_t sc, uint16_t pt, char* p, int s); SrsRtpSharedPacket* copy(); +// interface to modify rtp header +public: + srs_error_t set_marker(bool marker); }; #endif From c210c0b2f5e2de19d9b295c86f6f05dd20d78129 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 18 Mar 2020 10:03:20 +0800 Subject: [PATCH 45/69] For #1638, #307, refactor rtc player. --- trunk/research/players/rtc_player.html | 8 +++++++- trunk/src/app/srs_app_rtp.cpp | 3 --- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/trunk/research/players/rtc_player.html b/trunk/research/players/rtc_player.html index 56bc4be64f..e965120c81 100644 --- a/trunk/research/players/rtc_player.html +++ b/trunk/research/players/rtc_player.html @@ -53,6 +53,7 @@ From 018577e685a07d9de7a47354e7a9c5f77f5f4202 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 18 Mar 2020 18:12:37 +0800 Subject: [PATCH 47/69] For #1638, #307, fix error new bug for rtc --- trunk/src/app/srs_app_rtc_conn.cpp | 69 ++++++++++++++++----------- trunk/src/kernel/srs_kernel_error.hpp | 30 +++++++----- 2 files changed, 58 insertions(+), 41 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 13e74f636d..d78b5941d0 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -137,7 +137,7 @@ srs_error_t SrsSdp::decode(const string& sdp_str) srs_error_t err = srs_success; if (sdp_str.size() < 2 || sdp_str[0] != 'v' || sdp_str[1] != '=') { - return srs_error_wrap(err, "invalid sdp_str"); + return srs_error_new(ERROR_RTC_SDP_DECODE, "invalid sdp_str"); } string line; @@ -146,7 +146,7 @@ srs_error_t SrsSdp::decode(const string& sdp_str) srs_verbose("line=%s", line.c_str()); if (line.size() < 2 || line[1] != '=') { - return srs_error_wrap(err, "invalid sdp line=%s", line.c_str()); + return srs_error_new(ERROR_RTC_SDP_DECODE, "invalid sdp line=%s", line.c_str()); } switch (line[0]) { @@ -167,7 +167,7 @@ srs_error_t SrsSdp::decode(const string& sdp_str) } case 'a' :{ if ((err = parse_attr(line)) != srs_success) { - return srs_error_wrap(err, "decode sdp line=%s failed", line.c_str()); + return srs_error_new(ERROR_RTC_SDP_DECODE, "decode sdp line=%s failed", line.c_str()); } break; } @@ -397,7 +397,6 @@ srs_error_t SrsDtlsSession::on_dtls_handshake_done(SrsUdpMuxSocket* udp_mux_skt) handshake_done = true; if ((err = srtp_initialize()) != srs_success) { - srs_error("srtp init failed, err=%s", srs_error_desc(err).c_str()); return srs_error_wrap(err, "srtp init failed"); } @@ -450,7 +449,7 @@ srs_error_t SrsDtlsSession::srtp_initialize() unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp"; if (! SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) { - return srs_error_wrap(err, "SSL_export_keying_material failed"); + return srs_error_new(ERROR_RTC_SRTP_INIT, "SSL_export_keying_material failed"); } size_t offset = 0; @@ -501,7 +500,7 @@ srs_error_t SrsDtlsSession::srtp_send_init() if (srtp_create(&srtp_send, &policy) != 0) { srs_freepa(key); - return srs_error_wrap(err, "srtp_create failed"); + return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create failed"); } srs_freepa(key); @@ -533,7 +532,7 @@ srs_error_t SrsDtlsSession::srtp_recv_init() if (srtp_create(&srtp_recv, &policy) != 0) { srs_freepa(key); - return srs_error_wrap(err, "srtp_create failed"); + return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create failed"); } srs_freepa(key); @@ -548,13 +547,13 @@ srs_error_t SrsDtlsSession::protect_rtp(char* out_buf, const char* in_buf, int& if (srtp_send) { memcpy(out_buf, in_buf, nb_out_buf); if (srtp_protect(srtp_send, out_buf, &nb_out_buf) != 0) { - return srs_error_wrap(err, "rtp protect failed"); + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed"); } return err; } - return srs_error_wrap(err, "rtp protect failed"); + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed"); } srs_error_t SrsDtlsSession::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf) @@ -564,13 +563,13 @@ srs_error_t SrsDtlsSession::unprotect_rtp(char* out_buf, const char* in_buf, int if (srtp_recv) { memcpy(out_buf, in_buf, nb_out_buf); if (srtp_unprotect(srtp_recv, out_buf, &nb_out_buf) != 0) { - return srs_error_wrap(err, "rtp unprotect failed"); + return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect failed"); } return err; } - return srs_error_wrap(err, "rtp unprotect failed"); + return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect failed"); } srs_error_t SrsDtlsSession::protect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) @@ -580,13 +579,13 @@ srs_error_t SrsDtlsSession::protect_rtcp(char* out_buf, const char* in_buf, int& if (srtp_send) { memcpy(out_buf, in_buf, nb_out_buf); if (srtp_protect_rtcp(srtp_send, out_buf, &nb_out_buf) != 0) { - return srs_error_wrap(err, "rtcp protect failed"); + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); } return err; } - return srs_error_wrap(err, "rtcp protect failed"); + return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed"); } srs_error_t SrsDtlsSession::unprotect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf) @@ -596,13 +595,13 @@ srs_error_t SrsDtlsSession::unprotect_rtcp(char* out_buf, const char* in_buf, in if (srtp_recv) { memcpy(out_buf, in_buf, nb_out_buf); if (srtp_unprotect_rtcp(srtp_recv, out_buf, &nb_out_buf) != 0) { - return srs_error_wrap(err, "rtcp unprotect failed"); + return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); } return err; } - return srs_error_wrap(err, "rtcp unprotect failed"); + return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed"); } SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid) @@ -702,17 +701,30 @@ srs_error_t SrsRtcSenderThread::cycle() void SrsRtcSenderThread::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* udp_mux_skt) { + srs_error_t err = srs_success; + for (int i = 0; i < nb_msgs; i++) { SrsSharedPtrMessage* msg = msgs[i]; for (int i = 0; i < (int)msg->rtp_packets.size(); ++i) { - if (rtc_session->dtls_session) { - char protected_buf[kRtpPacketSize]; - int nb_protected_buf = msg->rtp_packets[i]->size; + if (!rtc_session->dtls_session) { + continue; + } + + SrsRtpSharedPacket* pkt = msg->rtp_packets[i]; + + int length = pkt->size; + char buf[kRtpPacketSize]; + if ((err = rtc_session->dtls_session->protect_rtp(buf, pkt->payload, length)) != srs_success) { + srs_warn("srtp err %s", srs_error_desc(err).c_str()); + srs_freep(err); + continue; + } - rtc_session->dtls_session->protect_rtp(protected_buf, msg->rtp_packets[i]->payload, nb_protected_buf); - // TODO: use sendmmsg to send multi packet one system call - udp_mux_skt->sendto(protected_buf, nb_protected_buf, 0); + // TODO: use sendmmsg to send multi packet one system call + if ((err = udp_mux_skt->sendto(buf, length, 0)) != srs_success) { + srs_warn("send err %s", srs_error_desc(err).c_str()); + srs_freep(err); } } @@ -826,7 +838,7 @@ srs_error_t SrsRtcSession::on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSock srs_error_t err = srs_success; if (nb_buf < 12) { - return srs_error_wrap(err, "invalid rtp feedback packet, nb_buf=%d", nb_buf); + return srs_error_new(ERROR_RTC_RTCP_CHECK, "invalid rtp feedback packet, nb_buf=%d", nb_buf); } SrsBuffer* stream = new SrsBuffer(buf, nb_buf); @@ -873,7 +885,7 @@ srs_error_t SrsRtcSession::on_rtcp_feedback(char* buf, int nb_buf, SrsUdpMuxSock return srs_error_wrap(err, "check"); } if (! source) { - return srs_error_wrap(err, "can not found source"); + return srs_error_new(ERROR_RTC_SOURCE_CHECK, "can not found source"); } vector resend_pkts; @@ -918,7 +930,7 @@ srs_error_t SrsRtcSession::on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxS srs_error_t err = srs_success; if (nb_buf < 12) { - return srs_error_wrap(err, "invalid rtp feedback packet, nb_buf=%d", nb_buf); + return srs_error_new(ERROR_RTC_RTCP_CHECK, "invalid rtp feedback packet, nb_buf=%d", nb_buf); } SrsBuffer* stream = new SrsBuffer(buf, nb_buf); @@ -953,7 +965,7 @@ srs_error_t SrsRtcSession::on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxS break; } default: { - return srs_error_wrap(err, "unknown payload specific feedback=%u", fmt); + return srs_error_new(ERROR_RTC_RTCP, "unknown payload specific feedback=%u", fmt); } } @@ -965,7 +977,7 @@ srs_error_t SrsRtcSession::on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdp srs_error_t err = srs_success; if (nb_buf < 8) { - return srs_error_wrap(err, "invalid rtp receiver report packet, nb_buf=%d", nb_buf); + return srs_error_new(ERROR_RTC_RTCP_CHECK, "invalid rtp receiver report packet, nb_buf=%d", nb_buf); } SrsBuffer* stream = new SrsBuffer(buf, nb_buf); @@ -1009,7 +1021,7 @@ block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ /*uint32_t ssrc_of_sender = */stream->read_4bytes(); if (((length + 1) * 4) != (rc * 24 + 8)) { - return srs_error_wrap(err, "invalid rtcp receiver packet, length=%u, rc=%u", length, rc); + return srs_error_new(ERROR_RTC_RTCP_CHECK, "invalid rtcp receiver packet, length=%u, rc=%u", length, rc); } for (int i = 0; i < rc; ++i) { @@ -1170,7 +1182,7 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) break; } default:{ - return srs_error_wrap(err, "unknown rtcp type=%u", payload_type); + return srs_error_new(ERROR_RTC_RTCP_CHECK, "unknown rtcp type=%u", payload_type); break; } } @@ -1453,7 +1465,6 @@ srs_error_t SrsRtcTimerThread::cycle() while (true) { if ((err = trd->pull()) != srs_success) { - srs_trace("rtc_timer cycle failed"); return srs_error_wrap(err, "rtc timer thread"); } diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index 6f9aa934e2..5997c9cdd3 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -328,18 +328,24 @@ /////////////////////////////////////////////////////// // RTC protocol error. /////////////////////////////////////////////////////// -#define ERROR_RTC_PORT 4041 -#define ERROR_RTP_PACKET_CREATE 4042 -#define ERROR_OpenSslCreateSSL 4043 -#define ERROR_OpenSslBIOReset 4044 -#define ERROR_OpenSslBIOWrite 4045 -#define ERROR_OpenSslBIONew 4046 -#define ERROR_RTC_RTP 4047 -#define ERROR_RTC_RTCP 4048 -#define ERROR_RTC_STUN 4049 -#define ERROR_RTC_DTLS 4050 -#define ERROR_RTC_UDP 4051 -#define ERROR_RTC_RTP_MUXER 4052 +#define ERROR_RTC_PORT 5000 +#define ERROR_RTP_PACKET_CREATE 5001 +#define ERROR_OpenSslCreateSSL 5002 +#define ERROR_OpenSslBIOReset 5003 +#define ERROR_OpenSslBIOWrite 5004 +#define ERROR_OpenSslBIONew 5005 +#define ERROR_RTC_RTP 5006 +#define ERROR_RTC_RTCP 5007 +#define ERROR_RTC_STUN 5008 +#define ERROR_RTC_DTLS 5009 +#define ERROR_RTC_UDP 5010 +#define ERROR_RTC_RTP_MUXER 5011 +#define ERROR_RTC_SDP_DECODE 5012 +#define ERROR_RTC_SRTP_INIT 5013 +#define ERROR_RTC_SRTP_PROTECT 5014 +#define ERROR_RTC_SRTP_UNPROTECT 5015 +#define ERROR_RTC_RTCP_CHECK 5016 +#define ERROR_RTC_SOURCE_CHECK 5017 /////////////////////////////////////////////////////// // HTTP API error. From 0b6e9257f94e5a82845f6182388a4c39ff31c8c4 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 18 Mar 2020 18:35:02 +0800 Subject: [PATCH 48/69] For #1638, #307, remove unused code for rtc --- trunk/src/app/srs_app_rtc_conn.cpp | 54 ++---------------------------- trunk/src/app/srs_app_rtc_conn.hpp | 1 - 2 files changed, 3 insertions(+), 52 deletions(-) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index d78b5941d0..ec4d08e2cf 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1078,56 +1078,6 @@ srs_error_t SrsRtcSession::on_dtls(SrsUdpMuxSocket* udp_mux_skt) return dtls_session->on_dtls(udp_mux_skt); } -srs_error_t SrsRtcSession::on_rtp(SrsUdpMuxSocket* udp_mux_skt) -{ - srs_error_t err = srs_success; - if (dtls_session == NULL) { - return srs_error_new(ERROR_RTC_RTP, "recv unexpect rtp packet before dtls done"); - } - - char unprotected_buf[1460]; - int nb_unprotected_buf = udp_mux_skt->size(); - if ((err = dtls_session->unprotect_rtp(unprotected_buf, udp_mux_skt->data(), nb_unprotected_buf)) != srs_success) { - return srs_error_wrap(err, "rtp unprotect failed"); - } - - // FIXME: use SrsRtpPacket - SrsBuffer* stream = new SrsBuffer(unprotected_buf, nb_unprotected_buf); - SrsAutoFree(SrsBuffer, stream); - uint8_t first = stream->read_1bytes(); - uint8_t second = stream->read_1bytes(); - - bool padding = (first & 0x20); - bool ext = (first & 0x10); - uint8_t cc = (first & 0x0F); - - bool marker = (second & 0x80); - - uint16_t sequence = stream->read_2bytes(); - uint32_t timestamp = stream->read_4bytes(); - uint32_t ssrc = stream->read_4bytes(); - - (void)padding; (void)marker; (void)sequence; (void)timestamp; (void)ssrc; - srs_verbose("sequence=%u, timestamp=%u, ssrc=%u, padding=%d, ext=%d, cc=%u, marker=%d, payload_type=%u", - sequence, timestamp, ssrc, padding, ext, cc, marker, payload_type); - - for (uint8_t i = 0; i < cc; ++i) { - /*uint32_t csrc = */stream->read_4bytes(); - } - - if (ext) { - uint16_t extern_profile = stream->read_2bytes(); - uint16_t extern_length = stream->read_2bytes(); - - (void)extern_profile; (void)extern_length; - srs_verbose("extern_profile=%u, extern_length=%u", extern_profile, extern_length); - - stream->read_string(extern_length * 4); - } - - return err; -} - srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; @@ -1370,7 +1320,9 @@ srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpMuxSocket* udp_mux_skt) if (is_rtcp(reinterpret_cast(udp_mux_skt->data()), udp_mux_skt->size())) { err = rtc_session->on_rtcp(udp_mux_skt); } else { - err = rtc_session->on_rtp(udp_mux_skt); + // We disable it because no RTP for player. + // see https://github.com/ossrs/srs/blob/018577e685a07d9de7a47354e7a9c5f77f5f4202/trunk/src/app/srs_app_rtc_conn.cpp#L1081 + // err = rtc_session->on_rtp(udp_mux_skt); } return err; diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 8164602444..5cef95d934 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -221,7 +221,6 @@ class SrsRtcSession public: srs_error_t on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* stun_req); srs_error_t on_dtls(SrsUdpMuxSocket* udp_mux_skt); - srs_error_t on_rtp(SrsUdpMuxSocket* udp_mux_skt); srs_error_t on_rtcp(SrsUdpMuxSocket* udp_mux_skt); public: srs_error_t send_client_hello(SrsUdpMuxSocket* udp_mux_skt); From d1d16d490ef3db3c1082e3c9b50fa7144a5989c7 Mon Sep 17 00:00:00 2001 From: HuyaJohn Date: Wed, 18 Mar 2020 16:27:31 -0700 Subject: [PATCH 49/69] Detect B frame in avc stream. Fix compiler error with verbose --- trunk/src/app/srs_app_edge.cpp | 1 - trunk/src/app/srs_app_pithy_print.cpp | 8 ++--- trunk/src/app/srs_app_rtc_conn.cpp | 5 ++- trunk/src/app/srs_app_rtp.cpp | 46 +++++++++++++++++++++++++-- trunk/src/app/srs_app_rtp.hpp | 7 ++-- trunk/src/kernel/srs_kernel_codec.hpp | 18 +++++++++++ 6 files changed, 71 insertions(+), 14 deletions(-) diff --git a/trunk/src/app/srs_app_edge.cpp b/trunk/src/app/srs_app_edge.cpp index 8c057af512..d59393daf0 100644 --- a/trunk/src/app/srs_app_edge.cpp +++ b/trunk/src/app/srs_app_edge.cpp @@ -579,7 +579,6 @@ srs_error_t SrsEdgeForwarder::do_cycle() SrsCommonMessage* msg = NULL; err = sdk->recv_message(&msg); - srs_verbose("edge loop recv message. ret=%d", ret); if (err != srs_success && srs_error_code(err) != ERROR_SOCKET_TIMEOUT) { srs_error("edge push get server control message failed. err=%s", srs_error_desc(err).c_str()); send_error_code = srs_error_code(err); diff --git a/trunk/src/app/srs_app_pithy_print.cpp b/trunk/src/app/srs_app_pithy_print.cpp index f31b44e510..9aacf3bfe4 100644 --- a/trunk/src/app/srs_app_pithy_print.cpp +++ b/trunk/src/app/srs_app_pithy_print.cpp @@ -186,8 +186,8 @@ int SrsPithyPrint::enter_stage() srs_assert(stage != NULL); client_id = stage->nb_clients++; - srs_verbose("enter stage, stage_id=%d, client_id=%d, nb_clients=%d, time_ms=%d", - stage->stage_id, client_id, stage->nb_clients, stage->pithy_print_time_ms); + srs_verbose("enter stage, stage_id=%d, client_id=%d, nb_clients=%d", + stage->stage_id, client_id, stage->nb_clients); return client_id; } @@ -199,8 +199,8 @@ void SrsPithyPrint::leave_stage() stage->nb_clients--; - srs_verbose("leave stage, stage_id=%d, client_id=%d, nb_clients=%d, time_ms=%d", - stage->stage_id, client_id, stage->nb_clients, stage->pithy_print_time_ms); + srs_verbose("leave stage, stage_id=%d, client_id=%d, nb_clients=%d", + stage->stage_id, client_id, stage->nb_clients); } void SrsPithyPrint::elapse() diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 13e74f636d..78df5e6437 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1095,9 +1095,8 @@ srs_error_t SrsRtcSession::on_rtp(SrsUdpMuxSocket* udp_mux_skt) uint32_t timestamp = stream->read_4bytes(); uint32_t ssrc = stream->read_4bytes(); - (void)padding; (void)marker; (void)sequence; (void)timestamp; (void)ssrc; - srs_verbose("sequence=%u, timestamp=%u, ssrc=%u, padding=%d, ext=%d, cc=%u, marker=%d, payload_type=%u", - sequence, timestamp, ssrc, padding, ext, cc, marker, payload_type); + srs_verbose("sequence=%u, timestamp=%u, ssrc=%u, padding=%d, ext=%d, cc=%u, marker=%d", + sequence, timestamp, ssrc, padding, ext, cc, marker); for (uint8_t i = 0; i < cc; ++i) { /*uint32_t csrc = */stream->read_4bytes(); diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index de01bc54f7..de8932018f 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -79,6 +79,32 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF uint8_t header = sample.bytes[0]; uint8_t nal_type = header & kNalTypeMask; + // TODO: Use config to determine should check avc stream. + if (nal_type == SrsAvcNaluTypeNonIDR || nal_type == SrsAvcNaluTypeDataPartitionA || nal_type == SrsAvcNaluTypeIDR) { + SrsBuffer* stream = new SrsBuffer(sample.bytes, sample.size); + SrsAutoFree(SrsBuffer, stream); + + // Skip nalu header. + stream->skip(1); + + SrsBitBuffer bitstream(stream); + int32_t first_mb_in_slice = 0; + if ((err = srs_avc_nalu_read_uev(&bitstream, first_mb_in_slice)) != srs_success) { + return srs_error_wrap(err, "nalu read uev"); + } + + int32_t slice_type = 0; + if ((err = srs_avc_nalu_read_uev(&bitstream, slice_type)) != srs_success) { + return srs_error_wrap(err, "nalu read uev"); + } + + srs_verbose("nal_type=%d, slice type=%d", nal_type, slice_type); + // TODO: Use config to determine how to process B frame + if (slice_type == SrsAvcSliceTypeB || slice_type == SrsAvcSliceTypeB1) { + continue; + } + } + if (sample.size <= max_payload_size) { if ((err = packet_single_nalu(shared_frame, format, &sample, rtp_packet_vec)) != srs_success) { return srs_error_wrap(err, "packet single nalu"); @@ -112,7 +138,7 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma uint8_t header = sample->bytes[0]; uint8_t nal_type = header & kNalTypeMask; - if (nal_type == kIdr) { + if (nal_type == SrsAvcNaluTypeIDR) { if ((err = packet_stap_a(sps, pps, shared_frame, rtp_packet_vec)) != srs_success) { return srs_error_wrap(err, "packet stap-a"); } @@ -153,6 +179,11 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma p += packet_size; nb_left -= packet_size; + srs_verbose("rtp fu-a nalu, size=%u, seq=%u, timestamp=%lu, ssrc=%u, payloadtype=%u, rtp header=%s, payload=%s", + sample->size, sequence, (shared_frame->timestamp * 90), kVideoSSRC, kH264PayloadType, + srs_string_dumps_hex(stream->data(), 12).c_str(), + srs_string_dumps_hex(stream->data() + 12, stream->pos() - 12).c_str()); + SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos()); @@ -174,7 +205,7 @@ srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, S SrsBuffer* stream = new SrsBuffer(buf, kRtpPacketSize); SrsAutoFree(SrsBuffer, stream); - if (nal_type == kIdr) { + if (nal_type == SrsAvcNaluTypeIDR) { if ((err = packet_stap_a(sps, pps, shared_frame, rtp_packet_vec)) != srs_success) { return srs_error_wrap(err, "packet stap-a"); } @@ -193,6 +224,12 @@ srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, S stream->write_bytes(sample->bytes, sample->size); + srs_verbose("sample=%s", srs_string_dumps_hex(sample->bytes, sample->size).c_str()); + srs_verbose("rtp single nalu, size=%u, seq=%u, timestamp=%lu, ssrc=%u, payloadtype=%u, rtp header=%s, payload=%s", + sample->size, sequence, (shared_frame->timestamp * 90), kVideoSSRC, kH264PayloadType, + srs_string_dumps_hex(stream->data(), 12).c_str(), + srs_string_dumps_hex(stream->data() + 12, stream->pos() - 12).c_str()); + SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos()); @@ -238,6 +275,11 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs stream->write_2bytes(pps.size()); stream->write_bytes((char*)pps.data(), pps.size()); + srs_verbose("rtp stap-a nalu, size=%u, seq=%u, timestamp=%lu, ssrc=%u, payloadtype=%u, rtp header=%s, payload=%s", + (sps.size() + pps.size()), sequence, (shared_frame->timestamp * 90), kVideoSSRC, kH264PayloadType, + srs_string_dumps_hex(stream->data(), 12).c_str(), + srs_string_dumps_hex(stream->data() + 12, stream->pos() - 12).c_str()); + SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos()); diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp index 212bf776c0..842d82620a 100644 --- a/trunk/src/app/srs_app_rtp.hpp +++ b/trunk/src/app/srs_app_rtp.hpp @@ -44,12 +44,11 @@ const uint8_t kH264PayloadType = 102; const uint8_t kNalTypeMask = 0x1F; -const uint8_t kIdr = 5; -const uint8_t kStapA = 24; -const uint8_t kFuA = 28; +const uint8_t kStapA = 24; +const uint8_t kFuA = 28; const uint8_t kStart = 0x80; -const uint8_t kEnd = 0x40; +const uint8_t kEnd = 0x40; // FIXME: ssrc can relate to source const uint32_t kVideoSSRC = 3233846889; diff --git a/trunk/src/kernel/srs_kernel_codec.hpp b/trunk/src/kernel/srs_kernel_codec.hpp index a8d674c2ba..c820cbeef3 100644 --- a/trunk/src/kernel/srs_kernel_codec.hpp +++ b/trunk/src/kernel/srs_kernel_codec.hpp @@ -398,6 +398,24 @@ enum SrsAvcNaluType }; std::string srs_avc_nalu2str(SrsAvcNaluType nalu_type); +/** + * Table 7-6 鈥 Name association to slice_type + * ISO_IEC_14496-10-AVC-2012.pdf, page 105. + */ +enum SrsAvcSliceType +{ + SrsAvcSliceTypeP = 0, + SrsAvcSliceTypeB = 1, + SrsAvcSliceTypeI = 2, + SrsAvcSliceTypeSP = 3, + SrsAvcSliceTypeSI = 4, + SrsAvcSliceTypeP1 = 5, + SrsAvcSliceTypeB1 = 6, + SrsAvcSliceTypeI1 = 7, + SrsAvcSliceTypeSP1 = 8, + SrsAvcSliceTypeSI1 = 9, +}; + /** * the avc payload format, must be ibmf or annexb format. * we guess by annexb first, then ibmf for the first time, From 830e60da29a7fc5689ab3ab5a7619a24c6ec4c6c Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 19 Mar 2020 10:36:47 +0800 Subject: [PATCH 50/69] For #1638, #307, update authors for rtc --- AUTHORS.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AUTHORS.txt b/AUTHORS.txt index 352376b94b..37935bc9a9 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -55,4 +55,7 @@ CONTRIBUTORS ordered by first contribution. * lam2003 * runner365 * XiaofengWang -* XiaLixin \ No newline at end of file +* XiaLixin +* xiaozhihong +* HuyaJohn + From 8eef439c90a79d69abc5955cdf9831e72abdb306 Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 19 Mar 2020 12:58:04 +0800 Subject: [PATCH 51/69] For #1638, #307, use hourglass for timer. --- trunk/src/app/srs_app_hourglass.cpp | 53 +++++++++++++++------- trunk/src/app/srs_app_hourglass.hpp | 55 +++++++++++++---------- trunk/src/app/srs_app_rtc_conn.cpp | 70 +++++------------------------ trunk/src/app/srs_app_rtc_conn.hpp | 29 +++--------- 4 files changed, 87 insertions(+), 120 deletions(-) diff --git a/trunk/src/app/srs_app_hourglass.cpp b/trunk/src/app/srs_app_hourglass.cpp index 88aeb2612e..24cec52e4a 100644 --- a/trunk/src/app/srs_app_hourglass.cpp +++ b/trunk/src/app/srs_app_hourglass.cpp @@ -26,7 +26,6 @@ using namespace std; #include -#include #include ISrsHourGlass::ISrsHourGlass() @@ -42,13 +41,31 @@ SrsHourGlass::SrsHourGlass(ISrsHourGlass* h, srs_utime_t resolution) handler = h; _resolution = resolution; total_elapse = 0; + trd = new SrsSTCoroutine("timer", this, _srs_context->get_id()); } SrsHourGlass::~SrsHourGlass() { + srs_freep(trd); } -srs_error_t SrsHourGlass::tick(int type, srs_utime_t interval) +srs_error_t SrsHourGlass::start() +{ + srs_error_t err = srs_success; + + if ((err = trd->start()) != srs_success) { + return srs_error_wrap(err, "start timer"); + } + + return err; +} + +srs_error_t SrsHourGlass::tick(srs_utime_t interval) +{ + return tick(0, interval); +} + +srs_error_t SrsHourGlass::tick(int event, srs_utime_t interval) { srs_error_t err = srs_success; @@ -57,7 +74,7 @@ srs_error_t SrsHourGlass::tick(int type, srs_utime_t interval) "invalid interval=%dms, resolution=%dms", srsu2msi(interval), srsu2msi(_resolution)); } - ticks[type] = interval; + ticks[event] = interval; return err; } @@ -65,22 +82,28 @@ srs_error_t SrsHourGlass::tick(int type, srs_utime_t interval) srs_error_t SrsHourGlass::cycle() { srs_error_t err = srs_success; + + while (true) { + if ((err = trd->pull()) != srs_success) { + return srs_error_wrap(err, "quit"); + } - map::iterator it; - for (it = ticks.begin(); it != ticks.end(); ++it) { - int type = it->first; - srs_utime_t interval = it->second; - - if (interval == 0 || (total_elapse % interval) == 0) { - if ((err = handler->notify(type, interval, total_elapse)) != srs_success) { - return srs_error_wrap(err, "notify"); + map::iterator it; + for (it = ticks.begin(); it != ticks.end(); ++it) { + int event = it->first; + srs_utime_t interval = it->second; + + if (interval == 0 || (total_elapse % interval) == 0) { + if ((err = handler->notify(event, interval, total_elapse)) != srs_success) { + return srs_error_wrap(err, "notify"); + } } } - } - // TODO: FIXME: Maybe we should use wallclock. - total_elapse += _resolution; - srs_usleep(_resolution); + // TODO: FIXME: Maybe we should use wallclock. + total_elapse += _resolution; + srs_usleep(_resolution); + } return err; } diff --git a/trunk/src/app/srs_app_hourglass.hpp b/trunk/src/app/srs_app_hourglass.hpp index 3c8447d4ca..aeb6893b58 100644 --- a/trunk/src/app/srs_app_hourglass.hpp +++ b/trunk/src/app/srs_app_hourglass.hpp @@ -26,8 +26,12 @@ #include +#include + #include +class SrsCoroutine; + // The handler for the tick. class ISrsHourGlass { @@ -36,40 +40,41 @@ class ISrsHourGlass virtual ~ISrsHourGlass(); public: // When time is ticked, this function is called. - virtual srs_error_t notify(int type, srs_utime_t interval, srs_utime_t tick) = 0; + virtual srs_error_t notify(int event, srs_utime_t interval, srs_utime_t tick) = 0; }; -// he hourglass used to do some specieal task, -// while these task is cycle when some interval, for example, -// there are N=3 tasks to do: -// 1. heartbeat every 3s. -// 2. print message every 5s. -// 3. notify backend every 7s. +// The hourglass(timer or SrsTimer) for special tasks, +// while these tasks are attached to some intervals, for example, +// there are N=3 tasks bellow: +// 1. A heartbeat every 3s. +// 2. A print message every 5s. +// 3. A notify backend every 7s. // The hourglass will call back when ticks: -// 1. notify(type=1, time=3) -// 2. notify(type=2, time=5) -// 3. notify(type=1, time=6) -// 4. notify(type=3, time=7) -// 5. notify(type=1, time=9) -// 6. notify(type=2, time=10) -// This is used for server and bocar server and other manager. +// 1. Got notify(event=1, time=3) +// 2. Got notify(event=2, time=5) +// 3. Got notify(event=1, time=6) +// 4. Got notify(event=3, time=7) +// 5. Got notify(event=1, time=9) +// 6. Got notify(event=2, time=10) +// It's a complex and high-performance timer. // // Usage: // SrsHourGlass* hg = new SrsHourGlass(handler, 1 * SRS_UTIME_MILLISECONDS); +// // hg->tick(1, 3 * SRS_UTIME_MILLISECONDS); // hg->tick(2, 5 * SRS_UTIME_MILLISECONDS); // hg->tick(3, 7 * SRS_UTIME_MILLISECONDS); -// // create a thread to cycle, which will call handerl when ticked. -// while (true) { -// hg->cycle(); -// } -class SrsHourGlass +// +// // The hg will create a thread for timer. +// hg->start(); +class SrsHourGlass : virtual public ISrsCoroutineHandler { private: + SrsCoroutine* trd; ISrsHourGlass* handler; srs_utime_t _resolution; // The ticks: - // key: the type of tick. + // key: the event of tick. // value: the interval of tick. std::map ticks; // The total elapsed time, @@ -79,10 +84,14 @@ class SrsHourGlass SrsHourGlass(ISrsHourGlass* h, srs_utime_t resolution); virtual ~SrsHourGlass(); public: - // Add a pair of tick(type, interval). - // @param type the type of tick. + // Start the hourglass. + virtual srs_error_t start(); +public: + // Add a pair of tick(event, interval). + // @param event the event of tick, default is 0. // @param interval the interval in srs_utime_t of tick. - virtual srs_error_t tick(int type, srs_utime_t interval); + virtual srs_error_t tick(srs_utime_t interval); + virtual srs_error_t tick(int event, srs_utime_t interval); public: // Cycle the hourglass, which will sleep resolution every time. // and call handler when ticked. diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index ec4d08e2cf..d739a53f45 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1151,23 +1151,25 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* udp_mux_skt) SrsRtcServer::SrsRtcServer() { listener = NULL; + timer = new SrsHourGlass(this, 1 * SRS_UTIME_SECONDS); } SrsRtcServer::~SrsRtcServer() { srs_freep(listener); - - rttrd->stop(); - srs_freep(rttrd); + srs_freep(timer); } srs_error_t SrsRtcServer::initialize() { srs_error_t err = srs_success; - rttrd = new SrsRtcTimerThread(this, _srs_context->get_id()); - if ((err = rttrd->start()) != srs_success) { - return srs_error_wrap(err, "rtc timer thread init failed"); + if ((err = timer->tick(1 * SRS_UTIME_SECONDS)) != srs_success) { + return srs_error_wrap(err, "hourglass tick"); + } + + if ((err = timer->start()) != srs_success) { + return srs_error_wrap(err, "start timer"); } return err; @@ -1369,60 +1371,10 @@ void SrsRtcServer::check_and_clean_timeout_session() } } -SrsRtcTimerThread::SrsRtcTimerThread(SrsRtcServer* rtc_svr, int parent_cid) -{ - _parent_cid = parent_cid; - trd = new SrsDummyCoroutine(); - - rtc_server = rtc_svr; -} - -SrsRtcTimerThread::~SrsRtcTimerThread() -{ - srs_freep(trd); -} - -int SrsRtcTimerThread::cid() -{ - return trd->cid(); -} - -srs_error_t SrsRtcTimerThread::start() -{ - srs_error_t err = srs_success; - - srs_freep(trd); - trd = new SrsSTCoroutine("rtc_timer", this, _parent_cid); - - if ((err = trd->start()) != srs_success) { - return srs_error_wrap(err, "rtc_timer"); - } - - return err; -} - -void SrsRtcTimerThread::stop() -{ - trd->stop(); -} - -void SrsRtcTimerThread::stop_loop() +srs_error_t SrsRtcServer::notify(int type, srs_utime_t interval, srs_utime_t tick) { - trd->interrupt(); -} - -srs_error_t SrsRtcTimerThread::cycle() -{ - srs_error_t err = srs_success; - - while (true) { - if ((err = trd->pull()) != srs_success) { - return srs_error_wrap(err, "rtc timer thread"); - } - - srs_usleep(1 * SRS_UTIME_SECONDS); - rtc_server->check_and_clean_timeout_session(); - } + check_and_clean_timeout_session(); + return srs_success; } RtcServerAdapter::RtcServerAdapter() diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 5cef95d934..029c8d4ab0 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -238,32 +239,11 @@ class SrsRtcSession srs_error_t on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* udp_mux_skt); }; -// TODO: FIXME: is there any other timer thread? -class SrsRtcTimerThread : public ISrsCoroutineHandler -{ -protected: - SrsCoroutine* trd; - int _parent_cid; -private: - SrsRtcServer* rtc_server; -public: - SrsRtcTimerThread(SrsRtcServer* rtc_svr, int parent_cid); - virtual ~SrsRtcTimerThread(); -public: - virtual int cid(); -public: - virtual srs_error_t start(); - virtual void stop(); - virtual void stop_loop(); -public: - virtual srs_error_t cycle(); -}; - -class SrsRtcServer : public ISrsUdpMuxHandler +class SrsRtcServer : virtual public ISrsUdpMuxHandler, virtual public ISrsHourGlass { private: SrsUdpMuxListener* listener; - SrsRtcTimerThread* rttrd; + SrsHourGlass* timer; private: std::map map_username_session; // key: username(local_ufrag + ":" + remote_ufrag) std::map map_id_session; // key: peerip(ip + ":" + port) @@ -289,6 +269,9 @@ class SrsRtcServer : public ISrsUdpMuxHandler private: SrsRtcSession* find_rtc_session_by_username(const std::string& ufrag); SrsRtcSession* find_rtc_session_by_peer_id(const std::string& peer_id); +// interface ISrsHourGlass +public: + virtual srs_error_t notify(int type, srs_utime_t interval, srs_utime_t tick); }; // The RTC server adapter. From 881506883e631a8e865cced15360f7bdf0e570fd Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 20 Mar 2020 15:16:30 +0800 Subject: [PATCH 52/69] Update --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 813e9d06d6..8b3284fc45 100755 --- a/README.md +++ b/README.md @@ -1708,6 +1708,7 @@ Winlin [bug #1631]: https://github.com/ossrs/srs/issues/1631 [bug #1612]: https://github.com/ossrs/srs/issues/1612 +[bug #1636]: https://github.com/ossrs/srs/issues/1636 [bug #zzzzzzzzzzzzz]: https://github.com/ossrs/srs/issues/zzzzzzzzzzzzz [exo #828]: https://github.com/google/ExoPlayer/pull/828 From 532750f18a949280dff8718ebf74a089c1af0bfd Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 21 Mar 2020 17:33:54 +0800 Subject: [PATCH 53/69] Refactor api data, url to api --- trunk/research/players/rtc_player.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trunk/research/players/rtc_player.html b/trunk/research/players/rtc_player.html index 20968798de..f9423bef3b 100644 --- a/trunk/research/players/rtc_player.html +++ b/trunk/research/players/rtc_player.html @@ -99,8 +99,8 @@ } var data = { - "url": url, "streamurl": urlObject.url, - "app": urlObject.app, "stream": urlObject.stream, + "api": url, + "streamurl": urlObject.url, "app": urlObject.app, "stream": urlObject.stream, "sdp": offer.sdp }; console.log("offer: " + JSON.stringify(data)); From 3360db7b779afe5ef4005f24582c95c4de1a4b14 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 21 Mar 2020 17:56:26 +0800 Subject: [PATCH 54/69] Refactor api, follow https://github.com/rtcdn/rtcdn-draft --- trunk/research/players/rtc_player.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/trunk/research/players/rtc_player.html b/trunk/research/players/rtc_player.html index f9423bef3b..082eb4a692 100644 --- a/trunk/research/players/rtc_player.html +++ b/trunk/research/players/rtc_player.html @@ -85,23 +85,23 @@ }).then(function(offer) { return new Promise(function(resolve, reject) { var port = urlObject.user_query.api || 1985; - var api = urlObject.user_query.play || '/api/v1/sdp/'; + + // @see https://github.com/rtcdn/rtcdn-draft + var api = urlObject.user_query.play || '/rtc/v1/play/'; if (api.lastIndexOf('/') != api.length - 1) { api += '/'; } - var url = schame + '//' + urlObject.server + ':' + port + api - + '?app=' + urlObject.app + '&stream=' + urlObject.stream; + var url = schame + '//' + urlObject.server + ':' + port + api; for (var key in urlObject.user_query) { if (key != 'api' && key != 'play') { url += '&' + key + '=' + urlObject.user_query[key]; } } + // @see https://github.com/rtcdn/rtcdn-draft var data = { - "api": url, - "streamurl": urlObject.url, "app": urlObject.app, "stream": urlObject.stream, - "sdp": offer.sdp + api: url, streamurl: urlObject.url, clientip: null, sdp: offer.sdp }; console.log("offer: " + JSON.stringify(data)); From 61b8ae8c3001f9d82a57643cdae586a69c51703f Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 21 Mar 2020 18:30:53 +0800 Subject: [PATCH 55/69] Refactor api, follow https://github.com/rtcdn/rtcdn-draft --- trunk/src/app/srs_app_http_api.cpp | 84 +++++++++++++++++++++--------- trunk/src/app/srs_app_rtc_conn.cpp | 2 +- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 822d9d35e1..add4a12967 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -790,42 +790,75 @@ SrsGoApiSdp::~SrsGoApiSdp() { } -// TODO: FIXME: Support query string http://localhost:1985/api/v1/sdp?app=live&stream=livestream + +// Request: +// POST /rtc/v1/play/ +// { +// "sdp":"offer...", "streamurl":"webrtc://r.ossrs.net/live/livestream", +// "api":'http...", "clientip":"..." +// } +// Response: +// {"sdp":"answer...", "sid":"..."} srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) { srs_error_t err = srs_success; - // path: {pattern} - // method: POST - // e.g. /api/v1/sdp/ args = json:{"sdp":"sdp...", "app":"webrtc", "stream":"test"} - // For each RTC session, we use short-term HTTP connection. SrsHttpHeader* hdr = w->header(); hdr->set("Connection", "Close"); - - string req_json; - if ((err = r->body_read_all(req_json)) != srs_success) { + + // Parse req, the request json object, from body. + SrsJsonObject* req = NULL; + if (true) { + string req_json; + if ((err = r->body_read_all(req_json)) != srs_success) { + return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + } + + SrsJsonAny* json = SrsJsonAny::loads(req_json); + if (!json || !json->is_object()) { + return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + } + + req = json->to_object(); + } + + // Fetch params from req object. + SrsJsonAny* prop = NULL; + if ((prop = req->ensure_property_string("sdp")) == NULL) { return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); } + string remote_sdp_str = prop->to_str(); - SrsJsonAny* json = SrsJsonAny::loads(req_json); - if (json == NULL) { + if ((prop = req->ensure_property_string("streamurl")) == NULL) { return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); } + string streamurl = prop->to_str(); - SrsJsonObject* req_obj = json->to_object(); + string clientip; + if ((prop = req->ensure_property_string("clientip")) != NULL) { + clientip = prop->to_str(); + } - SrsJsonAny* remote_sdp_obj = req_obj->get_property("sdp"); - SrsJsonAny* app_obj = req_obj->get_property("app"); - SrsJsonAny* stream_name_obj = req_obj->get_property("stream"); + string api; + if ((prop = req->ensure_property_string("api")) != NULL) { + api = prop->to_str(); + } - if (remote_sdp_obj == NULL || app_obj == NULL || stream_name_obj == NULL) { - return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + // Parse app and stream from streamurl. + string app; + string stream_name; + if (true) { + string tcUrl; + srs_parse_rtmp_url(streamurl, tcUrl, stream_name); + + int port; + string schema, host, vhost, param; + srs_discovery_tc_url(tcUrl, schema, host, vhost, app, stream_name, port, param); } - string remote_sdp_str = remote_sdp_obj->to_str(); - string app = app_obj->to_str(); - string stream_name = stream_name_obj->to_str(); + srs_trace("RTC play %s, api=%s, clientip=%s, app=%s, stream=%s, offer=%dB", + streamurl.c_str(), api.c_str(), clientip.c_str(), app.c_str(), stream_name.c_str(), remote_sdp_str.length()); // TODO: FIXME: It seems remote_sdp doesn't represents the full SDP information. SrsSdp remote_sdp; @@ -839,7 +872,7 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* request.stream = stream_name; SrsSdp local_sdp; // TODO: FIXME: Maybe need a better name? - /*SrsRtcSession* rtc_session = */rtc_server->create_rtc_session(request, remote_sdp, local_sdp); + SrsRtcSession* rtc_session = rtc_server->create_rtc_session(request, remote_sdp, local_sdp); string local_sdp_str = ""; if ((err = local_sdp.encode(local_sdp_str)) != srs_success) { @@ -853,12 +886,11 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* obj->set("server", SrsJsonAny::integer(SrsStatistic::instance()->server_id())); // TODO: add candidates in response json? - - if (r->is_http_post()) { - obj->set("sdp", SrsJsonAny::str(local_sdp_str.c_str())); - } else { - return srs_go_http_error(w, SRS_CONSTS_HTTP_MethodNotAllowed); - } + + obj->set("sdp", SrsJsonAny::str(local_sdp_str.c_str())); + obj->set("sessionid", SrsJsonAny::str(rtc_session->id().c_str())); + + srs_trace("RTC sid=%s, answer=%dB", rtc_session->id().c_str(), local_sdp_str.length()); return srs_api_response(w, r, obj->dumps()); } diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index d739a53f45..6eef83fbac 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1221,7 +1221,7 @@ srs_error_t SrsRtcServer::listen_api() // TODO: FIXME: Fetch api from hybrid manager. SrsHttpServeMux* http_api_mux = _srs_hybrid->srs()->instance()->api_server(); - if ((err = http_api_mux->handle("/api/v1/sdp/", new SrsGoApiSdp(this))) != srs_success) { + if ((err = http_api_mux->handle("/rtc/v1/play/", new SrsGoApiSdp(this))) != srs_success) { return srs_error_wrap(err, "handle sdp"); } From d2036455ac294f1bed7321172c75ef27eff9664d Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 21 Mar 2020 18:33:36 +0800 Subject: [PATCH 56/69] Refactor api, follow https://github.com/rtcdn/rtcdn-draft --- trunk/src/app/srs_app_http_api.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index add4a12967..51bb36d576 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -799,6 +799,7 @@ SrsGoApiSdp::~SrsGoApiSdp() // } // Response: // {"sdp":"answer...", "sid":"..."} +// @see https://github.com/rtcdn/rtcdn-draft srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) { srs_error_t err = srs_success; From 3f6a2871b05626ea7e41a92ae3a59157de6d740b Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 21 Mar 2020 19:00:47 +0800 Subject: [PATCH 57/69] For #1638, #307, show error information when api failed. --- trunk/src/app/srs_app_http_api.cpp | 46 +++++++++++++++++++----------- trunk/src/app/srs_app_http_api.hpp | 3 ++ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 51bb36d576..db3e8481ca 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -804,6 +804,22 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* { srs_error_t err = srs_success; + SrsJsonObject* res = SrsJsonAny::object(); + SrsAutoFree(SrsJsonObject, res); + + if ((err = do_serve_http(w, r, res)) != srs_success) { + srs_warn("RTC error %s", srs_error_desc(err).c_str()); srs_freep(err); + return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + + } + + return srs_api_response(w, r, res->dumps()); +} + +srs_error_t SrsGoApiSdp::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res) +{ + srs_error_t err = srs_success; + // For each RTC session, we use short-term HTTP connection. SrsHttpHeader* hdr = w->header(); hdr->set("Connection", "Close"); @@ -813,12 +829,12 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* if (true) { string req_json; if ((err = r->body_read_all(req_json)) != srs_success) { - return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + return srs_error_wrap(err, "read body"); } SrsJsonAny* json = SrsJsonAny::loads(req_json); if (!json || !json->is_object()) { - return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + return srs_error_wrap(err, "not json"); } req = json->to_object(); @@ -827,12 +843,12 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* // Fetch params from req object. SrsJsonAny* prop = NULL; if ((prop = req->ensure_property_string("sdp")) == NULL) { - return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + return srs_error_wrap(err, "not sdp"); } string remote_sdp_str = prop->to_str(); if ((prop = req->ensure_property_string("streamurl")) == NULL) { - return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + return srs_error_wrap(err, "not streamurl"); } string streamurl = prop->to_str(); @@ -863,9 +879,8 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* // TODO: FIXME: It seems remote_sdp doesn't represents the full SDP information. SrsSdp remote_sdp; - err = remote_sdp.decode(remote_sdp_str); - if (err != srs_success) { - return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + if ((err = remote_sdp.decode(remote_sdp_str)) != srs_success) { + return srs_error_wrap(err, "decode sdp"); } SrsRequest request; @@ -877,23 +892,20 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* string local_sdp_str = ""; if ((err = local_sdp.encode(local_sdp_str)) != srs_success) { - return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); + return srs_error_wrap(err, "encode sdp"); } - SrsJsonObject* obj = SrsJsonAny::object(); - SrsAutoFree(SrsJsonObject, obj); - - obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); - obj->set("server", SrsJsonAny::integer(SrsStatistic::instance()->server_id())); + res->set("code", SrsJsonAny::integer(ERROR_SUCCESS)); + res->set("server", SrsJsonAny::integer(SrsStatistic::instance()->server_id())); // TODO: add candidates in response json? - obj->set("sdp", SrsJsonAny::str(local_sdp_str.c_str())); - obj->set("sessionid", SrsJsonAny::str(rtc_session->id().c_str())); + res->set("sdp", SrsJsonAny::str(local_sdp_str.c_str())); + res->set("sessionid", SrsJsonAny::str(rtc_session->id().c_str())); srs_trace("RTC sid=%s, answer=%dB", rtc_session->id().c_str(), local_sdp_str.length()); - - return srs_api_response(w, r, obj->dumps()); + + return err; } SrsGoApiClients::SrsGoApiClients() diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 249ae7c31b..7b55eaf526 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -32,6 +32,7 @@ class SrsHttpParser; class SrsHttpHandler; class SrsServer; class SrsRtcServer; +class SrsJsonObject; #include #include @@ -174,6 +175,8 @@ class SrsGoApiSdp : public ISrsHttpHandler virtual ~SrsGoApiSdp(); public: virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); +private: + virtual srs_error_t do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res); }; class SrsGoApiClients : public ISrsHttpHandler From 68ad006b731edadc9d219421fa1ae4f2b3c9c521 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 21 Mar 2020 19:03:17 +0800 Subject: [PATCH 58/69] Remove empty line. --- trunk/src/app/srs_app_http_api.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index db3e8481ca..46c08ab790 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -810,7 +810,6 @@ srs_error_t SrsGoApiSdp::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* if ((err = do_serve_http(w, r, res)) != srs_success) { srs_warn("RTC error %s", srs_error_desc(err).c_str()); srs_freep(err); return srs_api_response_code(w, r, SRS_CONSTS_HTTP_BadRequest); - } return srs_api_response(w, r, res->dumps()); From fa700dad64f2791366864e0daf43f6cbf3210892 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Sat, 21 Mar 2020 21:26:30 +0800 Subject: [PATCH 59/69] 1. Modify rtc.conf to support Bframe discard. 2. Rename srs_app_rtp.cpp to srs_app_rtc.cpp --- trunk/conf/full.conf | 2 +- trunk/conf/rtc.conf | 6 +- trunk/configure | 2 +- trunk/src/app/srs_app_config.cpp | 69 ++++++++++++++++--- trunk/src/app/srs_app_config.hpp | 12 ++-- .../app/{srs_app_rtp.cpp => srs_app_rtc.cpp} | 52 +++++++------- .../app/{srs_app_rtp.hpp => srs_app_rtc.hpp} | 13 ++-- trunk/src/app/srs_app_rtc_conn.cpp | 10 +-- trunk/src/app/srs_app_source.cpp | 26 +++---- trunk/src/app/srs_app_source.hpp | 6 +- 10 files changed, 129 insertions(+), 69 deletions(-) rename trunk/src/app/{srs_app_rtp.cpp => srs_app_rtc.cpp} (90%) rename trunk/src/app/{srs_app_rtp.hpp => srs_app_rtc.hpp} (93%) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 3457350b9a..fac3799489 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -309,7 +309,7 @@ srt_server { ############################################################################################# # WebRTC server section ############################################################################################# -rtc { +rtc_server { # Whether enable WebRTC server. # default: off enabled on; diff --git a/trunk/conf/rtc.conf b/trunk/conf/rtc.conf index 300b81d6f4..f4578cec50 100644 --- a/trunk/conf/rtc.conf +++ b/trunk/conf/rtc.conf @@ -18,7 +18,7 @@ http_api { stats { network 0; } -rtc { +rtc_server { enabled on; # Listen at udp://8000 listen 8000; @@ -32,5 +32,9 @@ rtc { } vhost __defaultVhost__ { + rtc { + enabled on; + bframe discard; + } } diff --git a/trunk/configure b/trunk/configure index ab94025064..df55f860e3 100755 --- a/trunk/configure +++ b/trunk/configure @@ -256,7 +256,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" - "srs_app_mpegts_udp" "srs_app_rtp" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" + "srs_app_mpegts_udp" "srs_app_rtc" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" "srs_app_coworkers" "srs_app_hybrid") diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index b79fdadd76..7ec283f5fa 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3486,7 +3486,7 @@ srs_error_t SrsConfig::check_normal_config() && n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file" && n != "max_connections" && n != "daemon" && n != "heartbeat" && n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms" - && n != "http_server" && n != "stream_caster" && n != "rtc" && n != "srt_server" + && n != "http_server" && n != "stream_caster" && n != "rtc_server" && n != "srt_server" && n != "utc_time" && n != "work_dir" && n != "asprocess" && n != "ff_log_level" && n != "grace_final_wait" && n != "force_grace_quit" && n != "grace_start_wait" && n != "empty_ip_ok" && n != "disable_daemon_for_docker" @@ -3673,7 +3673,7 @@ srs_error_t SrsConfig::check_normal_config() && n != "play" && n != "publish" && n != "cluster" && n != "security" && n != "http_remux" && n != "dash" && n != "http_static" && n != "hds" && n != "exec" - && n != "in_ack_size" && n != "out_ack_size") { + && n != "in_ack_size" && n != "out_ack_size" && n != "rtc") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.%s", n.c_str()); } // for each sub directives of vhost. @@ -3819,6 +3819,13 @@ srs_error_t SrsConfig::check_normal_config() return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.bandcheck.%s of %s", m.c_str(), vhost->arg0().c_str()); } } + } else if (n == "rtc") { + for (int j = 0; j < (int)conf->directives.size(); j++) { + string m = conf->at(j)->name; + if (m != "enabled" && m != "bframe") { + return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.bandcheck.%s of %s", m.c_str(), vhost->arg0().c_str()); + } + } } } } @@ -4266,13 +4273,13 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* conf) return ::atoi(conf->arg0().c_str()); } -int SrsConfig::get_rtc_enabled() +int SrsConfig::get_rtc_server_enabled() { - SrsConfDirective* conf = root->get("rtc"); - return get_rtc_enabled(conf); + SrsConfDirective* conf = root->get("rtc_server"); + return get_rtc_server_enabled(conf); } -bool SrsConfig::get_rtc_enabled(SrsConfDirective* conf) +bool SrsConfig::get_rtc_server_enabled(SrsConfDirective* conf) { static bool DEFAULT = false; @@ -4288,11 +4295,11 @@ bool SrsConfig::get_rtc_enabled(SrsConfDirective* conf) return SRS_CONF_PERFER_FALSE(conf->arg0()); } -int SrsConfig::get_rtc_listen() +int SrsConfig::get_rtc_server_listen() { static int DEFAULT = 8000; - SrsConfDirective* conf = root->get("rtc"); + SrsConfDirective* conf = root->get("rtc_server"); if (!conf) { return DEFAULT; } @@ -4305,11 +4312,11 @@ int SrsConfig::get_rtc_listen() return ::atoi(conf->arg0().c_str()); } -std::string SrsConfig::get_rtc_candidates() +std::string SrsConfig::get_rtc_server_candidates() { static string DEFAULT = "*"; - SrsConfDirective* conf = root->get("rtc"); + SrsConfDirective* conf = root->get("rtc_server"); if (!conf) { return DEFAULT; } @@ -4332,6 +4339,48 @@ std::string SrsConfig::get_rtc_candidates() return (conf->arg0().c_str()); } +SrsConfDirective* SrsConfig::get_rtc(string vhost) +{ + SrsConfDirective* conf = get_vhost(vhost); + return conf? conf->get("rtc") : NULL; +} + +bool SrsConfig::get_rtc_enabled(string vhost) +{ + static bool DEFAULT = false; + + SrsConfDirective* conf = get_rtc(vhost); + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("enabled"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + +bool SrsConfig::get_rtc_bframe_discard(string vhost) +{ + static bool DEFAULT = false; + + SrsConfDirective* conf = get_rtc(vhost); + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("enabled"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return conf->arg0() == "discard"; +} + SrsConfDirective* SrsConfig::get_vhost(string vhost, bool try_default_vhost) { srs_assert(root); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 768e8368fc..e50aff296b 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -501,10 +501,14 @@ class SrsConfig // rtc section public: - virtual int get_rtc_enabled(); - virtual bool get_rtc_enabled(SrsConfDirective* conf); - virtual int get_rtc_listen(); - virtual std::string get_rtc_candidates(); + virtual int get_rtc_server_enabled(); + virtual bool get_rtc_server_enabled(SrsConfDirective* conf); + virtual int get_rtc_server_listen(); + virtual std::string get_rtc_server_candidates(); + + SrsConfDirective* get_rtc(std::string vhost); + bool get_rtc_enabled(std::string vhost); + bool get_rtc_bframe_discard(std::string vhost); // vhost specified section public: diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtc.cpp similarity index 90% rename from trunk/src/app/srs_app_rtp.cpp rename to trunk/src/app/srs_app_rtc.cpp index de8932018f..26351e4da1 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtc.cpp @@ -21,7 +21,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include +#include #include #include @@ -49,11 +49,13 @@ using namespace std; #include #include #include +#include #include SrsRtpMuxer::SrsRtpMuxer() { sequence = 0; + discard_bframe = false; } SrsRtpMuxer::~SrsRtpMuxer() @@ -99,9 +101,10 @@ srs_error_t SrsRtpMuxer::frame_to_packet(SrsSharedPtrMessage* shared_frame, SrsF } srs_verbose("nal_type=%d, slice type=%d", nal_type, slice_type); - // TODO: Use config to determine how to process B frame if (slice_type == SrsAvcSliceTypeB || slice_type == SrsAvcSliceTypeB1) { - continue; + if (discard_bframe) { + continue; + } } } @@ -179,11 +182,8 @@ srs_error_t SrsRtpMuxer::packet_fu_a(SrsSharedPtrMessage* shared_frame, SrsForma p += packet_size; nb_left -= packet_size; - srs_verbose("rtp fu-a nalu, size=%u, seq=%u, timestamp=%lu, ssrc=%u, payloadtype=%u, rtp header=%s, payload=%s", - sample->size, sequence, (shared_frame->timestamp * 90), kVideoSSRC, kH264PayloadType, - srs_string_dumps_hex(stream->data(), 12).c_str(), - srs_string_dumps_hex(stream->data() + 12, stream->pos() - 12).c_str()); - + srs_verbose("rtp fu-a nalu, size=%u, seq=%u, timestamp=%lu, ssrc=%u, payloadtype=%u", + sample->size, sequence, (shared_frame->timestamp * 90), kVideoSSRC, kH264PayloadType); SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos()); @@ -224,11 +224,8 @@ srs_error_t SrsRtpMuxer::packet_single_nalu(SrsSharedPtrMessage* shared_frame, S stream->write_bytes(sample->bytes, sample->size); - srs_verbose("sample=%s", srs_string_dumps_hex(sample->bytes, sample->size).c_str()); - srs_verbose("rtp single nalu, size=%u, seq=%u, timestamp=%lu, ssrc=%u, payloadtype=%u, rtp header=%s, payload=%s", - sample->size, sequence, (shared_frame->timestamp * 90), kVideoSSRC, kH264PayloadType, - srs_string_dumps_hex(stream->data(), 12).c_str(), - srs_string_dumps_hex(stream->data() + 12, stream->pos() - 12).c_str()); + srs_verbose("rtp single nalu, size=%u, seq=%u, timestamp=%lu, ssrc=%u, payloadtype=%u", + sample->size, sequence, (shared_frame->timestamp * 90), kVideoSSRC, kH264PayloadType); SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos()); @@ -275,10 +272,8 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs stream->write_2bytes(pps.size()); stream->write_bytes((char*)pps.data(), pps.size()); - srs_verbose("rtp stap-a nalu, size=%u, seq=%u, timestamp=%lu, ssrc=%u, payloadtype=%u, rtp header=%s, payload=%s", - (sps.size() + pps.size()), sequence, (shared_frame->timestamp * 90), kVideoSSRC, kH264PayloadType, - srs_string_dumps_hex(stream->data(), 12).c_str(), - srs_string_dumps_hex(stream->data() + 12, stream->pos() - 12).c_str()); + srs_verbose("rtp stap-a nalu, size=%u, seq=%u, timestamp=%lu, ssrc=%u, payloadtype=%u", + (sps.size() + pps.size()), sequence, (shared_frame->timestamp * 90), kVideoSSRC, kH264PayloadType); SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); rtp_shared_pkt->create((shared_frame->timestamp * 90), sequence++, kVideoSSRC, kH264PayloadType, stream->data(), stream->pos()); @@ -288,7 +283,7 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs return err; } -SrsRtp::SrsRtp() +SrsRtc::SrsRtc() { req = NULL; hub = NULL; @@ -298,12 +293,12 @@ SrsRtp::SrsRtp() last_update_time = 0; } -SrsRtp::~SrsRtp() +SrsRtc::~SrsRtc() { srs_freep(rtp_h264_muxer); } -void SrsRtp::dispose() +void SrsRtc::dispose() { if (enabled) { on_unpublish(); @@ -311,14 +306,14 @@ void SrsRtp::dispose() } // TODO: FIXME: Dead code? -srs_error_t SrsRtp::cycle() +srs_error_t SrsRtc::cycle() { srs_error_t err = srs_success; return err; } -srs_error_t SrsRtp::initialize(SrsOriginHub* h, SrsRequest* r) +srs_error_t SrsRtc::initialize(SrsOriginHub* h, SrsRequest* r) { srs_error_t err = srs_success; @@ -326,11 +321,12 @@ srs_error_t SrsRtp::initialize(SrsOriginHub* h, SrsRequest* r) req = r; rtp_h264_muxer = new SrsRtpMuxer(); + rtp_h264_muxer->discard_bframe = _srs_config->get_rtc_bframe_discard(req->vhost); return err; } -srs_error_t SrsRtp::on_publish() +srs_error_t SrsRtc::on_publish() { srs_error_t err = srs_success; @@ -341,6 +337,10 @@ srs_error_t SrsRtp::on_publish() if (enabled) { return err; } + + if (!_srs_config->get_rtc_enabled(req->vhost)) { + return err; + } // if enabled, open the muxer. enabled = true; @@ -351,7 +351,7 @@ srs_error_t SrsRtp::on_publish() return err; } -void SrsRtp::on_unpublish() +void SrsRtc::on_unpublish() { // support multiple unpublish. if (!enabled) { @@ -361,7 +361,7 @@ void SrsRtp::on_unpublish() enabled = false; } -srs_error_t SrsRtp::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format) +srs_error_t SrsRtc::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format) { srs_error_t err = srs_success; @@ -391,7 +391,7 @@ srs_error_t SrsRtp::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma return err; } -srs_error_t SrsRtp::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format) +srs_error_t SrsRtc::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtc.hpp similarity index 93% rename from trunk/src/app/srs_app_rtp.hpp rename to trunk/src/app/srs_app_rtc.hpp index 842d82620a..2a047d1109 100644 --- a/trunk/src/app/srs_app_rtp.hpp +++ b/trunk/src/app/srs_app_rtc.hpp @@ -21,8 +21,8 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef SRS_APP_RTP_HPP -#define SRS_APP_RTP_HPP +#ifndef SRS_APP_RTC_HPP +#define SRS_APP_RTC_HPP #include @@ -53,12 +53,15 @@ const uint8_t kEnd = 0x40; // FIXME: ssrc can relate to source const uint32_t kVideoSSRC = 3233846889; +// TODO: Define interface class like ISrsRtpMuxer to support SrsRtpOpusMuxer and so on. class SrsRtpMuxer { private: uint16_t sequence; std::string sps; std::string pps; +public: + bool discard_bframe; public: SrsRtpMuxer(); virtual ~SrsRtpMuxer(); @@ -70,7 +73,7 @@ class SrsRtpMuxer srs_error_t packet_stap_a(const std::string &sps, const std::string& pps, SrsSharedPtrMessage* shared_frame, std::vector& rtp_packet_vec); }; -class SrsRtp +class SrsRtc { private: SrsRequest* req; @@ -80,8 +83,8 @@ class SrsRtp SrsRtpMuxer* rtp_h264_muxer; SrsOriginHub* hub; public: - SrsRtp(); - virtual ~SrsRtp(); + SrsRtc(); + virtual ~SrsRtc(); public: virtual void dispose(); virtual srs_error_t cycle(); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 6eef83fbac..77de89bd69 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -46,7 +46,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include @@ -101,7 +101,7 @@ std::vector SrsCandidate::get_candidate_ips() { std::vector candidate_ips; - string candidate = _srs_config->get_rtc_candidates(); + string candidate = _srs_config->get_rtc_server_candidates(); if (candidate == "*" || candidate == "0.0.0.0") { std::vector tmp = srs_get_local_ips(); for (int i = 0; i < (int)tmp.size(); ++i) { @@ -189,7 +189,7 @@ srs_error_t SrsSdp::encode(string& sdp_str) std::vector candidate_ips = SrsCandidate::get_candidate_ips(); for (int i = 0; i < (int)candidate_ips.size(); ++i) { ostringstream os; - os << "a=candidate:10 1 udp 2115783679 " << candidate_ips[i] << " " << _srs_config->get_rtc_listen() <<" typ host generation 0\\r\\n"; + os << "a=candidate:10 1 udp 2115783679 " << candidate_ips[i] << " " << _srs_config->get_rtc_server_listen() <<" typ host generation 0\\r\\n"; candidate_lines += os.str(); } @@ -1179,11 +1179,11 @@ srs_error_t SrsRtcServer::listen_udp() { srs_error_t err = srs_success; - if (!_srs_config->get_rtc_enabled()) { + if (!_srs_config->get_rtc_server_enabled()) { return err; } - int port = _srs_config->get_rtc_listen(); + int port = _srs_config->get_rtc_server_listen(); if (port <= 0) { return srs_error_new(ERROR_RTC_PORT, "invalid port=%d", port); } diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index bccf5aae79..2d26c9e33c 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -33,7 +33,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include @@ -875,7 +875,7 @@ SrsOriginHub::SrsOriginHub() dash = new SrsDash(); dvr = new SrsDvr(); encoder = new SrsEncoder(); - rtp = new SrsRtp(); + rtc = new SrsRtc(); #ifdef SRS_AUTO_HDS hds = new SrsHds(); #endif @@ -920,8 +920,8 @@ srs_error_t SrsOriginHub::initialize(SrsSource* s, SrsRequest* r) return srs_error_wrap(err, "format initialize"); } - if ((err = rtp->initialize(this, req)) != srs_success) { - return srs_error_wrap(err, "rtp initialize"); + if ((err = rtc->initialize(this, req)) != srs_success) { + return srs_error_wrap(err, "rtc initialize"); } if ((err = hls->initialize(this, req)) != srs_success) { @@ -1022,10 +1022,10 @@ srs_error_t SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio) srs_flv_srates[c->sound_rate]); } - if ((err = rtp->on_audio(msg, format)) != srs_success) { - srs_warn("rtp: ignore audio error %s", srs_error_desc(err).c_str()); + if ((err = rtc->on_audio(msg, format)) != srs_success) { + srs_warn("rtc: ignore audio error %s", srs_error_desc(err).c_str()); srs_error_reset(err); - rtp->on_unpublish(); + rtc->on_unpublish(); } if ((err = hls->on_audio(msg, format)) != srs_success) { @@ -1122,11 +1122,11 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se } // Parse RTMP message to RTP packets, in FU-A if too large. - if ((err = rtp->on_video(msg, format)) != srs_success) { + if ((err = rtc->on_video(msg, format)) != srs_success) { // TODO: We should support more strategies. - srs_warn("rtp: ignore video error %s", srs_error_desc(err).c_str()); + srs_warn("rtc: ignore video error %s", srs_error_desc(err).c_str()); srs_error_reset(err); - rtp->on_unpublish(); + rtc->on_unpublish(); } // TODO: FIXME: Refactor to move to rtp? @@ -1201,8 +1201,8 @@ srs_error_t SrsOriginHub::on_publish() return srs_error_wrap(err, "encoder publish"); } - if ((err = rtp->on_publish()) != srs_success) { - return srs_error_wrap(err, "rtp publish"); + if ((err = rtc->on_publish()) != srs_success) { + return srs_error_wrap(err, "rtc publish"); } if ((err = hls->on_publish()) != srs_success) { @@ -1242,7 +1242,7 @@ void SrsOriginHub::on_unpublish() destroy_forwarders(); encoder->on_unpublish(); - rtp->on_unpublish(); + rtc->on_unpublish(); hls->on_unpublish(); dash->on_unpublish(); dvr->on_unpublish(); diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 083bf3e02d..01005d96ba 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -54,7 +54,7 @@ class SrsNgExec; class SrsConnection; class SrsMessageHeader; class SrsHls; -class SrsRtp; +class SrsRtc; class SrsDvr; class SrsDash; class SrsEncoder; @@ -360,8 +360,8 @@ class SrsOriginHub : public ISrsReloadHandler private: // The format, codec information. SrsRtmpFormat* format; - // rtp handler - SrsRtp* rtp; + // rtc handler + SrsRtc* rtc; // hls handler. SrsHls* hls; // The DASH encoder. From 7315b1a26d4405854af78cc728f178c8cdde193c Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Sat, 21 Mar 2020 21:40:26 +0800 Subject: [PATCH 60/69] Fix config read "bframe" discad bug. --- trunk/src/app/srs_app_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 7ec283f5fa..fdc5d1aefb 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -4373,7 +4373,7 @@ bool SrsConfig::get_rtc_bframe_discard(string vhost) return DEFAULT; } - conf = conf->get("enabled"); + conf = conf->get("bframe"); if (!conf || conf->arg0().empty()) { return DEFAULT; } From a0a4337214331f174abc5274e4e31e4cf3b72a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=83=E6=9B=A6?= Date: Sat, 21 Mar 2020 21:50:06 +0800 Subject: [PATCH 61/69] make webrtc audio work --- trunk/configure | 22 +- trunk/src/app/srs_app_audio_recode.cpp | 468 +++++++++++++++++++++++++ trunk/src/app/srs_app_audio_recode.hpp | 126 +++++++ trunk/src/app/srs_app_rtp.cpp | 154 +++++++- trunk/src/app/srs_app_rtp.hpp | 26 ++ trunk/src/app/srs_app_source.cpp | 10 +- 6 files changed, 790 insertions(+), 16 deletions(-) create mode 100644 trunk/src/app/srs_app_audio_recode.cpp create mode 100644 trunk/src/app/srs_app_audio_recode.hpp diff --git a/trunk/configure b/trunk/configure index ab94025064..0abbedc515 100755 --- a/trunk/configure +++ b/trunk/configure @@ -150,6 +150,8 @@ LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a" if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-lst"; fi # srtp LibSrtpRoot="${SRS_OBJS_DIR}/srtp2/include"; LibSrtpFile="${SRS_OBJS_DIR}/srtp2/lib/libsrtp2.a" +# ffmpeg +LibFfmpegRoot="${SRS_OBJS_DIR}/ffmpeg/include"; LibFfmpegFile="${SRS_OBJS_DIR}/ffmpeg/lib/libavcodec.a ${SRS_OBJS_DIR}/ffmpeg/lib/libswresample.a ${SRS_OBJS_DIR}/ffmpeg/lib/libavutil.a ${SRS_OBJS_DIR}/ffmpeg/lib/libopus.a -lpthread" # openssl-1.1.0e, for the RTMP complex handshake. LibSSLRoot="";LibSSLfile="" if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == NO ]]; then @@ -235,7 +237,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVICE" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL") - ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_service_log" "srs_service_st" "srs_service_http_client" "srs_service_http_conn" "srs_service_rtmp_conn" "srs_service_utility" "srs_service_conn") @@ -248,7 +250,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -259,7 +261,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_mpegts_udp" "srs_app_rtp" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" - "srs_app_coworkers" "srs_app_hybrid") + "srs_app_coworkers" "srs_app_hybrid" "srs_app_audio_recode") DEFINES="" # add each modules for app for SRS_MODULE in ${SRS_MODULES[*]}; do @@ -286,7 +288,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then if [[ $SRS_SRT == YES ]]; then MODULE_DEPENDS+=("SRT") fi - ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi @@ -299,7 +301,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="MAIN" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) MODULE_FILES=() DEFINES="" # add each modules for main @@ -326,13 +328,13 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then done # # all depends libraries - ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibFfmpegFile} ${LibSSLfile} ${LibGperfFile}) if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi # all depends objects MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" - ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then MODULE_OBJS="${MODULE_OBJS} ${SRT_OBJS[@]}" fi @@ -343,7 +345,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then # # For modules, without the app module. MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" - ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibFfmpegFile} ${LibSSLfile} ${LibGperfFile}) # for SRS_MODULE in ${SRS_MODULES[*]}; do . $SRS_MODULE/config @@ -363,11 +365,11 @@ if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSrtpRoot} ${LibSSLRoot}) + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${LibSSLRoot}) if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi - ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibSSLfile}) + ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibFfmpegFile} ${LibSSLfile}) if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi diff --git a/trunk/src/app/srs_app_audio_recode.cpp b/trunk/src/app/srs_app_audio_recode.cpp new file mode 100644 index 0000000000..ba6a9cf652 --- /dev/null +++ b/trunk/src/app/srs_app_audio_recode.cpp @@ -0,0 +1,468 @@ + +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +static const int kOpusPacketMs = 20; +static const int kOpusMaxbytes = 8000; +static const int kFrameBufMax = 40960; +static const int kPacketBufMax = 8192; +static const int kPcmBufMax = 4096*4; + +SrsAudioDecoder::SrsAudioDecoder(std::string codec) + : codec_name_(codec) +{ + frame_ = NULL; + packet_ = NULL; + codec_ctx_ = NULL; +} + +SrsAudioDecoder::~SrsAudioDecoder() +{ + if (codec_ctx_) { + avcodec_free_context(&codec_ctx_); + codec_ctx_ = NULL; + } + if (frame_) { + av_frame_free(&frame_); + frame_ = NULL; + } + if (packet_) { + av_packet_free(&packet_); + packet_ = NULL; + } +} + +srs_error_t SrsAudioDecoder::initialize() +{ + srs_error_t err = srs_success; + + if (codec_name_.compare("aac")) { + return srs_error_wrap(err, "Invalid codec name"); + } + + const AVCodec *codec = avcodec_find_decoder_by_name(codec_name_.c_str()); + if (!codec) { + return srs_error_wrap(err, "Codec not found by name"); + } + + codec_ctx_ = avcodec_alloc_context3(codec); + if (!codec_ctx_) { + return srs_error_wrap(err, "Could not allocate audio codec context"); + } + + if (avcodec_open2(codec_ctx_, codec, NULL) < 0) { + return srs_error_wrap(err, "Could not open codec"); + } + + frame_ = av_frame_alloc(); + if (!frame_) { + return srs_error_wrap(err, "Could not allocate audio frame"); + } + + packet_ = av_packet_alloc(); + if (!packet_) { + return srs_error_wrap(err, "Could not allocate audio packet"); + } + + return err; +} + +srs_error_t SrsAudioDecoder::decode(SrsSample *pkt, char *buf, int &size) +{ + srs_error_t err = srs_success; + + packet_->data = (uint8_t *)pkt->bytes; + packet_->size = pkt->size; + + int ret = avcodec_send_packet(codec_ctx_, packet_); + if (ret < 0) { + return srs_error_wrap(err, "Error submitting the packet to the decoder"); + } + + int max = size; + size = 0; + + while (ret >= 0) { + ret = avcodec_receive_frame(codec_ctx_, frame_); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + return err; + } else if (ret < 0) { + return srs_error_wrap(err, "Error during decoding"); + } + + int pcm_size = av_get_bytes_per_sample(codec_ctx_->sample_fmt); + if (pcm_size < 0) { + return srs_error_wrap(err, "Failed to calculate data size"); + } + + for (int i = 0; i < frame_->nb_samples; i++) { + if (size + pcm_size * codec_ctx_->channels <= max) { + memcpy(buf + size,frame_->data[0] + pcm_size*codec_ctx_->channels * i, pcm_size * codec_ctx_->channels); + size += pcm_size * codec_ctx_->channels; + } + } + } + + return err; +} + +AVCodecContext* SrsAudioDecoder::codec_ctx() +{ + return codec_ctx_; +} + +SrsAudioEncoder::SrsAudioEncoder(int samplerate, int channels, int fec, int complexity) + : inband_fec_(fec), + channels_(channels), + sampling_rate_(samplerate), + complexity_(complexity) +{ + opus_ = NULL; +} + +SrsAudioEncoder::~SrsAudioEncoder() +{ + if (opus_) { + opus_encoder_destroy(opus_); + opus_ = NULL; + } +} + +srs_error_t SrsAudioEncoder::initialize() +{ + srs_error_t err = srs_success; + + int error = 0; + opus_ = opus_encoder_create(sampling_rate_, channels_, OPUS_APPLICATION_VOIP, &error); + if (error != OPUS_OK) { + return srs_error_wrap(err, "Error create Opus encoder"); + } + + switch (sampling_rate_) + { + case 48000: + opus_encoder_ctl(opus_, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + break; + + case 24000: + opus_encoder_ctl(opus_, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); + + case 16000: + opus_encoder_ctl(opus_, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); + break; + + case 12000: + opus_encoder_ctl(opus_, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND)); + break; + + case 8000: + opus_encoder_ctl(opus_, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + break; + + default: + sampling_rate_ = 16000; + opus_encoder_ctl(opus_, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); + break; + } + opus_encoder_ctl(opus_, OPUS_SET_INBAND_FEC(inband_fec_)); + opus_encoder_ctl(opus_, OPUS_SET_COMPLEXITY(complexity_)); + + return err; +} + +srs_error_t SrsAudioEncoder::encode(SrsSample *frame, char *buf, int &size) +{ + srs_error_t err = srs_success; + + int nb_samples = sampling_rate_ * kOpusPacketMs / 1000; + if (frame->size != nb_samples * 2 * channels_) { + return srs_error_wrap(err, "invalid frame size %d, should be %d", frame->size, nb_samples * 2 * channels_); + } + + opus_int16 *data = (opus_int16 *)frame->bytes; + size = opus_encode(opus_, data, nb_samples, (unsigned char *)buf, kOpusMaxbytes); + + return err; +} + +SrsAudioResample::SrsAudioResample(int src_rate, int src_layout, enum AVSampleFormat src_fmt, + int src_nb, int dst_rate, int dst_layout, enum AVSampleFormat dst_fmt) + : src_rate_(src_rate), + src_ch_layout_(src_layout), + src_sample_fmt_(src_fmt), + src_nb_samples_(src_nb), + dst_rate_(dst_rate), + dst_ch_layout_(dst_layout), + dst_sample_fmt_(dst_fmt) +{ + src_nb_channels_ = 0; + dst_nb_channels_ = 0; + src_linesize_ = 0; + dst_linesize_ = 0; + dst_nb_samples_ = 0; + src_data_ = NULL; + dst_data_ = 0; + + max_dst_nb_samples_ = 0; + swr_ctx_ = NULL; +} + +SrsAudioResample::~SrsAudioResample() +{ + if (src_data_) { + av_freep(&src_data_[0]); + av_freep(&src_data_); + src_data_ = NULL; + } + if (dst_data_) { + av_freep(&dst_data_[0]); + av_freep(&dst_data_); + dst_data_ = NULL; + } + if (swr_ctx_) { + swr_free(&swr_ctx_); + swr_ctx_ = NULL; + } +} + +srs_error_t SrsAudioResample::initialize() +{ + srs_error_t err = srs_success; + + swr_ctx_ = swr_alloc(); + if (!swr_ctx_) { + return srs_error_wrap(err, "Could not allocate resampler context"); + } + + av_opt_set_int(swr_ctx_, "in_channel_layout", src_ch_layout_, 0); + av_opt_set_int(swr_ctx_, "in_sample_rate", src_rate_, 0); + av_opt_set_sample_fmt(swr_ctx_, "in_sample_fmt", src_sample_fmt_, 0); + + av_opt_set_int(swr_ctx_, "out_channel_layout", dst_ch_layout_, 0); + av_opt_set_int(swr_ctx_, "out_sample_rate", dst_rate_, 0); + av_opt_set_sample_fmt(swr_ctx_, "out_sample_fmt", dst_sample_fmt_, 0); + + int ret; + if ((ret = swr_init(swr_ctx_)) < 0) { + return srs_error_wrap(err, "Failed to initialize the resampling context"); + } + + src_nb_channels_ = av_get_channel_layout_nb_channels(src_ch_layout_); + ret = av_samples_alloc_array_and_samples(&src_data_, &src_linesize_, src_nb_channels_, + src_nb_samples_, src_sample_fmt_, 0); + if (ret < 0) { + return srs_error_wrap(err, "Could not allocate source samples"); + } + + max_dst_nb_samples_ = dst_nb_samples_ = + av_rescale_rnd(src_nb_samples_, dst_rate_, src_rate_, AV_ROUND_UP); + + dst_nb_channels_ = av_get_channel_layout_nb_channels(dst_ch_layout_); + ret = av_samples_alloc_array_and_samples(&dst_data_, &dst_linesize_, dst_nb_channels_, + dst_nb_samples_, dst_sample_fmt_, 0); + if (ret < 0) { + return srs_error_wrap(err, "Could not allocate destination samples"); + } + + return err; +} + +srs_error_t SrsAudioResample::resample(SrsSample *pcm, char *buf, int &size) +{ + srs_error_t err = srs_success; + + int ret, plane = 1; + if (src_sample_fmt_ == AV_SAMPLE_FMT_FLTP) { + plane = 2; + } + if (src_linesize_ * plane < pcm->size || pcm->size < 0) { + return srs_error_wrap(err, "size not ok"); + } + memcpy(src_data_[0], pcm->bytes, pcm->size); + + dst_nb_samples_ = av_rescale_rnd(swr_get_delay(swr_ctx_, src_rate_) + + src_nb_samples_, dst_rate_, src_rate_, AV_ROUND_UP); + if (dst_nb_samples_ > max_dst_nb_samples_) { + av_freep(&dst_data_[0]); + ret = av_samples_alloc(dst_data_, &dst_linesize_, dst_nb_channels_, + dst_nb_samples_, dst_sample_fmt_, 1); + if (ret < 0) { + return srs_error_wrap(err, "alloc error"); + } + max_dst_nb_samples_ = dst_nb_samples_; + } + + ret = swr_convert(swr_ctx_, dst_data_, dst_nb_samples_, (const uint8_t **)src_data_, src_nb_samples_); + if (ret < 0) { + return srs_error_wrap(err, "Error while converting"); + } + + int dst_bufsize = av_samples_get_buffer_size(&dst_linesize_, dst_nb_channels_, + ret, dst_sample_fmt_, 1); + if (dst_bufsize < 0) { + return srs_error_wrap(err, "Could not get sample buffer size"); + } + + int max = size; + size = 0; + if (max > dst_bufsize) { + memcpy(buf, dst_data_[0], dst_bufsize); + size = dst_bufsize; + } + + return err; +} + +SrsAudioRecode::SrsAudioRecode(int channels, int samplerate) + : dst_channels_(channels), + dst_samplerate_(samplerate) +{ + size_ = 0; + data_ = new char[kPcmBufMax]; +} + +SrsAudioRecode::~SrsAudioRecode() +{ + if (dec_) { + delete dec_; + dec_ = NULL; + } + if (enc_) { + delete enc_; + enc_ = NULL; + } + if (resample_) { + delete resample_; + resample_ = NULL; + } + + delete[] data_; +} + +srs_error_t SrsAudioRecode::initialize() +{ + srs_error_t err = srs_success; + + dec_ = new SrsAudioDecoder("aac"); + if (!dec_) { + return srs_error_wrap(err, "SrsAudioDecoder failed"); + } + dec_->initialize(); + + enc_ = new SrsAudioEncoder(dst_samplerate_, dst_channels_, 1, 1); + if (!enc_) { + return srs_error_wrap(err, "SrsAudioEncoder failed"); + } + enc_->initialize(); + + resample_ = NULL; + + return err; +} + +srs_error_t SrsAudioRecode::recode(SrsSample *pkt, char **buf, int *buf_len, int &n) +{ + srs_error_t err = srs_success; + + static char decode_buffer[kPacketBufMax]; + static char resample_buffer[kFrameBufMax]; + static char encode_buffer[kPacketBufMax]; + + if (!dec_) { + return srs_error_wrap(err, "dec_ nullptr"); + } + + int decode_len = kPacketBufMax; + if ((err = dec_->decode(pkt, decode_buffer, decode_len)) != srs_success) { + return srs_error_wrap(err, "decode error"); + } + + if (!resample_) { + int channel_layout = av_get_default_channel_layout(dst_channels_); + AVCodecContext *codec_ctx = dec_->codec_ctx(); + resample_ = new SrsAudioResample(codec_ctx->sample_rate, (int)codec_ctx->channel_layout, \ + codec_ctx->sample_fmt, codec_ctx->frame_size, dst_samplerate_, channel_layout, \ + AV_SAMPLE_FMT_S16); + + if (!resample_) { + return srs_error_wrap(err, "SrsAudioResample failed"); + } + resample_->initialize(); + } + + SrsSample pcm; + pcm.bytes = decode_buffer; + pcm.size = decode_len; + int resample_len = kFrameBufMax; + if ((err = resample_->resample(&pcm, resample_buffer, resample_len)) != srs_success) { + return srs_error_wrap(err, "decode error"); + } + + n = 0; + int data_left = resample_len; + int total; + total = (dst_samplerate_ * kOpusPacketMs / 1000) * 2 * dst_channels_; + + if (size_ + data_left < total) { + memcpy(data_ + size_, resample_buffer, data_left); + size_ += data_left; + } else { + int index = 0; + while (1) { + data_left = data_left - (total - size_); + memcpy(data_ + size_, resample_buffer + index, total - size_); + index += total - size_; + size_ += total - size_; + if (!enc_) { + return srs_error_wrap(err, "enc_ nullptr"); + } + + int encode_len; + pcm.bytes = (char *)data_; + pcm.size = size_; + if ((err = enc_->encode(&pcm, encode_buffer, encode_len)) != srs_success) { + return srs_error_wrap(err, "decode error"); + } + + memcpy(buf[n], encode_buffer, encode_len); + buf_len[n] = encode_len; + n++; + + size_ = 0; + if(!data_left) + break; + + if(data_left < total) { + memcpy(data_ + size_, resample_buffer + index, data_left); + size_ += data_left; + break; + } + } + } + + return err; +} diff --git a/trunk/src/app/srs_app_audio_recode.hpp b/trunk/src/app/srs_app_audio_recode.hpp new file mode 100644 index 0000000000..6dac2f07a2 --- /dev/null +++ b/trunk/src/app/srs_app_audio_recode.hpp @@ -0,0 +1,126 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2013-2020 Winlin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef SRS_APP_AUDIO_RECODE_HPP +#define SRS_APP_AUDIO_RECODE_HPP + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef __cplusplus +} +#endif + +class SrsSample; + +class SrsAudioDecoder +{ +private: + AVFrame* frame_; + AVPacket* packet_; + AVCodecContext* codec_ctx_; + std::string codec_name_; +public: + SrsAudioDecoder(std::string codec); + virtual ~SrsAudioDecoder(); + srs_error_t initialize(); + virtual srs_error_t decode(SrsSample *pkt, char *buf, int &size); + AVCodecContext* codec_ctx(); +}; + +class SrsAudioEncoder +{ +private: + int inband_fec_; + int channels_; + int sampling_rate_; + int complexity_; + OpusEncoder *opus_; +public: + SrsAudioEncoder(int samplerate, int channels, int fec, int complexity); + virtual ~SrsAudioEncoder(); + srs_error_t initialize(); + virtual srs_error_t encode(SrsSample *frame, char *buf, int &size); +}; + +class SrsAudioResample +{ +private: + int src_rate_; + int src_ch_layout_; + int src_nb_channels_; + enum AVSampleFormat src_sample_fmt_; + int src_linesize_; + int src_nb_samples_; + uint8_t **src_data_; + + int dst_rate_; + int dst_ch_layout_; + int dst_nb_channels_; + enum AVSampleFormat dst_sample_fmt_; + int dst_linesize_; + int dst_nb_samples_; + uint8_t **dst_data_; + + int max_dst_nb_samples_; + struct SwrContext *swr_ctx_; +public: + SrsAudioResample(int src_rate, int src_layout, enum AVSampleFormat src_fmt, + int src_nb, int dst_rate, int dst_layout, enum AVSampleFormat dst_fmt); + virtual ~SrsAudioResample(); + srs_error_t initialize(); + virtual srs_error_t resample(SrsSample *pcm, char *buf, int &size); +}; + +class SrsAudioRecode +{ +private: + SrsAudioDecoder *dec_; + SrsAudioEncoder *enc_; + SrsAudioResample *resample_; + int dst_channels_; + int dst_samplerate_; + int size_; + char *data_; +public: + SrsAudioRecode(int channels, int samplerate); + virtual ~SrsAudioRecode(); + srs_error_t initialize(); + virtual srs_error_t recode(SrsSample *pkt, char **buf, int *buf_len, int &n); +}; + +#endif /* SRS_APP_AUDIO_RECODE_HPP */ diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp index de8932018f..b9322ec7d2 100644 --- a/trunk/src/app/srs_app_rtp.cpp +++ b/trunk/src/app/srs_app_rtp.cpp @@ -50,6 +50,46 @@ using namespace std; #include #include #include +#include + +// TODO: Add this function into SrsRtpMux class. +srs_error_t aac_raw_append_adts_header(SrsSharedPtrMessage* shared_audio, SrsFormat* format, SrsBuffer** stream_ptr) +{ + srs_error_t err = srs_success; + + if (format->is_aac_sequence_header()) { + return err; + } + + if (stream_ptr == NULL) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "adts"); + } + + srs_verbose("audio samples=%d", format->audio->nb_samples); + + if (format->audio->nb_samples != 1) { + return srs_error_new(ERROR_RTC_RTP_MUXER, "adts"); + } + + int nb_buf = format->audio->samples[0].size + 7; + char* buf = new char[nb_buf]; + SrsBuffer* stream = new SrsBuffer(buf, nb_buf); + + // TODO: Add comment. + stream->write_1bytes(0xFF); + stream->write_1bytes(0xF9); + stream->write_1bytes(((format->acodec->aac_object - 1) << 6) | ((format->acodec->aac_sample_rate & 0x0F) << 2) | ((format->acodec->aac_channels & 0x04) >> 2)); + stream->write_1bytes(((format->acodec->aac_channels & 0x03) << 6) | ((nb_buf >> 11) & 0x03)); + stream->write_1bytes((nb_buf >> 3) & 0xFF); + stream->write_1bytes(((nb_buf & 0x07) << 5) | 0x1F); + stream->write_1bytes(0xFC); + + stream->write_bytes(format->audio->samples[0].bytes, format->audio->samples[0].size); + + *stream_ptr = stream; + + return err; +} SrsRtpMuxer::SrsRtpMuxer() { @@ -288,6 +328,104 @@ srs_error_t SrsRtpMuxer::packet_stap_a(const string &sps, const string& pps, Srs return err; } +SrsRtpOpusMuxer::SrsRtpOpusMuxer() +{ + sequence = 0; + timestamp = 0; + recoder = NULL; +} + +SrsRtpOpusMuxer::~SrsRtpOpusMuxer() +{ + if (recoder) { + delete recoder; + recoder = NULL; + } +} + +srs_error_t SrsRtpOpusMuxer::initialize() +{ + srs_error_t err = srs_success; + + recoder = new SrsAudioRecode(kChannel, kSamplerate); + if (!recoder) { + return srs_error_wrap(err, "SrsAacOpus init failed"); + } + recoder->initialize(); + + return err; +} + +srs_error_t SrsRtpOpusMuxer::frame_to_packet(SrsSharedPtrMessage* shared_audio, SrsFormat* format, SrsBuffer* stream) +{ + srs_error_t err = srs_success; + + vector rtp_packet_vec; + + char* data_ptr[kArrayLength]; + static char data_array[kArrayLength][kArrayBuffer]; + int elen[kArrayLength], number = 0; + + data_ptr[0] = &data_array[0][0]; + for (int i = 1; i < kArrayLength; i++) { + data_ptr[i] = data_array[i]; + } + + SrsSample pkt; + pkt.bytes = stream->data(); + pkt.size = stream->pos(); + + if ((err = recoder->recode(&pkt, data_ptr, elen, number)) != srs_success) { + return srs_error_wrap(err, "recode error"); + } + + for (int i = 0; i < number; i++) { + SrsSample sample; + sample.size = elen[i]; + sample.bytes = data_ptr[i]; + packet_opus(shared_audio, &sample, rtp_packet_vec); + } + + shared_audio->set_rtp_packets(rtp_packet_vec); + + return err; +} + +srs_error_t SrsRtpOpusMuxer::packet_opus(SrsSharedPtrMessage* shared_frame, SrsSample* sample, std::vector& rtp_packet_vec) +{ + srs_error_t err = srs_success; + + char* buf = new char[kRtpPacketSize]; + SrsBuffer* stream = new SrsBuffer(buf, kRtpPacketSize); + SrsAutoFree(SrsBuffer, stream); + + // v=2,p=0,x=0,cc=0 + stream->write_1bytes(0x80); + // marker payloadtype + stream->write_1bytes(kOpusPayloadType); + // sequenct + stream->write_2bytes(sequence); + // timestamp + stream->write_4bytes(int32_t(timestamp)); + timestamp += 960; + // ssrc + stream->write_4bytes(int32_t(kAudioSSRC)); + + stream->write_bytes(sample->bytes, sample->size); + + srs_verbose("sample=%s", srs_string_dumps_hex(sample->bytes, sample->size).c_str()); + srs_verbose("opus, size=%u, seq=%u, timestamp=%lu, ssrc=%u, payloadtype=%u", + sample->size, sequence, timestamp, kAudioSSRC, kOpusPayloadType); + + SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket(); + rtp_shared_pkt->create(timestamp, sequence++, kAudioSSRC, kOpusPayloadType, stream->data(), stream->pos()); + rtp_shared_pkt->set_marker(true); + + rtp_packet_vec.push_back(rtp_shared_pkt); + + return err; +} + SrsRtp::SrsRtp() { req = NULL; @@ -326,6 +464,11 @@ srs_error_t SrsRtp::initialize(SrsOriginHub* h, SrsRequest* r) req = r; rtp_h264_muxer = new SrsRtpMuxer(); + + rtp_opus_muxer = new SrsRtpOpusMuxer(); + if (rtp_opus_muxer) { + rtp_opus_muxer->initialize(); + } return err; } @@ -387,7 +530,16 @@ srs_error_t SrsRtp::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma // ignore sequence header srs_assert(format->audio); - // TODO: rtc no support aac + SrsBuffer* stream = NULL; + SrsAutoFree(SrsBuffer, stream); + if ((err = aac_raw_append_adts_header(shared_audio, format, &stream)) != srs_success) { + return srs_error_wrap(err, "aac append header"); + } + + if (stream) { + rtp_opus_muxer->frame_to_packet(shared_audio, format, stream); + } + return err; } diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp index 842d82620a..3b64bdf380 100644 --- a/trunk/src/app/srs_app_rtp.hpp +++ b/trunk/src/app/srs_app_rtp.hpp @@ -36,10 +36,13 @@ class SrsSharedPtrMessage; class SrsRtpSharedPacket; class SrsRequest; class SrsOriginHub; +class SrsAudioRecode; +class SrsBuffer; const int max_payload_size = 1200; const int kRtpPacketSize = 1500; +const uint8_t kOpusPayloadType = 111; const uint8_t kH264PayloadType = 102; const uint8_t kNalTypeMask = 0x1F; @@ -50,7 +53,13 @@ const uint8_t kFuA = 28; const uint8_t kStart = 0x80; const uint8_t kEnd = 0x40; +const int kChannel = 2; +const int kSamplerate = 48000; +const int kArrayLength = 8; +const int kArrayBuffer = 4096; + // FIXME: ssrc can relate to source +const uint32_t kAudioSSRC = 3233846890; const uint32_t kVideoSSRC = 3233846889; class SrsRtpMuxer @@ -70,6 +79,22 @@ class SrsRtpMuxer srs_error_t packet_stap_a(const std::string &sps, const std::string& pps, SrsSharedPtrMessage* shared_frame, std::vector& rtp_packet_vec); }; +class SrsRtpOpusMuxer +{ +private: + uint32_t timestamp; + uint16_t sequence; + SrsAudioRecode* recoder; +public: + SrsRtpOpusMuxer(); + virtual ~SrsRtpOpusMuxer(); + virtual srs_error_t initialize(); +public: + srs_error_t frame_to_packet(SrsSharedPtrMessage* shared_audio, SrsFormat* format, SrsBuffer* stream); +private: + srs_error_t packet_opus(SrsSharedPtrMessage* shared_frame, SrsSample* sample, std::vector& rtp_packet_vec); +}; + class SrsRtp { private: @@ -78,6 +103,7 @@ class SrsRtp bool disposable; srs_utime_t last_update_time; SrsRtpMuxer* rtp_h264_muxer; + SrsRtpOpusMuxer* rtp_opus_muxer; SrsOriginHub* hub; public: SrsRtp(); diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index bccf5aae79..8ecd711e3d 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -2261,6 +2261,11 @@ srs_error_t SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) } } + // Copy to hub to all utilities. + if ((err = hub->on_audio(msg)) != srs_success) { + return srs_error_wrap(err, "consume audio"); + } + // copy to all consumer if (!drop_for_reduce) { for (int i = 0; i < (int)consumers.size(); i++) { @@ -2271,11 +2276,6 @@ srs_error_t SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) } } - // Copy to hub to all utilities. - if ((err = hub->on_audio(msg)) != srs_success) { - return srs_error_wrap(err, "consume audio"); - } - // cache the sequence header of aac, or first packet of mp3. // for example, the mp3 is used for hls to write the "right" audio codec. // TODO: FIXME: to refine the stream info system. From 0cd67a997ec5812050758fd01d3eee90fbc69f9d Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 21 Mar 2020 22:52:59 +0800 Subject: [PATCH 62/69] For #1638, #307, add comments for vhost rtc config --- trunk/conf/full.conf | 13 +++++++++++++ trunk/src/app/srs_app_http_api.cpp | 1 + 2 files changed, 14 insertions(+) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index fac3799489..46b9229fc7 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -325,6 +325,19 @@ rtc_server { candidate *; } +vhost rtc.vhost.srs.com { + rtc { + # Whether enable WebRTC server. + # default: off + enabled on; + # The strategy for bframe. + # keep Keep bframe, which may make browser with playing problems. + # discard Discard bframe, maybe cause browser with little problems. + # default: keep + bframe discard; + } +} + ############################################################################################# # RTMP/HTTP VHOST sections ############################################################################################# diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 46c08ab790..2ea98230a5 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -887,6 +887,7 @@ srs_error_t SrsGoApiSdp::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessag request.stream = stream_name; SrsSdp local_sdp; // TODO: FIXME: Maybe need a better name? + // TODO: FIXME: When server enabled, but vhost disabled, should report error. SrsRtcSession* rtc_session = rtc_server->create_rtc_session(request, remote_sdp, local_sdp); string local_sdp_str = ""; From e1fe2d1c1daf6becb62f574c12c96cd2911f7518 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 22 Mar 2020 07:18:25 +0800 Subject: [PATCH 63/69] For #1638, #307, add comments for audio codec --- trunk/src/app/srs_app_audio_recode.cpp | 1 + trunk/src/app/srs_app_rtc.cpp | 1 + trunk/src/app/srs_app_rtc.hpp | 1 + 3 files changed, 3 insertions(+) diff --git a/trunk/src/app/srs_app_audio_recode.cpp b/trunk/src/app/srs_app_audio_recode.cpp index ba6a9cf652..d716766c6b 100644 --- a/trunk/src/app/srs_app_audio_recode.cpp +++ b/trunk/src/app/srs_app_audio_recode.cpp @@ -384,6 +384,7 @@ srs_error_t SrsAudioRecode::initialize() return err; } +// TODO: FIXME: Rename to transcode. srs_error_t SrsAudioRecode::recode(SrsSample *pkt, char **buf, int *buf_len, int &n) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtc.cpp b/trunk/src/app/srs_app_rtc.cpp index 360f3a6b7d..3cf8dc1eb4 100644 --- a/trunk/src/app/srs_app_rtc.cpp +++ b/trunk/src/app/srs_app_rtc.cpp @@ -402,6 +402,7 @@ srs_error_t SrsRtpOpusMuxer::packet_opus(SrsSharedPtrMessage* shared_frame, SrsS stream->write_2bytes(sequence); // timestamp stream->write_4bytes(int32_t(timestamp)); + // TODO: FIXME: Why 960? Need Refactoring? timestamp += 960; // ssrc stream->write_4bytes(int32_t(kAudioSSRC)); diff --git a/trunk/src/app/srs_app_rtc.hpp b/trunk/src/app/srs_app_rtc.hpp index e0a147c73e..27974943fb 100644 --- a/trunk/src/app/srs_app_rtc.hpp +++ b/trunk/src/app/srs_app_rtc.hpp @@ -85,6 +85,7 @@ class SrsRtpMuxer class SrsRtpOpusMuxer { private: + // TODO: FIXME: How to handle timestamp overflow? uint32_t timestamp; uint16_t sequence; SrsAudioRecode* recoder; From 2da4e0a43ed012180b01978eb1392671375e766c Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 22 Mar 2020 08:28:51 +0800 Subject: [PATCH 64/69] For #1638, #307, config to discard aac for rtc --- trunk/conf/full.conf | 5 +++++ trunk/src/app/srs_app_config.cpp | 22 ++++++++++++++++++++-- trunk/src/app/srs_app_config.hpp | 1 + trunk/src/app/srs_app_rtc.cpp | 9 +++++++++ trunk/src/app/srs_app_rtc.hpp | 2 ++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 46b9229fc7..bf2ec83775 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -335,6 +335,11 @@ vhost rtc.vhost.srs.com { # discard Discard bframe, maybe cause browser with little problems. # default: keep bframe discard; + # The strategy for aac audio. + # transcode Transcode aac to opus. + # discard Discard aac audio packet. + # default: transcode + aac transcode; } } diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index fdc5d1aefb..c5a0e3a3c4 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3822,8 +3822,8 @@ srs_error_t SrsConfig::check_normal_config() } else if (n == "rtc") { for (int j = 0; j < (int)conf->directives.size(); j++) { string m = conf->at(j)->name; - if (m != "enabled" && m != "bframe") { - return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.bandcheck.%s of %s", m.c_str(), vhost->arg0().c_str()); + if (m != "enabled" && m != "bframe" && m != "aac") { + return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.rtc.%s of %s", m.c_str(), vhost->arg0().c_str()); } } } @@ -4381,6 +4381,24 @@ bool SrsConfig::get_rtc_bframe_discard(string vhost) return conf->arg0() == "discard"; } +bool SrsConfig::get_rtc_aac_discard(string vhost) +{ + static bool DEFAULT = false; + + SrsConfDirective* conf = get_rtc(vhost); + + if (!conf) { + return DEFAULT; + } + + conf = conf->get("aac"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return conf->arg0() == "discard"; +} + SrsConfDirective* SrsConfig::get_vhost(string vhost, bool try_default_vhost) { srs_assert(root); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index e50aff296b..e58777dfa1 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -509,6 +509,7 @@ class SrsConfig SrsConfDirective* get_rtc(std::string vhost); bool get_rtc_enabled(std::string vhost); bool get_rtc_bframe_discard(std::string vhost); + bool get_rtc_aac_discard(std::string vhost); // vhost specified section public: diff --git a/trunk/src/app/srs_app_rtc.cpp b/trunk/src/app/srs_app_rtc.cpp index 3cf8dc1eb4..9a2acda3bb 100644 --- a/trunk/src/app/srs_app_rtc.cpp +++ b/trunk/src/app/srs_app_rtc.cpp @@ -430,6 +430,8 @@ SrsRtc::SrsRtc() enabled = false; disposable = false; last_update_time = 0; + + discard_aac = false; } SrsRtc::~SrsRtc() @@ -461,6 +463,8 @@ srs_error_t SrsRtc::initialize(SrsOriginHub* h, SrsRequest* r) rtp_h264_muxer = new SrsRtpMuxer(); rtp_h264_muxer->discard_bframe = _srs_config->get_rtc_bframe_discard(req->vhost); + // TODO: FIXME: Support reload and log it. + discard_aac = _srs_config->get_rtc_aac_discard(req->vhost); rtp_opus_muxer = new SrsRtpOpusMuxer(); if (rtp_opus_muxer) { @@ -527,6 +531,11 @@ srs_error_t SrsRtc::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma if (acodec != SrsAudioCodecIdAAC && acodec != SrsAudioCodecIdMP3) { return err; } + + // When drop aac audio packet, never transcode. + if (discard_aac && acodec == SrsAudioCodecIdAAC) { + return err; + } // ignore sequence header srs_assert(format->audio); diff --git a/trunk/src/app/srs_app_rtc.hpp b/trunk/src/app/srs_app_rtc.hpp index 27974943fb..64c28db570 100644 --- a/trunk/src/app/srs_app_rtc.hpp +++ b/trunk/src/app/srs_app_rtc.hpp @@ -82,6 +82,7 @@ class SrsRtpMuxer srs_error_t packet_stap_a(const std::string &sps, const std::string& pps, SrsSharedPtrMessage* shared_frame, std::vector& rtp_packet_vec); }; +// TODO: FIXME: It's not a muxer, but a transcoder. class SrsRtpOpusMuxer { private: @@ -105,6 +106,7 @@ class SrsRtc SrsRequest* req; bool enabled; bool disposable; + bool discard_aac; srs_utime_t last_update_time; SrsRtpMuxer* rtp_h264_muxer; SrsRtpOpusMuxer* rtp_opus_muxer; From 634a14bfa6c41d074d616f288bff251e424b739f Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 22 Mar 2020 14:03:48 +0800 Subject: [PATCH 65/69] For #1659, #307, add opus codec library --- trunk/3rdparty/opus-1.3.1.tar.gz | Bin 0 -> 1040054 bytes trunk/auto/depends.sh | 51 +++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 trunk/3rdparty/opus-1.3.1.tar.gz diff --git a/trunk/3rdparty/opus-1.3.1.tar.gz b/trunk/3rdparty/opus-1.3.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..1119371fc2a6638f8ce6e3393093a95409e3b4d5 GIT binary patch literal 1040054 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

gtmPJ?TYS=K!JZ16C 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ℜN{8 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%0Amdtk7pr1~JZ``fEO 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

    `ODe_%(OnBDU`TPInj!!v0Yce+mgAK396 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 z%0D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

    4)gn#3K!;zy2sGeVzwO-B?hz||fo#;AkaMe&`! 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


    V^=X}Jwcr4-sSQG9$6 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

    Y$2*6cN1G=HM;!huZeuVH41R%MIU+C> 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%0D1701C;t~ATGmt*CiL|bVf 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

    |}_*~%NTbF_?_CK$c9S4a>~#$(x2 zsze*a?-*Y}8@^T4;Rj4g zCFfpUGaC6L#r}80Un}y)C zbNNp#cu(SEv&&`On&^2w#OG3j8?Z|cEX>)<5DO_~!dQLJrp<>rd` zE?es8X8__*7a)F59A>!&mu0aBTl~C+SO?aD@?WaK3QCJ-J)u_FnMS^vOq2sX4^<>T zcYQpR^<>vREF!y<^TOqQ3%rsa8n!)-m?Mh#N=ko;&c7}b5}|5UG>&t#k`0XoK-+{3 zlp_AB;;9i)lZGEh@^aBKI7u!q*J}qHz9dsjEfX9`eB$Z4t2)YA3li}`F_;}fF3r&Z z4zX>cI>yEX1{NG1v>Udt5tEKsrN&FtF~dvG_ElrgqT{4^@wg71iM;Zc?RAY4! zuYepG6@;s74;I%;L1y%2{Hsuu)5s$;&W!9Cxlkk(Y4SoUk~9W1ym?vdKPt6ID57K# zkiIX`R`gUuR+vmrMUH`KOxI@4y3P=<6#(*&%hM4XUdV0Y(O2}V6BiPmw`?IXw6pJ|Fj zZ#|BRl~){!B7Ud@JK#w!*1f<(N_x*|z)YdJaN<;Qu7t#qH23+GzgHTGwB=pYm6D30 zL8EVdfzo$_2%cy5cmZN9@)j*io+;uhD3wI4!z>aSaD;37-$z!kxWY<(MrEO6vK`Z7 zPz*~NZr$UlP}3;*D;5>oRumUg7SRi8|pH22^Y}SG+K1Y8T3r@ z+p6o6Xgj5M;iMm`8b&*kId%T{ zp<~2^fYwUeT6x_8E&MaD^Yc-nN^6wNvBpz@_j^s|Ny2Ib({yg~8u6O8s=Wkjd z750sLLu7JpQV6pnx8p&fZ7^&Vfu7Z+XGbidN_DOm zG#!#t-Ga;X3D1c`4DbhCDd0*x^U3WPCqMrRroCl1k`MmE{{!dTbQbDT3w1<7FH)Va5+rYEyPz&?I<} z=eMWdIwPqHHQv&-gHdk|yu!X;R;Nm%VH$$zjneR(^w;2$O>yV5){5f>M}~Su6wSz9-70(Wd;w@i2CybxB3A)$ahKkswLc z`zC`TLnu^4bR4t*z4HS}B7Xd9Z=#_UZbvO+IHhEgdOORUBz$Mi2w!~#4mTkJZdvxS&QkS9$?xOmf(#G-2ULJ2MW*?Eme zY|#yoKv(53G9!4vZtjUXcv8c#>j#)E24wZJ{m{@n)yg0WnBZ+T*^u9=4QO5dlcQ@+ z#hsnYG>lH;7PO&1ztZsBPd;xubn}eP2}YfhIZD(j4TY>J*vcH{;JwD$nBEIjEFhlK zUo~@QFM#^adv%|bM+!UZf8F*-u0GjDtK_^QzvYLe`pLp~^5-IKlWC7>BTl5ZFVaGB#tkGHUT145xlL@d;#p{Q9&)4@zm24nAw{2eU8 zC~3hAE$iLO=KrFH@rM?A^afw3zsaVlk|{uuq{o%jiKRH*ahZK47Ohz8AVPK?qn{N( zGKl*j$>F>b5}l_G#uDBRF2)~~fJ3ZVS98qvTAA*`O`k6Sb5Y7eZQX^z5@N&R61WzD28ITjHe#)tH_*J8GEb4_o)(jK^)y+`KyrxanSaryELA<$=j2h;V%q5Z zRhQF7QTW?H;QNwiS;S3!S;SrgZG21Nborw#C{rmCL%>GPAVDe77(VHU`weh88pMLh zKv){tpzW62Sb%`9P{KopOHJ%Fjn7mE%*a+D=O8+vN9qx}1R)-j{)cM5m(e41vU4IAVFq6*CLE zJFvY9n(W@m8RYKhXcsc2>60AoBY{z?a%UJ{6(WoeMKr{THMu0svcu%ejll*_x}kj; zl+M}U0gOaq4gGn$IAF9(7;2kKD|`rGk<;{kLJq8dV#;>;gVWLN6tcKPZOihNJ$SZ( zFSj|Tl}~ucLZ?0E3e$(aJD&&zrD0>

    ceUN~3XfQN$V~vI*!;ea%*o0;2%Z9-=yp zmaxGuOFqNUycfnJAsBHYlf>*VPSD|XLu_xFcNb4;vou{1TDEc{H+^OfU`^`A;vpSD z)mqYFny;x&wXBl+k#1n|(L`NUi7qeDE)`xGI!-Mgt98-iPI?m#n=v|;z!fQ};X1mF zwNH-yl0MM7qr=NNgb|9)dxZNGitVZKA?g#WlSx1tA<4Y|+H%J>g|&?W5~f;1%7rW3 znX_OlL@T&rvrK+tc_lLph4{fHV*w2(j4wS2cbsfiZIuEEw!d4%8-fE8O5!Y)N~htE z1YnO-)|YM3%#*wh%I3Q*I2*ar!HgI3@ndOQdCNjLq-gCHPY|bh>gU|YOHyW6R06fOkA5SYEq(ub9Z)R!8$jP&f?!x`H?ru=Y!vq8K zjo67ayb@rfWfUHR7VQ4KxU=IvUXdi5{^mdT4{w%pjj{Myp*=)I5?N%gIR7%&5gbM38$ z+rn`;Wm4f3jtQtWYU&VYL3@gIxe+mgOg|zNlAyr+`JXS6TQ*&UViJbP9ql`a`RS3r zLH9jOG_T)Ao&f~23oiLmmj@{=L%ENR=tlk!kg(8ToiDtalHqu;C4|+$*hDzCBz@`- zIL^6)RiOwSS?oDdbj1Op8GlHF;8cnw{&g*qGuJFO@?|2xScoR!)T)6>s0PUS1%KKt zN2`s{6s3y6!UgAS_=_eLrR=3}5@pPs-6=wnB0{SV9Mjt{6j{b3uzRs3gS#x--kHg| z*$?`(u z7fa#|Fe?d%$fE#XsNhjlYRN{!RhF3dmrGm2RD2^>4`;7hwpQww3lFyjdiZ7)rjH;i znAMl}Fkit_9r&0(cFkYfj=EZ2*aYE_0dc67F3PwPkI2GGB>4`me{s^AE)Q%#`R@GW zx;Vm*m&pY|HvWmbgS4meV0{BF(AMKnSnLY}kA2L-6f;qlf}qpOq%4GdmK3f8 zsBeN^Bi9fn7E{!BO-hwNZ*wpbx*a)*wy=z$^HCg0MF}?z$fVf~H%W$zndMBohaYZC zj{>1ZqT0X*ojIdQOwnIje2Ivoo^x^P1#Ij6_Xs*60yuK`9TWC`o~!oTj_(z3($HeE z(ZPX> zliMr`4cs=)_DPWXhuQB=fTH^PlGtxC)gu(Cg8g=MCjg-3aUn8>os3xslsmEyq6vp*{S$BbYzppxpjmon6Fi$^tIf6SI+;15SoV7l

    q7eFajUysn_Z8=*WAHXEn*9SYudJ=+kK2xkzc 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�g4uH3$6-0%b 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�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

      Lm$RT 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� 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 literal 0 HcmV?d00001 diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index b2c69bbdbc..786c8aef82 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -84,6 +84,13 @@ function Ubuntu_prepare() echo "The unzip is installed." fi + nasm -v >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then + echo "Installing nasm." + require_sudoer "sudo apt-get install -y --force-yes nasm" + sudo apt-get install -y --force-yes nasm; ret=$?; if [[ 0 -ne $ret ]]; then return $ret; fi + echo "The nasm is installed." + fi + if [[ $SRS_VALGRIND == YES ]]; then valgrind --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then echo "Installing valgrind." @@ -157,6 +164,13 @@ function Centos_prepare() echo "The unzip is installed." fi + nasm -v >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then + echo "Installing nasm." + require_sudoer "sudo yum install -y nasm" + sudo yum install -y nasm; ret=$?; if [[ 0 -ne $ret ]]; then return $ret; fi + echo "The nasm is installed." + fi + if [[ $SRS_VALGRIND == YES ]]; then valgrind --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then echo "Installing valgrind." @@ -373,7 +387,7 @@ if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL != YES ]]; then rm -rf ${SRS_OBJS}/openssl-1.1.0e && cd ${SRS_OBJS} && unzip -q ../3rdparty/openssl-1.1.0e.zip && cd openssl-1.1.0e && ${OPENSSL_CONFIG} --prefix=`pwd`/_release $OPENSSL_OPTIONS && - make CC=${SRS_TOOL_CC} AR="${SRS_TOOL_AR} -rs" LD=${SRS_TOOL_LD} RANDLIB=${SRS_TOOL_RANDLIB} && make install_sw && + make CC=${SRS_TOOL_CC} AR="${SRS_TOOL_AR} -rs" LD=${SRS_TOOL_LD} RANDLIB=${SRS_TOOL_RANDLIB} ${SRS_JOBS} && make install_sw && cd .. && rm -rf openssl && ln -sf openssl-1.1.0e/_release openssl ) fi @@ -382,6 +396,27 @@ if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL != YES ]]; then if [ ! -f ${SRS_OBJS}/openssl/lib/libssl.a ]; then echo "Build openssl-1.1.0e failed."; exit -1; fi fi +##################################################################################### +# libopus, for WebRTC to transcode AAC with Opus. +##################################################################################### +if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then + # cross build not specified, if exists flag, need to rebuild for no-arm platform. + if [[ -f ${SRS_OBJS}/opus/lib/libopus.a ]]; then + echo "The opus-1.3.1 is ok."; + else + echo "Building opus-1.3.1."; + ( + rm -rf ${SRS_OBJS}/opus-1.3.1 && cd ${SRS_OBJS} && + tar xf ../3rdparty/opus-1.3.1.tar.gz && cd opus-1.3.1 && + ./configure --prefix=`pwd`/_release --enable-static --disable-shared && make ${SRS_JOBS} && make install + cd .. && rm -rf opus && ln -sf opus-1.3.1/_release opus + ) + fi + # check status + ret=$?; if [[ $ret -ne 0 ]]; then echo "Build opus-1.3.1 failed, ret=$ret"; exit $ret; fi + if [ ! -f ${SRS_OBJS}/opus/lib/libopus.a ]; then echo "Build opus-1.3.1 failed."; exit -1; fi +fi + ##################################################################################### # live transcoding, ffmpeg-4.1, x264-core157, lame-3.99.5, libaacplus-2.0.2. ##################################################################################### @@ -393,17 +428,9 @@ if [ $SRS_FFMPEG_TOOL = YES ]; then if [[ -f ${SRS_OBJS}/ffmpeg/bin/ffmpeg ]]; then echo "ffmpeg-4.1 is ok."; else - echo "build ffmpeg-4.1"; - ( - cd ${SRS_OBJS} && pwd_dir=`pwd` && - rm -rf ffmepg.src && mkdir -p ffmpeg.src && cd ffmpeg.src && - rm -f build_ffmpeg.sh && ln -sf ../../auto/build_ffmpeg.sh && . build_ffmpeg.sh && - cd ${pwd_dir} && rm -rf ffmpeg && ln -sf ffmpeg.src/_release ffmpeg - ) + echo "no ffmpeg-4.1 found, please run in docker ossrs/srs:dev"; + exit -1; fi - # check status - ret=$?; if [[ $ret -ne 0 ]]; then echo "build ffmpeg-4.1 failed, ret=$ret"; exit $ret; fi - if [ ! -f ${SRS_OBJS}/ffmpeg/bin/ffmpeg ]; then echo "build ffmpeg-4.1 failed."; exit -1; fi fi ##################################################################################### @@ -417,7 +444,7 @@ if [[ $SRS_SRT == YES ]]; then if [[ -f ${SRS_OBJS}/srt/lib/libsrt.a ]]; then echo "libsrt-1.4.1 is ok."; else - echo "no libsrt, please use srs-docker or build from source https://github.com/ossrs/srs/issues/1147#issuecomment-577469119"; + echo "no libsrt, please run in docker ossrs/srs:srt or build from source https://github.com/ossrs/srs/issues/1147#issuecomment-577469119"; exit -1; fi fi From 4308f238c069ba856678b5843294368615215823 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 22 Mar 2020 16:34:54 +0800 Subject: [PATCH 66/69] For #1659, #307, add ffmpeg-4.2-fit for rtc --- trunk/3rdparty/ffmpeg-4.2-fit/.gitignore | 17 + trunk/3rdparty/ffmpeg-4.2-fit/.version | 0 trunk/3rdparty/ffmpeg-4.2-fit/Makefile | 169 + .../compat/atomics/gcc/stdatomic.h | 173 + .../3rdparty/ffmpeg-4.2-fit/compat/va_copy.h | 34 + trunk/3rdparty/ffmpeg-4.2-fit/configure | 7531 +++++++++++++++++ .../3rdparty/ffmpeg-4.2-fit/ffbuild/arch.mak | 17 + .../ffmpeg-4.2-fit/ffbuild/common.mak | 175 + .../ffmpeg-4.2-fit/ffbuild/library.mak | 107 + .../ffmpeg-4.2-fit/ffbuild/libversion.sh | 13 + .../ffbuild/pkgconfig_generate.sh | 62 + .../ffmpeg-4.2-fit/ffbuild/version.sh | 63 + .../ffmpeg-4.2-fit/libavcodec/Makefile | 1225 +++ .../3rdparty/ffmpeg-4.2-fit/libavcodec/aac.h | 377 + .../libavcodec/aac_ac3_parser.c | 105 + .../libavcodec/aac_ac3_parser.h | 66 + .../libavcodec/aac_adtstoasc_bsf.c | 158 + .../ffmpeg-4.2-fit/libavcodec/aac_defines.h | 116 + .../ffmpeg-4.2-fit/libavcodec/aac_parser.c | 71 + .../ffmpeg-4.2-fit/libavcodec/aaccoder.c | 964 +++ .../libavcodec/aaccoder_trellis.h | 192 + .../libavcodec/aaccoder_twoloop.h | 763 ++ .../ffmpeg-4.2-fit/libavcodec/aacdec.c | 591 ++ .../ffmpeg-4.2-fit/libavcodec/aacdec_fixed.c | 468 + .../libavcodec/aacdec_template.c | 3450 ++++++++ .../ffmpeg-4.2-fit/libavcodec/aacdectab.h | 74 + .../ffmpeg-4.2-fit/libavcodec/aacenc.c | 1165 +++ .../ffmpeg-4.2-fit/libavcodec/aacenc.h | 428 + .../ffmpeg-4.2-fit/libavcodec/aacenc_is.c | 158 + .../ffmpeg-4.2-fit/libavcodec/aacenc_is.h | 51 + .../ffmpeg-4.2-fit/libavcodec/aacenc_ltp.c | 236 + .../ffmpeg-4.2-fit/libavcodec/aacenc_ltp.h | 41 + .../ffmpeg-4.2-fit/libavcodec/aacenc_pred.c | 347 + .../ffmpeg-4.2-fit/libavcodec/aacenc_pred.h | 47 + .../libavcodec/aacenc_quantization.h | 283 + .../libavcodec/aacenc_quantization_misc.h | 53 + .../ffmpeg-4.2-fit/libavcodec/aacenc_tns.c | 215 + .../ffmpeg-4.2-fit/libavcodec/aacenc_tns.h | 37 + .../ffmpeg-4.2-fit/libavcodec/aacenc_utils.h | 279 + .../ffmpeg-4.2-fit/libavcodec/aacencdsp.asm | 86 + .../libavcodec/aacencdsp_init.c | 43 + .../ffmpeg-4.2-fit/libavcodec/aacenctab.c | 108 + .../ffmpeg-4.2-fit/libavcodec/aacenctab.h | 139 + .../ffmpeg-4.2-fit/libavcodec/aacps.c | 1046 +++ .../ffmpeg-4.2-fit/libavcodec/aacps.h | 86 + .../ffmpeg-4.2-fit/libavcodec/aacps_fixed.c | 24 + .../libavcodec/aacps_fixed_tablegen.c | 24 + .../libavcodec/aacps_fixed_tablegen.h | 403 + .../ffmpeg-4.2-fit/libavcodec/aacps_float.c | 24 + .../libavcodec/aacps_tablegen.c | 24 + .../libavcodec/aacps_tablegen.h | 217 + .../libavcodec/aacps_tablegen_template.c | 107 + .../ffmpeg-4.2-fit/libavcodec/aacpsdata.c | 163 + .../ffmpeg-4.2-fit/libavcodec/aacpsdsp.asm | 487 ++ .../ffmpeg-4.2-fit/libavcodec/aacpsdsp.h | 60 + .../libavcodec/aacpsdsp_fixed.c | 23 + .../libavcodec/aacpsdsp_float.c | 23 + .../ffmpeg-4.2-fit/libavcodec/aacpsdsp_init.c | 72 + .../libavcodec/aacpsdsp_template.c | 233 + .../ffmpeg-4.2-fit/libavcodec/aacpsy.c | 1025 +++ .../ffmpeg-4.2-fit/libavcodec/aacsbr.c | 370 + .../ffmpeg-4.2-fit/libavcodec/aacsbr.h | 96 + .../ffmpeg-4.2-fit/libavcodec/aacsbr_fixed.c | 613 ++ .../libavcodec/aacsbr_fixed_tablegen.h | 28 + .../libavcodec/aacsbr_tablegen.h | 28 + .../libavcodec/aacsbr_tablegen_common.h | 114 + .../libavcodec/aacsbr_template.c | 1583 ++++ .../ffmpeg-4.2-fit/libavcodec/aacsbrdata.h | 535 ++ .../ffmpeg-4.2-fit/libavcodec/aactab.c | 3282 +++++++ .../ffmpeg-4.2-fit/libavcodec/aactab.h | 186 + .../aarch64/aacpsdsp_init_aarch64.c | 48 + .../libavcodec/aarch64/asm-offsets.h | 25 + .../ffmpeg-4.2-fit/libavcodec/aarch64/cabac.h | 104 + .../libavcodec/aarch64/fft_init_aarch64.c | 50 + .../libavcodec/aarch64/fmtconvert_init.c | 43 + .../aarch64/h264chroma_init_aarch64.c | 59 + .../libavcodec/aarch64/h264dsp_init_aarch64.c | 129 + .../libavcodec/aarch64/h264pred_init.c | 93 + .../aarch64/h264qpel_init_aarch64.c | 172 + .../libavcodec/aarch64/hpeldsp_init_aarch64.c | 123 + .../ffmpeg-4.2-fit/libavcodec/aarch64/idct.h | 28 + .../libavcodec/aarch64/idctdsp_init_aarch64.c | 41 + .../libavcodec/aarch64/mpegaudiodsp_init.c | 40 + .../libavcodec/aarch64/opusdsp_init.c | 35 + .../libavcodec/aarch64/rv40dsp_init_aarch64.c | 48 + .../libavcodec/aarch64/sbrdsp_init_aarch64.c | 70 + .../libavcodec/aarch64/synth_filter_init.c | 47 + .../libavcodec/aarch64/vc1dsp_init_aarch64.c | 47 + .../libavcodec/aarch64/videodsp_init.c | 32 + .../libavcodec/aarch64/vorbisdsp_init.c | 34 + .../libavcodec/aarch64/vp8dsp.h | 75 + .../libavcodec/aarch64/vp8dsp_init_aarch64.c | 124 + .../libavcodec/aarch64/vp9dsp_init.h | 29 + .../aarch64/vp9dsp_init_10bpp_aarch64.c | 23 + .../aarch64/vp9dsp_init_12bpp_aarch64.c | 23 + .../vp9dsp_init_16bpp_aarch64_template.c | 273 + .../libavcodec/aarch64/vp9dsp_init_aarch64.c | 258 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/ac3.c | 211 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/ac3.h | 263 + .../ffmpeg-4.2-fit/libavcodec/ac3_parser.c | 258 + .../ffmpeg-4.2-fit/libavcodec/ac3_parser.h | 36 + .../libavcodec/ac3_parser_internal.h | 42 + .../ffmpeg-4.2-fit/libavcodec/ac3dec.c | 1843 ++++ .../ffmpeg-4.2-fit/libavcodec/ac3dec.h | 277 + .../ffmpeg-4.2-fit/libavcodec/ac3dec_data.c | 60 + .../ffmpeg-4.2-fit/libavcodec/ac3dec_data.h | 32 + .../ffmpeg-4.2-fit/libavcodec/ac3dec_fixed.c | 197 + .../ffmpeg-4.2-fit/libavcodec/ac3dec_float.c | 93 + .../ffmpeg-4.2-fit/libavcodec/ac3dsp.c | 447 + .../ffmpeg-4.2-fit/libavcodec/ac3dsp.h | 167 + .../ffmpeg-4.2-fit/libavcodec/ac3enc.c | 2495 ++++++ .../ffmpeg-4.2-fit/libavcodec/ac3enc.h | 315 + .../ffmpeg-4.2-fit/libavcodec/ac3enc_fixed.c | 160 + .../ffmpeg-4.2-fit/libavcodec/ac3enc_float.c | 155 + .../libavcodec/ac3enc_opts_template.c | 82 + .../libavcodec/ac3enc_template.c | 436 + .../ffmpeg-4.2-fit/libavcodec/ac3tab.c | 334 + .../ffmpeg-4.2-fit/libavcodec/ac3tab.h | 71 + .../ffmpeg-4.2-fit/libavcodec/adts_header.c | 71 + .../ffmpeg-4.2-fit/libavcodec/adts_header.h | 50 + .../ffmpeg-4.2-fit/libavcodec/adts_parser.c | 44 + .../ffmpeg-4.2-fit/libavcodec/adts_parser.h | 37 + .../ffmpeg-4.2-fit/libavcodec/allcodecs.c | 921 ++ .../libavcodec/audio_frame_queue.c | 113 + .../libavcodec/audio_frame_queue.h | 83 + .../ffmpeg-4.2-fit/libavcodec/avcodec.h | 6228 ++++++++++++++ .../ffmpeg-4.2-fit/libavcodec/avdct.c | 129 + .../ffmpeg-4.2-fit/libavcodec/avdct.h | 84 + .../ffmpeg-4.2-fit/libavcodec/avfft.c | 145 + .../ffmpeg-4.2-fit/libavcodec/avfft.h | 118 + .../ffmpeg-4.2-fit/libavcodec/avpacket.c | 743 ++ .../ffmpeg-4.2-fit/libavcodec/avpicture.c | 82 + .../ffmpeg-4.2-fit/libavcodec/bitstream.c | 362 + .../libavcodec/bitstream_filter.c | 185 + .../libavcodec/bitstream_filters.c | 114 + .../ffmpeg-4.2-fit/libavcodec/blockdsp.c | 78 + .../ffmpeg-4.2-fit/libavcodec/blockdsp.h | 50 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/bsf.c | 567 ++ .../3rdparty/ffmpeg-4.2-fit/libavcodec/bsf.h | 44 + .../ffmpeg-4.2-fit/libavcodec/bsf_list.c | 3 + .../ffmpeg-4.2-fit/libavcodec/bytestream.h | 376 + .../ffmpeg-4.2-fit/libavcodec/cbrt_data.c | 30 + .../ffmpeg-4.2-fit/libavcodec/cbrt_data.h | 40 + .../libavcodec/cbrt_data_fixed.c | 29 + .../ffmpeg-4.2-fit/libavcodec/cbrt_tablegen.c | 24 + .../ffmpeg-4.2-fit/libavcodec/cbrt_tablegen.h | 73 + .../ffmpeg-4.2-fit/libavcodec/codec_desc.c | 3286 +++++++ .../ffmpeg-4.2-fit/libavcodec/codec_list.c | 9 + .../ffmpeg-4.2-fit/libavcodec/d3d11va.c | 48 + .../ffmpeg-4.2-fit/libavcodec/d3d11va.h | 112 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/dct.h | 69 + .../ffmpeg-4.2-fit/libavcodec/decode.c | 2062 +++++ .../ffmpeg-4.2-fit/libavcodec/decode.h | 81 + .../ffmpeg-4.2-fit/libavcodec/dirac.c | 408 + .../ffmpeg-4.2-fit/libavcodec/dirac.h | 131 + .../ffmpeg-4.2-fit/libavcodec/dirac_arith.h | 202 + .../ffmpeg-4.2-fit/libavcodec/dirac_dwt.h | 132 + .../ffmpeg-4.2-fit/libavcodec/dirac_vlc.h | 51 + .../ffmpeg-4.2-fit/libavcodec/diracdsp.h | 72 + .../ffmpeg-4.2-fit/libavcodec/diractab.h | 43 + .../ffmpeg-4.2-fit/libavcodec/dv_profile.c | 341 + .../ffmpeg-4.2-fit/libavcodec/dv_profile.h | 83 + .../libavcodec/dv_profile_internal.h | 35 + .../ffmpeg-4.2-fit/libavcodec/dxva2.h | 93 + .../ffmpeg-4.2-fit/libavcodec/encode.c | 447 + .../libavcodec/error_resilience.c | 1366 +++ .../libavcodec/error_resilience.h | 97 + .../ffmpeg-4.2-fit/libavcodec/fdctdsp.h | 37 + .../ffmpeg-4.2-fit/libavcodec/fft-internal.h | 94 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/fft.h | 175 + .../ffmpeg-4.2-fit/libavcodec/fft_fixed.c | 21 + .../ffmpeg-4.2-fit/libavcodec/fft_fixed_32.c | 52 + .../ffmpeg-4.2-fit/libavcodec/fft_float.c | 21 + .../ffmpeg-4.2-fit/libavcodec/fft_init.c | 61 + .../libavcodec/fft_init_table.c | 328 + .../ffmpeg-4.2-fit/libavcodec/fft_table.h | 66 + .../ffmpeg-4.2-fit/libavcodec/fft_template.c | 639 ++ .../libavcodec/frame_thread_encoder.c | 327 + .../libavcodec/frame_thread_encoder.h | 30 + .../ffmpeg-4.2-fit/libavcodec/get_bits.h | 868 ++ .../ffmpeg-4.2-fit/libavcodec/golomb.c | 173 + .../ffmpeg-4.2-fit/libavcodec/golomb.h | 747 ++ .../ffmpeg-4.2-fit/libavcodec/h263dsp.c | 126 + .../ffmpeg-4.2-fit/libavcodec/h263dsp.h | 35 + .../ffmpeg-4.2-fit/libavcodec/h264chroma.c | 59 + .../ffmpeg-4.2-fit/libavcodec/h264chroma.h | 40 + .../ffmpeg-4.2-fit/libavcodec/hpeldsp.c | 370 + .../ffmpeg-4.2-fit/libavcodec/hpeldsp.h | 106 + .../ffmpeg-4.2-fit/libavcodec/hwaccel.h | 84 + .../ffmpeg-4.2-fit/libavcodec/hwaccels.h | 78 + .../ffmpeg-4.2-fit/libavcodec/idctdsp.h | 122 + .../ffmpeg-4.2-fit/libavcodec/iirfilter.c | 327 + .../ffmpeg-4.2-fit/libavcodec/iirfilter.h | 147 + .../ffmpeg-4.2-fit/libavcodec/imgconvert.c | 232 + .../ffmpeg-4.2-fit/libavcodec/internal.h | 433 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/jni.c | 79 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/jni.h | 46 + .../ffmpeg-4.2-fit/libavcodec/kbdwin.c | 57 + .../ffmpeg-4.2-fit/libavcodec/kbdwin.h | 38 + .../ffmpeg-4.2-fit/libavcodec/latm_parser.c | 112 + .../ffmpeg-4.2-fit/libavcodec/libopus.c | 48 + .../ffmpeg-4.2-fit/libavcodec/libopus.h | 27 + .../ffmpeg-4.2-fit/libavcodec/libopusdec.c | 245 + .../ffmpeg-4.2-fit/libavcodec/libopusenc.c | 594 ++ .../3rdparty/ffmpeg-4.2-fit/libavcodec/lpc.c | 325 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/lpc.h | 212 + .../ffmpeg-4.2-fit/libavcodec/mathops.h | 251 + .../ffmpeg-4.2-fit/libavcodec/mathtables.c | 114 + .../ffmpeg-4.2-fit/libavcodec/mdct15.asm | 221 + .../ffmpeg-4.2-fit/libavcodec/mdct15.c | 329 + .../ffmpeg-4.2-fit/libavcodec/mdct15.h | 62 + .../ffmpeg-4.2-fit/libavcodec/mdct15_init.c | 99 + .../ffmpeg-4.2-fit/libavcodec/mdct_fixed.c | 65 + .../ffmpeg-4.2-fit/libavcodec/mdct_fixed_32.c | 52 + .../ffmpeg-4.2-fit/libavcodec/mdct_float.c | 21 + .../ffmpeg-4.2-fit/libavcodec/mdct_template.c | 213 + .../ffmpeg-4.2-fit/libavcodec/me_cmp.c | 1098 +++ .../ffmpeg-4.2-fit/libavcodec/me_cmp.h | 95 + .../ffmpeg-4.2-fit/libavcodec/mediacodec.c | 149 + .../ffmpeg-4.2-fit/libavcodec/mediacodec.h | 101 + .../libavcodec/mediacodec_surface.h | 31 + .../libavcodec/mediacodec_sw_buffer.h | 62 + .../libavcodec/mediacodec_wrapper.h | 131 + .../libavcodec/mediacodecdec_common.h | 109 + .../ffmpeg-4.2-fit/libavcodec/mjpegenc.h | 111 + .../libavcodec/mjpegenc_common.h | 46 + .../libavcodec/mjpegenc_huffman.c | 192 + .../libavcodec/mjpegenc_huffman.h | 76 + .../ffmpeg-4.2-fit/libavcodec/motion_est.c | 1741 ++++ .../ffmpeg-4.2-fit/libavcodec/motion_est.h | 135 + .../ffmpeg-4.2-fit/libavcodec/mpeg12.c | 332 + .../ffmpeg-4.2-fit/libavcodec/mpeg12.h | 80 + .../ffmpeg-4.2-fit/libavcodec/mpeg12data.c | 412 + .../ffmpeg-4.2-fit/libavcodec/mpeg12data.h | 57 + .../libavcodec/mpeg12framerate.c | 103 + .../ffmpeg-4.2-fit/libavcodec/mpeg12vlc.h | 52 + .../ffmpeg-4.2-fit/libavcodec/mpeg4audio.c | 169 + .../ffmpeg-4.2-fit/libavcodec/mpeg4audio.h | 162 + .../ffmpeg-4.2-fit/libavcodec/mpegpicture.c | 483 ++ .../ffmpeg-4.2-fit/libavcodec/mpegpicture.h | 114 + .../ffmpeg-4.2-fit/libavcodec/mpegutils.c | 393 + .../ffmpeg-4.2-fit/libavcodec/mpegutils.h | 148 + .../ffmpeg-4.2-fit/libavcodec/mpegvideo.c | 2356 ++++++ .../ffmpeg-4.2-fit/libavcodec/mpegvideo.h | 770 ++ .../ffmpeg-4.2-fit/libavcodec/mpegvideodata.c | 109 + .../ffmpeg-4.2-fit/libavcodec/mpegvideodata.h | 35 + .../ffmpeg-4.2-fit/libavcodec/mpegvideodsp.c | 119 + .../ffmpeg-4.2-fit/libavcodec/mpegvideodsp.h | 47 + .../libavcodec/mpegvideoencdsp.c | 256 + .../libavcodec/mpegvideoencdsp.h | 58 + .../ffmpeg-4.2-fit/libavcodec/null_bsf.c | 35 + .../ffmpeg-4.2-fit/libavcodec/options.c | 349 + .../ffmpeg-4.2-fit/libavcodec/options_table.h | 495 ++ .../3rdparty/ffmpeg-4.2-fit/libavcodec/opus.c | 900 ++ .../3rdparty/ffmpeg-4.2-fit/libavcodec/opus.h | 200 + .../ffmpeg-4.2-fit/libavcodec/opus_celt.c | 576 ++ .../ffmpeg-4.2-fit/libavcodec/opus_celt.h | 171 + .../ffmpeg-4.2-fit/libavcodec/opus_pvq.c | 917 ++ .../ffmpeg-4.2-fit/libavcodec/opus_pvq.h | 48 + .../ffmpeg-4.2-fit/libavcodec/opus_rc.c | 411 + .../ffmpeg-4.2-fit/libavcodec/opus_rc.h | 126 + .../ffmpeg-4.2-fit/libavcodec/opusdsp.c | 67 + .../ffmpeg-4.2-fit/libavcodec/opusdsp.h | 36 + .../ffmpeg-4.2-fit/libavcodec/opusenc.c | 738 ++ .../ffmpeg-4.2-fit/libavcodec/opusenc.h | 54 + .../ffmpeg-4.2-fit/libavcodec/opusenc_psy.c | 612 ++ .../ffmpeg-4.2-fit/libavcodec/opusenc_psy.h | 104 + .../ffmpeg-4.2-fit/libavcodec/opusenc_utils.h | 87 + .../ffmpeg-4.2-fit/libavcodec/opustab.c | 1158 +++ .../ffmpeg-4.2-fit/libavcodec/opustab.h | 161 + .../ffmpeg-4.2-fit/libavcodec/parser.c | 334 + .../ffmpeg-4.2-fit/libavcodec/parser.h | 60 + .../ffmpeg-4.2-fit/libavcodec/parser_list.c | 3 + .../ffmpeg-4.2-fit/libavcodec/parsers.c | 110 + .../ffmpeg-4.2-fit/libavcodec/pixblockdsp.h | 55 + .../ffmpeg-4.2-fit/libavcodec/profiles.c | 179 + .../ffmpeg-4.2-fit/libavcodec/profiles.h | 40 + .../ffmpeg-4.2-fit/libavcodec/psymodel.c | 161 + .../ffmpeg-4.2-fit/libavcodec/psymodel.h | 204 + .../ffmpeg-4.2-fit/libavcodec/pthread.c | 88 + .../ffmpeg-4.2-fit/libavcodec/pthread_frame.c | 1013 +++ .../libavcodec/pthread_internal.h | 34 + .../ffmpeg-4.2-fit/libavcodec/pthread_slice.c | 242 + .../ffmpeg-4.2-fit/libavcodec/put_bits.h | 365 + .../ffmpeg-4.2-fit/libavcodec/qpeldsp.c | 816 ++ .../ffmpeg-4.2-fit/libavcodec/qpeldsp.h | 83 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/qsv.h | 107 + .../ffmpeg-4.2-fit/libavcodec/qsv_api.c | 42 + .../ffmpeg-4.2-fit/libavcodec/ratecontrol.c | 1028 +++ .../ffmpeg-4.2-fit/libavcodec/ratecontrol.h | 99 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/raw.c | 338 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/raw.h | 48 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/rdft.h | 52 + trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rl.c | 147 + trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rl.h | 87 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/rle.h | 51 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/sbr.h | 217 + .../ffmpeg-4.2-fit/libavcodec/sbrdsp.asm | 548 ++ .../ffmpeg-4.2-fit/libavcodec/sbrdsp.c | 225 + .../ffmpeg-4.2-fit/libavcodec/sbrdsp.h | 55 + .../ffmpeg-4.2-fit/libavcodec/sbrdsp_fixed.c | 315 + .../ffmpeg-4.2-fit/libavcodec/sbrdsp_init.c | 87 + .../libavcodec/sbrdsp_template.c | 104 + .../ffmpeg-4.2-fit/libavcodec/sinewin.c | 21 + .../ffmpeg-4.2-fit/libavcodec/sinewin.h | 70 + .../ffmpeg-4.2-fit/libavcodec/sinewin_fixed.c | 21 + .../libavcodec/sinewin_tablegen.c | 24 + .../libavcodec/sinewin_tablegen.h | 83 + .../ffmpeg-4.2-fit/libavcodec/thread.h | 144 + .../ffmpeg-4.2-fit/libavcodec/utils.c | 2234 +++++ .../ffmpeg-4.2-fit/libavcodec/vaapi.h | 86 + .../ffmpeg-4.2-fit/libavcodec/vdpau.h | 176 + .../ffmpeg-4.2-fit/libavcodec/version.h | 140 + .../ffmpeg-4.2-fit/libavcodec/videodsp.c | 57 + .../ffmpeg-4.2-fit/libavcodec/videodsp.h | 88 + .../ffmpeg-4.2-fit/libavcodec/videotoolbox.h | 127 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/vlc.h | 81 + .../ffmpeg-4.2-fit/libavcodec/vorbis.c | 218 + .../ffmpeg-4.2-fit/libavcodec/vorbis.h | 50 + .../ffmpeg-4.2-fit/libavcodec/vorbis_data.c | 2193 +++++ .../libavcodec/vorbis_enc_data.h | 504 ++ .../ffmpeg-4.2-fit/libavcodec/vorbis_parser.c | 341 + .../ffmpeg-4.2-fit/libavcodec/vorbis_parser.h | 74 + .../libavcodec/vorbis_parser_internal.h | 46 + .../ffmpeg-4.2-fit/libavcodec/vorbisdsp.h | 38 + .../libavcodec/x86/aacencdsp_init.c | 43 + .../libavcodec/x86/aacpsdsp_init.c | 72 + .../libavcodec/x86/ac3dsp_init.c | 164 + .../libavcodec/x86/alacdsp_init.c | 44 + .../libavcodec/x86/audiodsp_init.c | 66 + .../libavcodec/x86/blockdsp_init.c | 60 + .../libavcodec/x86/bswapdsp_init.c | 40 + .../ffmpeg-4.2-fit/libavcodec/x86/cabac.h | 301 + .../ffmpeg-4.2-fit/libavcodec/x86/cavsdsp.c | 463 + .../libavcodec/x86/celt_pvq_init.c | 43 + .../ffmpeg-4.2-fit/libavcodec/x86/constants.c | 94 + .../ffmpeg-4.2-fit/libavcodec/x86/constants.h | 72 + .../libavcodec/x86/dcadsp_init.c | 52 + .../ffmpeg-4.2-fit/libavcodec/x86/dct_init.c | 41 + .../libavcodec/x86/dirac_dwt_init.c | 229 + .../libavcodec/x86/diracdsp_init.c | 195 + .../libavcodec/x86/dnxhdenc_init.c | 37 + .../libavcodec/x86/exrdsp_init.c | 52 + .../ffmpeg-4.2-fit/libavcodec/x86/fdct.c | 594 ++ .../ffmpeg-4.2-fit/libavcodec/x86/fdct.h | 28 + .../libavcodec/x86/fdctdsp_init.c | 44 + .../ffmpeg-4.2-fit/libavcodec/x86/fft.h | 38 + .../ffmpeg-4.2-fit/libavcodec/x86/fft_init.c | 61 + .../libavcodec/x86/flacdsp_init.c | 115 + .../libavcodec/x86/fmtconvert_init.c | 55 + .../ffmpeg-4.2-fit/libavcodec/x86/fpel.h | 49 + .../libavcodec/x86/g722dsp_init.c | 35 + .../libavcodec/x86/h263dsp_init.c | 39 + .../libavcodec/x86/h264_cabac.c | 208 + .../libavcodec/x86/h264_intrapred_init.c | 410 + .../ffmpeg-4.2-fit/libavcodec/x86/h264_qpel.c | 634 ++ .../libavcodec/x86/h264chroma_init.c | 117 + .../libavcodec/x86/h264dsp_init.c | 448 + .../ffmpeg-4.2-fit/libavcodec/x86/hevcdsp.h | 259 + .../libavcodec/x86/hevcdsp_init.c | 1151 +++ .../ffmpeg-4.2-fit/libavcodec/x86/hpeldsp.h | 57 + .../libavcodec/x86/hpeldsp_init.c | 313 + .../libavcodec/x86/hpeldsp_rnd_template.c | 202 + .../libavcodec/x86/hpeldsp_vp3_init.c | 56 + .../libavcodec/x86/huffyuvdsp_init.c | 61 + .../libavcodec/x86/huffyuvencdsp_init.c | 60 + .../ffmpeg-4.2-fit/libavcodec/x86/idctdsp.h | 39 + .../libavcodec/x86/idctdsp_init.c | 162 + .../libavcodec/x86/inline_asm.h | 100 + .../libavcodec/x86/jpeg2000dsp_init.c | 60 + .../libavcodec/x86/lossless_audiodsp_init.c | 56 + .../libavcodec/x86/lossless_videodsp_init.c | 128 + .../x86/lossless_videoencdsp_init.c | 111 + .../ffmpeg-4.2-fit/libavcodec/x86/lpc.c | 162 + .../ffmpeg-4.2-fit/libavcodec/x86/mathops.h | 133 + .../libavcodec/x86/mdct15_init.c | 99 + .../libavcodec/x86/me_cmp_init.c | 651 ++ .../libavcodec/x86/mlpdsp_init.c | 204 + .../libavcodec/x86/mpegaudiodsp.c | 289 + .../ffmpeg-4.2-fit/libavcodec/x86/mpegvideo.c | 469 + .../libavcodec/x86/mpegvideodsp.c | 161 + .../libavcodec/x86/mpegvideoenc.c | 244 + .../x86/mpegvideoenc_qns_template.c | 109 + .../libavcodec/x86/mpegvideoenc_template.c | 423 + .../libavcodec/x86/mpegvideoencdsp_init.c | 272 + .../libavcodec/x86/opusdsp_init.c | 35 + .../libavcodec/x86/pixblockdsp_init.c | 52 + .../libavcodec/x86/pngdsp_init.c | 50 + .../libavcodec/x86/proresdsp_init.c | 50 + .../libavcodec/x86/qpeldsp_init.c | 544 ++ .../libavcodec/x86/rnd_template.c | 175 + .../libavcodec/x86/rv34dsp_init.c | 48 + .../libavcodec/x86/rv40dsp_init.c | 278 + .../libavcodec/x86/sbcdsp_init.c | 51 + .../libavcodec/x86/sbrdsp_init.c | 87 + .../libavcodec/x86/simple_idct.h | 53 + .../ffmpeg-4.2-fit/libavcodec/x86/snowdsp.c | 908 ++ .../libavcodec/x86/svq1enc_init.c | 42 + .../libavcodec/x86/synth_filter_init.c | 74 + .../libavcodec/x86/takdsp_init.c | 45 + .../libavcodec/x86/ttadsp_init.c | 42 + .../libavcodec/x86/ttaencdsp_init.c | 42 + .../libavcodec/x86/utvideodsp_init.c | 54 + .../ffmpeg-4.2-fit/libavcodec/x86/v210-init.c | 56 + .../libavcodec/x86/v210enc_init.c | 54 + .../ffmpeg-4.2-fit/libavcodec/x86/vc1dsp.h | 29 + .../libavcodec/x86/vc1dsp_init.c | 168 + .../libavcodec/x86/vc1dsp_mmx.c | 486 ++ .../libavcodec/x86/videodsp_init.c | 309 + .../libavcodec/x86/vorbisdsp_init.c | 42 + .../libavcodec/x86/vp3dsp_init.c | 71 + .../libavcodec/x86/vp56_arith.h | 51 + .../libavcodec/x86/vp6dsp_init.c | 45 + .../libavcodec/x86/vp8dsp_init.c | 467 + .../libavcodec/x86/vp9dsp_init.c | 416 + .../libavcodec/x86/vp9dsp_init.h | 189 + .../libavcodec/x86/vp9dsp_init_10bpp.c | 25 + .../libavcodec/x86/vp9dsp_init_12bpp.c | 25 + .../libavcodec/x86/vp9dsp_init_16bpp.c | 149 + .../x86/vp9dsp_init_16bpp_template.c | 240 + .../ffmpeg-4.2-fit/libavcodec/x86/xvididct.h | 44 + .../libavcodec/x86/xvididct_init.c | 89 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/xiph.c | 63 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/xiph.h | 43 + .../3rdparty/ffmpeg-4.2-fit/libavcodec/xvmc.h | 170 + .../ffmpeg-4.2-fit/libavdevice/alldevices.c | 68 + .../ffmpeg-4.2-fit/libavdevice/indev_list.c | 2 + .../ffmpeg-4.2-fit/libavdevice/outdev_list.c | 2 + .../ffmpeg-4.2-fit/libavfilter/allfilters.c | 536 ++ .../ffmpeg-4.2-fit/libavfilter/avfilter.h | 1168 +++ .../ffmpeg-4.2-fit/libavfilter/bufferqueue.h | 121 + .../ffmpeg-4.2-fit/libavfilter/filter_list.c | 6 + .../ffmpeg-4.2-fit/libavfilter/version.h | 66 + .../ffmpeg-4.2-fit/libavfilter/window_func.h | 199 + .../ffmpeg-4.2-fit/libavformat/allformats.c | 641 ++ .../ffmpeg-4.2-fit/libavformat/demuxer_list.c | 2 + .../ffmpeg-4.2-fit/libavformat/muxer_list.c | 2 + .../libavformat/protocol_list.c | 2 + .../ffmpeg-4.2-fit/libavformat/protocols.c | 131 + .../ffmpeg-4.2-fit/libavutil/Makefile | 250 + .../ffmpeg-4.2-fit/libavutil/aarch64/bswap.h | 50 + .../ffmpeg-4.2-fit/libavutil/aarch64/cpu.c | 38 + .../ffmpeg-4.2-fit/libavutil/aarch64/cpu.h | 29 + .../libavutil/aarch64/float_dsp_init.c | 69 + .../libavutil/aarch64/neontest.h | 70 + .../ffmpeg-4.2-fit/libavutil/aarch64/timer.h | 44 + .../ffmpeg-4.2-fit/libavutil/adler32.c | 97 + .../ffmpeg-4.2-fit/libavutil/adler32.h | 60 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes.c | 268 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes.h | 65 + .../ffmpeg-4.2-fit/libavutil/aes_ctr.c | 135 + .../ffmpeg-4.2-fit/libavutil/aes_ctr.h | 88 + .../ffmpeg-4.2-fit/libavutil/aes_internal.h | 43 + .../ffmpeg-4.2-fit/libavutil/arm/bswap.h | 67 + .../ffmpeg-4.2-fit/libavutil/arm/cpu.c | 170 + .../ffmpeg-4.2-fit/libavutil/arm/cpu.h | 38 + .../libavutil/arm/float_dsp_arm.h | 29 + .../libavutil/arm/float_dsp_init_arm.c | 32 + .../libavutil/arm/float_dsp_init_neon.c | 59 + .../libavutil/arm/float_dsp_init_vfp.c | 46 + .../ffmpeg-4.2-fit/libavutil/arm/intmath.h | 134 + .../libavutil/arm/intreadwrite.h | 91 + .../ffmpeg-4.2-fit/libavutil/arm/neontest.h | 67 + .../ffmpeg-4.2-fit/libavutil/arm/timer.h | 40 + .../ffmpeg-4.2-fit/libavutil/attributes.h | 167 + .../ffmpeg-4.2-fit/libavutil/audio_fifo.c | 236 + .../ffmpeg-4.2-fit/libavutil/audio_fifo.h | 187 + .../ffmpeg-4.2-fit/libavutil/avassert.h | 75 + .../ffmpeg-4.2-fit/libavutil/avconfig.h | 6 + .../ffmpeg-4.2-fit/libavutil/avsscanf.c | 970 +++ .../ffmpeg-4.2-fit/libavutil/avstring.c | 461 + .../ffmpeg-4.2-fit/libavutil/avstring.h | 413 + .../ffmpeg-4.2-fit/libavutil/avutil.h | 365 + .../ffmpeg-4.2-fit/libavutil/avutilres.rc | 55 + .../ffmpeg-4.2-fit/libavutil/base64.c | 174 + .../ffmpeg-4.2-fit/libavutil/base64.h | 72 + .../ffmpeg-4.2-fit/libavutil/blowfish.c | 424 + .../ffmpeg-4.2-fit/libavutil/blowfish.h | 82 + .../ffmpeg-4.2-fit/libavutil/bprint.c | 305 + .../ffmpeg-4.2-fit/libavutil/bprint.h | 219 + .../3rdparty/ffmpeg-4.2-fit/libavutil/bswap.h | 109 + .../ffmpeg-4.2-fit/libavutil/buffer.c | 357 + .../ffmpeg-4.2-fit/libavutil/buffer.h | 291 + .../libavutil/buffer_internal.h | 98 + .../ffmpeg-4.2-fit/libavutil/camellia.c | 412 + .../ffmpeg-4.2-fit/libavutil/camellia.h | 70 + .../3rdparty/ffmpeg-4.2-fit/libavutil/cast5.c | 507 ++ .../3rdparty/ffmpeg-4.2-fit/libavutil/cast5.h | 80 + .../ffmpeg-4.2-fit/libavutil/channel_layout.c | 287 + .../ffmpeg-4.2-fit/libavutil/channel_layout.h | 232 + .../ffmpeg-4.2-fit/libavutil/color_utils.c | 235 + .../ffmpeg-4.2-fit/libavutil/color_utils.h | 56 + .../ffmpeg-4.2-fit/libavutil/colorspace.h | 150 + .../ffmpeg-4.2-fit/libavutil/common.h | 560 ++ trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu.c | 321 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu.h | 130 + .../ffmpeg-4.2-fit/libavutil/cpu_internal.h | 54 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/crc.c | 415 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/crc.h | 100 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/des.c | 331 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/des.h | 77 + .../3rdparty/ffmpeg-4.2-fit/libavutil/dict.c | 272 + .../3rdparty/ffmpeg-4.2-fit/libavutil/dict.h | 200 + .../ffmpeg-4.2-fit/libavutil/display.c | 73 + .../ffmpeg-4.2-fit/libavutil/display.h | 114 + .../ffmpeg-4.2-fit/libavutil/downmix_info.c | 38 + .../ffmpeg-4.2-fit/libavutil/downmix_info.h | 115 + .../ffmpeg-4.2-fit/libavutil/dynarray.h | 70 + .../libavutil/encryption_info.c | 339 + .../libavutil/encryption_info.h | 205 + .../3rdparty/ffmpeg-4.2-fit/libavutil/error.c | 129 + .../3rdparty/ffmpeg-4.2-fit/libavutil/error.h | 126 + .../3rdparty/ffmpeg-4.2-fit/libavutil/eval.c | 760 ++ .../3rdparty/ffmpeg-4.2-fit/libavutil/eval.h | 113 + .../ffmpeg-4.2-fit/libavutil/ffmath.h | 67 + .../ffmpeg-4.2-fit/libavutil/ffversion.h | 5 + .../3rdparty/ffmpeg-4.2-fit/libavutil/fifo.c | 240 + .../3rdparty/ffmpeg-4.2-fit/libavutil/fifo.h | 179 + .../3rdparty/ffmpeg-4.2-fit/libavutil/file.c | 154 + .../3rdparty/ffmpeg-4.2-fit/libavutil/file.h | 71 + .../ffmpeg-4.2-fit/libavutil/file_open.c | 190 + .../ffmpeg-4.2-fit/libavutil/fixed_dsp.c | 167 + .../ffmpeg-4.2-fit/libavutil/fixed_dsp.h | 205 + .../ffmpeg-4.2-fit/libavutil/float_dsp.c | 164 + .../ffmpeg-4.2-fit/libavutil/float_dsp.h | 218 + .../3rdparty/ffmpeg-4.2-fit/libavutil/frame.c | 947 +++ .../3rdparty/ffmpeg-4.2-fit/libavutil/frame.h | 971 +++ .../3rdparty/ffmpeg-4.2-fit/libavutil/hash.c | 243 + .../3rdparty/ffmpeg-4.2-fit/libavutil/hash.h | 269 + .../libavutil/hdr_dynamic_metadata.c | 47 + .../libavutil/hdr_dynamic_metadata.h | 343 + .../3rdparty/ffmpeg-4.2-fit/libavutil/hmac.c | 196 + .../3rdparty/ffmpeg-4.2-fit/libavutil/hmac.h | 100 + .../ffmpeg-4.2-fit/libavutil/hwcontext.c | 879 ++ .../ffmpeg-4.2-fit/libavutil/hwcontext.h | 584 ++ .../ffmpeg-4.2-fit/libavutil/hwcontext_cuda.c | 381 + .../ffmpeg-4.2-fit/libavutil/hwcontext_cuda.h | 52 + .../libavutil/hwcontext_cuda_internal.h | 37 + .../libavutil/hwcontext_d3d11va.c | 615 ++ .../libavutil/hwcontext_d3d11va.h | 169 + .../ffmpeg-4.2-fit/libavutil/hwcontext_drm.c | 289 + .../ffmpeg-4.2-fit/libavutil/hwcontext_drm.h | 169 + .../libavutil/hwcontext_dxva2.c | 594 ++ .../libavutil/hwcontext_dxva2.h | 75 + .../libavutil/hwcontext_internal.h | 176 + .../libavutil/hwcontext_mediacodec.c | 50 + .../libavutil/hwcontext_mediacodec.h | 36 + .../libavutil/hwcontext_opencl.c | 2942 +++++++ .../libavutil/hwcontext_opencl.h | 100 + .../ffmpeg-4.2-fit/libavutil/hwcontext_qsv.c | 1278 +++ .../ffmpeg-4.2-fit/libavutil/hwcontext_qsv.h | 53 + .../libavutil/hwcontext_vaapi.c | 1689 ++++ .../libavutil/hwcontext_vaapi.h | 117 + .../libavutil/hwcontext_vdpau.c | 511 ++ .../libavutil/hwcontext_vdpau.h | 44 + .../libavutil/hwcontext_videotoolbox.c | 246 + .../libavutil/hwcontext_videotoolbox.h | 54 + .../ffmpeg-4.2-fit/libavutil/imgutils.c | 645 ++ .../ffmpeg-4.2-fit/libavutil/imgutils.h | 277 + .../libavutil/imgutils_internal.h | 30 + .../ffmpeg-4.2-fit/libavutil/integer.c | 166 + .../ffmpeg-4.2-fit/libavutil/integer.h | 86 + .../ffmpeg-4.2-fit/libavutil/internal.h | 372 + .../ffmpeg-4.2-fit/libavutil/intfloat.h | 77 + .../ffmpeg-4.2-fit/libavutil/intmath.c | 34 + .../ffmpeg-4.2-fit/libavutil/intmath.h | 165 + .../ffmpeg-4.2-fit/libavutil/intreadwrite.h | 644 ++ trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lfg.c | 87 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lfg.h | 71 + .../3rdparty/ffmpeg-4.2-fit/libavutil/libm.h | 471 ++ trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lls.c | 123 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lls.h | 64 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log.c | 435 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log.h | 362 + .../ffmpeg-4.2-fit/libavutil/log2_tab.c | 32 + .../ffmpeg-4.2-fit/libavutil/macros.h | 50 + .../libavutil/mastering_display_metadata.c | 66 + .../libavutil/mastering_display_metadata.h | 128 + .../ffmpeg-4.2-fit/libavutil/mathematics.c | 211 + .../ffmpeg-4.2-fit/libavutil/mathematics.h | 242 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/md5.c | 218 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/md5.h | 98 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem.c | 508 ++ trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem.h | 700 ++ .../ffmpeg-4.2-fit/libavutil/mem_internal.h | 45 + .../ffmpeg-4.2-fit/libavutil/motion_vector.h | 57 + .../ffmpeg-4.2-fit/libavutil/murmur3.c | 159 + .../ffmpeg-4.2-fit/libavutil/murmur3.h | 120 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/opt.c | 2039 +++++ trunk/3rdparty/ffmpeg-4.2-fit/libavutil/opt.h | 865 ++ .../ffmpeg-4.2-fit/libavutil/parseutils.c | 786 ++ .../ffmpeg-4.2-fit/libavutil/parseutils.h | 193 + .../ffmpeg-4.2-fit/libavutil/pixdesc.c | 2961 +++++++ .../ffmpeg-4.2-fit/libavutil/pixdesc.h | 440 + .../ffmpeg-4.2-fit/libavutil/pixelutils.c | 89 + .../ffmpeg-4.2-fit/libavutil/pixelutils.h | 52 + .../ffmpeg-4.2-fit/libavutil/pixfmt.h | 552 ++ .../3rdparty/ffmpeg-4.2-fit/libavutil/qsort.h | 122 + .../ffmpeg-4.2-fit/libavutil/random_seed.c | 145 + .../ffmpeg-4.2-fit/libavutil/random_seed.h | 43 + .../ffmpeg-4.2-fit/libavutil/rational.c | 184 + .../ffmpeg-4.2-fit/libavutil/rational.h | 214 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rc4.c | 65 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rc4.h | 66 + .../ffmpeg-4.2-fit/libavutil/replaygain.h | 50 + .../ffmpeg-4.2-fit/libavutil/reverse.c | 40 + .../ffmpeg-4.2-fit/libavutil/reverse.h | 28 + .../ffmpeg-4.2-fit/libavutil/ripemd.c | 555 ++ .../ffmpeg-4.2-fit/libavutil/ripemd.h | 87 + .../ffmpeg-4.2-fit/libavutil/samplefmt.c | 254 + .../ffmpeg-4.2-fit/libavutil/samplefmt.h | 272 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha.c | 356 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha.h | 95 + .../ffmpeg-4.2-fit/libavutil/sha512.c | 287 + .../ffmpeg-4.2-fit/libavutil/sha512.h | 97 + .../ffmpeg-4.2-fit/libavutil/slicethread.c | 255 + .../ffmpeg-4.2-fit/libavutil/slicethread.h | 52 + .../ffmpeg-4.2-fit/libavutil/softfloat.h | 289 + .../libavutil/softfloat_ieee754.h | 115 + .../libavutil/softfloat_tables.h | 262 + .../ffmpeg-4.2-fit/libavutil/spherical.c | 79 + .../ffmpeg-4.2-fit/libavutil/spherical.h | 232 + .../ffmpeg-4.2-fit/libavutil/stereo3d.c | 76 + .../ffmpeg-4.2-fit/libavutil/stereo3d.h | 233 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tea.c | 121 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tea.h | 71 + .../ffmpeg-4.2-fit/libavutil/thread.h | 173 + .../ffmpeg-4.2-fit/libavutil/threadmessage.c | 235 + .../ffmpeg-4.2-fit/libavutil/threadmessage.h | 115 + .../3rdparty/ffmpeg-4.2-fit/libavutil/time.c | 98 + .../3rdparty/ffmpeg-4.2-fit/libavutil/time.h | 56 + .../ffmpeg-4.2-fit/libavutil/time_internal.h | 49 + .../ffmpeg-4.2-fit/libavutil/timecode.c | 220 + .../ffmpeg-4.2-fit/libavutil/timecode.h | 140 + .../3rdparty/ffmpeg-4.2-fit/libavutil/timer.h | 141 + .../ffmpeg-4.2-fit/libavutil/timestamp.h | 78 + .../3rdparty/ffmpeg-4.2-fit/libavutil/tree.c | 168 + .../3rdparty/ffmpeg-4.2-fit/libavutil/tree.h | 138 + .../ffmpeg-4.2-fit/libavutil/twofish.c | 331 + .../ffmpeg-4.2-fit/libavutil/twofish.h | 70 + trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tx.c | 803 ++ trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tx.h | 81 + .../3rdparty/ffmpeg-4.2-fit/libavutil/utils.c | 160 + .../ffmpeg-4.2-fit/libavutil/version.h | 139 + .../ffmpeg-4.2-fit/libavutil/x86/asm.h | 154 + .../ffmpeg-4.2-fit/libavutil/x86/bswap.h | 87 + .../ffmpeg-4.2-fit/libavutil/x86/cpu.c | 272 + .../ffmpeg-4.2-fit/libavutil/x86/cpu.h | 113 + .../ffmpeg-4.2-fit/libavutil/x86/emms.h | 55 + .../libavutil/x86/fixed_dsp_init.c | 35 + .../libavutil/x86/float_dsp_init.c | 121 + .../libavutil/x86/imgutils_init.c | 49 + .../ffmpeg-4.2-fit/libavutil/x86/intmath.h | 139 + .../libavutil/x86/intreadwrite.h | 97 + .../ffmpeg-4.2-fit/libavutil/x86/lls_init.c | 45 + .../ffmpeg-4.2-fit/libavutil/x86/pixelutils.h | 26 + .../libavutil/x86/pixelutils_init.c | 94 + .../ffmpeg-4.2-fit/libavutil/x86/timer.h | 50 + .../ffmpeg-4.2-fit/libavutil/x86/w64xmmtest.h | 78 + .../ffmpeg-4.2-fit/libavutil/xga_font_data.c | 417 + .../ffmpeg-4.2-fit/libavutil/xga_font_data.h | 35 + .../3rdparty/ffmpeg-4.2-fit/libavutil/xtea.c | 253 + .../3rdparty/ffmpeg-4.2-fit/libavutil/xtea.h | 94 + .../ffmpeg-4.2-fit/libswresample/Makefile | 23 + .../aarch64/audio_convert_init.c | 67 + .../libswresample/aarch64/resample_init.c | 120 + .../libswresample/arm/audio_convert_init.c | 67 + .../libswresample/arm/resample_init.c | 120 + .../libswresample/audioconvert.c | 247 + .../libswresample/audioconvert.h | 78 + .../ffmpeg-4.2-fit/libswresample/dither.c | 148 + .../libswresample/dither_template.c | 84 + .../libswresample/noise_shaping_data.c | 224 + .../ffmpeg-4.2-fit/libswresample/options.c | 156 + .../ffmpeg-4.2-fit/libswresample/rematrix.c | 576 ++ .../libswresample/rematrix_template.c | 111 + .../ffmpeg-4.2-fit/libswresample/resample.c | 622 ++ .../ffmpeg-4.2-fit/libswresample/resample.h | 68 + .../libswresample/resample_dsp.c | 74 + .../libswresample/resample_template.c | 212 + .../ffmpeg-4.2-fit/libswresample/swresample.c | 949 +++ .../ffmpeg-4.2-fit/libswresample/swresample.h | 579 ++ .../libswresample/swresample_frame.c | 159 + .../libswresample/swresample_internal.h | 222 + .../libswresample/swresampleres.rc | 55 + .../ffmpeg-4.2-fit/libswresample/version.h | 45 + .../libswresample/x86/audio_convert_init.c | 181 + .../libswresample/x86/rematrix_init.c | 90 + .../libswresample/x86/resample_init.c | 100 + trunk/auto/depends.sh | 65 +- 690 files changed, 182077 insertions(+), 1 deletion(-) create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/.gitignore create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/.version create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/compat/atomics/gcc/stdatomic.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/compat/va_copy.h create mode 100755 trunk/3rdparty/ffmpeg-4.2-fit/configure create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/arch.mak create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/common.mak create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/library.mak create mode 100755 trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/libversion.sh create mode 100755 trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/pkgconfig_generate.sh create mode 100755 trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/version.sh create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_ac3_parser.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_ac3_parser.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_adtstoasc_bsf.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_defines.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_parser.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder_trellis.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder_twoloop.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdectab.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_is.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_is.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_ltp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_ltp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_pred.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_pred.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_quantization.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_quantization_misc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_tns.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_tns.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_utils.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacencdsp.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacencdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenctab.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenctab.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed_tablegen.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed_tablegen.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_float.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdata.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_float.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsy.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_fixed_tablegen.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_tablegen.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_tablegen_common.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbrdata.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aactab.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aactab.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/aacpsdsp_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/asm-offsets.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/cabac.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/fft_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/fmtconvert_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264chroma_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264dsp_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264pred_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264qpel_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/hpeldsp_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/idct.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/idctdsp_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/mpegaudiodsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/opusdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/rv40dsp_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/sbrdsp_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/synth_filter_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vc1dsp_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/videodsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vorbisdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp8dsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp8dsp_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_10bpp_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_12bpp_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_16bpp_aarch64_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_aarch64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_data.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_data.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_float.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_float.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_opts_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3tab.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3tab.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_header.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_header.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_parser.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_parser.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/allcodecs.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/audio_frame_queue.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/audio_frame_queue.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avcodec.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avdct.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avdct.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avfft.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avfft.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avpacket.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avpicture.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream_filter.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream_filters.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/blockdsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/blockdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf_list.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bytestream.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_tablegen.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_tablegen.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/codec_desc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/codec_list.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/d3d11va.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/d3d11va.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dct.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/decode.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/decode.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_arith.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_dwt.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_vlc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/diracdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/diractab.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dxva2.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/encode.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/error_resilience.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/error_resilience.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fdctdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft-internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_fixed_32.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_float.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_init_table.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_table.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/frame_thread_encoder.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/frame_thread_encoder.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/get_bits.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/golomb.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/golomb.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h263dsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h263dsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h264chroma.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h264chroma.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hpeldsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hpeldsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hwaccel.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hwaccels.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/idctdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/iirfilter.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/iirfilter.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/imgconvert.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/jni.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/jni.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/kbdwin.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/kbdwin.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/latm_parser.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopus.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopus.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopusdec.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopusenc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/lpc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/lpc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mathops.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mathtables.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct_fixed_32.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct_float.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/me_cmp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/me_cmp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_surface.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_sw_buffer.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_wrapper.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodecdec_common.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_common.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_huffman.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_huffman.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/motion_est.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/motion_est.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12data.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12data.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12framerate.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12vlc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg4audio.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg4audio.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegpicture.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegpicture.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegutils.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegutils.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideo.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideo.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodata.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodata.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideoencdsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideoencdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/null_bsf.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/options.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/options_table.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_celt.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_celt.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_pvq.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_pvq.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_rc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_rc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusdsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_psy.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_psy.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_utils.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opustab.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opustab.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser_list.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parsers.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pixblockdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/profiles.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/profiles.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/psymodel.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/psymodel.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_frame.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_slice.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/put_bits.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qpeldsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qpeldsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qsv.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qsv_api.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ratecontrol.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ratecontrol.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/raw.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/raw.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rdft.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rl.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rl.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rle.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbr.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_fixed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_tablegen.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_tablegen.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/thread.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/utils.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vaapi.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vdpau.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/version.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videodsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videodsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videotoolbox.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vlc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_data.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_enc_data.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbisdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacencdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacpsdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ac3dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/alacdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/audiodsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/blockdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/bswapdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/cabac.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/cavsdsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/celt_pvq_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/constants.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/constants.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dcadsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dct_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dirac_dwt_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/diracdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dnxhdenc_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/exrdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdct.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdct.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdctdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/flacdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fmtconvert_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fpel.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/g722dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h263dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_cabac.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_intrapred_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_qpel.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264chroma_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hevcdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hevcdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_rnd_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_vp3_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/huffyuvdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/huffyuvencdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/idctdsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/idctdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/inline_asm.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/jpeg2000dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_audiodsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_videodsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_videoencdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lpc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mathops.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mdct15_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/me_cmp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mlpdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegaudiodsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideo.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideodsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc_qns_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoencdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/opusdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/pixblockdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/pngdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/proresdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/qpeldsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rnd_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rv34dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rv40dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbcdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbrdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/simple_idct.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/snowdsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/svq1enc_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/synth_filter_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/takdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ttadsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ttaencdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/utvideodsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/v210-init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/v210enc_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp_mmx.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/videodsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vorbisdsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp3dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp56_arith.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp6dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp8dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_10bpp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_12bpp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_16bpp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_16bpp_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/xvididct.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/xvididct_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xiph.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xiph.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xvmc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/alldevices.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/indev_list.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/outdev_list.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/allfilters.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/avfilter.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/bufferqueue.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/filter_list.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/version.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/window_func.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavformat/allformats.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavformat/demuxer_list.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavformat/muxer_list.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavformat/protocol_list.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavformat/protocols.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/bswap.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/cpu.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/cpu.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/float_dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/neontest.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/timer.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/adler32.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/adler32.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_ctr.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_ctr.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/bswap.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/cpu.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/cpu.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_arm.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_arm.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_neon.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_vfp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/intmath.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/intreadwrite.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/neontest.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/timer.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/attributes.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/audio_fifo.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/audio_fifo.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avassert.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avconfig.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avsscanf.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avstring.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avstring.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avutil.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avutilres.rc create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/base64.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/base64.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/blowfish.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/blowfish.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bprint.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bprint.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bswap.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/camellia.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/camellia.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cast5.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cast5.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/channel_layout.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/channel_layout.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/color_utils.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/color_utils.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/colorspace.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/common.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/crc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/crc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/des.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/des.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dict.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dict.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/display.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/display.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/downmix_info.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/downmix_info.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dynarray.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/encryption_info.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/encryption_info.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/error.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/error.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/eval.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/eval.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffmath.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffversion.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fifo.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fifo.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file_open.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fixed_dsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fixed_dsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/float_dsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/float_dsp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/frame.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/frame.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hash.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hash.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hdr_dynamic_metadata.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hdr_dynamic_metadata.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hmac.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hmac.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_d3d11va.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_d3d11va.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_drm.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_drm.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_dxva2.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_dxva2.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_mediacodec.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_mediacodec.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_opencl.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_opencl.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_qsv.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_qsv.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vaapi.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vaapi.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vdpau.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vdpau.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_videotoolbox.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_videotoolbox.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/integer.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/integer.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intfloat.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intmath.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intmath.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intreadwrite.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lfg.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lfg.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/libm.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lls.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lls.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log2_tab.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/macros.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mastering_display_metadata.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mastering_display_metadata.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mathematics.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mathematics.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/md5.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/md5.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/motion_vector.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/murmur3.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/murmur3.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/opt.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/opt.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/parseutils.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/parseutils.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixdesc.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixdesc.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixelutils.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixelutils.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixfmt.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/qsort.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/random_seed.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/random_seed.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rational.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rational.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rc4.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rc4.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/replaygain.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/reverse.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/reverse.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ripemd.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ripemd.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/samplefmt.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/samplefmt.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha512.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha512.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/slicethread.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/slicethread.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat_ieee754.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat_tables.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/spherical.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/spherical.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/stereo3d.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/stereo3d.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tea.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tea.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/thread.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/threadmessage.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/threadmessage.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timecode.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timecode.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timer.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timestamp.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tree.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tree.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/twofish.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/twofish.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tx.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tx.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/utils.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/version.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/asm.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/bswap.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpu.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpu.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/emms.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/fixed_dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/float_dsp_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/imgutils_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/intmath.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/intreadwrite.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/lls_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/pixelutils.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/pixelutils_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/timer.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/w64xmmtest.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xga_font_data.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xga_font_data.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xtea.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xtea.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/audio_convert_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/resample_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/audio_convert_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/resample_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/audioconvert.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/audioconvert.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/dither.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/dither_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/noise_shaping_data.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/options.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/rematrix.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/rematrix_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample_dsp.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample_template.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample_frame.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample_internal.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresampleres.rc create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/version.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/audio_convert_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/rematrix_init.c create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/resample_init.c diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/.gitignore b/trunk/3rdparty/ffmpeg-4.2-fit/.gitignore new file mode 100644 index 0000000000..c348b5e28b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/.gitignore @@ -0,0 +1,17 @@ +# Ignore files. +*.d +*.pc +*.o +config.asm +config.h +_release +doc +ffbuild/config.fate +ffbuild/config.log +ffbuild/config.mak +ffbuild/config.sh +ffbuild/.config +libavutil/lib.version +libavcodec/libavcodec.version +libavutil/libavutil.version +libswresample/libswresample.version \ No newline at end of file diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/.version b/trunk/3rdparty/ffmpeg-4.2-fit/.version new file mode 100644 index 0000000000..e69de29bb2 diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/Makefile new file mode 100644 index 0000000000..8bf04c169d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/Makefile @@ -0,0 +1,169 @@ +MAIN_MAKEFILE=1 +include ffbuild/config.mak + +vpath %.c $(SRC_PATH) +vpath %.cpp $(SRC_PATH) +vpath %.h $(SRC_PATH) +vpath %.inc $(SRC_PATH) +vpath %.m $(SRC_PATH) +vpath %.S $(SRC_PATH) +vpath %.asm $(SRC_PATH) +vpath %.rc $(SRC_PATH) +vpath %.v $(SRC_PATH) +vpath %.texi $(SRC_PATH) +vpath %.cu $(SRC_PATH) +vpath %.ptx $(SRC_PATH) +vpath %/fate_config.sh.template $(SRC_PATH) + +TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64 audiomatch +HOSTPROGS := $(TESTTOOLS:%=tests/%) doc/print_options + +# $(FFLIBS-yes) needs to be in linking order +FFLIBS-$(CONFIG_AVDEVICE) += avdevice +FFLIBS-$(CONFIG_AVFILTER) += avfilter +FFLIBS-$(CONFIG_AVFORMAT) += avformat +FFLIBS-$(CONFIG_AVCODEC) += avcodec +FFLIBS-$(CONFIG_AVRESAMPLE) += avresample +FFLIBS-$(CONFIG_POSTPROC) += postproc +FFLIBS-$(CONFIG_SWRESAMPLE) += swresample +FFLIBS-$(CONFIG_SWSCALE) += swscale + +FFLIBS := avutil + +DATA_FILES := $(wildcard $(SRC_PATH)/presets/*.ffpreset) $(SRC_PATH)/doc/ffprobe.xsd + +SKIPHEADERS = compat/w32pthreads.h + +# first so "all" becomes default target +all: all-yes + +include $(SRC_PATH)/ffbuild/common.mak + +FF_EXTRALIBS := $(FFEXTRALIBS) +FF_DEP_LIBS := $(DEP_LIBS) +FF_STATIC_DEP_LIBS := $(STATIC_DEP_LIBS) + +$(TOOLS): %$(EXESUF): %.o + $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(EXTRALIBS-$(*F)) $(EXTRALIBS) $(ELIBS) + +target_dec_%_fuzzer$(EXESUF): target_dec_%_fuzzer.o $(FF_DEP_LIBS) + $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + +tools/target_dem_fuzzer$(EXESUF): tools/target_dem_fuzzer.o $(FF_DEP_LIBS) + $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + +tools/sofa2wavs$(EXESUF): ELIBS = $(FF_EXTRALIBS) +tools/uncoded_frame$(EXESUF): $(FF_DEP_LIBS) +tools/uncoded_frame$(EXESUF): ELIBS = $(FF_EXTRALIBS) +tools/target_dec_%_fuzzer$(EXESUF): $(FF_DEP_LIBS) + +CONFIGURABLE_COMPONENTS = \ + $(wildcard $(FFLIBS:%=$(SRC_PATH)/lib%/all*.c)) \ + $(SRC_PATH)/libavcodec/bitstream_filters.c \ + $(SRC_PATH)/libavcodec/parsers.c \ + $(SRC_PATH)/libavformat/protocols.c \ + +config.h: ffbuild/.config +ffbuild/.config: $(CONFIGURABLE_COMPONENTS) + @-tput bold 2>/dev/null + @-printf '\nWARNING: $(?) newer than config.h, rerun configure\n\n' + @-tput sgr0 2>/dev/null + +SUBDIR_VARS := CLEANFILES FFLIBS HOSTPROGS TESTPROGS TOOLS \ + HEADERS ARCH_HEADERS BUILT_HEADERS SKIPHEADERS \ + ARMV5TE-OBJS ARMV6-OBJS ARMV8-OBJS VFP-OBJS NEON-OBJS \ + ALTIVEC-OBJS VSX-OBJS MMX-OBJS X86ASM-OBJS \ + MIPSFPU-OBJS MIPSDSPR2-OBJS MIPSDSP-OBJS MSA-OBJS \ + MMI-OBJS OBJS SLIBOBJS HOSTOBJS TESTOBJS + +define RESET +$(1) := +$(1)-yes := +endef + +define DOSUBDIR +$(foreach V,$(SUBDIR_VARS),$(eval $(call RESET,$(V)))) +SUBDIR := $(1)/ +include $(SRC_PATH)/$(1)/Makefile +-include $(SRC_PATH)/$(1)/$(ARCH)/Makefile +-include $(SRC_PATH)/$(1)/$(INTRINSICS)/Makefile +include $(SRC_PATH)/ffbuild/library.mak +endef + +$(foreach D,$(FFLIBS),$(eval $(call DOSUBDIR,lib$(D)))) + +libavcodec/utils.o libavformat/utils.o libavdevice/avdevice.o libavfilter/avfilter.o libavutil/utils.o libpostproc/postprocess.o libswresample/swresample.o libswscale/utils.o : libavutil/ffversion.h + +$(PROGS): %$(PROGSSUF)$(EXESUF): %$(PROGSSUF)_g$(EXESUF) +ifeq ($(STRIPTYPE),direct) + $(STRIP) -o $@ $< +else + $(CP) $< $@ + $(STRIP) $@ +endif + +%$(PROGSSUF)_g$(EXESUF): $(FF_DEP_LIBS) + $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(OBJS-$*) $(FF_EXTRALIBS) + +VERSION_SH = $(SRC_PATH)/ffbuild/version.sh +GIT_LOG = $(SRC_PATH)/.git/logs/HEAD + +.version: $(wildcard $(GIT_LOG)) $(VERSION_SH) ffbuild/config.mak +.version: M=@ + +libavutil/ffversion.h .version: + $(M)$(VERSION_SH) $(SRC_PATH) libavutil/ffversion.h $(EXTRA_VERSION) + $(Q)touch .version + +# force version.sh to run whenever version might have changed +-include .version + +install: install-libs install-headers + +install-libs: install-libs-yes + +install-data: $(DATA_FILES) + $(Q)mkdir -p "$(DATADIR)" + $(INSTALL) -m 644 $(DATA_FILES) "$(DATADIR)" + +uninstall: uninstall-data uninstall-headers uninstall-libs uninstall-pkgconfig + +uninstall-data: + $(RM) -r "$(DATADIR)" + +clean:: + $(RM) $(CLEANSUFFIXES) + $(RM) $(addprefix compat/,$(CLEANSUFFIXES)) $(addprefix compat/*/,$(CLEANSUFFIXES)) $(addprefix compat/*/*/,$(CLEANSUFFIXES)) + $(RM) -r coverage-html + $(RM) -rf coverage.info coverage.info.in lcov + +distclean:: clean + $(RM) .version avversion.h config.asm config.h mapfile \ + ffbuild/.config ffbuild/config.* libavutil/avconfig.h \ + version.h libavutil/ffversion.h libavcodec/codec_names.h \ + libavcodec/bsf_list.c libavformat/protocol_list.c \ + libavcodec/codec_list.c libavcodec/parser_list.c \ + libavformat/muxer_list.c libavformat/demuxer_list.c +ifeq ($(SRC_LINK),src) + $(RM) src +endif + +config: + $(SRC_PATH)/configure $(value FFMPEG_CONFIGURATION) + +build: all alltools testprogs +check: all alltools testprogs fate + +$(sort $(OUTDIRS)): + $(Q)mkdir -p $@ + +# Dummy rule to stop make trying to rebuild removed or renamed headers +%.h: + @: + +# Disable suffix rules. Most of the builtin rules are suffix rules, +# so this saves some time on slow systems. +.SUFFIXES: + +.PHONY: all all-yes alltools build check config testprogs +.PHONY: *clean install* uninstall* diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/compat/atomics/gcc/stdatomic.h b/trunk/3rdparty/ffmpeg-4.2-fit/compat/atomics/gcc/stdatomic.h new file mode 100644 index 0000000000..e13ed0e068 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/compat/atomics/gcc/stdatomic.h @@ -0,0 +1,173 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * based on vlc_atomic.h from VLC + * Copyright (C) 2010 R茅mi Denis-Courmont + */ + +#ifndef COMPAT_ATOMICS_GCC_STDATOMIC_H +#define COMPAT_ATOMICS_GCC_STDATOMIC_H + +#include +#include + +#define ATOMIC_FLAG_INIT 0 + +#define ATOMIC_VAR_INIT(value) (value) + +#define atomic_init(obj, value) \ +do { \ + *(obj) = (value); \ +} while(0) + +#define kill_dependency(y) ((void)0) + +#define atomic_thread_fence(order) \ + __sync_synchronize() + +#define atomic_signal_fence(order) \ + ((void)0) + +#define atomic_is_lock_free(obj) 0 + +typedef _Bool atomic_flag; +typedef _Bool atomic_bool; +typedef char atomic_char; +typedef signed char atomic_schar; +typedef unsigned char atomic_uchar; +typedef short atomic_short; +typedef unsigned short atomic_ushort; +typedef int atomic_int; +typedef unsigned int atomic_uint; +typedef long atomic_long; +typedef unsigned long atomic_ulong; +typedef long long atomic_llong; +typedef unsigned long long atomic_ullong; +typedef wchar_t atomic_wchar_t; +typedef int_least8_t atomic_int_least8_t; +typedef uint_least8_t atomic_uint_least8_t; +typedef int_least16_t atomic_int_least16_t; +typedef uint_least16_t atomic_uint_least16_t; +typedef int_least32_t atomic_int_least32_t; +typedef uint_least32_t atomic_uint_least32_t; +typedef int_least64_t atomic_int_least64_t; +typedef uint_least64_t atomic_uint_least64_t; +typedef int_fast8_t atomic_int_fast8_t; +typedef uint_fast8_t atomic_uint_fast8_t; +typedef int_fast16_t atomic_int_fast16_t; +typedef uint_fast16_t atomic_uint_fast16_t; +typedef int_fast32_t atomic_int_fast32_t; +typedef uint_fast32_t atomic_uint_fast32_t; +typedef int_fast64_t atomic_int_fast64_t; +typedef uint_fast64_t atomic_uint_fast64_t; +typedef intptr_t atomic_intptr_t; +typedef uintptr_t atomic_uintptr_t; +typedef size_t atomic_size_t; +typedef ptrdiff_t atomic_ptrdiff_t; +typedef intmax_t atomic_intmax_t; +typedef uintmax_t atomic_uintmax_t; + +#define atomic_store(object, desired) \ +do { \ + *(object) = (desired); \ + __sync_synchronize(); \ +} while (0) + +#define atomic_store_explicit(object, desired, order) \ + atomic_store(object, desired) + +#define atomic_load(object) \ + (__sync_synchronize(), *(object)) + +#define atomic_load_explicit(object, order) \ + atomic_load(object) + +#define atomic_exchange(object, desired) \ +({ \ + __typeof__(object) _obj = (object); \ + __typeof__(*object) _old; \ + do \ + _old = atomic_load(_obj); \ + while (!__sync_bool_compare_and_swap(_obj, _old, (desired))); \ + _old; \ +}) + +#define atomic_exchange_explicit(object, desired, order) \ + atomic_exchange(object, desired) + +#define atomic_compare_exchange_strong(object, expected, desired) \ +({ \ + __typeof__(object) _exp = (expected); \ + __typeof__(*object) _old = *_exp; \ + *_exp = __sync_val_compare_and_swap((object), _old, (desired)); \ + *_exp == _old; \ +}) + +#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \ + atomic_compare_exchange_strong(object, expected, desired) + +#define atomic_compare_exchange_weak(object, expected, desired) \ + atomic_compare_exchange_strong(object, expected, desired) + +#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \ + atomic_compare_exchange_weak(object, expected, desired) + +#define atomic_fetch_add(object, operand) \ + __sync_fetch_and_add(object, operand) + +#define atomic_fetch_add_explicit(object, operand, order) \ + atomic_fetch_add(object, operand) + +#define atomic_fetch_sub(object, operand) \ + __sync_fetch_and_sub(object, operand) + +#define atomic_fetch_sub_explicit(object, operand, order) \ + atomic_fetch_sub(object, operand) + +#define atomic_fetch_or(object, operand) \ + __sync_fetch_and_or(object, operand) + +#define atomic_fetch_or_explicit(object, operand, order) \ + atomic_fetch_or(object, operand) + +#define atomic_fetch_xor(object, operand) \ + __sync_fetch_and_xor(object, operand) + +#define atomic_fetch_xor_explicit(object, operand, order) \ + atomic_fetch_xor(object, operand) + +#define atomic_fetch_and(object, operand) \ + __sync_fetch_and_and(object, operand) + +#define atomic_fetch_and_explicit(object, operand, order) \ + atomic_fetch_and(object, operand) + +#define atomic_flag_test_and_set(object) \ + atomic_exchange(object, 1) + +#define atomic_flag_test_and_set_explicit(object, order) \ + atomic_flag_test_and_set(object) + +#define atomic_flag_clear(object) \ + atomic_store(object, 0) + +#define atomic_flag_clear_explicit(object, order) \ + atomic_flag_clear(object) + +#endif /* COMPAT_ATOMICS_GCC_STDATOMIC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/compat/va_copy.h b/trunk/3rdparty/ffmpeg-4.2-fit/compat/va_copy.h new file mode 100644 index 0000000000..a40bbe6637 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/compat/va_copy.h @@ -0,0 +1,34 @@ +/* + * MSVC Compatible va_copy macro + * Copyright (c) 2012 Derek Buitenhuis + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef COMPAT_VA_COPY_H +#define COMPAT_VA_COPY_H + +#include + +#if !defined(va_copy) && defined(_MSC_VER) +#define va_copy(dst, src) ((dst) = (src)) +#endif +#if !defined(va_copy) && defined(__GNUC__) && __GNUC__ < 3 +#define va_copy(dst, src) __va_copy(dst, src) +#endif + +#endif /* COMPAT_VA_COPY_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/configure b/trunk/3rdparty/ffmpeg-4.2-fit/configure new file mode 100755 index 0000000000..b950783be3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/configure @@ -0,0 +1,7531 @@ +#!/bin/sh +# +# FFmpeg configure script +# +# Copyright (c) 2000-2002 Fabrice Bellard +# Copyright (c) 2005-2008 Diego Biurrun +# Copyright (c) 2005-2008 Mans Rullgard +# + +# Prevent locale nonsense from breaking basic text processing. +LC_ALL=C +export LC_ALL + +# make sure we are running under a compatible shell +# try to make this part work with most shells + +try_exec(){ + echo "Trying shell $1" + type "$1" > /dev/null 2>&1 && exec "$@" +} + +unset foo +(: ${foo%%bar}) 2> /dev/null +E1="$?" + +(: ${foo?}) 2> /dev/null +E2="$?" + +if test "$E1" != 0 || test "$E2" = 0; then + echo "Broken shell detected. Trying alternatives." + export FF_CONF_EXEC + if test "0$FF_CONF_EXEC" -lt 1; then + FF_CONF_EXEC=1 + try_exec bash "$0" "$@" + fi + if test "0$FF_CONF_EXEC" -lt 2; then + FF_CONF_EXEC=2 + try_exec ksh "$0" "$@" + fi + if test "0$FF_CONF_EXEC" -lt 3; then + FF_CONF_EXEC=3 + try_exec /usr/xpg4/bin/sh "$0" "$@" + fi + echo "No compatible shell script interpreter found." + echo "This configure script requires a POSIX-compatible shell" + echo "such as bash or ksh." + echo "THIS IS NOT A BUG IN FFMPEG, DO NOT REPORT IT AS SUCH." + echo "Instead, install a working POSIX-compatible shell." + echo "Disabling this configure test will create a broken FFmpeg." + if test "$BASH_VERSION" = '2.04.0(1)-release'; then + echo "This bash version ($BASH_VERSION) is broken on your platform." + echo "Upgrade to a later version if available." + fi + exit 1 +fi + +test -d /usr/xpg4/bin && PATH=/usr/xpg4/bin:$PATH + +show_help(){ + cat </dev/null 2>&1; then + ncolors=$(tput colors) + if test -n "$ncolors" && test $ncolors -ge 8; then + bold_color=$(tput bold) + warn_color=$(tput setaf 3) + error_color=$(tput setaf 1) + reset_color=$(tput sgr0) + fi + # 72 used instead of 80 since that's the default of pr + ncols=$(tput cols) +fi +: ${ncols:=72} + +log(){ + echo "$@" >> $logfile +} + +log_file(){ + log BEGIN "$1" + log_file_i=1 + while IFS= read -r log_file_line; do + printf '%5d\t%s\n' "$log_file_i" "$log_file_line" + log_file_i=$(($log_file_i+1)) + done < "$1" >> "$logfile" + log END "$1" +} + +warn(){ + log "WARNING: $*" + WARNINGS="${WARNINGS}WARNING: $*\n" +} + +die(){ + log "$@" + echo "$error_color$bold_color$@$reset_color" + cat <>file; + } else if (file ~ /\\.asm\$/) { + printf(\"%%define %s %d\\n\", c, v) >>file; + } else if (file ~ /\\.mak\$/) { + n = -v ? \"\" : \"!\"; + printf(\"%s%s=yes\\n\", n, c) >>file; + } else if (file ~ /\\.texi\$/) { + pre = -v ? \"\" : \"@c \"; + yesno = \$2; + c2 = tolower(c); + gsub(/_/, \"-\", c2); + printf(\"%s@set %s %s\\n\", pre, c2, yesno) >>file; + } + } + }" +} + +print_enabled(){ + suf=$1 + shift + for v; do + enabled $v && printf "%s\n" ${v%$suf} + done +} + +append(){ + var=$1 + shift + eval "$var=\"\$$var $*\"" +} + +prepend(){ + var=$1 + shift + eval "$var=\"$* \$$var\"" +} + +reverse () { + eval ' + reverse_out= + for v in $'$1'; do + reverse_out="$v $reverse_out" + done + '$1'=$reverse_out + ' +} + +# keeps the last occurence of each non-unique item +unique(){ + unique_out= + eval unique_in=\$$1 + reverse unique_in + for v in $unique_in; do + # " $unique_out" +space such that every item is surrounded with spaces + case " $unique_out" in *" $v "*) continue; esac # already in list + unique_out="$unique_out$v " + done + reverse unique_out + eval $1=\$unique_out +} + +resolve(){ + resolve_out= + eval resolve_in=\$$1 + for v in $resolve_in; do + eval 'resolve_out="$resolve_out$'$v' "' + done + eval $1=\$resolve_out +} + +add_cppflags(){ + append CPPFLAGS "$@" +} + +add_cflags(){ + append CFLAGS $($cflags_filter "$@") +} + +add_cflags_headers(){ + append CFLAGS_HEADERS $($cflags_filter "$@") +} + +add_cxxflags(){ + append CXXFLAGS $($cflags_filter "$@") +} + +add_objcflags(){ + append OBJCFLAGS $($objcflags_filter "$@") +} + +add_asflags(){ + append ASFLAGS $($asflags_filter "$@") +} + +add_ldflags(){ + append LDFLAGS $($ldflags_filter "$@") +} + +add_ldexeflags(){ + append LDEXEFLAGS $($ldflags_filter "$@") +} + +add_ldsoflags(){ + append LDSOFLAGS $($ldflags_filter "$@") +} + +add_extralibs(){ + prepend extralibs $($ldflags_filter "$@") +} + +add_stripflags(){ + append ASMSTRIPFLAGS "$@" +} + +add_host_cppflags(){ + append host_cppflags "$@" +} + +add_host_cflags(){ + append host_cflags $($host_cflags_filter "$@") +} + +add_host_ldflags(){ + append host_ldflags $($host_ldflags_filter "$@") +} + +add_compat(){ + append compat_objs $1 + shift + map 'add_cppflags -D$v' "$@" +} + +test_cmd(){ + log "$@" + "$@" >> $logfile 2>&1 +} + +test_stat(){ + log test_stat "$@" + stat "$1" >> $logfile 2>&1 +} + +cc_e(){ + eval printf '%s\\n' $CC_E +} + +cc_o(){ + eval printf '%s\\n' $CC_O +} + +as_o(){ + eval printf '%s\\n' $AS_O +} + +x86asm_o(){ + eval printf '%s\\n' $X86ASM_O +} + +ld_o(){ + eval printf '%s\\n' $LD_O +} + +hostcc_e(){ + eval printf '%s\\n' $HOSTCC_E +} + +hostcc_o(){ + eval printf '%s\\n' $HOSTCC_O +} + +nvcc_o(){ + eval printf '%s\\n' $NVCC_O +} + +test_cc(){ + log test_cc "$@" + cat > $TMPC + log_file $TMPC + test_cmd $cc $CPPFLAGS $CFLAGS "$@" $CC_C $(cc_o $TMPO) $TMPC +} + +test_cxx(){ + log test_cxx "$@" + cat > $TMPCPP + log_file $TMPCPP + test_cmd $cxx $CPPFLAGS $CFLAGS $CXXFLAGS "$@" $CXX_C -o $TMPO $TMPCPP +} + +test_objcc(){ + log test_objcc "$@" + cat > $TMPM + log_file $TMPM + test_cmd $objcc -Werror=missing-prototypes $CPPFLAGS $CFLAGS $OBJCFLAGS "$@" $OBJCC_C $(cc_o $TMPO) $TMPM +} + +test_nvcc(){ + log test_nvcc "$@" + cat > $TMPCU + log_file $TMPCU + tmpcu_=$TMPCU + tmpo_=$TMPO + [ -x "$(command -v cygpath)" ] && tmpcu_=$(cygpath -m $tmpcu_) && tmpo_=$(cygpath -m $tmpo_) + test_cmd $nvcc $nvccflags "$@" $NVCC_C $(nvcc_o $tmpo_) $tmpcu_ +} + +check_nvcc() { + log check_nvcc "$@" + name=$1 + shift 1 + disabled $name && return + disable $name + test_nvcc "$@" < $TMPC + log_file $TMPC + test_cmd $cc $CPPFLAGS $CFLAGS "$@" $(cc_e $TMPO) $TMPC +} + +test_as(){ + log test_as "$@" + cat > $TMPS + log_file $TMPS + test_cmd $as $CPPFLAGS $ASFLAGS "$@" $AS_C $(as_o $TMPO) $TMPS +} + +test_x86asm(){ + log test_x86asm "$@" + echo "$1" > $TMPASM + log_file $TMPASM + shift + test_cmd $x86asmexe $X86ASMFLAGS -Werror "$@" $(x86asm_o $TMPO) $TMPASM +} + +check_cmd(){ + log check_cmd "$@" + cmd=$1 + disabled $cmd && return + disable $cmd + test_cmd $@ && enable $cmd +} + +check_as(){ + log check_as "$@" + name=$1 + code=$2 + shift 2 + disable $name + test_as $@ < $TMPC <" +} + +test_code(){ + log test_code "$@" + check=$1 + headers=$2 + code=$3 + shift 3 + { + for hdr in $headers; do + print_include $hdr + done + echo "int main(void) { $code; return 0; }" + } | test_$check "$@" +} + +check_cppflags(){ + log check_cppflags "$@" + test_cpp "$@" < +EOF +} + +test_cflags(){ + log test_cflags "$@" + set -- $($cflags_filter "$@") + test_cc "$@" <" + echo "int main(void) { return 0; }" + } | test_objcc && test_stat "$TMPO" && enable_sanitized $header +} + +check_apple_framework(){ + log check_apple_framework "$@" + framework="$1" + name="$(tolower $framework)" + header="${framework}/${framework}.h" + disable $name + check_header_objcc $header && + enable $name && eval ${name}_extralibs='"-framework $framework"' +} + +check_func(){ + log check_func "$@" + func=$1 + shift + disable $func + test_ld "cc" "$@" < +#include +float foo(complex float f, complex float g) { return $func($args); } +int main(void){ return (int) foo; } +EOF +} + +check_mathfunc(){ + log check_mathfunc "$@" + func=$1 + narg=$2 + shift 2 + test $narg = 2 && args="f, g" || args="f" + disable $func + test_ld "cc" "$@" < +float foo(float f, float g) { return $func($args); } +int main(void){ return (int) foo; } +EOF +} + +check_func_headers(){ + log check_func_headers "$@" + headers=$1 + funcs=$2 + shift 2 + { + for hdr in $headers; do + print_include $hdr + done + echo "#include " + for func in $funcs; do + echo "long check_$func(void) { return (long) $func; }" + done + echo "int main(void) { int ret = 0;" + # LTO could optimize out the test functions without this + for func in $funcs; do + echo " ret |= ((intptr_t)check_$func) & 0xFFFF;" + done + echo "return ret; }" + } | test_ld "cc" "$@" && enable $funcs && enable_sanitized $headers +} + +check_class_headers_cpp(){ + log check_class_headers_cpp "$@" + headers=$1 + classes=$2 + shift 2 + { + for hdr in $headers; do + echo "#include <$hdr>" + done + echo "int main(void) { " + i=1 + for class in $classes; do + echo "$class obj$i;" + i=$(expr $i + 1) + done + echo "return 0; }" + } | test_ld "cxx" "$@" && enable $funcs && enable_sanitized $headers +} + +test_cpp_condition(){ + log test_cpp_condition "$@" + header=$1 + condition=$2 + shift 2 + test_cpp "$@" < +#if !($condition) +#error "unsatisfied condition: $condition" +#endif +EOF +} + +check_cpp_condition(){ + log check_cpp_condition "$@" + name=$1 + shift 1 + disable $name + test_cpp_condition "$@" && enable $name +} + +test_cflags_cc(){ + log test_cflags_cc "$@" + flags=$1 + header=$2 + condition=$3 + shift 3 + set -- $($cflags_filter "$flags") + test_cc "$@" < +#if !($condition) +#error "unsatisfied condition: $condition" +#endif +EOF +} + +check_lib(){ + log check_lib "$@" + name="$1" + headers="$2" + funcs="$3" + shift 3 + disable $name + check_func_headers "$headers" "$funcs" "$@" && + enable $name && eval ${name}_extralibs="\$@" +} + +check_lib_cpp(){ + log check_lib_cpp "$@" + name="$1" + headers="$2" + classes="$3" + shift 3 + disable $name + check_class_headers_cpp "$headers" "$classes" "$@" && + enable $name && eval ${name}_extralibs="\$@" +} + +test_pkg_config(){ + log test_pkg_config "$@" + name="$1" + pkg_version="$2" + pkg="${2%% *}" + headers="$3" + funcs="$4" + shift 4 + disable $name + test_cmd $pkg_config --exists --print-errors $pkg_version || return + pkg_cflags=$($pkg_config --cflags $pkg_config_flags $pkg) + pkg_libs=$($pkg_config --libs $pkg_config_flags $pkg) + check_func_headers "$headers" "$funcs" $pkg_cflags $pkg_libs "$@" && + enable $name && + set_sanitized "${name}_cflags" $pkg_cflags && + set_sanitized "${name}_extralibs" $pkg_libs +} + +check_pkg_config(){ + log check_pkg_config "$@" + name="$1" + test_pkg_config "$@" && + eval add_cflags \$${name}_cflags +} + +test_exec(){ + test_ld "cc" "$@" && { enabled cross_compile || $TMPE >> $logfile 2>&1; } +} + +check_exec_crash(){ + log check_exec_crash "$@" + code=$(cat) + + # exit() is not async signal safe. _Exit (C99) and _exit (POSIX) + # are safe but may not be available everywhere. Thus we use + # raise(SIGTERM) instead. The check is run in a subshell so we + # can redirect the "Terminated" message from the shell. SIGBUS + # is not defined by standard C so it is used conditionally. + + (test_exec "$@") >> $logfile 2>&1 < +static void sighandler(int sig){ + raise(SIGTERM); +} +int foo(void){ + $code +} +int (*func_ptr)(void) = foo; +int main(void){ + signal(SIGILL, sighandler); + signal(SIGFPE, sighandler); + signal(SIGSEGV, sighandler); +#ifdef SIGBUS + signal(SIGBUS, sighandler); +#endif + return func_ptr(); +} +EOF +} + +check_type(){ + log check_type "$@" + headers=$1 + type=$2 + shift 2 + disable_sanitized "$type" + test_code cc "$headers" "$type v" "$@" && enable_sanitized "$type" +} + +check_struct(){ + log check_struct "$@" + headers=$1 + struct=$2 + member=$3 + shift 3 + disable_sanitized "${struct}_${member}" + test_code cc "$headers" "const void *p = &(($struct *)0)->$member" "$@" && + enable_sanitized "${struct}_${member}" +} + +check_builtin(){ + log check_builtin "$@" + name=$1 + headers=$2 + builtin=$3 + shift 3 + disable "$name" + test_code ld "$headers" "$builtin" "cc" "$@" && enable "$name" +} + +check_compile_assert(){ + log check_compile_assert "$@" + name=$1 + headers=$2 + condition=$3 + shift 3 + disable "$name" + test_code cc "$headers" "char c[2 * !!($condition) - 1]" "$@" && enable "$name" +} + +check_cc(){ + log check_cc "$@" + name=$1 + shift + disable "$name" + test_code cc "$@" && enable "$name" +} + +require(){ + log require "$@" + name_version="$1" + name="${1%% *}" + shift + check_lib $name "$@" || die "ERROR: $name_version not found" +} + +require_cc(){ + log require_cc "$@" + name="$1" + check_cc "$@" || die "ERROR: $name failed" +} + +require_cpp(){ + name="$1" + headers="$2" + classes="$3" + shift 3 + check_lib_cpp "$headers" "$classes" "$@" || die "ERROR: $name not found" +} + +require_headers(){ + log require_headers "$@" + headers="$1" + check_headers "$@" || die "ERROR: $headers not found" +} + +require_cpp_condition(){ + log require_cpp_condition "$@" + condition="$3" + check_cpp_condition "$@" || die "ERROR: $condition not satisfied" +} + +require_pkg_config(){ + log require_pkg_config "$@" + pkg_version="$2" + check_pkg_config "$@" || die "ERROR: $pkg_version not found using pkg-config$pkg_config_fail_message" +} + +test_host_cc(){ + log test_host_cc "$@" + cat > $TMPC + log_file $TMPC + test_cmd $host_cc $host_cflags "$@" $HOSTCC_C $(hostcc_o $TMPO) $TMPC +} + +test_host_cpp(){ + log test_host_cpp "$@" + cat > $TMPC + log_file $TMPC + test_cmd $host_cc $host_cppflags $host_cflags "$@" $(hostcc_e $TMPO) $TMPC +} + +check_host_cppflags(){ + log check_host_cppflags "$@" + test_host_cpp "$@" < +EOF +} + +check_host_cflags(){ + log check_host_cflags "$@" + set -- $($host_cflags_filter "$@") + test_host_cc "$@" < +#if !($condition) +#error "unsatisfied condition: $condition" +#endif +EOF +} + +check_host_cpp_condition(){ + log check_host_cpp_condition "$@" + name=$1 + shift 1 + disable $name + test_host_cpp_condition "$@" && enable $name +} + +cp_if_changed(){ + cmp -s "$1" "$2" && { test "$quiet" != "yes" && echo "$2 is unchanged"; } && return + mkdir -p "$(dirname $2)" + cp -f "$1" "$2" +} + +# CONFIG_LIST contains configurable options, while HAVE_LIST is for +# system-dependent things. + +AVCODEC_COMPONENTS=" + bsfs + decoders + encoders + hwaccels + parsers +" + +AVDEVICE_COMPONENTS=" + indevs + outdevs +" + +AVFILTER_COMPONENTS=" + filters +" + +AVFORMAT_COMPONENTS=" + demuxers + muxers + protocols +" + +COMPONENT_LIST=" + $AVCODEC_COMPONENTS + $AVDEVICE_COMPONENTS + $AVFILTER_COMPONENTS + $AVFORMAT_COMPONENTS +" + +EXAMPLE_LIST=" + avio_dir_cmd_example + avio_reading_example + decode_audio_example + decode_video_example + demuxing_decoding_example + encode_audio_example + encode_video_example + extract_mvs_example + filter_audio_example + filtering_audio_example + filtering_video_example + http_multiclient_example + hw_decode_example + metadata_example + muxing_example + qsvdec_example + remuxing_example + resampling_audio_example + scaling_video_example + transcode_aac_example + transcoding_example + vaapi_encode_example + vaapi_transcode_example +" + +EXTERNAL_AUTODETECT_LIBRARY_LIST=" + alsa + appkit + avfoundation + bzlib + coreimage + iconv + libxcb + libxcb_shm + libxcb_shape + libxcb_xfixes + lzma + schannel + sdl2 + securetransport + sndio + xlib + zlib +" + +EXTERNAL_LIBRARY_GPL_LIST=" + avisynth + frei0r + libcdio + libdavs2 + librubberband + libvidstab + libx264 + libx265 + libxavs + libxavs2 + libxvid +" + +EXTERNAL_LIBRARY_NONFREE_LIST=" + decklink + libfdk_aac + openssl + libtls +" + +EXTERNAL_LIBRARY_VERSION3_LIST=" + gmp + libaribb24 + liblensfun + libopencore_amrnb + libopencore_amrwb + libvmaf + libvo_amrwbenc + mbedtls + rkmpp +" + +EXTERNAL_LIBRARY_GPLV3_LIST=" + libsmbclient +" + +EXTERNAL_LIBRARY_LIST=" + $EXTERNAL_LIBRARY_GPL_LIST + $EXTERNAL_LIBRARY_NONFREE_LIST + $EXTERNAL_LIBRARY_VERSION3_LIST + $EXTERNAL_LIBRARY_GPLV3_LIST + chromaprint + gcrypt + gnutls + jni + ladspa + libaom + libass + libbluray + libbs2b + libcaca + libcelt + libcodec2 + libdav1d + libdc1394 + libdrm + libflite + libfontconfig + libfreetype + libfribidi + libgme + libgsm + libiec61883 + libilbc + libjack + libklvanc + libkvazaar + libmodplug + libmp3lame + libmysofa + libopencv + libopenh264 + libopenjpeg + libopenmpt + libopus + libpulse + librsvg + librtmp + libshine + libsmbclient + libsnappy + libsoxr + libspeex + libsrt + libssh + libtensorflow + libtesseract + libtheora + libtwolame + libv4l2 + libvorbis + libvpx + libwavpack + libwebp + libxml2 + libzimg + libzmq + libzvbi + lv2 + mediacodec + openal + opengl + pocketsphinx + vapoursynth +" + +HWACCEL_AUTODETECT_LIBRARY_LIST=" + amf + audiotoolbox + crystalhd + cuda + cuda_llvm + cuvid + d3d11va + dxva2 + ffnvcodec + nvdec + nvenc + vaapi + vdpau + videotoolbox + v4l2_m2m + xvmc +" + +# catchall list of things that require external libs to link +EXTRALIBS_LIST=" + cpu_init + cws2fws +" + +HWACCEL_LIBRARY_NONFREE_LIST=" + cuda_nvcc + cuda_sdk + libnpp +" + +HWACCEL_LIBRARY_LIST=" + $HWACCEL_LIBRARY_NONFREE_LIST + libmfx + mmal + omx + opencl +" + +DOCUMENT_LIST=" + doc + htmlpages + manpages + podpages + txtpages +" + +FEATURE_LIST=" + ftrapv + gray + hardcoded_tables + omx_rpi + runtime_cpudetect + safe_bitstream_reader + shared + small + static + swscale_alpha +" + +# this list should be kept in linking order +LIBRARY_LIST=" + avdevice + avfilter + swscale + postproc + avformat + avcodec + swresample + avresample + avutil +" + +LICENSE_LIST=" + gpl + nonfree + version3 +" + +PROGRAM_LIST=" + ffplay + ffprobe + ffmpeg +" + +SUBSYSTEM_LIST=" + dct + dwt + error_resilience + faan + fast_unaligned + fft + lsp + lzo + mdct + pixelutils + network + rdft +" + +# COMPONENT_LIST needs to come last to ensure correct dependency checking +CONFIG_LIST=" + $DOCUMENT_LIST + $EXAMPLE_LIST + $EXTERNAL_LIBRARY_LIST + $EXTERNAL_AUTODETECT_LIBRARY_LIST + $HWACCEL_LIBRARY_LIST + $HWACCEL_AUTODETECT_LIBRARY_LIST + $FEATURE_LIST + $LICENSE_LIST + $LIBRARY_LIST + $PROGRAM_LIST + $SUBSYSTEM_LIST + autodetect + fontconfig + linux_perf + memory_poisoning + neon_clobber_test + ossfuzz + pic + thumb + valgrind_backtrace + xmm_clobber_test + $COMPONENT_LIST +" + +THREADS_LIST=" + pthreads + os2threads + w32threads +" + +ATOMICS_LIST=" + atomics_gcc + atomics_suncc + atomics_win32 +" + +AUTODETECT_LIBS=" + $EXTERNAL_AUTODETECT_LIBRARY_LIST + $HWACCEL_AUTODETECT_LIBRARY_LIST + $THREADS_LIST +" + +ARCH_LIST=" + aarch64 + alpha + arm + avr32 + avr32_ap + avr32_uc + bfin + ia64 + m68k + mips + mips64 + parisc + ppc + ppc64 + s390 + sh4 + sparc + sparc64 + tilegx + tilepro + tomi + x86 + x86_32 + x86_64 +" + +ARCH_EXT_LIST_ARM=" + armv5te + armv6 + armv6t2 + armv8 + neon + vfp + vfpv3 + setend +" + +ARCH_EXT_LIST_MIPS=" + mipsfpu + mips32r2 + mips32r5 + mips64r2 + mips32r6 + mips64r6 + mipsdsp + mipsdspr2 + msa + msa2 +" + +ARCH_EXT_LIST_LOONGSON=" + loongson2 + loongson3 + mmi +" + +ARCH_EXT_LIST_X86_SIMD=" + aesni + amd3dnow + amd3dnowext + avx + avx2 + avx512 + fma3 + fma4 + mmx + mmxext + sse + sse2 + sse3 + sse4 + sse42 + ssse3 + xop +" + +ARCH_EXT_LIST_PPC=" + altivec + dcbzl + ldbrx + power8 + ppc4xx + vsx +" + +ARCH_EXT_LIST_X86=" + $ARCH_EXT_LIST_X86_SIMD + cpunop + i686 +" + +ARCH_EXT_LIST=" + $ARCH_EXT_LIST_ARM + $ARCH_EXT_LIST_PPC + $ARCH_EXT_LIST_X86 + $ARCH_EXT_LIST_MIPS + $ARCH_EXT_LIST_LOONGSON +" + +ARCH_FEATURES=" + aligned_stack + fast_64bit + fast_clz + fast_cmov + local_aligned + simd_align_16 + simd_align_32 + simd_align_64 +" + +BUILTIN_LIST=" + atomic_cas_ptr + machine_rw_barrier + MemoryBarrier + mm_empty + rdtsc + sem_timedwait + sync_val_compare_and_swap +" +HAVE_LIST_CMDLINE=" + inline_asm + symver + x86asm +" + +HAVE_LIST_PUB=" + bigendian + fast_unaligned +" + +HEADERS_LIST=" + arpa_inet_h + asm_types_h + cdio_paranoia_h + cdio_paranoia_paranoia_h + cuda_h + dispatch_dispatch_h + dev_bktr_ioctl_bt848_h + dev_bktr_ioctl_meteor_h + dev_ic_bt8xx_h + dev_video_bktr_ioctl_bt848_h + dev_video_meteor_ioctl_meteor_h + direct_h + dirent_h + dxgidebug_h + dxva_h + ES2_gl_h + gsm_h + io_h + linux_perf_event_h + machine_ioctl_bt848_h + machine_ioctl_meteor_h + malloc_h + opencv2_core_core_c_h + OpenGL_gl3_h + poll_h + sys_param_h + sys_resource_h + sys_select_h + sys_soundcard_h + sys_time_h + sys_un_h + sys_videoio_h + termios_h + udplite_h + unistd_h + valgrind_valgrind_h + windows_h + winsock2_h +" + +INTRINSICS_LIST=" + intrinsics_neon +" + +COMPLEX_FUNCS=" + cabs + cexp +" + +MATH_FUNCS=" + atanf + atan2f + cbrt + cbrtf + copysign + cosf + erf + exp2 + exp2f + expf + hypot + isfinite + isinf + isnan + ldexpf + llrint + llrintf + log2 + log2f + log10f + lrint + lrintf + powf + rint + round + roundf + sinf + trunc + truncf +" + +SYSTEM_FEATURES=" + dos_paths + libc_msvcrt + MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS + section_data_rel_ro + threads + uwp + winrt +" + +SYSTEM_FUNCS=" + access + aligned_malloc + arc4random + clock_gettime + closesocket + CommandLineToArgvW + fcntl + getaddrinfo + gethrtime + getopt + GetProcessAffinityMask + GetProcessMemoryInfo + GetProcessTimes + getrusage + GetSystemTimeAsFileTime + gettimeofday + glob + glXGetProcAddress + gmtime_r + inet_aton + isatty + kbhit + localtime_r + lstat + lzo1x_999_compress + mach_absolute_time + MapViewOfFile + memalign + mkstemp + mmap + mprotect + nanosleep + PeekNamedPipe + posix_memalign + pthread_cancel + sched_getaffinity + SecItemImport + SetConsoleTextAttribute + SetConsoleCtrlHandler + setmode + setrlimit + Sleep + strerror_r + sysconf + sysctl + usleep + UTGetOSTypeFromString + VirtualAlloc + wglGetProcAddress +" + +SYSTEM_LIBRARIES=" + bcrypt + vaapi_drm + vaapi_x11 + vdpau_x11 +" + +TOOLCHAIN_FEATURES=" + as_arch_directive + as_dn_directive + as_fpu_directive + as_func + as_object_arch + asm_mod_q + blocks_extension + ebp_available + ebx_available + gnu_as + gnu_windres + ibm_asm + inline_asm_direct_symbol_refs + inline_asm_labels + inline_asm_nonlocal_labels + pragma_deprecated + rsync_contimeout + symver_asm_label + symver_gnu_asm + vfp_args + xform_asm + xmm_clobbers +" + +TYPES_LIST=" + kCMVideoCodecType_HEVC + kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange + socklen_t + struct_addrinfo + struct_group_source_req + struct_ip_mreq_source + struct_ipv6_mreq + struct_msghdr_msg_flags + struct_pollfd + struct_rusage_ru_maxrss + struct_sctp_event_subscribe + struct_sockaddr_in6 + struct_sockaddr_sa_len + struct_sockaddr_storage + struct_stat_st_mtim_tv_nsec + struct_v4l2_frmivalenum_discrete +" + +HAVE_LIST=" + $ARCH_EXT_LIST + $(add_suffix _external $ARCH_EXT_LIST) + $(add_suffix _inline $ARCH_EXT_LIST) + $ARCH_FEATURES + $BUILTIN_LIST + $COMPLEX_FUNCS + $HAVE_LIST_CMDLINE + $HAVE_LIST_PUB + $HEADERS_LIST + $INTRINSICS_LIST + $MATH_FUNCS + $SYSTEM_FEATURES + $SYSTEM_FUNCS + $SYSTEM_LIBRARIES + $THREADS_LIST + $TOOLCHAIN_FEATURES + $TYPES_LIST + makeinfo + makeinfo_html + opencl_d3d11 + opencl_drm_arm + opencl_drm_beignet + opencl_dxva2 + opencl_vaapi_beignet + opencl_vaapi_intel_media + perl + pod2man + texi2html +" + +# options emitted with CONFIG_ prefix but not available on the command line +CONFIG_EXTRA=" + aandcttables + ac3dsp + adts_header + audio_frame_queue + audiodsp + blockdsp + bswapdsp + cabac + cbs + cbs_av1 + cbs_h264 + cbs_h265 + cbs_jpeg + cbs_mpeg2 + cbs_vp9 + dirac_parse + dnn + dvprofile + exif + faandct + faanidct + fdctdsp + flacdsp + fmtconvert + frame_thread_encoder + g722dsp + golomb + gplv3 + h263dsp + h264chroma + h264dsp + h264parse + h264pred + h264qpel + hevcparse + hpeldsp + huffman + huffyuvdsp + huffyuvencdsp + idctdsp + iirfilter + mdct15 + intrax8 + iso_media + ividsp + jpegtables + lgplv3 + libx262 + llauddsp + llviddsp + llvidencdsp + lpc + lzf + me_cmp + mpeg_er + mpegaudio + mpegaudiodsp + mpegaudioheader + mpegvideo + mpegvideoenc + mss34dsp + pixblockdsp + qpeldsp + qsv + qsvdec + qsvenc + qsvvpp + rangecoder + riffdec + riffenc + rtpdec + rtpenc_chain + rv34dsp + scene_sad + sinewin + snappy + srtp + startcode + texturedsp + texturedspenc + tpeldsp + vaapi_1 + vaapi_encode + vc1dsp + videodsp + vp3dsp + vp56dsp + vp8dsp + wma_freqs + wmv2dsp +" + +CMDLINE_SELECT=" + $ARCH_EXT_LIST + $CONFIG_LIST + $HAVE_LIST_CMDLINE + $THREADS_LIST + asm + cross_compile + debug + extra_warnings + logging + lto + optimizations + rpath + stripping +" + +PATHS_LIST=" + bindir + datadir + docdir + incdir + libdir + mandir + pkgconfigdir + prefix + shlibdir + install_name_dir +" + +CMDLINE_SET=" + $PATHS_LIST + ar + arch + as + assert_level + build_suffix + cc + objcc + cpu + cross_prefix + custom_allocator + cxx + dep_cc + doxygen + env + extra_version + gas + host_cc + host_cflags + host_extralibs + host_ld + host_ldflags + host_os + ignore_tests + install + ld + ln_s + logfile + malloc_prefix + nm + optflags + nvcc + nvccflags + pkg_config + pkg_config_flags + progs_suffix + random_seed + ranlib + samples + strip + sws_max_filter_size + sysinclude + sysroot + target_exec + target_os + target_path + target_samples + tempprefix + toolchain + valgrind + windres + x86asmexe +" + +CMDLINE_APPEND=" + extra_cflags + extra_cxxflags + extra_objcflags + host_cppflags +" + +# code dependency declarations + +# architecture extensions + +armv5te_deps="arm" +armv6_deps="arm" +armv6t2_deps="arm" +armv8_deps="aarch64" +neon_deps_any="aarch64 arm" +intrinsics_neon_deps="neon" +vfp_deps_any="aarch64 arm" +vfpv3_deps="vfp" +setend_deps="arm" + +map 'eval ${v}_inline_deps=inline_asm' $ARCH_EXT_LIST_ARM + +altivec_deps="ppc" +dcbzl_deps="ppc" +ldbrx_deps="ppc" +ppc4xx_deps="ppc" +vsx_deps="altivec" +power8_deps="vsx" + +loongson2_deps="mips" +loongson3_deps="mips" +mips32r2_deps="mips" +mips32r5_deps="mips" +mips32r6_deps="mips" +mips64r2_deps="mips" +mips64r6_deps="mips" +mipsfpu_deps="mips" +mipsdsp_deps="mips" +mipsdspr2_deps="mips" +mmi_deps="mips" +msa_deps="mipsfpu" +msa2_deps="msa" + +cpunop_deps="i686" +x86_64_select="i686" +x86_64_suggest="fast_cmov" + +amd3dnow_deps="mmx" +amd3dnowext_deps="amd3dnow" +i686_deps="x86" +mmx_deps="x86" +mmxext_deps="mmx" +sse_deps="mmxext" +sse2_deps="sse" +sse3_deps="sse2" +ssse3_deps="sse3" +sse4_deps="ssse3" +sse42_deps="sse4" +aesni_deps="sse42" +avx_deps="sse42" +xop_deps="avx" +fma3_deps="avx" +fma4_deps="avx" +avx2_deps="avx" +avx512_deps="avx2" + +mmx_external_deps="x86asm" +mmx_inline_deps="inline_asm x86" +mmx_suggest="mmx_external mmx_inline" + +for ext in $(filter_out mmx $ARCH_EXT_LIST_X86_SIMD); do + eval dep=\$${ext}_deps + eval ${ext}_external_deps='"${dep}_external"' + eval ${ext}_inline_deps='"${dep}_inline"' + eval ${ext}_suggest='"${ext}_external ${ext}_inline"' +done + +aligned_stack_if_any="aarch64 ppc x86" +fast_64bit_if_any="aarch64 alpha ia64 mips64 parisc64 ppc64 sparc64 x86_64" +fast_clz_if_any="aarch64 alpha avr32 mips ppc x86" +fast_unaligned_if_any="aarch64 ppc x86" +simd_align_16_if_any="altivec neon sse" +simd_align_32_if_any="avx" +simd_align_64_if_any="avx512" + +# system capabilities +linux_perf_deps="linux_perf_event_h" +symver_if_any="symver_asm_label symver_gnu_asm" +valgrind_backtrace_conflict="optimizations" +valgrind_backtrace_deps="valgrind_valgrind_h" + +# threading support +atomics_gcc_if="sync_val_compare_and_swap" +atomics_suncc_if="atomic_cas_ptr machine_rw_barrier" +atomics_win32_if="MemoryBarrier" +atomics_native_if_any="$ATOMICS_LIST" +w32threads_deps="atomics_native" +threads_if_any="$THREADS_LIST" + +# subsystems +cbs_av1_select="cbs" +cbs_h264_select="cbs" +cbs_h265_select="cbs" +cbs_jpeg_select="cbs" +cbs_mpeg2_select="cbs" +cbs_vp9_select="cbs" +dct_select="rdft" +dirac_parse_select="golomb" +dnn_suggest="libtensorflow" +error_resilience_select="me_cmp" +faandct_deps="faan" +faandct_select="fdctdsp" +faanidct_deps="faan" +faanidct_select="idctdsp" +h264dsp_select="startcode" +hevcparse_select="golomb" +frame_thread_encoder_deps="encoders threads" +intrax8_select="blockdsp idctdsp" +mdct_select="fft" +mdct15_select="fft" +me_cmp_select="fdctdsp idctdsp pixblockdsp" +mpeg_er_select="error_resilience" +mpegaudio_select="mpegaudiodsp mpegaudioheader" +mpegaudiodsp_select="dct" +mpegvideo_select="blockdsp h264chroma hpeldsp idctdsp me_cmp mpeg_er videodsp" +mpegvideoenc_select="aandcttables me_cmp mpegvideo pixblockdsp qpeldsp" +vc1dsp_select="h264chroma qpeldsp startcode" +rdft_select="fft" + +# decoders / encoders +aac_decoder_select="adts_header mdct15 mdct sinewin" +aac_fixed_decoder_select="adts_header mdct sinewin" +aac_encoder_select="audio_frame_queue iirfilter lpc mdct sinewin" +aac_latm_decoder_select="aac_decoder aac_latm_parser" +ac3_decoder_select="ac3_parser ac3dsp bswapdsp fmtconvert mdct" +ac3_fixed_decoder_select="ac3_parser ac3dsp bswapdsp mdct" +ac3_encoder_select="ac3dsp audiodsp mdct me_cmp" +ac3_fixed_encoder_select="ac3dsp audiodsp mdct me_cmp" +adpcm_g722_decoder_select="g722dsp" +adpcm_g722_encoder_select="g722dsp" +aic_decoder_select="golomb idctdsp" +alac_encoder_select="lpc" +als_decoder_select="bswapdsp" +amrnb_decoder_select="lsp" +amrwb_decoder_select="lsp" +amv_decoder_select="sp5x_decoder exif" +amv_encoder_select="jpegtables mpegvideoenc" +ape_decoder_select="bswapdsp llauddsp" +apng_decoder_deps="zlib" +apng_encoder_deps="zlib" +apng_encoder_select="llvidencdsp" +aptx_decoder_select="audio_frame_queue" +aptx_encoder_select="audio_frame_queue" +aptx_hd_decoder_select="audio_frame_queue" +aptx_hd_encoder_select="audio_frame_queue" +asv1_decoder_select="blockdsp bswapdsp idctdsp" +asv1_encoder_select="aandcttables bswapdsp fdctdsp pixblockdsp" +asv2_decoder_select="blockdsp bswapdsp idctdsp" +asv2_encoder_select="aandcttables bswapdsp fdctdsp pixblockdsp" +atrac1_decoder_select="mdct sinewin" +atrac3_decoder_select="mdct" +atrac3p_decoder_select="mdct sinewin" +atrac9_decoder_select="mdct" +avrn_decoder_select="exif jpegtables" +bink_decoder_select="blockdsp hpeldsp" +binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs" +binkaudio_rdft_decoder_select="mdct rdft sinewin wma_freqs" +cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp" +clearvideo_decoder_select="idctdsp" +cllc_decoder_select="bswapdsp" +comfortnoise_encoder_select="lpc" +cook_decoder_select="audiodsp mdct sinewin" +cscd_decoder_select="lzo" +cscd_decoder_suggest="zlib" +dca_decoder_select="mdct" +dds_decoder_select="texturedsp" +dirac_decoder_select="dirac_parse dwt golomb videodsp mpegvideoenc" +dnxhd_decoder_select="blockdsp idctdsp" +dnxhd_encoder_select="blockdsp fdctdsp idctdsp mpegvideoenc pixblockdsp" +dolby_e_decoder_select="mdct" +dvvideo_decoder_select="dvprofile idctdsp" +dvvideo_encoder_select="dvprofile fdctdsp me_cmp pixblockdsp" +dxa_decoder_deps="zlib" +dxv_decoder_select="lzf texturedsp" +eac3_decoder_select="ac3_decoder" +eac3_encoder_select="ac3_encoder" +eamad_decoder_select="aandcttables blockdsp bswapdsp idctdsp mpegvideo" +eatgq_decoder_select="aandcttables" +eatqi_decoder_select="aandcttables blockdsp bswapdsp idctdsp" +exr_decoder_deps="zlib" +ffv1_decoder_select="rangecoder" +ffv1_encoder_select="rangecoder" +ffvhuff_decoder_select="huffyuv_decoder" +ffvhuff_encoder_select="huffyuv_encoder" +fic_decoder_select="golomb" +flac_decoder_select="flacdsp" +flac_encoder_select="bswapdsp flacdsp lpc" +flashsv2_decoder_deps="zlib" +flashsv2_encoder_deps="zlib" +flashsv_decoder_deps="zlib" +flashsv_encoder_deps="zlib" +flv_decoder_select="h263_decoder" +flv_encoder_select="h263_encoder" +fourxm_decoder_select="blockdsp bswapdsp" +fraps_decoder_select="bswapdsp huffman" +g2m_decoder_deps="zlib" +g2m_decoder_select="blockdsp idctdsp jpegtables" +g729_decoder_select="audiodsp" +h261_decoder_select="mpegvideo" +h261_encoder_select="mpegvideoenc" +h263_decoder_select="h263_parser h263dsp mpegvideo qpeldsp" +h263_encoder_select="h263dsp mpegvideoenc" +h263i_decoder_select="h263_decoder" +h263p_decoder_select="h263_decoder" +h263p_encoder_select="h263_encoder" +h264_decoder_select="cabac golomb h264chroma h264dsp h264parse h264pred h264qpel videodsp" +h264_decoder_suggest="error_resilience" +hap_decoder_select="snappy texturedsp" +hap_encoder_deps="libsnappy" +hap_encoder_select="texturedspenc" +hevc_decoder_select="bswapdsp cabac golomb hevcparse videodsp" +huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp" +huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp" +hymt_decoder_select="huffyuv_decoder" +iac_decoder_select="imc_decoder" +imc_decoder_select="bswapdsp fft mdct sinewin" +indeo3_decoder_select="hpeldsp" +indeo4_decoder_select="ividsp" +indeo5_decoder_select="ividsp" +interplay_video_decoder_select="hpeldsp" +jpegls_decoder_select="mjpeg_decoder" +jv_decoder_select="blockdsp" +lagarith_decoder_select="llviddsp" +ljpeg_encoder_select="idctdsp jpegtables mpegvideoenc" +lscr_decoder_deps="zlib" +magicyuv_decoder_select="llviddsp" +magicyuv_encoder_select="llvidencdsp" +mdec_decoder_select="blockdsp idctdsp mpegvideo" +metasound_decoder_select="lsp mdct sinewin" +mimic_decoder_select="blockdsp bswapdsp hpeldsp idctdsp" +mjpeg_decoder_select="blockdsp hpeldsp exif idctdsp jpegtables" +mjpeg_encoder_select="jpegtables mpegvideoenc" +mjpegb_decoder_select="mjpeg_decoder" +mlp_decoder_select="mlp_parser" +mlp_encoder_select="lpc audio_frame_queue" +motionpixels_decoder_select="bswapdsp" +mp1_decoder_select="mpegaudio" +mp1float_decoder_select="mpegaudio" +mp2_decoder_select="mpegaudio" +mp2float_decoder_select="mpegaudio" +mp3_decoder_select="mpegaudio" +mp3adu_decoder_select="mpegaudio" +mp3adufloat_decoder_select="mpegaudio" +mp3float_decoder_select="mpegaudio" +mp3on4_decoder_select="mpegaudio" +mp3on4float_decoder_select="mpegaudio" +mpc7_decoder_select="bswapdsp mpegaudiodsp" +mpc8_decoder_select="mpegaudiodsp" +mpegvideo_decoder_select="mpegvideo" +mpeg1video_decoder_select="mpegvideo" +mpeg1video_encoder_select="mpegvideoenc h263dsp" +mpeg2video_decoder_select="mpegvideo" +mpeg2video_encoder_select="mpegvideoenc h263dsp" +mpeg4_decoder_select="h263_decoder mpeg4video_parser" +mpeg4_encoder_select="h263_encoder" +msa1_decoder_select="mss34dsp" +mscc_decoder_deps="zlib" +msmpeg4v1_decoder_select="h263_decoder" +msmpeg4v2_decoder_select="h263_decoder" +msmpeg4v2_encoder_select="h263_encoder" +msmpeg4v3_decoder_select="h263_decoder" +msmpeg4v3_encoder_select="h263_encoder" +mss2_decoder_select="mpegvideo qpeldsp vc1_decoder" +mts2_decoder_select="mss34dsp" +mwsc_decoder_deps="zlib" +mxpeg_decoder_select="mjpeg_decoder" +nellymoser_decoder_select="mdct sinewin" +nellymoser_encoder_select="audio_frame_queue mdct sinewin" +nuv_decoder_select="idctdsp lzo" +on2avc_decoder_select="mdct" +opus_decoder_deps="swresample" +opus_decoder_select="mdct15" +opus_encoder_select="audio_frame_queue mdct15" +png_decoder_deps="zlib" +png_encoder_deps="zlib" +png_encoder_select="llvidencdsp" +prores_decoder_select="blockdsp idctdsp" +prores_encoder_select="fdctdsp" +qcelp_decoder_select="lsp" +qdm2_decoder_select="mdct rdft mpegaudiodsp" +ra_144_decoder_select="audiodsp" +ra_144_encoder_select="audio_frame_queue lpc audiodsp" +ralf_decoder_select="golomb" +rasc_decoder_deps="zlib" +rawvideo_decoder_select="bswapdsp" +rscc_decoder_deps="zlib" +rtjpeg_decoder_select="me_cmp" +rv10_decoder_select="h263_decoder" +rv10_encoder_select="h263_encoder" +rv20_decoder_select="h263_decoder" +rv20_encoder_select="h263_encoder" +rv30_decoder_select="golomb h264pred h264qpel mpegvideo rv34dsp" +rv40_decoder_select="golomb h264pred h264qpel mpegvideo rv34dsp" +screenpresso_decoder_deps="zlib" +shorten_decoder_select="bswapdsp" +sipr_decoder_select="lsp" +snow_decoder_select="dwt h264qpel hpeldsp me_cmp rangecoder videodsp" +snow_encoder_select="dwt h264qpel hpeldsp me_cmp mpegvideoenc rangecoder" +sonic_decoder_select="golomb rangecoder" +sonic_encoder_select="golomb rangecoder" +sonic_ls_encoder_select="golomb rangecoder" +sp5x_decoder_select="mjpeg_decoder" +speedhq_decoder_select="mpegvideo" +srgc_decoder_deps="zlib" +svq1_decoder_select="hpeldsp" +svq1_encoder_select="hpeldsp me_cmp mpegvideoenc" +svq3_decoder_select="golomb h264dsp h264parse h264pred hpeldsp tpeldsp videodsp" +svq3_decoder_suggest="zlib" +tak_decoder_select="audiodsp" +tdsc_decoder_deps="zlib" +tdsc_decoder_select="mjpeg_decoder" +theora_decoder_select="vp3_decoder" +thp_decoder_select="mjpeg_decoder" +tiff_decoder_suggest="zlib lzma" +tiff_encoder_suggest="zlib" +truehd_decoder_select="mlp_parser" +truehd_encoder_select="lpc audio_frame_queue" +truemotion2_decoder_select="bswapdsp" +truespeech_decoder_select="bswapdsp" +tscc_decoder_deps="zlib" +twinvq_decoder_select="mdct lsp sinewin" +txd_decoder_select="texturedsp" +utvideo_decoder_select="bswapdsp llviddsp" +utvideo_encoder_select="bswapdsp huffman llvidencdsp" +vble_decoder_select="llviddsp" +vc1_decoder_select="blockdsp h263_decoder h264qpel intrax8 mpegvideo vc1dsp" +vc1image_decoder_select="vc1_decoder" +vorbis_decoder_select="mdct" +vorbis_encoder_select="audio_frame_queue mdct" +vp3_decoder_select="hpeldsp vp3dsp videodsp" +vp4_decoder_select="vp3_decoder" +vp5_decoder_select="h264chroma hpeldsp videodsp vp3dsp vp56dsp" +vp6_decoder_select="h264chroma hpeldsp huffman videodsp vp3dsp vp56dsp" +vp6a_decoder_select="vp6_decoder" +vp6f_decoder_select="vp6_decoder" +vp7_decoder_select="h264pred videodsp vp8dsp" +vp8_decoder_select="h264pred videodsp vp8dsp" +vp9_decoder_select="videodsp vp9_parser vp9_superframe_split_bsf" +wcmv_decoder_deps="zlib" +webp_decoder_select="vp8_decoder exif" +wmalossless_decoder_select="llauddsp" +wmapro_decoder_select="mdct sinewin wma_freqs" +wmav1_decoder_select="mdct sinewin wma_freqs" +wmav1_encoder_select="mdct sinewin wma_freqs" +wmav2_decoder_select="mdct sinewin wma_freqs" +wmav2_encoder_select="mdct sinewin wma_freqs" +wmavoice_decoder_select="lsp rdft dct mdct sinewin" +wmv1_decoder_select="h263_decoder" +wmv1_encoder_select="h263_encoder" +wmv2_decoder_select="blockdsp error_resilience h263_decoder idctdsp intrax8 videodsp wmv2dsp" +wmv2_encoder_select="h263_encoder wmv2dsp" +wmv3_decoder_select="vc1_decoder" +wmv3image_decoder_select="wmv3_decoder" +xma1_decoder_select="wmapro_decoder" +xma2_decoder_select="wmapro_decoder" +zerocodec_decoder_deps="zlib" +zlib_decoder_deps="zlib" +zlib_encoder_deps="zlib" +zmbv_decoder_deps="zlib" +zmbv_encoder_deps="zlib" + +# hardware accelerators +crystalhd_deps="libcrystalhd_libcrystalhd_if_h" +cuda_deps="ffnvcodec" +cuvid_deps="ffnvcodec" +d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext" +dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" +ffnvcodec_deps_any="libdl LoadLibrary" +nvdec_deps="ffnvcodec" +vaapi_x11_deps="xlib" +videotoolbox_hwaccel_deps="videotoolbox pthreads" +videotoolbox_hwaccel_extralibs="-framework QuartzCore" +xvmc_deps="X11_extensions_XvMClib_h" + +h263_vaapi_hwaccel_deps="vaapi" +h263_vaapi_hwaccel_select="h263_decoder" +h263_videotoolbox_hwaccel_deps="videotoolbox" +h263_videotoolbox_hwaccel_select="h263_decoder" +h264_d3d11va_hwaccel_deps="d3d11va" +h264_d3d11va_hwaccel_select="h264_decoder" +h264_d3d11va2_hwaccel_deps="d3d11va" +h264_d3d11va2_hwaccel_select="h264_decoder" +h264_dxva2_hwaccel_deps="dxva2" +h264_dxva2_hwaccel_select="h264_decoder" +h264_nvdec_hwaccel_deps="nvdec" +h264_nvdec_hwaccel_select="h264_decoder" +h264_vaapi_hwaccel_deps="vaapi" +h264_vaapi_hwaccel_select="h264_decoder" +h264_vdpau_hwaccel_deps="vdpau" +h264_vdpau_hwaccel_select="h264_decoder" +h264_videotoolbox_hwaccel_deps="videotoolbox" +h264_videotoolbox_hwaccel_select="h264_decoder" +hevc_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_HEVC" +hevc_d3d11va_hwaccel_select="hevc_decoder" +hevc_d3d11va2_hwaccel_deps="d3d11va DXVA_PicParams_HEVC" +hevc_d3d11va2_hwaccel_select="hevc_decoder" +hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC" +hevc_dxva2_hwaccel_select="hevc_decoder" +hevc_nvdec_hwaccel_deps="nvdec" +hevc_nvdec_hwaccel_select="hevc_decoder" +hevc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferHEVC" +hevc_vaapi_hwaccel_select="hevc_decoder" +hevc_vdpau_hwaccel_deps="vdpau VdpPictureInfoHEVC" +hevc_vdpau_hwaccel_select="hevc_decoder" +hevc_videotoolbox_hwaccel_deps="videotoolbox" +hevc_videotoolbox_hwaccel_select="hevc_decoder" +mjpeg_nvdec_hwaccel_deps="nvdec" +mjpeg_nvdec_hwaccel_select="mjpeg_decoder" +mjpeg_vaapi_hwaccel_deps="vaapi" +mjpeg_vaapi_hwaccel_select="mjpeg_decoder" +mpeg_xvmc_hwaccel_deps="xvmc" +mpeg_xvmc_hwaccel_select="mpeg2video_decoder" +mpeg1_nvdec_hwaccel_deps="nvdec" +mpeg1_nvdec_hwaccel_select="mpeg1video_decoder" +mpeg1_vdpau_hwaccel_deps="vdpau" +mpeg1_vdpau_hwaccel_select="mpeg1video_decoder" +mpeg1_videotoolbox_hwaccel_deps="videotoolbox" +mpeg1_videotoolbox_hwaccel_select="mpeg1video_decoder" +mpeg1_xvmc_hwaccel_deps="xvmc" +mpeg1_xvmc_hwaccel_select="mpeg1video_decoder" +mpeg2_d3d11va_hwaccel_deps="d3d11va" +mpeg2_d3d11va_hwaccel_select="mpeg2video_decoder" +mpeg2_d3d11va2_hwaccel_deps="d3d11va" +mpeg2_d3d11va2_hwaccel_select="mpeg2video_decoder" +mpeg2_dxva2_hwaccel_deps="dxva2" +mpeg2_dxva2_hwaccel_select="mpeg2video_decoder" +mpeg2_nvdec_hwaccel_deps="nvdec" +mpeg2_nvdec_hwaccel_select="mpeg2video_decoder" +mpeg2_vaapi_hwaccel_deps="vaapi" +mpeg2_vaapi_hwaccel_select="mpeg2video_decoder" +mpeg2_vdpau_hwaccel_deps="vdpau" +mpeg2_vdpau_hwaccel_select="mpeg2video_decoder" +mpeg2_videotoolbox_hwaccel_deps="videotoolbox" +mpeg2_videotoolbox_hwaccel_select="mpeg2video_decoder" +mpeg2_xvmc_hwaccel_deps="xvmc" +mpeg2_xvmc_hwaccel_select="mpeg2video_decoder" +mpeg4_nvdec_hwaccel_deps="nvdec" +mpeg4_nvdec_hwaccel_select="mpeg4_decoder" +mpeg4_vaapi_hwaccel_deps="vaapi" +mpeg4_vaapi_hwaccel_select="mpeg4_decoder" +mpeg4_vdpau_hwaccel_deps="vdpau" +mpeg4_vdpau_hwaccel_select="mpeg4_decoder" +mpeg4_videotoolbox_hwaccel_deps="videotoolbox" +mpeg4_videotoolbox_hwaccel_select="mpeg4_decoder" +vc1_d3d11va_hwaccel_deps="d3d11va" +vc1_d3d11va_hwaccel_select="vc1_decoder" +vc1_d3d11va2_hwaccel_deps="d3d11va" +vc1_d3d11va2_hwaccel_select="vc1_decoder" +vc1_dxva2_hwaccel_deps="dxva2" +vc1_dxva2_hwaccel_select="vc1_decoder" +vc1_nvdec_hwaccel_deps="nvdec" +vc1_nvdec_hwaccel_select="vc1_decoder" +vc1_vaapi_hwaccel_deps="vaapi" +vc1_vaapi_hwaccel_select="vc1_decoder" +vc1_vdpau_hwaccel_deps="vdpau" +vc1_vdpau_hwaccel_select="vc1_decoder" +vp8_nvdec_hwaccel_deps="nvdec" +vp8_nvdec_hwaccel_select="vp8_decoder" +vp8_vaapi_hwaccel_deps="vaapi" +vp8_vaapi_hwaccel_select="vp8_decoder" +vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9" +vp9_d3d11va_hwaccel_select="vp9_decoder" +vp9_d3d11va2_hwaccel_deps="d3d11va DXVA_PicParams_VP9" +vp9_d3d11va2_hwaccel_select="vp9_decoder" +vp9_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_VP9" +vp9_dxva2_hwaccel_select="vp9_decoder" +vp9_nvdec_hwaccel_deps="nvdec" +vp9_nvdec_hwaccel_select="vp9_decoder" +vp9_vaapi_hwaccel_deps="vaapi VADecPictureParameterBufferVP9_bit_depth" +vp9_vaapi_hwaccel_select="vp9_decoder" +wmv3_d3d11va_hwaccel_select="vc1_d3d11va_hwaccel" +wmv3_d3d11va2_hwaccel_select="vc1_d3d11va2_hwaccel" +wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel" +wmv3_nvdec_hwaccel_select="vc1_nvdec_hwaccel" +wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" +wmv3_vdpau_hwaccel_select="vc1_vdpau_hwaccel" + +# hardware-accelerated codecs +omx_deps="libdl pthreads" +omx_rpi_select="omx" +qsv_deps="libmfx" +qsvdec_select="qsv" +qsvenc_select="qsv" +qsvvpp_select="qsv" +vaapi_encode_deps="vaapi" +v4l2_m2m_deps="linux_videodev2_h sem_timedwait" + +hwupload_cuda_filter_deps="ffnvcodec" +scale_npp_filter_deps="ffnvcodec libnpp" +scale_cuda_filter_deps="ffnvcodec" +scale_cuda_filter_deps_any="cuda_nvcc cuda_llvm" +thumbnail_cuda_filter_deps="ffnvcodec" +thumbnail_cuda_filter_deps_any="cuda_nvcc cuda_llvm" +transpose_npp_filter_deps="ffnvcodec libnpp" + +amf_deps_any="libdl LoadLibrary" +nvenc_deps="ffnvcodec" +nvenc_deps_any="libdl LoadLibrary" +nvenc_encoder_deps="nvenc" + +h263_v4l2m2m_decoder_deps="v4l2_m2m h263_v4l2_m2m" +h263_v4l2m2m_encoder_deps="v4l2_m2m h263_v4l2_m2m" +h264_amf_encoder_deps="amf" +h264_crystalhd_decoder_select="crystalhd h264_mp4toannexb_bsf h264_parser" +h264_cuvid_decoder_deps="cuvid" +h264_cuvid_decoder_select="h264_mp4toannexb_bsf" +h264_mediacodec_decoder_deps="mediacodec" +h264_mediacodec_decoder_select="h264_mp4toannexb_bsf h264_parser" +h264_mmal_decoder_deps="mmal" +h264_nvenc_encoder_deps="nvenc" +h264_omx_encoder_deps="omx" +h264_qsv_decoder_select="h264_mp4toannexb_bsf h264_parser qsvdec" +h264_qsv_encoder_select="qsvenc" +h264_rkmpp_decoder_deps="rkmpp" +h264_rkmpp_decoder_select="h264_mp4toannexb_bsf" +h264_vaapi_encoder_select="cbs_h264 vaapi_encode" +h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m" +h264_v4l2m2m_decoder_select="h264_mp4toannexb_bsf" +h264_v4l2m2m_encoder_deps="v4l2_m2m h264_v4l2_m2m" +hevc_amf_encoder_deps="amf" +hevc_cuvid_decoder_deps="cuvid" +hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf" +hevc_mediacodec_decoder_deps="mediacodec" +hevc_mediacodec_decoder_select="hevc_mp4toannexb_bsf hevc_parser" +hevc_nvenc_encoder_deps="nvenc" +hevc_qsv_decoder_select="hevc_mp4toannexb_bsf hevc_parser qsvdec" +hevc_qsv_encoder_select="hevcparse qsvenc" +hevc_rkmpp_decoder_deps="rkmpp" +hevc_rkmpp_decoder_select="hevc_mp4toannexb_bsf" +hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC" +hevc_vaapi_encoder_select="cbs_h265 vaapi_encode" +hevc_v4l2m2m_decoder_deps="v4l2_m2m hevc_v4l2_m2m" +hevc_v4l2m2m_decoder_select="hevc_mp4toannexb_bsf" +hevc_v4l2m2m_encoder_deps="v4l2_m2m hevc_v4l2_m2m" +mjpeg_cuvid_decoder_deps="cuvid" +mjpeg_qsv_encoder_deps="libmfx" +mjpeg_qsv_encoder_select="qsvenc" +mjpeg_vaapi_encoder_deps="VAEncPictureParameterBufferJPEG" +mjpeg_vaapi_encoder_select="cbs_jpeg jpegtables vaapi_encode" +mpeg1_cuvid_decoder_deps="cuvid" +mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m" +mpeg2_crystalhd_decoder_select="crystalhd" +mpeg2_cuvid_decoder_deps="cuvid" +mpeg2_mmal_decoder_deps="mmal" +mpeg2_mediacodec_decoder_deps="mediacodec" +mpeg2_qsv_decoder_select="qsvdec mpegvideo_parser" +mpeg2_qsv_encoder_select="qsvenc" +mpeg2_vaapi_encoder_select="cbs_mpeg2 vaapi_encode" +mpeg2_v4l2m2m_decoder_deps="v4l2_m2m mpeg2_v4l2_m2m" +mpeg4_crystalhd_decoder_select="crystalhd" +mpeg4_cuvid_decoder_deps="cuvid" +mpeg4_mediacodec_decoder_deps="mediacodec" +mpeg4_mmal_decoder_deps="mmal" +mpeg4_omx_encoder_deps="omx" +mpeg4_v4l2m2m_decoder_deps="v4l2_m2m mpeg4_v4l2_m2m" +mpeg4_v4l2m2m_encoder_deps="v4l2_m2m mpeg4_v4l2_m2m" +msmpeg4_crystalhd_decoder_select="crystalhd" +nvenc_h264_encoder_select="h264_nvenc_encoder" +nvenc_hevc_encoder_select="hevc_nvenc_encoder" +vc1_crystalhd_decoder_select="crystalhd" +vc1_cuvid_decoder_deps="cuvid" +vc1_mmal_decoder_deps="mmal" +vc1_qsv_decoder_select="qsvdec vc1_parser" +vc1_v4l2m2m_decoder_deps="v4l2_m2m vc1_v4l2_m2m" +vp8_cuvid_decoder_deps="cuvid" +vp8_mediacodec_decoder_deps="mediacodec" +vp8_qsv_decoder_select="qsvdec vp8_parser" +vp8_rkmpp_decoder_deps="rkmpp" +vp8_vaapi_encoder_deps="VAEncPictureParameterBufferVP8" +vp8_vaapi_encoder_select="vaapi_encode" +vp8_v4l2m2m_decoder_deps="v4l2_m2m vp8_v4l2_m2m" +vp8_v4l2m2m_encoder_deps="v4l2_m2m vp8_v4l2_m2m" +vp9_cuvid_decoder_deps="cuvid" +vp9_mediacodec_decoder_deps="mediacodec" +vp9_rkmpp_decoder_deps="rkmpp" +vp9_vaapi_encoder_deps="VAEncPictureParameterBufferVP9" +vp9_vaapi_encoder_select="vaapi_encode" +vp9_v4l2m2m_decoder_deps="v4l2_m2m vp9_v4l2_m2m" +wmv3_crystalhd_decoder_select="crystalhd" + +# parsers +aac_parser_select="adts_header" +av1_parser_select="cbs_av1" +h264_parser_select="golomb h264dsp h264parse" +hevc_parser_select="hevcparse" +mpegaudio_parser_select="mpegaudioheader" +mpegvideo_parser_select="mpegvideo" +mpeg4video_parser_select="h263dsp mpegvideo qpeldsp" +vc1_parser_select="vc1dsp" + +# bitstream_filters +aac_adtstoasc_bsf_select="adts_header" +av1_frame_split_bsf_select="cbs_av1" +av1_metadata_bsf_select="cbs_av1" +eac3_core_bsf_select="ac3_parser" +filter_units_bsf_select="cbs" +h264_metadata_bsf_deps="const_nan" +h264_metadata_bsf_select="cbs_h264" +h264_redundant_pps_bsf_select="cbs_h264" +hevc_metadata_bsf_select="cbs_h265" +mjpeg2jpeg_bsf_select="jpegtables" +mpeg2_metadata_bsf_select="cbs_mpeg2" +trace_headers_bsf_select="cbs" +vp9_metadata_bsf_select="cbs_vp9" + +# external libraries +aac_at_decoder_deps="audiotoolbox" +aac_at_decoder_select="aac_adtstoasc_bsf" +ac3_at_decoder_deps="audiotoolbox" +ac3_at_decoder_select="ac3_parser" +adpcm_ima_qt_at_decoder_deps="audiotoolbox" +alac_at_decoder_deps="audiotoolbox" +amr_nb_at_decoder_deps="audiotoolbox" +avisynth_deps_any="libdl LoadLibrary" +avisynth_demuxer_deps="avisynth" +avisynth_demuxer_select="riffdec" +eac3_at_decoder_deps="audiotoolbox" +eac3_at_decoder_select="ac3_parser" +gsm_ms_at_decoder_deps="audiotoolbox" +ilbc_at_decoder_deps="audiotoolbox" +mp1_at_decoder_deps="audiotoolbox" +mp2_at_decoder_deps="audiotoolbox" +mp3_at_decoder_deps="audiotoolbox" +mp1_at_decoder_select="mpegaudioheader" +mp2_at_decoder_select="mpegaudioheader" +mp3_at_decoder_select="mpegaudioheader" +pcm_alaw_at_decoder_deps="audiotoolbox" +pcm_mulaw_at_decoder_deps="audiotoolbox" +qdmc_at_decoder_deps="audiotoolbox" +qdm2_at_decoder_deps="audiotoolbox" +aac_at_encoder_deps="audiotoolbox" +aac_at_encoder_select="audio_frame_queue" +alac_at_encoder_deps="audiotoolbox" +alac_at_encoder_select="audio_frame_queue" +ilbc_at_encoder_deps="audiotoolbox" +ilbc_at_encoder_select="audio_frame_queue" +pcm_alaw_at_encoder_deps="audiotoolbox" +pcm_alaw_at_encoder_select="audio_frame_queue" +pcm_mulaw_at_encoder_deps="audiotoolbox" +pcm_mulaw_at_encoder_select="audio_frame_queue" +chromaprint_muxer_deps="chromaprint" +h264_videotoolbox_encoder_deps="pthreads" +h264_videotoolbox_encoder_select="videotoolbox_encoder" +hevc_videotoolbox_encoder_deps="pthreads" +hevc_videotoolbox_encoder_select="videotoolbox_encoder" +libaom_av1_decoder_deps="libaom" +libaom_av1_encoder_deps="libaom" +libaom_av1_encoder_select="extract_extradata_bsf" +libaribb24_decoder_deps="libaribb24" +libcelt_decoder_deps="libcelt" +libcodec2_decoder_deps="libcodec2" +libcodec2_encoder_deps="libcodec2" +libdav1d_decoder_deps="libdav1d" +libdavs2_decoder_deps="libdavs2" +libfdk_aac_decoder_deps="libfdk_aac" +libfdk_aac_encoder_deps="libfdk_aac" +libfdk_aac_encoder_select="audio_frame_queue" +libgme_demuxer_deps="libgme" +libgsm_decoder_deps="libgsm" +libgsm_encoder_deps="libgsm" +libgsm_ms_decoder_deps="libgsm" +libgsm_ms_encoder_deps="libgsm" +libilbc_decoder_deps="libilbc" +libilbc_encoder_deps="libilbc" +libkvazaar_encoder_deps="libkvazaar" +libmodplug_demuxer_deps="libmodplug" +libmp3lame_encoder_deps="libmp3lame" +libmp3lame_encoder_select="audio_frame_queue mpegaudioheader" +libopencore_amrnb_decoder_deps="libopencore_amrnb" +libopencore_amrnb_encoder_deps="libopencore_amrnb" +libopencore_amrnb_encoder_select="audio_frame_queue" +libopencore_amrwb_decoder_deps="libopencore_amrwb" +libopenh264_decoder_deps="libopenh264" +libopenh264_decoder_select="h264_mp4toannexb_bsf" +libopenh264_encoder_deps="libopenh264" +libopenjpeg_decoder_deps="libopenjpeg" +libopenjpeg_encoder_deps="libopenjpeg" +libopenmpt_demuxer_deps="libopenmpt" +libopus_decoder_deps="libopus" +libopus_encoder_deps="libopus" +libopus_encoder_select="audio_frame_queue" +librsvg_decoder_deps="librsvg" +libshine_encoder_deps="libshine" +libshine_encoder_select="audio_frame_queue" +libspeex_decoder_deps="libspeex" +libspeex_encoder_deps="libspeex" +libspeex_encoder_select="audio_frame_queue" +libtheora_encoder_deps="libtheora" +libtwolame_encoder_deps="libtwolame" +libvo_amrwbenc_encoder_deps="libvo_amrwbenc" +libvorbis_decoder_deps="libvorbis" +libvorbis_encoder_deps="libvorbis libvorbisenc" +libvorbis_encoder_select="audio_frame_queue" +libvpx_vp8_decoder_deps="libvpx" +libvpx_vp8_encoder_deps="libvpx" +libvpx_vp9_decoder_deps="libvpx" +libvpx_vp9_encoder_deps="libvpx" +libwavpack_encoder_deps="libwavpack" +libwavpack_encoder_select="audio_frame_queue" +libwebp_encoder_deps="libwebp" +libwebp_anim_encoder_deps="libwebp" +libx262_encoder_deps="libx262" +libx264_encoder_deps="libx264" +libx264rgb_encoder_deps="libx264 x264_csp_bgr" +libx264rgb_encoder_select="libx264_encoder" +libx265_encoder_deps="libx265" +libxavs_encoder_deps="libxavs" +libxavs2_encoder_deps="libxavs2" +libxvid_encoder_deps="libxvid" +libzvbi_teletext_decoder_deps="libzvbi" +vapoursynth_demuxer_deps="vapoursynth" +videotoolbox_suggest="coreservices" +videotoolbox_deps="corefoundation coremedia corevideo" +videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" + +# demuxers / muxers +ac3_demuxer_select="ac3_parser" +aiff_muxer_select="iso_media" +asf_demuxer_select="riffdec" +asf_o_demuxer_select="riffdec" +asf_muxer_select="riffenc" +asf_stream_muxer_select="asf_muxer" +avi_demuxer_select="iso_media riffdec exif" +avi_muxer_select="riffenc" +caf_demuxer_select="iso_media riffdec" +caf_muxer_select="iso_media" +dash_muxer_select="mp4_muxer" +dash_demuxer_deps="libxml2" +dirac_demuxer_select="dirac_parser" +dts_demuxer_select="dca_parser" +dtshd_demuxer_select="dca_parser" +dv_demuxer_select="dvprofile" +dv_muxer_select="dvprofile" +dxa_demuxer_select="riffdec" +eac3_demuxer_select="ac3_parser" +f4v_muxer_select="mov_muxer" +fifo_muxer_deps="threads" +flac_demuxer_select="flac_parser" +hds_muxer_select="flv_muxer" +hls_muxer_select="mpegts_muxer" +hls_muxer_suggest="gcrypt openssl" +image2_alias_pix_demuxer_select="image2_demuxer" +image2_brender_pix_demuxer_select="image2_demuxer" +ipod_muxer_select="mov_muxer" +ismv_muxer_select="mov_muxer" +ivf_muxer_select="av1_metadata_bsf vp9_superframe_bsf" +matroska_audio_muxer_select="matroska_muxer" +matroska_demuxer_select="iso_media riffdec" +matroska_demuxer_suggest="bzlib lzo zlib" +matroska_muxer_select="iso_media riffenc" +mmf_muxer_select="riffenc" +mov_demuxer_select="iso_media riffdec" +mov_demuxer_suggest="zlib" +mov_muxer_select="iso_media riffenc rtpenc_chain" +mp3_demuxer_select="mpegaudio_parser" +mp3_muxer_select="mpegaudioheader" +mp4_muxer_select="mov_muxer" +mpegts_demuxer_select="iso_media" +mpegts_muxer_select="adts_muxer latm_muxer" +mpegtsraw_demuxer_select="mpegts_demuxer" +mxf_d10_muxer_select="mxf_muxer" +mxf_opatom_muxer_select="mxf_muxer" +nut_muxer_select="riffenc" +nuv_demuxer_select="riffdec" +oga_muxer_select="ogg_muxer" +ogg_demuxer_select="dirac_parse" +ogv_muxer_select="ogg_muxer" +opus_muxer_select="ogg_muxer" +psp_muxer_select="mov_muxer" +rtp_demuxer_select="sdp_demuxer" +rtp_muxer_select="golomb" +rtpdec_select="asf_demuxer jpegtables mov_demuxer mpegts_demuxer rm_demuxer rtp_protocol srtp" +rtsp_demuxer_select="http_protocol rtpdec" +rtsp_muxer_select="rtp_muxer http_protocol rtp_protocol rtpenc_chain" +sap_demuxer_select="sdp_demuxer" +sap_muxer_select="rtp_muxer rtp_protocol rtpenc_chain" +sdp_demuxer_select="rtpdec" +smoothstreaming_muxer_select="ismv_muxer" +spdif_demuxer_select="adts_header" +spdif_muxer_select="adts_header" +spx_muxer_select="ogg_muxer" +swf_demuxer_suggest="zlib" +tak_demuxer_select="tak_parser" +tg2_muxer_select="mov_muxer" +tgp_muxer_select="mov_muxer" +vobsub_demuxer_select="mpegps_demuxer" +w64_demuxer_select="wav_demuxer" +w64_muxer_select="wav_muxer" +wav_demuxer_select="riffdec" +wav_muxer_select="riffenc" +webm_muxer_select="iso_media riffenc" +webm_dash_manifest_demuxer_select="matroska_demuxer" +wtv_demuxer_select="mpegts_demuxer riffdec" +wtv_muxer_select="mpegts_muxer riffenc" +xmv_demuxer_select="riffdec" +xwma_demuxer_select="riffdec" + +# indevs / outdevs +android_camera_indev_deps="android camera2ndk mediandk pthreads" +android_camera_indev_extralibs="-landroid -lcamera2ndk -lmediandk" +alsa_indev_deps="alsa" +alsa_outdev_deps="alsa" +avfoundation_indev_deps="avfoundation corevideo coremedia pthreads" +avfoundation_indev_suggest="coregraphics applicationservices" +avfoundation_indev_extralibs="-framework Foundation" +bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" +caca_outdev_deps="libcaca" +decklink_deps_any="libdl LoadLibrary" +decklink_indev_deps="decklink threads" +decklink_indev_extralibs="-lstdc++" +decklink_outdev_deps="decklink threads" +decklink_outdev_suggest="libklvanc" +decklink_outdev_extralibs="-lstdc++" +dshow_indev_deps="IBaseFilter" +dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid -loleaut32 -lshlwapi" +fbdev_indev_deps="linux_fb_h" +fbdev_outdev_deps="linux_fb_h" +gdigrab_indev_deps="CreateDIBSection" +gdigrab_indev_extralibs="-lgdi32" +gdigrab_indev_select="bmp_decoder" +iec61883_indev_deps="libiec61883" +jack_indev_deps="libjack" +jack_indev_deps_any="sem_timedwait dispatch_dispatch_h" +kmsgrab_indev_deps="libdrm" +lavfi_indev_deps="avfilter" +libcdio_indev_deps="libcdio" +libdc1394_indev_deps="libdc1394" +openal_indev_deps="openal" +opengl_outdev_deps="opengl" +opengl_outdev_suggest="sdl2" +oss_indev_deps_any="sys_soundcard_h" +oss_outdev_deps_any="sys_soundcard_h" +pulse_indev_deps="libpulse" +pulse_outdev_deps="libpulse" +sdl2_outdev_deps="sdl2" +sndio_indev_deps="sndio" +sndio_outdev_deps="sndio" +v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h" +v4l2_indev_suggest="libv4l2" +v4l2_outdev_deps_any="linux_videodev2_h sys_videoio_h" +v4l2_outdev_suggest="libv4l2" +vfwcap_indev_deps="vfw32 vfwcap_defines" +xcbgrab_indev_deps="libxcb" +xcbgrab_indev_suggest="libxcb_shm libxcb_shape libxcb_xfixes" +xv_outdev_deps="xlib" + +# protocols +async_protocol_deps="threads" +bluray_protocol_deps="libbluray" +ffrtmpcrypt_protocol_conflict="librtmp_protocol" +ffrtmpcrypt_protocol_deps_any="gcrypt gmp openssl mbedtls" +ffrtmpcrypt_protocol_select="tcp_protocol" +ffrtmphttp_protocol_conflict="librtmp_protocol" +ffrtmphttp_protocol_select="http_protocol" +ftp_protocol_select="tcp_protocol" +gopher_protocol_select="network" +http_protocol_select="tcp_protocol" +http_protocol_suggest="zlib" +httpproxy_protocol_select="tcp_protocol" +httpproxy_protocol_suggest="zlib" +https_protocol_select="tls_protocol" +https_protocol_suggest="zlib" +icecast_protocol_select="http_protocol" +mmsh_protocol_select="http_protocol" +mmst_protocol_select="network" +rtmp_protocol_conflict="librtmp_protocol" +rtmp_protocol_select="tcp_protocol" +rtmp_protocol_suggest="zlib" +rtmpe_protocol_select="ffrtmpcrypt_protocol" +rtmpe_protocol_suggest="zlib" +rtmps_protocol_conflict="librtmp_protocol" +rtmps_protocol_select="tls_protocol" +rtmps_protocol_suggest="zlib" +rtmpt_protocol_select="ffrtmphttp_protocol" +rtmpt_protocol_suggest="zlib" +rtmpte_protocol_select="ffrtmpcrypt_protocol ffrtmphttp_protocol" +rtmpte_protocol_suggest="zlib" +rtmpts_protocol_select="ffrtmphttp_protocol https_protocol" +rtmpts_protocol_suggest="zlib" +rtp_protocol_select="udp_protocol" +schannel_conflict="openssl gnutls libtls mbedtls" +sctp_protocol_deps="struct_sctp_event_subscribe struct_msghdr_msg_flags" +sctp_protocol_select="network" +securetransport_conflict="openssl gnutls libtls mbedtls" +srtp_protocol_select="rtp_protocol srtp" +tcp_protocol_select="network" +tls_protocol_deps_any="gnutls openssl schannel securetransport libtls mbedtls" +tls_protocol_select="tcp_protocol" +udp_protocol_select="network" +udplite_protocol_select="network" +unix_protocol_deps="sys_un_h" +unix_protocol_select="network" + +# external library protocols +librtmp_protocol_deps="librtmp" +librtmpe_protocol_deps="librtmp" +librtmps_protocol_deps="librtmp" +librtmpt_protocol_deps="librtmp" +librtmpte_protocol_deps="librtmp" +libsmbclient_protocol_deps="libsmbclient gplv3" +libsrt_protocol_deps="libsrt" +libsrt_protocol_select="network" +libssh_protocol_deps="libssh" +libtls_conflict="openssl gnutls mbedtls" + +# filters +afftdn_filter_deps="avcodec" +afftdn_filter_select="fft" +afftfilt_filter_deps="avcodec" +afftfilt_filter_select="fft" +afir_filter_deps="avcodec" +afir_filter_select="fft" +amovie_filter_deps="avcodec avformat" +aresample_filter_deps="swresample" +asr_filter_deps="pocketsphinx" +ass_filter_deps="libass" +atempo_filter_deps="avcodec" +atempo_filter_select="rdft" +avgblur_opencl_filter_deps="opencl" +azmq_filter_deps="libzmq" +blackframe_filter_deps="gpl" +bm3d_filter_deps="avcodec" +bm3d_filter_select="dct" +boxblur_filter_deps="gpl" +boxblur_opencl_filter_deps="opencl gpl" +bs2b_filter_deps="libbs2b" +colorkey_opencl_filter_deps="opencl" +colormatrix_filter_deps="gpl" +convolution_opencl_filter_deps="opencl" +convolve_filter_deps="avcodec" +convolve_filter_select="fft" +coreimage_filter_deps="coreimage appkit" +coreimage_filter_extralibs="-framework OpenGL" +coreimagesrc_filter_deps="coreimage appkit" +coreimagesrc_filter_extralibs="-framework OpenGL" +cover_rect_filter_deps="avcodec avformat gpl" +cropdetect_filter_deps="gpl" +deconvolve_filter_deps="avcodec" +deconvolve_filter_select="fft" +deinterlace_qsv_filter_deps="libmfx" +deinterlace_vaapi_filter_deps="vaapi" +delogo_filter_deps="gpl" +denoise_vaapi_filter_deps="vaapi" +derain_filter_select="dnn" +deshake_filter_select="pixelutils" +dilation_opencl_filter_deps="opencl" +drawtext_filter_deps="libfreetype" +drawtext_filter_suggest="libfontconfig libfribidi" +elbg_filter_deps="avcodec" +eq_filter_deps="gpl" +erosion_opencl_filter_deps="opencl" +fftfilt_filter_deps="avcodec" +fftfilt_filter_select="rdft" +fftdnoiz_filter_deps="avcodec" +fftdnoiz_filter_select="fft" +find_rect_filter_deps="avcodec avformat gpl" +firequalizer_filter_deps="avcodec" +firequalizer_filter_select="rdft" +flite_filter_deps="libflite" +framerate_filter_select="scene_sad" +freezedetect_filter_select="scene_sad" +frei0r_filter_deps="frei0r libdl" +frei0r_src_filter_deps="frei0r libdl" +fspp_filter_deps="gpl" +geq_filter_deps="gpl" +histeq_filter_deps="gpl" +hqdn3d_filter_deps="gpl" +interlace_filter_deps="gpl" +kerndeint_filter_deps="gpl" +ladspa_filter_deps="ladspa libdl" +lensfun_filter_deps="liblensfun version3" +lv2_filter_deps="lv2" +mcdeint_filter_deps="avcodec gpl" +movie_filter_deps="avcodec avformat" +mpdecimate_filter_deps="gpl" +mpdecimate_filter_select="pixelutils" +minterpolate_filter_select="scene_sad" +mptestsrc_filter_deps="gpl" +negate_filter_deps="lut_filter" +nlmeans_opencl_filter_deps="opencl" +nnedi_filter_deps="gpl" +ocr_filter_deps="libtesseract" +ocv_filter_deps="libopencv" +openclsrc_filter_deps="opencl" +overlay_opencl_filter_deps="opencl" +overlay_qsv_filter_deps="libmfx" +overlay_qsv_filter_select="qsvvpp" +owdenoise_filter_deps="gpl" +pan_filter_deps="swresample" +perspective_filter_deps="gpl" +phase_filter_deps="gpl" +pp7_filter_deps="gpl" +pp_filter_deps="gpl postproc" +prewitt_opencl_filter_deps="opencl" +procamp_vaapi_filter_deps="vaapi" +program_opencl_filter_deps="opencl" +pullup_filter_deps="gpl" +removelogo_filter_deps="avcodec avformat swscale" +repeatfields_filter_deps="gpl" +resample_filter_deps="avresample" +roberts_opencl_filter_deps="opencl" +rubberband_filter_deps="librubberband" +sab_filter_deps="gpl swscale" +scale2ref_filter_deps="swscale" +scale_filter_deps="swscale" +scale_qsv_filter_deps="libmfx" +select_filter_select="scene_sad" +sharpness_vaapi_filter_deps="vaapi" +showcqt_filter_deps="avcodec avformat swscale" +showcqt_filter_suggest="libfontconfig libfreetype" +showcqt_filter_select="fft" +showfreqs_filter_deps="avcodec" +showfreqs_filter_select="fft" +showspectrum_filter_deps="avcodec" +showspectrum_filter_select="fft" +showspectrumpic_filter_deps="avcodec" +showspectrumpic_filter_select="fft" +signature_filter_deps="gpl avcodec avformat" +smartblur_filter_deps="gpl swscale" +sobel_opencl_filter_deps="opencl" +sofalizer_filter_deps="libmysofa avcodec" +sofalizer_filter_select="fft" +spectrumsynth_filter_deps="avcodec" +spectrumsynth_filter_select="fft" +spp_filter_deps="gpl avcodec" +spp_filter_select="fft idctdsp fdctdsp me_cmp pixblockdsp" +sr_filter_deps="avformat swscale" +sr_filter_select="dnn" +stereo3d_filter_deps="gpl" +subtitles_filter_deps="avformat avcodec libass" +super2xsai_filter_deps="gpl" +pixfmts_super2xsai_test_deps="super2xsai_filter" +tinterlace_filter_deps="gpl" +tinterlace_merge_test_deps="tinterlace_filter" +tinterlace_pad_test_deps="tinterlace_filter" +tonemap_filter_deps="const_nan" +tonemap_opencl_filter_deps="opencl const_nan" +transpose_opencl_filter_deps="opencl" +transpose_vaapi_filter_deps="vaapi VAProcPipelineCaps_rotation_flags" +unsharp_opencl_filter_deps="opencl" +uspp_filter_deps="gpl avcodec" +vaguedenoiser_filter_deps="gpl" +vidstabdetect_filter_deps="libvidstab" +vidstabtransform_filter_deps="libvidstab" +libvmaf_filter_deps="libvmaf pthreads" +zmq_filter_deps="libzmq" +zoompan_filter_deps="swscale" +zscale_filter_deps="libzimg const_nan" +scale_vaapi_filter_deps="vaapi" +vpp_qsv_filter_deps="libmfx" +vpp_qsv_filter_select="qsvvpp" +yadif_cuda_filter_deps="ffnvcodec" +yadif_cuda_filter_deps_any="cuda_nvcc cuda_llvm" + +# examples +avio_dir_cmd_deps="avformat avutil" +avio_reading_deps="avformat avcodec avutil" +decode_audio_example_deps="avcodec avutil" +decode_video_example_deps="avcodec avutil" +demuxing_decoding_example_deps="avcodec avformat avutil" +encode_audio_example_deps="avcodec avutil" +encode_video_example_deps="avcodec avutil" +extract_mvs_example_deps="avcodec avformat avutil" +filter_audio_example_deps="avfilter avutil" +filtering_audio_example_deps="avfilter avcodec avformat avutil" +filtering_video_example_deps="avfilter avcodec avformat avutil" +http_multiclient_example_deps="avformat avutil fork" +hw_decode_example_deps="avcodec avformat avutil" +metadata_example_deps="avformat avutil" +muxing_example_deps="avcodec avformat avutil swscale" +qsvdec_example_deps="avcodec avutil libmfx h264_qsv_decoder" +remuxing_example_deps="avcodec avformat avutil" +resampling_audio_example_deps="avutil swresample" +scaling_video_example_deps="avutil swscale" +transcode_aac_example_deps="avcodec avformat swresample" +transcoding_example_deps="avfilter avcodec avformat avutil" +vaapi_encode_example_deps="avcodec avutil h264_vaapi_encoder" +vaapi_transcode_example_deps="avcodec avformat avutil h264_vaapi_encoder" + +# EXTRALIBS_LIST +cpu_init_extralibs="pthreads_extralibs" +cws2fws_extralibs="zlib_extralibs" + +# libraries, in any order +avcodec_deps="avutil" +avcodec_suggest="libm" +avcodec_select="null_bsf" +avdevice_deps="avformat avcodec avutil" +avdevice_suggest="libm" +avfilter_deps="avutil" +avfilter_suggest="libm" +avformat_deps="avcodec avutil" +avformat_suggest="libm network zlib" +avresample_deps="avutil" +avresample_suggest="libm" +avutil_suggest="clock_gettime ffnvcodec libm libdrm libmfx opencl user32 vaapi videotoolbox corefoundation corevideo coremedia bcrypt" +postproc_deps="avutil gpl" +postproc_suggest="libm" +swresample_deps="avutil" +swresample_suggest="libm libsoxr" +swscale_deps="avutil" +swscale_suggest="libm" + +avcodec_extralibs="pthreads_extralibs iconv_extralibs dxva2_extralibs" +avfilter_extralibs="pthreads_extralibs" +avutil_extralibs="d3d11va_extralibs nanosleep_extralibs pthreads_extralibs vaapi_drm_extralibs vaapi_x11_extralibs vdpau_x11_extralibs" + +# programs +ffmpeg_deps="avcodec avfilter avformat" +ffmpeg_select="aformat_filter anull_filter atrim_filter format_filter + hflip_filter null_filter + transpose_filter trim_filter vflip_filter" +ffmpeg_suggest="ole32 psapi shell32" +ffplay_deps="avcodec avformat swscale swresample sdl2" +ffplay_select="rdft crop_filter transpose_filter hflip_filter vflip_filter rotate_filter" +ffplay_suggest="shell32" +ffprobe_deps="avcodec avformat" +ffprobe_suggest="shell32" + +# documentation +podpages_deps="perl" +manpages_deps="perl pod2man" +htmlpages_deps="perl" +htmlpages_deps_any="makeinfo_html texi2html" +txtpages_deps="perl makeinfo" +doc_deps_any="manpages htmlpages podpages txtpages" + +# default parameters + +logfile="ffbuild/config.log" + +# installation paths +prefix_default="/usr/local" +bindir_default='${prefix}/bin' +datadir_default='${prefix}/share/ffmpeg' +docdir_default='${prefix}/share/doc/ffmpeg' +incdir_default='${prefix}/include' +libdir_default='${prefix}/lib' +mandir_default='${prefix}/share/man' + +# toolchain +ar_default="ar" +cc_default="gcc" +cxx_default="g++" +host_cc_default="gcc" +doxygen_default="doxygen" +install="install" +ln_s_default="ln -s -f" +nm_default="nm -g" +pkg_config_default=pkg-config +ranlib_default="ranlib" +strip_default="strip" +version_script='--version-script' +objformat="elf32" +x86asmexe_default="nasm" +windres_default="windres" +striptype="direct" + +# OS +target_os_default=$(tolower $(uname -s)) +host_os=$target_os_default + +# machine +if test "$target_os_default" = aix; then + arch_default=$(uname -p) + strip_default="strip -X32_64" + nm_default="nm -g -X32_64" +else + arch_default=$(uname -m) +fi +cpu="generic" +intrinsics="none" + +# configurable options +enable $PROGRAM_LIST +enable $DOCUMENT_LIST +enable $EXAMPLE_LIST +enable $(filter_out avresample $LIBRARY_LIST) +enable stripping + +enable asm +enable debug +enable doc +enable faan faandct faanidct +enable optimizations +enable runtime_cpudetect +enable safe_bitstream_reader +enable static +enable swscale_alpha +enable valgrind_backtrace + +sws_max_filter_size_default=256 +set_default sws_max_filter_size + +# internal components are enabled by default +enable $EXTRALIBS_LIST + +# Avoid external, non-system, libraries getting enabled by dependency resolution +disable $EXTERNAL_LIBRARY_LIST $HWACCEL_LIBRARY_LIST + +# build settings +SHFLAGS='-shared -Wl,-soname,$$(@F)' +LIBPREF="lib" +LIBSUF=".a" +FULLNAME='$(NAME)$(BUILDSUF)' +LIBNAME='$(LIBPREF)$(FULLNAME)$(LIBSUF)' +SLIBPREF="lib" +SLIBSUF=".so" +SLIBNAME='$(SLIBPREF)$(FULLNAME)$(SLIBSUF)' +SLIBNAME_WITH_VERSION='$(SLIBNAME).$(LIBVERSION)' +SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)' +LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"' +SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)' +SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)' +VERSION_SCRIPT_POSTPROCESS_CMD="cat" + +asflags_filter=echo +cflags_filter=echo +ldflags_filter=echo + +AS_C='-c' +AS_O='-o $@' +CC_C='-c' +CC_E='-E -o $@' +CC_O='-o $@' +CXX_C='-c' +CXX_O='-o $@' +OBJCC_C='-c' +OBJCC_E='-E -o $@' +OBJCC_O='-o $@' +X86ASM_O='-o $@' +LD_O='-o $@' +LD_LIB='-l%' +LD_PATH='-L' +HOSTCC_C='-c' +HOSTCC_E='-E -o $@' +HOSTCC_O='-o $@' +HOSTLD_O='-o $@' +NVCC_C='-c' +NVCC_O='-o $@' + +host_extralibs='-lm' +host_cflags_filter=echo +host_ldflags_filter=echo + +target_path='$(CURDIR)' + +# since the object filename is not given with the -MM flag, the compiler +# is only able to print the basename, and we must add the path ourselves +DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>/dev/null | sed -e "/^\#.*/d" -e "s,^[[:space:]]*$(@F),$(@D)/$(@F)," > $(@:.o=.d)' +DEPFLAGS='-MM' + +mkdir -p ffbuild + +# find source path +if test -f configure; then + source_path=. +elif test -f src/configure; then + source_path=src +else + source_path=$(cd $(dirname "$0"); pwd) + case "$source_path" in + *[[:blank:]]*) die "Out of tree builds are impossible with whitespace in source path." ;; + esac + test -e "$source_path/config.h" && + die "Out of tree builds are impossible with config.h in source dir." +fi + +for v in "$@"; do + r=${v#*=} + l=${v%"$r"} + r=$(sh_quote "$r") + FFMPEG_CONFIGURATION="${FFMPEG_CONFIGURATION# } ${l}${r}" +done + +find_things_extern(){ + thing=$1 + pattern=$2 + file=$source_path/$3 + out=${4:-$thing} + sed -n "s/^[^#]*extern.*$pattern *ff_\([^ ]*\)_$thing;/\1_$out/p" "$file" +} + +find_filters_extern(){ + file=$source_path/$1 + sed -n 's/^extern AVFilter ff_[avfsinkrc]\{2,5\}_\([[:alnum:]_]\{1,\}\);/\1_filter/p' $file +} + +FILTER_LIST=$(find_filters_extern libavfilter/allfilters.c) +OUTDEV_LIST=$(find_things_extern muxer AVOutputFormat libavdevice/alldevices.c outdev) +INDEV_LIST=$(find_things_extern demuxer AVInputFormat libavdevice/alldevices.c indev) +MUXER_LIST=$(find_things_extern muxer AVOutputFormat libavformat/allformats.c) +DEMUXER_LIST=$(find_things_extern demuxer AVInputFormat libavformat/allformats.c) +ENCODER_LIST=$(find_things_extern encoder AVCodec libavcodec/allcodecs.c) +DECODER_LIST=$(find_things_extern decoder AVCodec libavcodec/allcodecs.c) +CODEC_LIST=" + $ENCODER_LIST + $DECODER_LIST +" +PARSER_LIST=$(find_things_extern parser AVCodecParser libavcodec/parsers.c) +BSF_LIST=$(find_things_extern bsf AVBitStreamFilter libavcodec/bitstream_filters.c) +HWACCEL_LIST=$(find_things_extern hwaccel AVHWAccel libavcodec/hwaccels.h) +PROTOCOL_LIST=$(find_things_extern protocol URLProtocol libavformat/protocols.c) + +AVCODEC_COMPONENTS_LIST=" + $BSF_LIST + $DECODER_LIST + $ENCODER_LIST + $HWACCEL_LIST + $PARSER_LIST +" + +AVDEVICE_COMPONENTS_LIST=" + $INDEV_LIST + $OUTDEV_LIST +" + +AVFILTER_COMPONENTS_LIST=" + $FILTER_LIST +" + +AVFORMAT_COMPONENTS_LIST=" + $DEMUXER_LIST + $MUXER_LIST + $PROTOCOL_LIST +" + +ALL_COMPONENTS=" + $AVCODEC_COMPONENTS_LIST + $AVDEVICE_COMPONENTS_LIST + $AVFILTER_COMPONENTS_LIST + $AVFORMAT_COMPONENTS_LIST +" + +for n in $COMPONENT_LIST; do + v=$(toupper ${n%s})_LIST + eval enable \$$v + eval ${n}_if_any="\$$v" +done + +enable $ARCH_EXT_LIST + +die_unknown(){ + echo "Unknown option \"$1\"." + echo "See $0 --help for available options." + exit 1 +} + +print_in_columns() { + tr ' ' '\n' | sort | tr '\r\n' ' ' | awk -v col_width=24 -v width="$ncols" ' + { + num_cols = width > col_width ? int(width / col_width) : 1; + num_rows = int((NF + num_cols-1) / num_cols); + y = x = 1; + for (y = 1; y <= num_rows; y++) { + i = y; + for (x = 1; x <= num_cols; x++) { + if (i <= NF) { + line = sprintf("%s%-" col_width "s", line, $i); + } + i = i + num_rows; + } + print line; line = ""; + } + }' | sed 's/ *$//' +} + +show_list() { + suffix=_$1 + shift + echo $* | sed s/$suffix//g | print_in_columns + exit 0 +} + +rand_list(){ + IFS=', ' + set -- $* + unset IFS + for thing; do + comp=${thing%:*} + prob=${thing#$comp} + prob=${prob#:} + is_in ${comp} $COMPONENT_LIST && eval comp=\$$(toupper ${comp%s})_LIST + echo "prob ${prob:-0.5}" + printf '%s\n' $comp + done +} + +do_random(){ + action=$1 + shift + random_seed=$(awk "BEGIN { srand($random_seed); print srand() }") + $action $(rand_list "$@" | awk "BEGIN { srand($random_seed) } \$1 == \"prob\" { prob = \$2; next } rand() < prob { print }") +} + +for opt do + optval="${opt#*=}" + case "$opt" in + --extra-ldflags=*) + add_ldflags $optval + ;; + --extra-ldexeflags=*) + add_ldexeflags $optval + ;; + --extra-ldsoflags=*) + add_ldsoflags $optval + ;; + --extra-ldlibflags=*) + warn "The --extra-ldlibflags option is only provided for compatibility and will be\n"\ + "removed in the future. Use --extra-ldsoflags instead." + add_ldsoflags $optval + ;; + --extra-libs=*) + add_extralibs $optval + ;; + --disable-devices) + disable $INDEV_LIST $OUTDEV_LIST + ;; + --enable-debug=*) + debuglevel="$optval" + ;; + --disable-programs) + disable $PROGRAM_LIST + ;; + --disable-everything) + map 'eval unset \${$(toupper ${v%s})_LIST}' $COMPONENT_LIST + ;; + --disable-all) + map 'eval unset \${$(toupper ${v%s})_LIST}' $COMPONENT_LIST + disable $LIBRARY_LIST $PROGRAM_LIST doc + enable avutil + ;; + --enable-random|--disable-random) + action=${opt%%-random} + do_random ${action#--} $COMPONENT_LIST + ;; + --enable-random=*|--disable-random=*) + action=${opt%%-random=*} + do_random ${action#--} $optval + ;; + --enable-sdl) + enable sdl2 + ;; + --enable-*=*|--disable-*=*) + eval $(echo "${opt%%=*}" | sed 's/--/action=/;s/-/ thing=/') + is_in "${thing}s" $COMPONENT_LIST || die_unknown "$opt" + eval list=\$$(toupper $thing)_LIST + name=$(echo "${optval}" | sed "s/,/_${thing}|/g")_${thing} + list=$(filter "$name" $list) + [ "$list" = "" ] && warn "Option $opt did not match anything" + test $action = enable && warn_if_gets_disabled $list + $action $list + ;; + --enable-yasm|--disable-yasm) + warn "The ${opt} option is only provided for compatibility and will be\n"\ + "removed in the future. Use --enable-x86asm / --disable-x86asm instead." + test $opt = --enable-yasm && x86asm=yes || x86asm=no + ;; + --yasmexe=*) + warn "The --yasmexe option is only provided for compatibility and will be\n"\ + "removed in the future. Use --x86asmexe instead." + x86asmexe="$optval" + ;; + --enable-?*|--disable-?*) + eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g') + if is_in $option $COMPONENT_LIST; then + test $action = disable && action=unset + eval $action \$$(toupper ${option%s})_LIST + elif is_in $option $CMDLINE_SELECT; then + $action $option + else + die_unknown $opt + fi + ;; + --list-*) + NAME="${opt#--list-}" + is_in $NAME $COMPONENT_LIST || die_unknown $opt + NAME=${NAME%s} + eval show_list $NAME \$$(toupper $NAME)_LIST + ;; + --help|-h) show_help + ;; + --quiet|-q) quiet=yes + ;; + --fatal-warnings) enable fatal_warnings + ;; + --libfuzzer=*) + libfuzzer_path="$optval" + ;; + *) + optname="${opt%%=*}" + optname="${optname#--}" + optname=$(echo "$optname" | sed 's/-/_/g') + if is_in $optname $CMDLINE_SET; then + eval $optname='$optval' + elif is_in $optname $CMDLINE_APPEND; then + append $optname "$optval" + else + die_unknown $opt + fi + ;; + esac +done + +for e in $env; do + eval "export $e" +done + +if disabled autodetect; then + + # Unless iconv is explicitely disabled by the user, we still want to probe + # for the iconv from the libc. + disabled iconv || enable libc_iconv + + disable_weak $EXTERNAL_AUTODETECT_LIBRARY_LIST + disable_weak $HWACCEL_AUTODETECT_LIBRARY_LIST +fi +# Mark specifically enabled, but normally autodetected libraries as requested. +for lib in $AUTODETECT_LIBS; do + enabled $lib && request $lib +done +#TODO: switch to $AUTODETECT_LIBS when $THREADS_LIST is supported the same way +enable_weak $EXTERNAL_AUTODETECT_LIBRARY_LIST +enable_weak $HWACCEL_AUTODETECT_LIBRARY_LIST + +disabled logging && logfile=/dev/null + +# command line configuration sanity checks + +# we need to build at least one lib type +if ! enabled_any static shared; then + cat < $logfile +set >> $logfile + +test -n "$valgrind" && toolchain="valgrind-memcheck" + +enabled ossfuzz && ! echo $CFLAGS | grep -q -- "-fsanitize=" && ! echo $CFLAGS | grep -q -- "-fcoverage-mapping" &&{ + add_cflags -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard,trace-cmp -fno-omit-frame-pointer + add_ldflags -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard,trace-cmp +} + +case "$toolchain" in + *-asan) + cc_default="${toolchain%-asan}" + add_cflags -fsanitize=address + add_ldflags -fsanitize=address + ;; + *-msan) + cc_default="${toolchain%-msan}" + add_cflags -fsanitize=memory -fsanitize-memory-track-origins + add_ldflags -fsanitize=memory + ;; + *-tsan) + cc_default="${toolchain%-tsan}" + add_cflags -fsanitize=thread + add_ldflags -fsanitize=thread + case "$toolchain" in + gcc-tsan) + add_cflags -fPIC + add_ldflags -fPIC + ;; + esac + ;; + *-usan) + cc_default="${toolchain%-usan}" + add_cflags -fsanitize=undefined + add_ldflags -fsanitize=undefined + ;; + valgrind-*) + target_exec_default="valgrind" + case "$toolchain" in + valgrind-massif) + target_exec_args="--tool=massif --alloc-fn=av_malloc --alloc-fn=av_mallocz --alloc-fn=av_calloc --alloc-fn=av_fast_padded_malloc --alloc-fn=av_fast_malloc --alloc-fn=av_realloc_f --alloc-fn=av_fast_realloc --alloc-fn=av_realloc" + ;; + valgrind-memcheck) + target_exec_args="--error-exitcode=1 --malloc-fill=0x2a --track-origins=yes --leak-check=full --gen-suppressions=all --suppressions=$source_path/tests/fate-valgrind.supp" + ;; + esac + ;; + msvc) + # Check whether the current MSVC version needs the C99 converter. + # From MSVC 2013 (compiler major version 18) onwards, it does actually + # support enough of C99 to build ffmpeg. Default to the new + # behaviour if the regexp was unable to match anything, since this + # successfully parses the version number of existing supported + # versions that require the converter (MSVC 2010 and 2012). + cl_major_ver=$(cl.exe 2>&1 | sed -n 's/.*Version \([[:digit:]]\{1,\}\)\..*/\1/p') + if [ -z "$cl_major_ver" ] || [ $cl_major_ver -ge 18 ]; then + cc_default="cl.exe" + cxx_default="cl.exe" + else + die "Unsupported MSVC version (2013 or newer required)" + fi + ld_default="$source_path/compat/windows/mslink" + nm_default="dumpbin.exe -symbols" + ar_default="lib.exe" + case "$arch" in + aarch64|arm64) + as_default="armasm64.exe" + ;; + arm*) + as_default="armasm.exe" + ;; + esac + target_os_default="win32" + # Use a relative path for TMPDIR. This makes sure all the + # ffconf temp files are written with a relative path, avoiding + # issues with msys/win32 path conversion for MSVC parameters + # such as -Fo or -out:. + TMPDIR=. + ;; + icl) + cc_default="icl" + ld_default="xilink" + nm_default="dumpbin -symbols" + ar_default="xilib" + target_os_default="win32" + TMPDIR=. + ;; + gcov) + add_cflags -fprofile-arcs -ftest-coverage + add_ldflags -fprofile-arcs -ftest-coverage + ;; + llvm-cov) + add_cflags -fprofile-arcs -ftest-coverage + add_ldflags --coverage + ;; + hardened) + add_cppflags -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 + add_cflags -fno-strict-overflow -fstack-protector-all + add_ldflags -Wl,-z,relro -Wl,-z,now + add_cflags -fPIE + add_ldexeflags -fPIE -pie + ;; + ?*) + die "Unknown toolchain $toolchain" + ;; +esac + +if test -n "$cross_prefix"; then + test -n "$arch" && test -n "$target_os" || + die "Must specify target arch (--arch) and OS (--target-os) when cross-compiling" + enable cross_compile +fi + +set_default target_os +if test "$target_os" = android; then + cc_default="clang" +fi + +ar_default="${cross_prefix}${ar_default}" +cc_default="${cross_prefix}${cc_default}" +cxx_default="${cross_prefix}${cxx_default}" +nm_default="${cross_prefix}${nm_default}" +pkg_config_default="${cross_prefix}${pkg_config_default}" +if ${cross_prefix}${ranlib_default} 2>&1 | grep -q "\-D "; then + ranlib_default="${cross_prefix}${ranlib_default} -D" +else + ranlib_default="${cross_prefix}${ranlib_default}" +fi +strip_default="${cross_prefix}${strip_default}" +windres_default="${cross_prefix}${windres_default}" + +sysinclude_default="${sysroot}/usr/include" + +if enabled cuda_sdk; then + warn "Option --enable-cuda-sdk is deprecated. Use --enable-cuda-nvcc instead." + enable cuda_nvcc +fi + +if enabled cuda_nvcc; then + nvcc_default="nvcc" + nvccflags_default="-gencode arch=compute_30,code=sm_30 -O2" +else + nvcc_default="clang" + nvccflags_default="--cuda-gpu-arch=sm_30 -O2" + NVCC_C="" +fi + +set_default arch cc cxx doxygen pkg_config ranlib strip sysinclude \ + target_exec x86asmexe nvcc +enabled cross_compile || host_cc_default=$cc +set_default host_cc + +pkg_config_fail_message="" +if ! $pkg_config --version >/dev/null 2>&1; then + warn "$pkg_config not found, library detection may fail." + pkg_config=false +elif is_in -static $cc $LDFLAGS && ! is_in --static $pkg_config $pkg_config_flags; then + pkg_config_fail_message=" +Note: When building a static binary, add --pkg-config-flags=\"--static\"." +fi + +if test $doxygen != $doxygen_default && \ + ! $doxygen --version >/dev/null 2>&1; then + warn "Specified doxygen \"$doxygen\" not found, API documentation will fail to build." +fi + +exesuf() { + case $1 in + mingw32*|mingw64*|win32|win64|cygwin*|*-dos|freedos|opendos|os/2*|symbian) echo .exe ;; + esac +} + +EXESUF=$(exesuf $target_os) +HOSTEXESUF=$(exesuf $host_os) + +# set temporary file name +: ${TMPDIR:=$TEMPDIR} +: ${TMPDIR:=$TMP} +: ${TMPDIR:=/tmp} + +if [ -n "$tempprefix" ] ; then + mktemp(){ + tmpname="$tempprefix.${HOSTNAME}.${UID}" + echo "$tmpname" + mkdir "$tmpname" + } +elif ! test_cmd mktemp -u XXXXXX; then + # simple replacement for missing mktemp + # NOT SAFE FOR GENERAL USE + mktemp(){ + tmpname="${2%%XXX*}.${HOSTNAME}.${UID}.$$" + echo "$tmpname" + mkdir "$tmpname" + } +fi + +FFTMPDIR=$(mktemp -d "${TMPDIR}/ffconf.XXXXXXXX" 2> /dev/null) || + die "Unable to create temporary directory in $TMPDIR." + +tmpfile(){ + tmp="${FFTMPDIR}/test"$2 + (set -C; exec > $tmp) 2> /dev/null || + die "Unable to create temporary file in $FFTMPDIR." + eval $1=$tmp +} + +trap 'rm -rf -- "$FFTMPDIR"' EXIT +trap 'exit 2' INT + +tmpfile TMPASM .asm +tmpfile TMPC .c +tmpfile TMPCPP .cpp +tmpfile TMPE $EXESUF +tmpfile TMPH .h +tmpfile TMPM .m +tmpfile TMPCU .cu +tmpfile TMPO .o +tmpfile TMPS .S +tmpfile TMPSH .sh +tmpfile TMPV .ver + +unset -f mktemp + +chmod +x $TMPE + +# make sure we can execute files in $TMPDIR +cat > $TMPSH 2>> $logfile <> $logfile 2>&1 +if ! $TMPSH >> $logfile 2>&1; then + cat <&1 | grep -q '^GNU assembler'; then + true # no-op to avoid reading stdin in following checks + elif $_cc -v 2>&1 | grep -q '^gcc.*LLVM'; then + _type=llvm_gcc + gcc_extra_ver=$(expr "$($_cc --version 2>/dev/null | head -n1)" : '.*\((.*)\)') + _ident="llvm-gcc $($_cc -dumpversion 2>/dev/null) $gcc_extra_ver" + _depflags='-MMD -MF $(@:.o=.d) -MT $@' + _cflags_speed='-O3' + _cflags_size='-Os' + elif $_cc -v 2>&1 | grep -qi ^gcc; then + _type=gcc + gcc_version=$($_cc --version | head -n1) + gcc_basever=$($_cc -dumpversion) + gcc_pkg_ver=$(expr "$gcc_version" : '[^ ]* \(([^)]*)\)') + gcc_ext_ver=$(expr "$gcc_version" : ".*$gcc_pkg_ver $gcc_basever \\(.*\\)") + _ident=$(cleanws "gcc $gcc_basever $gcc_pkg_ver $gcc_ext_ver") + case $gcc_basever in + 2) ;; + 2.*) ;; + *) _depflags='-MMD -MF $(@:.o=.d) -MT $@' ;; + esac + if [ "$first" = true ]; then + case $gcc_basever in + 4.2*) + warn "gcc 4.2 is outdated and may miscompile FFmpeg. Please use a newer compiler." ;; + esac + fi + _cflags_speed='-O3' + _cflags_size='-Os' + elif $_cc --version 2>/dev/null | grep -q ^icc; then + _type=icc + _ident=$($_cc --version | head -n1) + _depflags='-MMD' + _cflags_speed='-O3' + _cflags_size='-Os' + _cflags_noopt='-O1' + _flags_filter=icc_flags + elif $_cc -v 2>&1 | grep -q xlc; then + _type=xlc + _ident=$($_cc -qversion 2>/dev/null | head -n1) + _cflags_speed='-O5' + _cflags_size='-O5 -qcompact' + elif $_cc --vsn 2>/dev/null | grep -Eq "ARM (C/C\+\+ )?Compiler"; then + test -d "$sysroot" || die "No valid sysroot specified." + _type=armcc + _ident=$($_cc --vsn | grep -i build | head -n1 | sed 's/.*: //') + armcc_conf="$PWD/armcc.conf" + $_cc --arm_linux_configure \ + --arm_linux_config_file="$armcc_conf" \ + --configure_sysroot="$sysroot" \ + --configure_cpp_headers="$sysinclude" >>$logfile 2>&1 || + die "Error creating armcc configuration file." + $_cc --vsn | grep -q RVCT && armcc_opt=rvct || armcc_opt=armcc + _flags="--arm_linux_config_file=$armcc_conf --translate_gcc" + as_default="${cross_prefix}gcc" + _depflags='-MMD' + _cflags_speed='-O3' + _cflags_size='-Os' + elif $_cc -v 2>&1 | grep -q clang && ! $_cc -? > /dev/null 2>&1; then + _type=clang + _ident=$($_cc --version 2>/dev/null | head -n1) + _depflags='-MMD -MF $(@:.o=.d) -MT $@' + _cflags_speed='-O3' + _cflags_size='-Oz' + elif $_cc -V 2>&1 | grep -q Sun; then + _type=suncc + _ident=$($_cc -V 2>&1 | head -n1 | cut -d' ' -f 2-) + _DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< | sed -e "1s,^.*: ,$@: ," -e "\$$!s,\$$, \\\," -e "1!s,^.*: , ," > $(@:.o=.d)' + _DEPFLAGS='-xM1 -xc99' + _ldflags='-std=c99' + _cflags_speed='-O5' + _cflags_size='-O5 -xspace' + _flags_filter=suncc_flags + elif $_cc -v 2>&1 | grep -q 'PathScale\|Path64'; then + _type=pathscale + _ident=$($_cc -v 2>&1 | head -n1 | tr -d :) + _depflags='-MMD -MF $(@:.o=.d) -MT $@' + _cflags_speed='-O2' + _cflags_size='-Os' + _flags_filter='filter_out -Wdisabled-optimization' + elif $_cc -v 2>&1 | grep -q Open64; then + _type=open64 + _ident=$($_cc -v 2>&1 | head -n1 | tr -d :) + _depflags='-MMD -MF $(@:.o=.d) -MT $@' + _cflags_speed='-O2' + _cflags_size='-Os' + _flags_filter='filter_out -Wdisabled-optimization|-Wtype-limits|-fno-signed-zeros' + elif $_cc 2>&1 | grep -q 'Microsoft.*ARM.*Assembler'; then + _type=armasm + _ident=$($_cc | head -n1) + # 4509: "This form of conditional instruction is deprecated" + _flags="-nologo -ignore 4509" + _flags_filter=armasm_flags + elif $_cc 2>&1 | grep -q Intel; then + _type=icl + _ident=$($_cc 2>&1 | head -n1) + _depflags='-QMMD -QMF$(@:.o=.d) -QMT$@' + # Not only is O3 broken on 13.x+ but it is slower on all previous + # versions (tested) as well. + _cflags_speed="-O2" + _cflags_size="-O1 -Oi" # -O1 without -Oi miscompiles stuff + if $_cc 2>&1 | grep -q Linker; then + _ld_o='-out:$@' + else + _ld_o='-Fe$@' + fi + _cc_o='-Fo$@' + _cc_e='-P' + _flags_filter=icl_flags + _ld_lib='lib%.a' + _ld_path='-libpath:' + # -Qdiag-error to make icl error when seeing certain unknown arguments + _flags='-nologo -Qdiag-error:4044,10157' + # -Qvec- -Qsimd- to prevent miscompilation, -GS, fp:precise for consistency + # with MSVC which enables it by default. + _cflags='-Qms0 -Qvec- -Qsimd- -GS -fp:precise' + disable stripping + elif $_cc -? 2>/dev/null | grep -q 'LLVM.*Linker'; then + # lld can emulate multiple different linkers; in ms link.exe mode, + # the -? parameter gives the help output which contains an identifyable + # string, while it gives an error in other modes. + _type=lld-link + # The link.exe mode doesn't have a switch for getting the version, + # but we can force it back to gnu mode and get the version from there. + _ident=$($_cc -flavor gnu --version 2>/dev/null) + _ld_o='-out:$@' + _flags_filter=msvc_flags + _ld_lib='lib%.a' + _ld_path='-libpath:' + elif $_cc -nologo- 2>&1 | grep -q Microsoft || { $_cc -v 2>&1 | grep -q clang && $_cc -? > /dev/null 2>&1; }; then + _type=msvc + _ident=$($_cc 2>&1 | head -n1 | tr -d '\r') + _DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '\''/including/ { sub(/^.*file: */, ""); gsub(/\\/, "/"); if (!match($$0, / /)) print "$@:", $$0 }'\'' > $(@:.o=.d)' + _DEPFLAGS='$(CPPFLAGS) $(CFLAGS) -showIncludes -Zs' + _cflags_speed="-O2" + _cflags_size="-O1" + _cflags_noopt="-O1" + if $_cc -nologo- 2>&1 | grep -q Linker; then + _ld_o='-out:$@' + else + _ld_o='-Fe$@' + fi + _cc_o='-Fo$@' + _cc_e='-P -Fi$@' + _flags_filter=msvc_flags + _ld_lib='lib%.a' + _ld_path='-libpath:' + _flags='-nologo' + disable stripping + elif $_cc --version 2>/dev/null | grep -q ^cparser; then + _type=cparser + _ident=$($_cc --version | head -n1) + _depflags='-MMD' + _cflags_speed='-O4' + _cflags_size='-O2' + _flags_filter=cparser_flags + fi + + eval ${pfx}_type=\$_type + eval ${pfx}_ident=\$_ident +} + +set_ccvars(){ + eval ${1}_C=\${_cc_c-\${${1}_C}} + eval ${1}_E=\${_cc_e-\${${1}_E}} + eval ${1}_O=\${_cc_o-\${${1}_O}} + + if [ -n "$_depflags" ]; then + eval ${1}_DEPFLAGS=\$_depflags + else + eval ${1}DEP=\${_DEPCMD:-\$DEPCMD} + eval ${1}DEP_FLAGS=\${_DEPFLAGS:-\$DEPFLAGS} + eval DEP${1}FLAGS=\$_flags + fi +} + +probe_cc cc "$cc" "true" +cflags_filter=$_flags_filter +cflags_speed=$_cflags_speed +cflags_size=$_cflags_size +cflags_noopt=$_cflags_noopt +add_cflags $_flags $_cflags +cc_ldflags=$_ldflags +set_ccvars CC +set_ccvars CXX + +probe_cc hostcc "$host_cc" +host_cflags_filter=$_flags_filter +host_cflags_speed=$_cflags_speed +add_host_cflags $_flags $_cflags +set_ccvars HOSTCC + +test -n "$cc_type" && enable $cc_type || + warn "Unknown C compiler $cc, unable to select optimal CFLAGS" + +: ${as_default:=$cc} +: ${objcc_default:=$cc} +: ${dep_cc_default:=$cc} +: ${ld_default:=$cc} +: ${host_ld_default:=$host_cc} +set_default ar as objcc dep_cc ld ln_s host_ld windres + +probe_cc as "$as" +asflags_filter=$_flags_filter +add_asflags $_flags $_cflags +set_ccvars AS + +probe_cc objcc "$objcc" +objcflags_filter=$_flags_filter +add_objcflags $_flags $_cflags +set_ccvars OBJC + +probe_cc ld "$ld" +ldflags_filter=$_flags_filter +add_ldflags $_flags $_ldflags +test "$cc_type" != "$ld_type" && add_ldflags $cc_ldflags +LD_O=${_ld_o-$LD_O} +LD_LIB=${_ld_lib-$LD_LIB} +LD_PATH=${_ld_path-$LD_PATH} + +probe_cc hostld "$host_ld" +host_ldflags_filter=$_flags_filter +add_host_ldflags $_flags $_ldflags +HOSTLD_O=${_ld_o-$HOSTLD_O} + +if [ -z "$CC_DEPFLAGS" ] && [ "$dep_cc" != "$cc" ]; then + probe_cc depcc "$dep_cc" + CCDEP=${_DEPCMD:-$DEPCMD} + CCDEP_FLAGS=${_DEPFLAGS:=$DEPFLAGS} + DEPCCFLAGS=$_flags +fi + +if $ar 2>&1 | grep -q Microsoft; then + arflags="-nologo" + ar_o='-out:$@' +elif $ar 2>&1 | grep -q "\[D\] "; then + arflags="rcD" + ar_o='$@' +else + arflags="rc" + ar_o='$@' +fi + +add_cflags $extra_cflags +add_cxxflags $extra_cxxflags +add_objcflags $extra_objcflags +add_asflags $extra_cflags + +if test -n "$sysroot"; then + case "$cc_type" in + gcc|llvm_gcc|clang) + add_cppflags --sysroot="$sysroot" + add_ldflags --sysroot="$sysroot" + ;; + esac +fi + +if test "$cpu" = host; then + enabled cross_compile && + die "--cpu=host makes no sense when cross-compiling." + + case "$cc_type" in + gcc|llvm_gcc) + check_native(){ + $cc $1=native -v -c -o $TMPO $TMPC >$TMPE 2>&1 || return + sed -n "/cc1.*$1=/{ + s/.*$1=\\([^ ]*\\).*/\\1/ + p + q + }" $TMPE + } + cpu=$(check_native -march || check_native -mcpu) + ;; + clang) + check_native(){ + $cc $1=native -v -c -o $TMPO $TMPC >$TMPE 2>&1 || return + sed -n "/cc1.*-target-cpu /{ + s/.*-target-cpu \\([^ ]*\\).*/\\1/ + p + q + }" $TMPE + } + cpu=$(check_native -march) + ;; + esac + + test "${cpu:-host}" = host && + die "--cpu=host not supported with compiler $cc" +fi + +# Deal with common $arch aliases +case "$arch" in + aarch64|arm64) + arch="aarch64" + ;; + arm*|iPad*|iPhone*) + arch="arm" + ;; + mips*|IP*) + case "$arch" in + *el) + add_cppflags -EL + add_ldflags -EL + ;; + *eb) + add_cppflags -EB + add_ldflags -EB + ;; + esac + arch="mips" + ;; + parisc*|hppa*) + arch="parisc" + ;; + "Power Macintosh"|ppc*|powerpc*) + arch="ppc" + ;; + s390|s390x) + arch="s390" + ;; + sh4|sh) + arch="sh4" + ;; + sun4*|sparc*) + arch="sparc" + ;; + tilegx|tile-gx) + arch="tilegx" + ;; + i[3-6]86*|i86pc|BePC|x86pc|x86_64|x86_32|amd64) + arch="x86" + ;; +esac + +is_in $arch $ARCH_LIST || warn "unknown architecture $arch" +enable $arch + +# Add processor-specific flags +if enabled aarch64; then + + case $cpu in + armv*) + cpuflags="-march=$cpu" + ;; + *) + cpuflags="-mcpu=$cpu" + ;; + esac + +elif enabled alpha; then + + cpuflags="-mcpu=$cpu" + +elif enabled arm; then + + check_arm_arch() { + test_cpp_condition stddef.h \ + "defined __ARM_ARCH_${1}__ || defined __TARGET_ARCH_${2:-$1}" \ + $cpuflags + } + + probe_arm_arch() { + if check_arm_arch 4; then echo armv4 + elif check_arm_arch 4T; then echo armv4t + elif check_arm_arch 5; then echo armv5 + elif check_arm_arch 5E; then echo armv5e + elif check_arm_arch 5T; then echo armv5t + elif check_arm_arch 5TE; then echo armv5te + elif check_arm_arch 5TEJ; then echo armv5te + elif check_arm_arch 6; then echo armv6 + elif check_arm_arch 6J; then echo armv6j + elif check_arm_arch 6K; then echo armv6k + elif check_arm_arch 6Z; then echo armv6z + elif check_arm_arch 6KZ; then echo armv6zk + elif check_arm_arch 6ZK; then echo armv6zk + elif check_arm_arch 6T2; then echo armv6t2 + elif check_arm_arch 7; then echo armv7 + elif check_arm_arch 7A 7_A; then echo armv7-a + elif check_arm_arch 7S; then echo armv7-a + elif check_arm_arch 7R 7_R; then echo armv7-r + elif check_arm_arch 7M 7_M; then echo armv7-m + elif check_arm_arch 7EM 7E_M; then echo armv7-m + elif check_arm_arch 8A 8_A; then echo armv8-a + fi + } + + [ "$cpu" = generic ] && cpu=$(probe_arm_arch) + + case $cpu in + armv*) + cpuflags="-march=$cpu" + subarch=$(echo $cpu | sed 's/[^a-z0-9]//g') + ;; + *) + cpuflags="-mcpu=$cpu" + case $cpu in + cortex-a*) subarch=armv7a ;; + cortex-r*) subarch=armv7r ;; + cortex-m*) enable thumb; subarch=armv7m ;; + arm11*) subarch=armv6 ;; + arm[79]*e*|arm9[24]6*|arm96*|arm102[26]) subarch=armv5te ;; + armv4*|arm7*|arm9[24]*) subarch=armv4 ;; + *) subarch=$(probe_arm_arch) ;; + esac + ;; + esac + + case "$subarch" in + armv5t*) enable fast_clz ;; + armv[6-8]*) + enable fast_clz + disabled fast_unaligned || enable fast_unaligned + ;; + esac + +elif enabled avr32; then + + case $cpu in + ap7[02]0[0-2]) + subarch="avr32_ap" + cpuflags="-mpart=$cpu" + ;; + ap) + subarch="avr32_ap" + cpuflags="-march=$cpu" + ;; + uc3[ab]*) + subarch="avr32_uc" + cpuflags="-mcpu=$cpu" + ;; + uc) + subarch="avr32_uc" + cpuflags="-march=$cpu" + ;; + esac + +elif enabled bfin; then + + cpuflags="-mcpu=$cpu" + +elif enabled mips; then + + cpuflags="-march=$cpu" + + if [ "$cpu" != "generic" ]; then + disable mips32r2 + disable mips32r5 + disable mips64r2 + disable mips32r6 + disable mips64r6 + disable loongson2 + disable loongson3 + + case $cpu in + 24kc|24kf*|24kec|34kc|1004kc|24kef*|34kf*|1004kf*|74kc|74kf) + enable mips32r2 + disable msa + ;; + p5600|i6400|p6600) + disable mipsdsp + disable mipsdspr2 + ;; + loongson*) + enable loongson2 + enable loongson3 + enable local_aligned + enable simd_align_16 + enable fast_64bit + enable fast_clz + enable fast_cmov + enable fast_unaligned + disable aligned_stack + disable mipsdsp + disable mipsdspr2 + # When gcc version less than 5.3.0, add -fno-expensive-optimizations flag. + if [ $cc == gcc ]; then + gcc_version=$(gcc -dumpversion) + if [ "$(echo "$gcc_version 5.3.0" | tr " " "\n" | sort -rV | head -n 1)" == "$gcc_version" ]; then + expensive_optimization_flag="" + else + expensive_optimization_flag="-fno-expensive-optimizations" + fi + fi + case $cpu in + loongson3*) + cpuflags="-march=loongson3a -mhard-float $expensive_optimization_flag" + ;; + loongson2e) + cpuflags="-march=loongson2e -mhard-float $expensive_optimization_flag" + ;; + loongson2f) + cpuflags="-march=loongson2f -mhard-float $expensive_optimization_flag" + ;; + esac + ;; + *) + # Unknown CPU. Disable everything. + warn "unknown CPU. Disabling all MIPS optimizations." + disable mipsfpu + disable mipsdsp + disable mipsdspr2 + disable msa + disable mmi + ;; + esac + + case $cpu in + 24kc) + disable mipsfpu + disable mipsdsp + disable mipsdspr2 + ;; + 24kf*) + disable mipsdsp + disable mipsdspr2 + ;; + 24kec|34kc|1004kc) + disable mipsfpu + disable mipsdspr2 + ;; + 24kef*|34kf*|1004kf*) + disable mipsdspr2 + ;; + 74kc) + disable mipsfpu + ;; + p5600) + enable mips32r5 + check_cflags "-mtune=p5600" && check_cflags "-msched-weight -mload-store-pairs -funroll-loops" + ;; + i6400) + enable mips64r6 + check_cflags "-mtune=i6400 -mabi=64" && check_cflags "-msched-weight -mload-store-pairs -funroll-loops" && check_ldflags "-mabi=64" + ;; + p6600) + enable mips64r6 + check_cflags "-mtune=p6600 -mabi=64" && check_cflags "-msched-weight -mload-store-pairs -funroll-loops" && check_ldflags "-mabi=64" + ;; + esac + else + # We do not disable anything. Is up to the user to disable the unwanted features. + warn 'generic cpu selected' + fi + +elif enabled ppc; then + + disable ldbrx + + case $(tolower $cpu) in + 601|ppc601|powerpc601) + cpuflags="-mcpu=601" + disable altivec + ;; + 603*|ppc603*|powerpc603*) + cpuflags="-mcpu=603" + disable altivec + ;; + 604*|ppc604*|powerpc604*) + cpuflags="-mcpu=604" + disable altivec + ;; + g3|75*|ppc75*|powerpc75*) + cpuflags="-mcpu=750" + disable altivec + ;; + g4|745*|ppc745*|powerpc745*) + cpuflags="-mcpu=7450" + disable vsx + ;; + 74*|ppc74*|powerpc74*) + cpuflags="-mcpu=7400" + disable vsx + ;; + g5|970|ppc970|powerpc970) + cpuflags="-mcpu=970" + disable vsx + ;; + power[3-6]*) + cpuflags="-mcpu=$cpu" + disable vsx + ;; + power[7-8]*) + cpuflags="-mcpu=$cpu" + ;; + cell) + cpuflags="-mcpu=cell" + enable ldbrx + disable vsx + ;; + e500mc) + cpuflags="-mcpu=e500mc" + disable altivec + ;; + e500v2) + cpuflags="-mcpu=8548 -mhard-float -mfloat-gprs=double" + disable altivec + disable dcbzl + ;; + e500) + cpuflags="-mcpu=8540 -mhard-float" + disable altivec + disable dcbzl + ;; + esac + +elif enabled sparc; then + + case $cpu in + cypress|f93[04]|tsc701|sparcl*|supersparc|hypersparc|niagara|v[789]) + cpuflags="-mcpu=$cpu" + ;; + ultrasparc*|niagara[234]) + cpuflags="-mcpu=$cpu" + ;; + esac + +elif enabled x86; then + + case $cpu in + i[345]86|pentium) + cpuflags="-march=$cpu" + disable i686 + disable mmx + ;; + # targets that do NOT support nopl and conditional mov (cmov) + pentium-mmx|k6|k6-[23]|winchip-c6|winchip2|c3) + cpuflags="-march=$cpu" + disable i686 + ;; + # targets that do support nopl and conditional mov (cmov) + i686|pentiumpro|pentium[23]|pentium-m|athlon|athlon-tbird|athlon-4|athlon-[mx]p|athlon64*|k8*|opteron*|athlon-fx\ + |core*|atom|bonnell|nehalem|westmere|silvermont|sandybridge|ivybridge|haswell|broadwell|skylake*|knl\ + |amdfam10|barcelona|b[dt]ver*|znver*) + cpuflags="-march=$cpu" + enable i686 + enable fast_cmov + ;; + # targets that do support conditional mov but on which it's slow + pentium4|pentium4m|prescott|nocona) + cpuflags="-march=$cpu" + enable i686 + disable fast_cmov + ;; + esac + +fi + +if [ "$cpu" != generic ]; then + add_cflags $cpuflags + add_asflags $cpuflags + test "$cc_type" = "$ld_type" && add_ldflags $cpuflags +fi + +# compiler sanity check +test_exec <= 201112L" && + add_cflags -std=c11 || + check_cflags -std=c99 + +check_cppflags -D_FILE_OFFSET_BITS=64 +check_cppflags -D_LARGEFILE_SOURCE + +add_host_cppflags -D_ISOC99_SOURCE +check_host_cflags -std=c99 +check_host_cflags -Wall +check_host_cflags $host_cflags_speed + +check_64bit(){ + arch32=$1 + arch64=$2 + expr=${3:-'sizeof(void *) > 4'} + test_code cc "" "int test[2*($expr) - 1]" && + subarch=$arch64 || subarch=$arch32 + enable $subarch +} + +case "$arch" in + aarch64|alpha|ia64) + enabled shared && enable_weak pic + ;; + mips) + check_64bit mips mips64 '_MIPS_SIM > 1' + enabled shared && enable_weak pic + ;; + parisc) + check_64bit parisc parisc64 + enabled shared && enable_weak pic + ;; + ppc) + check_64bit ppc ppc64 + enabled shared && enable_weak pic + ;; + s390) + check_64bit s390 s390x + enabled shared && enable_weak pic + ;; + sparc) + check_64bit sparc sparc64 + enabled shared && enable_weak pic + ;; + x86) + check_64bit x86_32 x86_64 + # Treat x32 as x64 for now. Note it also needs pic if shared + test "$subarch" = "x86_32" && test_cpp_condition stddef.h 'defined(__x86_64__)' && + subarch=x86_64 && enable x86_64 && disable x86_32 + if enabled x86_64; then + enabled shared && enable_weak pic + objformat=elf64 + fi + ;; +esac + +# OS specific +case $target_os in + aix) + SHFLAGS=-shared + add_cppflags '-I\$(SRC_PATH)/compat/aix' + enabled shared && add_ldflags -Wl,-brtl + arflags='-Xany -r -c' + striptype="" + ;; + android) + disable symver + enable section_data_rel_ro + add_cflags -fPIE + add_ldexeflags -fPIE -pie + SLIB_INSTALL_NAME='$(SLIBNAME)' + SLIB_INSTALL_LINKS= + SHFLAGS='-shared -Wl,-soname,$(SLIBNAME)' + ;; + haiku) + prefix_default="/boot/common" + network_extralibs="-lnetwork" + host_extralibs= + ;; + sunos) + SHFLAGS='-shared -Wl,-h,$$(@F)' + enabled x86 && append SHFLAGS -mimpure-text + network_extralibs="-lsocket -lnsl" + add_cppflags -D__EXTENSIONS__ + # When using suncc to build, the Solaris linker will mark + # an executable with each instruction set encountered by + # the Solaris assembler. As our libraries contain their own + # guards for processor-specific code, instead suppress + # generation of the HWCAPS ELF section on Solaris x86 only. + enabled_all suncc x86 && + echo "hwcap_1 = OVERRIDE;" > mapfile && + add_ldflags -Wl,-M,mapfile + nm_default='nm -P -g' + striptype="" + version_script='-M' + VERSION_SCRIPT_POSTPROCESS_CMD='perl $(SRC_PATH)/compat/solaris/make_sunver.pl - $(OBJS)' + ;; + netbsd) + disable symver + oss_indev_extralibs="-lossaudio" + oss_outdev_extralibs="-lossaudio" + enabled gcc || check_ldflags -Wl,-zmuldefs + ;; + openbsd|bitrig) + disable symver + striptype="" + SHFLAGS='-shared' + SLIB_INSTALL_NAME='$(SLIBNAME).$(LIBMAJOR).$(LIBMINOR)' + SLIB_INSTALL_LINKS= + oss_indev_extralibs="-lossaudio" + oss_outdev_extralibs="-lossaudio" + ;; + dragonfly) + disable symver + ;; + freebsd) + ;; + bsd/os) + add_extralibs -lpoll -lgnugetopt + strip="strip -d" + ;; + darwin) + enabled ppc && add_asflags -force_cpusubtype_ALL + install_name_dir_default='$(SHLIBDIR)' + SHFLAGS='-dynamiclib -Wl,-single_module -Wl,-install_name,$(INSTALL_NAME_DIR)/$(SLIBNAME_WITH_MAJOR),-current_version,$(LIBVERSION),-compatibility_version,$(LIBMAJOR)' + enabled x86_32 && append SHFLAGS -Wl,-read_only_relocs,suppress + strip="${strip} -x" + add_ldflags -Wl,-dynamic,-search_paths_first + check_cflags -Werror=partial-availability + SLIBSUF=".dylib" + SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME).$(LIBVERSION)$(SLIBSUF)' + SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME).$(LIBMAJOR)$(SLIBSUF)' + enabled x86_64 && objformat="macho64" || objformat="macho32" + enabled_any pic shared x86_64 || + { check_cflags -mdynamic-no-pic && add_asflags -mdynamic-no-pic; } + check_headers dispatch/dispatch.h && + add_cppflags '-I\$(SRC_PATH)/compat/dispatch_semaphore' + if test -n "$sysroot"; then + is_in -isysroot $cc $CPPFLAGS $CFLAGS || check_cppflags -isysroot $sysroot + is_in -isysroot $ld $LDFLAGS || check_ldflags -isysroot $sysroot + fi + version_script='-exported_symbols_list' + VERSION_SCRIPT_POSTPROCESS_CMD='tr " " "\n" | sed -n /global:/,/local:/p | grep ";" | tr ";" "\n" | sed -E "s/(.+)/_\1/g" | sed -E "s/(.+[^*])$$$$/\1*/"' + ;; + msys*) + die "Native MSYS builds are discouraged, please use the MINGW environment." + ;; + mingw32*|mingw64*) + target_os=mingw32 + LIBTARGET=i386 + if enabled x86_64; then + LIBTARGET="i386:x86-64" + elif enabled arm; then + LIBTARGET="arm" + elif enabled aarch64; then + LIBTARGET="arm64" + fi + if enabled shared; then + # Cannot build both shared and static libs when using dllimport. + disable static + fi + enabled shared && ! enabled small && test_cmd $windres --version && enable gnu_windres + enabled x86_32 && check_ldflags -Wl,--large-address-aware + shlibdir_default="$bindir_default" + SLIBPREF="" + SLIBSUF=".dll" + SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' + SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)' + if test_cmd lib.exe -list; then + SLIB_EXTRA_CMD=-'lib.exe -nologo -machine:$(LIBTARGET) -def:$$(@:$(SLIBSUF)=.def) -out:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' + if enabled x86_64; then + LIBTARGET=x64 + fi + else + SLIB_EXTRA_CMD=-'$(DLLTOOL) -m $(LIBTARGET) -d $$(@:$(SLIBSUF)=.def) -l $(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib) -D $(SLIBNAME_WITH_MAJOR)' + fi + SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)' + SLIB_INSTALL_LINKS= + SLIB_INSTALL_EXTRA_SHLIB='$(SLIBNAME:$(SLIBSUF)=.lib)' + SLIB_INSTALL_EXTRA_LIB='lib$(SLIBNAME:$(SLIBSUF)=.dll.a) $(SLIBNAME_WITH_MAJOR:$(SLIBSUF)=.def)' + SLIB_CREATE_DEF_CMD='EXTERN_PREFIX="$(EXTERN_PREFIX)" AR="$(AR_CMD)" NM="$(NM_CMD)" $(SRC_PATH)/compat/windows/makedef $(SUBDIR)lib$(NAME).ver $(OBJS) > $$(@:$(SLIBSUF)=.def)' + SHFLAGS='-shared -Wl,--out-implib,$(SUBDIR)lib$(SLIBNAME:$(SLIBSUF)=.dll.a) -Wl,--disable-auto-image-base $$(@:$(SLIBSUF)=.def)' + enabled x86_64 && objformat="win64" || objformat="win32" + dlltool="${cross_prefix}dlltool" + ranlib=: + enable dos_paths + check_ldflags -Wl,--nxcompat,--dynamicbase + # Lets work around some stupidity in binutils. + # ld will strip relocations from executables even though we need them + # for dynamicbase (ASLR). Using -pie does retain the reloc section + # however ld then forgets what the entry point should be (oops) so we + # have to manually (re)set it. + if enabled x86_32; then + disabled debug && add_ldexeflags -Wl,--pic-executable,-e,_mainCRTStartup + elif enabled x86_64; then + disabled debug && add_ldexeflags -Wl,--pic-executable,-e,mainCRTStartup + check_ldflags -Wl,--high-entropy-va # binutils 2.25 + # Set image base >4GB for extra entropy with HEASLR + add_ldexeflags -Wl,--image-base,0x140000000 + append SHFLAGS -Wl,--image-base,0x180000000 + fi + ;; + win32|win64) + disable symver + if enabled shared; then + # Link to the import library instead of the normal static library + # for shared libs. + LD_LIB='%.lib' + # Cannot build both shared and static libs with MSVC or icl. + disable static + fi + enabled x86_32 && check_ldflags -LARGEADDRESSAWARE + shlibdir_default="$bindir_default" + SLIBPREF="" + SLIBSUF=".dll" + SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' + SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)' + SLIB_CREATE_DEF_CMD='EXTERN_PREFIX="$(EXTERN_PREFIX)" $(SRC_PATH)/compat/windows/makedef $(SUBDIR)lib$(NAME).ver $(OBJS) > $$(@:$(SLIBSUF)=.def)' + SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)' + SLIB_INSTALL_LINKS= + SLIB_INSTALL_EXTRA_SHLIB='$(SLIBNAME:$(SLIBSUF)=.lib)' + SLIB_INSTALL_EXTRA_LIB='$(SLIBNAME_WITH_MAJOR:$(SLIBSUF)=.def)' + SHFLAGS='-dll -def:$$(@:$(SLIBSUF)=.def) -implib:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' + enabled x86_64 && objformat="win64" || objformat="win32" + ranlib=: + enable dos_paths + ;; + cygwin*) + target_os=cygwin + shlibdir_default="$bindir_default" + SLIBPREF="cyg" + SLIBSUF=".dll" + SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' + SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)' + SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)' + SLIB_INSTALL_LINKS= + SLIB_INSTALL_EXTRA_LIB='lib$(FULLNAME).dll.a' + SHFLAGS='-shared -Wl,--out-implib,$(SUBDIR)lib$(FULLNAME).dll.a' + enabled x86_64 && objformat="win64" || objformat="win32" + enable dos_paths + enabled shared && ! enabled small && test_cmd $windres --version && enable gnu_windres + add_cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 + ;; + *-dos|freedos|opendos) + network_extralibs="-lsocket" + objformat="coff" + enable dos_paths + ;; + linux) + enable section_data_rel_ro + enabled_any arm aarch64 && enable_weak linux_perf + ;; + irix*) + target_os=irix + ranlib="echo ignoring ranlib" + ;; + os/2*) + strip="lxlite -CS" + striptype="" + objformat="aout" + add_cppflags -D_GNU_SOURCE + add_ldflags -Zomf -Zbin-files -Zargs-wild -Zhigh-mem -Zmap + SHFLAGS='$(SUBDIR)$(NAME).def -Zdll -Zomf' + LIBSUF="_s.a" + SLIBPREF="" + SLIBSUF=".dll" + SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' + SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(shell echo $(FULLNAME) | cut -c1-6)$(LIBMAJOR)$(SLIBSUF)' + SLIB_CREATE_DEF_CMD='echo LIBRARY $(SLIBNAME_WITH_MAJOR:$(SLIBSUF)=) INITINSTANCE TERMINSTANCE > $(SUBDIR)$(FULLNAME).def; \ + echo CODE PRELOAD MOVEABLE DISCARDABLE >> $(SUBDIR)$(FULLNAME).def; \ + echo DATA PRELOAD MOVEABLE MULTIPLE NONSHARED >> $(SUBDIR)$(FULLNAME).def; \ + echo EXPORTS >> $(SUBDIR)$(FULLNAME).def; \ + emxexp $(OBJS) >> $(SUBDIR)$(FULLNAME).def' + SLIB_EXTRA_CMD='emximp -o $(SUBDIR)$(LIBPREF)$(FULLNAME)_dll.a $(SUBDIR)$(FULLNAME).def; \ + emximp -o $(SUBDIR)$(LIBPREF)$(FULLNAME)_dll.lib $(SUBDIR)$(FULLNAME).def;' + SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)' + SLIB_INSTALL_LINKS= + SLIB_INSTALL_EXTRA_LIB='$(LIBPREF)$(FULLNAME)_dll.a $(LIBPREF)$(FULLNAME)_dll.lib' + enable dos_paths + enable_weak os2threads + ;; + gnu/kfreebsd) + add_cppflags -D_BSD_SOURCE + ;; + gnu) + ;; + qnx) + add_cppflags -D_QNX_SOURCE + network_extralibs="-lsocket" + ;; + symbian) + SLIBSUF=".dll" + enable dos_paths + add_cflags --include=$sysinclude/gcce/gcce.h -fvisibility=default + add_cppflags -D__GCCE__ -D__SYMBIAN32__ -DSYMBIAN_OE_POSIX_SIGNALS + add_ldflags -Wl,--target1-abs,--no-undefined \ + -Wl,-Ttext,0x80000,-Tdata,0x1000000 -shared \ + -Wl,--entry=_E32Startup -Wl,-u,_E32Startup + add_extralibs -l:eexe.lib -l:usrt2_2.lib -l:dfpaeabi.dso \ + -l:drtaeabi.dso -l:scppnwdl.dso -lsupc++ -lgcc \ + -l:libc.dso -l:libm.dso -l:euser.dso -l:libcrt0.lib + ;; + minix) + ;; + none) + ;; + *) + die "Unknown OS '$target_os'." + ;; +esac + +# test if creating links works +link_dest=$(mktemp -u $TMPDIR/dest_XXXXXXXX) +link_name=$(mktemp -u $TMPDIR/name_XXXXXXXX) +mkdir "$link_dest" +$ln_s "$link_dest" "$link_name" +touch "$link_dest/test_file" +if [ "$source_path" != "." ] && [ "$source_path" != "src" ] && ([ ! -d src ] || [ -L src ]) && [ -e "$link_name/test_file" ]; then + # create link to source path + [ -e src ] && rm src + $ln_s "$source_path" src + source_link=src +else + # creating directory links doesn't work + # fall back to using the full source path + source_link="$source_path" +fi +# cleanup +rm -r "$link_dest" +rm -r "$link_name" + +# determine libc flavour + +probe_libc(){ + pfx=$1 + pfx_no_=${pfx%_} + # uclibc defines __GLIBC__, so it needs to be checked before glibc. + if test_${pfx}cpp_condition features.h "defined __UCLIBC__"; then + eval ${pfx}libc_type=uclibc + add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 + elif test_${pfx}cpp_condition features.h "defined __GLIBC__"; then + eval ${pfx}libc_type=glibc + add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 + # MinGW headers can be installed on Cygwin, so check for newlib first. + elif test_${pfx}cpp_condition newlib.h "defined _NEWLIB_VERSION"; then + eval ${pfx}libc_type=newlib + add_${pfx}cppflags -U__STRICT_ANSI__ -D_XOPEN_SOURCE=600 + # MinGW64 is backwards compatible with MinGW32, so check for it first. + elif test_${pfx}cpp_condition _mingw.h "defined __MINGW64_VERSION_MAJOR"; then + eval ${pfx}libc_type=mingw64 + if test_${pfx}cpp_condition _mingw.h "__MINGW64_VERSION_MAJOR < 3"; then + add_compat msvcrt/snprintf.o + add_cflags "-include $source_path/compat/msvcrt/snprintf.h" + fi + add_${pfx}cppflags -U__STRICT_ANSI__ -D__USE_MINGW_ANSI_STDIO=1 + eval test \$${pfx_no_}cc_type = "gcc" && + add_${pfx}cppflags -D__printf__=__gnu_printf__ + test_${pfx}cpp_condition windows.h "!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600" && + add_${pfx}cppflags -D_WIN32_WINNT=0x0600 + add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 + elif test_${pfx}cpp_condition _mingw.h "defined __MINGW_VERSION" || + test_${pfx}cpp_condition _mingw.h "defined __MINGW32_VERSION"; then + eval ${pfx}libc_type=mingw32 + test_${pfx}cpp_condition _mingw.h "__MINGW32_MAJOR_VERSION > 3 || \ + (__MINGW32_MAJOR_VERSION == 3 && __MINGW32_MINOR_VERSION >= 15)" || + die "ERROR: MinGW32 runtime version must be >= 3.15." + add_${pfx}cppflags -U__STRICT_ANSI__ -D__USE_MINGW_ANSI_STDIO=1 + test_${pfx}cpp_condition _mingw.h "__MSVCRT_VERSION__ < 0x0700" && + add_${pfx}cppflags -D__MSVCRT_VERSION__=0x0700 + test_${pfx}cpp_condition windows.h "!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600" && + add_${pfx}cppflags -D_WIN32_WINNT=0x0600 + eval test \$${pfx_no_}cc_type = "gcc" && + add_${pfx}cppflags -D__printf__=__gnu_printf__ + add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 + elif test_${pfx}cpp_condition crtversion.h "defined _VC_CRT_MAJOR_VERSION"; then + eval ${pfx}libc_type=msvcrt + if test_${pfx}cpp_condition crtversion.h "_VC_CRT_MAJOR_VERSION < 14"; then + if [ "$pfx" = host_ ]; then + add_host_cppflags -Dsnprintf=_snprintf + else + add_compat strtod.o strtod=avpriv_strtod + add_compat msvcrt/snprintf.o snprintf=avpriv_snprintf \ + _snprintf=avpriv_snprintf \ + vsnprintf=avpriv_vsnprintf + fi + fi + add_${pfx}cppflags -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS + # The MSVC 2010 headers (Win 7.0 SDK) set _WIN32_WINNT to + # 0x601 by default unless something else is set by the user. + # This can easily lead to us detecting functions only present + # in such new versions and producing binaries requiring windows 7.0. + # Therefore explicitly set the default to Vista unless the user has + # set something else on the command line. + # Don't do this if WINAPI_FAMILY is set and is set to a non-desktop + # family. For these cases, configure is free to use any functions + # found in the SDK headers by default. (Alternatively, we could force + # _WIN32_WINNT to 0x0602 in that case.) + test_${pfx}cpp_condition stdlib.h "defined(_WIN32_WINNT)" || + { test_${pfx}cpp < +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#error not desktop +#endif +#endif +EOF + if [ "$pfx" = "" ]; then + check_func strtoll || add_cflags -Dstrtoll=_strtoi64 + check_func strtoull || add_cflags -Dstrtoull=_strtoui64 + fi + elif test_${pfx}cpp_condition stddef.h "defined __KLIBC__"; then + eval ${pfx}libc_type=klibc + elif test_${pfx}cpp_condition sys/cdefs.h "defined __BIONIC__"; then + eval ${pfx}libc_type=bionic + elif test_${pfx}cpp_condition sys/brand.h "defined LABELED_BRAND_NAME"; then + eval ${pfx}libc_type=solaris + add_${pfx}cppflags -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 + elif test_${pfx}cpp_condition sys/version.h "defined __DJGPP__"; then + eval ${pfx}libc_type=djgpp + add_cppflags -U__STRICT_ANSI__ + add_cflags "-include $source_path/compat/djgpp/math.h" + add_compat djgpp/math.o + fi + test_${pfx}cc < +void *v = localtime_r; +EOF +test "$?" != 0 && test_${pfx}cc -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 < +void *v = localtime_r; +EOF + + eval test -n "\${${pfx}libc_type}" && enable ${pfx}libc_${libc_type} +} + +probe_libc +probe_libc host_ + +# hacks for compiler/libc/os combinations + +case $libc_type in + bionic) + add_compat strtod.o strtod=avpriv_strtod + ;; +esac + +check_compile_assert flt_lim "float.h limits.h" "DBL_MAX == (double)DBL_MAX" || + add_cppflags '-I\$(SRC_PATH)/compat/float' + +test_cpp_condition stdlib.h "defined(__PIC__) || defined(__pic__) || defined(PIC)" && enable_weak pic + +set_default libdir +: ${shlibdir_default:="$libdir"} +: ${pkgconfigdir_default:="$libdir/pkgconfig"} + +set_default $PATHS_LIST +set_default nm + +disabled optimizations || enabled ossfuzz || check_cflags -fomit-frame-pointer + +enable_weak_pic() { + disabled pic && return + enable pic + add_cppflags -DPIC + case "$target_os" in + mingw*|cygwin*|win*) + ;; + *) + add_cflags -fPIC + add_asflags -fPIC + ;; + esac +} + +enabled pic && enable_weak_pic + +test_cc <= 30"; then + : + elif ! test_cpp_condition stddef.h "defined __ARM_PCS || defined __SOFTFP__" && [ $target_os != darwin ]; then + case "${cross_prefix:-$cc}" in + *hardfloat*) enable vfp_args; fpabi=vfp ;; + *) check_ld "cc" vfp_args <= 9.0.18.0" "$ffnv_hdr_list" "" || \ + check_pkg_config ffnvcodec "ffnvcodec >= 8.2.15.8 ffnvcodec < 8.3" "$ffnv_hdr_list" "" || \ + check_pkg_config ffnvcodec "ffnvcodec >= 8.1.24.9 ffnvcodec < 8.2" "$ffnv_hdr_list" "" || \ + check_pkg_config ffnvcodec "ffnvcodec >= 8.0.14.9 ffnvcodec < 8.1" "$ffnv_hdr_list" "" +fi + +check_cpp_condition winrt windows.h "!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)" + +if ! disabled w32threads && ! enabled pthreads; then + check_func_headers "windows.h process.h" _beginthreadex && + check_type "windows.h" CONDITION_VARIABLE && + check_type "windows.h" INIT_ONCE && + enable w32threads || disable w32threads + if ! enabled w32threads && enabled winrt; then + check_func_headers "windows.h" CreateThread && + enable w32threads || disable w32threads + fi +fi + +# check for some common methods of building with pthread support +# do this before the optional library checks as some of them require pthreads +if ! disabled pthreads && ! enabled w32threads && ! enabled os2threads; then + if check_lib pthreads pthread.h pthread_join -pthread && + check_lib pthreads pthread.h pthread_create -pthread; then + add_cflags -pthread + elif check_lib pthreads pthread.h pthread_join -pthreads && + check_lib pthreads pthread.h pthread_create -pthreads; then + add_cflags -pthreads + elif check_lib pthreads pthread.h pthread_join -ldl -pthread && + check_lib pthreads pthread.h pthread_create -ldl -pthread; then + add_cflags -ldl -pthread + elif check_lib pthreads pthread.h pthread_join -lpthreadGC2 && + check_lib pthreads pthread.h pthread_create -lpthreadGC2; then + : + elif check_lib pthreads pthread.h pthread_join -lpthread && + check_lib pthreads pthread.h pthread_create -lpthread; then + : + elif check_func pthread_join && check_func pthread_create; then + enable pthreads + fi + check_cc pthreads "pthread.h" "static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER" + + if enabled pthreads; then + check_builtin sem_timedwait semaphore.h "sem_t *s; sem_init(s,0,0); sem_timedwait(s,0); sem_destroy(s)" $pthreads_extralibs + check_func pthread_cancel $pthreads_extralibs + fi +fi + +enabled zlib && { check_pkg_config zlib zlib "zlib.h" zlibVersion || + check_lib zlib zlib.h zlibVersion -lz; } +enabled bzlib && check_lib bzlib bzlib.h BZ2_bzlibVersion -lbz2 +enabled lzma && check_lib lzma lzma.h lzma_version_number -llzma + +# On some systems dynamic loading requires no extra linker flags +check_lib libdl dlfcn.h "dlopen dlsym" || check_lib libdl dlfcn.h "dlopen dlsym" -ldl + +check_lib libm math.h sin -lm + +atan2f_args=2 +copysign_args=2 +hypot_args=2 +ldexpf_args=2 +powf_args=2 + +for func in $MATH_FUNCS; do + eval check_mathfunc $func \${${func}_args:-1} $libm_extralibs +done + +for func in $COMPLEX_FUNCS; do + eval check_complexfunc $func \${${func}_args:-1} +done + +# these are off by default, so fail if requested and not available +enabled cuda_nvcc && { check_nvcc cuda_nvcc || die "ERROR: failed checking for nvcc."; } +enabled chromaprint && require chromaprint chromaprint.h chromaprint_get_version -lchromaprint +enabled decklink && { require_headers DeckLinkAPI.h && + { test_cpp_condition DeckLinkAPIVersion.h "BLACKMAGIC_DECKLINK_API_VERSION >= 0x0a090500" || die "ERROR: Decklink API version must be >= 10.9.5."; } } +enabled frei0r && require_headers "frei0r.h dlfcn.h" +enabled gmp && require gmp gmp.h mpz_export -lgmp +enabled gnutls && require_pkg_config gnutls gnutls gnutls/gnutls.h gnutls_global_init +enabled jni && { [ $target_os = "android" ] && check_headers jni.h && enabled pthreads || die "ERROR: jni not found"; } +enabled ladspa && require_headers "ladspa.h dlfcn.h" +enabled libaom && require_pkg_config libaom "aom >= 1.0.0" aom/aom_codec.h aom_codec_version +enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "aribb24/aribb24.h" arib_instance_new || + { enabled gpl && require_pkg_config libaribb24 aribb24 "aribb24/aribb24.h" arib_instance_new; } || + die "ERROR: libaribb24 requires version higher than 1.0.3 or --enable-gpl."; } +enabled lv2 && require_pkg_config lv2 lilv-0 "lilv/lilv.h" lilv_world_new +enabled libiec61883 && require libiec61883 libiec61883/iec61883.h iec61883_cmp_connect -lraw1394 -lavc1394 -lrom1394 -liec61883 +enabled libass && require_pkg_config libass libass ass/ass.h ass_library_init +enabled libbluray && require_pkg_config libbluray libbluray libbluray/bluray.h bd_open +enabled libbs2b && require_pkg_config libbs2b libbs2b bs2b.h bs2b_open +enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && + { check_lib libcelt celt/celt.h celt_decoder_create_custom -lcelt0 || + die "ERROR: libcelt must be installed and version must be >= 0.11.0."; } +enabled libcaca && require_pkg_config libcaca caca caca.h caca_create_canvas +enabled libcodec2 && require libcodec2 codec2/codec2.h codec2_create -lcodec2 +enabled libdav1d && require_pkg_config libdav1d "dav1d >= 0.2.1" "dav1d/dav1d.h" dav1d_version +enabled libdavs2 && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open +enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new +enabled libdrm && require_pkg_config libdrm libdrm xf86drm.h drmGetVersion +enabled libfdk_aac && { check_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen || + { require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac && + warn "using libfdk without pkg-config"; } } +flite_extralibs="-lflite_cmu_time_awb -lflite_cmu_us_awb -lflite_cmu_us_kal -lflite_cmu_us_kal16 -lflite_cmu_us_rms -lflite_cmu_us_slt -lflite_usenglish -lflite_cmulex -lflite" +enabled libflite && require libflite "flite/flite.h" flite_init $flite_extralibs +enabled fontconfig && enable libfontconfig +enabled libfontconfig && require_pkg_config libfontconfig fontconfig "fontconfig/fontconfig.h" FcInit +enabled libfreetype && require_pkg_config libfreetype freetype2 "ft2build.h FT_FREETYPE_H" FT_Init_FreeType +enabled libfribidi && require_pkg_config libfribidi fribidi fribidi.h fribidi_version_info +enabled libgme && { check_pkg_config libgme libgme gme/gme.h gme_new_emu || + require libgme gme/gme.h gme_new_emu -lgme -lstdc++; } +enabled libgsm && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do + check_lib libgsm "${gsm_hdr}" gsm_create -lgsm && break; + done || die "ERROR: libgsm not found"; } +enabled libilbc && require libilbc ilbc.h WebRtcIlbcfix_InitDecode -lilbc $pthreads_extralibs +enabled libklvanc && require libklvanc libklvanc/vanc.h klvanc_context_create -lklvanc +enabled libkvazaar && require_pkg_config libkvazaar "kvazaar >= 0.8.1" kvazaar.h kvz_api_get +enabled liblensfun && require_pkg_config liblensfun lensfun lensfun.h lf_db_new +# While it may appear that require is being used as a pkg-config +# fallback for libmfx, it is actually being used to detect a different +# installation route altogether. If libmfx is installed via the Intel +# Media SDK or Intel Media Server Studio, these don't come with +# pkg-config support. Instead, users should make sure that the build +# can find the libraries and headers through other means. +enabled libmfx && { check_pkg_config libmfx libmfx "mfx/mfxvideo.h" MFXInit || + { require libmfx "mfx/mfxvideo.h" MFXInit "-llibmfx $advapi32_extralibs" && warn "using libmfx without pkg-config"; } } +enabled libmodplug && require_pkg_config libmodplug libmodplug libmodplug/modplug.h ModPlug_Load +enabled libmp3lame && require "libmp3lame >= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame $libm_extralibs +enabled libmysofa && { check_pkg_config libmysofa libmysofa mysofa.h mysofa_load || + require libmysofa mysofa.h mysofa_load -lmysofa $zlib_extralibs; } +enabled libnpp && { check_lib libnpp npp.h nppGetLibVersion -lnppig -lnppicc -lnppc -lnppidei || + check_lib libnpp npp.h nppGetLibVersion -lnppi -lnppc -lnppidei || + die "ERROR: libnpp not found"; } +enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb +enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb +enabled libopencv && { check_headers opencv2/core/core_c.h && + { check_pkg_config libopencv opencv opencv2/core/core_c.h cvCreateImageHeader || + require libopencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } || + require_pkg_config libopencv opencv opencv/cxcore.h cvCreateImageHeader; } +enabled libopenh264 && require_pkg_config libopenh264 openh264 wels/codec_api.h WelsGetCodecVersion +enabled libopenjpeg && { check_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version || + { require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } } +enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create -lstdc++ && append libopenmpt_extralibs "-lstdc++" +enabled libopus && { + enabled libopus_decoder && { + require_pkg_config libopus opus opus_multistream.h opus_multistream_decoder_create + } + enabled libopus_encoder && { + require_pkg_config libopus opus opus_multistream.h opus_multistream_surround_encoder_create + } +} +enabled libpulse && require_pkg_config libpulse libpulse pulse/pulseaudio.h pa_context_new +enabled librsvg && require_pkg_config librsvg librsvg-2.0 librsvg-2.0/librsvg/rsvg.h rsvg_handle_render_cairo +enabled librtmp && require_pkg_config librtmp librtmp librtmp/rtmp.h RTMP_Socket +enabled librubberband && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new -lstdc++ && append librubberband_extralibs "-lstdc++" +enabled libshine && require_pkg_config libshine shine shine/layer3.h shine_encode_buffer +enabled libsmbclient && { check_pkg_config libsmbclient smbclient libsmbclient.h smbc_init || + require libsmbclient libsmbclient.h smbc_init -lsmbclient; } +enabled libsnappy && require libsnappy snappy-c.h snappy_compress -lsnappy -lstdc++ +enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr +enabled libssh && require_pkg_config libssh libssh libssh/sftp.h sftp_init +enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init +enabled libsrt && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket +enabled libtensorflow && require libtensorflow tensorflow/c/c_api.h TF_Version -ltensorflow +enabled libtesseract && require_pkg_config libtesseract tesseract tesseract/capi.h TessBaseAPICreate +enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg +enabled libtls && require_pkg_config libtls libtls tls.h tls_configure +enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame && + { check_lib libtwolame twolame.h twolame_encode_buffer_float32_interleaved -ltwolame || + die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; } +enabled libv4l2 && require_pkg_config libv4l2 libv4l2 libv4l2.h v4l2_ioctl +enabled libvidstab && require_pkg_config libvidstab "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit +enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 1.3.9" libvmaf.h compute_vmaf +enabled libvo_amrwbenc && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc +enabled libvorbis && require_pkg_config libvorbis vorbis vorbis/codec.h vorbis_info_init && + require_pkg_config libvorbisenc vorbisenc vorbis/vorbisenc.h vorbis_encode_init + +enabled libvpx && { + enabled libvpx_vp8_decoder && { + check_pkg_config libvpx_vp8_decoder "vpx >= 1.4.0" "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_vp8_dx || + check_lib libvpx_vp8_decoder "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_vp8_dx VPX_IMG_FMT_HIGHBITDEPTH" "-lvpx $libm_extralibs $pthreads_extralibs" + } + enabled libvpx_vp8_encoder && { + check_pkg_config libvpx_vp8_encoder "vpx >= 1.4.0" "vpx/vpx_encoder.h vpx/vp8cx.h" vpx_codec_vp8_cx || + check_lib libvpx_vp8_encoder "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_vp8_cx VPX_IMG_FMT_HIGHBITDEPTH" "-lvpx $libm_extralibs $pthreads_extralibs" + } + enabled libvpx_vp9_decoder && { + check_pkg_config libvpx_vp9_decoder "vpx >= 1.4.0" "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_vp9_dx || + check_lib libvpx_vp9_decoder "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_vp9_dx VPX_IMG_FMT_HIGHBITDEPTH" "-lvpx $libm_extralibs $pthreads_extralibs" + } + enabled libvpx_vp9_encoder && { + check_pkg_config libvpx_vp9_encoder "vpx >= 1.4.0" "vpx/vpx_encoder.h vpx/vp8cx.h" vpx_codec_vp9_cx || + check_lib libvpx_vp9_encoder "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_vp9_cx VPX_IMG_FMT_HIGHBITDEPTH" "-lvpx $libm_extralibs $pthreads_extralibs" + } + if disabled_all libvpx_vp8_decoder libvpx_vp9_decoder libvpx_vp8_encoder libvpx_vp9_encoder; then + die "libvpx enabled but no supported decoders found" + fi +} + +enabled libwavpack && require libwavpack wavpack/wavpack.h WavpackOpenFileOutput -lwavpack +enabled libwebp && { + enabled libwebp_encoder && require_pkg_config libwebp "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion + enabled libwebp_anim_encoder && check_pkg_config libwebp_anim_encoder "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit; } +enabled libx264 && { check_pkg_config libx264 x264 "stdint.h x264.h" x264_encoder_encode || + { require libx264 "stdint.h x264.h" x264_encoder_encode "-lx264 $pthreads_extralibs $libm_extralibs" && + warn "using libx264 without pkg-config"; } } && + require_cpp_condition libx264 x264.h "X264_BUILD >= 118" && + check_cpp_condition libx262 x264.h "X264_MPEG2" +enabled libx265 && require_pkg_config libx265 x265 x265.h x265_api_get && + require_cpp_condition libx265 x265.h "X265_BUILD >= 68" +enabled libxavs && require libxavs "stdint.h xavs.h" xavs_encoder_encode "-lxavs $pthreads_extralibs $libm_extralibs" +enabled libxavs2 && require_pkg_config libxavs2 "xavs2 >= 1.3.0" "stdint.h xavs2.h" xavs2_api_get +enabled libxvid && require libxvid xvid.h xvid_global -lxvidcore +enabled libzimg && require_pkg_config libzimg "zimg >= 2.7.0" zimg.h zimg_get_api_version +enabled libzmq && require_pkg_config libzmq libzmq zmq.h zmq_ctx_new +enabled libzvbi && require_pkg_config libzvbi zvbi-0.2 libzvbi.h vbi_decoder_new && + { test_cpp_condition libzvbi.h "VBI_VERSION_MAJOR > 0 || VBI_VERSION_MINOR > 2 || VBI_VERSION_MINOR == 2 && VBI_VERSION_MICRO >= 28" || + enabled gpl || die "ERROR: libzvbi requires version 0.2.28 or --enable-gpl."; } +enabled libxml2 && require_pkg_config libxml2 libxml-2.0 libxml2/libxml/xmlversion.h xmlCheckVersion +enabled mbedtls && { check_pkg_config mbedtls mbedtls mbedtls/x509_crt.h mbedtls_x509_crt_init || + check_pkg_config mbedtls mbedtls mbedtls/ssl.h mbedtls_ssl_init || + check_lib mbedtls mbedtls/ssl.h mbedtls_ssl_init -lmbedtls -lmbedx509 -lmbedcrypto || + die "ERROR: mbedTLS not found"; } +enabled mediacodec && { enabled jni || die "ERROR: mediacodec requires --enable-jni"; } +enabled mmal && { check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host || + { ! enabled cross_compile && + add_cflags -isystem/opt/vc/include/ -isystem/opt/vc/include/interface/vmcs_host/linux -isystem/opt/vc/include/interface/vcos/pthreads -fgnu89-inline && + add_ldflags -L/opt/vc/lib/ && + check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host; } || + die "ERROR: mmal not found" && + check_func_headers interface/mmal/mmal.h "MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS"; } +enabled openal && { { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do + check_lib openal 'AL/al.h' alGetError "${al_extralibs}" && break; done } || + die "ERROR: openal not found"; } && + { test_cpp_condition "AL/al.h" "defined(AL_VERSION_1_1)" || + die "ERROR: openal must be installed and version must be 1.1 or compatible"; } +enabled opencl && { check_pkg_config opencl OpenCL CL/cl.h clEnqueueNDRangeKernel || + check_lib opencl OpenCL/cl.h clEnqueueNDRangeKernel -Wl,-framework,OpenCL || + check_lib opencl CL/cl.h clEnqueueNDRangeKernel -lOpenCL || + die "ERROR: opencl not found"; } && + { test_cpp_condition "OpenCL/cl.h" "defined(CL_VERSION_1_2)" || + test_cpp_condition "CL/cl.h" "defined(CL_VERSION_1_2)" || + die "ERROR: opencl must be installed and version must be 1.2 or compatible"; } +enabled opengl && { check_lib opengl GL/glx.h glXGetProcAddress "-lGL" || + check_lib opengl windows.h wglGetProcAddress "-lopengl32 -lgdi32" || + check_lib opengl OpenGL/gl3.h glGetError "-Wl,-framework,OpenGL" || + check_lib opengl ES2/gl.h glGetError "-isysroot=${sysroot} -Wl,-framework,OpenGLES" || + die "ERROR: opengl not found." + } +enabled omx && require_headers OMX_Core.h +enabled omx_rpi && { check_headers OMX_Core.h || + { ! enabled cross_compile && add_cflags -isystem/opt/vc/include/IL && check_headers OMX_Core.h ; } || + die "ERROR: OpenMAX IL headers not found"; } && enable omx +enabled openssl && { check_pkg_config openssl openssl openssl/ssl.h OPENSSL_init_ssl || + check_pkg_config openssl openssl openssl/ssl.h SSL_library_init || + check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto || + check_lib openssl openssl/ssl.h SSL_library_init -lssl32 -leay32 || + check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 || + die "ERROR: openssl not found"; } +enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init +enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create && + require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.7" rockchip/rk_mpi.h mpp_create && + { enabled libdrm || + die "ERROR: rkmpp requires --enable-libdrm"; } + } +enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init + + +if enabled gcrypt; then + GCRYPT_CONFIG="${cross_prefix}libgcrypt-config" + if "${GCRYPT_CONFIG}" --version > /dev/null 2>&1; then + gcrypt_cflags=$("${GCRYPT_CONFIG}" --cflags) + gcrypt_extralibs=$("${GCRYPT_CONFIG}" --libs) + check_func_headers gcrypt.h gcry_mpi_new $gcrypt_cflags $gcrypt_extralibs || + die "ERROR: gcrypt not found" + add_cflags $gcrypt_cflags + else + require gcrypt gcrypt.h gcry_mpi_new -lgcrypt + fi +fi + +if enabled sdl2; then + SDL2_CONFIG="${cross_prefix}sdl2-config" + test_pkg_config sdl2 "sdl2 >= 2.0.1 sdl2 < 2.1.0" SDL_events.h SDL_PollEvent + if disabled sdl2 && "${SDL2_CONFIG}" --version > /dev/null 2>&1; then + sdl2_cflags=$("${SDL2_CONFIG}" --cflags) + sdl2_extralibs=$("${SDL2_CONFIG}" --libs) + test_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) >= 0x020001" $sdl2_cflags && + test_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) < 0x020100" $sdl2_cflags && + check_func_headers SDL_events.h SDL_PollEvent $sdl2_extralibs $sdl2_cflags && + enable sdl2 + fi + if test $target_os = "mingw32"; then + sdl2_extralibs=$(filter_out '-mwindows' $sdl2_extralibs) + fi +fi + +if enabled decklink; then + case $target_os in + mingw32*|mingw64*|win32|win64) + decklink_outdev_extralibs="$decklink_outdev_extralibs -lole32 -loleaut32" + decklink_indev_extralibs="$decklink_indev_extralibs -lole32 -loleaut32" + ;; + esac +fi + +enabled securetransport && + check_func SecIdentityCreate "-Wl,-framework,CoreFoundation -Wl,-framework,Security" && + check_lib securetransport "Security/SecureTransport.h Security/Security.h" "SSLCreateContext" "-Wl,-framework,CoreFoundation -Wl,-framework,Security" || + disable securetransport + +enabled securetransport && + check_func SecItemImport "-Wl,-framework,CoreFoundation -Wl,-framework,Security" + +enabled schannel && + check_func_headers "windows.h security.h" InitializeSecurityContext -DSECURITY_WIN32 -lsecur32 && + test_cpp_condition winerror.h "defined(SEC_I_CONTEXT_EXPIRED)" && + schannel_extralibs="-lsecur32" || + disable schannel + +makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable makeinfo +enabled makeinfo \ + && [ 0$(makeinfo --version | grep "texinfo" | sed 's/.*texinfo[^0-9]*\([0-9]*\)\..*/\1/') -ge 5 ] \ + && enable makeinfo_html || disable makeinfo_html +disabled makeinfo_html && texi2html --help 2> /dev/null | grep -q 'init-file' && enable texi2html || disable texi2html +perl -v > /dev/null 2>&1 && enable perl || disable perl +pod2man --help > /dev/null 2>&1 && enable pod2man || disable pod2man +rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout + +# check V4L2 codecs available in the API +check_headers linux/fb.h +check_headers linux/videodev2.h +test_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete +check_cc v4l2_m2m linux/videodev2.h "int i = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_VIDEO_M2M | V4L2_BUF_FLAG_LAST;" +check_cc vc1_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VC1_ANNEX_G;" +check_cc mpeg1_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG1;" +check_cc mpeg2_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG2;" +check_cc mpeg4_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG4;" +check_cc hevc_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_HEVC;" +check_cc h263_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_H263;" +check_cc h264_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_H264;" +check_cc vp8_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP8;" +check_cc vp9_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP9;" + +check_headers sys/videoio.h +test_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete + +check_lib user32 "windows.h winuser.h" GetShellWindow -luser32 +check_lib vfw32 "windows.h vfw.h" capCreateCaptureWindow -lvfw32 +# check that WM_CAP_DRIVER_CONNECT is defined to the proper value +# w32api 3.12 had it defined wrong +check_cpp_condition vfwcap_defines vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" + +check_type "dshow.h" IBaseFilter + +# check for ioctl_meteor.h, ioctl_bt848.h and alternatives +check_headers "dev/bktr/ioctl_meteor.h dev/bktr/ioctl_bt848.h" || + check_headers "machine/ioctl_meteor.h machine/ioctl_bt848.h" || + check_headers "dev/video/meteor/ioctl_meteor.h dev/video/bktr/ioctl_bt848.h" || + check_headers "dev/ic/bt8xx.h" + +if check_struct sys/soundcard.h audio_buf_info bytes; then + enable_sanitized sys/soundcard.h +else + test_cc -D__BSD_VISIBLE -D__XSI_VISIBLE < + audio_buf_info abc; +EOF +fi + +enabled alsa && check_pkg_config alsa alsa "alsa/asoundlib.h" snd_pcm_htimestamp || + check_lib alsa alsa/asoundlib.h snd_pcm_htimestamp -lasound + +enabled libjack && + require_pkg_config libjack jack jack/jack.h jack_port_get_latency_range + +enabled sndio && check_lib sndio sndio.h sio_open -lsndio + +if enabled libcdio; then + check_pkg_config libcdio libcdio_paranoia "cdio/cdda.h cdio/paranoia.h" cdio_cddap_open || + check_pkg_config libcdio libcdio_paranoia "cdio/paranoia/cdda.h cdio/paranoia/paranoia.h" cdio_cddap_open || + check_lib libcdio "cdio/cdda.h cdio/paranoia.h" cdio_cddap_open -lcdio_paranoia -lcdio_cdda -lcdio || + check_lib libcdio "cdio/paranoia/cdda.h cdio/paranoia/paranoia.h" cdio_cddap_open -lcdio_paranoia -lcdio_cdda -lcdio || + die "ERROR: No usable libcdio/cdparanoia found" +fi + +enabled libxcb && check_pkg_config libxcb "xcb >= 1.4" xcb/xcb.h xcb_connect || + disable libxcb_shm libxcb_shape libxcb_xfixes + +if enabled libxcb; then + enabled libxcb_shm && check_pkg_config libxcb_shm xcb-shm xcb/shm.h xcb_shm_attach + enabled libxcb_shape && check_pkg_config libxcb_shape xcb-shape xcb/shape.h xcb_shape_get_rectangles + enabled libxcb_xfixes && check_pkg_config libxcb_xfixes xcb-xfixes xcb/xfixes.h xcb_xfixes_get_cursor_image +fi + +check_func_headers "windows.h" CreateDIBSection "$gdigrab_indev_extralibs" + +# d3d11va requires linking directly to dxgi and d3d11 if not building for +# the desktop api partition +test_cpp < +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#error desktop, not uwp +#else +// WINAPI_FAMILY_APP, WINAPI_FAMILY_PHONE_APP => UWP +#endif +#else +#error no family set +#endif +EOF + +enabled vaapi && + check_pkg_config vaapi "libva >= 0.35.0" "va/va.h" vaInitialize + +if enabled vaapi; then + check_pkg_config vaapi_drm "libva-drm" "va/va_drm.h" vaGetDisplayDRM + + if enabled xlib; then + check_pkg_config vaapi_x11 "libva-x11" "va/va_x11.h" vaGetDisplay + fi + + check_cpp_condition vaapi_1 "va/va.h" "VA_CHECK_VERSION(1, 0, 0)" + + check_type "va/va.h va/va_dec_hevc.h" "VAPictureParameterBufferHEVC" + check_struct "va/va.h" "VADecPictureParameterBufferVP9" bit_depth + check_struct "va/va.h va/va_vpp.h" "VAProcPipelineCaps" rotation_flags + check_type "va/va.h va/va_enc_hevc.h" "VAEncPictureParameterBufferHEVC" + check_type "va/va.h va/va_enc_jpeg.h" "VAEncPictureParameterBufferJPEG" + check_type "va/va.h va/va_enc_vp8.h" "VAEncPictureParameterBufferVP8" + check_type "va/va.h va/va_enc_vp9.h" "VAEncPictureParameterBufferVP9" +fi + +if enabled_all opencl libdrm ; then + check_type "CL/cl_intel.h" "clCreateImageFromFdINTEL_fn" && + enable opencl_drm_beignet + check_func_headers "CL/cl_ext.h" clImportMemoryARM && + enable opencl_drm_arm +fi + +if enabled_all opencl vaapi ; then + if enabled opencl_drm_beignet ; then + enable opencl_vaapi_beignet + else + check_type "CL/cl.h CL/cl_va_api_media_sharing_intel.h" "clCreateFromVA_APIMediaSurfaceINTEL_fn" && + enable opencl_vaapi_intel_media + fi +fi + +if enabled_all opencl dxva2 ; then + check_type "CL/cl_dx9_media_sharing.h" cl_dx9_surface_info_khr && + enable opencl_dxva2 +fi + +if enabled_all opencl d3d11va ; then + check_type "CL/cl_d3d11.h" clGetDeviceIDsFromD3D11KHR_fn && + enable opencl_d3d11 +fi + +enabled vdpau && + check_cpp_condition vdpau vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" + +enabled vdpau && + check_lib vdpau_x11 "vdpau/vdpau.h vdpau/vdpau_x11.h" vdp_device_create_x11 -lvdpau -lX11 + +enabled crystalhd && check_lib crystalhd "stdint.h libcrystalhd/libcrystalhd_if.h" DtsCrystalHDVersion -lcrystalhd + +if enabled x86; then + case $target_os in + mingw32*|mingw64*|win32|win64|linux|cygwin*) + ;; + *) + disable ffnvcodec cuvid nvdec nvenc + ;; + esac +elif enabled ppc64 && ! enabled bigendian; then + case $target_os in + linux) + ;; + *) + disable ffnvcodec cuvid nvdec nvenc + ;; + esac +else + disable ffnvcodec cuvid nvdec nvenc +fi + +enabled ffnvcodec && enable cuda + +enabled nvenc && + test_cc -I$source_path < +NV_ENCODE_API_FUNCTION_LIST flist; +void f(void) { struct { const GUID guid; } s[] = { { NV_ENC_PRESET_HQ_GUID } }; } +int main(void) { return 0; } +EOF + +enabled amf && + check_cpp_condition amf "AMF/core/Version.h" \ + "(AMF_VERSION_MAJOR << 48 | AMF_VERSION_MINOR << 32 | AMF_VERSION_RELEASE << 16 | AMF_VERSION_BUILD_NUM) >= 0x0001000400040001" + +# Funny iconv installations are not unusual, so check it after all flags have been set +if enabled libc_iconv; then + check_func_headers iconv.h iconv +elif enabled iconv; then + check_func_headers iconv.h iconv || check_lib iconv iconv.h iconv -liconv +fi + +enabled debug && add_cflags -g"$debuglevel" && add_asflags -g"$debuglevel" + +# add some useful compiler flags if supported +check_cflags -Wdeclaration-after-statement +check_cflags -Wall +check_cflags -Wdisabled-optimization +check_cflags -Wpointer-arith +check_cflags -Wredundant-decls +check_cflags -Wwrite-strings +check_cflags -Wtype-limits +check_cflags -Wundef +check_cflags -Wmissing-prototypes +check_cflags -Wno-pointer-to-int-cast +check_cflags -Wstrict-prototypes +check_cflags -Wempty-body + +if enabled extra_warnings; then + check_cflags -Wcast-qual + check_cflags -Wextra + check_cflags -Wpedantic +fi + +check_disable_warning(){ + warning_flag=-W${1#-Wno-} + test_cflags $unknown_warning_flags $warning_flag && add_cflags $1 +} + +test_cflags -Werror=unused-command-line-argument && + append unknown_warning_flags "-Werror=unused-command-line-argument" +test_cflags -Werror=unknown-warning-option && + append unknown_warning_flags "-Werror=unknown-warning-option" + +check_disable_warning -Wno-parentheses +check_disable_warning -Wno-switch +check_disable_warning -Wno-format-zero-length +check_disable_warning -Wno-pointer-sign +check_disable_warning -Wno-unused-const-variable +check_disable_warning -Wno-bool-operation +check_disable_warning -Wno-char-subscripts + +check_disable_warning_headers(){ + warning_flag=-W${1#-Wno-} + test_cflags $warning_flag && add_cflags_headers $1 +} + +check_disable_warning_headers -Wno-deprecated-declarations +check_disable_warning_headers -Wno-unused-variable + +test_cc < $TMPV + if test_ldflags -Wl,${version_script},$TMPV; then + append SHFLAGS '-Wl,${version_script},\$(SUBDIR)lib\$(NAME).ver' + quotes='""' + test_cc <= 1400" && + add_cflags -Qansi-alias + # Some inline asm is not compilable in debug + if enabled debug; then + disable ebp_available + disable ebx_available + fi + fi + # msvcrt10 x64 incorrectly enables log2, only msvcrt12 (MSVC 2013) onwards actually has log2. + check_cpp_condition log2 crtversion.h "_VC_CRT_MAJOR_VERSION >= 12" + # The CRT headers contain __declspec(restrict) in a few places, but if redefining + # restrict, this might break. MSVC 2010 and 2012 fail with __declspec(__restrict) + # (as it ends up if the restrict redefine is done before including stdlib.h), while + # MSVC 2013 and newer can handle it fine. + # If this declspec fails, force including stdlib.h before the restrict redefinition + # happens in config.h. + if [ $restrict_keyword != restrict ]; then + test_cc <= 190024218" || + check_cflags -d2SSAOptimizer- + # enable utf-8 source processing on VS2015 U2 and newer + test_cpp_condition windows.h "_MSC_FULL_VER >= 190023918" && + add_cflags -utf-8 +fi + +for pfx in "" host_; do + varname=${pfx%_}cc_type + eval "type=\$$varname" + if [ "$type" = "msvc" ]; then + test_${pfx}cc < Makefile + +esc(){ + echo "$*" | sed 's/%/%25/g;s/:/%3a/g' +} + +echo "config:$arch:$subarch:$cpu:$target_os:$(esc $cc_ident):$(esc $FFMPEG_CONFIGURATION)" > ffbuild/config.fate + +enabled stripping || strip="echo skipping strip" +enabled stripping || striptype="" + +config_files="$TMPH ffbuild/config.mak" + +cat > ffbuild/config.mak <> ffbuild/config.mak' $LIBRARY_LIST + +for entry in $LIBRARY_LIST $PROGRAM_LIST $EXTRALIBS_LIST; do + eval echo "EXTRALIBS-${entry}=\$${entry}_extralibs" >> ffbuild/config.mak +done + +cat > $TMPH <>$TMPH + +test -n "$malloc_prefix" && + echo "#define MALLOC_PREFIX $malloc_prefix" >>$TMPH + +if enabled x86asm; then + append config_files $TMPASM + cat > $TMPASM <> $TMPH + +print_config ARCH_ "$config_files" $ARCH_LIST +print_config HAVE_ "$config_files" $HAVE_LIST +print_config CONFIG_ "$config_files" $CONFIG_LIST \ + $CONFIG_EXTRA \ + $ALL_COMPONENTS \ + +echo "#endif /* FFMPEG_CONFIG_H */" >> $TMPH +echo "endif # FFMPEG_CONFIG_MAK" >> ffbuild/config.mak + +# Do not overwrite an unchanged config.h to avoid superfluous rebuilds. +cp_if_changed $TMPH config.h +touch ffbuild/.config + +enabled x86asm && cp_if_changed $TMPASM config.asm + +cat > $TMPH <> $TMPH + +cp_if_changed $TMPH libavutil/avconfig.h + +# full_filter_name_foo=vf_foo +# full_filter_name_bar=asrc_bar +# ... +eval "$(sed -n "s/^extern AVFilter ff_\([avfsinkrc]\{2,5\}\)_\(.*\);/full_filter_name_\2=\1_\2/p" $source_path/libavfilter/allfilters.c)" + +# generate the lists of enabled components +print_enabled_components(){ + file=$1 + struct_name=$2 + name=$3 + shift 3 + echo "static const $struct_name * const $name[] = {" > $TMPH + for c in $*; do + if enabled $c; then + case $name in + filter_list) + eval c=\$full_filter_name_${c%_filter} + ;; + indev_list) + c=${c%_indev}_demuxer + ;; + outdev_list) + c=${c%_outdev}_muxer + ;; + esac + printf " &ff_%s,\n" $c >> $TMPH + fi + done + if [ "$name" = "filter_list" ]; then + for c in asrc_abuffer vsrc_buffer asink_abuffer vsink_buffer; do + printf " &ff_%s,\n" $c >> $TMPH + done + fi + echo " NULL };" >> $TMPH + cp_if_changed $TMPH $file +} + +print_enabled_components libavfilter/filter_list.c AVFilter filter_list $FILTER_LIST +print_enabled_components libavcodec/codec_list.c AVCodec codec_list $CODEC_LIST +print_enabled_components libavcodec/parser_list.c AVCodecParser parser_list $PARSER_LIST +print_enabled_components libavcodec/bsf_list.c AVBitStreamFilter bitstream_filters $BSF_LIST +print_enabled_components libavformat/demuxer_list.c AVInputFormat demuxer_list $DEMUXER_LIST +print_enabled_components libavformat/muxer_list.c AVOutputFormat muxer_list $MUXER_LIST +print_enabled_components libavdevice/indev_list.c AVInputFormat indev_list $INDEV_LIST +print_enabled_components libavdevice/outdev_list.c AVOutputFormat outdev_list $OUTDEV_LIST +print_enabled_components libavformat/protocol_list.c URLProtocol url_protocols $PROTOCOL_LIST + +# Settings for pkg-config files + +cat > $TMPH <> $TMPH +done + +cp_if_changed $TMPH ffbuild/config.sh diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/arch.mak b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/arch.mak new file mode 100644 index 0000000000..e09006efca --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/arch.mak @@ -0,0 +1,17 @@ +OBJS-$(HAVE_ARMV5TE) += $(ARMV5TE-OBJS) $(ARMV5TE-OBJS-yes) +OBJS-$(HAVE_ARMV6) += $(ARMV6-OBJS) $(ARMV6-OBJS-yes) +OBJS-$(HAVE_ARMV8) += $(ARMV8-OBJS) $(ARMV8-OBJS-yes) +OBJS-$(HAVE_VFP) += $(VFP-OBJS) $(VFP-OBJS-yes) +OBJS-$(HAVE_NEON) += $(NEON-OBJS) $(NEON-OBJS-yes) + +OBJS-$(HAVE_MIPSFPU) += $(MIPSFPU-OBJS) $(MIPSFPU-OBJS-yes) +OBJS-$(HAVE_MIPSDSP) += $(MIPSDSP-OBJS) $(MIPSDSP-OBJS-yes) +OBJS-$(HAVE_MIPSDSPR2) += $(MIPSDSPR2-OBJS) $(MIPSDSPR2-OBJS-yes) +OBJS-$(HAVE_MSA) += $(MSA-OBJS) $(MSA-OBJS-yes) +OBJS-$(HAVE_MMI) += $(MMI-OBJS) $(MMI-OBJS-yes) + +OBJS-$(HAVE_ALTIVEC) += $(ALTIVEC-OBJS) $(ALTIVEC-OBJS-yes) +OBJS-$(HAVE_VSX) += $(VSX-OBJS) $(VSX-OBJS-yes) + +OBJS-$(HAVE_MMX) += $(MMX-OBJS) $(MMX-OBJS-yes) +OBJS-$(HAVE_X86ASM) += $(X86ASM-OBJS) $(X86ASM-OBJS-yes) diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/common.mak b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/common.mak new file mode 100644 index 0000000000..7355508ea0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/common.mak @@ -0,0 +1,175 @@ +# +# common bits used by all libraries +# + +DEFAULT_X86ASMD=.dbg + +ifeq ($(DBG),1) +X86ASMD=$(DEFAULT_X86ASMD) +else +X86ASMD= +endif + +ifndef SUBDIR + +ifndef V +Q = @ +ECHO = printf "$(1)\t%s\n" $(2) +BRIEF = CC CXX OBJCC HOSTCC HOSTLD AS X86ASM AR LD STRIP CP WINDRES NVCC +SILENT = DEPCC DEPHOSTCC DEPAS DEPX86ASM RANLIB RM + +MSG = $@ +M = @$(call ECHO,$(TAG),$@); +$(foreach VAR,$(BRIEF), \ + $(eval override $(VAR) = @$$(call ECHO,$(VAR),$$(MSG)); $($(VAR)))) +$(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR)))) +$(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL)) +endif + +ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample + +# NASM requires -I path terminated with / +IFLAGS := -I. -I$(SRC_LINK)/ +CPPFLAGS := $(IFLAGS) $(CPPFLAGS) +CFLAGS += $(ECFLAGS) +CCFLAGS = $(CPPFLAGS) $(CFLAGS) +OBJCFLAGS += $(EOBJCFLAGS) +OBJCCFLAGS = $(CPPFLAGS) $(CFLAGS) $(OBJCFLAGS) +ASFLAGS := $(CPPFLAGS) $(ASFLAGS) +CXXFLAGS := $(CPPFLAGS) $(CFLAGS) $(CXXFLAGS) +X86ASMFLAGS += $(IFLAGS:%=%/) -I$( $(@:.asm=.d) + $(X86ASM) $(X86ASMFLAGS) -e $< | sed '/^%/d;/^$$/d;' > $@ + +%.o: %.asm + $(COMPILE_X86ASM) + -$(if $(ASMSTRIPFLAGS), $(STRIP) $(ASMSTRIPFLAGS) $@) + +%.o: %.rc + $(WINDRES) $(IFLAGS) --preprocessor "$(DEPWINDRES) -E -xc-header -DRC_INVOKED $(CC_DEPFLAGS)" -o $@ $< + +%.i: %.c + $(CC) $(CCFLAGS) $(CC_E) $< + +%.h.c: + $(Q)echo '#include "$*.h"' >$@ + +%.ptx: %.cu $(SRC_PATH)/compat/cuda/cuda_runtime.h + $(COMPILE_NVCC) + +%.ptx.c: %.ptx + $(Q)sh $(SRC_PATH)/compat/cuda/ptx2c.sh $@ $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<) + +%.c %.h %.pc %.ver %.version: TAG = GEN + +# Dummy rule to stop make trying to rebuild removed or renamed headers +%.h: + @: + +# Disable suffix rules. Most of the builtin rules are suffix rules, +# so this saves some time on slow systems. +.SUFFIXES: + +# Do not delete intermediate files from chains of implicit rules +$(OBJS): +endif + +include $(SRC_PATH)/ffbuild/arch.mak + +OBJS += $(OBJS-yes) +SLIBOBJS += $(SLIBOBJS-yes) +FFLIBS := $($(NAME)_FFLIBS) $(FFLIBS-yes) $(FFLIBS) +TESTPROGS += $(TESTPROGS-yes) + +LDLIBS = $(FFLIBS:%=%$(BUILDSUF)) +FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(foreach lib,EXTRALIBS-$(NAME) $(FFLIBS:%=EXTRALIBS-%),$($(lib))) $(EXTRALIBS) + +OBJS := $(sort $(OBJS:%=$(SUBDIR)%)) +SLIBOBJS := $(sort $(SLIBOBJS:%=$(SUBDIR)%)) +TESTOBJS := $(TESTOBJS:%=$(SUBDIR)tests/%) $(TESTPROGS:%=$(SUBDIR)tests/%.o) +TESTPROGS := $(TESTPROGS:%=$(SUBDIR)tests/%$(EXESUF)) +HOSTOBJS := $(HOSTPROGS:%=$(SUBDIR)%.o) +HOSTPROGS := $(HOSTPROGS:%=$(SUBDIR)%$(HOSTEXESUF)) +TOOLS += $(TOOLS-yes) +TOOLOBJS := $(TOOLS:%=tools/%.o) +TOOLS := $(TOOLS:%=tools/%$(EXESUF)) +HEADERS += $(HEADERS-yes) + +PATH_LIBNAME = $(foreach NAME,$(1),lib$(NAME)/$($(2)LIBNAME)) +DEP_LIBS := $(foreach lib,$(FFLIBS),$(call PATH_LIBNAME,$(lib),$(CONFIG_SHARED:yes=S))) +STATIC_DEP_LIBS := $(foreach lib,$(FFLIBS),$(call PATH_LIBNAME,$(lib))) + +SRC_DIR := $(SRC_PATH)/lib$(NAME) +ALLHEADERS := $(subst $(SRC_DIR)/,$(SUBDIR),$(wildcard $(SRC_DIR)/*.h $(SRC_DIR)/$(ARCH)/*.h)) +SKIPHEADERS += $(ARCH_HEADERS:%=$(ARCH)/%) $(SKIPHEADERS-) +SKIPHEADERS := $(SKIPHEADERS:%=$(SUBDIR)%) +HOBJS = $(filter-out $(SKIPHEADERS:.h=.h.o),$(ALLHEADERS:.h=.h.o)) +PTXOBJS = $(filter %.ptx.o,$(OBJS)) +$(HOBJS): CCFLAGS += $(CFLAGS_HEADERS) +checkheaders: $(HOBJS) +.SECONDARY: $(HOBJS:.o=.c) $(PTXOBJS:.o=.c) $(PTXOBJS:.o=) + +alltools: $(TOOLS) + +$(HOSTOBJS): %.o: %.c + $(COMPILE_HOSTC) + +$(HOSTPROGS): %$(HOSTEXESUF): %.o + $(HOSTLD) $(HOSTLDFLAGS) $(HOSTLD_O) $^ $(HOSTEXTRALIBS) + +$(OBJS): | $(sort $(dir $(OBJS))) +$(HOBJS): | $(sort $(dir $(HOBJS))) +$(HOSTOBJS): | $(sort $(dir $(HOSTOBJS))) +$(SLIBOBJS): | $(sort $(dir $(SLIBOBJS))) +$(TESTOBJS): | $(sort $(dir $(TESTOBJS))) +$(TOOLOBJS): | tools + +OUTDIRS := $(OUTDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SLIBOBJS) $(TESTOBJS)) + +CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.pc *.ptx *.ptx.c *.ver *.version *$(DEFAULT_X86ASMD).asm *~ +LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a + +define RULES +clean:: + $(RM) $(HOSTPROGS) $(TESTPROGS) $(TOOLS) +endef + +$(eval $(RULES)) + +-include $(wildcard $(OBJS:.o=.d) $(HOSTOBJS:.o=.d) $(TESTOBJS:.o=.d) $(HOBJS:.o=.d) $(SLIBOBJS:.o=.d)) $(OBJS:.o=$(DEFAULT_X86ASMD).d) diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/library.mak b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/library.mak new file mode 100644 index 0000000000..612bacb980 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/library.mak @@ -0,0 +1,107 @@ +include $(SRC_PATH)/ffbuild/common.mak + +ifeq (,$(filter %clean config,$(MAKECMDGOALS))) +-include $(SUBDIR)lib$(NAME).version +endif + +LIBVERSION := $(lib$(NAME)_VERSION) +LIBMAJOR := $(lib$(NAME)_VERSION_MAJOR) +LIBMINOR := $(lib$(NAME)_VERSION_MINOR) +INCINSTDIR := $(INCDIR)/lib$(NAME) + +INSTHEADERS := $(INSTHEADERS) $(HEADERS:%=$(SUBDIR)%) + +all-$(CONFIG_STATIC): $(SUBDIR)$(LIBNAME) $(SUBDIR)lib$(FULLNAME).pc +all-$(CONFIG_SHARED): $(SUBDIR)$(SLIBNAME) $(SUBDIR)lib$(FULLNAME).pc + +LIBOBJS := $(OBJS) $(SUBDIR)%.h.o $(TESTOBJS) +$(LIBOBJS) $(LIBOBJS:.o=.s) $(LIBOBJS:.o=.i): CPPFLAGS += -DHAVE_AV_CONFIG_H + +$(SUBDIR)$(LIBNAME): $(OBJS) + $(RM) $@ + $(AR) $(ARFLAGS) $(AR_O) $^ + $(RANLIB) $@ + +install-headers: install-lib$(NAME)-headers install-lib$(NAME)-pkgconfig + +install-libs-$(CONFIG_STATIC): install-lib$(NAME)-static +install-libs-$(CONFIG_SHARED): install-lib$(NAME)-shared + +define RULES +$(TOOLS): THISLIB = $(FULLNAME:%=$(LD_LIB)) +$(TESTPROGS): THISLIB = $(SUBDIR)$(LIBNAME) + +$(LIBOBJS): CPPFLAGS += -DBUILDING_$(NAME) + +$(TESTPROGS) $(TOOLS): %$(EXESUF): %.o + $$(LD) $(LDFLAGS) $(LDEXEFLAGS) $$(LD_O) $$(filter %.o,$$^) $$(THISLIB) $(FFEXTRALIBS) $$(EXTRALIBS-$$(*F)) $$(ELIBS) + +$(SUBDIR)lib$(NAME).version: $(SUBDIR)version.h | $(SUBDIR) + $$(M) $$(SRC_PATH)/ffbuild/libversion.sh $(NAME) $$< > $$@ + +$(SUBDIR)lib$(FULLNAME).pc: $(SUBDIR)version.h ffbuild/config.sh | $(SUBDIR) + $$(M) $$(SRC_PATH)/ffbuild/pkgconfig_generate.sh $(NAME) "$(DESC)" + +$(SUBDIR)lib$(NAME).ver: $(SUBDIR)lib$(NAME).v $(OBJS) + $$(M)sed 's/MAJOR/$(lib$(NAME)_VERSION_MAJOR)/' $$< | $(VERSION_SCRIPT_POSTPROCESS_CMD) > $$@ + +$(SUBDIR)$(SLIBNAME): $(SUBDIR)$(SLIBNAME_WITH_MAJOR) + $(Q)cd ./$(SUBDIR) && $(LN_S) $(SLIBNAME_WITH_MAJOR) $(SLIBNAME) + +$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SLIBOBJS) $(SUBDIR)lib$(NAME).ver + $(SLIB_CREATE_DEF_CMD) + $$(LD) $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS) + $(SLIB_EXTRA_CMD) + +ifdef SUBDIR +$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(DEP_LIBS) +endif + +clean:: + $(RM) $(addprefix $(SUBDIR),$(CLEANFILES) $(CLEANSUFFIXES) $(LIBSUFFIXES)) \ + $(CLEANSUFFIXES:%=$(SUBDIR)$(ARCH)/%) $(CLEANSUFFIXES:%=$(SUBDIR)tests/%) + +install-lib$(NAME)-shared: $(SUBDIR)$(SLIBNAME) + $(Q)mkdir -p "$(SHLIBDIR)" + $$(INSTALL) -m 755 $$< "$(SHLIBDIR)/$(SLIB_INSTALL_NAME)" + $$(STRIP) "$(SHLIBDIR)/$(SLIB_INSTALL_NAME)" + $(Q)$(foreach F,$(SLIB_INSTALL_LINKS),(cd "$(SHLIBDIR)" && $(LN_S) $(SLIB_INSTALL_NAME) $(F));) + $(if $(SLIB_INSTALL_EXTRA_SHLIB),$$(INSTALL) -m 644 $(SLIB_INSTALL_EXTRA_SHLIB:%=$(SUBDIR)%) "$(SHLIBDIR)") + $(if $(SLIB_INSTALL_EXTRA_LIB),$(Q)mkdir -p "$(LIBDIR)") + $(if $(SLIB_INSTALL_EXTRA_LIB),$$(INSTALL) -m 644 $(SLIB_INSTALL_EXTRA_LIB:%=$(SUBDIR)%) "$(LIBDIR)") + +install-lib$(NAME)-static: $(SUBDIR)$(LIBNAME) + $(Q)mkdir -p "$(LIBDIR)" + $$(INSTALL) -m 644 $$< "$(LIBDIR)" + $(LIB_INSTALL_EXTRA_CMD) + +install-lib$(NAME)-headers: $(addprefix $(SUBDIR),$(HEADERS) $(BUILT_HEADERS)) + $(Q)mkdir -p "$(INCINSTDIR)" + $$(INSTALL) -m 644 $$^ "$(INCINSTDIR)" + +install-lib$(NAME)-pkgconfig: $(SUBDIR)lib$(FULLNAME).pc + $(Q)mkdir -p "$(PKGCONFIGDIR)" + $$(INSTALL) -m 644 $$^ "$(PKGCONFIGDIR)" + +uninstall-libs:: + -$(RM) "$(SHLIBDIR)/$(SLIBNAME_WITH_MAJOR)" \ + "$(SHLIBDIR)/$(SLIBNAME)" \ + "$(SHLIBDIR)/$(SLIBNAME_WITH_VERSION)" + -$(RM) $(SLIB_INSTALL_EXTRA_SHLIB:%="$(SHLIBDIR)/%") + -$(RM) $(SLIB_INSTALL_EXTRA_LIB:%="$(LIBDIR)/%") + -$(RM) "$(LIBDIR)/$(LIBNAME)" + +uninstall-headers:: + $(RM) $(addprefix "$(INCINSTDIR)/",$(HEADERS) $(BUILT_HEADERS)) + -rmdir "$(INCINSTDIR)" + +uninstall-pkgconfig:: + $(RM) "$(PKGCONFIGDIR)/lib$(FULLNAME).pc" +endef + +$(eval $(RULES)) + +$(TOOLS): $(DEP_LIBS) $(SUBDIR)$($(CONFIG_SHARED:yes=S)LIBNAME) +$(TESTPROGS): $(DEP_LIBS) $(SUBDIR)$(LIBNAME) + +testprogs: $(TESTPROGS) diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/libversion.sh b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/libversion.sh new file mode 100755 index 0000000000..990ce9f640 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/libversion.sh @@ -0,0 +1,13 @@ +toupper(){ + echo "$@" | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ +} + +name=lib$1 +ucname=$(toupper ${name}) +file=$2 + +eval $(awk "/#define ${ucname}_VERSION_M/ { print \$2 \"=\" \$3 }" "$file") +eval ${ucname}_VERSION=\$${ucname}_VERSION_MAJOR.\$${ucname}_VERSION_MINOR.\$${ucname}_VERSION_MICRO +eval echo "${name}_VERSION=\$${ucname}_VERSION" +eval echo "${name}_VERSION_MAJOR=\$${ucname}_VERSION_MAJOR" +eval echo "${name}_VERSION_MINOR=\$${ucname}_VERSION_MINOR" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/pkgconfig_generate.sh b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/pkgconfig_generate.sh new file mode 100755 index 0000000000..e5de6716d2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/pkgconfig_generate.sh @@ -0,0 +1,62 @@ +#!/bin/sh + +. ffbuild/config.sh + +if test "$shared" = "yes"; then + shared=true +else + shared=false +fi + +shortname=$1 +name=lib${shortname} +fullname=${name}${build_suffix} +comment=$2 +libs=$(eval echo \$extralibs_${shortname}) +deps=$(eval echo \$${shortname}_deps) + +for dep in $deps; do + depname=lib${dep} + fulldepname=${depname}${build_suffix} + . ${depname}/${depname}.version + depversion=$(eval echo \$${depname}_VERSION) + requires="$requires ${fulldepname} >= ${depversion}, " +done +requires=${requires%, } + +version=$(grep ${name}_VERSION= $name/${name}.version | cut -d= -f2) + +cat < $name/$fullname.pc +prefix=$prefix +exec_prefix=\${prefix} +libdir=$libdir +includedir=$incdir + +Name: $fullname +Description: $comment +Version: $version +Requires: $($shared || echo $requires) +Requires.private: $($shared && echo $requires) +Conflicts: +Libs: -L\${libdir} $rpath -l${fullname#lib} $($shared || echo $libs) +Libs.private: $($shared && echo $libs) +Cflags: -I\${includedir} +EOF + +mkdir -p doc/examples/pc-uninstalled +includedir=${source_path} +[ "$includedir" = . ] && includedir="\${pcfiledir}/../../.." + cat < doc/examples/pc-uninstalled/${name}-uninstalled.pc +prefix= +exec_prefix= +libdir=\${pcfiledir}/../../../$name +includedir=${source_path} + +Name: $fullname +Description: $comment +Version: $version +Requires: $requires +Conflicts: +Libs: -L\${libdir} -Wl,-rpath,\${libdir} -l${fullname#lib} $($shared || echo $libs) +Cflags: -I\${includedir} +EOF diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/version.sh b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/version.sh new file mode 100755 index 0000000000..edc4dd33c5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/ffbuild/version.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +# Usage: version.sh + +# check for git short hash +if ! test "$revision"; then + if (cd "$1" && grep git RELEASE 2> /dev/null >/dev/null) ; then + revision=$(cd "$1" && git describe --tags --match N 2> /dev/null) + else + revision=$(cd "$1" && git describe --tags --always 2> /dev/null) + fi +fi + +# Shallow Git clones (--depth) do not have the N tag: +# use 'git-YYYY-MM-DD-hhhhhhh'. +test "$revision" || revision=$(cd "$1" && + git log -1 --pretty=format:"git-%cd-%h" --date=short 2> /dev/null) + +# Snapshots from gitweb are in a directory called ffmpeg-hhhhhhh or +# ffmpeg-HEAD-hhhhhhh. +if [ -z "$revision" ]; then + srcdir=$(cd "$1" && pwd) + case "$srcdir" in + */ffmpeg-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]) + git_hash="${srcdir##*-}";; + */ffmpeg-HEAD-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]) + git_hash="${srcdir##*-}";; + esac +fi + +# no revision number found +test "$revision" || revision=$(cd "$1" && cat RELEASE 2> /dev/null) + +# Append the Git hash if we have one +test "$revision" && test "$git_hash" && revision="$revision-$git_hash" + +# releases extract the version number from the VERSION file +version=$(cd "$1" && cat VERSION 2> /dev/null) +test "$version" || version=$revision + +test -n "$3" && version=$version-$3 + +if [ -z "$2" ]; then + echo "$version" + exit +fi + +NEW_REVISION="#define FFMPEG_VERSION \"$version\"" +OLD_REVISION=$(cat "$2" 2> /dev/null | head -4 | tail -1) + +# String used for preprocessor guard +GUARD=$(echo "$2" | sed 's/\//_/' | sed 's/\./_/' | tr '[:lower:]' '[:upper:]' | sed 's/LIB//') + +# Update version header only on revision changes to avoid spurious rebuilds +if test "$NEW_REVISION" != "$OLD_REVISION"; then + cat << EOF > "$2" +/* Automatically generated by version.sh, do not manually edit! */ +#ifndef $GUARD +#define $GUARD +$NEW_REVISION +#endif /* $GUARD */ +EOF +fi diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/Makefile new file mode 100644 index 0000000000..3cd73fbcc6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/Makefile @@ -0,0 +1,1225 @@ +NAME = avcodec +DESC = FFmpeg codec library + +HEADERS = ac3_parser.h \ + adts_parser.h \ + avcodec.h \ + avdct.h \ + avfft.h \ + d3d11va.h \ + dirac.h \ + dv_profile.h \ + dxva2.h \ + jni.h \ + mediacodec.h \ + qsv.h \ + vaapi.h \ + vdpau.h \ + version.h \ + videotoolbox.h \ + vorbis_parser.h \ + xvmc.h \ + +OBJS = ac3_parser.o \ + adts_parser.o \ + allcodecs.o \ + avdct.o \ + avpacket.o \ + avpicture.o \ + bitstream.o \ + bitstream_filter.o \ + bitstream_filters.o \ + bsf.o \ + codec_desc.o \ + d3d11va.o \ + decode.o \ + dirac.o \ + dv_profile.o \ + encode.o \ + imgconvert.o \ + jni.o \ + mathtables.o \ + mediacodec.o \ + mpeg12framerate.o \ + options.o \ + mjpegenc_huffman.o \ + parser.o \ + parsers.o \ + profiles.o \ + qsv_api.o \ + raw.o \ + utils.o \ + vorbis_parser.o \ + xiph.o \ + +# subsystems +OBJS-$(CONFIG_AANDCTTABLES) += aandcttab.o +OBJS-$(CONFIG_AC3DSP) += ac3dsp.o ac3.o ac3tab.o +OBJS-$(CONFIG_ADTS_HEADER) += adts_header.o mpeg4audio.o +OBJS-$(CONFIG_AMF) += amfenc.o +OBJS-$(CONFIG_AUDIO_FRAME_QUEUE) += audio_frame_queue.o +OBJS-$(CONFIG_AUDIODSP) += audiodsp.o +OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o +OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o +OBJS-$(CONFIG_CABAC) += cabac.o +OBJS-$(CONFIG_CBS) += cbs.o +OBJS-$(CONFIG_CBS_AV1) += cbs_av1.o +OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o h2645_parse.o +OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o h2645_parse.o +OBJS-$(CONFIG_CBS_JPEG) += cbs_jpeg.o +OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o +OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o +OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o +OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o +OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o +OBJS-$(CONFIG_EXIF) += exif.o tiff_common.o +OBJS-$(CONFIG_FAANDCT) += faandct.o +OBJS-$(CONFIG_FAANIDCT) += faanidct.o +OBJS-$(CONFIG_FDCTDSP) += fdctdsp.o jfdctfst.o jfdctint.o +FFT-OBJS-$(CONFIG_HARDCODED_TABLES) += cos_tables.o cos_fixed_tables.o +OBJS-$(CONFIG_FFT) += avfft.o fft_fixed.o fft_float.o \ + fft_fixed_32.o fft_init_table.o \ + $(FFT-OBJS-yes) +OBJS-$(CONFIG_FLACDSP) += flacdsp.o +OBJS-$(CONFIG_FMTCONVERT) += fmtconvert.o +OBJS-$(CONFIG_GOLOMB) += golomb.o +OBJS-$(CONFIG_H263DSP) += h263dsp.o +OBJS-$(CONFIG_H264CHROMA) += h264chroma.o +OBJS-$(CONFIG_H264DSP) += h264dsp.o h264idct.o +OBJS-$(CONFIG_H264PARSE) += h264_parse.o h2645_parse.o h264_ps.o +OBJS-$(CONFIG_H264PRED) += h264pred.o +OBJS-$(CONFIG_H264QPEL) += h264qpel.o +OBJS-$(CONFIG_HEVCPARSE) += hevc_parse.o h2645_parse.o hevc_ps.o hevc_sei.o hevc_data.o +OBJS-$(CONFIG_HPELDSP) += hpeldsp.o +OBJS-$(CONFIG_HUFFMAN) += huffman.o +OBJS-$(CONFIG_HUFFYUVDSP) += huffyuvdsp.o +OBJS-$(CONFIG_HUFFYUVENCDSP) += huffyuvencdsp.o +OBJS-$(CONFIG_IDCTDSP) += idctdsp.o simple_idct.o jrevdct.o +OBJS-$(CONFIG_IIRFILTER) += iirfilter.o +OBJS-$(CONFIG_MDCT15) += mdct15.o +OBJS-$(CONFIG_INTRAX8) += intrax8.o intrax8dsp.o msmpeg4data.o +OBJS-$(CONFIG_IVIDSP) += ivi_dsp.o +OBJS-$(CONFIG_JNI) += ffjni.o jni.o +OBJS-$(CONFIG_JPEGTABLES) += jpegtables.o +OBJS-$(CONFIG_LLAUDDSP) += lossless_audiodsp.o +OBJS-$(CONFIG_LLVIDDSP) += lossless_videodsp.o +OBJS-$(CONFIG_LLVIDENCDSP) += lossless_videoencdsp.o +OBJS-$(CONFIG_LPC) += lpc.o +OBJS-$(CONFIG_LSP) += lsp.o +OBJS-$(CONFIG_LZF) += lzf.o +OBJS-$(CONFIG_MDCT) += mdct_fixed.o mdct_float.o mdct_fixed_32.o +OBJS-$(CONFIG_ME_CMP) += me_cmp.o +OBJS-$(CONFIG_MEDIACODEC) += mediacodecdec_common.o mediacodec_surface.o mediacodec_wrapper.o mediacodec_sw_buffer.o +OBJS-$(CONFIG_MPEG_ER) += mpeg_er.o +OBJS-$(CONFIG_MPEGAUDIO) += mpegaudio.o +OBJS-$(CONFIG_MPEGAUDIODSP) += mpegaudiodsp.o \ + mpegaudiodsp_data.o \ + mpegaudiodsp_fixed.o \ + mpegaudiodsp_float.o +OBJS-$(CONFIG_MPEGAUDIOHEADER) += mpegaudiodecheader.o mpegaudiodata.o +OBJS-$(CONFIG_MPEGVIDEO) += mpegvideo.o mpegvideodsp.o rl.o \ + mpegvideo_motion.o mpegutils.o \ + mpegvideodata.o mpegpicture.o +OBJS-$(CONFIG_MPEGVIDEOENC) += mpegvideo_enc.o mpeg12data.o \ + motion_est.o ratecontrol.o \ + mpegvideoencdsp.o +OBJS-$(CONFIG_MSS34DSP) += mss34dsp.o +OBJS-$(CONFIG_NVENC) += nvenc.o +OBJS-$(CONFIG_PIXBLOCKDSP) += pixblockdsp.o +OBJS-$(CONFIG_QPELDSP) += qpeldsp.o +OBJS-$(CONFIG_QSV) += qsv.o +OBJS-$(CONFIG_QSVDEC) += qsvdec.o +OBJS-$(CONFIG_QSVENC) += qsvenc.o +OBJS-$(CONFIG_RANGECODER) += rangecoder.o +OBJS-$(CONFIG_RDFT) += rdft.o +OBJS-$(CONFIG_RV34DSP) += rv34dsp.o +OBJS-$(CONFIG_SHARED) += log2_tab.o reverse.o +OBJS-$(CONFIG_SINEWIN) += sinewin.o sinewin_fixed.o +OBJS-$(CONFIG_SNAPPY) += snappy.o +OBJS-$(CONFIG_STARTCODE) += startcode.o +OBJS-$(CONFIG_TEXTUREDSP) += texturedsp.o +OBJS-$(CONFIG_TEXTUREDSPENC) += texturedspenc.o +OBJS-$(CONFIG_TPELDSP) += tpeldsp.o +OBJS-$(CONFIG_VAAPI_ENCODE) += vaapi_encode.o +OBJS-$(CONFIG_VC1DSP) += vc1dsp.o +OBJS-$(CONFIG_VIDEODSP) += videodsp.o +OBJS-$(CONFIG_VP3DSP) += vp3dsp.o +OBJS-$(CONFIG_VP56DSP) += vp56dsp.o +OBJS-$(CONFIG_VP8DSP) += vp8dsp.o +OBJS-$(CONFIG_V4L2_M2M) += v4l2_m2m.o v4l2_context.o v4l2_buffers.o v4l2_fmt.o +OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o +OBJS-$(CONFIG_WMV2DSP) += wmv2dsp.o + +# decoders/encoders +OBJS-$(CONFIG_ZERO12V_DECODER) += 012v.o +OBJS-$(CONFIG_A64MULTI_ENCODER) += a64multienc.o elbg.o +OBJS-$(CONFIG_A64MULTI5_ENCODER) += a64multienc.o elbg.o +OBJS-$(CONFIG_AAC_DECODER) += aacdec.o aactab.o aacsbr.o aacps_float.o \ + mpeg4audio.o kbdwin.o \ + sbrdsp.o aacpsdsp_float.o cbrt_data.o +OBJS-$(CONFIG_AAC_FIXED_DECODER) += aacdec_fixed.o aactab.o aacsbr_fixed.o aacps_fixed.o \ + mpeg4audio.o kbdwin.o \ + sbrdsp_fixed.o aacpsdsp_fixed.o cbrt_data_fixed.o +OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o aacenctab.o \ + aacpsy.o aactab.o \ + aacenc_is.o \ + aacenc_tns.o \ + aacenc_ltp.o \ + aacenc_pred.o \ + psymodel.o mpeg4audio.o kbdwin.o cbrt_data.o +OBJS-$(CONFIG_AASC_DECODER) += aasc.o msrledec.o +OBJS-$(CONFIG_AC3_DECODER) += ac3dec_float.o ac3dec_data.o ac3.o kbdwin.o ac3tab.o +OBJS-$(CONFIG_AC3_FIXED_DECODER) += ac3dec_fixed.o ac3dec_data.o ac3.o kbdwin.o ac3tab.o +OBJS-$(CONFIG_AC3_ENCODER) += ac3enc_float.o ac3enc.o ac3tab.o \ + ac3.o kbdwin.o +OBJS-$(CONFIG_AC3_FIXED_ENCODER) += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o +OBJS-$(CONFIG_AGM_DECODER) += agm.o +OBJS-$(CONFIG_AIC_DECODER) += aic.o +OBJS-$(CONFIG_ALAC_DECODER) += alac.o alac_data.o alacdsp.o +OBJS-$(CONFIG_ALAC_ENCODER) += alacenc.o alac_data.o +OBJS-$(CONFIG_ALIAS_PIX_DECODER) += aliaspixdec.o +OBJS-$(CONFIG_ALIAS_PIX_ENCODER) += aliaspixenc.o +OBJS-$(CONFIG_ALS_DECODER) += alsdec.o bgmc.o mlz.o mpeg4audio.o +OBJS-$(CONFIG_AMRNB_DECODER) += amrnbdec.o celp_filters.o \ + celp_math.o acelp_filters.o \ + acelp_vectors.o \ + acelp_pitch_delay.o +OBJS-$(CONFIG_AMRWB_DECODER) += amrwbdec.o celp_filters.o \ + celp_math.o acelp_filters.o \ + acelp_vectors.o \ + acelp_pitch_delay.o +OBJS-$(CONFIG_AMV_ENCODER) += mjpegenc.o mjpegenc_common.o \ + mjpegenc_huffman.o +OBJS-$(CONFIG_ANM_DECODER) += anm.o +OBJS-$(CONFIG_ANSI_DECODER) += ansi.o cga_data.o +OBJS-$(CONFIG_APE_DECODER) += apedec.o +OBJS-$(CONFIG_APTX_DECODER) += aptx.o +OBJS-$(CONFIG_APTX_ENCODER) += aptx.o +OBJS-$(CONFIG_APTX_HD_DECODER) += aptx.o +OBJS-$(CONFIG_APTX_HD_ENCODER) += aptx.o +OBJS-$(CONFIG_APNG_DECODER) += png.o pngdec.o pngdsp.o +OBJS-$(CONFIG_APNG_ENCODER) += png.o pngenc.o +OBJS-$(CONFIG_ARBC_DECODER) += arbc.o +OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o +OBJS-$(CONFIG_SSA_ENCODER) += assenc.o ass.o +OBJS-$(CONFIG_ASS_DECODER) += assdec.o ass.o +OBJS-$(CONFIG_ASS_ENCODER) += assenc.o ass.o +OBJS-$(CONFIG_ASV1_DECODER) += asvdec.o asv.o mpeg12data.o +OBJS-$(CONFIG_ASV1_ENCODER) += asvenc.o asv.o mpeg12data.o +OBJS-$(CONFIG_ASV2_DECODER) += asvdec.o asv.o mpeg12data.o +OBJS-$(CONFIG_ASV2_ENCODER) += asvenc.o asv.o mpeg12data.o +OBJS-$(CONFIG_ATRAC1_DECODER) += atrac1.o atrac.o +OBJS-$(CONFIG_ATRAC3_DECODER) += atrac3.o atrac.o +OBJS-$(CONFIG_ATRAC3AL_DECODER) += atrac3.o atrac.o +OBJS-$(CONFIG_ATRAC3P_DECODER) += atrac3plusdec.o atrac3plus.o \ + atrac3plusdsp.o atrac.o +OBJS-$(CONFIG_ATRAC3PAL_DECODER) += atrac3plusdec.o atrac3plus.o \ + atrac3plusdsp.o atrac.o +OBJS-$(CONFIG_ATRAC9_DECODER) += atrac9dec.o +OBJS-$(CONFIG_AURA_DECODER) += cyuv.o +OBJS-$(CONFIG_AURA2_DECODER) += aura.o +OBJS-$(CONFIG_AVRN_DECODER) += avrndec.o mjpegdec.o +OBJS-$(CONFIG_AVRP_DECODER) += r210dec.o +OBJS-$(CONFIG_AVRP_ENCODER) += r210enc.o +OBJS-$(CONFIG_AVS_DECODER) += avs.o +OBJS-$(CONFIG_AVUI_DECODER) += avuidec.o +OBJS-$(CONFIG_AVUI_ENCODER) += avuienc.o +OBJS-$(CONFIG_AYUV_DECODER) += v408dec.o +OBJS-$(CONFIG_AYUV_ENCODER) += v408enc.o +OBJS-$(CONFIG_BETHSOFTVID_DECODER) += bethsoftvideo.o +OBJS-$(CONFIG_BFI_DECODER) += bfi.o +OBJS-$(CONFIG_BINK_DECODER) += bink.o binkdsp.o +OBJS-$(CONFIG_BINKAUDIO_DCT_DECODER) += binkaudio.o +OBJS-$(CONFIG_BINKAUDIO_RDFT_DECODER) += binkaudio.o +OBJS-$(CONFIG_BINTEXT_DECODER) += bintext.o cga_data.o +OBJS-$(CONFIG_BITPACKED_DECODER) += bitpacked.o +OBJS-$(CONFIG_BMP_DECODER) += bmp.o msrledec.o +OBJS-$(CONFIG_BMP_ENCODER) += bmpenc.o +OBJS-$(CONFIG_BMV_AUDIO_DECODER) += bmvaudio.o +OBJS-$(CONFIG_BMV_VIDEO_DECODER) += bmvvideo.o +OBJS-$(CONFIG_BRENDER_PIX_DECODER) += brenderpix.o +OBJS-$(CONFIG_C93_DECODER) += c93.o +OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.o \ + cavsdata.o +OBJS-$(CONFIG_CCAPTION_DECODER) += ccaption_dec.o +OBJS-$(CONFIG_CDGRAPHICS_DECODER) += cdgraphics.o +OBJS-$(CONFIG_CDXL_DECODER) += cdxl.o +OBJS-$(CONFIG_CFHD_DECODER) += cfhd.o cfhddata.o +OBJS-$(CONFIG_CINEPAK_DECODER) += cinepak.o +OBJS-$(CONFIG_CINEPAK_ENCODER) += cinepakenc.o elbg.o +OBJS-$(CONFIG_CLEARVIDEO_DECODER) += clearvideo.o +OBJS-$(CONFIG_CLJR_DECODER) += cljrdec.o +OBJS-$(CONFIG_CLJR_ENCODER) += cljrenc.o +OBJS-$(CONFIG_CLLC_DECODER) += cllc.o canopus.o +OBJS-$(CONFIG_COMFORTNOISE_DECODER) += cngdec.o celp_filters.o +OBJS-$(CONFIG_COMFORTNOISE_ENCODER) += cngenc.o +OBJS-$(CONFIG_COOK_DECODER) += cook.o +OBJS-$(CONFIG_CPIA_DECODER) += cpia.o +OBJS-$(CONFIG_CSCD_DECODER) += cscd.o +OBJS-$(CONFIG_CYUV_DECODER) += cyuv.o +OBJS-$(CONFIG_DCA_DECODER) += dcadec.o dca.o dcadata.o dcahuff.o \ + dca_core.o dca_exss.o dca_xll.o dca_lbr.o \ + dcadsp.o dcadct.o synth_filter.o +OBJS-$(CONFIG_DCA_ENCODER) += dcaenc.o dca.o dcadata.o dcahuff.o \ + dcaadpcm.o +OBJS-$(CONFIG_DDS_DECODER) += dds.o +OBJS-$(CONFIG_DIRAC_DECODER) += diracdec.o dirac.o diracdsp.o diractab.o \ + dirac_arith.o dirac_dwt.o dirac_vlc.o +OBJS-$(CONFIG_DFA_DECODER) += dfa.o +OBJS-$(CONFIG_DNXHD_DECODER) += dnxhddec.o dnxhddata.o +OBJS-$(CONFIG_DNXHD_ENCODER) += dnxhdenc.o dnxhddata.o +OBJS-$(CONFIG_DOLBY_E_DECODER) += dolby_e.o kbdwin.o +OBJS-$(CONFIG_DPX_DECODER) += dpx.o +OBJS-$(CONFIG_DPX_ENCODER) += dpxenc.o +OBJS-$(CONFIG_DSD_LSBF_DECODER) += dsddec.o dsd.o +OBJS-$(CONFIG_DSD_MSBF_DECODER) += dsddec.o dsd.o +OBJS-$(CONFIG_DSD_LSBF_PLANAR_DECODER) += dsddec.o dsd.o +OBJS-$(CONFIG_DSD_MSBF_PLANAR_DECODER) += dsddec.o dsd.o +OBJS-$(CONFIG_DSICINAUDIO_DECODER) += dsicinaudio.o +OBJS-$(CONFIG_DSICINVIDEO_DECODER) += dsicinvideo.o +OBJS-$(CONFIG_DSS_SP_DECODER) += dss_sp.o +OBJS-$(CONFIG_DST_DECODER) += dstdec.o dsd.o +OBJS-$(CONFIG_DVBSUB_DECODER) += dvbsubdec.o +OBJS-$(CONFIG_DVBSUB_ENCODER) += dvbsub.o +OBJS-$(CONFIG_DVDSUB_DECODER) += dvdsubdec.o +OBJS-$(CONFIG_DVDSUB_ENCODER) += dvdsubenc.o +OBJS-$(CONFIG_DVAUDIO_DECODER) += dvaudiodec.o +OBJS-$(CONFIG_DVVIDEO_DECODER) += dvdec.o dv.o dvdata.o +OBJS-$(CONFIG_DVVIDEO_ENCODER) += dvenc.o dv.o dvdata.o +OBJS-$(CONFIG_DXA_DECODER) += dxa.o +OBJS-$(CONFIG_DXTORY_DECODER) += dxtory.o +OBJS-$(CONFIG_DXV_DECODER) += dxv.o +OBJS-$(CONFIG_EAC3_DECODER) += eac3_data.o +OBJS-$(CONFIG_EAC3_ENCODER) += eac3enc.o eac3_data.o +OBJS-$(CONFIG_EACMV_DECODER) += eacmv.o +OBJS-$(CONFIG_EAMAD_DECODER) += eamad.o eaidct.o mpeg12.o \ + mpeg12data.o +OBJS-$(CONFIG_EATGQ_DECODER) += eatgq.o eaidct.o +OBJS-$(CONFIG_EATGV_DECODER) += eatgv.o +OBJS-$(CONFIG_EATQI_DECODER) += eatqi.o eaidct.o mpeg12.o mpeg12data.o mpegvideodata.o rl.o +OBJS-$(CONFIG_EIGHTBPS_DECODER) += 8bps.o +OBJS-$(CONFIG_EIGHTSVX_EXP_DECODER) += 8svx.o +OBJS-$(CONFIG_EIGHTSVX_FIB_DECODER) += 8svx.o +OBJS-$(CONFIG_ESCAPE124_DECODER) += escape124.o +OBJS-$(CONFIG_ESCAPE130_DECODER) += escape130.o +OBJS-$(CONFIG_EVRC_DECODER) += evrcdec.o acelp_vectors.o lsp.o +OBJS-$(CONFIG_EXR_DECODER) += exr.o exrdsp.o +OBJS-$(CONFIG_FFV1_DECODER) += ffv1dec.o ffv1.o +OBJS-$(CONFIG_FFV1_ENCODER) += ffv1enc.o ffv1.o +OBJS-$(CONFIG_FFWAVESYNTH_DECODER) += ffwavesynth.o +OBJS-$(CONFIG_FIC_DECODER) += fic.o +OBJS-$(CONFIG_FITS_DECODER) += fitsdec.o fits.o +OBJS-$(CONFIG_FITS_ENCODER) += fitsenc.o +OBJS-$(CONFIG_FLAC_DECODER) += flacdec.o flacdata.o flac.o +OBJS-$(CONFIG_FLAC_ENCODER) += flacenc.o flacdata.o flac.o vorbis_data.o +OBJS-$(CONFIG_FLASHSV_DECODER) += flashsv.o +OBJS-$(CONFIG_FLASHSV_ENCODER) += flashsvenc.o +OBJS-$(CONFIG_FLASHSV2_ENCODER) += flashsv2enc.o +OBJS-$(CONFIG_FLASHSV2_DECODER) += flashsv.o +OBJS-$(CONFIG_FLIC_DECODER) += flicvideo.o +OBJS-$(CONFIG_FMVC_DECODER) += fmvc.o +OBJS-$(CONFIG_FOURXM_DECODER) += 4xm.o +OBJS-$(CONFIG_FRAPS_DECODER) += fraps.o +OBJS-$(CONFIG_FRWU_DECODER) += frwu.o +OBJS-$(CONFIG_G2M_DECODER) += g2meet.o elsdec.o +OBJS-$(CONFIG_G723_1_DECODER) += g723_1dec.o g723_1.o \ + acelp_vectors.o celp_filters.o celp_math.o +OBJS-$(CONFIG_G723_1_ENCODER) += g723_1enc.o g723_1.o \ + acelp_vectors.o celp_filters.o celp_math.o +OBJS-$(CONFIG_G729_DECODER) += g729dec.o lsp.o celp_math.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o +OBJS-$(CONFIG_GDV_DECODER) += gdv.o +OBJS-$(CONFIG_GIF_DECODER) += gifdec.o lzw.o +OBJS-$(CONFIG_GIF_ENCODER) += gif.o lzwenc.o +OBJS-$(CONFIG_GREMLIN_DPCM_DECODER) += dpcm.o +OBJS-$(CONFIG_GSM_DECODER) += gsmdec.o gsmdec_data.o msgsmdec.o +OBJS-$(CONFIG_GSM_MS_DECODER) += gsmdec.o gsmdec_data.o msgsmdec.o +OBJS-$(CONFIG_H261_DECODER) += h261dec.o h261data.o h261.o +OBJS-$(CONFIG_H261_ENCODER) += h261enc.o h261data.o h261.o +OBJS-$(CONFIG_H263_DECODER) += h263dec.o h263.o ituh263dec.o \ + mpeg4video.o mpeg4videodec.o flvdec.o\ + intelh263dec.o h263data.o +OBJS-$(CONFIG_H263_ENCODER) += mpeg4videoenc.o mpeg4video.o \ + h263.o ituh263enc.o flvenc.o h263data.o +OBJS-$(CONFIG_H263_V4L2M2M_DECODER) += v4l2_m2m_dec.o +OBJS-$(CONFIG_H263_V4L2M2M_ENCODER) += v4l2_m2m_enc.o +OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \ + h264_direct.o h264_loopfilter.o \ + h264_mb.o h264_picture.o \ + h264_refs.o h264_sei.o \ + h264_slice.o h264data.o +OBJS-$(CONFIG_H264_AMF_ENCODER) += amfenc_h264.o +OBJS-$(CONFIG_H264_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o +OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o +OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o +OBJS-$(CONFIG_NVENC_ENCODER) += nvenc_h264.o +OBJS-$(CONFIG_NVENC_H264_ENCODER) += nvenc_h264.o +OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o +OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h2645.o +OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o +OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmppdec.o +OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.o h264_levels.o +OBJS-$(CONFIG_H264_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o +OBJS-$(CONFIG_H264_V4L2M2M_DECODER) += v4l2_m2m_dec.o +OBJS-$(CONFIG_H264_V4L2M2M_ENCODER) += v4l2_m2m_enc.o +OBJS-$(CONFIG_HAP_DECODER) += hapdec.o hap.o +OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o hap.o +OBJS-$(CONFIG_HCOM_DECODER) += hcom.o +OBJS-$(CONFIG_HEVC_DECODER) += hevcdec.o hevc_mvs.o \ + hevc_cabac.o hevc_refs.o hevcpred.o \ + hevcdsp.o hevc_filter.o hevc_data.o +OBJS-$(CONFIG_HEVC_AMF_ENCODER) += amfenc_hevc.o +OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o +OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o +OBJS-$(CONFIG_NVENC_HEVC_ENCODER) += nvenc_hevc.o +OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec_h2645.o +OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o \ + hevc_data.o +OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o +OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o h265_profile_level.o +OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER) += v4l2_m2m_dec.o +OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER) += v4l2_m2m_enc.o +OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o +OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadata.o hq_hqadsp.o \ + canopus.o +OBJS-$(CONFIG_HQX_DECODER) += hqx.o hqxvlc.o hqxdsp.o canopus.o +OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o +OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o +OBJS-$(CONFIG_HYMT_DECODER) += huffyuv.o huffyuvdec.o +OBJS-$(CONFIG_IDCIN_DECODER) += idcinvideo.o +OBJS-$(CONFIG_IDF_DECODER) += bintext.o cga_data.o +OBJS-$(CONFIG_IFF_ILBM_DECODER) += iff.o +OBJS-$(CONFIG_ILBC_DECODER) += ilbcdec.o +OBJS-$(CONFIG_IMC_DECODER) += imc.o +OBJS-$(CONFIG_IMM4_DECODER) += imm4.o +OBJS-$(CONFIG_INDEO2_DECODER) += indeo2.o +OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o +OBJS-$(CONFIG_INDEO4_DECODER) += indeo4.o ivi.o +OBJS-$(CONFIG_INDEO5_DECODER) += indeo5.o ivi.o +OBJS-$(CONFIG_INTERPLAY_ACM_DECODER) += interplayacm.o +OBJS-$(CONFIG_INTERPLAY_DPCM_DECODER) += dpcm.o +OBJS-$(CONFIG_INTERPLAY_VIDEO_DECODER) += interplayvideo.o +OBJS-$(CONFIG_JACOSUB_DECODER) += jacosubdec.o ass.o +OBJS-$(CONFIG_JPEG2000_ENCODER) += j2kenc.o mqcenc.o mqc.o jpeg2000.o \ + jpeg2000dwt.o +OBJS-$(CONFIG_JPEG2000_DECODER) += jpeg2000dec.o jpeg2000.o jpeg2000dsp.o \ + jpeg2000dwt.o mqcdec.o mqc.o +OBJS-$(CONFIG_JPEGLS_DECODER) += jpeglsdec.o jpegls.o +OBJS-$(CONFIG_JPEGLS_ENCODER) += jpeglsenc.o jpegls.o +OBJS-$(CONFIG_JV_DECODER) += jvdec.o +OBJS-$(CONFIG_KGV1_DECODER) += kgv1dec.o +OBJS-$(CONFIG_KMVC_DECODER) += kmvc.o +OBJS-$(CONFIG_LAGARITH_DECODER) += lagarith.o lagarithrac.o +OBJS-$(CONFIG_LJPEG_ENCODER) += ljpegenc.o mjpegenc_common.o +OBJS-$(CONFIG_LOCO_DECODER) += loco.o +OBJS-$(CONFIG_LSCR_DECODER) += png.o pngdec.o pngdsp.o +OBJS-$(CONFIG_M101_DECODER) += m101.o +OBJS-$(CONFIG_MACE3_DECODER) += mace.o +OBJS-$(CONFIG_MACE6_DECODER) += mace.o +OBJS-$(CONFIG_MAGICYUV_DECODER) += magicyuv.o +OBJS-$(CONFIG_MAGICYUV_ENCODER) += magicyuvenc.o +OBJS-$(CONFIG_MDEC_DECODER) += mdec.o mpeg12.o mpeg12data.o +OBJS-$(CONFIG_METASOUND_DECODER) += metasound.o metasound_data.o \ + twinvq.o +OBJS-$(CONFIG_MICRODVD_DECODER) += microdvddec.o ass.o +OBJS-$(CONFIG_MIMIC_DECODER) += mimic.o +OBJS-$(CONFIG_MJPEG_DECODER) += mjpegdec.o +OBJS-$(CONFIG_MJPEG_ENCODER) += mjpegenc.o mjpegenc_common.o \ + mjpegenc_huffman.o +OBJS-$(CONFIG_MJPEGB_DECODER) += mjpegbdec.o +OBJS-$(CONFIG_MJPEG_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_MJPEG_QSV_ENCODER) += qsvenc_jpeg.o +OBJS-$(CONFIG_MJPEG_VAAPI_ENCODER) += vaapi_encode_mjpeg.o +OBJS-$(CONFIG_MLP_DECODER) += mlpdec.o mlpdsp.o +OBJS-$(CONFIG_MLP_ENCODER) += mlpenc.o mlp.o +OBJS-$(CONFIG_MMVIDEO_DECODER) += mmvideo.o +OBJS-$(CONFIG_MOTIONPIXELS_DECODER) += motionpixels.o +OBJS-$(CONFIG_MOVTEXT_DECODER) += movtextdec.o ass.o +OBJS-$(CONFIG_MOVTEXT_ENCODER) += movtextenc.o ass_split.o +OBJS-$(CONFIG_MP1_DECODER) += mpegaudiodec_fixed.o +OBJS-$(CONFIG_MP1FLOAT_DECODER) += mpegaudiodec_float.o +OBJS-$(CONFIG_MP2_DECODER) += mpegaudiodec_fixed.o +OBJS-$(CONFIG_MP2_ENCODER) += mpegaudioenc_float.o mpegaudio.o \ + mpegaudiodata.o mpegaudiodsp_data.o +OBJS-$(CONFIG_MP2FIXED_ENCODER) += mpegaudioenc_fixed.o mpegaudio.o \ + mpegaudiodata.o mpegaudiodsp_data.o +OBJS-$(CONFIG_MP2FLOAT_DECODER) += mpegaudiodec_float.o +OBJS-$(CONFIG_MP3_DECODER) += mpegaudiodec_fixed.o +OBJS-$(CONFIG_MP3ADU_DECODER) += mpegaudiodec_fixed.o +OBJS-$(CONFIG_MP3ADUFLOAT_DECODER) += mpegaudiodec_float.o +OBJS-$(CONFIG_MP3FLOAT_DECODER) += mpegaudiodec_float.o +OBJS-$(CONFIG_MP3ON4_DECODER) += mpegaudiodec_fixed.o mpeg4audio.o +OBJS-$(CONFIG_MP3ON4FLOAT_DECODER) += mpegaudiodec_float.o mpeg4audio.o +OBJS-$(CONFIG_MPC7_DECODER) += mpc7.o mpc.o +OBJS-$(CONFIG_MPC8_DECODER) += mpc8.o mpc.o +OBJS-$(CONFIG_MPEGVIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o +OBJS-$(CONFIG_MPEG1VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o +OBJS-$(CONFIG_MPEG1VIDEO_ENCODER) += mpeg12enc.o mpeg12.o +OBJS-$(CONFIG_MPEG1_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_MPEG1_V4L2M2M_DECODER) += v4l2_m2m_dec.o +OBJS-$(CONFIG_MPEG2_MMAL_DECODER) += mmaldec.o +OBJS-$(CONFIG_MPEG2_QSV_DECODER) += qsvdec_other.o +OBJS-$(CONFIG_MPEG2_QSV_ENCODER) += qsvenc_mpeg2.o +OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o +OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpeg12.o +OBJS-$(CONFIG_MPEG2_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o +OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER) += vaapi_encode_mpeg2.o +OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER) += v4l2_m2m_dec.o +OBJS-$(CONFIG_MPEG4_DECODER) += xvididct.o +OBJS-$(CONFIG_MPEG4_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o +OBJS-$(CONFIG_MPEG4_OMX_ENCODER) += omx.o +OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER) += v4l2_m2m_dec.o +OBJS-$(CONFIG_MPEG4_V4L2M2M_ENCODER) += v4l2_m2m_enc.o +OBJS-$(CONFIG_MPL2_DECODER) += mpl2dec.o ass.o +OBJS-$(CONFIG_MSA1_DECODER) += mss3.o +OBJS-$(CONFIG_MSCC_DECODER) += mscc.o +OBJS-$(CONFIG_MSMPEG4V1_DECODER) += msmpeg4dec.o msmpeg4.o msmpeg4data.o +OBJS-$(CONFIG_MSMPEG4V2_DECODER) += msmpeg4dec.o msmpeg4.o msmpeg4data.o +OBJS-$(CONFIG_MSMPEG4V2_ENCODER) += msmpeg4enc.o msmpeg4.o msmpeg4data.o +OBJS-$(CONFIG_MSMPEG4V3_DECODER) += msmpeg4dec.o msmpeg4.o msmpeg4data.o +OBJS-$(CONFIG_MSMPEG4V3_ENCODER) += msmpeg4enc.o msmpeg4.o msmpeg4data.o +OBJS-$(CONFIG_MSRLE_DECODER) += msrle.o msrledec.o +OBJS-$(CONFIG_MSS1_DECODER) += mss1.o mss12.o +OBJS-$(CONFIG_MSS2_DECODER) += mss2.o mss12.o mss2dsp.o wmv2data.o +OBJS-$(CONFIG_MSVIDEO1_DECODER) += msvideo1.o +OBJS-$(CONFIG_MSVIDEO1_ENCODER) += msvideo1enc.o elbg.o +OBJS-$(CONFIG_MSZH_DECODER) += lcldec.o +OBJS-$(CONFIG_MTS2_DECODER) += mss4.o +OBJS-$(CONFIG_MVC1_DECODER) += mvcdec.o +OBJS-$(CONFIG_MVC2_DECODER) += mvcdec.o +OBJS-$(CONFIG_MWSC_DECODER) += mwsc.o +OBJS-$(CONFIG_MXPEG_DECODER) += mxpegdec.o +OBJS-$(CONFIG_NELLYMOSER_DECODER) += nellymoserdec.o nellymoser.o +OBJS-$(CONFIG_NELLYMOSER_ENCODER) += nellymoserenc.o nellymoser.o +OBJS-$(CONFIG_NUV_DECODER) += nuv.o rtjpeg.o +OBJS-$(CONFIG_ON2AVC_DECODER) += on2avc.o on2avcdata.o +OBJS-$(CONFIG_OPUS_DECODER) += opusdec.o opus.o opus_celt.o opus_rc.o \ + opus_pvq.o opus_silk.o opustab.o vorbis_data.o \ + opusdsp.o +OBJS-$(CONFIG_OPUS_ENCODER) += opusenc.o opus.o opus_rc.o opustab.o opus_pvq.o \ + opusenc_psy.o +OBJS-$(CONFIG_PAF_AUDIO_DECODER) += pafaudio.o +OBJS-$(CONFIG_PAF_VIDEO_DECODER) += pafvideo.o +OBJS-$(CONFIG_PAM_DECODER) += pnmdec.o pnm.o +OBJS-$(CONFIG_PAM_ENCODER) += pamenc.o +OBJS-$(CONFIG_PBM_DECODER) += pnmdec.o pnm.o +OBJS-$(CONFIG_PBM_ENCODER) += pnmenc.o +OBJS-$(CONFIG_PCX_DECODER) += pcx.o +OBJS-$(CONFIG_PCX_ENCODER) += pcxenc.o +OBJS-$(CONFIG_PGM_DECODER) += pnmdec.o pnm.o +OBJS-$(CONFIG_PGM_ENCODER) += pnmenc.o +OBJS-$(CONFIG_PGMYUV_DECODER) += pnmdec.o pnm.o +OBJS-$(CONFIG_PGMYUV_ENCODER) += pnmenc.o +OBJS-$(CONFIG_PGSSUB_DECODER) += pgssubdec.o +OBJS-$(CONFIG_PICTOR_DECODER) += pictordec.o cga_data.o +OBJS-$(CONFIG_PIXLET_DECODER) += pixlet.o +OBJS-$(CONFIG_PJS_DECODER) += textdec.o ass.o +OBJS-$(CONFIG_PNG_DECODER) += png.o pngdec.o pngdsp.o +OBJS-$(CONFIG_PNG_ENCODER) += png.o pngenc.o +OBJS-$(CONFIG_PPM_DECODER) += pnmdec.o pnm.o +OBJS-$(CONFIG_PPM_ENCODER) += pnmenc.o +OBJS-$(CONFIG_PRORES_DECODER) += proresdec2.o proresdsp.o proresdata.o +OBJS-$(CONFIG_PRORES_ENCODER) += proresenc_anatoliy.o proresdata.o +OBJS-$(CONFIG_PRORES_AW_ENCODER) += proresenc_anatoliy.o proresdata.o +OBJS-$(CONFIG_PRORES_KS_ENCODER) += proresenc_kostya.o proresdata.o +OBJS-$(CONFIG_PROSUMER_DECODER) += prosumer.o +OBJS-$(CONFIG_PSD_DECODER) += psd.o +OBJS-$(CONFIG_PTX_DECODER) += ptx.o +OBJS-$(CONFIG_QCELP_DECODER) += qcelpdec.o \ + celp_filters.o acelp_vectors.o \ + acelp_filters.o +OBJS-$(CONFIG_QDM2_DECODER) += qdm2.o +OBJS-$(CONFIG_QDMC_DECODER) += qdmc.o +OBJS-$(CONFIG_QDRAW_DECODER) += qdrw.o +OBJS-$(CONFIG_QPEG_DECODER) += qpeg.o +OBJS-$(CONFIG_QTRLE_DECODER) += qtrle.o +OBJS-$(CONFIG_QTRLE_ENCODER) += qtrleenc.o +OBJS-$(CONFIG_R10K_DECODER) += r210dec.o +OBJS-$(CONFIG_R10K_ENCODER) += r210enc.o +OBJS-$(CONFIG_R210_DECODER) += r210dec.o +OBJS-$(CONFIG_R210_ENCODER) += r210enc.o +OBJS-$(CONFIG_RA_144_DECODER) += ra144dec.o ra144.o celp_filters.o +OBJS-$(CONFIG_RA_144_ENCODER) += ra144enc.o ra144.o celp_filters.o +OBJS-$(CONFIG_RA_288_DECODER) += ra288.o celp_filters.o +OBJS-$(CONFIG_RALF_DECODER) += ralf.o +OBJS-$(CONFIG_RASC_DECODER) += rasc.o +OBJS-$(CONFIG_RAWVIDEO_DECODER) += rawdec.o +OBJS-$(CONFIG_RAWVIDEO_ENCODER) += rawenc.o +OBJS-$(CONFIG_REALTEXT_DECODER) += realtextdec.o ass.o +OBJS-$(CONFIG_RL2_DECODER) += rl2.o +OBJS-$(CONFIG_ROQ_DECODER) += roqvideodec.o roqvideo.o +OBJS-$(CONFIG_ROQ_ENCODER) += roqvideoenc.o roqvideo.o elbg.o +OBJS-$(CONFIG_ROQ_DPCM_DECODER) += dpcm.o +OBJS-$(CONFIG_ROQ_DPCM_ENCODER) += roqaudioenc.o +OBJS-$(CONFIG_RPZA_DECODER) += rpza.o +OBJS-$(CONFIG_RSCC_DECODER) += rscc.o +OBJS-$(CONFIG_RV10_DECODER) += rv10.o +OBJS-$(CONFIG_RV10_ENCODER) += rv10enc.o +OBJS-$(CONFIG_RV20_DECODER) += rv10.o +OBJS-$(CONFIG_RV20_ENCODER) += rv20enc.o +OBJS-$(CONFIG_RV30_DECODER) += rv30.o rv34.o rv30dsp.o +OBJS-$(CONFIG_RV40_DECODER) += rv40.o rv34.o rv40dsp.o +OBJS-$(CONFIG_SAMI_DECODER) += samidec.o ass.o htmlsubtitles.o +OBJS-$(CONFIG_S302M_DECODER) += s302m.o +OBJS-$(CONFIG_S302M_ENCODER) += s302menc.o +OBJS-$(CONFIG_SANM_DECODER) += sanm.o +OBJS-$(CONFIG_SCPR_DECODER) += scpr.o +OBJS-$(CONFIG_SCREENPRESSO_DECODER) += screenpresso.o +OBJS-$(CONFIG_SDX2_DPCM_DECODER) += dpcm.o +OBJS-$(CONFIG_SGI_DECODER) += sgidec.o +OBJS-$(CONFIG_SGI_ENCODER) += sgienc.o rle.o +OBJS-$(CONFIG_SGIRLE_DECODER) += sgirledec.o +OBJS-$(CONFIG_SHEERVIDEO_DECODER) += sheervideo.o +OBJS-$(CONFIG_SHORTEN_DECODER) += shorten.o +OBJS-$(CONFIG_SIPR_DECODER) += sipr.o acelp_pitch_delay.o \ + celp_math.o acelp_vectors.o \ + acelp_filters.o celp_filters.o \ + sipr16k.o +OBJS-$(CONFIG_SMACKAUD_DECODER) += smacker.o +OBJS-$(CONFIG_SMACKER_DECODER) += smacker.o +OBJS-$(CONFIG_SMC_DECODER) += smc.o +OBJS-$(CONFIG_SMVJPEG_DECODER) += smvjpegdec.o +OBJS-$(CONFIG_SNOW_DECODER) += snowdec.o snow.o snow_dwt.o +OBJS-$(CONFIG_SNOW_ENCODER) += snowenc.o snow.o snow_dwt.o \ + h263.o ituh263enc.o +OBJS-$(CONFIG_SOL_DPCM_DECODER) += dpcm.o +OBJS-$(CONFIG_SONIC_DECODER) += sonic.o +OBJS-$(CONFIG_SONIC_ENCODER) += sonic.o +OBJS-$(CONFIG_SONIC_LS_ENCODER) += sonic.o +OBJS-$(CONFIG_SPEEDHQ_DECODER) += speedhq.o mpeg12.o mpeg12data.o simple_idct.o +OBJS-$(CONFIG_SP5X_DECODER) += sp5xdec.o +OBJS-$(CONFIG_SRGC_DECODER) += mscc.o +OBJS-$(CONFIG_SRT_DECODER) += srtdec.o ass.o htmlsubtitles.o +OBJS-$(CONFIG_SRT_ENCODER) += srtenc.o ass_split.o +OBJS-$(CONFIG_STL_DECODER) += textdec.o ass.o +OBJS-$(CONFIG_SUBRIP_DECODER) += srtdec.o ass.o htmlsubtitles.o +OBJS-$(CONFIG_SUBRIP_ENCODER) += srtenc.o ass_split.o +OBJS-$(CONFIG_SUBVIEWER1_DECODER) += textdec.o ass.o +OBJS-$(CONFIG_SUBVIEWER_DECODER) += subviewerdec.o ass.o +OBJS-$(CONFIG_SUNRAST_DECODER) += sunrast.o +OBJS-$(CONFIG_SUNRAST_ENCODER) += sunrastenc.o +OBJS-$(CONFIG_LIBRSVG_DECODER) += librsvgdec.o +OBJS-$(CONFIG_SBC_DECODER) += sbcdec.o sbcdec_data.o sbc.o +OBJS-$(CONFIG_SBC_ENCODER) += sbcenc.o sbc.o sbcdsp.o sbcdsp_data.o +OBJS-$(CONFIG_SVQ1_DECODER) += svq1dec.o svq1.o svq13.o h263data.o +OBJS-$(CONFIG_SVQ1_ENCODER) += svq1enc.o svq1.o h263data.o \ + h263.o ituh263enc.o +OBJS-$(CONFIG_SVQ3_DECODER) += svq3.o svq13.o mpegutils.o h264data.o +OBJS-$(CONFIG_TEXT_DECODER) += textdec.o ass.o +OBJS-$(CONFIG_TEXT_ENCODER) += srtenc.o ass_split.o +OBJS-$(CONFIG_TAK_DECODER) += takdec.o tak.o takdsp.o +OBJS-$(CONFIG_TARGA_DECODER) += targa.o +OBJS-$(CONFIG_TARGA_ENCODER) += targaenc.o rle.o +OBJS-$(CONFIG_TARGA_Y216_DECODER) += targa_y216dec.o +OBJS-$(CONFIG_TDSC_DECODER) += tdsc.o +OBJS-$(CONFIG_TIERTEXSEQVIDEO_DECODER) += tiertexseqv.o +OBJS-$(CONFIG_TIFF_DECODER) += tiff.o lzw.o faxcompr.o tiff_data.o tiff_common.o +OBJS-$(CONFIG_TIFF_ENCODER) += tiffenc.o rle.o lzwenc.o tiff_data.o +OBJS-$(CONFIG_TMV_DECODER) += tmv.o cga_data.o +OBJS-$(CONFIG_TRUEHD_DECODER) += mlpdec.o mlpdsp.o +OBJS-$(CONFIG_TRUEHD_ENCODER) += mlpenc.o mlp.o +OBJS-$(CONFIG_TRUEMOTION1_DECODER) += truemotion1.o +OBJS-$(CONFIG_TRUEMOTION2_DECODER) += truemotion2.o +OBJS-$(CONFIG_TRUEMOTION2RT_DECODER) += truemotion2rt.o +OBJS-$(CONFIG_TRUESPEECH_DECODER) += truespeech.o +OBJS-$(CONFIG_TSCC_DECODER) += tscc.o msrledec.o +OBJS-$(CONFIG_TSCC2_DECODER) += tscc2.o +OBJS-$(CONFIG_TTA_DECODER) += tta.o ttadata.o ttadsp.o +OBJS-$(CONFIG_TTA_ENCODER) += ttaenc.o ttaencdsp.o ttadata.o +OBJS-$(CONFIG_TWINVQ_DECODER) += twinvqdec.o twinvq.o +OBJS-$(CONFIG_TXD_DECODER) += txd.o +OBJS-$(CONFIG_ULTI_DECODER) += ulti.o +OBJS-$(CONFIG_UTVIDEO_DECODER) += utvideodec.o utvideo.o utvideodsp.o +OBJS-$(CONFIG_UTVIDEO_ENCODER) += utvideoenc.o utvideo.o +OBJS-$(CONFIG_V210_DECODER) += v210dec.o +OBJS-$(CONFIG_V210_ENCODER) += v210enc.o +OBJS-$(CONFIG_V210X_DECODER) += v210x.o +OBJS-$(CONFIG_V308_DECODER) += v308dec.o +OBJS-$(CONFIG_V308_ENCODER) += v308enc.o +OBJS-$(CONFIG_V408_DECODER) += v408dec.o +OBJS-$(CONFIG_V408_ENCODER) += v408enc.o +OBJS-$(CONFIG_V410_DECODER) += v410dec.o +OBJS-$(CONFIG_V410_ENCODER) += v410enc.o +OBJS-$(CONFIG_VB_DECODER) += vb.o +OBJS-$(CONFIG_VBLE_DECODER) += vble.o +OBJS-$(CONFIG_VC1_DECODER) += vc1dec.o vc1_block.o vc1_loopfilter.o \ + vc1_mc.o vc1_pred.o vc1.o vc1data.o \ + msmpeg4dec.o msmpeg4.o msmpeg4data.o \ + wmv2dsp.o wmv2data.o +OBJS-$(CONFIG_VC1_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_VC1_MMAL_DECODER) += mmaldec.o +OBJS-$(CONFIG_VC1_QSV_DECODER) += qsvdec_other.o +OBJS-$(CONFIG_VC1_V4L2M2M_DECODER) += v4l2_m2m_dec.o +OBJS-$(CONFIG_VC2_ENCODER) += vc2enc.o vc2enc_dwt.o diractab.o +OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o +OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdaudio.o +OBJS-$(CONFIG_VMDVIDEO_DECODER) += vmdvideo.o +OBJS-$(CONFIG_VMNC_DECODER) += vmnc.o +OBJS-$(CONFIG_VORBIS_DECODER) += vorbisdec.o vorbisdsp.o vorbis.o \ + vorbis_data.o +OBJS-$(CONFIG_VORBIS_ENCODER) += vorbisenc.o vorbis.o \ + vorbis_data.o +OBJS-$(CONFIG_VP3_DECODER) += vp3.o +OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o vp56rac.o +OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o \ + vp6dsp.o vp56rac.o +OBJS-$(CONFIG_VP7_DECODER) += vp8.o vp56rac.o +OBJS-$(CONFIG_VP8_DECODER) += vp8.o vp56rac.o +OBJS-$(CONFIG_VP8_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_VP8_MEDIACODEC_DECODER) += mediacodecdec.o +OBJS-$(CONFIG_VP8_QSV_DECODER) += qsvdec_other.o +OBJS-$(CONFIG_VP8_RKMPP_DECODER) += rkmppdec.o +OBJS-$(CONFIG_VP8_VAAPI_ENCODER) += vaapi_encode_vp8.o +OBJS-$(CONFIG_VP8_V4L2M2M_DECODER) += v4l2_m2m_dec.o +OBJS-$(CONFIG_VP8_V4L2M2M_ENCODER) += v4l2_m2m_enc.o +OBJS-$(CONFIG_VP9_DECODER) += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9recon.o \ + vp9block.o vp9prob.o vp9mvs.o vp56rac.o \ + vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o +OBJS-$(CONFIG_VP9_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER) += mediacodecdec.o +OBJS-$(CONFIG_VP9_RKMPP_DECODER) += rkmppdec.o +OBJS-$(CONFIG_VP9_VAAPI_ENCODER) += vaapi_encode_vp9.o +OBJS-$(CONFIG_VPLAYER_DECODER) += textdec.o ass.o +OBJS-$(CONFIG_VP9_V4L2M2M_DECODER) += v4l2_m2m_dec.o +OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o +OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o +OBJS-$(CONFIG_WAVPACK_ENCODER) += wavpackenc.o +OBJS-$(CONFIG_WCMV_DECODER) += wcmv.o +OBJS-$(CONFIG_WEBP_DECODER) += webp.o +OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.o ass.o +OBJS-$(CONFIG_WEBVTT_ENCODER) += webvttenc.o ass_split.o +OBJS-$(CONFIG_WMALOSSLESS_DECODER) += wmalosslessdec.o wma_common.o +OBJS-$(CONFIG_WMAPRO_DECODER) += wmaprodec.o wma.o wma_common.o +OBJS-$(CONFIG_WMAV1_DECODER) += wmadec.o wma.o wma_common.o aactab.o +OBJS-$(CONFIG_WMAV1_ENCODER) += wmaenc.o wma.o wma_common.o aactab.o +OBJS-$(CONFIG_WMAV2_DECODER) += wmadec.o wma.o wma_common.o aactab.o +OBJS-$(CONFIG_WMAV2_ENCODER) += wmaenc.o wma.o wma_common.o aactab.o +OBJS-$(CONFIG_WMAVOICE_DECODER) += wmavoice.o \ + celp_filters.o \ + acelp_vectors.o acelp_filters.o +OBJS-$(CONFIG_WMV1_DECODER) += msmpeg4dec.o msmpeg4.o msmpeg4data.o +OBJS-$(CONFIG_WMV1_ENCODER) += msmpeg4enc.o +OBJS-$(CONFIG_WMV2_DECODER) += wmv2dec.o wmv2.o wmv2data.o \ + msmpeg4dec.o msmpeg4.o msmpeg4data.o +OBJS-$(CONFIG_WMV2_ENCODER) += wmv2enc.o wmv2.o wmv2data.o \ + msmpeg4.o msmpeg4enc.o msmpeg4data.o +OBJS-$(CONFIG_WNV1_DECODER) += wnv1.o +OBJS-$(CONFIG_WRAPPED_AVFRAME_DECODER) += wrapped_avframe.o +OBJS-$(CONFIG_WRAPPED_AVFRAME_ENCODER) += wrapped_avframe.o +OBJS-$(CONFIG_WS_SND1_DECODER) += ws-snd1.o +OBJS-$(CONFIG_XAN_DPCM_DECODER) += dpcm.o +OBJS-$(CONFIG_XAN_WC3_DECODER) += xan.o +OBJS-$(CONFIG_XAN_WC4_DECODER) += xxan.o +OBJS-$(CONFIG_XBIN_DECODER) += bintext.o cga_data.o +OBJS-$(CONFIG_XBM_DECODER) += xbmdec.o +OBJS-$(CONFIG_XBM_ENCODER) += xbmenc.o +OBJS-$(CONFIG_XFACE_DECODER) += xfacedec.o xface.o +OBJS-$(CONFIG_XFACE_ENCODER) += xfaceenc.o xface.o +OBJS-$(CONFIG_XL_DECODER) += xl.o +OBJS-$(CONFIG_XMA1_DECODER) += wmaprodec.o wma.o wma_common.o +OBJS-$(CONFIG_XMA2_DECODER) += wmaprodec.o wma.o wma_common.o +OBJS-$(CONFIG_XPM_DECODER) += xpmdec.o +OBJS-$(CONFIG_XSUB_DECODER) += xsubdec.o +OBJS-$(CONFIG_XSUB_ENCODER) += xsubenc.o +OBJS-$(CONFIG_XWD_DECODER) += xwddec.o +OBJS-$(CONFIG_XWD_ENCODER) += xwdenc.o +OBJS-$(CONFIG_Y41P_DECODER) += y41pdec.o +OBJS-$(CONFIG_Y41P_ENCODER) += y41penc.o +OBJS-$(CONFIG_YLC_DECODER) += ylc.o +OBJS-$(CONFIG_YOP_DECODER) += yop.o +OBJS-$(CONFIG_YUV4_DECODER) += yuv4dec.o +OBJS-$(CONFIG_YUV4_ENCODER) += yuv4enc.o +OBJS-$(CONFIG_ZEROCODEC_DECODER) += zerocodec.o +OBJS-$(CONFIG_ZLIB_DECODER) += lcldec.o +OBJS-$(CONFIG_ZLIB_ENCODER) += lclenc.o +OBJS-$(CONFIG_ZMBV_DECODER) += zmbv.o +OBJS-$(CONFIG_ZMBV_ENCODER) += zmbvenc.o + +# (AD)PCM decoders/encoders +OBJS-$(CONFIG_PCM_ALAW_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_ALAW_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_BLURAY_DECODER) += pcm-bluray.o +OBJS-$(CONFIG_PCM_DVD_DECODER) += pcm-dvd.o +OBJS-$(CONFIG_PCM_DVD_ENCODER) += pcm-dvdenc.o +OBJS-$(CONFIG_PCM_F16LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_F24LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_F32BE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_F32BE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_F32LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_F32LE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_F64BE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_F64BE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_F64LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_F64LE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_LXF_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_MULAW_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_MULAW_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S8_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S8_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S8_PLANAR_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S8_PLANAR_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S16BE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S16BE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S16BE_PLANAR_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S16BE_PLANAR_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S16LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S16LE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S16LE_PLANAR_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S16LE_PLANAR_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S24BE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S24BE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S24DAUD_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S24DAUD_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S24LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S24LE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S24LE_PLANAR_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S24LE_PLANAR_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S32BE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S32BE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S32LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S32LE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S32LE_PLANAR_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S32LE_PLANAR_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S64BE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S64BE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_S64LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_S64LE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_U8_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_U8_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_U16BE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_U16BE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_U16LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_U16LE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_U24BE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_U24BE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_U24LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_U24LE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_U32BE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_U32BE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_U32LE_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_U32LE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_VIDC_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_VIDC_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_ZORK_DECODER) += pcm.o + +OBJS-$(CONFIG_ADPCM_4XM_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_ADX_DECODER) += adxdec.o adx.o +OBJS-$(CONFIG_ADPCM_ADX_ENCODER) += adxenc.o adx.o +OBJS-$(CONFIG_ADPCM_AFC_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_AGM_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_AICA_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_DTK_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_EA_MAXIS_XA_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_EA_R1_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_EA_R2_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_EA_R3_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_EA_XAS_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_G722_DECODER) += g722.o g722dsp.o g722dec.o +OBJS-$(CONFIG_ADPCM_G722_ENCODER) += g722.o g722dsp.o g722enc.o +OBJS-$(CONFIG_ADPCM_G726_DECODER) += g726.o +OBJS-$(CONFIG_ADPCM_G726_ENCODER) += g726.o +OBJS-$(CONFIG_ADPCM_G726LE_DECODER) += g726.o +OBJS-$(CONFIG_ADPCM_G726LE_ENCODER) += g726.o +OBJS-$(CONFIG_ADPCM_IMA_AMV_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_APC_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_DAT4_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_DK3_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_DK4_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_EA_EACS_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_EA_SEAD_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_ISS_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_OKI_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_QT_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_QT_ENCODER) += adpcmenc.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_RAD_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_SMJPEG_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER) += adpcmenc.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_WS_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_MS_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_MS_ENCODER) += adpcmenc.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_MTAF_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_PSX_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_SBPRO_2_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_SBPRO_3_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_SBPRO_4_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_SWF_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_SWF_ENCODER) += adpcmenc.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_THP_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_THP_LE_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_VIMA_DECODER) += vima.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_XA_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcmenc.o adpcm_data.o + +# hardware accelerators +OBJS-$(CONFIG_D3D11VA) += dxva2.o +OBJS-$(CONFIG_DXVA2) += dxva2.o +OBJS-$(CONFIG_NVDEC) += nvdec.o +OBJS-$(CONFIG_VAAPI) += vaapi_decode.o +OBJS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.o +OBJS-$(CONFIG_VDPAU) += vdpau.o + +OBJS-$(CONFIG_H263_VAAPI_HWACCEL) += vaapi_mpeg4.o +OBJS-$(CONFIG_H263_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o +OBJS-$(CONFIG_H264_D3D11VA_HWACCEL) += dxva2_h264.o +OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o +OBJS-$(CONFIG_H264_NVDEC_HWACCEL) += nvdec_h264.o +OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec_h2645.o +OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o +OBJS-$(CONFIG_H264_VDPAU_HWACCEL) += vdpau_h264.o +OBJS-$(CONFIG_H264_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o +OBJS-$(CONFIG_HEVC_D3D11VA_HWACCEL) += dxva2_hevc.o +OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o +OBJS-$(CONFIG_HEVC_NVDEC_HWACCEL) += nvdec_hevc.o +OBJS-$(CONFIG_HEVC_QSV_HWACCEL) += qsvdec_h2645.o +OBJS-$(CONFIG_HEVC_VAAPI_HWACCEL) += vaapi_hevc.o +OBJS-$(CONFIG_HEVC_VDPAU_HWACCEL) += vdpau_hevc.o +OBJS-$(CONFIG_MJPEG_NVDEC_HWACCEL) += nvdec_mjpeg.o +OBJS-$(CONFIG_MJPEG_VAAPI_HWACCEL) += vaapi_mjpeg.o +OBJS-$(CONFIG_MPEG1_NVDEC_HWACCEL) += nvdec_mpeg12.o +OBJS-$(CONFIG_MPEG1_VDPAU_HWACCEL) += vdpau_mpeg12.o +OBJS-$(CONFIG_MPEG1_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o +OBJS-$(CONFIG_MPEG1_XVMC_HWACCEL) += mpegvideo_xvmc.o +OBJS-$(CONFIG_MPEG2_D3D11VA_HWACCEL) += dxva2_mpeg2.o +OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o +OBJS-$(CONFIG_MPEG2_NVDEC_HWACCEL) += nvdec_mpeg12.o +OBJS-$(CONFIG_MPEG2_QSV_HWACCEL) += qsvdec_other.o +OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o +OBJS-$(CONFIG_MPEG2_VDPAU_HWACCEL) += vdpau_mpeg12.o +OBJS-$(CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o +OBJS-$(CONFIG_MPEG2_XVMC_HWACCEL) += mpegvideo_xvmc.o +OBJS-$(CONFIG_MPEG4_NVDEC_HWACCEL) += nvdec_mpeg4.o +OBJS-$(CONFIG_MPEG4_VAAPI_HWACCEL) += vaapi_mpeg4.o +OBJS-$(CONFIG_MPEG4_VDPAU_HWACCEL) += vdpau_mpeg4.o +OBJS-$(CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o +OBJS-$(CONFIG_VC1_D3D11VA_HWACCEL) += dxva2_vc1.o +OBJS-$(CONFIG_VC1_DXVA2_HWACCEL) += dxva2_vc1.o +OBJS-$(CONFIG_VC1_NVDEC_HWACCEL) += nvdec_vc1.o +OBJS-$(CONFIG_VC1_QSV_HWACCEL) += qsvdec_other.o +OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o +OBJS-$(CONFIG_VC1_VDPAU_HWACCEL) += vdpau_vc1.o +OBJS-$(CONFIG_VP8_NVDEC_HWACCEL) += nvdec_vp8.o +OBJS-$(CONFIG_VP8_VAAPI_HWACCEL) += vaapi_vp8.o +OBJS-$(CONFIG_VP9_D3D11VA_HWACCEL) += dxva2_vp9.o +OBJS-$(CONFIG_VP9_DXVA2_HWACCEL) += dxva2_vp9.o +OBJS-$(CONFIG_VP9_NVDEC_HWACCEL) += nvdec_vp9.o +OBJS-$(CONFIG_VP9_VAAPI_HWACCEL) += vaapi_vp9.o +OBJS-$(CONFIG_VP8_QSV_HWACCEL) += qsvdec_other.o + +# libavformat dependencies +OBJS-$(CONFIG_ISO_MEDIA) += mpeg4audio.o mpegaudiodata.o + +OBJS-$(CONFIG_ADTS_MUXER) += mpeg4audio.o +OBJS-$(CONFIG_CAF_DEMUXER) += ac3tab.o +OBJS-$(CONFIG_CODEC2_DEMUXER) += codec2utils.o +OBJS-$(CONFIG_CODEC2_MUXER) += codec2utils.o +OBJS-$(CONFIG_CODEC2RAW_DEMUXER) += codec2utils.o +OBJS-$(CONFIG_DNXHD_DEMUXER) += dnxhddata.o +OBJS-$(CONFIG_FITS_DEMUXER) += fits.o +OBJS-$(CONFIG_FLV_DEMUXER) += mpeg4audio.o +OBJS-$(CONFIG_LATM_MUXER) += mpeg4audio.o +OBJS-$(CONFIG_MATROSKA_AUDIO_MUXER) += mpeg4audio.o +OBJS-$(CONFIG_MATROSKA_MUXER) += mpeg4audio.o +OBJS-$(CONFIG_MOV_DEMUXER) += ac3tab.o +OBJS-$(CONFIG_MXF_MUXER) += dnxhddata.o +OBJS-$(CONFIG_NUT_MUXER) += mpegaudiodata.o +OBJS-$(CONFIG_NUT_DEMUXER) += mpegaudiodata.o mpeg4audio.o +OBJS-$(CONFIG_RTP_MUXER) += mpeg4audio.o +OBJS-$(CONFIG_SPDIF_MUXER) += dca.o +OBJS-$(CONFIG_TAK_DEMUXER) += tak.o +OBJS-$(CONFIG_WEBM_MUXER) += mpeg4audio.o + +# libavfilter dependencies +OBJS-$(CONFIG_ELBG_FILTER) += elbg.o + +# external codec libraries +OBJS-$(CONFIG_AAC_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_AC3_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_ADPCM_IMA_QT_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_ALAC_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_AMR_NB_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_EAC3_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_GSM_MS_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_ILBC_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_MP1_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_MP2_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_MP3_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_PCM_MULAW_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_PCM_ALAW_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_QDMC_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_QDM2_AT_DECODER) += audiotoolboxdec.o +OBJS-$(CONFIG_AAC_AT_ENCODER) += audiotoolboxenc.o +OBJS-$(CONFIG_ALAC_AT_ENCODER) += audiotoolboxenc.o +OBJS-$(CONFIG_ILBC_AT_ENCODER) += audiotoolboxenc.o +OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER) += audiotoolboxenc.o +OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER) += audiotoolboxenc.o +OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o +OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o +OBJS-$(CONFIG_LIBARIBB24_DECODER) += libaribb24.o ass.o +OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o +OBJS-$(CONFIG_LIBCODEC2_DECODER) += libcodec2.o codec2utils.o +OBJS-$(CONFIG_LIBCODEC2_ENCODER) += libcodec2.o codec2utils.o +OBJS-$(CONFIG_LIBDAV1D_DECODER) += libdav1d.o +OBJS-$(CONFIG_LIBDAVS2_DECODER) += libdavs2.o +OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o +OBJS-$(CONFIG_LIBFDK_AAC_ENCODER) += libfdk-aacenc.o +OBJS-$(CONFIG_LIBGSM_DECODER) += libgsmdec.o +OBJS-$(CONFIG_LIBGSM_ENCODER) += libgsmenc.o +OBJS-$(CONFIG_LIBGSM_MS_DECODER) += libgsmdec.o +OBJS-$(CONFIG_LIBGSM_MS_ENCODER) += libgsmenc.o +OBJS-$(CONFIG_LIBILBC_DECODER) += libilbc.o +OBJS-$(CONFIG_LIBILBC_ENCODER) += libilbc.o +OBJS-$(CONFIG_LIBKVAZAAR_ENCODER) += libkvazaar.o +OBJS-$(CONFIG_LIBMP3LAME_ENCODER) += libmp3lame.o +OBJS-$(CONFIG_LIBOPENCORE_AMRNB_DECODER) += libopencore-amr.o +OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER) += libopencore-amr.o +OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER) += libopencore-amr.o +OBJS-$(CONFIG_LIBOPENH264_DECODER) += libopenh264dec.o libopenh264.o +OBJS-$(CONFIG_LIBOPENH264_ENCODER) += libopenh264enc.o libopenh264.o +OBJS-$(CONFIG_LIBOPENJPEG_DECODER) += libopenjpegdec.o +OBJS-$(CONFIG_LIBOPENJPEG_ENCODER) += libopenjpegenc.o +OBJS-$(CONFIG_LIBOPUS_DECODER) += libopusdec.o libopus.o \ + vorbis_data.o +OBJS-$(CONFIG_LIBOPUS_ENCODER) += libopusenc.o libopus.o \ + vorbis_data.o +OBJS-$(CONFIG_LIBSHINE_ENCODER) += libshine.o +OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.o +OBJS-$(CONFIG_LIBSPEEX_ENCODER) += libspeexenc.o +OBJS-$(CONFIG_LIBTHEORA_ENCODER) += libtheoraenc.o +OBJS-$(CONFIG_LIBTWOLAME_ENCODER) += libtwolame.o +OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER) += libvo-amrwbenc.o +OBJS-$(CONFIG_LIBVORBIS_DECODER) += libvorbisdec.o +OBJS-$(CONFIG_LIBVORBIS_ENCODER) += libvorbisenc.o \ + vorbis_data.o +OBJS-$(CONFIG_LIBVPX_VP8_DECODER) += libvpxdec.o +OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o +OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o libvpx.o +OBJS-$(CONFIG_LIBVPX_VP9_ENCODER) += libvpxenc.o libvpx.o +OBJS-$(CONFIG_LIBWAVPACK_ENCODER) += libwavpackenc.o +OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.o libwebpenc.o +OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_animencoder.o +OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o +OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o +OBJS-$(CONFIG_LIBX265_ENCODER) += libx265.o +OBJS-$(CONFIG_LIBXAVS_ENCODER) += libxavs.o +OBJS-$(CONFIG_LIBXAVS2_ENCODER) += libxavs2.o +OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o +OBJS-$(CONFIG_LIBZVBI_TELETEXT_DECODER) += libzvbi-teletextdec.o ass.o + +# parsers +OBJS-$(CONFIG_AAC_LATM_PARSER) += latm_parser.o +OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o \ + mpeg4audio.o +OBJS-$(CONFIG_AC3_PARSER) += ac3tab.o aac_ac3_parser.o +OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o adx.o +OBJS-$(CONFIG_AV1_PARSER) += av1_parser.o av1_parse.o +OBJS-$(CONFIG_AVS2_PARSER) += avs2_parser.o +OBJS-$(CONFIG_BMP_PARSER) += bmp_parser.o +OBJS-$(CONFIG_CAVSVIDEO_PARSER) += cavs_parser.o +OBJS-$(CONFIG_COOK_PARSER) += cook_parser.o +OBJS-$(CONFIG_DCA_PARSER) += dca_parser.o dca_exss.o dca.o +OBJS-$(CONFIG_DIRAC_PARSER) += dirac_parser.o +OBJS-$(CONFIG_DNXHD_PARSER) += dnxhd_parser.o dnxhddata.o +OBJS-$(CONFIG_DPX_PARSER) += dpx_parser.o +OBJS-$(CONFIG_DVAUDIO_PARSER) += dvaudio_parser.o +OBJS-$(CONFIG_DVBSUB_PARSER) += dvbsub_parser.o +OBJS-$(CONFIG_DVD_NAV_PARSER) += dvd_nav_parser.o +OBJS-$(CONFIG_DVDSUB_PARSER) += dvdsub_parser.o +OBJS-$(CONFIG_FLAC_PARSER) += flac_parser.o flacdata.o flac.o \ + vorbis_data.o +OBJS-$(CONFIG_G723_1_PARSER) += g723_1_parser.o +OBJS-$(CONFIG_G729_PARSER) += g729_parser.o +OBJS-$(CONFIG_GIF_PARSER) += gif_parser.o +OBJS-$(CONFIG_GSM_PARSER) += gsm_parser.o +OBJS-$(CONFIG_H261_PARSER) += h261_parser.o +OBJS-$(CONFIG_H263_PARSER) += h263_parser.o +OBJS-$(CONFIG_H264_PARSER) += h264_parser.o h264_sei.o h264data.o +OBJS-$(CONFIG_HEVC_PARSER) += hevc_parser.o hevc_data.o +OBJS-$(CONFIG_MJPEG_PARSER) += mjpeg_parser.o +OBJS-$(CONFIG_MLP_PARSER) += mlp_parse.o mlp_parser.o mlp.o +OBJS-$(CONFIG_MPEG4VIDEO_PARSER) += mpeg4video_parser.o h263.o \ + mpeg4videodec.o mpeg4video.o \ + ituh263dec.o h263dec.o h263data.o +OBJS-$(CONFIG_PNG_PARSER) += png_parser.o +OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o +OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ + mpeg12.o mpeg12data.o +OBJS-$(CONFIG_OPUS_PARSER) += opus_parser.o opus.o opustab.o \ + opus_rc.o vorbis_data.o +OBJS-$(CONFIG_PNG_PARSER) += png_parser.o +OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o +OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o +OBJS-$(CONFIG_RV40_PARSER) += rv34_parser.o +OBJS-$(CONFIG_SBC_PARSER) += sbc_parser.o +OBJS-$(CONFIG_SIPR_PARSER) += sipr_parser.o +OBJS-$(CONFIG_TAK_PARSER) += tak_parser.o tak.o +OBJS-$(CONFIG_VC1_PARSER) += vc1_parser.o vc1.o vc1data.o \ + simple_idct.o wmv2data.o +OBJS-$(CONFIG_VP3_PARSER) += vp3_parser.o +OBJS-$(CONFIG_VP8_PARSER) += vp8_parser.o +OBJS-$(CONFIG_VP9_PARSER) += vp9_parser.o +OBJS-$(CONFIG_XMA_PARSER) += xma_parser.o + +# bitstream filters +OBJS-$(CONFIG_AAC_ADTSTOASC_BSF) += aac_adtstoasc_bsf.o mpeg4audio.o +OBJS-$(CONFIG_AV1_METADATA_BSF) += av1_metadata_bsf.o +OBJS-$(CONFIG_AV1_FRAME_SPLIT_BSF) += av1_frame_split_bsf.o +OBJS-$(CONFIG_CHOMP_BSF) += chomp_bsf.o +OBJS-$(CONFIG_DUMP_EXTRADATA_BSF) += dump_extradata_bsf.o +OBJS-$(CONFIG_DCA_CORE_BSF) += dca_core_bsf.o +OBJS-$(CONFIG_EAC3_CORE_BSF) += eac3_core_bsf.o +OBJS-$(CONFIG_EXTRACT_EXTRADATA_BSF) += extract_extradata_bsf.o \ + av1_parse.o h2645_parse.o +OBJS-$(CONFIG_FILTER_UNITS_BSF) += filter_units_bsf.o +OBJS-$(CONFIG_H264_METADATA_BSF) += h264_metadata_bsf.o h264_levels.o +OBJS-$(CONFIG_H264_MP4TOANNEXB_BSF) += h264_mp4toannexb_bsf.o +OBJS-$(CONFIG_H264_REDUNDANT_PPS_BSF) += h264_redundant_pps_bsf.o +OBJS-$(CONFIG_HAPQA_EXTRACT_BSF) += hapqa_extract_bsf.o hap.o +OBJS-$(CONFIG_HEVC_METADATA_BSF) += h265_metadata_bsf.o h265_profile_level.o +OBJS-$(CONFIG_HEVC_MP4TOANNEXB_BSF) += hevc_mp4toannexb_bsf.o +OBJS-$(CONFIG_IMX_DUMP_HEADER_BSF) += imx_dump_header_bsf.o +OBJS-$(CONFIG_MJPEG2JPEG_BSF) += mjpeg2jpeg_bsf.o +OBJS-$(CONFIG_MJPEGA_DUMP_HEADER_BSF) += mjpega_dump_header_bsf.o +OBJS-$(CONFIG_MPEG4_UNPACK_BFRAMES_BSF) += mpeg4_unpack_bframes_bsf.o +OBJS-$(CONFIG_MOV2TEXTSUB_BSF) += movsub_bsf.o +OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF) += mp3_header_decompress_bsf.o \ + mpegaudiodata.o +OBJS-$(CONFIG_MPEG2_METADATA_BSF) += mpeg2_metadata_bsf.o +OBJS-$(CONFIG_NOISE_BSF) += noise_bsf.o +OBJS-$(CONFIG_NULL_BSF) += null_bsf.o +OBJS-$(CONFIG_PRORES_METADATA_BSF) += prores_metadata_bsf.o +OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += remove_extradata_bsf.o +OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += movsub_bsf.o +OBJS-$(CONFIG_TRACE_HEADERS_BSF) += trace_headers_bsf.o +OBJS-$(CONFIG_TRUEHD_CORE_BSF) += truehd_core_bsf.o mlp_parse.o mlp.o +OBJS-$(CONFIG_VP9_METADATA_BSF) += vp9_metadata_bsf.o +OBJS-$(CONFIG_VP9_RAW_REORDER_BSF) += vp9_raw_reorder_bsf.o +OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o +OBJS-$(CONFIG_VP9_SUPERFRAME_SPLIT_BSF) += vp9_superframe_split_bsf.o + +# thread libraries +OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o +OBJS-$(HAVE_THREADS) += pthread.o pthread_slice.o pthread_frame.o + +OBJS-$(CONFIG_FRAME_THREAD_ENCODER) += frame_thread_encoder.o + +# Windows resource file +SLIBOBJS-$(HAVE_GNU_WINDRES) += avcodecres.o + +SKIPHEADERS += %_tablegen.h \ + %_tables.h \ + fft-internal.h \ + tableprint.h \ + tableprint_vlc.h \ + aaccoder_twoloop.h \ + aaccoder_trellis.h \ + aacenc_quantization.h \ + aacenc_quantization_misc.h \ + $(ARCH)/vp56_arith.h \ + +SKIPHEADERS-$(CONFIG_AMF) += amfenc.h +SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h +SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h +SKIPHEADERS-$(CONFIG_JNI) += ffjni.h +SKIPHEADERS-$(CONFIG_LIBVPX) += libvpx.h +SKIPHEADERS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.h +SKIPHEADERS-$(CONFIG_MEDIACODEC) += mediacodecdec_common.h mediacodec_surface.h mediacodec_wrapper.h mediacodec_sw_buffer.h +SKIPHEADERS-$(CONFIG_NVDEC) += nvdec.h +SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h +SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h +SKIPHEADERS-$(CONFIG_QSVDEC) += qsvdec.h +SKIPHEADERS-$(CONFIG_QSVENC) += qsvenc.h +SKIPHEADERS-$(CONFIG_XVMC) += xvmc.h +SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_decode.h vaapi_encode.h +SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h vdpau_internal.h +SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.h vt_internal.h +SKIPHEADERS-$(CONFIG_V4L2_M2M) += v4l2_buffers.h v4l2_context.h v4l2_m2m.h + +TESTPROGS = avpacket \ + celp_math \ + codec_desc \ + htmlsubtitles \ + imgconvert \ + jpeg2000dwt \ + mathops \ + options \ + mjpegenc_huffman \ + utils \ + +TESTPROGS-$(CONFIG_CABAC) += cabac +TESTPROGS-$(CONFIG_DCT) += avfft +TESTPROGS-$(CONFIG_FFT) += fft fft-fixed fft-fixed32 +TESTPROGS-$(CONFIG_GOLOMB) += golomb +TESTPROGS-$(CONFIG_IDCTDSP) += dct +TESTPROGS-$(CONFIG_IIRFILTER) += iirfilter +TESTPROGS-$(HAVE_MMX) += motion +TESTPROGS-$(CONFIG_MPEGVIDEO) += mpeg12framerate +TESTPROGS-$(CONFIG_H264_METADATA_BSF) += h264_levels +TESTPROGS-$(CONFIG_HEVC_METADATA_BSF) += h265_levels +TESTPROGS-$(CONFIG_RANGECODER) += rangecoder +TESTPROGS-$(CONFIG_SNOW_ENCODER) += snowenc + +TESTOBJS = dctref.o + +TOOLS = fourcc2pixfmt + +HOSTPROGS = aacps_tablegen \ + aacps_fixed_tablegen \ + cbrt_tablegen \ + cbrt_fixed_tablegen \ + cos_tablegen \ + dv_tablegen \ + motionpixels_tablegen \ + mpegaudio_tablegen \ + pcm_tablegen \ + qdm2_tablegen \ + sinewin_tablegen \ + sinewin_fixed_tablegen \ + +CLEANFILES = *_tables.c *_tables.h *_tablegen$(HOSTEXESUF) + +$(SUBDIR)tests/dct$(EXESUF): $(SUBDIR)dctref.o $(SUBDIR)aandcttab.o +$(SUBDIR)dv_tablegen$(HOSTEXESUF): $(SUBDIR)dvdata_host.o + +TRIG_TABLES = cos cos_fixed sin +TRIG_TABLES := $(TRIG_TABLES:%=$(SUBDIR)%_tables.c) + +$(TRIG_TABLES): $(SUBDIR)%_tables.c: $(SUBDIR)cos_tablegen$(HOSTEXESUF) + $(M)./$< $* > $@ + +ifdef CONFIG_SMALL +$(SUBDIR)%_tablegen$(HOSTEXESUF): HOSTCFLAGS += -DCONFIG_SMALL=1 +else +$(SUBDIR)%_tablegen$(HOSTEXESUF): HOSTCFLAGS += -DCONFIG_SMALL=0 +endif + +GEN_HEADERS = cbrt_tables.h cbrt_fixed_tables.h aacps_tables.h aacps_fixed_tables.h \ + dv_tables.h \ + sinewin_tables.h sinewin_fixed_tables.h mpegaudio_tables.h motionpixels_tables.h \ + pcm_tables.h qdm2_tables.h +GEN_HEADERS := $(addprefix $(SUBDIR), $(GEN_HEADERS)) + +$(GEN_HEADERS): $(SUBDIR)%_tables.h: $(SUBDIR)%_tablegen$(HOSTEXESUF) + $(M)./$< > $@ + +ifdef CONFIG_HARDCODED_TABLES +$(SUBDIR)cbrt_data.o: $(SUBDIR)cbrt_tables.h +$(SUBDIR)cbrt_data_fixed.o: $(SUBDIR)cbrt_fixed_tables.h +$(SUBDIR)aacps_float.o: $(SUBDIR)aacps_tables.h +$(SUBDIR)aacps_fixed.o: $(SUBDIR)aacps_fixed_tables.h +$(SUBDIR)aactab_fixed.o: $(SUBDIR)aac_fixed_tables.h +$(SUBDIR)dvenc.o: $(SUBDIR)dv_tables.h +$(SUBDIR)motionpixels.o: $(SUBDIR)motionpixels_tables.h +$(SUBDIR)mpegaudiodec_fixed.o: $(SUBDIR)mpegaudio_tables.h +$(SUBDIR)mpegaudiodec_float.o: $(SUBDIR)mpegaudio_tables.h +$(SUBDIR)pcm.o: $(SUBDIR)pcm_tables.h +$(SUBDIR)qdm2.o: $(SUBDIR)qdm2_tables.h +$(SUBDIR)sinewin.o: $(SUBDIR)sinewin_tables.h +$(SUBDIR)sinewin_fixed.o: $(SUBDIR)sinewin_fixed_tables.h +endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac.h new file mode 100644 index 0000000000..c2b9c980cb --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac.h @@ -0,0 +1,377 @@ +/* + * AAC definitions and structures + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC definitions and structures + * @author Oded Shimon ( ods15 ods15 dyndns org ) + * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) + */ + +#ifndef AVCODEC_AAC_H +#define AVCODEC_AAC_H + + +#include "aac_defines.h" +#include "libavutil/float_dsp.h" +#include "libavutil/fixed_dsp.h" +#include "avcodec.h" +#if !USE_FIXED +#include "mdct15.h" +#endif +#include "fft.h" +#include "mpeg4audio.h" +#include "sbr.h" + +#include + +#define MAX_CHANNELS 64 +#define MAX_ELEM_ID 16 + +#define TNS_MAX_ORDER 20 +#define MAX_LTP_LONG_SFB 40 + +#define CLIP_AVOIDANCE_FACTOR 0.95f + +enum RawDataBlockType { + TYPE_SCE, + TYPE_CPE, + TYPE_CCE, + TYPE_LFE, + TYPE_DSE, + TYPE_PCE, + TYPE_FIL, + TYPE_END, +}; + +enum ExtensionPayloadID { + EXT_FILL, + EXT_FILL_DATA, + EXT_DATA_ELEMENT, + EXT_DYNAMIC_RANGE = 0xb, + EXT_SBR_DATA = 0xd, + EXT_SBR_DATA_CRC = 0xe, +}; + +enum WindowSequence { + ONLY_LONG_SEQUENCE, + LONG_START_SEQUENCE, + EIGHT_SHORT_SEQUENCE, + LONG_STOP_SEQUENCE, +}; + +enum BandType { + ZERO_BT = 0, ///< Scalefactors and spectral data are all zero. + FIRST_PAIR_BT = 5, ///< This and later band types encode two values (rather than four) with one code word. + ESC_BT = 11, ///< Spectral data are coded with an escape sequence. + RESERVED_BT = 12, ///< Band types following are encoded differently from others. + NOISE_BT = 13, ///< Spectral data are scaled white noise not coded in the bitstream. + INTENSITY_BT2 = 14, ///< Scalefactor data are intensity stereo positions (out of phase). + INTENSITY_BT = 15, ///< Scalefactor data are intensity stereo positions (in phase). +}; + +#define IS_CODEBOOK_UNSIGNED(x) (((x) - 1) & 10) + +enum ChannelPosition { + AAC_CHANNEL_OFF = 0, + AAC_CHANNEL_FRONT = 1, + AAC_CHANNEL_SIDE = 2, + AAC_CHANNEL_BACK = 3, + AAC_CHANNEL_LFE = 4, + AAC_CHANNEL_CC = 5, +}; + +/** + * The point during decoding at which channel coupling is applied. + */ +enum CouplingPoint { + BEFORE_TNS, + BETWEEN_TNS_AND_IMDCT, + AFTER_IMDCT = 3, +}; + +/** + * Output configuration status + */ +enum OCStatus { + OC_NONE, ///< Output unconfigured + OC_TRIAL_PCE, ///< Output configuration under trial specified by an inband PCE + OC_TRIAL_FRAME, ///< Output configuration under trial specified by a frame header + OC_GLOBAL_HDR, ///< Output configuration set in a global header but not yet locked + OC_LOCKED, ///< Output configuration locked in place +}; + +typedef struct OutputConfiguration { + MPEG4AudioConfig m4ac; + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int layout_map_tags; + int channels; + uint64_t channel_layout; + enum OCStatus status; +} OutputConfiguration; + +/** + * Predictor State + */ +typedef struct PredictorState { + AAC_FLOAT cor0; + AAC_FLOAT cor1; + AAC_FLOAT var0; + AAC_FLOAT var1; + AAC_FLOAT r0; + AAC_FLOAT r1; + AAC_FLOAT k1; + AAC_FLOAT x_est; +} PredictorState; + +#define MAX_PREDICTORS 672 + +#define SCALE_DIV_512 36 ///< scalefactor difference that corresponds to scale difference in 512 times +#define SCALE_ONE_POS 140 ///< scalefactor index that corresponds to scale=1.0 +#define SCALE_MAX_POS 255 ///< scalefactor index maximum value +#define SCALE_MAX_DIFF 60 ///< maximum scalefactor difference allowed by standard +#define SCALE_DIFF_ZERO 60 ///< codebook index corresponding to zero scalefactor indices difference + +#define POW_SF2_ZERO 200 ///< ff_aac_pow2sf_tab index corresponding to pow(2, 0); + +#define NOISE_PRE 256 ///< preamble for NOISE_BT, put in bitstream with the first noise band +#define NOISE_PRE_BITS 9 ///< length of preamble +#define NOISE_OFFSET 90 ///< subtracted from global gain, used as offset for the preamble + +/** + * Long Term Prediction + */ +typedef struct LongTermPrediction { + int8_t present; + int16_t lag; + int coef_idx; + INTFLOAT coef; + int8_t used[MAX_LTP_LONG_SFB]; +} LongTermPrediction; + +/** + * Individual Channel Stream + */ +typedef struct IndividualChannelStream { + uint8_t max_sfb; ///< number of scalefactor bands per group + enum WindowSequence window_sequence[2]; + uint8_t use_kb_window[2]; ///< If set, use Kaiser-Bessel window, otherwise use a sine window. + int num_window_groups; + uint8_t group_len[8]; + LongTermPrediction ltp; + const uint16_t *swb_offset; ///< table of offsets to the lowest spectral coefficient of a scalefactor band, sfb, for a particular window + const uint8_t *swb_sizes; ///< table of scalefactor band sizes for a particular window + int num_swb; ///< number of scalefactor window bands + int num_windows; + int tns_max_bands; + int predictor_present; + int predictor_initialized; + int predictor_reset_group; + int predictor_reset_count[31]; ///< used by encoder to count prediction resets + uint8_t prediction_used[41]; + uint8_t window_clipping[8]; ///< set if a certain window is near clipping + float clip_avoidance_factor; ///< set if any window is near clipping to the necessary atennuation factor to avoid it +} IndividualChannelStream; + +/** + * Temporal Noise Shaping + */ +typedef struct TemporalNoiseShaping { + int present; + int n_filt[8]; + int length[8][4]; + int direction[8][4]; + int order[8][4]; + int coef_idx[8][4][TNS_MAX_ORDER]; + INTFLOAT coef[8][4][TNS_MAX_ORDER]; +} TemporalNoiseShaping; + +/** + * Dynamic Range Control - decoded from the bitstream but not processed further. + */ +typedef struct DynamicRangeControl { + int pce_instance_tag; ///< Indicates with which program the DRC info is associated. + int dyn_rng_sgn[17]; ///< DRC sign information; 0 - positive, 1 - negative + int dyn_rng_ctl[17]; ///< DRC magnitude information + int exclude_mask[MAX_CHANNELS]; ///< Channels to be excluded from DRC processing. + int band_incr; ///< Number of DRC bands greater than 1 having DRC info. + int interpolation_scheme; ///< Indicates the interpolation scheme used in the SBR QMF domain. + int band_top[17]; ///< Indicates the top of the i-th DRC band in units of 4 spectral lines. + int prog_ref_level; /**< A reference level for the long-term program audio level for all + * channels combined. + */ +} DynamicRangeControl; + +typedef struct Pulse { + int num_pulse; + int start; + int pos[4]; + int amp[4]; +} Pulse; + +/** + * coupling parameters + */ +typedef struct ChannelCoupling { + enum CouplingPoint coupling_point; ///< The point during decoding at which coupling is applied. + int num_coupled; ///< number of target elements + enum RawDataBlockType type[8]; ///< Type of channel element to be coupled - SCE or CPE. + int id_select[8]; ///< element id + int ch_select[8]; /**< [0] shared list of gains; [1] list of gains for right channel; + * [2] list of gains for left channel; [3] lists of gains for both channels + */ + INTFLOAT gain[16][120]; +} ChannelCoupling; + +/** + * Single Channel Element - used for both SCE and LFE elements. + */ +typedef struct SingleChannelElement { + IndividualChannelStream ics; + TemporalNoiseShaping tns; + Pulse pulse; + enum BandType band_type[128]; ///< band types + enum BandType band_alt[128]; ///< alternative band type (used by encoder) + int band_type_run_end[120]; ///< band type run end points + INTFLOAT sf[120]; ///< scalefactors + int sf_idx[128]; ///< scalefactor indices (used by encoder) + uint8_t zeroes[128]; ///< band is not coded (used by encoder) + uint8_t can_pns[128]; ///< band is allowed to PNS (informative) + float is_ener[128]; ///< Intensity stereo pos (used by encoder) + float pns_ener[128]; ///< Noise energy values (used by encoder) + DECLARE_ALIGNED(32, INTFLOAT, pcoeffs)[1024]; ///< coefficients for IMDCT, pristine + DECLARE_ALIGNED(32, INTFLOAT, coeffs)[1024]; ///< coefficients for IMDCT, maybe processed + DECLARE_ALIGNED(32, INTFLOAT, saved)[1536]; ///< overlap + DECLARE_ALIGNED(32, INTFLOAT, ret_buf)[2048]; ///< PCM output buffer + DECLARE_ALIGNED(16, INTFLOAT, ltp_state)[3072]; ///< time signal for LTP + DECLARE_ALIGNED(32, AAC_FLOAT, lcoeffs)[1024]; ///< MDCT of LTP coefficients (used by encoder) + DECLARE_ALIGNED(32, AAC_FLOAT, prcoeffs)[1024]; ///< Main prediction coefs (used by encoder) + PredictorState predictor_state[MAX_PREDICTORS]; + INTFLOAT *ret; ///< PCM output +} SingleChannelElement; + +/** + * channel element - generic struct for SCE/CPE/CCE/LFE + */ +typedef struct ChannelElement { + int present; + // CPE specific + int common_window; ///< Set if channels share a common 'IndividualChannelStream' in bitstream. + int ms_mode; ///< Signals mid/side stereo flags coding mode (used by encoder) + uint8_t is_mode; ///< Set if any bands have been encoded using intensity stereo (used by encoder) + uint8_t ms_mask[128]; ///< Set if mid/side stereo is used for each scalefactor window band + uint8_t is_mask[128]; ///< Set if intensity stereo is used (used by encoder) + // shared + SingleChannelElement ch[2]; + // CCE specific + ChannelCoupling coup; + SpectralBandReplication sbr; +} ChannelElement; + +/** + * main AAC context + */ +struct AACContext { + AVClass *class; + AVCodecContext *avctx; + AVFrame *frame; + + int is_saved; ///< Set if elements have stored overlap from previous frame. + DynamicRangeControl che_drc; + + /** + * @name Channel element related data + * @{ + */ + ChannelElement *che[4][MAX_ELEM_ID]; + ChannelElement *tag_che_map[4][MAX_ELEM_ID]; + int tags_mapped; + int warned_remapping_once; + /** @} */ + + /** + * @name temporary aligned temporary buffers + * (We do not want to have these on the stack.) + * @{ + */ + DECLARE_ALIGNED(32, INTFLOAT, buf_mdct)[1024]; + /** @} */ + + /** + * @name Computed / set up during initialization + * @{ + */ + FFTContext mdct; + FFTContext mdct_small; + FFTContext mdct_ld; + FFTContext mdct_ltp; +#if USE_FIXED + AVFixedDSPContext *fdsp; +#else + MDCT15Context *mdct120; + MDCT15Context *mdct480; + MDCT15Context *mdct960; + AVFloatDSPContext *fdsp; +#endif /* USE_FIXED */ + int random_state; + /** @} */ + + /** + * @name Members used for output + * @{ + */ + SingleChannelElement *output_element[MAX_CHANNELS]; ///< Points to each SingleChannelElement + /** @} */ + + + /** + * @name Japanese DTV specific extension + * @{ + */ + int force_dmono_mode;///< 0->not dmono, 1->use first channel, 2->use second channel + int dmono_mode; ///< 0->not dmono, 1->use first channel, 2->use second channel + /** @} */ + + DECLARE_ALIGNED(32, INTFLOAT, temp)[128]; + + OutputConfiguration oc[2]; + int warned_num_aac_frames; + int warned_960_sbr; + + int warned_gain_control; + + /* aacdec functions pointers */ + void (*imdct_and_windowing)(AACContext *ac, SingleChannelElement *sce); + void (*apply_ltp)(AACContext *ac, SingleChannelElement *sce); + void (*apply_tns)(INTFLOAT coef[1024], TemporalNoiseShaping *tns, + IndividualChannelStream *ics, int decode); + void (*windowing_and_mdct_ltp)(AACContext *ac, INTFLOAT *out, + INTFLOAT *in, IndividualChannelStream *ics); + void (*update_ltp)(AACContext *ac, SingleChannelElement *sce); + void (*vector_pow43)(int *coefs, int len); + void (*subband_scale)(int *dst, int *src, int scale, int offset, int len, void *log_context); + +}; + +void ff_aacdec_init_mips(AACContext *c); + +#endif /* AVCODEC_AAC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_ac3_parser.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_ac3_parser.c new file mode 100644 index 0000000000..54e459844f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_ac3_parser.c @@ -0,0 +1,105 @@ +/* + * Common AAC and AC-3 parser + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/channel_layout.h" +#include "libavutil/common.h" +#include "parser.h" +#include "aac_ac3_parser.h" + +int ff_aac_ac3_parse(AVCodecParserContext *s1, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + AACAC3ParseContext *s = s1->priv_data; + ParseContext *pc = &s->pc; + int len, i; + int new_frame_start; + int got_frame = 0; + +get_next: + i=END_NOT_FOUND; + if(s->remaining_size <= buf_size){ + if(s->remaining_size && !s->need_next_header){ + i= s->remaining_size; + s->remaining_size = 0; + }else{ //we need a header first + len=0; + for(i=s->remaining_size; istate = (s->state<<8) + buf[i]; + if((len=s->sync(s->state, s, &s->need_next_header, &new_frame_start))) + break; + } + if(len<=0){ + i=END_NOT_FOUND; + }else{ + got_frame = 1; + s->state=0; + i-= s->header_size -1; + s->remaining_size = len; + if(!new_frame_start || pc->index+i<=0){ + s->remaining_size += i; + goto get_next; + } + else if (i < 0) { + s->remaining_size += i; + } + } + } + } + + if(ff_combine_frame(pc, i, &buf, &buf_size)<0){ + s->remaining_size -= FFMIN(s->remaining_size, buf_size); + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + + *poutbuf = buf; + *poutbuf_size = buf_size; + + /* update codec info */ + if(s->codec_id) + avctx->codec_id = s->codec_id; + + if (got_frame) { + /* Due to backwards compatible HE-AAC the sample rate, channel count, + and total number of samples found in an AAC ADTS header are not + reliable. Bit rate is still accurate because the total frame + duration in seconds is still correct (as is the number of bits in + the frame). */ + if (avctx->codec_id != AV_CODEC_ID_AAC) { + avctx->sample_rate = s->sample_rate; + if (avctx->codec_id != AV_CODEC_ID_EAC3) { + avctx->channels = s->channels; + avctx->channel_layout = s->channel_layout; + } + s1->duration = s->samples; + avctx->audio_service_type = s->service_type; + } + + if (avctx->codec_id != AV_CODEC_ID_EAC3) + avctx->bit_rate = s->bit_rate; + } + + return i; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_ac3_parser.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_ac3_parser.h new file mode 100644 index 0000000000..c2506a5bfd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_ac3_parser.h @@ -0,0 +1,66 @@ +/* + * Common AAC and AC-3 parser prototypes + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AAC_AC3_PARSER_H +#define AVCODEC_AAC_AC3_PARSER_H + +#include +#include "avcodec.h" +#include "parser.h" + +typedef enum { + AAC_AC3_PARSE_ERROR_SYNC = -0x1030c0a, + AAC_AC3_PARSE_ERROR_BSID = -0x2030c0a, + AAC_AC3_PARSE_ERROR_SAMPLE_RATE = -0x3030c0a, + AAC_AC3_PARSE_ERROR_FRAME_SIZE = -0x4030c0a, + AAC_AC3_PARSE_ERROR_FRAME_TYPE = -0x5030c0a, + AAC_AC3_PARSE_ERROR_CRC = -0x6030c0a, + AAC_AC3_PARSE_ERROR_CHANNEL_CFG = -0x7030c0a, +} AACAC3ParseError; + +typedef struct AACAC3ParseContext { + ParseContext pc; + int frame_size; + int header_size; + int (*sync)(uint64_t state, struct AACAC3ParseContext *hdr_info, + int *need_next_header, int *new_frame_start); + + int channels; + int sample_rate; + int bit_rate; + int samples; + uint64_t channel_layout; + int service_type; + + int remaining_size; + uint64_t state; + + int need_next_header; + enum AVCodecID codec_id; +} AACAC3ParseContext; + +int ff_aac_ac3_parse(AVCodecParserContext *s1, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size); + +#endif /* AVCODEC_AAC_AC3_PARSER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_adtstoasc_bsf.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_adtstoasc_bsf.c new file mode 100644 index 0000000000..6541b1189c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_adtstoasc_bsf.c @@ -0,0 +1,158 @@ +/* + * MPEG-2/4 AAC ADTS to MPEG-4 Audio Specific Configuration bitstream filter + * Copyright (c) 2009 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "adts_header.h" +#include "adts_parser.h" +#include "avcodec.h" +#include "bsf.h" +#include "put_bits.h" +#include "get_bits.h" +#include "mpeg4audio.h" +#include "internal.h" + +typedef struct AACBSFContext { + int first_frame_done; +} AACBSFContext; + +/** + * This filter creates an MPEG-4 AudioSpecificConfig from an MPEG-2/4 + * ADTS header and removes the ADTS header. + */ +static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *pkt) +{ + AACBSFContext *ctx = bsfc->priv_data; + + GetBitContext gb; + PutBitContext pb; + AACADTSHeaderInfo hdr; + int ret; + + ret = ff_bsf_get_packet_ref(bsfc, pkt); + if (ret < 0) + return ret; + + if (bsfc->par_in->extradata && pkt->size >= 2 && (AV_RB16(pkt->data) >> 4) != 0xfff) + return 0; + + if (pkt->size < AV_AAC_ADTS_HEADER_SIZE) + goto packet_too_small; + + init_get_bits(&gb, pkt->data, AV_AAC_ADTS_HEADER_SIZE * 8); + + if (ff_adts_header_parse(&gb, &hdr) < 0) { + av_log(bsfc, AV_LOG_ERROR, "Error parsing ADTS frame header!\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + if (!hdr.crc_absent && hdr.num_aac_frames > 1) { + avpriv_report_missing_feature(bsfc, + "Multiple RDBs per frame with CRC"); + ret = AVERROR_PATCHWELCOME; + goto fail; + } + + pkt->size -= AV_AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; + if (pkt->size <= 0) + goto packet_too_small; + pkt->data += AV_AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; + + if (!ctx->first_frame_done) { + int pce_size = 0; + uint8_t pce_data[MAX_PCE_SIZE]; + uint8_t *extradata; + + if (!hdr.chan_config) { + init_get_bits(&gb, pkt->data, pkt->size * 8); + if (get_bits(&gb, 3) != 5) { + avpriv_report_missing_feature(bsfc, + "PCE-based channel configuration " + "without PCE as first syntax " + "element"); + ret = AVERROR_PATCHWELCOME; + goto fail; + } + init_put_bits(&pb, pce_data, MAX_PCE_SIZE); + pce_size = ff_copy_pce_data(&pb, &gb) / 8; + flush_put_bits(&pb); + pkt->size -= get_bits_count(&gb)/8; + pkt->data += get_bits_count(&gb)/8; + } + + extradata = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, + 2 + pce_size); + if (!extradata) { + ret = AVERROR(ENOMEM); + goto fail; + } + + init_put_bits(&pb, extradata, 2 + pce_size); + put_bits(&pb, 5, hdr.object_type); + put_bits(&pb, 4, hdr.sampling_index); + put_bits(&pb, 4, hdr.chan_config); + put_bits(&pb, 1, 0); //frame length - 1024 samples + put_bits(&pb, 1, 0); //does not depend on core coder + put_bits(&pb, 1, 0); //is not extension + flush_put_bits(&pb); + if (pce_size) { + memcpy(extradata + 2, pce_data, pce_size); + } + + ctx->first_frame_done = 1; + } + + return 0; + +packet_too_small: + av_log(bsfc, AV_LOG_ERROR, "Input packet too small\n"); + ret = AVERROR_INVALIDDATA; +fail: + av_packet_unref(pkt); + return ret; +} + +static int aac_adtstoasc_init(AVBSFContext *ctx) +{ + /* Validate the extradata if the stream is already MPEG-4 AudioSpecificConfig */ + if (ctx->par_in->extradata) { + MPEG4AudioConfig mp4ac; + int ret = avpriv_mpeg4audio_get_config(&mp4ac, ctx->par_in->extradata, + ctx->par_in->extradata_size * 8, 1); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error parsing AudioSpecificConfig extradata!\n"); + return ret; + } + } + + return 0; +} + +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_AAC, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_aac_adtstoasc_bsf = { + .name = "aac_adtstoasc", + .priv_data_size = sizeof(AACBSFContext), + .init = aac_adtstoasc_init, + .filter = aac_adtstoasc_filter, + .codec_ids = codec_ids, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_defines.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_defines.h new file mode 100644 index 0000000000..438d78a7aa --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_defines.h @@ -0,0 +1,116 @@ +/* + * AAC defines + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AAC_DEFINES_H +#define AVCODEC_AAC_DEFINES_H + +#ifndef USE_FIXED +#define USE_FIXED 0 +#endif + +#if USE_FIXED + +#include "libavutil/softfloat.h" + +#define FFT_FLOAT 0 +#define FFT_FIXED_32 1 + +#define AAC_RENAME(x) x ## _fixed +#define AAC_RENAME_32(x) x ## _fixed_32 +typedef int INTFLOAT; +typedef unsigned UINTFLOAT; ///< Equivalent to INTFLOAT, Used as temporal cast to avoid undefined sign overflow operations. +typedef int64_t INT64FLOAT; +typedef int16_t SHORTFLOAT; +typedef SoftFloat AAC_FLOAT; +typedef int AAC_SIGNE; +#define FIXR(a) ((int)((a) * 1 + 0.5)) +#define FIXR10(a) ((int)((a) * 1024.0 + 0.5)) +#define Q23(a) (int)((a) * 8388608.0 + 0.5) +#define Q30(x) (int)((x)*1073741824.0 + 0.5) +#define Q31(x) (int)((x)*2147483648.0 + 0.5) +#define RANGE15(x) x +#define GET_GAIN(x, y) (-(y) * (1 << (x))) + 1024 +#define AAC_MUL16(x, y) (int)(((int64_t)(x) * (y) + 0x8000) >> 16) +#define AAC_MUL26(x, y) (int)(((int64_t)(x) * (y) + 0x2000000) >> 26) +#define AAC_MUL30(x, y) (int)(((int64_t)(x) * (y) + 0x20000000) >> 30) +#define AAC_MUL31(x, y) (int)(((int64_t)(x) * (y) + 0x40000000) >> 31) +#define AAC_MADD28(x, y, a, b) (int)((((int64_t)(x) * (y)) + \ + ((int64_t)(a) * (b)) + \ + 0x8000000) >> 28) +#define AAC_MADD30(x, y, a, b) (int)((((int64_t)(x) * (y)) + \ + ((int64_t)(a) * (b)) + \ + 0x20000000) >> 30) +#define AAC_MADD30_V8(x, y, a, b, c, d, e, f) (int)((((int64_t)(x) * (y)) + \ + ((int64_t)(a) * (b)) + \ + ((int64_t)(c) * (d)) + \ + ((int64_t)(e) * (f)) + \ + 0x20000000) >> 30) +#define AAC_MSUB30(x, y, a, b) (int)((((int64_t)(x) * (y)) - \ + ((int64_t)(a) * (b)) + \ + 0x20000000) >> 30) +#define AAC_MSUB30_V8(x, y, a, b, c, d, e, f) (int)((((int64_t)(x) * (y)) + \ + ((int64_t)(a) * (b)) - \ + ((int64_t)(c) * (d)) - \ + ((int64_t)(e) * (f)) + \ + 0x20000000) >> 30) +#define AAC_MSUB31_V3(x, y, z) (int)((((int64_t)(x) * (z)) - \ + ((int64_t)(y) * (z)) + \ + 0x40000000) >> 31) +#define AAC_HALF_SUM(x, y) (((x) >> 1) + ((y) >> 1)) +#define AAC_SRA_R(x, y) (int)(((x) + (1 << ((y) - 1))) >> (y)) + +#else + +#define FFT_FLOAT 1 +#define FFT_FIXED_32 0 + +#define AAC_RENAME(x) x +#define AAC_RENAME_32(x) x +typedef float INTFLOAT; +typedef float UINTFLOAT; +typedef float INT64FLOAT; +typedef float SHORTFLOAT; +typedef float AAC_FLOAT; +typedef unsigned AAC_SIGNE; +#define FIXR(x) ((float)(x)) +#define FIXR10(x) ((float)(x)) +#define Q23(x) ((float)(x)) +#define Q30(x) ((float)(x)) +#define Q31(x) ((float)(x)) +#define RANGE15(x) (32768.0 * (x)) +#define GET_GAIN(x, y) powf((x), -(y)) +#define AAC_MUL16(x, y) ((x) * (y)) +#define AAC_MUL26(x, y) ((x) * (y)) +#define AAC_MUL30(x, y) ((x) * (y)) +#define AAC_MUL31(x, y) ((x) * (y)) +#define AAC_MADD28(x, y, a, b) ((x) * (y) + (a) * (b)) +#define AAC_MADD30(x, y, a, b) ((x) * (y) + (a) * (b)) +#define AAC_MADD30_V8(x, y, a, b, c, d, e, f) ((x) * (y) + (a) * (b) + \ + (c) * (d) + (e) * (f)) +#define AAC_MSUB30(x, y, a, b) ((x) * (y) - (a) * (b)) +#define AAC_MSUB30_V8(x, y, a, b, c, d, e, f) ((x) * (y) + (a) * (b) - \ + (c) * (d) - (e) * (f)) +#define AAC_MSUB31_V3(x, y, z) ((x) - (y)) * (z) +#define AAC_HALF_SUM(x, y) ((x) + (y)) * 0.5f +#define AAC_SRA_R(x, y) (x) + +#endif /* USE_FIXED */ + +#endif /* AVCODEC_AAC_DEFINES_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_parser.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_parser.c new file mode 100644 index 0000000000..b8692625f3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aac_parser.c @@ -0,0 +1,71 @@ +/* + * Audio and Video frame extraction + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "parser.h" +#include "aac_ac3_parser.h" +#include "adts_header.h" +#include "adts_parser.h" +#include "get_bits.h" +#include "mpeg4audio.h" + +static int aac_sync(uint64_t state, AACAC3ParseContext *hdr_info, + int *need_next_header, int *new_frame_start) +{ + GetBitContext bits; + AACADTSHeaderInfo hdr; + int size; + union { + uint64_t u64; + uint8_t u8[8 + AV_INPUT_BUFFER_PADDING_SIZE]; + } tmp; + + tmp.u64 = av_be2ne64(state); + init_get_bits(&bits, tmp.u8 + 8 - AV_AAC_ADTS_HEADER_SIZE, + AV_AAC_ADTS_HEADER_SIZE * 8); + + if ((size = ff_adts_header_parse(&bits, &hdr)) < 0) + return 0; + *need_next_header = 0; + *new_frame_start = 1; + hdr_info->sample_rate = hdr.sample_rate; + hdr_info->channels = ff_mpeg4audio_channels[hdr.chan_config]; + hdr_info->samples = hdr.samples; + hdr_info->bit_rate = hdr.bit_rate; + return size; +} + +static av_cold int aac_parse_init(AVCodecParserContext *s1) +{ + AACAC3ParseContext *s = s1->priv_data; + s->header_size = AV_AAC_ADTS_HEADER_SIZE; + s->sync = aac_sync; + return 0; +} + + +AVCodecParser ff_aac_parser = { + .codec_ids = { AV_CODEC_ID_AAC }, + .priv_data_size = sizeof(AACAC3ParseContext), + .parser_init = aac_parse_init, + .parser_parse = ff_aac_ac3_parse, + .parser_close = ff_parse_close, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder.c new file mode 100644 index 0000000000..baa82489b1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder.c @@ -0,0 +1,964 @@ +/* + * AAC coefficients encoder + * Copyright (C) 2008-2009 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC coefficients encoder + */ + +/*********************************** + * TODOs: + * speedup quantizer selection + * add sane pulse detection + ***********************************/ + +#include "libavutil/libm.h" // brought forward to work around cygwin header breakage + +#include + +#include "libavutil/mathematics.h" +#include "mathops.h" +#include "avcodec.h" +#include "put_bits.h" +#include "aac.h" +#include "aacenc.h" +#include "aactab.h" +#include "aacenctab.h" +#include "aacenc_utils.h" +#include "aacenc_quantization.h" + +#include "aacenc_is.h" +#include "aacenc_tns.h" +#include "aacenc_ltp.h" +#include "aacenc_pred.h" + +#include "libavcodec/aaccoder_twoloop.h" + +/* Parameter of f(x) = a*(lambda/100), defines the maximum fourier spread + * beyond which no PNS is used (since the SFBs contain tone rather than noise) */ +#define NOISE_SPREAD_THRESHOLD 0.9f + +/* Parameter of f(x) = a*(100/lambda), defines how much PNS is allowed to + * replace low energy non zero bands */ +#define NOISE_LAMBDA_REPLACE 1.948f + +#include "libavcodec/aaccoder_trellis.h" + +/** + * structure used in optimal codebook search + */ +typedef struct BandCodingPath { + int prev_idx; ///< pointer to the previous path point + float cost; ///< path cost + int run; +} BandCodingPath; + +/** + * Encode band info for single window group bands. + */ +static void encode_window_bands_info(AACEncContext *s, SingleChannelElement *sce, + int win, int group_len, const float lambda) +{ + BandCodingPath path[120][CB_TOT_ALL]; + int w, swb, cb, start, size; + int i, j; + const int max_sfb = sce->ics.max_sfb; + const int run_bits = sce->ics.num_windows == 1 ? 5 : 3; + const int run_esc = (1 << run_bits) - 1; + int idx, ppos, count; + int stackrun[120], stackcb[120], stack_len; + float next_minrd = INFINITY; + int next_mincb = 0; + + s->abs_pow34(s->scoefs, sce->coeffs, 1024); + start = win*128; + for (cb = 0; cb < CB_TOT_ALL; cb++) { + path[0][cb].cost = 0.0f; + path[0][cb].prev_idx = -1; + path[0][cb].run = 0; + } + for (swb = 0; swb < max_sfb; swb++) { + size = sce->ics.swb_sizes[swb]; + if (sce->zeroes[win*16 + swb]) { + for (cb = 0; cb < CB_TOT_ALL; cb++) { + path[swb+1][cb].prev_idx = cb; + path[swb+1][cb].cost = path[swb][cb].cost; + path[swb+1][cb].run = path[swb][cb].run + 1; + } + } else { + float minrd = next_minrd; + int mincb = next_mincb; + next_minrd = INFINITY; + next_mincb = 0; + for (cb = 0; cb < CB_TOT_ALL; cb++) { + float cost_stay_here, cost_get_here; + float rd = 0.0f; + if (cb >= 12 && sce->band_type[win*16+swb] < aac_cb_out_map[cb] || + cb < aac_cb_in_map[sce->band_type[win*16+swb]] && sce->band_type[win*16+swb] > aac_cb_out_map[cb]) { + path[swb+1][cb].prev_idx = -1; + path[swb+1][cb].cost = INFINITY; + path[swb+1][cb].run = path[swb][cb].run + 1; + continue; + } + for (w = 0; w < group_len; w++) { + FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(win+w)*16+swb]; + rd += quantize_band_cost(s, &sce->coeffs[start + w*128], + &s->scoefs[start + w*128], size, + sce->sf_idx[(win+w)*16+swb], aac_cb_out_map[cb], + lambda / band->threshold, INFINITY, NULL, NULL, 0); + } + cost_stay_here = path[swb][cb].cost + rd; + cost_get_here = minrd + rd + run_bits + 4; + if ( run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run] + != run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run+1]) + cost_stay_here += run_bits; + if (cost_get_here < cost_stay_here) { + path[swb+1][cb].prev_idx = mincb; + path[swb+1][cb].cost = cost_get_here; + path[swb+1][cb].run = 1; + } else { + path[swb+1][cb].prev_idx = cb; + path[swb+1][cb].cost = cost_stay_here; + path[swb+1][cb].run = path[swb][cb].run + 1; + } + if (path[swb+1][cb].cost < next_minrd) { + next_minrd = path[swb+1][cb].cost; + next_mincb = cb; + } + } + } + start += sce->ics.swb_sizes[swb]; + } + + //convert resulting path from backward-linked list + stack_len = 0; + idx = 0; + for (cb = 1; cb < CB_TOT_ALL; cb++) + if (path[max_sfb][cb].cost < path[max_sfb][idx].cost) + idx = cb; + ppos = max_sfb; + while (ppos > 0) { + av_assert1(idx >= 0); + cb = idx; + stackrun[stack_len] = path[ppos][cb].run; + stackcb [stack_len] = cb; + idx = path[ppos-path[ppos][cb].run+1][cb].prev_idx; + ppos -= path[ppos][cb].run; + stack_len++; + } + //perform actual band info encoding + start = 0; + for (i = stack_len - 1; i >= 0; i--) { + cb = aac_cb_out_map[stackcb[i]]; + put_bits(&s->pb, 4, cb); + count = stackrun[i]; + memset(sce->zeroes + win*16 + start, !cb, count); + //XXX: memset when band_type is also uint8_t + for (j = 0; j < count; j++) { + sce->band_type[win*16 + start] = cb; + start++; + } + while (count >= run_esc) { + put_bits(&s->pb, run_bits, run_esc); + count -= run_esc; + } + put_bits(&s->pb, run_bits, count); + } +} + + +typedef struct TrellisPath { + float cost; + int prev; +} TrellisPath; + +#define TRELLIS_STAGES 121 +#define TRELLIS_STATES (SCALE_MAX_DIFF+1) + +static void set_special_band_scalefactors(AACEncContext *s, SingleChannelElement *sce) +{ + int w, g; + int prevscaler_n = -255, prevscaler_i = 0; + int bands = 0; + + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = 0; g < sce->ics.num_swb; g++) { + if (sce->zeroes[w*16+g]) + continue; + if (sce->band_type[w*16+g] == INTENSITY_BT || sce->band_type[w*16+g] == INTENSITY_BT2) { + sce->sf_idx[w*16+g] = av_clip(roundf(log2f(sce->is_ener[w*16+g])*2), -155, 100); + bands++; + } else if (sce->band_type[w*16+g] == NOISE_BT) { + sce->sf_idx[w*16+g] = av_clip(3+ceilf(log2f(sce->pns_ener[w*16+g])*2), -100, 155); + if (prevscaler_n == -255) + prevscaler_n = sce->sf_idx[w*16+g]; + bands++; + } + } + } + + if (!bands) + return; + + /* Clip the scalefactor indices */ + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = 0; g < sce->ics.num_swb; g++) { + if (sce->zeroes[w*16+g]) + continue; + if (sce->band_type[w*16+g] == INTENSITY_BT || sce->band_type[w*16+g] == INTENSITY_BT2) { + sce->sf_idx[w*16+g] = prevscaler_i = av_clip(sce->sf_idx[w*16+g], prevscaler_i - SCALE_MAX_DIFF, prevscaler_i + SCALE_MAX_DIFF); + } else if (sce->band_type[w*16+g] == NOISE_BT) { + sce->sf_idx[w*16+g] = prevscaler_n = av_clip(sce->sf_idx[w*16+g], prevscaler_n - SCALE_MAX_DIFF, prevscaler_n + SCALE_MAX_DIFF); + } + } + } +} + +static void search_for_quantizers_anmr(AVCodecContext *avctx, AACEncContext *s, + SingleChannelElement *sce, + const float lambda) +{ + int q, w, w2, g, start = 0; + int i, j; + int idx; + TrellisPath paths[TRELLIS_STAGES][TRELLIS_STATES]; + int bandaddr[TRELLIS_STAGES]; + int minq; + float mincost; + float q0f = FLT_MAX, q1f = 0.0f, qnrgf = 0.0f; + int q0, q1, qcnt = 0; + + for (i = 0; i < 1024; i++) { + float t = fabsf(sce->coeffs[i]); + if (t > 0.0f) { + q0f = FFMIN(q0f, t); + q1f = FFMAX(q1f, t); + qnrgf += t*t; + qcnt++; + } + } + + if (!qcnt) { + memset(sce->sf_idx, 0, sizeof(sce->sf_idx)); + memset(sce->zeroes, 1, sizeof(sce->zeroes)); + return; + } + + //minimum scalefactor index is when minimum nonzero coefficient after quantizing is not clipped + q0 = av_clip(coef2minsf(q0f), 0, SCALE_MAX_POS-1); + //maximum scalefactor index is when maximum coefficient after quantizing is still not zero + q1 = av_clip(coef2maxsf(q1f), 1, SCALE_MAX_POS); + if (q1 - q0 > 60) { + int q0low = q0; + int q1high = q1; + //minimum scalefactor index is when maximum nonzero coefficient after quantizing is not clipped + int qnrg = av_clip_uint8(log2f(sqrtf(qnrgf/qcnt))*4 - 31 + SCALE_ONE_POS - SCALE_DIV_512); + q1 = qnrg + 30; + q0 = qnrg - 30; + if (q0 < q0low) { + q1 += q0low - q0; + q0 = q0low; + } else if (q1 > q1high) { + q0 -= q1 - q1high; + q1 = q1high; + } + } + // q0 == q1 isn't really a legal situation + if (q0 == q1) { + // the following is indirect but guarantees q1 != q0 && q1 near q0 + q1 = av_clip(q0+1, 1, SCALE_MAX_POS); + q0 = av_clip(q1-1, 0, SCALE_MAX_POS - 1); + } + + for (i = 0; i < TRELLIS_STATES; i++) { + paths[0][i].cost = 0.0f; + paths[0][i].prev = -1; + } + for (j = 1; j < TRELLIS_STAGES; j++) { + for (i = 0; i < TRELLIS_STATES; i++) { + paths[j][i].cost = INFINITY; + paths[j][i].prev = -2; + } + } + idx = 1; + s->abs_pow34(s->scoefs, sce->coeffs, 1024); + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + start = w*128; + for (g = 0; g < sce->ics.num_swb; g++) { + const float *coefs = &sce->coeffs[start]; + float qmin, qmax; + int nz = 0; + + bandaddr[idx] = w * 16 + g; + qmin = INT_MAX; + qmax = 0.0f; + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; + if (band->energy <= band->threshold || band->threshold == 0.0f) { + sce->zeroes[(w+w2)*16+g] = 1; + continue; + } + sce->zeroes[(w+w2)*16+g] = 0; + nz = 1; + for (i = 0; i < sce->ics.swb_sizes[g]; i++) { + float t = fabsf(coefs[w2*128+i]); + if (t > 0.0f) + qmin = FFMIN(qmin, t); + qmax = FFMAX(qmax, t); + } + } + if (nz) { + int minscale, maxscale; + float minrd = INFINITY; + float maxval; + //minimum scalefactor index is when minimum nonzero coefficient after quantizing is not clipped + minscale = coef2minsf(qmin); + //maximum scalefactor index is when maximum coefficient after quantizing is still not zero + maxscale = coef2maxsf(qmax); + minscale = av_clip(minscale - q0, 0, TRELLIS_STATES - 1); + maxscale = av_clip(maxscale - q0, 0, TRELLIS_STATES); + if (minscale == maxscale) { + maxscale = av_clip(minscale+1, 1, TRELLIS_STATES); + minscale = av_clip(maxscale-1, 0, TRELLIS_STATES - 1); + } + maxval = find_max_val(sce->ics.group_len[w], sce->ics.swb_sizes[g], s->scoefs+start); + for (q = minscale; q < maxscale; q++) { + float dist = 0; + int cb = find_min_book(maxval, sce->sf_idx[w*16+g]); + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; + dist += quantize_band_cost(s, coefs + w2*128, s->scoefs + start + w2*128, sce->ics.swb_sizes[g], + q + q0, cb, lambda / band->threshold, INFINITY, NULL, NULL, 0); + } + minrd = FFMIN(minrd, dist); + + for (i = 0; i < q1 - q0; i++) { + float cost; + cost = paths[idx - 1][i].cost + dist + + ff_aac_scalefactor_bits[q - i + SCALE_DIFF_ZERO]; + if (cost < paths[idx][q].cost) { + paths[idx][q].cost = cost; + paths[idx][q].prev = i; + } + } + } + } else { + for (q = 0; q < q1 - q0; q++) { + paths[idx][q].cost = paths[idx - 1][q].cost + 1; + paths[idx][q].prev = q; + } + } + sce->zeroes[w*16+g] = !nz; + start += sce->ics.swb_sizes[g]; + idx++; + } + } + idx--; + mincost = paths[idx][0].cost; + minq = 0; + for (i = 1; i < TRELLIS_STATES; i++) { + if (paths[idx][i].cost < mincost) { + mincost = paths[idx][i].cost; + minq = i; + } + } + while (idx) { + sce->sf_idx[bandaddr[idx]] = minq + q0; + minq = FFMAX(paths[idx][minq].prev, 0); + idx--; + } + //set the same quantizers inside window groups + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) + for (g = 0; g < sce->ics.num_swb; g++) + for (w2 = 1; w2 < sce->ics.group_len[w]; w2++) + sce->sf_idx[(w+w2)*16+g] = sce->sf_idx[w*16+g]; +} + +static void search_for_quantizers_fast(AVCodecContext *avctx, AACEncContext *s, + SingleChannelElement *sce, + const float lambda) +{ + int start = 0, i, w, w2, g; + int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate / avctx->channels * (lambda / 120.f); + float dists[128] = { 0 }, uplims[128] = { 0 }; + float maxvals[128]; + int fflag, minscaler; + int its = 0; + int allz = 0; + float minthr = INFINITY; + + // for values above this the decoder might end up in an endless loop + // due to always having more bits than what can be encoded. + destbits = FFMIN(destbits, 5800); + //some heuristic to determine initial quantizers will reduce search time + //determine zero bands and upper limits + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + start = 0; + for (g = 0; g < sce->ics.num_swb; g++) { + int nz = 0; + float uplim = 0.0f, energy = 0.0f; + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; + uplim += band->threshold; + energy += band->energy; + if (band->energy <= band->threshold || band->threshold == 0.0f) { + sce->zeroes[(w+w2)*16+g] = 1; + continue; + } + nz = 1; + } + uplims[w*16+g] = uplim *512; + sce->band_type[w*16+g] = 0; + sce->zeroes[w*16+g] = !nz; + if (nz) + minthr = FFMIN(minthr, uplim); + allz |= nz; + start += sce->ics.swb_sizes[g]; + } + } + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = 0; g < sce->ics.num_swb; g++) { + if (sce->zeroes[w*16+g]) { + sce->sf_idx[w*16+g] = SCALE_ONE_POS; + continue; + } + sce->sf_idx[w*16+g] = SCALE_ONE_POS + FFMIN(log2f(uplims[w*16+g]/minthr)*4,59); + } + } + + if (!allz) + return; + s->abs_pow34(s->scoefs, sce->coeffs, 1024); + ff_quantize_band_cost_cache_init(s); + + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + start = w*128; + for (g = 0; g < sce->ics.num_swb; g++) { + const float *scaled = s->scoefs + start; + maxvals[w*16+g] = find_max_val(sce->ics.group_len[w], sce->ics.swb_sizes[g], scaled); + start += sce->ics.swb_sizes[g]; + } + } + + //perform two-loop search + //outer loop - improve quality + do { + int tbits, qstep; + minscaler = sce->sf_idx[0]; + //inner loop - quantize spectrum to fit into given number of bits + qstep = its ? 1 : 32; + do { + int prev = -1; + tbits = 0; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + start = w*128; + for (g = 0; g < sce->ics.num_swb; g++) { + const float *coefs = sce->coeffs + start; + const float *scaled = s->scoefs + start; + int bits = 0; + int cb; + float dist = 0.0f; + + if (sce->zeroes[w*16+g] || sce->sf_idx[w*16+g] >= 218) { + start += sce->ics.swb_sizes[g]; + continue; + } + minscaler = FFMIN(minscaler, sce->sf_idx[w*16+g]); + cb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]); + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + int b; + dist += quantize_band_cost_cached(s, w + w2, g, + coefs + w2*128, + scaled + w2*128, + sce->ics.swb_sizes[g], + sce->sf_idx[w*16+g], + cb, 1.0f, INFINITY, + &b, NULL, 0); + bits += b; + } + dists[w*16+g] = dist - bits; + if (prev != -1) { + bits += ff_aac_scalefactor_bits[sce->sf_idx[w*16+g] - prev + SCALE_DIFF_ZERO]; + } + tbits += bits; + start += sce->ics.swb_sizes[g]; + prev = sce->sf_idx[w*16+g]; + } + } + if (tbits > destbits) { + for (i = 0; i < 128; i++) + if (sce->sf_idx[i] < 218 - qstep) + sce->sf_idx[i] += qstep; + } else { + for (i = 0; i < 128; i++) + if (sce->sf_idx[i] > 60 - qstep) + sce->sf_idx[i] -= qstep; + } + qstep >>= 1; + if (!qstep && tbits > destbits*1.02 && sce->sf_idx[0] < 217) + qstep = 1; + } while (qstep); + + fflag = 0; + minscaler = av_clip(minscaler, 60, 255 - SCALE_MAX_DIFF); + + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = 0; g < sce->ics.num_swb; g++) { + int prevsc = sce->sf_idx[w*16+g]; + if (dists[w*16+g] > uplims[w*16+g] && sce->sf_idx[w*16+g] > 60) { + if (find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]-1)) + sce->sf_idx[w*16+g]--; + else //Try to make sure there is some energy in every band + sce->sf_idx[w*16+g]-=2; + } + sce->sf_idx[w*16+g] = av_clip(sce->sf_idx[w*16+g], minscaler, minscaler + SCALE_MAX_DIFF); + sce->sf_idx[w*16+g] = FFMIN(sce->sf_idx[w*16+g], 219); + if (sce->sf_idx[w*16+g] != prevsc) + fflag = 1; + sce->band_type[w*16+g] = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]); + } + } + its++; + } while (fflag && its < 10); +} + +static void search_for_pns(AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce) +{ + FFPsyBand *band; + int w, g, w2, i; + int wlen = 1024 / sce->ics.num_windows; + int bandwidth, cutoff; + float *PNS = &s->scoefs[0*128], *PNS34 = &s->scoefs[1*128]; + float *NOR34 = &s->scoefs[3*128]; + uint8_t nextband[128]; + const float lambda = s->lambda; + const float freq_mult = avctx->sample_rate*0.5f/wlen; + const float thr_mult = NOISE_LAMBDA_REPLACE*(100.0f/lambda); + const float spread_threshold = FFMIN(0.75f, NOISE_SPREAD_THRESHOLD*FFMAX(0.5f, lambda/100.f)); + const float dist_bias = av_clipf(4.f * 120 / lambda, 0.25f, 4.0f); + const float pns_transient_energy_r = FFMIN(0.7f, lambda / 140.f); + + int refbits = avctx->bit_rate * 1024.0 / avctx->sample_rate + / ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->channels) + * (lambda / 120.f); + + /** Keep this in sync with twoloop's cutoff selection */ + float rate_bandwidth_multiplier = 1.5f; + int prev = -1000, prev_sf = -1; + int frame_bit_rate = (avctx->flags & AV_CODEC_FLAG_QSCALE) + ? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024) + : (avctx->bit_rate / avctx->channels); + + frame_bit_rate *= 1.15f; + + if (avctx->cutoff > 0) { + bandwidth = avctx->cutoff; + } else { + bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_bit_rate, 1, avctx->sample_rate)); + } + + cutoff = bandwidth * 2 * wlen / avctx->sample_rate; + + memcpy(sce->band_alt, sce->band_type, sizeof(sce->band_type)); + ff_init_nextband_map(sce, nextband); + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + int wstart = w*128; + for (g = 0; g < sce->ics.num_swb; g++) { + int noise_sfi; + float dist1 = 0.0f, dist2 = 0.0f, noise_amp; + float pns_energy = 0.0f, pns_tgt_energy, energy_ratio, dist_thresh; + float sfb_energy = 0.0f, threshold = 0.0f, spread = 2.0f; + float min_energy = -1.0f, max_energy = 0.0f; + const int start = wstart+sce->ics.swb_offset[g]; + const float freq = (start-wstart)*freq_mult; + const float freq_boost = FFMAX(0.88f*freq/NOISE_LOW_LIMIT, 1.0f); + if (freq < NOISE_LOW_LIMIT || (start-wstart) >= cutoff) { + if (!sce->zeroes[w*16+g]) + prev_sf = sce->sf_idx[w*16+g]; + continue; + } + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; + sfb_energy += band->energy; + spread = FFMIN(spread, band->spread); + threshold += band->threshold; + if (!w2) { + min_energy = max_energy = band->energy; + } else { + min_energy = FFMIN(min_energy, band->energy); + max_energy = FFMAX(max_energy, band->energy); + } + } + + /* Ramps down at ~8000Hz and loosens the dist threshold */ + dist_thresh = av_clipf(2.5f*NOISE_LOW_LIMIT/freq, 0.5f, 2.5f) * dist_bias; + + /* PNS is acceptable when all of these are true: + * 1. high spread energy (noise-like band) + * 2. near-threshold energy (high PE means the random nature of PNS content will be noticed) + * 3. on short window groups, all windows have similar energy (variations in energy would be destroyed by PNS) + * + * At this stage, point 2 is relaxed for zeroed bands near the noise threshold (hole avoidance is more important) + */ + if ((!sce->zeroes[w*16+g] && !ff_sfdelta_can_remove_band(sce, nextband, prev_sf, w*16+g)) || + ((sce->zeroes[w*16+g] || !sce->band_alt[w*16+g]) && sfb_energy < threshold*sqrtf(1.0f/freq_boost)) || spread < spread_threshold || + (!sce->zeroes[w*16+g] && sce->band_alt[w*16+g] && sfb_energy > threshold*thr_mult*freq_boost) || + min_energy < pns_transient_energy_r * max_energy ) { + sce->pns_ener[w*16+g] = sfb_energy; + if (!sce->zeroes[w*16+g]) + prev_sf = sce->sf_idx[w*16+g]; + continue; + } + + pns_tgt_energy = sfb_energy*FFMIN(1.0f, spread*spread); + noise_sfi = av_clip(roundf(log2f(pns_tgt_energy)*2), -100, 155); /* Quantize */ + noise_amp = -ff_aac_pow2sf_tab[noise_sfi + POW_SF2_ZERO]; /* Dequantize */ + if (prev != -1000) { + int noise_sfdiff = noise_sfi - prev + SCALE_DIFF_ZERO; + if (noise_sfdiff < 0 || noise_sfdiff > 2*SCALE_MAX_DIFF) { + if (!sce->zeroes[w*16+g]) + prev_sf = sce->sf_idx[w*16+g]; + continue; + } + } + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + float band_energy, scale, pns_senergy; + const int start_c = (w+w2)*128+sce->ics.swb_offset[g]; + band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; + for (i = 0; i < sce->ics.swb_sizes[g]; i++) { + s->random_state = lcg_random(s->random_state); + PNS[i] = s->random_state; + } + band_energy = s->fdsp->scalarproduct_float(PNS, PNS, sce->ics.swb_sizes[g]); + scale = noise_amp/sqrtf(band_energy); + s->fdsp->vector_fmul_scalar(PNS, PNS, scale, sce->ics.swb_sizes[g]); + pns_senergy = s->fdsp->scalarproduct_float(PNS, PNS, sce->ics.swb_sizes[g]); + pns_energy += pns_senergy; + s->abs_pow34(NOR34, &sce->coeffs[start_c], sce->ics.swb_sizes[g]); + s->abs_pow34(PNS34, PNS, sce->ics.swb_sizes[g]); + dist1 += quantize_band_cost(s, &sce->coeffs[start_c], + NOR34, + sce->ics.swb_sizes[g], + sce->sf_idx[(w+w2)*16+g], + sce->band_alt[(w+w2)*16+g], + lambda/band->threshold, INFINITY, NULL, NULL, 0); + /* Estimate rd on average as 5 bits for SF, 4 for the CB, plus spread energy * lambda/thr */ + dist2 += band->energy/(band->spread*band->spread)*lambda*dist_thresh/band->threshold; + } + if (g && sce->band_type[w*16+g-1] == NOISE_BT) { + dist2 += 5; + } else { + dist2 += 9; + } + energy_ratio = pns_tgt_energy/pns_energy; /* Compensates for quantization error */ + sce->pns_ener[w*16+g] = energy_ratio*pns_tgt_energy; + if (sce->zeroes[w*16+g] || !sce->band_alt[w*16+g] || (energy_ratio > 0.85f && energy_ratio < 1.25f && dist2 < dist1)) { + sce->band_type[w*16+g] = NOISE_BT; + sce->zeroes[w*16+g] = 0; + prev = noise_sfi; + } else { + if (!sce->zeroes[w*16+g]) + prev_sf = sce->sf_idx[w*16+g]; + } + } + } +} + +static void mark_pns(AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce) +{ + FFPsyBand *band; + int w, g, w2; + int wlen = 1024 / sce->ics.num_windows; + int bandwidth, cutoff; + const float lambda = s->lambda; + const float freq_mult = avctx->sample_rate*0.5f/wlen; + const float spread_threshold = FFMIN(0.75f, NOISE_SPREAD_THRESHOLD*FFMAX(0.5f, lambda/100.f)); + const float pns_transient_energy_r = FFMIN(0.7f, lambda / 140.f); + + int refbits = avctx->bit_rate * 1024.0 / avctx->sample_rate + / ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->channels) + * (lambda / 120.f); + + /** Keep this in sync with twoloop's cutoff selection */ + float rate_bandwidth_multiplier = 1.5f; + int frame_bit_rate = (avctx->flags & AV_CODEC_FLAG_QSCALE) + ? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024) + : (avctx->bit_rate / avctx->channels); + + frame_bit_rate *= 1.15f; + + if (avctx->cutoff > 0) { + bandwidth = avctx->cutoff; + } else { + bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_bit_rate, 1, avctx->sample_rate)); + } + + cutoff = bandwidth * 2 * wlen / avctx->sample_rate; + + memcpy(sce->band_alt, sce->band_type, sizeof(sce->band_type)); + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = 0; g < sce->ics.num_swb; g++) { + float sfb_energy = 0.0f, threshold = 0.0f, spread = 2.0f; + float min_energy = -1.0f, max_energy = 0.0f; + const int start = sce->ics.swb_offset[g]; + const float freq = start*freq_mult; + const float freq_boost = FFMAX(0.88f*freq/NOISE_LOW_LIMIT, 1.0f); + if (freq < NOISE_LOW_LIMIT || start >= cutoff) { + sce->can_pns[w*16+g] = 0; + continue; + } + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; + sfb_energy += band->energy; + spread = FFMIN(spread, band->spread); + threshold += band->threshold; + if (!w2) { + min_energy = max_energy = band->energy; + } else { + min_energy = FFMIN(min_energy, band->energy); + max_energy = FFMAX(max_energy, band->energy); + } + } + + /* PNS is acceptable when all of these are true: + * 1. high spread energy (noise-like band) + * 2. near-threshold energy (high PE means the random nature of PNS content will be noticed) + * 3. on short window groups, all windows have similar energy (variations in energy would be destroyed by PNS) + */ + sce->pns_ener[w*16+g] = sfb_energy; + if (sfb_energy < threshold*sqrtf(1.5f/freq_boost) || spread < spread_threshold || min_energy < pns_transient_energy_r * max_energy) { + sce->can_pns[w*16+g] = 0; + } else { + sce->can_pns[w*16+g] = 1; + } + } + } +} + +static void search_for_ms(AACEncContext *s, ChannelElement *cpe) +{ + int start = 0, i, w, w2, g, sid_sf_boost, prev_mid, prev_side; + uint8_t nextband0[128], nextband1[128]; + float *M = s->scoefs + 128*0, *S = s->scoefs + 128*1; + float *L34 = s->scoefs + 128*2, *R34 = s->scoefs + 128*3; + float *M34 = s->scoefs + 128*4, *S34 = s->scoefs + 128*5; + const float lambda = s->lambda; + const float mslambda = FFMIN(1.0f, lambda / 120.f); + SingleChannelElement *sce0 = &cpe->ch[0]; + SingleChannelElement *sce1 = &cpe->ch[1]; + if (!cpe->common_window) + return; + + /** Scout out next nonzero bands */ + ff_init_nextband_map(sce0, nextband0); + ff_init_nextband_map(sce1, nextband1); + + prev_mid = sce0->sf_idx[0]; + prev_side = sce1->sf_idx[0]; + for (w = 0; w < sce0->ics.num_windows; w += sce0->ics.group_len[w]) { + start = 0; + for (g = 0; g < sce0->ics.num_swb; g++) { + float bmax = bval2bmax(g * 17.0f / sce0->ics.num_swb) / 0.0045f; + if (!cpe->is_mask[w*16+g]) + cpe->ms_mask[w*16+g] = 0; + if (!sce0->zeroes[w*16+g] && !sce1->zeroes[w*16+g] && !cpe->is_mask[w*16+g]) { + float Mmax = 0.0f, Smax = 0.0f; + + /* Must compute mid/side SF and book for the whole window group */ + for (w2 = 0; w2 < sce0->ics.group_len[w]; w2++) { + for (i = 0; i < sce0->ics.swb_sizes[g]; i++) { + M[i] = (sce0->coeffs[start+(w+w2)*128+i] + + sce1->coeffs[start+(w+w2)*128+i]) * 0.5; + S[i] = M[i] + - sce1->coeffs[start+(w+w2)*128+i]; + } + s->abs_pow34(M34, M, sce0->ics.swb_sizes[g]); + s->abs_pow34(S34, S, sce0->ics.swb_sizes[g]); + for (i = 0; i < sce0->ics.swb_sizes[g]; i++ ) { + Mmax = FFMAX(Mmax, M34[i]); + Smax = FFMAX(Smax, S34[i]); + } + } + + for (sid_sf_boost = 0; sid_sf_boost < 4; sid_sf_boost++) { + float dist1 = 0.0f, dist2 = 0.0f; + int B0 = 0, B1 = 0; + int minidx; + int mididx, sididx; + int midcb, sidcb; + + minidx = FFMIN(sce0->sf_idx[w*16+g], sce1->sf_idx[w*16+g]); + mididx = av_clip(minidx, 0, SCALE_MAX_POS - SCALE_DIV_512); + sididx = av_clip(minidx - sid_sf_boost * 3, 0, SCALE_MAX_POS - SCALE_DIV_512); + if (sce0->band_type[w*16+g] != NOISE_BT && sce1->band_type[w*16+g] != NOISE_BT + && ( !ff_sfdelta_can_replace(sce0, nextband0, prev_mid, mididx, w*16+g) + || !ff_sfdelta_can_replace(sce1, nextband1, prev_side, sididx, w*16+g))) { + /* scalefactor range violation, bad stuff, will decrease quality unacceptably */ + continue; + } + + midcb = find_min_book(Mmax, mididx); + sidcb = find_min_book(Smax, sididx); + + /* No CB can be zero */ + midcb = FFMAX(1,midcb); + sidcb = FFMAX(1,sidcb); + + for (w2 = 0; w2 < sce0->ics.group_len[w]; w2++) { + FFPsyBand *band0 = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g]; + FFPsyBand *band1 = &s->psy.ch[s->cur_channel+1].psy_bands[(w+w2)*16+g]; + float minthr = FFMIN(band0->threshold, band1->threshold); + int b1,b2,b3,b4; + for (i = 0; i < sce0->ics.swb_sizes[g]; i++) { + M[i] = (sce0->coeffs[start+(w+w2)*128+i] + + sce1->coeffs[start+(w+w2)*128+i]) * 0.5; + S[i] = M[i] + - sce1->coeffs[start+(w+w2)*128+i]; + } + + s->abs_pow34(L34, sce0->coeffs+start+(w+w2)*128, sce0->ics.swb_sizes[g]); + s->abs_pow34(R34, sce1->coeffs+start+(w+w2)*128, sce0->ics.swb_sizes[g]); + s->abs_pow34(M34, M, sce0->ics.swb_sizes[g]); + s->abs_pow34(S34, S, sce0->ics.swb_sizes[g]); + dist1 += quantize_band_cost(s, &sce0->coeffs[start + (w+w2)*128], + L34, + sce0->ics.swb_sizes[g], + sce0->sf_idx[w*16+g], + sce0->band_type[w*16+g], + lambda / band0->threshold, INFINITY, &b1, NULL, 0); + dist1 += quantize_band_cost(s, &sce1->coeffs[start + (w+w2)*128], + R34, + sce1->ics.swb_sizes[g], + sce1->sf_idx[w*16+g], + sce1->band_type[w*16+g], + lambda / band1->threshold, INFINITY, &b2, NULL, 0); + dist2 += quantize_band_cost(s, M, + M34, + sce0->ics.swb_sizes[g], + mididx, + midcb, + lambda / minthr, INFINITY, &b3, NULL, 0); + dist2 += quantize_band_cost(s, S, + S34, + sce1->ics.swb_sizes[g], + sididx, + sidcb, + mslambda / (minthr * bmax), INFINITY, &b4, NULL, 0); + B0 += b1+b2; + B1 += b3+b4; + dist1 -= b1+b2; + dist2 -= b3+b4; + } + cpe->ms_mask[w*16+g] = dist2 <= dist1 && B1 < B0; + if (cpe->ms_mask[w*16+g]) { + if (sce0->band_type[w*16+g] != NOISE_BT && sce1->band_type[w*16+g] != NOISE_BT) { + sce0->sf_idx[w*16+g] = mididx; + sce1->sf_idx[w*16+g] = sididx; + sce0->band_type[w*16+g] = midcb; + sce1->band_type[w*16+g] = sidcb; + } else if ((sce0->band_type[w*16+g] != NOISE_BT) ^ (sce1->band_type[w*16+g] != NOISE_BT)) { + /* ms_mask unneeded, and it confuses some decoders */ + cpe->ms_mask[w*16+g] = 0; + } + break; + } else if (B1 > B0) { + /* More boost won't fix this */ + break; + } + } + } + if (!sce0->zeroes[w*16+g] && sce0->band_type[w*16+g] < RESERVED_BT) + prev_mid = sce0->sf_idx[w*16+g]; + if (!sce1->zeroes[w*16+g] && !cpe->is_mask[w*16+g] && sce1->band_type[w*16+g] < RESERVED_BT) + prev_side = sce1->sf_idx[w*16+g]; + start += sce0->ics.swb_sizes[g]; + } + } +} + +const AACCoefficientsEncoder ff_aac_coders[AAC_CODER_NB] = { + [AAC_CODER_ANMR] = { + search_for_quantizers_anmr, + encode_window_bands_info, + quantize_and_encode_band, + ff_aac_encode_tns_info, + ff_aac_encode_ltp_info, + ff_aac_encode_main_pred, + ff_aac_adjust_common_pred, + ff_aac_adjust_common_ltp, + ff_aac_apply_main_pred, + ff_aac_apply_tns, + ff_aac_update_ltp, + ff_aac_ltp_insert_new_frame, + set_special_band_scalefactors, + search_for_pns, + mark_pns, + ff_aac_search_for_tns, + ff_aac_search_for_ltp, + search_for_ms, + ff_aac_search_for_is, + ff_aac_search_for_pred, + }, + [AAC_CODER_TWOLOOP] = { + search_for_quantizers_twoloop, + codebook_trellis_rate, + quantize_and_encode_band, + ff_aac_encode_tns_info, + ff_aac_encode_ltp_info, + ff_aac_encode_main_pred, + ff_aac_adjust_common_pred, + ff_aac_adjust_common_ltp, + ff_aac_apply_main_pred, + ff_aac_apply_tns, + ff_aac_update_ltp, + ff_aac_ltp_insert_new_frame, + set_special_band_scalefactors, + search_for_pns, + mark_pns, + ff_aac_search_for_tns, + ff_aac_search_for_ltp, + search_for_ms, + ff_aac_search_for_is, + ff_aac_search_for_pred, + }, + [AAC_CODER_FAST] = { + search_for_quantizers_fast, + codebook_trellis_rate, + quantize_and_encode_band, + ff_aac_encode_tns_info, + ff_aac_encode_ltp_info, + ff_aac_encode_main_pred, + ff_aac_adjust_common_pred, + ff_aac_adjust_common_ltp, + ff_aac_apply_main_pred, + ff_aac_apply_tns, + ff_aac_update_ltp, + ff_aac_ltp_insert_new_frame, + set_special_band_scalefactors, + search_for_pns, + mark_pns, + ff_aac_search_for_tns, + ff_aac_search_for_ltp, + search_for_ms, + ff_aac_search_for_is, + ff_aac_search_for_pred, + }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder_trellis.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder_trellis.h new file mode 100644 index 0000000000..940ebf029d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder_trellis.h @@ -0,0 +1,192 @@ +/* + * AAC encoder trellis codebook selector + * Copyright (C) 2008-2009 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder trellis codebook selector + * @author Konstantin Shishkov + */ + +/** + * This file contains a template for the codebook_trellis_rate selector function. + * It needs to be provided, externally, as an already included declaration, + * the following functions from aacenc_quantization/util.h. They're not included + * explicitly here to make it possible to provide alternative implementations: + * - quantize_band_cost_bits + * - abs_pow34_v + */ + +#ifndef AVCODEC_AACCODER_TRELLIS_H +#define AVCODEC_AACCODER_TRELLIS_H + +#include +#include "libavutil/mathematics.h" +#include "avcodec.h" +#include "put_bits.h" +#include "aac.h" +#include "aacenc.h" +#include "aactab.h" +#include "aacenctab.h" + +/** + * structure used in optimal codebook search + */ +typedef struct TrellisBandCodingPath { + int prev_idx; ///< pointer to the previous path point + float cost; ///< path cost + int run; +} TrellisBandCodingPath; + + +static void codebook_trellis_rate(AACEncContext *s, SingleChannelElement *sce, + int win, int group_len, const float lambda) +{ + TrellisBandCodingPath path[120][CB_TOT_ALL]; + int w, swb, cb, start, size; + int i, j; + const int max_sfb = sce->ics.max_sfb; + const int run_bits = sce->ics.num_windows == 1 ? 5 : 3; + const int run_esc = (1 << run_bits) - 1; + int idx, ppos, count; + int stackrun[120], stackcb[120], stack_len; + float next_minbits = INFINITY; + int next_mincb = 0; + + s->abs_pow34(s->scoefs, sce->coeffs, 1024); + start = win*128; + for (cb = 0; cb < CB_TOT_ALL; cb++) { + path[0][cb].cost = run_bits+4; + path[0][cb].prev_idx = -1; + path[0][cb].run = 0; + } + for (swb = 0; swb < max_sfb; swb++) { + size = sce->ics.swb_sizes[swb]; + if (sce->zeroes[win*16 + swb]) { + float cost_stay_here = path[swb][0].cost; + float cost_get_here = next_minbits + run_bits + 4; + if ( run_value_bits[sce->ics.num_windows == 8][path[swb][0].run] + != run_value_bits[sce->ics.num_windows == 8][path[swb][0].run+1]) + cost_stay_here += run_bits; + if (cost_get_here < cost_stay_here) { + path[swb+1][0].prev_idx = next_mincb; + path[swb+1][0].cost = cost_get_here; + path[swb+1][0].run = 1; + } else { + path[swb+1][0].prev_idx = 0; + path[swb+1][0].cost = cost_stay_here; + path[swb+1][0].run = path[swb][0].run + 1; + } + next_minbits = path[swb+1][0].cost; + next_mincb = 0; + for (cb = 1; cb < CB_TOT_ALL; cb++) { + path[swb+1][cb].cost = 61450; + path[swb+1][cb].prev_idx = -1; + path[swb+1][cb].run = 0; + } + } else { + float minbits = next_minbits; + int mincb = next_mincb; + int startcb = sce->band_type[win*16+swb]; + startcb = aac_cb_in_map[startcb]; + next_minbits = INFINITY; + next_mincb = 0; + for (cb = 0; cb < startcb; cb++) { + path[swb+1][cb].cost = 61450; + path[swb+1][cb].prev_idx = -1; + path[swb+1][cb].run = 0; + } + for (cb = startcb; cb < CB_TOT_ALL; cb++) { + float cost_stay_here, cost_get_here; + float bits = 0.0f; + if (cb >= 12 && sce->band_type[win*16+swb] != aac_cb_out_map[cb]) { + path[swb+1][cb].cost = 61450; + path[swb+1][cb].prev_idx = -1; + path[swb+1][cb].run = 0; + continue; + } + for (w = 0; w < group_len; w++) { + bits += quantize_band_cost_bits(s, &sce->coeffs[start + w*128], + &s->scoefs[start + w*128], size, + sce->sf_idx[win*16+swb], + aac_cb_out_map[cb], + 0, INFINITY, NULL, NULL, 0); + } + cost_stay_here = path[swb][cb].cost + bits; + cost_get_here = minbits + bits + run_bits + 4; + if ( run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run] + != run_value_bits[sce->ics.num_windows == 8][path[swb][cb].run+1]) + cost_stay_here += run_bits; + if (cost_get_here < cost_stay_here) { + path[swb+1][cb].prev_idx = mincb; + path[swb+1][cb].cost = cost_get_here; + path[swb+1][cb].run = 1; + } else { + path[swb+1][cb].prev_idx = cb; + path[swb+1][cb].cost = cost_stay_here; + path[swb+1][cb].run = path[swb][cb].run + 1; + } + if (path[swb+1][cb].cost < next_minbits) { + next_minbits = path[swb+1][cb].cost; + next_mincb = cb; + } + } + } + start += sce->ics.swb_sizes[swb]; + } + + //convert resulting path from backward-linked list + stack_len = 0; + idx = 0; + for (cb = 1; cb < CB_TOT_ALL; cb++) + if (path[max_sfb][cb].cost < path[max_sfb][idx].cost) + idx = cb; + ppos = max_sfb; + while (ppos > 0) { + av_assert1(idx >= 0); + cb = idx; + stackrun[stack_len] = path[ppos][cb].run; + stackcb [stack_len] = cb; + idx = path[ppos-path[ppos][cb].run+1][cb].prev_idx; + ppos -= path[ppos][cb].run; + stack_len++; + } + //perform actual band info encoding + start = 0; + for (i = stack_len - 1; i >= 0; i--) { + cb = aac_cb_out_map[stackcb[i]]; + put_bits(&s->pb, 4, cb); + count = stackrun[i]; + memset(sce->zeroes + win*16 + start, !cb, count); + //XXX: memset when band_type is also uint8_t + for (j = 0; j < count; j++) { + sce->band_type[win*16 + start] = cb; + start++; + } + while (count >= run_esc) { + put_bits(&s->pb, run_bits, run_esc); + count -= run_esc; + } + put_bits(&s->pb, run_bits, count); + } +} + + +#endif /* AVCODEC_AACCODER_TRELLIS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder_twoloop.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder_twoloop.h new file mode 100644 index 0000000000..8e1bc88a85 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aaccoder_twoloop.h @@ -0,0 +1,763 @@ +/* + * AAC encoder twoloop coder + * Copyright (C) 2008-2009 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder twoloop coder + * @author Konstantin Shishkov, Claudio Freire + */ + +/** + * This file contains a template for the twoloop coder function. + * It needs to be provided, externally, as an already included declaration, + * the following functions from aacenc_quantization/util.h. They're not included + * explicitly here to make it possible to provide alternative implementations: + * - quantize_band_cost + * - abs_pow34_v + * - find_max_val + * - find_min_book + * - find_form_factor + */ + +#ifndef AVCODEC_AACCODER_TWOLOOP_H +#define AVCODEC_AACCODER_TWOLOOP_H + +#include +#include "libavutil/mathematics.h" +#include "mathops.h" +#include "avcodec.h" +#include "put_bits.h" +#include "aac.h" +#include "aacenc.h" +#include "aactab.h" +#include "aacenctab.h" + +/** Frequency in Hz for lower limit of noise substitution **/ +#define NOISE_LOW_LIMIT 4000 + +#define sclip(x) av_clip(x,60,218) + +/* Reflects the cost to change codebooks */ +static inline int ff_pns_bits(SingleChannelElement *sce, int w, int g) +{ + return (!g || !sce->zeroes[w*16+g-1] || !sce->can_pns[w*16+g-1]) ? 9 : 5; +} + +/** + * two-loop quantizers search taken from ISO 13818-7 Appendix C + */ +static void search_for_quantizers_twoloop(AVCodecContext *avctx, + AACEncContext *s, + SingleChannelElement *sce, + const float lambda) +{ + int start = 0, i, w, w2, g, recomprd; + int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate + / ((avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : avctx->channels) + * (lambda / 120.f); + int refbits = destbits; + int toomanybits, toofewbits; + char nzs[128]; + uint8_t nextband[128]; + int maxsf[128], minsf[128]; + float dists[128] = { 0 }, qenergies[128] = { 0 }, uplims[128], euplims[128], energies[128]; + float maxvals[128], spread_thr_r[128]; + float min_spread_thr_r, max_spread_thr_r; + + /** + * rdlambda controls the maximum tolerated distortion. Twoloop + * will keep iterating until it fails to lower it or it reaches + * ulimit * rdlambda. Keeping it low increases quality on difficult + * signals, but lower it too much, and bits will be taken from weak + * signals, creating "holes". A balance is necessary. + * rdmax and rdmin specify the relative deviation from rdlambda + * allowed for tonality compensation + */ + float rdlambda = av_clipf(2.0f * 120.f / lambda, 0.0625f, 16.0f); + const float nzslope = 1.5f; + float rdmin = 0.03125f; + float rdmax = 1.0f; + + /** + * sfoffs controls an offset of optmium allocation that will be + * applied based on lambda. Keep it real and modest, the loop + * will take care of the rest, this just accelerates convergence + */ + float sfoffs = av_clipf(log2f(120.0f / lambda) * 4.0f, -5, 10); + + int fflag, minscaler, maxscaler, nminscaler; + int its = 0; + int maxits = 30; + int allz = 0; + int tbits; + int cutoff = 1024; + int pns_start_pos; + int prev; + + /** + * zeroscale controls a multiplier of the threshold, if band energy + * is below this, a zero is forced. Keep it lower than 1, unless + * low lambda is used, because energy < threshold doesn't mean there's + * no audible signal outright, it's just energy. Also make it rise + * slower than rdlambda, as rdscale has due compensation with + * noisy band depriorization below, whereas zeroing logic is rather dumb + */ + float zeroscale; + if (lambda > 120.f) { + zeroscale = av_clipf(powf(120.f / lambda, 0.25f), 0.0625f, 1.0f); + } else { + zeroscale = 1.f; + } + + if (s->psy.bitres.alloc >= 0) { + /** + * Psy granted us extra bits to use, from the reservoire + * adjust for lambda except what psy already did + */ + destbits = s->psy.bitres.alloc + * (lambda / (avctx->global_quality ? avctx->global_quality : 120)); + } + + if (avctx->flags & AV_CODEC_FLAG_QSCALE) { + /** + * Constant Q-scale doesn't compensate MS coding on its own + * No need to be overly precise, this only controls RD + * adjustment CB limits when going overboard + */ + if (s->options.mid_side && s->cur_type == TYPE_CPE) + destbits *= 2; + + /** + * When using a constant Q-scale, don't adjust bits, just use RD + * Don't let it go overboard, though... 8x psy target is enough + */ + toomanybits = 5800; + toofewbits = destbits / 16; + + /** Don't offset scalers, just RD */ + sfoffs = sce->ics.num_windows - 1; + rdlambda = sqrtf(rdlambda); + + /** search further */ + maxits *= 2; + } else { + /* When using ABR, be strict, but a reasonable leeway is + * critical to allow RC to smoothly track desired bitrate + * without sudden quality drops that cause audible artifacts. + * Symmetry is also desirable, to avoid systematic bias. + */ + toomanybits = destbits + destbits/8; + toofewbits = destbits - destbits/8; + + sfoffs = 0; + rdlambda = sqrtf(rdlambda); + } + + /** and zero out above cutoff frequency */ + { + int wlen = 1024 / sce->ics.num_windows; + int bandwidth; + + /** + * Scale, psy gives us constant quality, this LP only scales + * bitrate by lambda, so we save bits on subjectively unimportant HF + * rather than increase quantization noise. Adjust nominal bitrate + * to effective bitrate according to encoding parameters, + * AAC_CUTOFF_FROM_BITRATE is calibrated for effective bitrate. + */ + float rate_bandwidth_multiplier = 1.5f; + int frame_bit_rate = (avctx->flags & AV_CODEC_FLAG_QSCALE) + ? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024) + : (avctx->bit_rate / avctx->channels); + + /** Compensate for extensions that increase efficiency */ + if (s->options.pns || s->options.intensity_stereo) + frame_bit_rate *= 1.15f; + + if (avctx->cutoff > 0) { + bandwidth = avctx->cutoff; + } else { + bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_bit_rate, 1, avctx->sample_rate)); + s->psy.cutoff = bandwidth; + } + + cutoff = bandwidth * 2 * wlen / avctx->sample_rate; + pns_start_pos = NOISE_LOW_LIMIT * 2 * wlen / avctx->sample_rate; + } + + /** + * for values above this the decoder might end up in an endless loop + * due to always having more bits than what can be encoded. + */ + destbits = FFMIN(destbits, 5800); + toomanybits = FFMIN(toomanybits, 5800); + toofewbits = FFMIN(toofewbits, 5800); + /** + * XXX: some heuristic to determine initial quantizers will reduce search time + * determine zero bands and upper distortion limits + */ + min_spread_thr_r = -1; + max_spread_thr_r = -1; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = start = 0; g < sce->ics.num_swb; start += sce->ics.swb_sizes[g++]) { + int nz = 0; + float uplim = 0.0f, energy = 0.0f, spread = 0.0f; + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; + if (start >= cutoff || band->energy <= (band->threshold * zeroscale) || band->threshold == 0.0f) { + sce->zeroes[(w+w2)*16+g] = 1; + continue; + } + nz = 1; + } + if (!nz) { + uplim = 0.0f; + } else { + nz = 0; + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; + if (band->energy <= (band->threshold * zeroscale) || band->threshold == 0.0f) + continue; + uplim += band->threshold; + energy += band->energy; + spread += band->spread; + nz++; + } + } + uplims[w*16+g] = uplim; + energies[w*16+g] = energy; + nzs[w*16+g] = nz; + sce->zeroes[w*16+g] = !nz; + allz |= nz; + if (nz && sce->can_pns[w*16+g]) { + spread_thr_r[w*16+g] = energy * nz / (uplim * spread); + if (min_spread_thr_r < 0) { + min_spread_thr_r = max_spread_thr_r = spread_thr_r[w*16+g]; + } else { + min_spread_thr_r = FFMIN(min_spread_thr_r, spread_thr_r[w*16+g]); + max_spread_thr_r = FFMAX(max_spread_thr_r, spread_thr_r[w*16+g]); + } + } + } + } + + /** Compute initial scalers */ + minscaler = 65535; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = 0; g < sce->ics.num_swb; g++) { + if (sce->zeroes[w*16+g]) { + sce->sf_idx[w*16+g] = SCALE_ONE_POS; + continue; + } + /** + * log2f-to-distortion ratio is, technically, 2 (1.5db = 4, but it's power vs level so it's 2). + * But, as offsets are applied, low-frequency signals are too sensitive to the induced distortion, + * so we make scaling more conservative by choosing a lower log2f-to-distortion ratio, and thus + * more robust. + */ + sce->sf_idx[w*16+g] = av_clip( + SCALE_ONE_POS + + 1.75*log2f(FFMAX(0.00125f,uplims[w*16+g]) / sce->ics.swb_sizes[g]) + + sfoffs, + 60, SCALE_MAX_POS); + minscaler = FFMIN(minscaler, sce->sf_idx[w*16+g]); + } + } + + /** Clip */ + minscaler = av_clip(minscaler, SCALE_ONE_POS - SCALE_DIV_512, SCALE_MAX_POS - SCALE_DIV_512); + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) + for (g = 0; g < sce->ics.num_swb; g++) + if (!sce->zeroes[w*16+g]) + sce->sf_idx[w*16+g] = av_clip(sce->sf_idx[w*16+g], minscaler, minscaler + SCALE_MAX_DIFF - 1); + + if (!allz) + return; + s->abs_pow34(s->scoefs, sce->coeffs, 1024); + ff_quantize_band_cost_cache_init(s); + + for (i = 0; i < sizeof(minsf) / sizeof(minsf[0]); ++i) + minsf[i] = 0; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + start = w*128; + for (g = 0; g < sce->ics.num_swb; g++) { + const float *scaled = s->scoefs + start; + int minsfidx; + maxvals[w*16+g] = find_max_val(sce->ics.group_len[w], sce->ics.swb_sizes[g], scaled); + if (maxvals[w*16+g] > 0) { + minsfidx = coef2minsf(maxvals[w*16+g]); + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) + minsf[(w+w2)*16+g] = minsfidx; + } + start += sce->ics.swb_sizes[g]; + } + } + + /** + * Scale uplims to match rate distortion to quality + * bu applying noisy band depriorization and tonal band priorization. + * Maxval-energy ratio gives us an idea of how noisy/tonal the band is. + * If maxval^2 ~ energy, then that band is mostly noise, and we can relax + * rate distortion requirements. + */ + memcpy(euplims, uplims, sizeof(euplims)); + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + /** psy already priorizes transients to some extent */ + float de_psy_factor = (sce->ics.num_windows > 1) ? 8.0f / sce->ics.group_len[w] : 1.0f; + start = w*128; + for (g = 0; g < sce->ics.num_swb; g++) { + if (nzs[g] > 0) { + float cleanup_factor = ff_sqrf(av_clipf(start / (cutoff * 0.75f), 1.0f, 2.0f)); + float energy2uplim = find_form_factor( + sce->ics.group_len[w], sce->ics.swb_sizes[g], + uplims[w*16+g] / (nzs[g] * sce->ics.swb_sizes[w]), + sce->coeffs + start, + nzslope * cleanup_factor); + energy2uplim *= de_psy_factor; + if (!(avctx->flags & AV_CODEC_FLAG_QSCALE)) { + /** In ABR, we need to priorize less and let rate control do its thing */ + energy2uplim = sqrtf(energy2uplim); + } + energy2uplim = FFMAX(0.015625f, FFMIN(1.0f, energy2uplim)); + uplims[w*16+g] *= av_clipf(rdlambda * energy2uplim, rdmin, rdmax) + * sce->ics.group_len[w]; + + energy2uplim = find_form_factor( + sce->ics.group_len[w], sce->ics.swb_sizes[g], + uplims[w*16+g] / (nzs[g] * sce->ics.swb_sizes[w]), + sce->coeffs + start, + 2.0f); + energy2uplim *= de_psy_factor; + if (!(avctx->flags & AV_CODEC_FLAG_QSCALE)) { + /** In ABR, we need to priorize less and let rate control do its thing */ + energy2uplim = sqrtf(energy2uplim); + } + energy2uplim = FFMAX(0.015625f, FFMIN(1.0f, energy2uplim)); + euplims[w*16+g] *= av_clipf(rdlambda * energy2uplim * sce->ics.group_len[w], + 0.5f, 1.0f); + } + start += sce->ics.swb_sizes[g]; + } + } + + for (i = 0; i < sizeof(maxsf) / sizeof(maxsf[0]); ++i) + maxsf[i] = SCALE_MAX_POS; + + //perform two-loop search + //outer loop - improve quality + do { + //inner loop - quantize spectrum to fit into given number of bits + int overdist; + int qstep = its ? 1 : 32; + do { + int changed = 0; + prev = -1; + recomprd = 0; + tbits = 0; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + start = w*128; + for (g = 0; g < sce->ics.num_swb; g++) { + const float *coefs = &sce->coeffs[start]; + const float *scaled = &s->scoefs[start]; + int bits = 0; + int cb; + float dist = 0.0f; + float qenergy = 0.0f; + + if (sce->zeroes[w*16+g] || sce->sf_idx[w*16+g] >= 218) { + start += sce->ics.swb_sizes[g]; + if (sce->can_pns[w*16+g]) { + /** PNS isn't free */ + tbits += ff_pns_bits(sce, w, g); + } + continue; + } + cb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]); + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + int b; + float sqenergy; + dist += quantize_band_cost_cached(s, w + w2, g, coefs + w2*128, + scaled + w2*128, + sce->ics.swb_sizes[g], + sce->sf_idx[w*16+g], + cb, + 1.0f, + INFINITY, + &b, &sqenergy, + 0); + bits += b; + qenergy += sqenergy; + } + dists[w*16+g] = dist - bits; + qenergies[w*16+g] = qenergy; + if (prev != -1) { + int sfdiff = av_clip(sce->sf_idx[w*16+g] - prev + SCALE_DIFF_ZERO, 0, 2*SCALE_MAX_DIFF); + bits += ff_aac_scalefactor_bits[sfdiff]; + } + tbits += bits; + start += sce->ics.swb_sizes[g]; + prev = sce->sf_idx[w*16+g]; + } + } + if (tbits > toomanybits) { + recomprd = 1; + for (i = 0; i < 128; i++) { + if (sce->sf_idx[i] < (SCALE_MAX_POS - SCALE_DIV_512)) { + int maxsf_i = (tbits > 5800) ? SCALE_MAX_POS : maxsf[i]; + int new_sf = FFMIN(maxsf_i, sce->sf_idx[i] + qstep); + if (new_sf != sce->sf_idx[i]) { + sce->sf_idx[i] = new_sf; + changed = 1; + } + } + } + } else if (tbits < toofewbits) { + recomprd = 1; + for (i = 0; i < 128; i++) { + if (sce->sf_idx[i] > SCALE_ONE_POS) { + int new_sf = FFMAX3(minsf[i], SCALE_ONE_POS, sce->sf_idx[i] - qstep); + if (new_sf != sce->sf_idx[i]) { + sce->sf_idx[i] = new_sf; + changed = 1; + } + } + } + } + qstep >>= 1; + if (!qstep && tbits > toomanybits && sce->sf_idx[0] < 217 && changed) + qstep = 1; + } while (qstep); + + overdist = 1; + fflag = tbits < toofewbits; + for (i = 0; i < 2 && (overdist || recomprd); ++i) { + if (recomprd) { + /** Must recompute distortion */ + prev = -1; + tbits = 0; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + start = w*128; + for (g = 0; g < sce->ics.num_swb; g++) { + const float *coefs = sce->coeffs + start; + const float *scaled = s->scoefs + start; + int bits = 0; + int cb; + float dist = 0.0f; + float qenergy = 0.0f; + + if (sce->zeroes[w*16+g] || sce->sf_idx[w*16+g] >= 218) { + start += sce->ics.swb_sizes[g]; + if (sce->can_pns[w*16+g]) { + /** PNS isn't free */ + tbits += ff_pns_bits(sce, w, g); + } + continue; + } + cb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]); + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + int b; + float sqenergy; + dist += quantize_band_cost_cached(s, w + w2, g, coefs + w2*128, + scaled + w2*128, + sce->ics.swb_sizes[g], + sce->sf_idx[w*16+g], + cb, + 1.0f, + INFINITY, + &b, &sqenergy, + 0); + bits += b; + qenergy += sqenergy; + } + dists[w*16+g] = dist - bits; + qenergies[w*16+g] = qenergy; + if (prev != -1) { + int sfdiff = av_clip(sce->sf_idx[w*16+g] - prev + SCALE_DIFF_ZERO, 0, 2*SCALE_MAX_DIFF); + bits += ff_aac_scalefactor_bits[sfdiff]; + } + tbits += bits; + start += sce->ics.swb_sizes[g]; + prev = sce->sf_idx[w*16+g]; + } + } + } + if (!i && s->options.pns && its > maxits/2 && tbits > toofewbits) { + float maxoverdist = 0.0f; + float ovrfactor = 1.f+(maxits-its)*16.f/maxits; + overdist = recomprd = 0; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = start = 0; g < sce->ics.num_swb; start += sce->ics.swb_sizes[g++]) { + if (!sce->zeroes[w*16+g] && sce->sf_idx[w*16+g] > SCALE_ONE_POS && dists[w*16+g] > uplims[w*16+g]*ovrfactor) { + float ovrdist = dists[w*16+g] / FFMAX(uplims[w*16+g],euplims[w*16+g]); + maxoverdist = FFMAX(maxoverdist, ovrdist); + overdist++; + } + } + } + if (overdist) { + /* We have overdistorted bands, trade for zeroes (that can be noise) + * Zero the bands in the lowest 1.25% spread-energy-threshold ranking + */ + float minspread = max_spread_thr_r; + float maxspread = min_spread_thr_r; + float zspread; + int zeroable = 0; + int zeroed = 0; + int maxzeroed, zloop; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = start = 0; g < sce->ics.num_swb; start += sce->ics.swb_sizes[g++]) { + if (start >= pns_start_pos && !sce->zeroes[w*16+g] && sce->can_pns[w*16+g]) { + minspread = FFMIN(minspread, spread_thr_r[w*16+g]); + maxspread = FFMAX(maxspread, spread_thr_r[w*16+g]); + zeroable++; + } + } + } + zspread = (maxspread-minspread) * 0.0125f + minspread; + /* Don't PNS everything even if allowed. It suppresses bit starvation signals from RC, + * and forced the hand of the later search_for_pns step. + * Instead, PNS a fraction of the spread_thr_r range depending on how starved for bits we are, + * and leave further PNSing to search_for_pns if worthwhile. + */ + zspread = FFMIN3(min_spread_thr_r * 8.f, zspread, + ((toomanybits - tbits) * min_spread_thr_r + (tbits - toofewbits) * max_spread_thr_r) / (toomanybits - toofewbits + 1)); + maxzeroed = FFMIN(zeroable, FFMAX(1, (zeroable * its + maxits - 1) / (2 * maxits))); + for (zloop = 0; zloop < 2; zloop++) { + /* Two passes: first distorted stuff - two birds in one shot and all that, + * then anything viable. Viable means not zero, but either CB=zero-able + * (too high SF), not SF <= 1 (that means we'd be operating at very high + * quality, we don't want PNS when doing VHQ), PNS allowed, and within + * the lowest ranking percentile. + */ + float loopovrfactor = (zloop) ? 1.0f : ovrfactor; + int loopminsf = (zloop) ? (SCALE_ONE_POS - SCALE_DIV_512) : SCALE_ONE_POS; + int mcb; + for (g = sce->ics.num_swb-1; g > 0 && zeroed < maxzeroed; g--) { + if (sce->ics.swb_offset[g] < pns_start_pos) + continue; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + if (!sce->zeroes[w*16+g] && sce->can_pns[w*16+g] && spread_thr_r[w*16+g] <= zspread + && sce->sf_idx[w*16+g] > loopminsf + && (dists[w*16+g] > loopovrfactor*uplims[w*16+g] || !(mcb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g])) + || (mcb <= 1 && dists[w*16+g] > FFMIN(uplims[w*16+g], euplims[w*16+g]))) ) { + sce->zeroes[w*16+g] = 1; + sce->band_type[w*16+g] = 0; + zeroed++; + } + } + } + } + if (zeroed) + recomprd = fflag = 1; + } else { + overdist = 0; + } + } + } + + minscaler = SCALE_MAX_POS; + maxscaler = 0; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = 0; g < sce->ics.num_swb; g++) { + if (!sce->zeroes[w*16+g]) { + minscaler = FFMIN(minscaler, sce->sf_idx[w*16+g]); + maxscaler = FFMAX(maxscaler, sce->sf_idx[w*16+g]); + } + } + } + + minscaler = nminscaler = av_clip(minscaler, SCALE_ONE_POS - SCALE_DIV_512, SCALE_MAX_POS - SCALE_DIV_512); + prev = -1; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + /** Start with big steps, end up fine-tunning */ + int depth = (its > maxits/2) ? ((its > maxits*2/3) ? 1 : 3) : 10; + int edepth = depth+2; + float uplmax = its / (maxits*0.25f) + 1.0f; + uplmax *= (tbits > destbits) ? FFMIN(2.0f, tbits / (float)FFMAX(1,destbits)) : 1.0f; + start = w * 128; + for (g = 0; g < sce->ics.num_swb; g++) { + int prevsc = sce->sf_idx[w*16+g]; + if (prev < 0 && !sce->zeroes[w*16+g]) + prev = sce->sf_idx[0]; + if (!sce->zeroes[w*16+g]) { + const float *coefs = sce->coeffs + start; + const float *scaled = s->scoefs + start; + int cmb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]); + int mindeltasf = FFMAX(0, prev - SCALE_MAX_DIFF); + int maxdeltasf = FFMIN(SCALE_MAX_POS - SCALE_DIV_512, prev + SCALE_MAX_DIFF); + if ((!cmb || dists[w*16+g] > uplims[w*16+g]) && sce->sf_idx[w*16+g] > FFMAX(mindeltasf, minsf[w*16+g])) { + /* Try to make sure there is some energy in every nonzero band + * NOTE: This algorithm must be forcibly imbalanced, pushing harder + * on holes or more distorted bands at first, otherwise there's + * no net gain (since the next iteration will offset all bands + * on the opposite direction to compensate for extra bits) + */ + for (i = 0; i < edepth && sce->sf_idx[w*16+g] > mindeltasf; ++i) { + int cb, bits; + float dist, qenergy; + int mb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]-1); + cb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]); + dist = qenergy = 0.f; + bits = 0; + if (!cb) { + maxsf[w*16+g] = FFMIN(sce->sf_idx[w*16+g]-1, maxsf[w*16+g]); + } else if (i >= depth && dists[w*16+g] < euplims[w*16+g]) { + break; + } + /* !g is the DC band, it's important, since quantization error here + * applies to less than a cycle, it creates horrible intermodulation + * distortion if it doesn't stick to what psy requests + */ + if (!g && sce->ics.num_windows > 1 && dists[w*16+g] >= euplims[w*16+g]) + maxsf[w*16+g] = FFMIN(sce->sf_idx[w*16+g], maxsf[w*16+g]); + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + int b; + float sqenergy; + dist += quantize_band_cost_cached(s, w + w2, g, coefs + w2*128, + scaled + w2*128, + sce->ics.swb_sizes[g], + sce->sf_idx[w*16+g]-1, + cb, + 1.0f, + INFINITY, + &b, &sqenergy, + 0); + bits += b; + qenergy += sqenergy; + } + sce->sf_idx[w*16+g]--; + dists[w*16+g] = dist - bits; + qenergies[w*16+g] = qenergy; + if (mb && (sce->sf_idx[w*16+g] < mindeltasf || ( + (dists[w*16+g] < FFMIN(uplmax*uplims[w*16+g], euplims[w*16+g])) + && (fabsf(qenergies[w*16+g]-energies[w*16+g]) < euplims[w*16+g]) + ) )) { + break; + } + } + } else if (tbits > toofewbits && sce->sf_idx[w*16+g] < FFMIN(maxdeltasf, maxsf[w*16+g]) + && (dists[w*16+g] < FFMIN(euplims[w*16+g], uplims[w*16+g])) + && (fabsf(qenergies[w*16+g]-energies[w*16+g]) < euplims[w*16+g]) + ) { + /** Um... over target. Save bits for more important stuff. */ + for (i = 0; i < depth && sce->sf_idx[w*16+g] < maxdeltasf; ++i) { + int cb, bits; + float dist, qenergy; + cb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]+1); + if (cb > 0) { + dist = qenergy = 0.f; + bits = 0; + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + int b; + float sqenergy; + dist += quantize_band_cost_cached(s, w + w2, g, coefs + w2*128, + scaled + w2*128, + sce->ics.swb_sizes[g], + sce->sf_idx[w*16+g]+1, + cb, + 1.0f, + INFINITY, + &b, &sqenergy, + 0); + bits += b; + qenergy += sqenergy; + } + dist -= bits; + if (dist < FFMIN(euplims[w*16+g], uplims[w*16+g])) { + sce->sf_idx[w*16+g]++; + dists[w*16+g] = dist; + qenergies[w*16+g] = qenergy; + } else { + break; + } + } else { + maxsf[w*16+g] = FFMIN(sce->sf_idx[w*16+g], maxsf[w*16+g]); + break; + } + } + } + prev = sce->sf_idx[w*16+g] = av_clip(sce->sf_idx[w*16+g], mindeltasf, maxdeltasf); + if (sce->sf_idx[w*16+g] != prevsc) + fflag = 1; + nminscaler = FFMIN(nminscaler, sce->sf_idx[w*16+g]); + sce->band_type[w*16+g] = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]); + } + start += sce->ics.swb_sizes[g]; + } + } + + /** SF difference limit violation risk. Must re-clamp. */ + prev = -1; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = 0; g < sce->ics.num_swb; g++) { + if (!sce->zeroes[w*16+g]) { + int prevsf = sce->sf_idx[w*16+g]; + if (prev < 0) + prev = prevsf; + sce->sf_idx[w*16+g] = av_clip(sce->sf_idx[w*16+g], prev - SCALE_MAX_DIFF, prev + SCALE_MAX_DIFF); + sce->band_type[w*16+g] = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]); + prev = sce->sf_idx[w*16+g]; + if (!fflag && prevsf != sce->sf_idx[w*16+g]) + fflag = 1; + } + } + } + + its++; + } while (fflag && its < maxits); + + /** Scout out next nonzero bands */ + ff_init_nextband_map(sce, nextband); + + prev = -1; + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + /** Make sure proper codebooks are set */ + for (g = 0; g < sce->ics.num_swb; g++) { + if (!sce->zeroes[w*16+g]) { + sce->band_type[w*16+g] = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]); + if (sce->band_type[w*16+g] <= 0) { + if (!ff_sfdelta_can_remove_band(sce, nextband, prev, w*16+g)) { + /** Cannot zero out, make sure it's not attempted */ + sce->band_type[w*16+g] = 1; + } else { + sce->zeroes[w*16+g] = 1; + sce->band_type[w*16+g] = 0; + } + } + } else { + sce->band_type[w*16+g] = 0; + } + /** Check that there's no SF delta range violations */ + if (!sce->zeroes[w*16+g]) { + if (prev != -1) { + av_unused int sfdiff = sce->sf_idx[w*16+g] - prev + SCALE_DIFF_ZERO; + av_assert1(sfdiff >= 0 && sfdiff <= 2*SCALE_MAX_DIFF); + } else if (sce->zeroes[0]) { + /** Set global gain to something useful */ + sce->sf_idx[0] = sce->sf_idx[w*16+g]; + } + prev = sce->sf_idx[w*16+g]; + } + } + } +} + +#endif /* AVCODEC_AACCODER_TWOLOOP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec.c new file mode 100644 index 0000000000..c606ad40a9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec.c @@ -0,0 +1,591 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC decoder + * @author Oded Shimon ( ods15 ods15 dyndns org ) + * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) + */ + +#define FFT_FLOAT 1 +#define FFT_FIXED_32 0 +#define USE_FIXED 0 + +#include "libavutil/float_dsp.h" +#include "libavutil/opt.h" +#include "avcodec.h" +#include "internal.h" +#include "get_bits.h" +#include "fft.h" +#include "mdct15.h" +#include "lpc.h" +#include "kbdwin.h" +#include "sinewin.h" + +#include "aac.h" +#include "aactab.h" +#include "aacdectab.h" +#include "adts_header.h" +#include "cbrt_data.h" +#include "sbr.h" +#include "aacsbr.h" +#include "mpeg4audio.h" +#include "profiles.h" +#include "libavutil/intfloat.h" + +#include +#include +#include +#include + +#if ARCH_ARM +# include "arm/aac.h" +#elif ARCH_MIPS +# include "mips/aacdec_mips.h" +#endif + +static av_always_inline void reset_predict_state(PredictorState *ps) +{ + ps->r0 = 0.0f; + ps->r1 = 0.0f; + ps->cor0 = 0.0f; + ps->cor1 = 0.0f; + ps->var0 = 1.0f; + ps->var1 = 1.0f; +} + +#ifndef VMUL2 +static inline float *VMUL2(float *dst, const float *v, unsigned idx, + const float *scale) +{ + float s = *scale; + *dst++ = v[idx & 15] * s; + *dst++ = v[idx>>4 & 15] * s; + return dst; +} +#endif + +#ifndef VMUL4 +static inline float *VMUL4(float *dst, const float *v, unsigned idx, + const float *scale) +{ + float s = *scale; + *dst++ = v[idx & 3] * s; + *dst++ = v[idx>>2 & 3] * s; + *dst++ = v[idx>>4 & 3] * s; + *dst++ = v[idx>>6 & 3] * s; + return dst; +} +#endif + +#ifndef VMUL2S +static inline float *VMUL2S(float *dst, const float *v, unsigned idx, + unsigned sign, const float *scale) +{ + union av_intfloat32 s0, s1; + + s0.f = s1.f = *scale; + s0.i ^= sign >> 1 << 31; + s1.i ^= sign << 31; + + *dst++ = v[idx & 15] * s0.f; + *dst++ = v[idx>>4 & 15] * s1.f; + + return dst; +} +#endif + +#ifndef VMUL4S +static inline float *VMUL4S(float *dst, const float *v, unsigned idx, + unsigned sign, const float *scale) +{ + unsigned nz = idx >> 12; + union av_intfloat32 s = { .f = *scale }; + union av_intfloat32 t; + + t.i = s.i ^ (sign & 1U<<31); + *dst++ = v[idx & 3] * t.f; + + sign <<= nz & 1; nz >>= 1; + t.i = s.i ^ (sign & 1U<<31); + *dst++ = v[idx>>2 & 3] * t.f; + + sign <<= nz & 1; nz >>= 1; + t.i = s.i ^ (sign & 1U<<31); + *dst++ = v[idx>>4 & 3] * t.f; + + sign <<= nz & 1; + t.i = s.i ^ (sign & 1U<<31); + *dst++ = v[idx>>6 & 3] * t.f; + + return dst; +} +#endif + +static av_always_inline float flt16_round(float pf) +{ + union av_intfloat32 tmp; + tmp.f = pf; + tmp.i = (tmp.i + 0x00008000U) & 0xFFFF0000U; + return tmp.f; +} + +static av_always_inline float flt16_even(float pf) +{ + union av_intfloat32 tmp; + tmp.f = pf; + tmp.i = (tmp.i + 0x00007FFFU + (tmp.i & 0x00010000U >> 16)) & 0xFFFF0000U; + return tmp.f; +} + +static av_always_inline float flt16_trunc(float pf) +{ + union av_intfloat32 pun; + pun.f = pf; + pun.i &= 0xFFFF0000U; + return pun.f; +} + +static av_always_inline void predict(PredictorState *ps, float *coef, + int output_enable) +{ + const float a = 0.953125; // 61.0 / 64 + const float alpha = 0.90625; // 29.0 / 32 + float e0, e1; + float pv; + float k1, k2; + float r0 = ps->r0, r1 = ps->r1; + float cor0 = ps->cor0, cor1 = ps->cor1; + float var0 = ps->var0, var1 = ps->var1; + + k1 = var0 > 1 ? cor0 * flt16_even(a / var0) : 0; + k2 = var1 > 1 ? cor1 * flt16_even(a / var1) : 0; + + pv = flt16_round(k1 * r0 + k2 * r1); + if (output_enable) + *coef += pv; + + e0 = *coef; + e1 = e0 - k1 * r0; + + ps->cor1 = flt16_trunc(alpha * cor1 + r1 * e1); + ps->var1 = flt16_trunc(alpha * var1 + 0.5f * (r1 * r1 + e1 * e1)); + ps->cor0 = flt16_trunc(alpha * cor0 + r0 * e0); + ps->var0 = flt16_trunc(alpha * var0 + 0.5f * (r0 * r0 + e0 * e0)); + + ps->r1 = flt16_trunc(a * (r0 - k1 * e0)); + ps->r0 = flt16_trunc(a * e0); +} + +/** + * Apply dependent channel coupling (applied before IMDCT). + * + * @param index index into coupling gain array + */ +static void apply_dependent_coupling(AACContext *ac, + SingleChannelElement *target, + ChannelElement *cce, int index) +{ + IndividualChannelStream *ics = &cce->ch[0].ics; + const uint16_t *offsets = ics->swb_offset; + float *dest = target->coeffs; + const float *src = cce->ch[0].coeffs; + int g, i, group, k, idx = 0; + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) { + av_log(ac->avctx, AV_LOG_ERROR, + "Dependent coupling is not supported together with LTP\n"); + return; + } + for (g = 0; g < ics->num_window_groups; g++) { + for (i = 0; i < ics->max_sfb; i++, idx++) { + if (cce->ch[0].band_type[idx] != ZERO_BT) { + const float gain = cce->coup.gain[index][idx]; + for (group = 0; group < ics->group_len[g]; group++) { + for (k = offsets[i]; k < offsets[i + 1]; k++) { + // FIXME: SIMDify + dest[group * 128 + k] += gain * src[group * 128 + k]; + } + } + } + } + dest += ics->group_len[g] * 128; + src += ics->group_len[g] * 128; + } +} + +/** + * Apply independent channel coupling (applied after IMDCT). + * + * @param index index into coupling gain array + */ +static void apply_independent_coupling(AACContext *ac, + SingleChannelElement *target, + ChannelElement *cce, int index) +{ + const float gain = cce->coup.gain[index][0]; + const float *src = cce->ch[0].ret; + float *dest = target->ret; + const int len = 1024 << (ac->oc[1].m4ac.sbr == 1); + + ac->fdsp->vector_fmac_scalar(dest, src, gain, len); +} + +#include "aacdec_template.c" + +#define LOAS_SYNC_WORD 0x2b7 ///< 11 bits LOAS sync word + +struct LATMContext { + AACContext aac_ctx; ///< containing AACContext + int initialized; ///< initialized after a valid extradata was seen + + // parser data + int audio_mux_version_A; ///< LATM syntax version + int frame_length_type; ///< 0/1 variable/fixed frame length + int frame_length; ///< frame length for fixed frame length +}; + +static inline uint32_t latm_get_value(GetBitContext *b) +{ + int length = get_bits(b, 2); + + return get_bits_long(b, (length+1)*8); +} + +static int latm_decode_audio_specific_config(struct LATMContext *latmctx, + GetBitContext *gb, int asclen) +{ + AACContext *ac = &latmctx->aac_ctx; + AVCodecContext *avctx = ac->avctx; + MPEG4AudioConfig m4ac = { 0 }; + GetBitContext gbc; + int config_start_bit = get_bits_count(gb); + int sync_extension = 0; + int bits_consumed, esize, i; + + if (asclen > 0) { + sync_extension = 1; + asclen = FFMIN(asclen, get_bits_left(gb)); + init_get_bits(&gbc, gb->buffer, config_start_bit + asclen); + skip_bits_long(&gbc, config_start_bit); + } else if (asclen == 0) { + gbc = *gb; + } else { + return AVERROR_INVALIDDATA; + } + + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + + bits_consumed = decode_audio_specific_config_gb(NULL, avctx, &m4ac, + &gbc, config_start_bit, + sync_extension); + + if (bits_consumed < config_start_bit) + return AVERROR_INVALIDDATA; + bits_consumed -= config_start_bit; + + if (asclen == 0) + asclen = bits_consumed; + + if (!latmctx->initialized || + ac->oc[1].m4ac.sample_rate != m4ac.sample_rate || + ac->oc[1].m4ac.chan_config != m4ac.chan_config) { + + if (latmctx->initialized) { + av_log(avctx, AV_LOG_INFO, "audio config changed (sample_rate=%d, chan_config=%d)\n", m4ac.sample_rate, m4ac.chan_config); + } else { + av_log(avctx, AV_LOG_DEBUG, "initializing latmctx\n"); + } + latmctx->initialized = 0; + + esize = (asclen + 7) / 8; + + if (avctx->extradata_size < esize) { + av_free(avctx->extradata); + avctx->extradata = av_malloc(esize + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) + return AVERROR(ENOMEM); + } + + avctx->extradata_size = esize; + gbc = *gb; + for (i = 0; i < esize; i++) { + avctx->extradata[i] = get_bits(&gbc, 8); + } + memset(avctx->extradata+esize, 0, AV_INPUT_BUFFER_PADDING_SIZE); + } + skip_bits_long(gb, asclen); + + return 0; +} + +static int read_stream_mux_config(struct LATMContext *latmctx, + GetBitContext *gb) +{ + int ret, audio_mux_version = get_bits(gb, 1); + + latmctx->audio_mux_version_A = 0; + if (audio_mux_version) + latmctx->audio_mux_version_A = get_bits(gb, 1); + + if (!latmctx->audio_mux_version_A) { + + if (audio_mux_version) + latm_get_value(gb); // taraFullness + + skip_bits(gb, 1); // allStreamSameTimeFraming + skip_bits(gb, 6); // numSubFrames + // numPrograms + if (get_bits(gb, 4)) { // numPrograms + avpriv_request_sample(latmctx->aac_ctx.avctx, "Multiple programs"); + return AVERROR_PATCHWELCOME; + } + + // for each program (which there is only one in DVB) + + // for each layer (which there is only one in DVB) + if (get_bits(gb, 3)) { // numLayer + avpriv_request_sample(latmctx->aac_ctx.avctx, "Multiple layers"); + return AVERROR_PATCHWELCOME; + } + + // for all but first stream: use_same_config = get_bits(gb, 1); + if (!audio_mux_version) { + if ((ret = latm_decode_audio_specific_config(latmctx, gb, 0)) < 0) + return ret; + } else { + int ascLen = latm_get_value(gb); + if ((ret = latm_decode_audio_specific_config(latmctx, gb, ascLen)) < 0) + return ret; + } + + latmctx->frame_length_type = get_bits(gb, 3); + switch (latmctx->frame_length_type) { + case 0: + skip_bits(gb, 8); // latmBufferFullness + break; + case 1: + latmctx->frame_length = get_bits(gb, 9); + break; + case 3: + case 4: + case 5: + skip_bits(gb, 6); // CELP frame length table index + break; + case 6: + case 7: + skip_bits(gb, 1); // HVXC frame length table index + break; + } + + if (get_bits(gb, 1)) { // other data + if (audio_mux_version) { + latm_get_value(gb); // other_data_bits + } else { + int esc; + do { + esc = get_bits(gb, 1); + skip_bits(gb, 8); + } while (esc); + } + } + + if (get_bits(gb, 1)) // crc present + skip_bits(gb, 8); // config_crc + } + + return 0; +} + +static int read_payload_length_info(struct LATMContext *ctx, GetBitContext *gb) +{ + uint8_t tmp; + + if (ctx->frame_length_type == 0) { + int mux_slot_length = 0; + do { + if (get_bits_left(gb) < 8) + return AVERROR_INVALIDDATA; + tmp = get_bits(gb, 8); + mux_slot_length += tmp; + } while (tmp == 255); + return mux_slot_length; + } else if (ctx->frame_length_type == 1) { + return ctx->frame_length; + } else if (ctx->frame_length_type == 3 || + ctx->frame_length_type == 5 || + ctx->frame_length_type == 7) { + skip_bits(gb, 2); // mux_slot_length_coded + } + return 0; +} + +static int read_audio_mux_element(struct LATMContext *latmctx, + GetBitContext *gb) +{ + int err; + uint8_t use_same_mux = get_bits(gb, 1); + if (!use_same_mux) { + if ((err = read_stream_mux_config(latmctx, gb)) < 0) + return err; + } else if (!latmctx->aac_ctx.avctx->extradata) { + av_log(latmctx->aac_ctx.avctx, AV_LOG_DEBUG, + "no decoder config found\n"); + return 1; + } + if (latmctx->audio_mux_version_A == 0) { + int mux_slot_length_bytes = read_payload_length_info(latmctx, gb); + if (mux_slot_length_bytes < 0 || mux_slot_length_bytes * 8LL > get_bits_left(gb)) { + av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, "incomplete frame\n"); + return AVERROR_INVALIDDATA; + } else if (mux_slot_length_bytes * 8 + 256 < get_bits_left(gb)) { + av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, + "frame length mismatch %d << %d\n", + mux_slot_length_bytes * 8, get_bits_left(gb)); + return AVERROR_INVALIDDATA; + } + } + return 0; +} + + +static int latm_decode_frame(AVCodecContext *avctx, void *out, + int *got_frame_ptr, AVPacket *avpkt) +{ + struct LATMContext *latmctx = avctx->priv_data; + int muxlength, err; + GetBitContext gb; + + if ((err = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) + return err; + + // check for LOAS sync word + if (get_bits(&gb, 11) != LOAS_SYNC_WORD) + return AVERROR_INVALIDDATA; + + muxlength = get_bits(&gb, 13) + 3; + // not enough data, the parser should have sorted this out + if (muxlength > avpkt->size) + return AVERROR_INVALIDDATA; + + if ((err = read_audio_mux_element(latmctx, &gb))) + return (err < 0) ? err : avpkt->size; + + if (!latmctx->initialized) { + if (!avctx->extradata) { + *got_frame_ptr = 0; + return avpkt->size; + } else { + push_output_configuration(&latmctx->aac_ctx); + if ((err = decode_audio_specific_config( + &latmctx->aac_ctx, avctx, &latmctx->aac_ctx.oc[1].m4ac, + avctx->extradata, avctx->extradata_size*8LL, 1)) < 0) { + pop_output_configuration(&latmctx->aac_ctx); + return err; + } + latmctx->initialized = 1; + } + } + + if (show_bits(&gb, 12) == 0xfff) { + av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, + "ADTS header detected, probably as result of configuration " + "misparsing\n"); + return AVERROR_INVALIDDATA; + } + + switch (latmctx->aac_ctx.oc[1].m4ac.object_type) { + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LTP: + case AOT_ER_AAC_LD: + case AOT_ER_AAC_ELD: + err = aac_decode_er_frame(avctx, out, got_frame_ptr, &gb); + break; + default: + err = aac_decode_frame_int(avctx, out, got_frame_ptr, &gb, avpkt); + } + if (err < 0) + return err; + + return muxlength; +} + +static av_cold int latm_decode_init(AVCodecContext *avctx) +{ + struct LATMContext *latmctx = avctx->priv_data; + int ret = aac_decode_init(avctx); + + if (avctx->extradata_size > 0) + latmctx->initialized = !ret; + + return ret; +} + +AVCodec ff_aac_decoder = { + .name = "aac", + .long_name = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_AAC, + .priv_data_size = sizeof(AACContext), + .init = aac_decode_init, + .close = aac_decode_close, + .decode = aac_decode_frame, + .sample_fmts = (const enum AVSampleFormat[]) { + AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE + }, + .capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = aac_channel_layout, + .flush = flush, + .priv_class = &aac_decoder_class, + .profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), +}; + +/* + Note: This decoder filter is intended to decode LATM streams transferred + in MPEG transport streams which only contain one program. + To do a more complex LATM demuxing a separate LATM demuxer should be used. +*/ +AVCodec ff_aac_latm_decoder = { + .name = "aac_latm", + .long_name = NULL_IF_CONFIG_SMALL("AAC LATM (Advanced Audio Coding LATM syntax)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_AAC_LATM, + .priv_data_size = sizeof(struct LATMContext), + .init = latm_decode_init, + .close = aac_decode_close, + .decode = latm_decode_frame, + .sample_fmts = (const enum AVSampleFormat[]) { + AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE + }, + .capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = aac_channel_layout, + .flush = flush, + .profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec_fixed.c new file mode 100644 index 0000000000..1d0142fdb0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec_fixed.c @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * AAC decoder fixed-point implementation + * + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC decoder + * @author Oded Shimon ( ods15 ods15 dyndns org ) + * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) + * + * Fixed point implementation + * @author Stanislav Ocovaj ( stanislav.ocovaj imgtec com ) + */ + +#define FFT_FLOAT 0 +#define FFT_FIXED_32 1 +#define USE_FIXED 1 + +#include "libavutil/fixed_dsp.h" +#include "libavutil/opt.h" +#include "avcodec.h" +#include "internal.h" +#include "get_bits.h" +#include "fft.h" +#include "lpc.h" +#include "kbdwin.h" +#include "sinewin.h" + +#include "aac.h" +#include "aactab.h" +#include "aacdectab.h" +#include "adts_header.h" +#include "cbrt_data.h" +#include "sbr.h" +#include "aacsbr.h" +#include "mpeg4audio.h" +#include "profiles.h" +#include "libavutil/intfloat.h" + +#include +#include + +static av_always_inline void reset_predict_state(PredictorState *ps) +{ + ps->r0.mant = 0; + ps->r0.exp = 0; + ps->r1.mant = 0; + ps->r1.exp = 0; + ps->cor0.mant = 0; + ps->cor0.exp = 0; + ps->cor1.mant = 0; + ps->cor1.exp = 0; + ps->var0.mant = 0x20000000; + ps->var0.exp = 1; + ps->var1.mant = 0x20000000; + ps->var1.exp = 1; +} + +static const int exp2tab[4] = { Q31(1.0000000000/2), Q31(1.1892071150/2), Q31(1.4142135624/2), Q31(1.6817928305/2) }; // 2^0, 2^0.25, 2^0.5, 2^0.75 + +static inline int *DEC_SPAIR(int *dst, unsigned idx) +{ + dst[0] = (idx & 15) - 4; + dst[1] = (idx >> 4 & 15) - 4; + + return dst + 2; +} + +static inline int *DEC_SQUAD(int *dst, unsigned idx) +{ + dst[0] = (idx & 3) - 1; + dst[1] = (idx >> 2 & 3) - 1; + dst[2] = (idx >> 4 & 3) - 1; + dst[3] = (idx >> 6 & 3) - 1; + + return dst + 4; +} + +static inline int *DEC_UPAIR(int *dst, unsigned idx, unsigned sign) +{ + dst[0] = (idx & 15) * (1 - (sign & 0xFFFFFFFE)); + dst[1] = (idx >> 4 & 15) * (1 - ((sign & 1) * 2)); + + return dst + 2; +} + +static inline int *DEC_UQUAD(int *dst, unsigned idx, unsigned sign) +{ + unsigned nz = idx >> 12; + + dst[0] = (idx & 3) * (1 + (((int)sign >> 31) * 2)); + sign <<= nz & 1; + nz >>= 1; + dst[1] = (idx >> 2 & 3) * (1 + (((int)sign >> 31) * 2)); + sign <<= nz & 1; + nz >>= 1; + dst[2] = (idx >> 4 & 3) * (1 + (((int)sign >> 31) * 2)); + sign <<= nz & 1; + nz >>= 1; + dst[3] = (idx >> 6 & 3) * (1 + (((int)sign >> 31) * 2)); + + return dst + 4; +} + +static void vector_pow43(int *coefs, int len) +{ + int i, coef; + + for (i=0; i> 2); + + if (s > 31) { + for (i=0; i 0) { + round = 1 << (s-1); + for (i=0; i> 32); + dst[i] = ((int)(out+round) >> s) * ssign; + } + } else if (s > -32) { + s = s + 32; + round = 1U << (s-1); + for (i=0; i> s); + dst[i] = out * (unsigned)ssign; + } + } else { + av_log(log_context, AV_LOG_ERROR, "Overflow in subband_scale()\n"); + } +} + +static void noise_scale(int *coefs, int scale, int band_energy, int len) +{ + int s = -scale; + unsigned int round; + int i, out, c = exp2tab[s & 3]; + int nlz = 0; + + av_assert0(s >= 0); + while (band_energy > 0x7fff) { + band_energy >>= 1; + nlz++; + } + c /= band_energy; + s = 21 + nlz - (s >> 2); + + if (s > 31) { + for (i=0; i= 0) { + round = s ? 1 << (s-1) : 0; + for (i=0; i> 32); + coefs[i] = -((int)(out+round) >> s); + } + } + else { + s = s + 32; + if (s > 0) { + round = 1 << (s-1); + for (i=0; i> s); + coefs[i] = -out; + } + } else { + for (i=0; i> 31; + tmp.mant = (pf.mant ^ s) - s; + tmp.mant = (tmp.mant + 0x00200000U) & 0xFFC00000U; + tmp.mant = (tmp.mant ^ s) - s; + + return tmp; +} + +static av_always_inline SoftFloat flt16_even(SoftFloat pf) +{ + SoftFloat tmp; + int s; + + tmp.exp = pf.exp; + s = pf.mant >> 31; + tmp.mant = (pf.mant ^ s) - s; + tmp.mant = (tmp.mant + 0x001FFFFFU + (tmp.mant & 0x00400000U >> 16)) & 0xFFC00000U; + tmp.mant = (tmp.mant ^ s) - s; + + return tmp; +} + +static av_always_inline SoftFloat flt16_trunc(SoftFloat pf) +{ + SoftFloat pun; + int s; + + pun.exp = pf.exp; + s = pf.mant >> 31; + pun.mant = (pf.mant ^ s) - s; + pun.mant = pun.mant & 0xFFC00000U; + pun.mant = (pun.mant ^ s) - s; + + return pun; +} + +static av_always_inline void predict(PredictorState *ps, int *coef, + int output_enable) +{ + const SoftFloat a = { 1023410176, 0 }; // 61.0 / 64 + const SoftFloat alpha = { 973078528, 0 }; // 29.0 / 32 + SoftFloat e0, e1; + SoftFloat pv; + SoftFloat k1, k2; + SoftFloat r0 = ps->r0, r1 = ps->r1; + SoftFloat cor0 = ps->cor0, cor1 = ps->cor1; + SoftFloat var0 = ps->var0, var1 = ps->var1; + SoftFloat tmp; + + if (var0.exp > 1 || (var0.exp == 1 && var0.mant > 0x20000000)) { + k1 = av_mul_sf(cor0, flt16_even(av_div_sf(a, var0))); + } + else { + k1.mant = 0; + k1.exp = 0; + } + + if (var1.exp > 1 || (var1.exp == 1 && var1.mant > 0x20000000)) { + k2 = av_mul_sf(cor1, flt16_even(av_div_sf(a, var1))); + } + else { + k2.mant = 0; + k2.exp = 0; + } + + tmp = av_mul_sf(k1, r0); + pv = flt16_round(av_add_sf(tmp, av_mul_sf(k2, r1))); + if (output_enable) { + int shift = 28 - pv.exp; + + if (shift < 31) { + if (shift > 0) { + *coef += (unsigned)((pv.mant + (1 << (shift - 1))) >> shift); + } else + *coef += (unsigned)pv.mant << -shift; + } + } + + e0 = av_int2sf(*coef, 2); + e1 = av_sub_sf(e0, tmp); + + ps->cor1 = flt16_trunc(av_add_sf(av_mul_sf(alpha, cor1), av_mul_sf(r1, e1))); + tmp = av_add_sf(av_mul_sf(r1, r1), av_mul_sf(e1, e1)); + tmp.exp--; + ps->var1 = flt16_trunc(av_add_sf(av_mul_sf(alpha, var1), tmp)); + ps->cor0 = flt16_trunc(av_add_sf(av_mul_sf(alpha, cor0), av_mul_sf(r0, e0))); + tmp = av_add_sf(av_mul_sf(r0, r0), av_mul_sf(e0, e0)); + tmp.exp--; + ps->var0 = flt16_trunc(av_add_sf(av_mul_sf(alpha, var0), tmp)); + + ps->r1 = flt16_trunc(av_mul_sf(a, av_sub_sf(r0, av_mul_sf(k1, e0)))); + ps->r0 = flt16_trunc(av_mul_sf(a, e0)); +} + + +static const int cce_scale_fixed[8] = { + Q30(1.0), //2^(0/8) + Q30(1.0905077327), //2^(1/8) + Q30(1.1892071150), //2^(2/8) + Q30(1.2968395547), //2^(3/8) + Q30(1.4142135624), //2^(4/8) + Q30(1.5422108254), //2^(5/8) + Q30(1.6817928305), //2^(6/8) + Q30(1.8340080864), //2^(7/8) +}; + +/** + * Apply dependent channel coupling (applied before IMDCT). + * + * @param index index into coupling gain array + */ +static void apply_dependent_coupling_fixed(AACContext *ac, + SingleChannelElement *target, + ChannelElement *cce, int index) +{ + IndividualChannelStream *ics = &cce->ch[0].ics; + const uint16_t *offsets = ics->swb_offset; + int *dest = target->coeffs; + const int *src = cce->ch[0].coeffs; + int g, i, group, k, idx = 0; + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) { + av_log(ac->avctx, AV_LOG_ERROR, + "Dependent coupling is not supported together with LTP\n"); + return; + } + for (g = 0; g < ics->num_window_groups; g++) { + for (i = 0; i < ics->max_sfb; i++, idx++) { + if (cce->ch[0].band_type[idx] != ZERO_BT) { + const int gain = cce->coup.gain[index][idx]; + int shift, round, c, tmp; + + if (gain < 0) { + c = -cce_scale_fixed[-gain & 7]; + shift = (-gain-1024) >> 3; + } + else { + c = cce_scale_fixed[gain & 7]; + shift = (gain-1024) >> 3; + } + + if (shift < -31) { + // Nothing to do + } else if (shift < 0) { + shift = -shift; + round = 1 << (shift - 1); + + for (group = 0; group < ics->group_len[g]; group++) { + for (k = offsets[i]; k < offsets[i + 1]; k++) { + tmp = (int)(((int64_t)src[group * 128 + k] * c + \ + (int64_t)0x1000000000) >> 37); + dest[group * 128 + k] += (tmp + (int64_t)round) >> shift; + } + } + } + else { + for (group = 0; group < ics->group_len[g]; group++) { + for (k = offsets[i]; k < offsets[i + 1]; k++) { + tmp = (int)(((int64_t)src[group * 128 + k] * c + \ + (int64_t)0x1000000000) >> 37); + dest[group * 128 + k] += tmp * (1U << shift); + } + } + } + } + } + dest += ics->group_len[g] * 128; + src += ics->group_len[g] * 128; + } +} + +/** + * Apply independent channel coupling (applied after IMDCT). + * + * @param index index into coupling gain array + */ +static void apply_independent_coupling_fixed(AACContext *ac, + SingleChannelElement *target, + ChannelElement *cce, int index) +{ + int i, c, shift, round, tmp; + const int gain = cce->coup.gain[index][0]; + const int *src = cce->ch[0].ret; + unsigned int *dest = target->ret; + const int len = 1024 << (ac->oc[1].m4ac.sbr == 1); + + c = cce_scale_fixed[gain & 7]; + shift = (gain-1024) >> 3; + if (shift < -31) { + return; + } else if (shift < 0) { + shift = -shift; + round = 1 << (shift - 1); + + for (i = 0; i < len; i++) { + tmp = (int)(((int64_t)src[i] * c + (int64_t)0x1000000000) >> 37); + dest[i] += (tmp + round) >> shift; + } + } + else { + for (i = 0; i < len; i++) { + tmp = (int)(((int64_t)src[i] * c + (int64_t)0x1000000000) >> 37); + dest[i] += tmp * (1U << shift); + } + } +} + +#include "aacdec_template.c" + +AVCodec ff_aac_fixed_decoder = { + .name = "aac_fixed", + .long_name = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_AAC, + .priv_data_size = sizeof(AACContext), + .init = aac_decode_init, + .close = aac_decode_close, + .decode = aac_decode_frame, + .sample_fmts = (const enum AVSampleFormat[]) { + AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE + }, + .capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = aac_channel_layout, + .profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), + .flush = flush, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec_template.c new file mode 100644 index 0000000000..28765c768d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdec_template.c @@ -0,0 +1,3450 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall + * Copyright (c) 2010 Janne Grunau + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC decoder + * @author Oded Shimon ( ods15 ods15 dyndns org ) + * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) + * + * AAC decoder fixed-point implementation + * @author Stanislav Ocovaj ( stanislav.ocovaj imgtec com ) + * @author Nedeljko Babic ( nedeljko.babic imgtec com ) + */ + +/* + * supported tools + * + * Support? Name + * N (code in SoC repo) gain control + * Y block switching + * Y window shapes - standard + * N window shapes - Low Delay + * Y filterbank - standard + * N (code in SoC repo) filterbank - Scalable Sample Rate + * Y Temporal Noise Shaping + * Y Long Term Prediction + * Y intensity stereo + * Y channel coupling + * Y frequency domain prediction + * Y Perceptual Noise Substitution + * Y Mid/Side stereo + * N Scalable Inverse AAC Quantization + * N Frequency Selective Switch + * N upsampling filter + * Y quantization & coding - AAC + * N quantization & coding - TwinVQ + * N quantization & coding - BSAC + * N AAC Error Resilience tools + * N Error Resilience payload syntax + * N Error Protection tool + * N CELP + * N Silence Compression + * N HVXC + * N HVXC 4kbits/s VR + * N Structured Audio tools + * N Structured Audio Sample Bank Format + * N MIDI + * N Harmonic and Individual Lines plus Noise + * N Text-To-Speech Interface + * Y Spectral Band Replication + * Y (not in this code) Layer-1 + * Y (not in this code) Layer-2 + * Y (not in this code) Layer-3 + * N SinuSoidal Coding (Transient, Sinusoid, Noise) + * Y Parametric Stereo + * N Direct Stream Transfer + * Y (not in fixed point code) Enhanced AAC Low Delay (ER AAC ELD) + * + * Note: - HE AAC v1 comprises LC AAC with Spectral Band Replication. + * - HE AAC v2 comprises LC AAC with Spectral Band Replication and + Parametric Stereo. + */ + +#include "libavutil/thread.h" + +static VLC vlc_scalefactors; +static VLC vlc_spectral[11]; + +static int output_configure(AACContext *ac, + uint8_t layout_map[MAX_ELEM_ID*4][3], int tags, + enum OCStatus oc_type, int get_new_frame); + +#define overread_err "Input buffer exhausted before END element found\n" + +static int count_channels(uint8_t (*layout)[3], int tags) +{ + int i, sum = 0; + for (i = 0; i < tags; i++) { + int syn_ele = layout[i][0]; + int pos = layout[i][2]; + sum += (1 + (syn_ele == TYPE_CPE)) * + (pos != AAC_CHANNEL_OFF && pos != AAC_CHANNEL_CC); + } + return sum; +} + +/** + * Check for the channel element in the current channel position configuration. + * If it exists, make sure the appropriate element is allocated and map the + * channel order to match the internal FFmpeg channel layout. + * + * @param che_pos current channel position configuration + * @param type channel element type + * @param id channel element id + * @param channels count of the number of channels in the configuration + * + * @return Returns error status. 0 - OK, !0 - error + */ +static av_cold int che_configure(AACContext *ac, + enum ChannelPosition che_pos, + int type, int id, int *channels) +{ + if (*channels >= MAX_CHANNELS) + return AVERROR_INVALIDDATA; + if (che_pos) { + if (!ac->che[type][id]) { + if (!(ac->che[type][id] = av_mallocz(sizeof(ChannelElement)))) + return AVERROR(ENOMEM); + AAC_RENAME(ff_aac_sbr_ctx_init)(ac, &ac->che[type][id]->sbr, type); + } + if (type != TYPE_CCE) { + if (*channels >= MAX_CHANNELS - (type == TYPE_CPE || (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1))) { + av_log(ac->avctx, AV_LOG_ERROR, "Too many channels\n"); + return AVERROR_INVALIDDATA; + } + ac->output_element[(*channels)++] = &ac->che[type][id]->ch[0]; + if (type == TYPE_CPE || + (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1)) { + ac->output_element[(*channels)++] = &ac->che[type][id]->ch[1]; + } + } + } else { + if (ac->che[type][id]) + AAC_RENAME(ff_aac_sbr_ctx_close)(&ac->che[type][id]->sbr); + av_freep(&ac->che[type][id]); + } + return 0; +} + +static int frame_configure_elements(AVCodecContext *avctx) +{ + AACContext *ac = avctx->priv_data; + int type, id, ch, ret; + + /* set channel pointers to internal buffers by default */ + for (type = 0; type < 4; type++) { + for (id = 0; id < MAX_ELEM_ID; id++) { + ChannelElement *che = ac->che[type][id]; + if (che) { + che->ch[0].ret = che->ch[0].ret_buf; + che->ch[1].ret = che->ch[1].ret_buf; + } + } + } + + /* get output buffer */ + av_frame_unref(ac->frame); + if (!avctx->channels) + return 1; + + ac->frame->nb_samples = 2048; + if ((ret = ff_get_buffer(avctx, ac->frame, 0)) < 0) + return ret; + + /* map output channel pointers to AVFrame data */ + for (ch = 0; ch < avctx->channels; ch++) { + if (ac->output_element[ch]) + ac->output_element[ch]->ret = (INTFLOAT *)ac->frame->extended_data[ch]; + } + + return 0; +} + +struct elem_to_channel { + uint64_t av_position; + uint8_t syn_ele; + uint8_t elem_id; + uint8_t aac_position; +}; + +static int assign_pair(struct elem_to_channel e2c_vec[MAX_ELEM_ID], + uint8_t (*layout_map)[3], int offset, uint64_t left, + uint64_t right, int pos) +{ + if (layout_map[offset][0] == TYPE_CPE) { + e2c_vec[offset] = (struct elem_to_channel) { + .av_position = left | right, + .syn_ele = TYPE_CPE, + .elem_id = layout_map[offset][1], + .aac_position = pos + }; + return 1; + } else { + e2c_vec[offset] = (struct elem_to_channel) { + .av_position = left, + .syn_ele = TYPE_SCE, + .elem_id = layout_map[offset][1], + .aac_position = pos + }; + e2c_vec[offset + 1] = (struct elem_to_channel) { + .av_position = right, + .syn_ele = TYPE_SCE, + .elem_id = layout_map[offset + 1][1], + .aac_position = pos + }; + return 2; + } +} + +static int count_paired_channels(uint8_t (*layout_map)[3], int tags, int pos, + int *current) +{ + int num_pos_channels = 0; + int first_cpe = 0; + int sce_parity = 0; + int i; + for (i = *current; i < tags; i++) { + if (layout_map[i][2] != pos) + break; + if (layout_map[i][0] == TYPE_CPE) { + if (sce_parity) { + if (pos == AAC_CHANNEL_FRONT && !first_cpe) { + sce_parity = 0; + } else { + return -1; + } + } + num_pos_channels += 2; + first_cpe = 1; + } else { + num_pos_channels++; + sce_parity ^= 1; + } + } + if (sce_parity && + ((pos == AAC_CHANNEL_FRONT && first_cpe) || pos == AAC_CHANNEL_SIDE)) + return -1; + *current = i; + return num_pos_channels; +} + +static uint64_t sniff_channel_order(uint8_t (*layout_map)[3], int tags) +{ + int i, n, total_non_cc_elements; + struct elem_to_channel e2c_vec[4 * MAX_ELEM_ID] = { { 0 } }; + int num_front_channels, num_side_channels, num_back_channels; + uint64_t layout; + + if (FF_ARRAY_ELEMS(e2c_vec) < tags) + return 0; + + i = 0; + num_front_channels = + count_paired_channels(layout_map, tags, AAC_CHANNEL_FRONT, &i); + if (num_front_channels < 0) + return 0; + num_side_channels = + count_paired_channels(layout_map, tags, AAC_CHANNEL_SIDE, &i); + if (num_side_channels < 0) + return 0; + num_back_channels = + count_paired_channels(layout_map, tags, AAC_CHANNEL_BACK, &i); + if (num_back_channels < 0) + return 0; + + if (num_side_channels == 0 && num_back_channels >= 4) { + num_side_channels = 2; + num_back_channels -= 2; + } + + i = 0; + if (num_front_channels & 1) { + e2c_vec[i] = (struct elem_to_channel) { + .av_position = AV_CH_FRONT_CENTER, + .syn_ele = TYPE_SCE, + .elem_id = layout_map[i][1], + .aac_position = AAC_CHANNEL_FRONT + }; + i++; + num_front_channels--; + } + if (num_front_channels >= 4) { + i += assign_pair(e2c_vec, layout_map, i, + AV_CH_FRONT_LEFT_OF_CENTER, + AV_CH_FRONT_RIGHT_OF_CENTER, + AAC_CHANNEL_FRONT); + num_front_channels -= 2; + } + if (num_front_channels >= 2) { + i += assign_pair(e2c_vec, layout_map, i, + AV_CH_FRONT_LEFT, + AV_CH_FRONT_RIGHT, + AAC_CHANNEL_FRONT); + num_front_channels -= 2; + } + while (num_front_channels >= 2) { + i += assign_pair(e2c_vec, layout_map, i, + UINT64_MAX, + UINT64_MAX, + AAC_CHANNEL_FRONT); + num_front_channels -= 2; + } + + if (num_side_channels >= 2) { + i += assign_pair(e2c_vec, layout_map, i, + AV_CH_SIDE_LEFT, + AV_CH_SIDE_RIGHT, + AAC_CHANNEL_FRONT); + num_side_channels -= 2; + } + while (num_side_channels >= 2) { + i += assign_pair(e2c_vec, layout_map, i, + UINT64_MAX, + UINT64_MAX, + AAC_CHANNEL_SIDE); + num_side_channels -= 2; + } + + while (num_back_channels >= 4) { + i += assign_pair(e2c_vec, layout_map, i, + UINT64_MAX, + UINT64_MAX, + AAC_CHANNEL_BACK); + num_back_channels -= 2; + } + if (num_back_channels >= 2) { + i += assign_pair(e2c_vec, layout_map, i, + AV_CH_BACK_LEFT, + AV_CH_BACK_RIGHT, + AAC_CHANNEL_BACK); + num_back_channels -= 2; + } + if (num_back_channels) { + e2c_vec[i] = (struct elem_to_channel) { + .av_position = AV_CH_BACK_CENTER, + .syn_ele = TYPE_SCE, + .elem_id = layout_map[i][1], + .aac_position = AAC_CHANNEL_BACK + }; + i++; + num_back_channels--; + } + + if (i < tags && layout_map[i][2] == AAC_CHANNEL_LFE) { + e2c_vec[i] = (struct elem_to_channel) { + .av_position = AV_CH_LOW_FREQUENCY, + .syn_ele = TYPE_LFE, + .elem_id = layout_map[i][1], + .aac_position = AAC_CHANNEL_LFE + }; + i++; + } + while (i < tags && layout_map[i][2] == AAC_CHANNEL_LFE) { + e2c_vec[i] = (struct elem_to_channel) { + .av_position = UINT64_MAX, + .syn_ele = TYPE_LFE, + .elem_id = layout_map[i][1], + .aac_position = AAC_CHANNEL_LFE + }; + i++; + } + + // Must choose a stable sort + total_non_cc_elements = n = i; + do { + int next_n = 0; + for (i = 1; i < n; i++) + if (e2c_vec[i - 1].av_position > e2c_vec[i].av_position) { + FFSWAP(struct elem_to_channel, e2c_vec[i - 1], e2c_vec[i]); + next_n = i; + } + n = next_n; + } while (n > 0); + + layout = 0; + for (i = 0; i < total_non_cc_elements; i++) { + layout_map[i][0] = e2c_vec[i].syn_ele; + layout_map[i][1] = e2c_vec[i].elem_id; + layout_map[i][2] = e2c_vec[i].aac_position; + if (e2c_vec[i].av_position != UINT64_MAX) { + layout |= e2c_vec[i].av_position; + } + } + + return layout; +} + +/** + * Save current output configuration if and only if it has been locked. + */ +static int push_output_configuration(AACContext *ac) { + int pushed = 0; + + if (ac->oc[1].status == OC_LOCKED || ac->oc[0].status == OC_NONE) { + ac->oc[0] = ac->oc[1]; + pushed = 1; + } + ac->oc[1].status = OC_NONE; + return pushed; +} + +/** + * Restore the previous output configuration if and only if the current + * configuration is unlocked. + */ +static void pop_output_configuration(AACContext *ac) { + if (ac->oc[1].status != OC_LOCKED && ac->oc[0].status != OC_NONE) { + ac->oc[1] = ac->oc[0]; + ac->avctx->channels = ac->oc[1].channels; + ac->avctx->channel_layout = ac->oc[1].channel_layout; + output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags, + ac->oc[1].status, 0); + } +} + +/** + * Configure output channel order based on the current program + * configuration element. + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int output_configure(AACContext *ac, + uint8_t layout_map[MAX_ELEM_ID * 4][3], int tags, + enum OCStatus oc_type, int get_new_frame) +{ + AVCodecContext *avctx = ac->avctx; + int i, channels = 0, ret; + uint64_t layout = 0; + uint8_t id_map[TYPE_END][MAX_ELEM_ID] = {{ 0 }}; + uint8_t type_counts[TYPE_END] = { 0 }; + + if (ac->oc[1].layout_map != layout_map) { + memcpy(ac->oc[1].layout_map, layout_map, tags * sizeof(layout_map[0])); + ac->oc[1].layout_map_tags = tags; + } + for (i = 0; i < tags; i++) { + int type = layout_map[i][0]; + int id = layout_map[i][1]; + id_map[type][id] = type_counts[type]++; + if (id_map[type][id] >= MAX_ELEM_ID) { + avpriv_request_sample(ac->avctx, "Too large remapped id"); + return AVERROR_PATCHWELCOME; + } + } + // Try to sniff a reasonable channel order, otherwise output the + // channels in the order the PCE declared them. + if (avctx->request_channel_layout != AV_CH_LAYOUT_NATIVE) + layout = sniff_channel_order(layout_map, tags); + for (i = 0; i < tags; i++) { + int type = layout_map[i][0]; + int id = layout_map[i][1]; + int iid = id_map[type][id]; + int position = layout_map[i][2]; + // Allocate or free elements depending on if they are in the + // current program configuration. + ret = che_configure(ac, position, type, iid, &channels); + if (ret < 0) + return ret; + ac->tag_che_map[type][id] = ac->che[type][iid]; + } + if (ac->oc[1].m4ac.ps == 1 && channels == 2) { + if (layout == AV_CH_FRONT_CENTER) { + layout = AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT; + } else { + layout = 0; + } + } + + if (layout) avctx->channel_layout = layout; + ac->oc[1].channel_layout = layout; + avctx->channels = ac->oc[1].channels = channels; + ac->oc[1].status = oc_type; + + if (get_new_frame) { + if ((ret = frame_configure_elements(ac->avctx)) < 0) + return ret; + } + + return 0; +} + +static void flush(AVCodecContext *avctx) +{ + AACContext *ac= avctx->priv_data; + int type, i, j; + + for (type = 3; type >= 0; type--) { + for (i = 0; i < MAX_ELEM_ID; i++) { + ChannelElement *che = ac->che[type][i]; + if (che) { + for (j = 0; j <= 1; j++) { + memset(che->ch[j].saved, 0, sizeof(che->ch[j].saved)); + } + } + } + } +} + +/** + * Set up channel positions based on a default channel configuration + * as specified in table 1.17. + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int set_default_channel_config(AVCodecContext *avctx, + uint8_t (*layout_map)[3], + int *tags, + int channel_config) +{ + if (channel_config < 1 || (channel_config > 7 && channel_config < 11) || + channel_config > 12) { + av_log(avctx, AV_LOG_ERROR, + "invalid default channel configuration (%d)\n", + channel_config); + return AVERROR_INVALIDDATA; + } + *tags = tags_per_config[channel_config]; + memcpy(layout_map, aac_channel_layout_map[channel_config - 1], + *tags * sizeof(*layout_map)); + + /* + * AAC specification has 7.1(wide) as a default layout for 8-channel streams. + * However, at least Nero AAC encoder encodes 7.1 streams using the default + * channel config 7, mapping the side channels of the original audio stream + * to the second AAC_CHANNEL_FRONT pair in the AAC stream. Similarly, e.g. FAAD + * decodes the second AAC_CHANNEL_FRONT pair as side channels, therefore decoding + * the incorrect streams as if they were correct (and as the encoder intended). + * + * As actual intended 7.1(wide) streams are very rare, default to assuming a + * 7.1 layout was intended. + */ + if (channel_config == 7 && avctx->strict_std_compliance < FF_COMPLIANCE_STRICT) { + av_log(avctx, AV_LOG_INFO, "Assuming an incorrectly encoded 7.1 channel layout" + " instead of a spec-compliant 7.1(wide) layout, use -strict %d to decode" + " according to the specification instead.\n", FF_COMPLIANCE_STRICT); + layout_map[2][2] = AAC_CHANNEL_SIDE; + } + + return 0; +} + +static ChannelElement *get_che(AACContext *ac, int type, int elem_id) +{ + /* For PCE based channel configurations map the channels solely based + * on tags. */ + if (!ac->oc[1].m4ac.chan_config) { + return ac->tag_che_map[type][elem_id]; + } + // Allow single CPE stereo files to be signalled with mono configuration. + if (!ac->tags_mapped && type == TYPE_CPE && + ac->oc[1].m4ac.chan_config == 1) { + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int layout_map_tags; + push_output_configuration(ac); + + av_log(ac->avctx, AV_LOG_DEBUG, "mono with CPE\n"); + + if (set_default_channel_config(ac->avctx, layout_map, + &layout_map_tags, 2) < 0) + return NULL; + if (output_configure(ac, layout_map, layout_map_tags, + OC_TRIAL_FRAME, 1) < 0) + return NULL; + + ac->oc[1].m4ac.chan_config = 2; + ac->oc[1].m4ac.ps = 0; + } + // And vice-versa + if (!ac->tags_mapped && type == TYPE_SCE && + ac->oc[1].m4ac.chan_config == 2) { + uint8_t layout_map[MAX_ELEM_ID * 4][3]; + int layout_map_tags; + push_output_configuration(ac); + + av_log(ac->avctx, AV_LOG_DEBUG, "stereo with SCE\n"); + + if (set_default_channel_config(ac->avctx, layout_map, + &layout_map_tags, 1) < 0) + return NULL; + if (output_configure(ac, layout_map, layout_map_tags, + OC_TRIAL_FRAME, 1) < 0) + return NULL; + + ac->oc[1].m4ac.chan_config = 1; + if (ac->oc[1].m4ac.sbr) + ac->oc[1].m4ac.ps = -1; + } + /* For indexed channel configurations map the channels solely based + * on position. */ + switch (ac->oc[1].m4ac.chan_config) { + case 12: + case 7: + if (ac->tags_mapped == 3 && type == TYPE_CPE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][2]; + } + case 11: + if (ac->tags_mapped == 2 && + ac->oc[1].m4ac.chan_config == 11 && + type == TYPE_SCE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1]; + } + case 6: + /* Some streams incorrectly code 5.1 audio as + * SCE[0] CPE[0] CPE[1] SCE[1] + * instead of + * SCE[0] CPE[0] CPE[1] LFE[0]. + * If we seem to have encountered such a stream, transfer + * the LFE[0] element to the SCE[1]'s mapping */ + if (ac->tags_mapped == tags_per_config[ac->oc[1].m4ac.chan_config] - 1 && (type == TYPE_LFE || type == TYPE_SCE)) { + if (!ac->warned_remapping_once && (type != TYPE_LFE || elem_id != 0)) { + av_log(ac->avctx, AV_LOG_WARNING, + "This stream seems to incorrectly report its last channel as %s[%d], mapping to LFE[0]\n", + type == TYPE_SCE ? "SCE" : "LFE", elem_id); + ac->warned_remapping_once++; + } + ac->tags_mapped++; + return ac->tag_che_map[type][elem_id] = ac->che[TYPE_LFE][0]; + } + case 5: + if (ac->tags_mapped == 2 && type == TYPE_CPE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][1]; + } + case 4: + /* Some streams incorrectly code 4.0 audio as + * SCE[0] CPE[0] LFE[0] + * instead of + * SCE[0] CPE[0] SCE[1]. + * If we seem to have encountered such a stream, transfer + * the SCE[1] element to the LFE[0]'s mapping */ + if (ac->tags_mapped == tags_per_config[ac->oc[1].m4ac.chan_config] - 1 && (type == TYPE_LFE || type == TYPE_SCE)) { + if (!ac->warned_remapping_once && (type != TYPE_SCE || elem_id != 1)) { + av_log(ac->avctx, AV_LOG_WARNING, + "This stream seems to incorrectly report its last channel as %s[%d], mapping to SCE[1]\n", + type == TYPE_SCE ? "SCE" : "LFE", elem_id); + ac->warned_remapping_once++; + } + ac->tags_mapped++; + return ac->tag_che_map[type][elem_id] = ac->che[TYPE_SCE][1]; + } + if (ac->tags_mapped == 2 && + ac->oc[1].m4ac.chan_config == 4 && + type == TYPE_SCE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1]; + } + case 3: + case 2: + if (ac->tags_mapped == (ac->oc[1].m4ac.chan_config != 2) && + type == TYPE_CPE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][0]; + } else if (ac->oc[1].m4ac.chan_config == 2) { + return NULL; + } + case 1: + if (!ac->tags_mapped && type == TYPE_SCE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][0]; + } + default: + return NULL; + } +} + +/** + * Decode an array of 4 bit element IDs, optionally interleaved with a + * stereo/mono switching bit. + * + * @param type speaker type/position for these channels + */ +static void decode_channel_map(uint8_t layout_map[][3], + enum ChannelPosition type, + GetBitContext *gb, int n) +{ + while (n--) { + enum RawDataBlockType syn_ele; + switch (type) { + case AAC_CHANNEL_FRONT: + case AAC_CHANNEL_BACK: + case AAC_CHANNEL_SIDE: + syn_ele = get_bits1(gb); + break; + case AAC_CHANNEL_CC: + skip_bits1(gb); + syn_ele = TYPE_CCE; + break; + case AAC_CHANNEL_LFE: + syn_ele = TYPE_LFE; + break; + default: + // AAC_CHANNEL_OFF has no channel map + av_assert0(0); + } + layout_map[0][0] = syn_ele; + layout_map[0][1] = get_bits(gb, 4); + layout_map[0][2] = type; + layout_map++; + } +} + +static inline void relative_align_get_bits(GetBitContext *gb, + int reference_position) { + int n = (reference_position - get_bits_count(gb) & 7); + if (n) + skip_bits(gb, n); +} + +/** + * Decode program configuration element; reference: table 4.2. + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac, + uint8_t (*layout_map)[3], + GetBitContext *gb, int byte_align_ref) +{ + int num_front, num_side, num_back, num_lfe, num_assoc_data, num_cc; + int sampling_index; + int comment_len; + int tags; + + skip_bits(gb, 2); // object_type + + sampling_index = get_bits(gb, 4); + if (m4ac->sampling_index != sampling_index) + av_log(avctx, AV_LOG_WARNING, + "Sample rate index in program config element does not " + "match the sample rate index configured by the container.\n"); + + num_front = get_bits(gb, 4); + num_side = get_bits(gb, 4); + num_back = get_bits(gb, 4); + num_lfe = get_bits(gb, 2); + num_assoc_data = get_bits(gb, 3); + num_cc = get_bits(gb, 4); + + if (get_bits1(gb)) + skip_bits(gb, 4); // mono_mixdown_tag + if (get_bits1(gb)) + skip_bits(gb, 4); // stereo_mixdown_tag + + if (get_bits1(gb)) + skip_bits(gb, 3); // mixdown_coeff_index and pseudo_surround + + if (get_bits_left(gb) < 5 * (num_front + num_side + num_back + num_cc) + 4 *(num_lfe + num_assoc_data + num_cc)) { + av_log(avctx, AV_LOG_ERROR, "decode_pce: " overread_err); + return -1; + } + decode_channel_map(layout_map , AAC_CHANNEL_FRONT, gb, num_front); + tags = num_front; + decode_channel_map(layout_map + tags, AAC_CHANNEL_SIDE, gb, num_side); + tags += num_side; + decode_channel_map(layout_map + tags, AAC_CHANNEL_BACK, gb, num_back); + tags += num_back; + decode_channel_map(layout_map + tags, AAC_CHANNEL_LFE, gb, num_lfe); + tags += num_lfe; + + skip_bits_long(gb, 4 * num_assoc_data); + + decode_channel_map(layout_map + tags, AAC_CHANNEL_CC, gb, num_cc); + tags += num_cc; + + relative_align_get_bits(gb, byte_align_ref); + + /* comment field, first byte is length */ + comment_len = get_bits(gb, 8) * 8; + if (get_bits_left(gb) < comment_len) { + av_log(avctx, AV_LOG_ERROR, "decode_pce: " overread_err); + return AVERROR_INVALIDDATA; + } + skip_bits_long(gb, comment_len); + return tags; +} + +/** + * Decode GA "General Audio" specific configuration; reference: table 4.1. + * + * @param ac pointer to AACContext, may be null + * @param avctx pointer to AVCCodecContext, used for logging + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_ga_specific_config(AACContext *ac, AVCodecContext *avctx, + GetBitContext *gb, + int get_bit_alignment, + MPEG4AudioConfig *m4ac, + int channel_config) +{ + int extension_flag, ret, ep_config, res_flags; + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int tags = 0; + +#if USE_FIXED + if (get_bits1(gb)) { // frameLengthFlag + avpriv_report_missing_feature(avctx, "Fixed point 960/120 MDCT window"); + return AVERROR_PATCHWELCOME; + } + m4ac->frame_length_short = 0; +#else + m4ac->frame_length_short = get_bits1(gb); + if (m4ac->frame_length_short && m4ac->sbr == 1) { + avpriv_report_missing_feature(avctx, "SBR with 960 frame length"); + if (ac) ac->warned_960_sbr = 1; + m4ac->sbr = 0; + m4ac->ps = 0; + } +#endif + + if (get_bits1(gb)) // dependsOnCoreCoder + skip_bits(gb, 14); // coreCoderDelay + extension_flag = get_bits1(gb); + + if (m4ac->object_type == AOT_AAC_SCALABLE || + m4ac->object_type == AOT_ER_AAC_SCALABLE) + skip_bits(gb, 3); // layerNr + + if (channel_config == 0) { + skip_bits(gb, 4); // element_instance_tag + tags = decode_pce(avctx, m4ac, layout_map, gb, get_bit_alignment); + if (tags < 0) + return tags; + } else { + if ((ret = set_default_channel_config(avctx, layout_map, + &tags, channel_config))) + return ret; + } + + if (count_channels(layout_map, tags) > 1) { + m4ac->ps = 0; + } else if (m4ac->sbr == 1 && m4ac->ps == -1) + m4ac->ps = 1; + + if (ac && (ret = output_configure(ac, layout_map, tags, OC_GLOBAL_HDR, 0))) + return ret; + + if (extension_flag) { + switch (m4ac->object_type) { + case AOT_ER_BSAC: + skip_bits(gb, 5); // numOfSubFrame + skip_bits(gb, 11); // layer_length + break; + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LTP: + case AOT_ER_AAC_SCALABLE: + case AOT_ER_AAC_LD: + res_flags = get_bits(gb, 3); + if (res_flags) { + avpriv_report_missing_feature(avctx, + "AAC data resilience (flags %x)", + res_flags); + return AVERROR_PATCHWELCOME; + } + break; + } + skip_bits1(gb); // extensionFlag3 (TBD in version 3) + } + switch (m4ac->object_type) { + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LTP: + case AOT_ER_AAC_SCALABLE: + case AOT_ER_AAC_LD: + ep_config = get_bits(gb, 2); + if (ep_config) { + avpriv_report_missing_feature(avctx, + "epConfig %d", ep_config); + return AVERROR_PATCHWELCOME; + } + } + return 0; +} + +static int decode_eld_specific_config(AACContext *ac, AVCodecContext *avctx, + GetBitContext *gb, + MPEG4AudioConfig *m4ac, + int channel_config) +{ + int ret, ep_config, res_flags; + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int tags = 0; + const int ELDEXT_TERM = 0; + + m4ac->ps = 0; + m4ac->sbr = 0; +#if USE_FIXED + if (get_bits1(gb)) { // frameLengthFlag + avpriv_request_sample(avctx, "960/120 MDCT window"); + return AVERROR_PATCHWELCOME; + } +#else + m4ac->frame_length_short = get_bits1(gb); +#endif + res_flags = get_bits(gb, 3); + if (res_flags) { + avpriv_report_missing_feature(avctx, + "AAC data resilience (flags %x)", + res_flags); + return AVERROR_PATCHWELCOME; + } + + if (get_bits1(gb)) { // ldSbrPresentFlag + avpriv_report_missing_feature(avctx, + "Low Delay SBR"); + return AVERROR_PATCHWELCOME; + } + + while (get_bits(gb, 4) != ELDEXT_TERM) { + int len = get_bits(gb, 4); + if (len == 15) + len += get_bits(gb, 8); + if (len == 15 + 255) + len += get_bits(gb, 16); + if (get_bits_left(gb) < len * 8 + 4) { + av_log(avctx, AV_LOG_ERROR, overread_err); + return AVERROR_INVALIDDATA; + } + skip_bits_long(gb, 8 * len); + } + + if ((ret = set_default_channel_config(avctx, layout_map, + &tags, channel_config))) + return ret; + + if (ac && (ret = output_configure(ac, layout_map, tags, OC_GLOBAL_HDR, 0))) + return ret; + + ep_config = get_bits(gb, 2); + if (ep_config) { + avpriv_report_missing_feature(avctx, + "epConfig %d", ep_config); + return AVERROR_PATCHWELCOME; + } + return 0; +} + +/** + * Decode audio specific configuration; reference: table 1.13. + * + * @param ac pointer to AACContext, may be null + * @param avctx pointer to AVCCodecContext, used for logging + * @param m4ac pointer to MPEG4AudioConfig, used for parsing + * @param gb buffer holding an audio specific config + * @param get_bit_alignment relative alignment for byte align operations + * @param sync_extension look for an appended sync extension + * + * @return Returns error status or number of consumed bits. <0 - error + */ +static int decode_audio_specific_config_gb(AACContext *ac, + AVCodecContext *avctx, + MPEG4AudioConfig *m4ac, + GetBitContext *gb, + int get_bit_alignment, + int sync_extension) +{ + int i, ret; + GetBitContext gbc = *gb; + + if ((i = ff_mpeg4audio_get_config_gb(m4ac, &gbc, sync_extension)) < 0) + return AVERROR_INVALIDDATA; + + if (m4ac->sampling_index > 12) { + av_log(avctx, AV_LOG_ERROR, + "invalid sampling rate index %d\n", + m4ac->sampling_index); + return AVERROR_INVALIDDATA; + } + if (m4ac->object_type == AOT_ER_AAC_LD && + (m4ac->sampling_index < 3 || m4ac->sampling_index > 7)) { + av_log(avctx, AV_LOG_ERROR, + "invalid low delay sampling rate index %d\n", + m4ac->sampling_index); + return AVERROR_INVALIDDATA; + } + + skip_bits_long(gb, i); + + switch (m4ac->object_type) { + case AOT_AAC_MAIN: + case AOT_AAC_LC: + case AOT_AAC_SSR: + case AOT_AAC_LTP: + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LD: + if ((ret = decode_ga_specific_config(ac, avctx, gb, get_bit_alignment, + m4ac, m4ac->chan_config)) < 0) + return ret; + break; + case AOT_ER_AAC_ELD: + if ((ret = decode_eld_specific_config(ac, avctx, gb, + m4ac, m4ac->chan_config)) < 0) + return ret; + break; + default: + avpriv_report_missing_feature(avctx, + "Audio object type %s%d", + m4ac->sbr == 1 ? "SBR+" : "", + m4ac->object_type); + return AVERROR(ENOSYS); + } + + ff_dlog(avctx, + "AOT %d chan config %d sampling index %d (%d) SBR %d PS %d\n", + m4ac->object_type, m4ac->chan_config, m4ac->sampling_index, + m4ac->sample_rate, m4ac->sbr, + m4ac->ps); + + return get_bits_count(gb); +} + +static int decode_audio_specific_config(AACContext *ac, + AVCodecContext *avctx, + MPEG4AudioConfig *m4ac, + const uint8_t *data, int64_t bit_size, + int sync_extension) +{ + int i, ret; + GetBitContext gb; + + if (bit_size < 0 || bit_size > INT_MAX) { + av_log(avctx, AV_LOG_ERROR, "Audio specific config size is invalid\n"); + return AVERROR_INVALIDDATA; + } + + ff_dlog(avctx, "audio specific config size %d\n", (int)bit_size >> 3); + for (i = 0; i < bit_size >> 3; i++) + ff_dlog(avctx, "%02x ", data[i]); + ff_dlog(avctx, "\n"); + + if ((ret = init_get_bits(&gb, data, bit_size)) < 0) + return ret; + + return decode_audio_specific_config_gb(ac, avctx, m4ac, &gb, 0, + sync_extension); +} + +/** + * linear congruential pseudorandom number generator + * + * @param previous_val pointer to the current state of the generator + * + * @return Returns a 32-bit pseudorandom integer + */ +static av_always_inline int lcg_random(unsigned previous_val) +{ + union { unsigned u; int s; } v = { previous_val * 1664525u + 1013904223 }; + return v.s; +} + +static void reset_all_predictors(PredictorState *ps) +{ + int i; + for (i = 0; i < MAX_PREDICTORS; i++) + reset_predict_state(&ps[i]); +} + +static int sample_rate_idx (int rate) +{ + if (92017 <= rate) return 0; + else if (75132 <= rate) return 1; + else if (55426 <= rate) return 2; + else if (46009 <= rate) return 3; + else if (37566 <= rate) return 4; + else if (27713 <= rate) return 5; + else if (23004 <= rate) return 6; + else if (18783 <= rate) return 7; + else if (13856 <= rate) return 8; + else if (11502 <= rate) return 9; + else if (9391 <= rate) return 10; + else return 11; +} + +static void reset_predictor_group(PredictorState *ps, int group_num) +{ + int i; + for (i = group_num - 1; i < MAX_PREDICTORS; i += 30) + reset_predict_state(&ps[i]); +} + +#define AAC_INIT_VLC_STATIC(num, size) \ + INIT_VLC_STATIC(&vlc_spectral[num], 8, ff_aac_spectral_sizes[num], \ + ff_aac_spectral_bits[num], sizeof(ff_aac_spectral_bits[num][0]), \ + sizeof(ff_aac_spectral_bits[num][0]), \ + ff_aac_spectral_codes[num], sizeof(ff_aac_spectral_codes[num][0]), \ + sizeof(ff_aac_spectral_codes[num][0]), \ + size); + +static void aacdec_init(AACContext *ac); + +static av_cold void aac_static_table_init(void) +{ + AAC_INIT_VLC_STATIC( 0, 304); + AAC_INIT_VLC_STATIC( 1, 270); + AAC_INIT_VLC_STATIC( 2, 550); + AAC_INIT_VLC_STATIC( 3, 300); + AAC_INIT_VLC_STATIC( 4, 328); + AAC_INIT_VLC_STATIC( 5, 294); + AAC_INIT_VLC_STATIC( 6, 306); + AAC_INIT_VLC_STATIC( 7, 268); + AAC_INIT_VLC_STATIC( 8, 510); + AAC_INIT_VLC_STATIC( 9, 366); + AAC_INIT_VLC_STATIC(10, 462); + + AAC_RENAME(ff_aac_sbr_init)(); + + ff_aac_tableinit(); + + INIT_VLC_STATIC(&vlc_scalefactors, 7, + FF_ARRAY_ELEMS(ff_aac_scalefactor_code), + ff_aac_scalefactor_bits, + sizeof(ff_aac_scalefactor_bits[0]), + sizeof(ff_aac_scalefactor_bits[0]), + ff_aac_scalefactor_code, + sizeof(ff_aac_scalefactor_code[0]), + sizeof(ff_aac_scalefactor_code[0]), + 352); + + // window initialization + AAC_RENAME(ff_kbd_window_init)(AAC_RENAME(ff_aac_kbd_long_1024), 4.0, 1024); + AAC_RENAME(ff_kbd_window_init)(AAC_RENAME(ff_aac_kbd_short_128), 6.0, 128); +#if !USE_FIXED + AAC_RENAME(ff_kbd_window_init)(AAC_RENAME(ff_aac_kbd_long_960), 4.0, 960); + AAC_RENAME(ff_kbd_window_init)(AAC_RENAME(ff_aac_kbd_short_120), 6.0, 120); + AAC_RENAME(ff_sine_window_init)(AAC_RENAME(ff_sine_960), 960); + AAC_RENAME(ff_sine_window_init)(AAC_RENAME(ff_sine_120), 120); +#endif + AAC_RENAME(ff_init_ff_sine_windows)(10); + AAC_RENAME(ff_init_ff_sine_windows)( 9); + AAC_RENAME(ff_init_ff_sine_windows)( 7); + + AAC_RENAME(ff_cbrt_tableinit)(); +} + +static AVOnce aac_table_init = AV_ONCE_INIT; + +static av_cold int aac_decode_init(AVCodecContext *avctx) +{ + AACContext *ac = avctx->priv_data; + int ret; + + ret = ff_thread_once(&aac_table_init, &aac_static_table_init); + if (ret != 0) + return AVERROR_UNKNOWN; + + ac->avctx = avctx; + ac->oc[1].m4ac.sample_rate = avctx->sample_rate; + + aacdec_init(ac); +#if USE_FIXED + avctx->sample_fmt = AV_SAMPLE_FMT_S32P; +#else + avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; +#endif /* USE_FIXED */ + + if (avctx->extradata_size > 0) { + if ((ret = decode_audio_specific_config(ac, ac->avctx, &ac->oc[1].m4ac, + avctx->extradata, + avctx->extradata_size * 8LL, + 1)) < 0) + return ret; + } else { + int sr, i; + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int layout_map_tags; + + sr = sample_rate_idx(avctx->sample_rate); + ac->oc[1].m4ac.sampling_index = sr; + ac->oc[1].m4ac.channels = avctx->channels; + ac->oc[1].m4ac.sbr = -1; + ac->oc[1].m4ac.ps = -1; + + for (i = 0; i < FF_ARRAY_ELEMS(ff_mpeg4audio_channels); i++) + if (ff_mpeg4audio_channels[i] == avctx->channels) + break; + if (i == FF_ARRAY_ELEMS(ff_mpeg4audio_channels)) { + i = 0; + } + ac->oc[1].m4ac.chan_config = i; + + if (ac->oc[1].m4ac.chan_config) { + int ret = set_default_channel_config(avctx, layout_map, + &layout_map_tags, ac->oc[1].m4ac.chan_config); + if (!ret) + output_configure(ac, layout_map, layout_map_tags, + OC_GLOBAL_HDR, 0); + else if (avctx->err_recognition & AV_EF_EXPLODE) + return AVERROR_INVALIDDATA; + } + } + + if (avctx->channels > MAX_CHANNELS) { + av_log(avctx, AV_LOG_ERROR, "Too many channels\n"); + return AVERROR_INVALIDDATA; + } + +#if USE_FIXED + ac->fdsp = avpriv_alloc_fixed_dsp(avctx->flags & AV_CODEC_FLAG_BITEXACT); +#else + ac->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); +#endif /* USE_FIXED */ + if (!ac->fdsp) { + return AVERROR(ENOMEM); + } + + ac->random_state = 0x1f2e3d4c; + + AAC_RENAME_32(ff_mdct_init)(&ac->mdct, 11, 1, 1.0 / RANGE15(1024.0)); + AAC_RENAME_32(ff_mdct_init)(&ac->mdct_ld, 10, 1, 1.0 / RANGE15(512.0)); + AAC_RENAME_32(ff_mdct_init)(&ac->mdct_small, 8, 1, 1.0 / RANGE15(128.0)); + AAC_RENAME_32(ff_mdct_init)(&ac->mdct_ltp, 11, 0, RANGE15(-2.0)); +#if !USE_FIXED + ret = ff_mdct15_init(&ac->mdct120, 1, 3, 1.0f/(16*1024*120*2)); + if (ret < 0) + return ret; + ret = ff_mdct15_init(&ac->mdct480, 1, 5, 1.0f/(16*1024*960)); + if (ret < 0) + return ret; + ret = ff_mdct15_init(&ac->mdct960, 1, 6, 1.0f/(16*1024*960*2)); + if (ret < 0) + return ret; +#endif + + return 0; +} + +/** + * Skip data_stream_element; reference: table 4.10. + */ +static int skip_data_stream_element(AACContext *ac, GetBitContext *gb) +{ + int byte_align = get_bits1(gb); + int count = get_bits(gb, 8); + if (count == 255) + count += get_bits(gb, 8); + if (byte_align) + align_get_bits(gb); + + if (get_bits_left(gb) < 8 * count) { + av_log(ac->avctx, AV_LOG_ERROR, "skip_data_stream_element: "overread_err); + return AVERROR_INVALIDDATA; + } + skip_bits_long(gb, 8 * count); + return 0; +} + +static int decode_prediction(AACContext *ac, IndividualChannelStream *ics, + GetBitContext *gb) +{ + int sfb; + if (get_bits1(gb)) { + ics->predictor_reset_group = get_bits(gb, 5); + if (ics->predictor_reset_group == 0 || + ics->predictor_reset_group > 30) { + av_log(ac->avctx, AV_LOG_ERROR, + "Invalid Predictor Reset Group.\n"); + return AVERROR_INVALIDDATA; + } + } + for (sfb = 0; sfb < FFMIN(ics->max_sfb, ff_aac_pred_sfb_max[ac->oc[1].m4ac.sampling_index]); sfb++) { + ics->prediction_used[sfb] = get_bits1(gb); + } + return 0; +} + +/** + * Decode Long Term Prediction data; reference: table 4.xx. + */ +static void decode_ltp(LongTermPrediction *ltp, + GetBitContext *gb, uint8_t max_sfb) +{ + int sfb; + + ltp->lag = get_bits(gb, 11); + ltp->coef = ltp_coef[get_bits(gb, 3)]; + for (sfb = 0; sfb < FFMIN(max_sfb, MAX_LTP_LONG_SFB); sfb++) + ltp->used[sfb] = get_bits1(gb); +} + +/** + * Decode Individual Channel Stream info; reference: table 4.6. + */ +static int decode_ics_info(AACContext *ac, IndividualChannelStream *ics, + GetBitContext *gb) +{ + const MPEG4AudioConfig *const m4ac = &ac->oc[1].m4ac; + const int aot = m4ac->object_type; + const int sampling_index = m4ac->sampling_index; + int ret_fail = AVERROR_INVALIDDATA; + + if (aot != AOT_ER_AAC_ELD) { + if (get_bits1(gb)) { + av_log(ac->avctx, AV_LOG_ERROR, "Reserved bit set.\n"); + if (ac->avctx->err_recognition & AV_EF_BITSTREAM) + return AVERROR_INVALIDDATA; + } + ics->window_sequence[1] = ics->window_sequence[0]; + ics->window_sequence[0] = get_bits(gb, 2); + if (aot == AOT_ER_AAC_LD && + ics->window_sequence[0] != ONLY_LONG_SEQUENCE) { + av_log(ac->avctx, AV_LOG_ERROR, + "AAC LD is only defined for ONLY_LONG_SEQUENCE but " + "window sequence %d found.\n", ics->window_sequence[0]); + ics->window_sequence[0] = ONLY_LONG_SEQUENCE; + return AVERROR_INVALIDDATA; + } + ics->use_kb_window[1] = ics->use_kb_window[0]; + ics->use_kb_window[0] = get_bits1(gb); + } + ics->num_window_groups = 1; + ics->group_len[0] = 1; + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + int i; + ics->max_sfb = get_bits(gb, 4); + for (i = 0; i < 7; i++) { + if (get_bits1(gb)) { + ics->group_len[ics->num_window_groups - 1]++; + } else { + ics->num_window_groups++; + ics->group_len[ics->num_window_groups - 1] = 1; + } + } + ics->num_windows = 8; + if (m4ac->frame_length_short) { + ics->swb_offset = ff_swb_offset_120[sampling_index]; + ics->num_swb = ff_aac_num_swb_120[sampling_index]; + } else { + ics->swb_offset = ff_swb_offset_128[sampling_index]; + ics->num_swb = ff_aac_num_swb_128[sampling_index]; + } + ics->tns_max_bands = ff_tns_max_bands_128[sampling_index]; + ics->predictor_present = 0; + } else { + ics->max_sfb = get_bits(gb, 6); + ics->num_windows = 1; + if (aot == AOT_ER_AAC_LD || aot == AOT_ER_AAC_ELD) { + if (m4ac->frame_length_short) { + ics->swb_offset = ff_swb_offset_480[sampling_index]; + ics->num_swb = ff_aac_num_swb_480[sampling_index]; + ics->tns_max_bands = ff_tns_max_bands_480[sampling_index]; + } else { + ics->swb_offset = ff_swb_offset_512[sampling_index]; + ics->num_swb = ff_aac_num_swb_512[sampling_index]; + ics->tns_max_bands = ff_tns_max_bands_512[sampling_index]; + } + if (!ics->num_swb || !ics->swb_offset) { + ret_fail = AVERROR_BUG; + goto fail; + } + } else { + if (m4ac->frame_length_short) { + ics->num_swb = ff_aac_num_swb_960[sampling_index]; + ics->swb_offset = ff_swb_offset_960[sampling_index]; + } else { + ics->num_swb = ff_aac_num_swb_1024[sampling_index]; + ics->swb_offset = ff_swb_offset_1024[sampling_index]; + } + ics->tns_max_bands = ff_tns_max_bands_1024[sampling_index]; + } + if (aot != AOT_ER_AAC_ELD) { + ics->predictor_present = get_bits1(gb); + ics->predictor_reset_group = 0; + } + if (ics->predictor_present) { + if (aot == AOT_AAC_MAIN) { + if (decode_prediction(ac, ics, gb)) { + goto fail; + } + } else if (aot == AOT_AAC_LC || + aot == AOT_ER_AAC_LC) { + av_log(ac->avctx, AV_LOG_ERROR, + "Prediction is not allowed in AAC-LC.\n"); + goto fail; + } else { + if (aot == AOT_ER_AAC_LD) { + av_log(ac->avctx, AV_LOG_ERROR, + "LTP in ER AAC LD not yet implemented.\n"); + ret_fail = AVERROR_PATCHWELCOME; + goto fail; + } + if ((ics->ltp.present = get_bits(gb, 1))) + decode_ltp(&ics->ltp, gb, ics->max_sfb); + } + } + } + + if (ics->max_sfb > ics->num_swb) { + av_log(ac->avctx, AV_LOG_ERROR, + "Number of scalefactor bands in group (%d) " + "exceeds limit (%d).\n", + ics->max_sfb, ics->num_swb); + goto fail; + } + + return 0; +fail: + ics->max_sfb = 0; + return ret_fail; +} + +/** + * Decode band types (section_data payload); reference: table 4.46. + * + * @param band_type array of the used band type + * @param band_type_run_end array of the last scalefactor band of a band type run + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_band_types(AACContext *ac, enum BandType band_type[120], + int band_type_run_end[120], GetBitContext *gb, + IndividualChannelStream *ics) +{ + int g, idx = 0; + const int bits = (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) ? 3 : 5; + for (g = 0; g < ics->num_window_groups; g++) { + int k = 0; + while (k < ics->max_sfb) { + uint8_t sect_end = k; + int sect_len_incr; + int sect_band_type = get_bits(gb, 4); + if (sect_band_type == 12) { + av_log(ac->avctx, AV_LOG_ERROR, "invalid band type\n"); + return AVERROR_INVALIDDATA; + } + do { + sect_len_incr = get_bits(gb, bits); + sect_end += sect_len_incr; + if (get_bits_left(gb) < 0) { + av_log(ac->avctx, AV_LOG_ERROR, "decode_band_types: "overread_err); + return AVERROR_INVALIDDATA; + } + if (sect_end > ics->max_sfb) { + av_log(ac->avctx, AV_LOG_ERROR, + "Number of bands (%d) exceeds limit (%d).\n", + sect_end, ics->max_sfb); + return AVERROR_INVALIDDATA; + } + } while (sect_len_incr == (1 << bits) - 1); + for (; k < sect_end; k++) { + band_type [idx] = sect_band_type; + band_type_run_end[idx++] = sect_end; + } + } + } + return 0; +} + +/** + * Decode scalefactors; reference: table 4.47. + * + * @param global_gain first scalefactor value as scalefactors are differentially coded + * @param band_type array of the used band type + * @param band_type_run_end array of the last scalefactor band of a band type run + * @param sf array of scalefactors or intensity stereo positions + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_scalefactors(AACContext *ac, INTFLOAT sf[120], GetBitContext *gb, + unsigned int global_gain, + IndividualChannelStream *ics, + enum BandType band_type[120], + int band_type_run_end[120]) +{ + int g, i, idx = 0; + int offset[3] = { global_gain, global_gain - NOISE_OFFSET, 0 }; + int clipped_offset; + int noise_flag = 1; + for (g = 0; g < ics->num_window_groups; g++) { + for (i = 0; i < ics->max_sfb;) { + int run_end = band_type_run_end[idx]; + if (band_type[idx] == ZERO_BT) { + for (; i < run_end; i++, idx++) + sf[idx] = FIXR(0.); + } else if ((band_type[idx] == INTENSITY_BT) || + (band_type[idx] == INTENSITY_BT2)) { + for (; i < run_end; i++, idx++) { + offset[2] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - SCALE_DIFF_ZERO; + clipped_offset = av_clip(offset[2], -155, 100); + if (offset[2] != clipped_offset) { + avpriv_request_sample(ac->avctx, + "If you heard an audible artifact, there may be a bug in the decoder. " + "Clipped intensity stereo position (%d -> %d)", + offset[2], clipped_offset); + } +#if USE_FIXED + sf[idx] = 100 - clipped_offset; +#else + sf[idx] = ff_aac_pow2sf_tab[-clipped_offset + POW_SF2_ZERO]; +#endif /* USE_FIXED */ + } + } else if (band_type[idx] == NOISE_BT) { + for (; i < run_end; i++, idx++) { + if (noise_flag-- > 0) + offset[1] += get_bits(gb, NOISE_PRE_BITS) - NOISE_PRE; + else + offset[1] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - SCALE_DIFF_ZERO; + clipped_offset = av_clip(offset[1], -100, 155); + if (offset[1] != clipped_offset) { + avpriv_request_sample(ac->avctx, + "If you heard an audible artifact, there may be a bug in the decoder. " + "Clipped noise gain (%d -> %d)", + offset[1], clipped_offset); + } +#if USE_FIXED + sf[idx] = -(100 + clipped_offset); +#else + sf[idx] = -ff_aac_pow2sf_tab[clipped_offset + POW_SF2_ZERO]; +#endif /* USE_FIXED */ + } + } else { + for (; i < run_end; i++, idx++) { + offset[0] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - SCALE_DIFF_ZERO; + if (offset[0] > 255U) { + av_log(ac->avctx, AV_LOG_ERROR, + "Scalefactor (%d) out of range.\n", offset[0]); + return AVERROR_INVALIDDATA; + } +#if USE_FIXED + sf[idx] = -offset[0]; +#else + sf[idx] = -ff_aac_pow2sf_tab[offset[0] - 100 + POW_SF2_ZERO]; +#endif /* USE_FIXED */ + } + } + } + } + return 0; +} + +/** + * Decode pulse data; reference: table 4.7. + */ +static int decode_pulses(Pulse *pulse, GetBitContext *gb, + const uint16_t *swb_offset, int num_swb) +{ + int i, pulse_swb; + pulse->num_pulse = get_bits(gb, 2) + 1; + pulse_swb = get_bits(gb, 6); + if (pulse_swb >= num_swb) + return -1; + pulse->pos[0] = swb_offset[pulse_swb]; + pulse->pos[0] += get_bits(gb, 5); + if (pulse->pos[0] >= swb_offset[num_swb]) + return -1; + pulse->amp[0] = get_bits(gb, 4); + for (i = 1; i < pulse->num_pulse; i++) { + pulse->pos[i] = get_bits(gb, 5) + pulse->pos[i - 1]; + if (pulse->pos[i] >= swb_offset[num_swb]) + return -1; + pulse->amp[i] = get_bits(gb, 4); + } + return 0; +} + +/** + * Decode Temporal Noise Shaping data; reference: table 4.48. + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_tns(AACContext *ac, TemporalNoiseShaping *tns, + GetBitContext *gb, const IndividualChannelStream *ics) +{ + int w, filt, i, coef_len, coef_res, coef_compress; + const int is8 = ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE; + const int tns_max_order = is8 ? 7 : ac->oc[1].m4ac.object_type == AOT_AAC_MAIN ? 20 : 12; + for (w = 0; w < ics->num_windows; w++) { + if ((tns->n_filt[w] = get_bits(gb, 2 - is8))) { + coef_res = get_bits1(gb); + + for (filt = 0; filt < tns->n_filt[w]; filt++) { + int tmp2_idx; + tns->length[w][filt] = get_bits(gb, 6 - 2 * is8); + + if ((tns->order[w][filt] = get_bits(gb, 5 - 2 * is8)) > tns_max_order) { + av_log(ac->avctx, AV_LOG_ERROR, + "TNS filter order %d is greater than maximum %d.\n", + tns->order[w][filt], tns_max_order); + tns->order[w][filt] = 0; + return AVERROR_INVALIDDATA; + } + if (tns->order[w][filt]) { + tns->direction[w][filt] = get_bits1(gb); + coef_compress = get_bits1(gb); + coef_len = coef_res + 3 - coef_compress; + tmp2_idx = 2 * coef_compress + coef_res; + + for (i = 0; i < tns->order[w][filt]; i++) + tns->coef[w][filt][i] = tns_tmp2_map[tmp2_idx][get_bits(gb, coef_len)]; + } + } + } + } + return 0; +} + +/** + * Decode Mid/Side data; reference: table 4.54. + * + * @param ms_present Indicates mid/side stereo presence. [0] mask is all 0s; + * [1] mask is decoded from bitstream; [2] mask is all 1s; + * [3] reserved for scalable AAC + */ +static void decode_mid_side_stereo(ChannelElement *cpe, GetBitContext *gb, + int ms_present) +{ + int idx; + int max_idx = cpe->ch[0].ics.num_window_groups * cpe->ch[0].ics.max_sfb; + if (ms_present == 1) { + for (idx = 0; idx < max_idx; idx++) + cpe->ms_mask[idx] = get_bits1(gb); + } else if (ms_present == 2) { + memset(cpe->ms_mask, 1, max_idx * sizeof(cpe->ms_mask[0])); + } +} + +/** + * Decode spectral data; reference: table 4.50. + * Dequantize and scale spectral data; reference: 4.6.3.3. + * + * @param coef array of dequantized, scaled spectral data + * @param sf array of scalefactors or intensity stereo positions + * @param pulse_present set if pulses are present + * @param pulse pointer to pulse data struct + * @param band_type array of the used band type + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_spectrum_and_dequant(AACContext *ac, INTFLOAT coef[1024], + GetBitContext *gb, const INTFLOAT sf[120], + int pulse_present, const Pulse *pulse, + const IndividualChannelStream *ics, + enum BandType band_type[120]) +{ + int i, k, g, idx = 0; + const int c = 1024 / ics->num_windows; + const uint16_t *offsets = ics->swb_offset; + INTFLOAT *coef_base = coef; + + for (g = 0; g < ics->num_windows; g++) + memset(coef + g * 128 + offsets[ics->max_sfb], 0, + sizeof(INTFLOAT) * (c - offsets[ics->max_sfb])); + + for (g = 0; g < ics->num_window_groups; g++) { + unsigned g_len = ics->group_len[g]; + + for (i = 0; i < ics->max_sfb; i++, idx++) { + const unsigned cbt_m1 = band_type[idx] - 1; + INTFLOAT *cfo = coef + offsets[i]; + int off_len = offsets[i + 1] - offsets[i]; + int group; + + if (cbt_m1 >= INTENSITY_BT2 - 1) { + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + memset(cfo, 0, off_len * sizeof(*cfo)); + } + } else if (cbt_m1 == NOISE_BT - 1) { + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + INTFLOAT band_energy; +#if USE_FIXED + for (k = 0; k < off_len; k++) { + ac->random_state = lcg_random(ac->random_state); + cfo[k] = ac->random_state >> 3; + } + + band_energy = ac->fdsp->scalarproduct_fixed(cfo, cfo, off_len); + band_energy = fixed_sqrt(band_energy, 31); + noise_scale(cfo, sf[idx], band_energy, off_len); +#else + float scale; + + for (k = 0; k < off_len; k++) { + ac->random_state = lcg_random(ac->random_state); + cfo[k] = ac->random_state; + } + + band_energy = ac->fdsp->scalarproduct_float(cfo, cfo, off_len); + scale = sf[idx] / sqrtf(band_energy); + ac->fdsp->vector_fmul_scalar(cfo, cfo, scale, off_len); +#endif /* USE_FIXED */ + } + } else { +#if !USE_FIXED + const float *vq = ff_aac_codebook_vector_vals[cbt_m1]; +#endif /* !USE_FIXED */ + const uint16_t *cb_vector_idx = ff_aac_codebook_vector_idx[cbt_m1]; + VLC_TYPE (*vlc_tab)[2] = vlc_spectral[cbt_m1].table; + OPEN_READER(re, gb); + + switch (cbt_m1 >> 1) { + case 0: + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + INTFLOAT *cf = cfo; + int len = off_len; + + do { + int code; + unsigned cb_idx; + + UPDATE_CACHE(re, gb); + GET_VLC(code, re, gb, vlc_tab, 8, 2); + cb_idx = cb_vector_idx[code]; +#if USE_FIXED + cf = DEC_SQUAD(cf, cb_idx); +#else + cf = VMUL4(cf, vq, cb_idx, sf + idx); +#endif /* USE_FIXED */ + } while (len -= 4); + } + break; + + case 1: + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + INTFLOAT *cf = cfo; + int len = off_len; + + do { + int code; + unsigned nnz; + unsigned cb_idx; + uint32_t bits; + + UPDATE_CACHE(re, gb); + GET_VLC(code, re, gb, vlc_tab, 8, 2); + cb_idx = cb_vector_idx[code]; + nnz = cb_idx >> 8 & 15; + bits = nnz ? GET_CACHE(re, gb) : 0; + LAST_SKIP_BITS(re, gb, nnz); +#if USE_FIXED + cf = DEC_UQUAD(cf, cb_idx, bits); +#else + cf = VMUL4S(cf, vq, cb_idx, bits, sf + idx); +#endif /* USE_FIXED */ + } while (len -= 4); + } + break; + + case 2: + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + INTFLOAT *cf = cfo; + int len = off_len; + + do { + int code; + unsigned cb_idx; + + UPDATE_CACHE(re, gb); + GET_VLC(code, re, gb, vlc_tab, 8, 2); + cb_idx = cb_vector_idx[code]; +#if USE_FIXED + cf = DEC_SPAIR(cf, cb_idx); +#else + cf = VMUL2(cf, vq, cb_idx, sf + idx); +#endif /* USE_FIXED */ + } while (len -= 2); + } + break; + + case 3: + case 4: + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { + INTFLOAT *cf = cfo; + int len = off_len; + + do { + int code; + unsigned nnz; + unsigned cb_idx; + unsigned sign; + + UPDATE_CACHE(re, gb); + GET_VLC(code, re, gb, vlc_tab, 8, 2); + cb_idx = cb_vector_idx[code]; + nnz = cb_idx >> 8 & 15; + sign = nnz ? SHOW_UBITS(re, gb, nnz) << (cb_idx >> 12) : 0; + LAST_SKIP_BITS(re, gb, nnz); +#if USE_FIXED + cf = DEC_UPAIR(cf, cb_idx, sign); +#else + cf = VMUL2S(cf, vq, cb_idx, sign, sf + idx); +#endif /* USE_FIXED */ + } while (len -= 2); + } + break; + + default: + for (group = 0; group < (AAC_SIGNE)g_len; group++, cfo+=128) { +#if USE_FIXED + int *icf = cfo; + int v; +#else + float *cf = cfo; + uint32_t *icf = (uint32_t *) cf; +#endif /* USE_FIXED */ + int len = off_len; + + do { + int code; + unsigned nzt, nnz; + unsigned cb_idx; + uint32_t bits; + int j; + + UPDATE_CACHE(re, gb); + GET_VLC(code, re, gb, vlc_tab, 8, 2); + + if (!code) { + *icf++ = 0; + *icf++ = 0; + continue; + } + + cb_idx = cb_vector_idx[code]; + nnz = cb_idx >> 12; + nzt = cb_idx >> 8; + bits = SHOW_UBITS(re, gb, nnz) << (32-nnz); + LAST_SKIP_BITS(re, gb, nnz); + + for (j = 0; j < 2; j++) { + if (nzt & 1< 8) { + av_log(ac->avctx, AV_LOG_ERROR, "error in spectral data, ESC overflow\n"); + return AVERROR_INVALIDDATA; + } + + SKIP_BITS(re, gb, b + 1); + b += 4; + n = (1 << b) + SHOW_UBITS(re, gb, b); + LAST_SKIP_BITS(re, gb, b); +#if USE_FIXED + v = n; + if (bits & 1U<<31) + v = -v; + *icf++ = v; +#else + *icf++ = ff_cbrt_tab[n] | (bits & 1U<<31); +#endif /* USE_FIXED */ + bits <<= 1; + } else { +#if USE_FIXED + v = cb_idx & 15; + if (bits & 1U<<31) + v = -v; + *icf++ = v; +#else + unsigned v = ((const uint32_t*)vq)[cb_idx & 15]; + *icf++ = (bits & 1U<<31) | v; +#endif /* USE_FIXED */ + bits <<= !!v; + } + cb_idx >>= 4; + } + } while (len -= 2); +#if !USE_FIXED + ac->fdsp->vector_fmul_scalar(cfo, cfo, sf[idx], off_len); +#endif /* !USE_FIXED */ + } + } + + CLOSE_READER(re, gb); + } + } + coef += g_len << 7; + } + + if (pulse_present) { + idx = 0; + for (i = 0; i < pulse->num_pulse; i++) { + INTFLOAT co = coef_base[ pulse->pos[i] ]; + while (offsets[idx + 1] <= pulse->pos[i]) + idx++; + if (band_type[idx] != NOISE_BT && sf[idx]) { + INTFLOAT ico = -pulse->amp[i]; +#if USE_FIXED + if (co) { + ico = co + (co > 0 ? -ico : ico); + } + coef_base[ pulse->pos[i] ] = ico; +#else + if (co) { + co /= sf[idx]; + ico = co / sqrtf(sqrtf(fabsf(co))) + (co > 0 ? -ico : ico); + } + coef_base[ pulse->pos[i] ] = cbrtf(fabsf(ico)) * ico * sf[idx]; +#endif /* USE_FIXED */ + } + } + } +#if USE_FIXED + coef = coef_base; + idx = 0; + for (g = 0; g < ics->num_window_groups; g++) { + unsigned g_len = ics->group_len[g]; + + for (i = 0; i < ics->max_sfb; i++, idx++) { + const unsigned cbt_m1 = band_type[idx] - 1; + int *cfo = coef + offsets[i]; + int off_len = offsets[i + 1] - offsets[i]; + int group; + + if (cbt_m1 < NOISE_BT - 1) { + for (group = 0; group < (int)g_len; group++, cfo+=128) { + ac->vector_pow43(cfo, off_len); + ac->subband_scale(cfo, cfo, sf[idx], 34, off_len, ac->avctx); + } + } + } + coef += g_len << 7; + } +#endif /* USE_FIXED */ + return 0; +} + +/** + * Apply AAC-Main style frequency domain prediction. + */ +static void apply_prediction(AACContext *ac, SingleChannelElement *sce) +{ + int sfb, k; + + if (!sce->ics.predictor_initialized) { + reset_all_predictors(sce->predictor_state); + sce->ics.predictor_initialized = 1; + } + + if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { + for (sfb = 0; + sfb < ff_aac_pred_sfb_max[ac->oc[1].m4ac.sampling_index]; + sfb++) { + for (k = sce->ics.swb_offset[sfb]; + k < sce->ics.swb_offset[sfb + 1]; + k++) { + predict(&sce->predictor_state[k], &sce->coeffs[k], + sce->ics.predictor_present && + sce->ics.prediction_used[sfb]); + } + } + if (sce->ics.predictor_reset_group) + reset_predictor_group(sce->predictor_state, + sce->ics.predictor_reset_group); + } else + reset_all_predictors(sce->predictor_state); +} + +static void decode_gain_control(SingleChannelElement * sce, GetBitContext * gb) +{ + // wd_num, wd_test, aloc_size + static const uint8_t gain_mode[4][3] = { + {1, 0, 5}, // ONLY_LONG_SEQUENCE = 0, + {2, 1, 2}, // LONG_START_SEQUENCE, + {8, 0, 2}, // EIGHT_SHORT_SEQUENCE, + {2, 1, 5}, // LONG_STOP_SEQUENCE + }; + + const int mode = sce->ics.window_sequence[0]; + uint8_t bd, wd, ad; + + // FIXME: Store the gain control data on |sce| and do something with it. + uint8_t max_band = get_bits(gb, 2); + for (bd = 0; bd < max_band; bd++) { + for (wd = 0; wd < gain_mode[mode][0]; wd++) { + uint8_t adjust_num = get_bits(gb, 3); + for (ad = 0; ad < adjust_num; ad++) { + skip_bits(gb, 4 + ((wd == 0 && gain_mode[mode][1]) + ? 4 + : gain_mode[mode][2])); + } + } + } +} + +/** + * Decode an individual_channel_stream payload; reference: table 4.44. + * + * @param common_window Channels have independent [0], or shared [1], Individual Channel Stream information. + * @param scale_flag scalable [1] or non-scalable [0] AAC (Unused until scalable AAC is implemented.) + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_ics(AACContext *ac, SingleChannelElement *sce, + GetBitContext *gb, int common_window, int scale_flag) +{ + Pulse pulse; + TemporalNoiseShaping *tns = &sce->tns; + IndividualChannelStream *ics = &sce->ics; + INTFLOAT *out = sce->coeffs; + int global_gain, eld_syntax, er_syntax, pulse_present = 0; + int ret; + + eld_syntax = ac->oc[1].m4ac.object_type == AOT_ER_AAC_ELD; + er_syntax = ac->oc[1].m4ac.object_type == AOT_ER_AAC_LC || + ac->oc[1].m4ac.object_type == AOT_ER_AAC_LTP || + ac->oc[1].m4ac.object_type == AOT_ER_AAC_LD || + ac->oc[1].m4ac.object_type == AOT_ER_AAC_ELD; + + /* This assignment is to silence a GCC warning about the variable being used + * uninitialized when in fact it always is. + */ + pulse.num_pulse = 0; + + global_gain = get_bits(gb, 8); + + if (!common_window && !scale_flag) { + ret = decode_ics_info(ac, ics, gb); + if (ret < 0) + goto fail; + } + + if ((ret = decode_band_types(ac, sce->band_type, + sce->band_type_run_end, gb, ics)) < 0) + goto fail; + if ((ret = decode_scalefactors(ac, sce->sf, gb, global_gain, ics, + sce->band_type, sce->band_type_run_end)) < 0) + goto fail; + + pulse_present = 0; + if (!scale_flag) { + if (!eld_syntax && (pulse_present = get_bits1(gb))) { + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + av_log(ac->avctx, AV_LOG_ERROR, + "Pulse tool not allowed in eight short sequence.\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + if (decode_pulses(&pulse, gb, ics->swb_offset, ics->num_swb)) { + av_log(ac->avctx, AV_LOG_ERROR, + "Pulse data corrupt or invalid.\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + } + tns->present = get_bits1(gb); + if (tns->present && !er_syntax) { + ret = decode_tns(ac, tns, gb, ics); + if (ret < 0) + goto fail; + } + if (!eld_syntax && get_bits1(gb)) { + decode_gain_control(sce, gb); + if (!ac->warned_gain_control) { + avpriv_report_missing_feature(ac->avctx, "Gain control"); + ac->warned_gain_control = 1; + } + } + // I see no textual basis in the spec for this occurring after SSR gain + // control, but this is what both reference and real implmentations do + if (tns->present && er_syntax) { + ret = decode_tns(ac, tns, gb, ics); + if (ret < 0) + goto fail; + } + } + + ret = decode_spectrum_and_dequant(ac, out, gb, sce->sf, pulse_present, + &pulse, ics, sce->band_type); + if (ret < 0) + goto fail; + + if (ac->oc[1].m4ac.object_type == AOT_AAC_MAIN && !common_window) + apply_prediction(ac, sce); + + return 0; +fail: + tns->present = 0; + return ret; +} + +/** + * Mid/Side stereo decoding; reference: 4.6.8.1.3. + */ +static void apply_mid_side_stereo(AACContext *ac, ChannelElement *cpe) +{ + const IndividualChannelStream *ics = &cpe->ch[0].ics; + INTFLOAT *ch0 = cpe->ch[0].coeffs; + INTFLOAT *ch1 = cpe->ch[1].coeffs; + int g, i, group, idx = 0; + const uint16_t *offsets = ics->swb_offset; + for (g = 0; g < ics->num_window_groups; g++) { + for (i = 0; i < ics->max_sfb; i++, idx++) { + if (cpe->ms_mask[idx] && + cpe->ch[0].band_type[idx] < NOISE_BT && + cpe->ch[1].band_type[idx] < NOISE_BT) { +#if USE_FIXED + for (group = 0; group < ics->group_len[g]; group++) { + ac->fdsp->butterflies_fixed(ch0 + group * 128 + offsets[i], + ch1 + group * 128 + offsets[i], + offsets[i+1] - offsets[i]); +#else + for (group = 0; group < ics->group_len[g]; group++) { + ac->fdsp->butterflies_float(ch0 + group * 128 + offsets[i], + ch1 + group * 128 + offsets[i], + offsets[i+1] - offsets[i]); +#endif /* USE_FIXED */ + } + } + } + ch0 += ics->group_len[g] * 128; + ch1 += ics->group_len[g] * 128; + } +} + +/** + * intensity stereo decoding; reference: 4.6.8.2.3 + * + * @param ms_present Indicates mid/side stereo presence. [0] mask is all 0s; + * [1] mask is decoded from bitstream; [2] mask is all 1s; + * [3] reserved for scalable AAC + */ +static void apply_intensity_stereo(AACContext *ac, + ChannelElement *cpe, int ms_present) +{ + const IndividualChannelStream *ics = &cpe->ch[1].ics; + SingleChannelElement *sce1 = &cpe->ch[1]; + INTFLOAT *coef0 = cpe->ch[0].coeffs, *coef1 = cpe->ch[1].coeffs; + const uint16_t *offsets = ics->swb_offset; + int g, group, i, idx = 0; + int c; + INTFLOAT scale; + for (g = 0; g < ics->num_window_groups; g++) { + for (i = 0; i < ics->max_sfb;) { + if (sce1->band_type[idx] == INTENSITY_BT || + sce1->band_type[idx] == INTENSITY_BT2) { + const int bt_run_end = sce1->band_type_run_end[idx]; + for (; i < bt_run_end; i++, idx++) { + c = -1 + 2 * (sce1->band_type[idx] - 14); + if (ms_present) + c *= 1 - 2 * cpe->ms_mask[idx]; + scale = c * sce1->sf[idx]; + for (group = 0; group < ics->group_len[g]; group++) +#if USE_FIXED + ac->subband_scale(coef1 + group * 128 + offsets[i], + coef0 + group * 128 + offsets[i], + scale, + 23, + offsets[i + 1] - offsets[i] ,ac->avctx); +#else + ac->fdsp->vector_fmul_scalar(coef1 + group * 128 + offsets[i], + coef0 + group * 128 + offsets[i], + scale, + offsets[i + 1] - offsets[i]); +#endif /* USE_FIXED */ + } + } else { + int bt_run_end = sce1->band_type_run_end[idx]; + idx += bt_run_end - i; + i = bt_run_end; + } + } + coef0 += ics->group_len[g] * 128; + coef1 += ics->group_len[g] * 128; + } +} + +/** + * Decode a channel_pair_element; reference: table 4.4. + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_cpe(AACContext *ac, GetBitContext *gb, ChannelElement *cpe) +{ + int i, ret, common_window, ms_present = 0; + int eld_syntax = ac->oc[1].m4ac.object_type == AOT_ER_AAC_ELD; + + common_window = eld_syntax || get_bits1(gb); + if (common_window) { + if (decode_ics_info(ac, &cpe->ch[0].ics, gb)) + return AVERROR_INVALIDDATA; + i = cpe->ch[1].ics.use_kb_window[0]; + cpe->ch[1].ics = cpe->ch[0].ics; + cpe->ch[1].ics.use_kb_window[1] = i; + if (cpe->ch[1].ics.predictor_present && + (ac->oc[1].m4ac.object_type != AOT_AAC_MAIN)) + if ((cpe->ch[1].ics.ltp.present = get_bits(gb, 1))) + decode_ltp(&cpe->ch[1].ics.ltp, gb, cpe->ch[1].ics.max_sfb); + ms_present = get_bits(gb, 2); + if (ms_present == 3) { + av_log(ac->avctx, AV_LOG_ERROR, "ms_present = 3 is reserved.\n"); + return AVERROR_INVALIDDATA; + } else if (ms_present) + decode_mid_side_stereo(cpe, gb, ms_present); + } + if ((ret = decode_ics(ac, &cpe->ch[0], gb, common_window, 0))) + return ret; + if ((ret = decode_ics(ac, &cpe->ch[1], gb, common_window, 0))) + return ret; + + if (common_window) { + if (ms_present) + apply_mid_side_stereo(ac, cpe); + if (ac->oc[1].m4ac.object_type == AOT_AAC_MAIN) { + apply_prediction(ac, &cpe->ch[0]); + apply_prediction(ac, &cpe->ch[1]); + } + } + + apply_intensity_stereo(ac, cpe, ms_present); + return 0; +} + +static const float cce_scale[] = { + 1.09050773266525765921, //2^(1/8) + 1.18920711500272106672, //2^(1/4) + M_SQRT2, + 2, +}; + +/** + * Decode coupling_channel_element; reference: table 4.8. + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_cce(AACContext *ac, GetBitContext *gb, ChannelElement *che) +{ + int num_gain = 0; + int c, g, sfb, ret; + int sign; + INTFLOAT scale; + SingleChannelElement *sce = &che->ch[0]; + ChannelCoupling *coup = &che->coup; + + coup->coupling_point = 2 * get_bits1(gb); + coup->num_coupled = get_bits(gb, 3); + for (c = 0; c <= coup->num_coupled; c++) { + num_gain++; + coup->type[c] = get_bits1(gb) ? TYPE_CPE : TYPE_SCE; + coup->id_select[c] = get_bits(gb, 4); + if (coup->type[c] == TYPE_CPE) { + coup->ch_select[c] = get_bits(gb, 2); + if (coup->ch_select[c] == 3) + num_gain++; + } else + coup->ch_select[c] = 2; + } + coup->coupling_point += get_bits1(gb) || (coup->coupling_point >> 1); + + sign = get_bits(gb, 1); +#if USE_FIXED + scale = get_bits(gb, 2); +#else + scale = cce_scale[get_bits(gb, 2)]; +#endif + + if ((ret = decode_ics(ac, sce, gb, 0, 0))) + return ret; + + for (c = 0; c < num_gain; c++) { + int idx = 0; + int cge = 1; + int gain = 0; + INTFLOAT gain_cache = FIXR10(1.); + if (c) { + cge = coup->coupling_point == AFTER_IMDCT ? 1 : get_bits1(gb); + gain = cge ? get_vlc2(gb, vlc_scalefactors.table, 7, 3) - 60: 0; + gain_cache = GET_GAIN(scale, gain); +#if USE_FIXED + if ((abs(gain_cache)-1024) >> 3 > 30) + return AVERROR(ERANGE); +#endif + } + if (coup->coupling_point == AFTER_IMDCT) { + coup->gain[c][0] = gain_cache; + } else { + for (g = 0; g < sce->ics.num_window_groups; g++) { + for (sfb = 0; sfb < sce->ics.max_sfb; sfb++, idx++) { + if (sce->band_type[idx] != ZERO_BT) { + if (!cge) { + int t = get_vlc2(gb, vlc_scalefactors.table, 7, 3) - 60; + if (t) { + int s = 1; + t = gain += t; + if (sign) { + s -= 2 * (t & 0x1); + t >>= 1; + } + gain_cache = GET_GAIN(scale, t) * s; +#if USE_FIXED + if ((abs(gain_cache)-1024) >> 3 > 30) + return AVERROR(ERANGE); +#endif + } + } + coup->gain[c][idx] = gain_cache; + } + } + } + } + } + return 0; +} + +/** + * Parse whether channels are to be excluded from Dynamic Range Compression; reference: table 4.53. + * + * @return Returns number of bytes consumed. + */ +static int decode_drc_channel_exclusions(DynamicRangeControl *che_drc, + GetBitContext *gb) +{ + int i; + int num_excl_chan = 0; + + do { + for (i = 0; i < 7; i++) + che_drc->exclude_mask[num_excl_chan++] = get_bits1(gb); + } while (num_excl_chan < MAX_CHANNELS - 7 && get_bits1(gb)); + + return num_excl_chan / 7; +} + +/** + * Decode dynamic range information; reference: table 4.52. + * + * @return Returns number of bytes consumed. + */ +static int decode_dynamic_range(DynamicRangeControl *che_drc, + GetBitContext *gb) +{ + int n = 1; + int drc_num_bands = 1; + int i; + + /* pce_tag_present? */ + if (get_bits1(gb)) { + che_drc->pce_instance_tag = get_bits(gb, 4); + skip_bits(gb, 4); // tag_reserved_bits + n++; + } + + /* excluded_chns_present? */ + if (get_bits1(gb)) { + n += decode_drc_channel_exclusions(che_drc, gb); + } + + /* drc_bands_present? */ + if (get_bits1(gb)) { + che_drc->band_incr = get_bits(gb, 4); + che_drc->interpolation_scheme = get_bits(gb, 4); + n++; + drc_num_bands += che_drc->band_incr; + for (i = 0; i < drc_num_bands; i++) { + che_drc->band_top[i] = get_bits(gb, 8); + n++; + } + } + + /* prog_ref_level_present? */ + if (get_bits1(gb)) { + che_drc->prog_ref_level = get_bits(gb, 7); + skip_bits1(gb); // prog_ref_level_reserved_bits + n++; + } + + for (i = 0; i < drc_num_bands; i++) { + che_drc->dyn_rng_sgn[i] = get_bits1(gb); + che_drc->dyn_rng_ctl[i] = get_bits(gb, 7); + n++; + } + + return n; +} + +static int decode_fill(AACContext *ac, GetBitContext *gb, int len) { + uint8_t buf[256]; + int i, major, minor; + + if (len < 13+7*8) + goto unknown; + + get_bits(gb, 13); len -= 13; + + for(i=0; i+1=8; i++, len-=8) + buf[i] = get_bits(gb, 8); + + buf[i] = 0; + if (ac->avctx->debug & FF_DEBUG_PICT_INFO) + av_log(ac->avctx, AV_LOG_DEBUG, "FILL:%s\n", buf); + + if (sscanf(buf, "libfaac %d.%d", &major, &minor) == 2){ + ac->avctx->internal->skip_samples = 1024; + } + +unknown: + skip_bits_long(gb, len); + + return 0; +} + +/** + * Decode extension data (incomplete); reference: table 4.51. + * + * @param cnt length of TYPE_FIL syntactic element in bytes + * + * @return Returns number of bytes consumed + */ +static int decode_extension_payload(AACContext *ac, GetBitContext *gb, int cnt, + ChannelElement *che, enum RawDataBlockType elem_type) +{ + int crc_flag = 0; + int res = cnt; + int type = get_bits(gb, 4); + + if (ac->avctx->debug & FF_DEBUG_STARTCODE) + av_log(ac->avctx, AV_LOG_DEBUG, "extension type: %d len:%d\n", type, cnt); + + switch (type) { // extension type + case EXT_SBR_DATA_CRC: + crc_flag++; + case EXT_SBR_DATA: + if (!che) { + av_log(ac->avctx, AV_LOG_ERROR, "SBR was found before the first channel element.\n"); + return res; + } else if (ac->oc[1].m4ac.frame_length_short) { + if (!ac->warned_960_sbr) + avpriv_report_missing_feature(ac->avctx, + "SBR with 960 frame length"); + ac->warned_960_sbr = 1; + skip_bits_long(gb, 8 * cnt - 4); + return res; + } else if (!ac->oc[1].m4ac.sbr) { + av_log(ac->avctx, AV_LOG_ERROR, "SBR signaled to be not-present but was found in the bitstream.\n"); + skip_bits_long(gb, 8 * cnt - 4); + return res; + } else if (ac->oc[1].m4ac.sbr == -1 && ac->oc[1].status == OC_LOCKED) { + av_log(ac->avctx, AV_LOG_ERROR, "Implicit SBR was found with a first occurrence after the first frame.\n"); + skip_bits_long(gb, 8 * cnt - 4); + return res; + } else if (ac->oc[1].m4ac.ps == -1 && ac->oc[1].status < OC_LOCKED && ac->avctx->channels == 1) { + ac->oc[1].m4ac.sbr = 1; + ac->oc[1].m4ac.ps = 1; + ac->avctx->profile = FF_PROFILE_AAC_HE_V2; + output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags, + ac->oc[1].status, 1); + } else { + ac->oc[1].m4ac.sbr = 1; + ac->avctx->profile = FF_PROFILE_AAC_HE; + } + res = AAC_RENAME(ff_decode_sbr_extension)(ac, &che->sbr, gb, crc_flag, cnt, elem_type); + break; + case EXT_DYNAMIC_RANGE: + res = decode_dynamic_range(&ac->che_drc, gb); + break; + case EXT_FILL: + decode_fill(ac, gb, 8 * cnt - 4); + break; + case EXT_FILL_DATA: + case EXT_DATA_ELEMENT: + default: + skip_bits_long(gb, 8 * cnt - 4); + break; + }; + return res; +} + +/** + * Decode Temporal Noise Shaping filter coefficients and apply all-pole filters; reference: 4.6.9.3. + * + * @param decode 1 if tool is used normally, 0 if tool is used in LTP. + * @param coef spectral coefficients + */ +static void apply_tns(INTFLOAT coef_param[1024], TemporalNoiseShaping *tns, + IndividualChannelStream *ics, int decode) +{ + const int mmm = FFMIN(ics->tns_max_bands, ics->max_sfb); + int w, filt, m, i; + int bottom, top, order, start, end, size, inc; + INTFLOAT lpc[TNS_MAX_ORDER]; + INTFLOAT tmp[TNS_MAX_ORDER+1]; + UINTFLOAT *coef = coef_param; + + if(!mmm) + return; + + for (w = 0; w < ics->num_windows; w++) { + bottom = ics->num_swb; + for (filt = 0; filt < tns->n_filt[w]; filt++) { + top = bottom; + bottom = FFMAX(0, top - tns->length[w][filt]); + order = tns->order[w][filt]; + if (order == 0) + continue; + + // tns_decode_coef + AAC_RENAME(compute_lpc_coefs)(tns->coef[w][filt], order, lpc, 0, 0, 0); + + start = ics->swb_offset[FFMIN(bottom, mmm)]; + end = ics->swb_offset[FFMIN( top, mmm)]; + if ((size = end - start) <= 0) + continue; + if (tns->direction[w][filt]) { + inc = -1; + start = end - 1; + } else { + inc = 1; + } + start += w * 128; + + if (decode) { + // ar filter + for (m = 0; m < size; m++, start += inc) + for (i = 1; i <= FFMIN(m, order); i++) + coef[start] -= AAC_MUL26((INTFLOAT)coef[start - i * inc], lpc[i - 1]); + } else { + // ma filter + for (m = 0; m < size; m++, start += inc) { + tmp[0] = coef[start]; + for (i = 1; i <= FFMIN(m, order); i++) + coef[start] += AAC_MUL26(tmp[i], lpc[i - 1]); + for (i = order; i > 0; i--) + tmp[i] = tmp[i - 1]; + } + } + } + } +} + +/** + * Apply windowing and MDCT to obtain the spectral + * coefficient from the predicted sample by LTP. + */ +static void windowing_and_mdct_ltp(AACContext *ac, INTFLOAT *out, + INTFLOAT *in, IndividualChannelStream *ics) +{ + const INTFLOAT *lwindow = ics->use_kb_window[0] ? AAC_RENAME(ff_aac_kbd_long_1024) : AAC_RENAME(ff_sine_1024); + const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME(ff_aac_kbd_short_128) : AAC_RENAME(ff_sine_128); + const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME(ff_aac_kbd_long_1024) : AAC_RENAME(ff_sine_1024); + const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME(ff_aac_kbd_short_128) : AAC_RENAME(ff_sine_128); + + if (ics->window_sequence[0] != LONG_STOP_SEQUENCE) { + ac->fdsp->vector_fmul(in, in, lwindow_prev, 1024); + } else { + memset(in, 0, 448 * sizeof(*in)); + ac->fdsp->vector_fmul(in + 448, in + 448, swindow_prev, 128); + } + if (ics->window_sequence[0] != LONG_START_SEQUENCE) { + ac->fdsp->vector_fmul_reverse(in + 1024, in + 1024, lwindow, 1024); + } else { + ac->fdsp->vector_fmul_reverse(in + 1024 + 448, in + 1024 + 448, swindow, 128); + memset(in + 1024 + 576, 0, 448 * sizeof(*in)); + } + ac->mdct_ltp.mdct_calc(&ac->mdct_ltp, out, in); +} + +/** + * Apply the long term prediction + */ +static void apply_ltp(AACContext *ac, SingleChannelElement *sce) +{ + const LongTermPrediction *ltp = &sce->ics.ltp; + const uint16_t *offsets = sce->ics.swb_offset; + int i, sfb; + + if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { + INTFLOAT *predTime = sce->ret; + INTFLOAT *predFreq = ac->buf_mdct; + int16_t num_samples = 2048; + + if (ltp->lag < 1024) + num_samples = ltp->lag + 1024; + for (i = 0; i < num_samples; i++) + predTime[i] = AAC_MUL30(sce->ltp_state[i + 2048 - ltp->lag], ltp->coef); + memset(&predTime[i], 0, (2048 - i) * sizeof(*predTime)); + + ac->windowing_and_mdct_ltp(ac, predFreq, predTime, &sce->ics); + + if (sce->tns.present) + ac->apply_tns(predFreq, &sce->tns, &sce->ics, 0); + + for (sfb = 0; sfb < FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++) + if (ltp->used[sfb]) + for (i = offsets[sfb]; i < offsets[sfb + 1]; i++) + sce->coeffs[i] += (UINTFLOAT)predFreq[i]; + } +} + +/** + * Update the LTP buffer for next frame + */ +static void update_ltp(AACContext *ac, SingleChannelElement *sce) +{ + IndividualChannelStream *ics = &sce->ics; + INTFLOAT *saved = sce->saved; + INTFLOAT *saved_ltp = sce->coeffs; + const INTFLOAT *lwindow = ics->use_kb_window[0] ? AAC_RENAME(ff_aac_kbd_long_1024) : AAC_RENAME(ff_sine_1024); + const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME(ff_aac_kbd_short_128) : AAC_RENAME(ff_sine_128); + int i; + + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + memcpy(saved_ltp, saved, 512 * sizeof(*saved_ltp)); + memset(saved_ltp + 576, 0, 448 * sizeof(*saved_ltp)); + ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64); + + for (i = 0; i < 64; i++) + saved_ltp[i + 512] = AAC_MUL31(ac->buf_mdct[1023 - i], swindow[63 - i]); + } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { + memcpy(saved_ltp, ac->buf_mdct + 512, 448 * sizeof(*saved_ltp)); + memset(saved_ltp + 576, 0, 448 * sizeof(*saved_ltp)); + ac->fdsp->vector_fmul_reverse(saved_ltp + 448, ac->buf_mdct + 960, &swindow[64], 64); + + for (i = 0; i < 64; i++) + saved_ltp[i + 512] = AAC_MUL31(ac->buf_mdct[1023 - i], swindow[63 - i]); + } else { // LONG_STOP or ONLY_LONG + ac->fdsp->vector_fmul_reverse(saved_ltp, ac->buf_mdct + 512, &lwindow[512], 512); + + for (i = 0; i < 512; i++) + saved_ltp[i + 512] = AAC_MUL31(ac->buf_mdct[1023 - i], lwindow[511 - i]); + } + + memcpy(sce->ltp_state, sce->ltp_state+1024, 1024 * sizeof(*sce->ltp_state)); + memcpy(sce->ltp_state+1024, sce->ret, 1024 * sizeof(*sce->ltp_state)); + memcpy(sce->ltp_state+2048, saved_ltp, 1024 * sizeof(*sce->ltp_state)); +} + +/** + * Conduct IMDCT and windowing. + */ +static void imdct_and_windowing(AACContext *ac, SingleChannelElement *sce) +{ + IndividualChannelStream *ics = &sce->ics; + INTFLOAT *in = sce->coeffs; + INTFLOAT *out = sce->ret; + INTFLOAT *saved = sce->saved; + const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME(ff_aac_kbd_short_128) : AAC_RENAME(ff_sine_128); + const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME(ff_aac_kbd_long_1024) : AAC_RENAME(ff_sine_1024); + const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME(ff_aac_kbd_short_128) : AAC_RENAME(ff_sine_128); + INTFLOAT *buf = ac->buf_mdct; + INTFLOAT *temp = ac->temp; + int i; + + // imdct + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + for (i = 0; i < 1024; i += 128) + ac->mdct_small.imdct_half(&ac->mdct_small, buf + i, in + i); + } else { + ac->mdct.imdct_half(&ac->mdct, buf, in); +#if USE_FIXED + for (i=0; i<1024; i++) + buf[i] = (buf[i] + 4) >> 3; +#endif /* USE_FIXED */ + } + + /* window overlapping + * NOTE: To simplify the overlapping code, all 'meaningless' short to long + * and long to short transitions are considered to be short to short + * transitions. This leaves just two cases (long to long and short to short) + * with a little special sauce for EIGHT_SHORT_SEQUENCE. + */ + if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) && + (ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) { + ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 512); + } else { + memcpy( out, saved, 448 * sizeof(*out)); + + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + ac->fdsp->vector_fmul_window(out + 448 + 0*128, saved + 448, buf + 0*128, swindow_prev, 64); + ac->fdsp->vector_fmul_window(out + 448 + 1*128, buf + 0*128 + 64, buf + 1*128, swindow, 64); + ac->fdsp->vector_fmul_window(out + 448 + 2*128, buf + 1*128 + 64, buf + 2*128, swindow, 64); + ac->fdsp->vector_fmul_window(out + 448 + 3*128, buf + 2*128 + 64, buf + 3*128, swindow, 64); + ac->fdsp->vector_fmul_window(temp, buf + 3*128 + 64, buf + 4*128, swindow, 64); + memcpy( out + 448 + 4*128, temp, 64 * sizeof(*out)); + } else { + ac->fdsp->vector_fmul_window(out + 448, saved + 448, buf, swindow_prev, 64); + memcpy( out + 576, buf + 64, 448 * sizeof(*out)); + } + } + + // buffer update + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + memcpy( saved, temp + 64, 64 * sizeof(*saved)); + ac->fdsp->vector_fmul_window(saved + 64, buf + 4*128 + 64, buf + 5*128, swindow, 64); + ac->fdsp->vector_fmul_window(saved + 192, buf + 5*128 + 64, buf + 6*128, swindow, 64); + ac->fdsp->vector_fmul_window(saved + 320, buf + 6*128 + 64, buf + 7*128, swindow, 64); + memcpy( saved + 448, buf + 7*128 + 64, 64 * sizeof(*saved)); + } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { + memcpy( saved, buf + 512, 448 * sizeof(*saved)); + memcpy( saved + 448, buf + 7*128 + 64, 64 * sizeof(*saved)); + } else { // LONG_STOP or ONLY_LONG + memcpy( saved, buf + 512, 512 * sizeof(*saved)); + } +} + +/** + * Conduct IMDCT and windowing. + */ +static void imdct_and_windowing_960(AACContext *ac, SingleChannelElement *sce) +{ +#if !USE_FIXED + IndividualChannelStream *ics = &sce->ics; + INTFLOAT *in = sce->coeffs; + INTFLOAT *out = sce->ret; + INTFLOAT *saved = sce->saved; + const INTFLOAT *swindow = ics->use_kb_window[0] ? AAC_RENAME(ff_aac_kbd_short_120) : AAC_RENAME(ff_sine_120); + const INTFLOAT *lwindow_prev = ics->use_kb_window[1] ? AAC_RENAME(ff_aac_kbd_long_960) : AAC_RENAME(ff_sine_960); + const INTFLOAT *swindow_prev = ics->use_kb_window[1] ? AAC_RENAME(ff_aac_kbd_short_120) : AAC_RENAME(ff_sine_120); + INTFLOAT *buf = ac->buf_mdct; + INTFLOAT *temp = ac->temp; + int i; + + // imdct + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + for (i = 0; i < 8; i++) + ac->mdct120->imdct_half(ac->mdct120, buf + i * 120, in + i * 128, 1); + } else { + ac->mdct960->imdct_half(ac->mdct960, buf, in, 1); + } + + /* window overlapping + * NOTE: To simplify the overlapping code, all 'meaningless' short to long + * and long to short transitions are considered to be short to short + * transitions. This leaves just two cases (long to long and short to short) + * with a little special sauce for EIGHT_SHORT_SEQUENCE. + */ + + if ((ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) && + (ics->window_sequence[0] == ONLY_LONG_SEQUENCE || ics->window_sequence[0] == LONG_START_SEQUENCE)) { + ac->fdsp->vector_fmul_window( out, saved, buf, lwindow_prev, 480); + } else { + memcpy( out, saved, 420 * sizeof(*out)); + + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + ac->fdsp->vector_fmul_window(out + 420 + 0*120, saved + 420, buf + 0*120, swindow_prev, 60); + ac->fdsp->vector_fmul_window(out + 420 + 1*120, buf + 0*120 + 60, buf + 1*120, swindow, 60); + ac->fdsp->vector_fmul_window(out + 420 + 2*120, buf + 1*120 + 60, buf + 2*120, swindow, 60); + ac->fdsp->vector_fmul_window(out + 420 + 3*120, buf + 2*120 + 60, buf + 3*120, swindow, 60); + ac->fdsp->vector_fmul_window(temp, buf + 3*120 + 60, buf + 4*120, swindow, 60); + memcpy( out + 420 + 4*120, temp, 60 * sizeof(*out)); + } else { + ac->fdsp->vector_fmul_window(out + 420, saved + 420, buf, swindow_prev, 60); + memcpy( out + 540, buf + 60, 420 * sizeof(*out)); + } + } + + // buffer update + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + memcpy( saved, temp + 60, 60 * sizeof(*saved)); + ac->fdsp->vector_fmul_window(saved + 60, buf + 4*120 + 60, buf + 5*120, swindow, 60); + ac->fdsp->vector_fmul_window(saved + 180, buf + 5*120 + 60, buf + 6*120, swindow, 60); + ac->fdsp->vector_fmul_window(saved + 300, buf + 6*120 + 60, buf + 7*120, swindow, 60); + memcpy( saved + 420, buf + 7*120 + 60, 60 * sizeof(*saved)); + } else if (ics->window_sequence[0] == LONG_START_SEQUENCE) { + memcpy( saved, buf + 480, 420 * sizeof(*saved)); + memcpy( saved + 420, buf + 7*120 + 60, 60 * sizeof(*saved)); + } else { // LONG_STOP or ONLY_LONG + memcpy( saved, buf + 480, 480 * sizeof(*saved)); + } +#endif +} +static void imdct_and_windowing_ld(AACContext *ac, SingleChannelElement *sce) +{ + IndividualChannelStream *ics = &sce->ics; + INTFLOAT *in = sce->coeffs; + INTFLOAT *out = sce->ret; + INTFLOAT *saved = sce->saved; + INTFLOAT *buf = ac->buf_mdct; +#if USE_FIXED + int i; +#endif /* USE_FIXED */ + + // imdct + ac->mdct.imdct_half(&ac->mdct_ld, buf, in); + +#if USE_FIXED + for (i = 0; i < 1024; i++) + buf[i] = (buf[i] + 2) >> 2; +#endif /* USE_FIXED */ + + // window overlapping + if (ics->use_kb_window[1]) { + // AAC LD uses a low overlap sine window instead of a KBD window + memcpy(out, saved, 192 * sizeof(*out)); + ac->fdsp->vector_fmul_window(out + 192, saved + 192, buf, AAC_RENAME(ff_sine_128), 64); + memcpy( out + 320, buf + 64, 192 * sizeof(*out)); + } else { + ac->fdsp->vector_fmul_window(out, saved, buf, AAC_RENAME(ff_sine_512), 256); + } + + // buffer update + memcpy(saved, buf + 256, 256 * sizeof(*saved)); +} + +static void imdct_and_windowing_eld(AACContext *ac, SingleChannelElement *sce) +{ + INTFLOAT *in = sce->coeffs; + INTFLOAT *out = sce->ret; + INTFLOAT *saved = sce->saved; + INTFLOAT *buf = ac->buf_mdct; + int i; + const int n = ac->oc[1].m4ac.frame_length_short ? 480 : 512; + const int n2 = n >> 1; + const int n4 = n >> 2; + const INTFLOAT *const window = n == 480 ? AAC_RENAME(ff_aac_eld_window_480) : + AAC_RENAME(ff_aac_eld_window_512); + + // Inverse transform, mapped to the conventional IMDCT by + // Chivukula, R.K.; Reznik, Y.A.; Devarajan, V., + // "Efficient algorithms for MPEG-4 AAC-ELD, AAC-LD and AAC-LC filterbanks," + // International Conference on Audio, Language and Image Processing, ICALIP 2008. + // URL: http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4590245&isnumber=4589950 + for (i = 0; i < n2; i+=2) { + INTFLOAT temp; + temp = in[i ]; in[i ] = -in[n - 1 - i]; in[n - 1 - i] = temp; + temp = -in[i + 1]; in[i + 1] = in[n - 2 - i]; in[n - 2 - i] = temp; + } +#if !USE_FIXED + if (n == 480) + ac->mdct480->imdct_half(ac->mdct480, buf, in, 1); + else +#endif + ac->mdct.imdct_half(&ac->mdct_ld, buf, in); + +#if USE_FIXED + for (i = 0; i < 1024; i++) + buf[i] = (buf[i] + 1) >> 1; +#endif /* USE_FIXED */ + + for (i = 0; i < n; i+=2) { + buf[i] = -buf[i]; + } + // Like with the regular IMDCT at this point we still have the middle half + // of a transform but with even symmetry on the left and odd symmetry on + // the right + + // window overlapping + // The spec says to use samples [0..511] but the reference decoder uses + // samples [128..639]. + for (i = n4; i < n2; i ++) { + out[i - n4] = AAC_MUL31( buf[ n2 - 1 - i] , window[i - n4]) + + AAC_MUL31( saved[ i + n2] , window[i + n - n4]) + + AAC_MUL31(-saved[n + n2 - 1 - i] , window[i + 2*n - n4]) + + AAC_MUL31(-saved[ 2*n + n2 + i] , window[i + 3*n - n4]); + } + for (i = 0; i < n2; i ++) { + out[n4 + i] = AAC_MUL31( buf[ i] , window[i + n2 - n4]) + + AAC_MUL31(-saved[ n - 1 - i] , window[i + n2 + n - n4]) + + AAC_MUL31(-saved[ n + i] , window[i + n2 + 2*n - n4]) + + AAC_MUL31( saved[2*n + n - 1 - i] , window[i + n2 + 3*n - n4]); + } + for (i = 0; i < n4; i ++) { + out[n2 + n4 + i] = AAC_MUL31( buf[ i + n2] , window[i + n - n4]) + + AAC_MUL31(-saved[n2 - 1 - i] , window[i + 2*n - n4]) + + AAC_MUL31(-saved[n + n2 + i] , window[i + 3*n - n4]); + } + + // buffer update + memmove(saved + n, saved, 2 * n * sizeof(*saved)); + memcpy( saved, buf, n * sizeof(*saved)); +} + +/** + * channel coupling transformation interface + * + * @param apply_coupling_method pointer to (in)dependent coupling function + */ +static void apply_channel_coupling(AACContext *ac, ChannelElement *cc, + enum RawDataBlockType type, int elem_id, + enum CouplingPoint coupling_point, + void (*apply_coupling_method)(AACContext *ac, SingleChannelElement *target, ChannelElement *cce, int index)) +{ + int i, c; + + for (i = 0; i < MAX_ELEM_ID; i++) { + ChannelElement *cce = ac->che[TYPE_CCE][i]; + int index = 0; + + if (cce && cce->coup.coupling_point == coupling_point) { + ChannelCoupling *coup = &cce->coup; + + for (c = 0; c <= coup->num_coupled; c++) { + if (coup->type[c] == type && coup->id_select[c] == elem_id) { + if (coup->ch_select[c] != 1) { + apply_coupling_method(ac, &cc->ch[0], cce, index); + if (coup->ch_select[c] != 0) + index++; + } + if (coup->ch_select[c] != 2) + apply_coupling_method(ac, &cc->ch[1], cce, index++); + } else + index += 1 + (coup->ch_select[c] == 3); + } + } + } +} + +/** + * Convert spectral data to samples, applying all supported tools as appropriate. + */ +static void spectral_to_sample(AACContext *ac, int samples) +{ + int i, type; + void (*imdct_and_window)(AACContext *ac, SingleChannelElement *sce); + switch (ac->oc[1].m4ac.object_type) { + case AOT_ER_AAC_LD: + imdct_and_window = imdct_and_windowing_ld; + break; + case AOT_ER_AAC_ELD: + imdct_and_window = imdct_and_windowing_eld; + break; + default: + if (ac->oc[1].m4ac.frame_length_short) + imdct_and_window = imdct_and_windowing_960; + else + imdct_and_window = ac->imdct_and_windowing; + } + for (type = 3; type >= 0; type--) { + for (i = 0; i < MAX_ELEM_ID; i++) { + ChannelElement *che = ac->che[type][i]; + if (che && che->present) { + if (type <= TYPE_CPE) + apply_channel_coupling(ac, che, type, i, BEFORE_TNS, AAC_RENAME(apply_dependent_coupling)); + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) { + if (che->ch[0].ics.predictor_present) { + if (che->ch[0].ics.ltp.present) + ac->apply_ltp(ac, &che->ch[0]); + if (che->ch[1].ics.ltp.present && type == TYPE_CPE) + ac->apply_ltp(ac, &che->ch[1]); + } + } + if (che->ch[0].tns.present) + ac->apply_tns(che->ch[0].coeffs, &che->ch[0].tns, &che->ch[0].ics, 1); + if (che->ch[1].tns.present) + ac->apply_tns(che->ch[1].coeffs, &che->ch[1].tns, &che->ch[1].ics, 1); + if (type <= TYPE_CPE) + apply_channel_coupling(ac, che, type, i, BETWEEN_TNS_AND_IMDCT, AAC_RENAME(apply_dependent_coupling)); + if (type != TYPE_CCE || che->coup.coupling_point == AFTER_IMDCT) { + imdct_and_window(ac, &che->ch[0]); + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) + ac->update_ltp(ac, &che->ch[0]); + if (type == TYPE_CPE) { + imdct_and_window(ac, &che->ch[1]); + if (ac->oc[1].m4ac.object_type == AOT_AAC_LTP) + ac->update_ltp(ac, &che->ch[1]); + } + if (ac->oc[1].m4ac.sbr > 0) { + AAC_RENAME(ff_sbr_apply)(ac, &che->sbr, type, che->ch[0].ret, che->ch[1].ret); + } + } + if (type <= TYPE_CCE) + apply_channel_coupling(ac, che, type, i, AFTER_IMDCT, AAC_RENAME(apply_independent_coupling)); + +#if USE_FIXED + { + int j; + /* preparation for resampler */ + for(j = 0; jch[0].ret[j] = (int32_t)av_clip64((int64_t)che->ch[0].ret[j]*128, INT32_MIN, INT32_MAX-0x8000)+0x8000; + if(type == TYPE_CPE) + che->ch[1].ret[j] = (int32_t)av_clip64((int64_t)che->ch[1].ret[j]*128, INT32_MIN, INT32_MAX-0x8000)+0x8000; + } + } +#endif /* USE_FIXED */ + che->present = 0; + } else if (che) { + av_log(ac->avctx, AV_LOG_VERBOSE, "ChannelElement %d.%d missing \n", type, i); + } + } + } +} + +static int parse_adts_frame_header(AACContext *ac, GetBitContext *gb) +{ + int size; + AACADTSHeaderInfo hdr_info; + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int layout_map_tags, ret; + + size = ff_adts_header_parse(gb, &hdr_info); + if (size > 0) { + if (!ac->warned_num_aac_frames && hdr_info.num_aac_frames != 1) { + // This is 2 for "VLB " audio in NSV files. + // See samples/nsv/vlb_audio. + avpriv_report_missing_feature(ac->avctx, + "More than one AAC RDB per ADTS frame"); + ac->warned_num_aac_frames = 1; + } + push_output_configuration(ac); + if (hdr_info.chan_config) { + ac->oc[1].m4ac.chan_config = hdr_info.chan_config; + if ((ret = set_default_channel_config(ac->avctx, + layout_map, + &layout_map_tags, + hdr_info.chan_config)) < 0) + return ret; + if ((ret = output_configure(ac, layout_map, layout_map_tags, + FFMAX(ac->oc[1].status, + OC_TRIAL_FRAME), 0)) < 0) + return ret; + } else { + ac->oc[1].m4ac.chan_config = 0; + /** + * dual mono frames in Japanese DTV can have chan_config 0 + * WITHOUT specifying PCE. + * thus, set dual mono as default. + */ + if (ac->dmono_mode && ac->oc[0].status == OC_NONE) { + layout_map_tags = 2; + layout_map[0][0] = layout_map[1][0] = TYPE_SCE; + layout_map[0][2] = layout_map[1][2] = AAC_CHANNEL_FRONT; + layout_map[0][1] = 0; + layout_map[1][1] = 1; + if (output_configure(ac, layout_map, layout_map_tags, + OC_TRIAL_FRAME, 0)) + return -7; + } + } + ac->oc[1].m4ac.sample_rate = hdr_info.sample_rate; + ac->oc[1].m4ac.sampling_index = hdr_info.sampling_index; + ac->oc[1].m4ac.object_type = hdr_info.object_type; + ac->oc[1].m4ac.frame_length_short = 0; + if (ac->oc[0].status != OC_LOCKED || + ac->oc[0].m4ac.chan_config != hdr_info.chan_config || + ac->oc[0].m4ac.sample_rate != hdr_info.sample_rate) { + ac->oc[1].m4ac.sbr = -1; + ac->oc[1].m4ac.ps = -1; + } + if (!hdr_info.crc_absent) + skip_bits(gb, 16); + } + return size; +} + +static int aac_decode_er_frame(AVCodecContext *avctx, void *data, + int *got_frame_ptr, GetBitContext *gb) +{ + AACContext *ac = avctx->priv_data; + const MPEG4AudioConfig *const m4ac = &ac->oc[1].m4ac; + ChannelElement *che; + int err, i; + int samples = m4ac->frame_length_short ? 960 : 1024; + int chan_config = m4ac->chan_config; + int aot = m4ac->object_type; + + if (aot == AOT_ER_AAC_LD || aot == AOT_ER_AAC_ELD) + samples >>= 1; + + ac->frame = data; + + if ((err = frame_configure_elements(avctx)) < 0) + return err; + + // The FF_PROFILE_AAC_* defines are all object_type - 1 + // This may lead to an undefined profile being signaled + ac->avctx->profile = aot - 1; + + ac->tags_mapped = 0; + + if (chan_config < 0 || (chan_config >= 8 && chan_config < 11) || chan_config >= 13) { + avpriv_request_sample(avctx, "Unknown ER channel configuration %d", + chan_config); + return AVERROR_INVALIDDATA; + } + for (i = 0; i < tags_per_config[chan_config]; i++) { + const int elem_type = aac_channel_layout_map[chan_config-1][i][0]; + const int elem_id = aac_channel_layout_map[chan_config-1][i][1]; + if (!(che=get_che(ac, elem_type, elem_id))) { + av_log(ac->avctx, AV_LOG_ERROR, + "channel element %d.%d is not allocated\n", + elem_type, elem_id); + return AVERROR_INVALIDDATA; + } + che->present = 1; + if (aot != AOT_ER_AAC_ELD) + skip_bits(gb, 4); + switch (elem_type) { + case TYPE_SCE: + err = decode_ics(ac, &che->ch[0], gb, 0, 0); + break; + case TYPE_CPE: + err = decode_cpe(ac, gb, che); + break; + case TYPE_LFE: + err = decode_ics(ac, &che->ch[0], gb, 0, 0); + break; + } + if (err < 0) + return err; + } + + spectral_to_sample(ac, samples); + + if (!ac->frame->data[0] && samples) { + av_log(avctx, AV_LOG_ERROR, "no frame data found\n"); + return AVERROR_INVALIDDATA; + } + + ac->frame->nb_samples = samples; + ac->frame->sample_rate = avctx->sample_rate; + *got_frame_ptr = 1; + + skip_bits_long(gb, get_bits_left(gb)); + return 0; +} + +static int aac_decode_frame_int(AVCodecContext *avctx, void *data, + int *got_frame_ptr, GetBitContext *gb, AVPacket *avpkt) +{ + AACContext *ac = avctx->priv_data; + ChannelElement *che = NULL, *che_prev = NULL; + enum RawDataBlockType elem_type, che_prev_type = TYPE_END; + int err, elem_id; + int samples = 0, multiplier, audio_found = 0, pce_found = 0; + int is_dmono, sce_count = 0; + int payload_alignment; + uint8_t che_presence[4][MAX_ELEM_ID] = {{0}}; + + ac->frame = data; + + if (show_bits(gb, 12) == 0xfff) { + if ((err = parse_adts_frame_header(ac, gb)) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error decoding AAC frame header.\n"); + goto fail; + } + if (ac->oc[1].m4ac.sampling_index > 12) { + av_log(ac->avctx, AV_LOG_ERROR, "invalid sampling rate index %d\n", ac->oc[1].m4ac.sampling_index); + err = AVERROR_INVALIDDATA; + goto fail; + } + } + + if ((err = frame_configure_elements(avctx)) < 0) + goto fail; + + // The FF_PROFILE_AAC_* defines are all object_type - 1 + // This may lead to an undefined profile being signaled + ac->avctx->profile = ac->oc[1].m4ac.object_type - 1; + + payload_alignment = get_bits_count(gb); + ac->tags_mapped = 0; + // parse + while ((elem_type = get_bits(gb, 3)) != TYPE_END) { + elem_id = get_bits(gb, 4); + + if (avctx->debug & FF_DEBUG_STARTCODE) + av_log(avctx, AV_LOG_DEBUG, "Elem type:%x id:%x\n", elem_type, elem_id); + + if (!avctx->channels && elem_type != TYPE_PCE) { + err = AVERROR_INVALIDDATA; + goto fail; + } + + if (elem_type < TYPE_DSE) { + if (che_presence[elem_type][elem_id]) { + int error = che_presence[elem_type][elem_id] > 1; + av_log(ac->avctx, error ? AV_LOG_ERROR : AV_LOG_DEBUG, "channel element %d.%d duplicate\n", + elem_type, elem_id); + if (error) { + err = AVERROR_INVALIDDATA; + goto fail; + } + } + che_presence[elem_type][elem_id]++; + + if (!(che=get_che(ac, elem_type, elem_id))) { + av_log(ac->avctx, AV_LOG_ERROR, "channel element %d.%d is not allocated\n", + elem_type, elem_id); + err = AVERROR_INVALIDDATA; + goto fail; + } + samples = ac->oc[1].m4ac.frame_length_short ? 960 : 1024; + che->present = 1; + } + + switch (elem_type) { + + case TYPE_SCE: + err = decode_ics(ac, &che->ch[0], gb, 0, 0); + audio_found = 1; + sce_count++; + break; + + case TYPE_CPE: + err = decode_cpe(ac, gb, che); + audio_found = 1; + break; + + case TYPE_CCE: + err = decode_cce(ac, gb, che); + break; + + case TYPE_LFE: + err = decode_ics(ac, &che->ch[0], gb, 0, 0); + audio_found = 1; + break; + + case TYPE_DSE: + err = skip_data_stream_element(ac, gb); + break; + + case TYPE_PCE: { + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int tags; + + int pushed = push_output_configuration(ac); + if (pce_found && !pushed) { + err = AVERROR_INVALIDDATA; + goto fail; + } + + tags = decode_pce(avctx, &ac->oc[1].m4ac, layout_map, gb, + payload_alignment); + if (tags < 0) { + err = tags; + break; + } + if (pce_found) { + av_log(avctx, AV_LOG_ERROR, + "Not evaluating a further program_config_element as this construct is dubious at best.\n"); + pop_output_configuration(ac); + } else { + err = output_configure(ac, layout_map, tags, OC_TRIAL_PCE, 1); + if (!err) + ac->oc[1].m4ac.chan_config = 0; + pce_found = 1; + } + break; + } + + case TYPE_FIL: + if (elem_id == 15) + elem_id += get_bits(gb, 8) - 1; + if (get_bits_left(gb) < 8 * elem_id) { + av_log(avctx, AV_LOG_ERROR, "TYPE_FIL: "overread_err); + err = AVERROR_INVALIDDATA; + goto fail; + } + while (elem_id > 0) + elem_id -= decode_extension_payload(ac, gb, elem_id, che_prev, che_prev_type); + err = 0; /* FIXME */ + break; + + default: + err = AVERROR_BUG; /* should not happen, but keeps compiler happy */ + break; + } + + if (elem_type < TYPE_DSE) { + che_prev = che; + che_prev_type = elem_type; + } + + if (err) + goto fail; + + if (get_bits_left(gb) < 3) { + av_log(avctx, AV_LOG_ERROR, overread_err); + err = AVERROR_INVALIDDATA; + goto fail; + } + } + + if (!avctx->channels) { + *got_frame_ptr = 0; + return 0; + } + + multiplier = (ac->oc[1].m4ac.sbr == 1) ? ac->oc[1].m4ac.ext_sample_rate > ac->oc[1].m4ac.sample_rate : 0; + samples <<= multiplier; + + spectral_to_sample(ac, samples); + + if (ac->oc[1].status && audio_found) { + avctx->sample_rate = ac->oc[1].m4ac.sample_rate << multiplier; + avctx->frame_size = samples; + ac->oc[1].status = OC_LOCKED; + } + + if (multiplier) + avctx->internal->skip_samples_multiplier = 2; + + if (!ac->frame->data[0] && samples) { + av_log(avctx, AV_LOG_ERROR, "no frame data found\n"); + err = AVERROR_INVALIDDATA; + goto fail; + } + + if (samples) { + ac->frame->nb_samples = samples; + ac->frame->sample_rate = avctx->sample_rate; + } else + av_frame_unref(ac->frame); + *got_frame_ptr = !!samples; + + /* for dual-mono audio (SCE + SCE) */ + is_dmono = ac->dmono_mode && sce_count == 2 && + ac->oc[1].channel_layout == (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT); + if (is_dmono) { + if (ac->dmono_mode == 1) + ((AVFrame *)data)->data[1] =((AVFrame *)data)->data[0]; + else if (ac->dmono_mode == 2) + ((AVFrame *)data)->data[0] =((AVFrame *)data)->data[1]; + } + + return 0; +fail: + pop_output_configuration(ac); + return err; +} + +static int aac_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame_ptr, AVPacket *avpkt) +{ + AACContext *ac = avctx->priv_data; + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; + GetBitContext gb; + int buf_consumed; + int buf_offset; + int err; + int new_extradata_size; + const uint8_t *new_extradata = av_packet_get_side_data(avpkt, + AV_PKT_DATA_NEW_EXTRADATA, + &new_extradata_size); + int jp_dualmono_size; + const uint8_t *jp_dualmono = av_packet_get_side_data(avpkt, + AV_PKT_DATA_JP_DUALMONO, + &jp_dualmono_size); + + if (new_extradata) { + /* discard previous configuration */ + ac->oc[1].status = OC_NONE; + err = decode_audio_specific_config(ac, ac->avctx, &ac->oc[1].m4ac, + new_extradata, + new_extradata_size * 8LL, 1); + if (err < 0) { + return err; + } + } + + ac->dmono_mode = 0; + if (jp_dualmono && jp_dualmono_size > 0) + ac->dmono_mode = 1 + *jp_dualmono; + if (ac->force_dmono_mode >= 0) + ac->dmono_mode = ac->force_dmono_mode; + + if (INT_MAX / 8 <= buf_size) + return AVERROR_INVALIDDATA; + + if ((err = init_get_bits8(&gb, buf, buf_size)) < 0) + return err; + + switch (ac->oc[1].m4ac.object_type) { + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LTP: + case AOT_ER_AAC_LD: + case AOT_ER_AAC_ELD: + err = aac_decode_er_frame(avctx, data, got_frame_ptr, &gb); + break; + default: + err = aac_decode_frame_int(avctx, data, got_frame_ptr, &gb, avpkt); + } + if (err < 0) + return err; + + buf_consumed = (get_bits_count(&gb) + 7) >> 3; + for (buf_offset = buf_consumed; buf_offset < buf_size; buf_offset++) + if (buf[buf_offset]) + break; + + return buf_size > buf_offset ? buf_consumed : buf_size; +} + +static av_cold int aac_decode_close(AVCodecContext *avctx) +{ + AACContext *ac = avctx->priv_data; + int i, type; + + for (i = 0; i < MAX_ELEM_ID; i++) { + for (type = 0; type < 4; type++) { + if (ac->che[type][i]) + AAC_RENAME(ff_aac_sbr_ctx_close)(&ac->che[type][i]->sbr); + av_freep(&ac->che[type][i]); + } + } + + ff_mdct_end(&ac->mdct); + ff_mdct_end(&ac->mdct_small); + ff_mdct_end(&ac->mdct_ld); + ff_mdct_end(&ac->mdct_ltp); +#if !USE_FIXED + ff_mdct15_uninit(&ac->mdct120); + ff_mdct15_uninit(&ac->mdct480); + ff_mdct15_uninit(&ac->mdct960); +#endif + av_freep(&ac->fdsp); + return 0; +} + +static void aacdec_init(AACContext *c) +{ + c->imdct_and_windowing = imdct_and_windowing; + c->apply_ltp = apply_ltp; + c->apply_tns = apply_tns; + c->windowing_and_mdct_ltp = windowing_and_mdct_ltp; + c->update_ltp = update_ltp; +#if USE_FIXED + c->vector_pow43 = vector_pow43; + c->subband_scale = subband_scale; +#endif + +#if !USE_FIXED + if(ARCH_MIPS) + ff_aacdec_init_mips(c); +#endif /* !USE_FIXED */ +} +/** + * AVOptions for Japanese DTV specific extensions (ADTS only) + */ +#define AACDEC_FLAGS AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM +static const AVOption options[] = { + {"dual_mono_mode", "Select the channel to decode for dual mono", + offsetof(AACContext, force_dmono_mode), AV_OPT_TYPE_INT, {.i64=-1}, -1, 2, + AACDEC_FLAGS, "dual_mono_mode"}, + + {"auto", "autoselection", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"}, + {"main", "Select Main/Left channel", 0, AV_OPT_TYPE_CONST, {.i64= 1}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"}, + {"sub" , "Select Sub/Right channel", 0, AV_OPT_TYPE_CONST, {.i64= 2}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"}, + {"both", "Select both channels", 0, AV_OPT_TYPE_CONST, {.i64= 0}, INT_MIN, INT_MAX, AACDEC_FLAGS, "dual_mono_mode"}, + + {NULL}, +}; + +static const AVClass aac_decoder_class = { + .class_name = "AAC decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdectab.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdectab.h new file mode 100644 index 0000000000..baf51a74bf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacdectab.h @@ -0,0 +1,74 @@ +/* + * AAC decoder data + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC decoder data + * @author Oded Shimon ( ods15 ods15 dyndns org ) + * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) + */ + +#ifndef AVCODEC_AACDECTAB_H +#define AVCODEC_AACDECTAB_H + +#include "libavutil/channel_layout.h" +#include "aac.h" + +#include + +static const int8_t tags_per_config[16] = { 0, 1, 1, 2, 3, 3, 4, 5, 0, 0, 0, 4, 5, 0, 5, 0 }; + +static const uint8_t aac_channel_layout_map[16][5][3] = { + { { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, }, + { { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, }, + { { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, }, + { { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, { TYPE_SCE, 1, AAC_CHANNEL_BACK }, }, + { { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 1, AAC_CHANNEL_BACK }, }, + { { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 1, AAC_CHANNEL_BACK }, { TYPE_LFE, 0, AAC_CHANNEL_LFE }, }, + { { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 1, AAC_CHANNEL_FRONT }, { TYPE_CPE, 2, AAC_CHANNEL_BACK }, { TYPE_LFE, 0, AAC_CHANNEL_LFE }, }, + { { 0, } }, + { { 0, } }, + { { 0, } }, + { { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 1, AAC_CHANNEL_BACK }, { TYPE_SCE, 1, AAC_CHANNEL_BACK }, { TYPE_LFE, 0, AAC_CHANNEL_LFE }, }, + { { TYPE_SCE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 0, AAC_CHANNEL_FRONT }, { TYPE_CPE, 1, AAC_CHANNEL_SIDE }, { TYPE_CPE, 2, AAC_CHANNEL_BACK }, { TYPE_LFE, 0, AAC_CHANNEL_LFE }, }, + { { 0, } }, + /* TODO: Add 7+1 TOP configuration */ +}; + +static const uint64_t aac_channel_layout[16] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0_BACK, + AV_CH_LAYOUT_5POINT1_BACK, + AV_CH_LAYOUT_7POINT1_WIDE_BACK, + 0, + 0, + 0, + AV_CH_LAYOUT_6POINT1, + AV_CH_LAYOUT_7POINT1, + 0, + /* AV_CH_LAYOUT_7POINT1_TOP, */ +}; + +#endif /* AVCODEC_AACDECTAB_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc.c new file mode 100644 index 0000000000..4d0abb107f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc.c @@ -0,0 +1,1165 @@ +/* + * AAC encoder + * Copyright (C) 2008 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder + */ + +/*********************************** + * TODOs: + * add sane pulse detection + ***********************************/ + +#include "libavutil/libm.h" +#include "libavutil/thread.h" +#include "libavutil/float_dsp.h" +#include "libavutil/opt.h" +#include "avcodec.h" +#include "put_bits.h" +#include "internal.h" +#include "mpeg4audio.h" +#include "kbdwin.h" +#include "sinewin.h" + +#include "aac.h" +#include "aactab.h" +#include "aacenc.h" +#include "aacenctab.h" +#include "aacenc_utils.h" + +#include "psymodel.h" + +static AVOnce aac_table_init = AV_ONCE_INIT; + +static void put_pce(PutBitContext *pb, AVCodecContext *avctx) +{ + int i, j; + AACEncContext *s = avctx->priv_data; + AACPCEInfo *pce = &s->pce; + const int bitexact = avctx->flags & AV_CODEC_FLAG_BITEXACT; + const char *aux_data = bitexact ? "Lavc" : LIBAVCODEC_IDENT; + + put_bits(pb, 4, 0); + + put_bits(pb, 2, avctx->profile); + put_bits(pb, 4, s->samplerate_index); + + put_bits(pb, 4, pce->num_ele[0]); /* Front */ + put_bits(pb, 4, pce->num_ele[1]); /* Side */ + put_bits(pb, 4, pce->num_ele[2]); /* Back */ + put_bits(pb, 2, pce->num_ele[3]); /* LFE */ + put_bits(pb, 3, 0); /* Assoc data */ + put_bits(pb, 4, 0); /* CCs */ + + put_bits(pb, 1, 0); /* Stereo mixdown */ + put_bits(pb, 1, 0); /* Mono mixdown */ + put_bits(pb, 1, 0); /* Something else */ + + for (i = 0; i < 4; i++) { + for (j = 0; j < pce->num_ele[i]; j++) { + if (i < 3) + put_bits(pb, 1, pce->pairing[i][j]); + put_bits(pb, 4, pce->index[i][j]); + } + } + + avpriv_align_put_bits(pb); + put_bits(pb, 8, strlen(aux_data)); + avpriv_put_string(pb, aux_data, 0); +} + +/** + * Make AAC audio config object. + * @see 1.6.2.1 "Syntax - AudioSpecificConfig" + */ +static int put_audio_specific_config(AVCodecContext *avctx) +{ + PutBitContext pb; + AACEncContext *s = avctx->priv_data; + int channels = (!s->needs_pce)*(s->channels - (s->channels == 8 ? 1 : 0)); + const int max_size = 32; + + avctx->extradata = av_mallocz(max_size); + if (!avctx->extradata) + return AVERROR(ENOMEM); + + init_put_bits(&pb, avctx->extradata, max_size); + put_bits(&pb, 5, s->profile+1); //profile + put_bits(&pb, 4, s->samplerate_index); //sample rate index + put_bits(&pb, 4, channels); + //GASpecificConfig + put_bits(&pb, 1, 0); //frame length - 1024 samples + put_bits(&pb, 1, 0); //does not depend on core coder + put_bits(&pb, 1, 0); //is not extension + if (s->needs_pce) + put_pce(&pb, avctx); + + //Explicitly Mark SBR absent + put_bits(&pb, 11, 0x2b7); //sync extension + put_bits(&pb, 5, AOT_SBR); + put_bits(&pb, 1, 0); + flush_put_bits(&pb); + avctx->extradata_size = put_bits_count(&pb) >> 3; + + return 0; +} + +void ff_quantize_band_cost_cache_init(struct AACEncContext *s) +{ + ++s->quantize_band_cost_cache_generation; + if (s->quantize_band_cost_cache_generation == 0) { + memset(s->quantize_band_cost_cache, 0, sizeof(s->quantize_band_cost_cache)); + s->quantize_band_cost_cache_generation = 1; + } +} + +#define WINDOW_FUNC(type) \ +static void apply_ ##type ##_window(AVFloatDSPContext *fdsp, \ + SingleChannelElement *sce, \ + const float *audio) + +WINDOW_FUNC(only_long) +{ + const float *lwindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_long_1024 : ff_sine_1024; + const float *pwindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_long_1024 : ff_sine_1024; + float *out = sce->ret_buf; + + fdsp->vector_fmul (out, audio, lwindow, 1024); + fdsp->vector_fmul_reverse(out + 1024, audio + 1024, pwindow, 1024); +} + +WINDOW_FUNC(long_start) +{ + const float *lwindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_long_1024 : ff_sine_1024; + const float *swindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128; + float *out = sce->ret_buf; + + fdsp->vector_fmul(out, audio, lwindow, 1024); + memcpy(out + 1024, audio + 1024, sizeof(out[0]) * 448); + fdsp->vector_fmul_reverse(out + 1024 + 448, audio + 1024 + 448, swindow, 128); + memset(out + 1024 + 576, 0, sizeof(out[0]) * 448); +} + +WINDOW_FUNC(long_stop) +{ + const float *lwindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_long_1024 : ff_sine_1024; + const float *swindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_short_128 : ff_sine_128; + float *out = sce->ret_buf; + + memset(out, 0, sizeof(out[0]) * 448); + fdsp->vector_fmul(out + 448, audio + 448, swindow, 128); + memcpy(out + 576, audio + 576, sizeof(out[0]) * 448); + fdsp->vector_fmul_reverse(out + 1024, audio + 1024, lwindow, 1024); +} + +WINDOW_FUNC(eight_short) +{ + const float *swindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128; + const float *pwindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_short_128 : ff_sine_128; + const float *in = audio + 448; + float *out = sce->ret_buf; + int w; + + for (w = 0; w < 8; w++) { + fdsp->vector_fmul (out, in, w ? pwindow : swindow, 128); + out += 128; + in += 128; + fdsp->vector_fmul_reverse(out, in, swindow, 128); + out += 128; + } +} + +static void (*const apply_window[4])(AVFloatDSPContext *fdsp, + SingleChannelElement *sce, + const float *audio) = { + [ONLY_LONG_SEQUENCE] = apply_only_long_window, + [LONG_START_SEQUENCE] = apply_long_start_window, + [EIGHT_SHORT_SEQUENCE] = apply_eight_short_window, + [LONG_STOP_SEQUENCE] = apply_long_stop_window +}; + +static void apply_window_and_mdct(AACEncContext *s, SingleChannelElement *sce, + float *audio) +{ + int i; + const float *output = sce->ret_buf; + + apply_window[sce->ics.window_sequence[0]](s->fdsp, sce, audio); + + if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) + s->mdct1024.mdct_calc(&s->mdct1024, sce->coeffs, output); + else + for (i = 0; i < 1024; i += 128) + s->mdct128.mdct_calc(&s->mdct128, &sce->coeffs[i], output + i*2); + memcpy(audio, audio + 1024, sizeof(audio[0]) * 1024); + memcpy(sce->pcoeffs, sce->coeffs, sizeof(sce->pcoeffs)); +} + +/** + * Encode ics_info element. + * @see Table 4.6 (syntax of ics_info) + */ +static void put_ics_info(AACEncContext *s, IndividualChannelStream *info) +{ + int w; + + put_bits(&s->pb, 1, 0); // ics_reserved bit + put_bits(&s->pb, 2, info->window_sequence[0]); + put_bits(&s->pb, 1, info->use_kb_window[0]); + if (info->window_sequence[0] != EIGHT_SHORT_SEQUENCE) { + put_bits(&s->pb, 6, info->max_sfb); + put_bits(&s->pb, 1, !!info->predictor_present); + } else { + put_bits(&s->pb, 4, info->max_sfb); + for (w = 1; w < 8; w++) + put_bits(&s->pb, 1, !info->group_len[w]); + } +} + +/** + * Encode MS data. + * @see 4.6.8.1 "Joint Coding - M/S Stereo" + */ +static void encode_ms_info(PutBitContext *pb, ChannelElement *cpe) +{ + int i, w; + + put_bits(pb, 2, cpe->ms_mode); + if (cpe->ms_mode == 1) + for (w = 0; w < cpe->ch[0].ics.num_windows; w += cpe->ch[0].ics.group_len[w]) + for (i = 0; i < cpe->ch[0].ics.max_sfb; i++) + put_bits(pb, 1, cpe->ms_mask[w*16 + i]); +} + +/** + * Produce integer coefficients from scalefactors provided by the model. + */ +static void adjust_frame_information(ChannelElement *cpe, int chans) +{ + int i, w, w2, g, ch; + int maxsfb, cmaxsfb; + + for (ch = 0; ch < chans; ch++) { + IndividualChannelStream *ics = &cpe->ch[ch].ics; + maxsfb = 0; + cpe->ch[ch].pulse.num_pulse = 0; + for (w = 0; w < ics->num_windows; w += ics->group_len[w]) { + for (w2 = 0; w2 < ics->group_len[w]; w2++) { + for (cmaxsfb = ics->num_swb; cmaxsfb > 0 && cpe->ch[ch].zeroes[w*16+cmaxsfb-1]; cmaxsfb--) + ; + maxsfb = FFMAX(maxsfb, cmaxsfb); + } + } + ics->max_sfb = maxsfb; + + //adjust zero bands for window groups + for (w = 0; w < ics->num_windows; w += ics->group_len[w]) { + for (g = 0; g < ics->max_sfb; g++) { + i = 1; + for (w2 = w; w2 < w + ics->group_len[w]; w2++) { + if (!cpe->ch[ch].zeroes[w2*16 + g]) { + i = 0; + break; + } + } + cpe->ch[ch].zeroes[w*16 + g] = i; + } + } + } + + if (chans > 1 && cpe->common_window) { + IndividualChannelStream *ics0 = &cpe->ch[0].ics; + IndividualChannelStream *ics1 = &cpe->ch[1].ics; + int msc = 0; + ics0->max_sfb = FFMAX(ics0->max_sfb, ics1->max_sfb); + ics1->max_sfb = ics0->max_sfb; + for (w = 0; w < ics0->num_windows*16; w += 16) + for (i = 0; i < ics0->max_sfb; i++) + if (cpe->ms_mask[w+i]) + msc++; + if (msc == 0 || ics0->max_sfb == 0) + cpe->ms_mode = 0; + else + cpe->ms_mode = msc < ics0->max_sfb * ics0->num_windows ? 1 : 2; + } +} + +static void apply_intensity_stereo(ChannelElement *cpe) +{ + int w, w2, g, i; + IndividualChannelStream *ics = &cpe->ch[0].ics; + if (!cpe->common_window) + return; + for (w = 0; w < ics->num_windows; w += ics->group_len[w]) { + for (w2 = 0; w2 < ics->group_len[w]; w2++) { + int start = (w+w2) * 128; + for (g = 0; g < ics->num_swb; g++) { + int p = -1 + 2 * (cpe->ch[1].band_type[w*16+g] - 14); + float scale = cpe->ch[0].is_ener[w*16+g]; + if (!cpe->is_mask[w*16 + g]) { + start += ics->swb_sizes[g]; + continue; + } + if (cpe->ms_mask[w*16 + g]) + p *= -1; + for (i = 0; i < ics->swb_sizes[g]; i++) { + float sum = (cpe->ch[0].coeffs[start+i] + p*cpe->ch[1].coeffs[start+i])*scale; + cpe->ch[0].coeffs[start+i] = sum; + cpe->ch[1].coeffs[start+i] = 0.0f; + } + start += ics->swb_sizes[g]; + } + } + } +} + +static void apply_mid_side_stereo(ChannelElement *cpe) +{ + int w, w2, g, i; + IndividualChannelStream *ics = &cpe->ch[0].ics; + if (!cpe->common_window) + return; + for (w = 0; w < ics->num_windows; w += ics->group_len[w]) { + for (w2 = 0; w2 < ics->group_len[w]; w2++) { + int start = (w+w2) * 128; + for (g = 0; g < ics->num_swb; g++) { + /* ms_mask can be used for other purposes in PNS and I/S, + * so must not apply M/S if any band uses either, even if + * ms_mask is set. + */ + if (!cpe->ms_mask[w*16 + g] || cpe->is_mask[w*16 + g] + || cpe->ch[0].band_type[w*16 + g] >= NOISE_BT + || cpe->ch[1].band_type[w*16 + g] >= NOISE_BT) { + start += ics->swb_sizes[g]; + continue; + } + for (i = 0; i < ics->swb_sizes[g]; i++) { + float L = (cpe->ch[0].coeffs[start+i] + cpe->ch[1].coeffs[start+i]) * 0.5f; + float R = L - cpe->ch[1].coeffs[start+i]; + cpe->ch[0].coeffs[start+i] = L; + cpe->ch[1].coeffs[start+i] = R; + } + start += ics->swb_sizes[g]; + } + } + } +} + +/** + * Encode scalefactor band coding type. + */ +static void encode_band_info(AACEncContext *s, SingleChannelElement *sce) +{ + int w; + + if (s->coder->set_special_band_scalefactors) + s->coder->set_special_band_scalefactors(s, sce); + + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) + s->coder->encode_window_bands_info(s, sce, w, sce->ics.group_len[w], s->lambda); +} + +/** + * Encode scalefactors. + */ +static void encode_scale_factors(AVCodecContext *avctx, AACEncContext *s, + SingleChannelElement *sce) +{ + int diff, off_sf = sce->sf_idx[0], off_pns = sce->sf_idx[0] - NOISE_OFFSET; + int off_is = 0, noise_flag = 1; + int i, w; + + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (i = 0; i < sce->ics.max_sfb; i++) { + if (!sce->zeroes[w*16 + i]) { + if (sce->band_type[w*16 + i] == NOISE_BT) { + diff = sce->sf_idx[w*16 + i] - off_pns; + off_pns = sce->sf_idx[w*16 + i]; + if (noise_flag-- > 0) { + put_bits(&s->pb, NOISE_PRE_BITS, diff + NOISE_PRE); + continue; + } + } else if (sce->band_type[w*16 + i] == INTENSITY_BT || + sce->band_type[w*16 + i] == INTENSITY_BT2) { + diff = sce->sf_idx[w*16 + i] - off_is; + off_is = sce->sf_idx[w*16 + i]; + } else { + diff = sce->sf_idx[w*16 + i] - off_sf; + off_sf = sce->sf_idx[w*16 + i]; + } + diff += SCALE_DIFF_ZERO; + av_assert0(diff >= 0 && diff <= 120); + put_bits(&s->pb, ff_aac_scalefactor_bits[diff], ff_aac_scalefactor_code[diff]); + } + } + } +} + +/** + * Encode pulse data. + */ +static void encode_pulses(AACEncContext *s, Pulse *pulse) +{ + int i; + + put_bits(&s->pb, 1, !!pulse->num_pulse); + if (!pulse->num_pulse) + return; + + put_bits(&s->pb, 2, pulse->num_pulse - 1); + put_bits(&s->pb, 6, pulse->start); + for (i = 0; i < pulse->num_pulse; i++) { + put_bits(&s->pb, 5, pulse->pos[i]); + put_bits(&s->pb, 4, pulse->amp[i]); + } +} + +/** + * Encode spectral coefficients processed by psychoacoustic model. + */ +static void encode_spectral_coeffs(AACEncContext *s, SingleChannelElement *sce) +{ + int start, i, w, w2; + + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + start = 0; + for (i = 0; i < sce->ics.max_sfb; i++) { + if (sce->zeroes[w*16 + i]) { + start += sce->ics.swb_sizes[i]; + continue; + } + for (w2 = w; w2 < w + sce->ics.group_len[w]; w2++) { + s->coder->quantize_and_encode_band(s, &s->pb, + &sce->coeffs[start + w2*128], + NULL, sce->ics.swb_sizes[i], + sce->sf_idx[w*16 + i], + sce->band_type[w*16 + i], + s->lambda, + sce->ics.window_clipping[w]); + } + start += sce->ics.swb_sizes[i]; + } + } +} + +/** + * Downscale spectral coefficients for near-clipping windows to avoid artifacts + */ +static void avoid_clipping(AACEncContext *s, SingleChannelElement *sce) +{ + int start, i, j, w; + + if (sce->ics.clip_avoidance_factor < 1.0f) { + for (w = 0; w < sce->ics.num_windows; w++) { + start = 0; + for (i = 0; i < sce->ics.max_sfb; i++) { + float *swb_coeffs = &sce->coeffs[start + w*128]; + for (j = 0; j < sce->ics.swb_sizes[i]; j++) + swb_coeffs[j] *= sce->ics.clip_avoidance_factor; + start += sce->ics.swb_sizes[i]; + } + } + } +} + +/** + * Encode one channel of audio data. + */ +static int encode_individual_channel(AVCodecContext *avctx, AACEncContext *s, + SingleChannelElement *sce, + int common_window) +{ + put_bits(&s->pb, 8, sce->sf_idx[0]); + if (!common_window) { + put_ics_info(s, &sce->ics); + if (s->coder->encode_main_pred) + s->coder->encode_main_pred(s, sce); + if (s->coder->encode_ltp_info) + s->coder->encode_ltp_info(s, sce, 0); + } + encode_band_info(s, sce); + encode_scale_factors(avctx, s, sce); + encode_pulses(s, &sce->pulse); + put_bits(&s->pb, 1, !!sce->tns.present); + if (s->coder->encode_tns_info) + s->coder->encode_tns_info(s, sce); + put_bits(&s->pb, 1, 0); //ssr + encode_spectral_coeffs(s, sce); + return 0; +} + +/** + * Write some auxiliary information about the created AAC file. + */ +static void put_bitstream_info(AACEncContext *s, const char *name) +{ + int i, namelen, padbits; + + namelen = strlen(name) + 2; + put_bits(&s->pb, 3, TYPE_FIL); + put_bits(&s->pb, 4, FFMIN(namelen, 15)); + if (namelen >= 15) + put_bits(&s->pb, 8, namelen - 14); + put_bits(&s->pb, 4, 0); //extension type - filler + padbits = -put_bits_count(&s->pb) & 7; + avpriv_align_put_bits(&s->pb); + for (i = 0; i < namelen - 2; i++) + put_bits(&s->pb, 8, name[i]); + put_bits(&s->pb, 12 - padbits, 0); +} + +/* + * Copy input samples. + * Channels are reordered from libavcodec's default order to AAC order. + */ +static void copy_input_samples(AACEncContext *s, const AVFrame *frame) +{ + int ch; + int end = 2048 + (frame ? frame->nb_samples : 0); + const uint8_t *channel_map = s->reorder_map; + + /* copy and remap input samples */ + for (ch = 0; ch < s->channels; ch++) { + /* copy last 1024 samples of previous frame to the start of the current frame */ + memcpy(&s->planar_samples[ch][1024], &s->planar_samples[ch][2048], 1024 * sizeof(s->planar_samples[0][0])); + + /* copy new samples and zero any remaining samples */ + if (frame) { + memcpy(&s->planar_samples[ch][2048], + frame->extended_data[channel_map[ch]], + frame->nb_samples * sizeof(s->planar_samples[0][0])); + } + memset(&s->planar_samples[ch][end], 0, + (3072 - end) * sizeof(s->planar_samples[0][0])); + } +} + +static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + AACEncContext *s = avctx->priv_data; + float **samples = s->planar_samples, *samples2, *la, *overlap; + ChannelElement *cpe; + SingleChannelElement *sce; + IndividualChannelStream *ics; + int i, its, ch, w, chans, tag, start_ch, ret, frame_bits; + int target_bits, rate_bits, too_many_bits, too_few_bits; + int ms_mode = 0, is_mode = 0, tns_mode = 0, pred_mode = 0; + int chan_el_counter[4]; + FFPsyWindowInfo windows[AAC_MAX_CHANNELS]; + + /* add current frame to queue */ + if (frame) { + if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) + return ret; + } else { + if (!s->afq.remaining_samples || (!s->afq.frame_alloc && !s->afq.frame_count)) + return 0; + } + + copy_input_samples(s, frame); + if (s->psypp) + ff_psy_preprocess(s->psypp, s->planar_samples, s->channels); + + if (!avctx->frame_number) + return 0; + + start_ch = 0; + for (i = 0; i < s->chan_map[0]; i++) { + FFPsyWindowInfo* wi = windows + start_ch; + tag = s->chan_map[i+1]; + chans = tag == TYPE_CPE ? 2 : 1; + cpe = &s->cpe[i]; + for (ch = 0; ch < chans; ch++) { + int k; + float clip_avoidance_factor; + sce = &cpe->ch[ch]; + ics = &sce->ics; + s->cur_channel = start_ch + ch; + overlap = &samples[s->cur_channel][0]; + samples2 = overlap + 1024; + la = samples2 + (448+64); + if (!frame) + la = NULL; + if (tag == TYPE_LFE) { + wi[ch].window_type[0] = wi[ch].window_type[1] = ONLY_LONG_SEQUENCE; + wi[ch].window_shape = 0; + wi[ch].num_windows = 1; + wi[ch].grouping[0] = 1; + wi[ch].clipping[0] = 0; + + /* Only the lowest 12 coefficients are used in a LFE channel. + * The expression below results in only the bottom 8 coefficients + * being used for 11.025kHz to 16kHz sample rates. + */ + ics->num_swb = s->samplerate_index >= 8 ? 1 : 3; + } else { + wi[ch] = s->psy.model->window(&s->psy, samples2, la, s->cur_channel, + ics->window_sequence[0]); + } + ics->window_sequence[1] = ics->window_sequence[0]; + ics->window_sequence[0] = wi[ch].window_type[0]; + ics->use_kb_window[1] = ics->use_kb_window[0]; + ics->use_kb_window[0] = wi[ch].window_shape; + ics->num_windows = wi[ch].num_windows; + ics->swb_sizes = s->psy.bands [ics->num_windows == 8]; + ics->num_swb = tag == TYPE_LFE ? ics->num_swb : s->psy.num_bands[ics->num_windows == 8]; + ics->max_sfb = FFMIN(ics->max_sfb, ics->num_swb); + ics->swb_offset = wi[ch].window_type[0] == EIGHT_SHORT_SEQUENCE ? + ff_swb_offset_128 [s->samplerate_index]: + ff_swb_offset_1024[s->samplerate_index]; + ics->tns_max_bands = wi[ch].window_type[0] == EIGHT_SHORT_SEQUENCE ? + ff_tns_max_bands_128 [s->samplerate_index]: + ff_tns_max_bands_1024[s->samplerate_index]; + + for (w = 0; w < ics->num_windows; w++) + ics->group_len[w] = wi[ch].grouping[w]; + + /* Calculate input sample maximums and evaluate clipping risk */ + clip_avoidance_factor = 0.0f; + for (w = 0; w < ics->num_windows; w++) { + const float *wbuf = overlap + w * 128; + const int wlen = 2048 / ics->num_windows; + float max = 0; + int j; + /* mdct input is 2 * output */ + for (j = 0; j < wlen; j++) + max = FFMAX(max, fabsf(wbuf[j])); + wi[ch].clipping[w] = max; + } + for (w = 0; w < ics->num_windows; w++) { + if (wi[ch].clipping[w] > CLIP_AVOIDANCE_FACTOR) { + ics->window_clipping[w] = 1; + clip_avoidance_factor = FFMAX(clip_avoidance_factor, wi[ch].clipping[w]); + } else { + ics->window_clipping[w] = 0; + } + } + if (clip_avoidance_factor > CLIP_AVOIDANCE_FACTOR) { + ics->clip_avoidance_factor = CLIP_AVOIDANCE_FACTOR / clip_avoidance_factor; + } else { + ics->clip_avoidance_factor = 1.0f; + } + + apply_window_and_mdct(s, sce, overlap); + + if (s->options.ltp && s->coder->update_ltp) { + s->coder->update_ltp(s, sce); + apply_window[sce->ics.window_sequence[0]](s->fdsp, sce, &sce->ltp_state[0]); + s->mdct1024.mdct_calc(&s->mdct1024, sce->lcoeffs, sce->ret_buf); + } + + for (k = 0; k < 1024; k++) { + if (!(fabs(cpe->ch[ch].coeffs[k]) < 1E16)) { // Ensure headroom for energy calculation + av_log(avctx, AV_LOG_ERROR, "Input contains (near) NaN/+-Inf\n"); + return AVERROR(EINVAL); + } + } + avoid_clipping(s, sce); + } + start_ch += chans; + } + if ((ret = ff_alloc_packet2(avctx, avpkt, 8192 * s->channels, 0)) < 0) + return ret; + frame_bits = its = 0; + do { + init_put_bits(&s->pb, avpkt->data, avpkt->size); + + if ((avctx->frame_number & 0xFF)==1 && !(avctx->flags & AV_CODEC_FLAG_BITEXACT)) + put_bitstream_info(s, LIBAVCODEC_IDENT); + start_ch = 0; + target_bits = 0; + memset(chan_el_counter, 0, sizeof(chan_el_counter)); + for (i = 0; i < s->chan_map[0]; i++) { + FFPsyWindowInfo* wi = windows + start_ch; + const float *coeffs[2]; + tag = s->chan_map[i+1]; + chans = tag == TYPE_CPE ? 2 : 1; + cpe = &s->cpe[i]; + cpe->common_window = 0; + memset(cpe->is_mask, 0, sizeof(cpe->is_mask)); + memset(cpe->ms_mask, 0, sizeof(cpe->ms_mask)); + put_bits(&s->pb, 3, tag); + put_bits(&s->pb, 4, chan_el_counter[tag]++); + for (ch = 0; ch < chans; ch++) { + sce = &cpe->ch[ch]; + coeffs[ch] = sce->coeffs; + sce->ics.predictor_present = 0; + sce->ics.ltp.present = 0; + memset(sce->ics.ltp.used, 0, sizeof(sce->ics.ltp.used)); + memset(sce->ics.prediction_used, 0, sizeof(sce->ics.prediction_used)); + memset(&sce->tns, 0, sizeof(TemporalNoiseShaping)); + for (w = 0; w < 128; w++) + if (sce->band_type[w] > RESERVED_BT) + sce->band_type[w] = 0; + } + s->psy.bitres.alloc = -1; + s->psy.bitres.bits = s->last_frame_pb_count / s->channels; + s->psy.model->analyze(&s->psy, start_ch, coeffs, wi); + if (s->psy.bitres.alloc > 0) { + /* Lambda unused here on purpose, we need to take psy's unscaled allocation */ + target_bits += s->psy.bitres.alloc + * (s->lambda / (avctx->global_quality ? avctx->global_quality : 120)); + s->psy.bitres.alloc /= chans; + } + s->cur_type = tag; + for (ch = 0; ch < chans; ch++) { + s->cur_channel = start_ch + ch; + if (s->options.pns && s->coder->mark_pns) + s->coder->mark_pns(s, avctx, &cpe->ch[ch]); + s->coder->search_for_quantizers(avctx, s, &cpe->ch[ch], s->lambda); + } + if (chans > 1 + && wi[0].window_type[0] == wi[1].window_type[0] + && wi[0].window_shape == wi[1].window_shape) { + + cpe->common_window = 1; + for (w = 0; w < wi[0].num_windows; w++) { + if (wi[0].grouping[w] != wi[1].grouping[w]) { + cpe->common_window = 0; + break; + } + } + } + for (ch = 0; ch < chans; ch++) { /* TNS and PNS */ + sce = &cpe->ch[ch]; + s->cur_channel = start_ch + ch; + if (s->options.tns && s->coder->search_for_tns) + s->coder->search_for_tns(s, sce); + if (s->options.tns && s->coder->apply_tns_filt) + s->coder->apply_tns_filt(s, sce); + if (sce->tns.present) + tns_mode = 1; + if (s->options.pns && s->coder->search_for_pns) + s->coder->search_for_pns(s, avctx, sce); + } + s->cur_channel = start_ch; + if (s->options.intensity_stereo) { /* Intensity Stereo */ + if (s->coder->search_for_is) + s->coder->search_for_is(s, avctx, cpe); + if (cpe->is_mode) is_mode = 1; + apply_intensity_stereo(cpe); + } + if (s->options.pred) { /* Prediction */ + for (ch = 0; ch < chans; ch++) { + sce = &cpe->ch[ch]; + s->cur_channel = start_ch + ch; + if (s->options.pred && s->coder->search_for_pred) + s->coder->search_for_pred(s, sce); + if (cpe->ch[ch].ics.predictor_present) pred_mode = 1; + } + if (s->coder->adjust_common_pred) + s->coder->adjust_common_pred(s, cpe); + for (ch = 0; ch < chans; ch++) { + sce = &cpe->ch[ch]; + s->cur_channel = start_ch + ch; + if (s->options.pred && s->coder->apply_main_pred) + s->coder->apply_main_pred(s, sce); + } + s->cur_channel = start_ch; + } + if (s->options.mid_side) { /* Mid/Side stereo */ + if (s->options.mid_side == -1 && s->coder->search_for_ms) + s->coder->search_for_ms(s, cpe); + else if (cpe->common_window) + memset(cpe->ms_mask, 1, sizeof(cpe->ms_mask)); + apply_mid_side_stereo(cpe); + } + adjust_frame_information(cpe, chans); + if (s->options.ltp) { /* LTP */ + for (ch = 0; ch < chans; ch++) { + sce = &cpe->ch[ch]; + s->cur_channel = start_ch + ch; + if (s->coder->search_for_ltp) + s->coder->search_for_ltp(s, sce, cpe->common_window); + if (sce->ics.ltp.present) pred_mode = 1; + } + s->cur_channel = start_ch; + if (s->coder->adjust_common_ltp) + s->coder->adjust_common_ltp(s, cpe); + } + if (chans == 2) { + put_bits(&s->pb, 1, cpe->common_window); + if (cpe->common_window) { + put_ics_info(s, &cpe->ch[0].ics); + if (s->coder->encode_main_pred) + s->coder->encode_main_pred(s, &cpe->ch[0]); + if (s->coder->encode_ltp_info) + s->coder->encode_ltp_info(s, &cpe->ch[0], 1); + encode_ms_info(&s->pb, cpe); + if (cpe->ms_mode) ms_mode = 1; + } + } + for (ch = 0; ch < chans; ch++) { + s->cur_channel = start_ch + ch; + encode_individual_channel(avctx, s, &cpe->ch[ch], cpe->common_window); + } + start_ch += chans; + } + + if (avctx->flags & AV_CODEC_FLAG_QSCALE) { + /* When using a constant Q-scale, don't mess with lambda */ + break; + } + + /* rate control stuff + * allow between the nominal bitrate, and what psy's bit reservoir says to target + * but drift towards the nominal bitrate always + */ + frame_bits = put_bits_count(&s->pb); + rate_bits = avctx->bit_rate * 1024 / avctx->sample_rate; + rate_bits = FFMIN(rate_bits, 6144 * s->channels - 3); + too_many_bits = FFMAX(target_bits, rate_bits); + too_many_bits = FFMIN(too_many_bits, 6144 * s->channels - 3); + too_few_bits = FFMIN(FFMAX(rate_bits - rate_bits/4, target_bits), too_many_bits); + + /* When using ABR, be strict (but only for increasing) */ + too_few_bits = too_few_bits - too_few_bits/8; + too_many_bits = too_many_bits + too_many_bits/2; + + if ( its == 0 /* for steady-state Q-scale tracking */ + || (its < 5 && (frame_bits < too_few_bits || frame_bits > too_many_bits)) + || frame_bits >= 6144 * s->channels - 3 ) + { + float ratio = ((float)rate_bits) / frame_bits; + + if (frame_bits >= too_few_bits && frame_bits <= too_many_bits) { + /* + * This path is for steady-state Q-scale tracking + * When frame bits fall within the stable range, we still need to adjust + * lambda to maintain it like so in a stable fashion (large jumps in lambda + * create artifacts and should be avoided), but slowly + */ + ratio = sqrtf(sqrtf(ratio)); + ratio = av_clipf(ratio, 0.9f, 1.1f); + } else { + /* Not so fast though */ + ratio = sqrtf(ratio); + } + s->lambda = FFMIN(s->lambda * ratio, 65536.f); + + /* Keep iterating if we must reduce and lambda is in the sky */ + if (ratio > 0.9f && ratio < 1.1f) { + break; + } else { + if (is_mode || ms_mode || tns_mode || pred_mode) { + for (i = 0; i < s->chan_map[0]; i++) { + // Must restore coeffs + chans = tag == TYPE_CPE ? 2 : 1; + cpe = &s->cpe[i]; + for (ch = 0; ch < chans; ch++) + memcpy(cpe->ch[ch].coeffs, cpe->ch[ch].pcoeffs, sizeof(cpe->ch[ch].coeffs)); + } + } + its++; + } + } else { + break; + } + } while (1); + + if (s->options.ltp && s->coder->ltp_insert_new_frame) + s->coder->ltp_insert_new_frame(s); + + put_bits(&s->pb, 3, TYPE_END); + flush_put_bits(&s->pb); + + s->last_frame_pb_count = put_bits_count(&s->pb); + + s->lambda_sum += s->lambda; + s->lambda_count++; + + ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, + &avpkt->duration); + + avpkt->size = put_bits_count(&s->pb) >> 3; + *got_packet_ptr = 1; + return 0; +} + +static av_cold int aac_encode_end(AVCodecContext *avctx) +{ + AACEncContext *s = avctx->priv_data; + + av_log(avctx, AV_LOG_INFO, "Qavg: %.3f\n", s->lambda_sum / s->lambda_count); + + ff_mdct_end(&s->mdct1024); + ff_mdct_end(&s->mdct128); + ff_psy_end(&s->psy); + ff_lpc_end(&s->lpc); + if (s->psypp) + ff_psy_preprocess_end(s->psypp); + av_freep(&s->buffer.samples); + av_freep(&s->cpe); + av_freep(&s->fdsp); + ff_af_queue_close(&s->afq); + return 0; +} + +static av_cold int dsp_init(AVCodecContext *avctx, AACEncContext *s) +{ + int ret = 0; + + s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); + if (!s->fdsp) + return AVERROR(ENOMEM); + + // window init + ff_kbd_window_init(ff_aac_kbd_long_1024, 4.0, 1024); + ff_kbd_window_init(ff_aac_kbd_short_128, 6.0, 128); + ff_init_ff_sine_windows(10); + ff_init_ff_sine_windows(7); + + if ((ret = ff_mdct_init(&s->mdct1024, 11, 0, 32768.0)) < 0) + return ret; + if ((ret = ff_mdct_init(&s->mdct128, 8, 0, 32768.0)) < 0) + return ret; + + return 0; +} + +static av_cold int alloc_buffers(AVCodecContext *avctx, AACEncContext *s) +{ + int ch; + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->buffer.samples, s->channels, 3 * 1024 * sizeof(s->buffer.samples[0]), alloc_fail); + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->cpe, s->chan_map[0], sizeof(ChannelElement), alloc_fail); + + for(ch = 0; ch < s->channels; ch++) + s->planar_samples[ch] = s->buffer.samples + 3 * 1024 * ch; + + return 0; +alloc_fail: + return AVERROR(ENOMEM); +} + +static av_cold void aac_encode_init_tables(void) +{ + ff_aac_tableinit(); +} + +static av_cold int aac_encode_init(AVCodecContext *avctx) +{ + AACEncContext *s = avctx->priv_data; + int i, ret = 0; + const uint8_t *sizes[2]; + uint8_t grouping[AAC_MAX_CHANNELS]; + int lengths[2]; + + /* Constants */ + s->last_frame_pb_count = 0; + avctx->frame_size = 1024; + avctx->initial_padding = 1024; + s->lambda = avctx->global_quality > 0 ? avctx->global_quality : 120; + + /* Channel map and unspecified bitrate guessing */ + s->channels = avctx->channels; + + s->needs_pce = 1; + for (i = 0; i < FF_ARRAY_ELEMS(aac_normal_chan_layouts); i++) { + if (avctx->channel_layout == aac_normal_chan_layouts[i]) { + s->needs_pce = s->options.pce; + break; + } + } + + if (s->needs_pce) { + char buf[64]; + for (i = 0; i < FF_ARRAY_ELEMS(aac_pce_configs); i++) + if (avctx->channel_layout == aac_pce_configs[i].layout) + break; + av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout); + ERROR_IF(i == FF_ARRAY_ELEMS(aac_pce_configs), "Unsupported channel layout \"%s\"\n", buf); + av_log(avctx, AV_LOG_INFO, "Using a PCE to encode channel layout \"%s\"\n", buf); + s->pce = aac_pce_configs[i]; + s->reorder_map = s->pce.reorder_map; + s->chan_map = s->pce.config_map; + } else { + s->reorder_map = aac_chan_maps[s->channels - 1]; + s->chan_map = aac_chan_configs[s->channels - 1]; + } + + if (!avctx->bit_rate) { + for (i = 1; i <= s->chan_map[0]; i++) { + avctx->bit_rate += s->chan_map[i] == TYPE_CPE ? 128000 : /* Pair */ + s->chan_map[i] == TYPE_LFE ? 16000 : /* LFE */ + 69000 ; /* SCE */ + } + } + + /* Samplerate */ + for (i = 0; i < 16; i++) + if (avctx->sample_rate == avpriv_mpeg4audio_sample_rates[i]) + break; + s->samplerate_index = i; + ERROR_IF(s->samplerate_index == 16 || + s->samplerate_index >= ff_aac_swb_size_1024_len || + s->samplerate_index >= ff_aac_swb_size_128_len, + "Unsupported sample rate %d\n", avctx->sample_rate); + + /* Bitrate limiting */ + WARN_IF(1024.0 * avctx->bit_rate / avctx->sample_rate > 6144 * s->channels, + "Too many bits %f > %d per frame requested, clamping to max\n", + 1024.0 * avctx->bit_rate / avctx->sample_rate, + 6144 * s->channels); + avctx->bit_rate = (int64_t)FFMIN(6144 * s->channels / 1024.0 * avctx->sample_rate, + avctx->bit_rate); + + /* Profile and option setting */ + avctx->profile = avctx->profile == FF_PROFILE_UNKNOWN ? FF_PROFILE_AAC_LOW : + avctx->profile; + for (i = 0; i < FF_ARRAY_ELEMS(aacenc_profiles); i++) + if (avctx->profile == aacenc_profiles[i]) + break; + if (avctx->profile == FF_PROFILE_MPEG2_AAC_LOW) { + avctx->profile = FF_PROFILE_AAC_LOW; + ERROR_IF(s->options.pred, + "Main prediction unavailable in the \"mpeg2_aac_low\" profile\n"); + ERROR_IF(s->options.ltp, + "LTP prediction unavailable in the \"mpeg2_aac_low\" profile\n"); + WARN_IF(s->options.pns, + "PNS unavailable in the \"mpeg2_aac_low\" profile, turning off\n"); + s->options.pns = 0; + } else if (avctx->profile == FF_PROFILE_AAC_LTP) { + s->options.ltp = 1; + ERROR_IF(s->options.pred, + "Main prediction unavailable in the \"aac_ltp\" profile\n"); + } else if (avctx->profile == FF_PROFILE_AAC_MAIN) { + s->options.pred = 1; + ERROR_IF(s->options.ltp, + "LTP prediction unavailable in the \"aac_main\" profile\n"); + } else if (s->options.ltp) { + avctx->profile = FF_PROFILE_AAC_LTP; + WARN_IF(1, + "Chainging profile to \"aac_ltp\"\n"); + ERROR_IF(s->options.pred, + "Main prediction unavailable in the \"aac_ltp\" profile\n"); + } else if (s->options.pred) { + avctx->profile = FF_PROFILE_AAC_MAIN; + WARN_IF(1, + "Chainging profile to \"aac_main\"\n"); + ERROR_IF(s->options.ltp, + "LTP prediction unavailable in the \"aac_main\" profile\n"); + } + s->profile = avctx->profile; + + /* Coder limitations */ + s->coder = &ff_aac_coders[s->options.coder]; + if (s->options.coder == AAC_CODER_ANMR) { + ERROR_IF(avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL, + "The ANMR coder is considered experimental, add -strict -2 to enable!\n"); + s->options.intensity_stereo = 0; + s->options.pns = 0; + } + ERROR_IF(s->options.ltp && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL, + "The LPT profile requires experimental compliance, add -strict -2 to enable!\n"); + + /* M/S introduces horrible artifacts with multichannel files, this is temporary */ + if (s->channels > 3) + s->options.mid_side = 0; + + if ((ret = dsp_init(avctx, s)) < 0) + goto fail; + + if ((ret = alloc_buffers(avctx, s)) < 0) + goto fail; + + if ((ret = put_audio_specific_config(avctx))) + goto fail; + + sizes[0] = ff_aac_swb_size_1024[s->samplerate_index]; + sizes[1] = ff_aac_swb_size_128[s->samplerate_index]; + lengths[0] = ff_aac_num_swb_1024[s->samplerate_index]; + lengths[1] = ff_aac_num_swb_128[s->samplerate_index]; + for (i = 0; i < s->chan_map[0]; i++) + grouping[i] = s->chan_map[i + 1] == TYPE_CPE; + if ((ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths, + s->chan_map[0], grouping)) < 0) + goto fail; + s->psypp = ff_psy_preprocess_init(avctx); + ff_lpc_init(&s->lpc, 2*avctx->frame_size, TNS_MAX_ORDER, FF_LPC_TYPE_LEVINSON); + s->random_state = 0x1f2e3d4c; + + s->abs_pow34 = abs_pow34_v; + s->quant_bands = quantize_bands; + + if (ARCH_X86) + ff_aac_dsp_init_x86(s); + + if (HAVE_MIPSDSP) + ff_aac_coder_init_mips(s); + + if ((ret = ff_thread_once(&aac_table_init, &aac_encode_init_tables)) != 0) + return AVERROR_UNKNOWN; + + ff_af_queue_init(avctx, &s->afq); + + return 0; +fail: + aac_encode_end(avctx); + return ret; +} + +#define AACENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM +static const AVOption aacenc_options[] = { + {"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_FAST}, 0, AAC_CODER_NB-1, AACENC_FLAGS, "coder"}, + {"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, + {"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, + {"fast", "Default fast search", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, + {"aac_ms", "Force M/S stereo coding", offsetof(AACEncContext, options.mid_side), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AACENC_FLAGS}, + {"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS}, + {"aac_pns", "Perceptual noise substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS}, + {"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS}, + {"aac_ltp", "Long term prediction", offsetof(AACEncContext, options.ltp), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, + {"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, + {"aac_pce", "Forces the use of PCEs", offsetof(AACEncContext, options.pce), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, + {NULL} +}; + +static const AVClass aacenc_class = { + .class_name = "AAC encoder", + .item_name = av_default_item_name, + .option = aacenc_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVCodecDefault aac_encode_defaults[] = { + { "b", "0" }, + { NULL } +}; + +AVCodec ff_aac_encoder = { + .name = "aac", + .long_name = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_AAC, + .priv_data_size = sizeof(AACEncContext), + .init = aac_encode_init, + .encode2 = aac_encode_frame, + .close = aac_encode_end, + .defaults = aac_encode_defaults, + .supported_samplerates = mpeg4audio_sample_rates, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_NONE }, + .priv_class = &aacenc_class, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc.h new file mode 100644 index 0000000000..5a015ca92e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc.h @@ -0,0 +1,428 @@ +/* + * AAC encoder + * Copyright (C) 2008 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AACENC_H +#define AVCODEC_AACENC_H + +#include "libavutil/float_dsp.h" +#include "avcodec.h" +#include "put_bits.h" + +#include "aac.h" +#include "audio_frame_queue.h" +#include "psymodel.h" + +#include "lpc.h" + +typedef enum AACCoder { + AAC_CODER_ANMR = 0, + AAC_CODER_TWOLOOP, + AAC_CODER_FAST, + + AAC_CODER_NB, +}AACCoder; + +typedef struct AACEncOptions { + int coder; + int pns; + int tns; + int ltp; + int pce; + int pred; + int mid_side; + int intensity_stereo; +} AACEncOptions; + +struct AACEncContext; + +typedef struct AACCoefficientsEncoder { + void (*search_for_quantizers)(AVCodecContext *avctx, struct AACEncContext *s, + SingleChannelElement *sce, const float lambda); + void (*encode_window_bands_info)(struct AACEncContext *s, SingleChannelElement *sce, + int win, int group_len, const float lambda); + void (*quantize_and_encode_band)(struct AACEncContext *s, PutBitContext *pb, const float *in, float *out, int size, + int scale_idx, int cb, const float lambda, int rtz); + void (*encode_tns_info)(struct AACEncContext *s, SingleChannelElement *sce); + void (*encode_ltp_info)(struct AACEncContext *s, SingleChannelElement *sce, int common_window); + void (*encode_main_pred)(struct AACEncContext *s, SingleChannelElement *sce); + void (*adjust_common_pred)(struct AACEncContext *s, ChannelElement *cpe); + void (*adjust_common_ltp)(struct AACEncContext *s, ChannelElement *cpe); + void (*apply_main_pred)(struct AACEncContext *s, SingleChannelElement *sce); + void (*apply_tns_filt)(struct AACEncContext *s, SingleChannelElement *sce); + void (*update_ltp)(struct AACEncContext *s, SingleChannelElement *sce); + void (*ltp_insert_new_frame)(struct AACEncContext *s); + void (*set_special_band_scalefactors)(struct AACEncContext *s, SingleChannelElement *sce); + void (*search_for_pns)(struct AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce); + void (*mark_pns)(struct AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce); + void (*search_for_tns)(struct AACEncContext *s, SingleChannelElement *sce); + void (*search_for_ltp)(struct AACEncContext *s, SingleChannelElement *sce, int common_window); + void (*search_for_ms)(struct AACEncContext *s, ChannelElement *cpe); + void (*search_for_is)(struct AACEncContext *s, AVCodecContext *avctx, ChannelElement *cpe); + void (*search_for_pred)(struct AACEncContext *s, SingleChannelElement *sce); +} AACCoefficientsEncoder; + +extern const AACCoefficientsEncoder ff_aac_coders[]; + +typedef struct AACQuantizeBandCostCacheEntry { + float rd; + float energy; + int bits; + char cb; + char rtz; + uint16_t generation; +} AACQuantizeBandCostCacheEntry; + +typedef struct AACPCEInfo { + int64_t layout; + int num_ele[4]; ///< front, side, back, lfe + int pairing[3][8]; ///< front, side, back + int index[4][8]; ///< front, side, back, lfe + uint8_t config_map[16]; ///< configs the encoder's channel specific settings + uint8_t reorder_map[16]; ///< maps channels from lavc to aac order +} AACPCEInfo; + +/** + * List of PCE (Program Configuration Element) for the channel layouts listed + * in channel_layout.h + * + * For those wishing in the future to add other layouts: + * + * - num_ele: number of elements in each group of front, side, back, lfe channels + * (an element is of type SCE (single channel), CPE (channel pair) for + * the first 3 groups; and is LFE for LFE group). + * + * - pairing: 0 for an SCE element or 1 for a CPE; does not apply to LFE group + * + * - index: there are three independent indices for SCE, CPE and LFE; + * they are incremented irrespective of the group to which the element belongs; + * they are not reset when going from one group to another + * + * Example: for 7.0 channel layout, + * .pairing = { { 1, 0 }, { 1 }, { 1 }, }, (3 CPE and 1 SCE in front group) + * .index = { { 0, 0 }, { 1 }, { 2 }, }, + * (index is 0 for the single SCE but goes from 0 to 2 for the CPEs) + * + * The index order impacts the channel ordering. But is otherwise arbitrary + * (the sequence could have been 2, 0, 1 instead of 0, 1, 2). + * + * Spec allows for discontinuous indices, e.g. if one has a total of two SCE, + * SCE.0 SCE.15 is OK per spec; BUT it won't be decoded by our AAC decoder + * which at this time requires that indices fully cover some range starting + * from 0 (SCE.1 SCE.0 is OK but not SCE.0 SCE.15). + * + * - config_map: total number of elements and their types. Beware, the way the + * types are ordered impacts the final channel ordering. + * + * - reorder_map: reorders the channels. + * + */ +static const AACPCEInfo aac_pce_configs[] = { + { + .layout = AV_CH_LAYOUT_MONO, + .num_ele = { 1, 0, 0, 0 }, + .pairing = { { 0 }, }, + .index = { { 0 }, }, + .config_map = { 1, TYPE_SCE, }, + .reorder_map = { 0 }, + }, + { + .layout = AV_CH_LAYOUT_STEREO, + .num_ele = { 1, 0, 0, 0 }, + .pairing = { { 1 }, }, + .index = { { 0 }, }, + .config_map = { 1, TYPE_CPE, }, + .reorder_map = { 0, 1 }, + }, + { + .layout = AV_CH_LAYOUT_2POINT1, + .num_ele = { 1, 0, 0, 1 }, + .pairing = { { 1 }, }, + .index = { { 0 },{ 0 },{ 0 },{ 0 } }, + .config_map = { 2, TYPE_CPE, TYPE_LFE }, + .reorder_map = { 0, 1, 2 }, + }, + { + .layout = AV_CH_LAYOUT_2_1, + .num_ele = { 1, 0, 1, 0 }, + .pairing = { { 1 },{ 0 },{ 0 } }, + .index = { { 0 },{ 0 },{ 0 }, }, + .config_map = { 2, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2 }, + }, + { + .layout = AV_CH_LAYOUT_SURROUND, + .num_ele = { 2, 0, 0, 0 }, + .pairing = { { 1, 0 }, }, + .index = { { 0, 0 }, }, + .config_map = { 2, TYPE_CPE, TYPE_SCE, }, + .reorder_map = { 0, 1, 2 }, + }, + { + .layout = AV_CH_LAYOUT_3POINT1, + .num_ele = { 2, 0, 0, 1 }, + .pairing = { { 1, 0 }, }, + .index = { { 0, 0 }, { 0 }, { 0 }, { 0 }, }, + .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_LFE }, + .reorder_map = { 0, 1, 2, 3 }, + }, + { + .layout = AV_CH_LAYOUT_4POINT0, + .num_ele = { 2, 0, 1, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 0 }, }, + .index = { { 0, 0 }, { 0 }, { 1 } }, + .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3 }, + }, + { + .layout = AV_CH_LAYOUT_4POINT1, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 0 }, }, + .index = { { 0, 0 }, { 1 }, { 2 }, { 0 } }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4 }, + }, + { + .layout = AV_CH_LAYOUT_2_2, + .num_ele = { 1, 1, 0, 0 }, + .pairing = { { 1 }, { 1 }, }, + .index = { { 0 }, { 1 }, }, + .config_map = { 2, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3 }, + }, + { + .layout = AV_CH_LAYOUT_QUAD, + .num_ele = { 1, 0, 1, 0 }, + .pairing = { { 1 }, { 0 }, { 1 }, }, + .index = { { 0 }, { 0 }, { 1 } }, + .config_map = { 2, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3 }, + }, + { + .layout = AV_CH_LAYOUT_5POINT0, + .num_ele = { 2, 1, 0, 0 }, + .pairing = { { 1, 0 }, { 1 }, }, + .index = { { 0, 0 }, { 1 } }, + .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4 }, + }, + { + .layout = AV_CH_LAYOUT_5POINT1, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1 }, }, + .index = { { 0, 0 }, { 1 }, { 1 } }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5 }, + }, + { + .layout = AV_CH_LAYOUT_5POINT0_BACK, + .num_ele = { 2, 0, 1, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1 } }, + .index = { { 0, 0 }, { 0 }, { 1 } }, + .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4 }, + }, + { + .layout = AV_CH_LAYOUT_5POINT1_BACK, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1 }, }, + .index = { { 0, 0 }, { 1 }, { 1 } }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5 }, + }, + { + .layout = AV_CH_LAYOUT_6POINT0, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 1 }, { 0 }, }, + .index = { { 0, 0 }, { 1 }, { 1 } }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5 }, + }, + { + .layout = AV_CH_LAYOUT_6POINT0_FRONT, + .num_ele = { 2, 1, 0, 0 }, + .pairing = { { 1, 1 }, { 1 } }, + .index = { { 1, 0 }, { 2 }, }, + .config_map = { 3, TYPE_CPE, TYPE_CPE, TYPE_CPE, }, + .reorder_map = { 0, 1, 2, 3, 4, 5 }, + }, + { + .layout = AV_CH_LAYOUT_HEXAGONAL, + .num_ele = { 2, 0, 2, 0 }, + .pairing = { { 1, 0 },{ 0 },{ 1, 0 }, }, + .index = { { 0, 0 },{ 0 },{ 1, 1 } }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, }, + .reorder_map = { 0, 1, 2, 3, 4, 5 }, + }, + { + .layout = AV_CH_LAYOUT_6POINT1, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 },{ 0 },{ 1, 0 }, }, + .index = { { 0, 0 },{ 1 },{ 1, 2 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, + }, + { + .layout = AV_CH_LAYOUT_6POINT1_BACK, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1, 0 }, }, + .index = { { 0, 0 }, { 1 }, { 1, 2 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, + }, + { + .layout = AV_CH_LAYOUT_6POINT1_FRONT, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1, 0 }, }, + .index = { { 0, 0 }, { 1 }, { 1, 2 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, + }, + { + .layout = AV_CH_LAYOUT_7POINT0, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 1 }, { 1 }, }, + .index = { { 0, 0 }, { 1 }, { 2 }, }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, + }, + { + .layout = AV_CH_LAYOUT_7POINT0_FRONT, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 1 }, { 1 }, }, + .index = { { 0, 0 }, { 1 }, { 2 }, }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, + }, + { + .layout = AV_CH_LAYOUT_7POINT1, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1, 1 }, }, + .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, + }, + { + .layout = AV_CH_LAYOUT_7POINT1_WIDE, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 0 },{ 1, 1 }, }, + .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, + }, + { + .layout = AV_CH_LAYOUT_7POINT1_WIDE_BACK, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1, 1 }, }, + .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, + }, + { + .layout = AV_CH_LAYOUT_OCTAGONAL, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 1 }, { 1, 0 }, }, + .index = { { 0, 0 }, { 1 }, { 2, 1 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, + }, + { /* Meant for order 2/mixed ambisonics */ + .layout = AV_CH_LAYOUT_OCTAGONAL | AV_CH_TOP_CENTER, + .num_ele = { 2, 2, 2, 0 }, + .pairing = { { 1, 0 }, { 1, 0 }, { 1, 0 }, }, + .index = { { 0, 0 }, { 1, 1 }, { 2, 2 } }, + .config_map = { 6, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, + }, + { /* Meant for order 2/mixed ambisonics */ + .layout = AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_BACK_CENTER | + AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT | AV_CH_TOP_CENTER, + .num_ele = { 2, 2, 2, 0 }, + .pairing = { { 1, 1 }, { 1, 0 }, { 1, 0 }, }, + .index = { { 0, 1 }, { 2, 0 }, { 3, 1 } }, + .config_map = { 6, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + }, + { + .layout = AV_CH_LAYOUT_HEXADECAGONAL, + .num_ele = { 4, 2, 4, 0 }, + .pairing = { { 1, 0, 1, 0 }, { 1, 1 }, { 1, 0, 1, 0 }, }, + .index = { { 0, 0, 1, 1 }, { 2, 3 }, { 4, 2, 5, 3 } }, + .config_map = { 10, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + }, +}; + +/** + * AAC encoder context + */ +typedef struct AACEncContext { + AVClass *av_class; + AACEncOptions options; ///< encoding options + PutBitContext pb; + FFTContext mdct1024; ///< long (1024 samples) frame transform context + FFTContext mdct128; ///< short (128 samples) frame transform context + AVFloatDSPContext *fdsp; + AACPCEInfo pce; ///< PCE data, if needed + float *planar_samples[16]; ///< saved preprocessed input + + int profile; ///< copied from avctx + int needs_pce; ///< flag for non-standard layout + LPCContext lpc; ///< used by TNS + int samplerate_index; ///< MPEG-4 samplerate index + int channels; ///< channel count + const uint8_t *reorder_map; ///< lavc to aac reorder map + const uint8_t *chan_map; ///< channel configuration map + + ChannelElement *cpe; ///< channel elements + FFPsyContext psy; + struct FFPsyPreprocessContext* psypp; + const AACCoefficientsEncoder *coder; + int cur_channel; ///< current channel for coder context + int random_state; + float lambda; + int last_frame_pb_count; ///< number of bits for the previous frame + float lambda_sum; ///< sum(lambda), for Qvg reporting + int lambda_count; ///< count(lambda), for Qvg reporting + enum RawDataBlockType cur_type; ///< channel group type cur_channel belongs to + + AudioFrameQueue afq; + DECLARE_ALIGNED(16, int, qcoefs)[96]; ///< quantized coefficients + DECLARE_ALIGNED(32, float, scoefs)[1024]; ///< scaled coefficients + + uint16_t quantize_band_cost_cache_generation; + AACQuantizeBandCostCacheEntry quantize_band_cost_cache[256][128]; ///< memoization area for quantize_band_cost + + void (*abs_pow34)(float *out, const float *in, const int size); + void (*quant_bands)(int *out, const float *in, const float *scaled, + int size, int is_signed, int maxval, const float Q34, + const float rounding); + + struct { + float *samples; + } buffer; +} AACEncContext; + +void ff_aac_dsp_init_x86(AACEncContext *s); +void ff_aac_coder_init_mips(AACEncContext *c); +void ff_quantize_band_cost_cache_init(struct AACEncContext *s); + + +#endif /* AVCODEC_AACENC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_is.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_is.c new file mode 100644 index 0000000000..2f5b7eb8dc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_is.c @@ -0,0 +1,158 @@ +/* + * AAC encoder intensity stereo + * Copyright (C) 2015 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder Intensity Stereo + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#include "aacenc.h" +#include "aacenc_utils.h" +#include "aacenc_is.h" +#include "aacenc_quantization.h" + +struct AACISError ff_aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe, + int start, int w, int g, float ener0, + float ener1, float ener01, + int use_pcoeffs, int phase) +{ + int i, w2; + SingleChannelElement *sce0 = &cpe->ch[0]; + SingleChannelElement *sce1 = &cpe->ch[1]; + float *L = use_pcoeffs ? sce0->pcoeffs : sce0->coeffs; + float *R = use_pcoeffs ? sce1->pcoeffs : sce1->coeffs; + float *L34 = &s->scoefs[256*0], *R34 = &s->scoefs[256*1]; + float *IS = &s->scoefs[256*2], *I34 = &s->scoefs[256*3]; + float dist1 = 0.0f, dist2 = 0.0f; + struct AACISError is_error = {0}; + + if (ener01 <= 0 || ener0 <= 0) { + is_error.pass = 0; + return is_error; + } + + for (w2 = 0; w2 < sce0->ics.group_len[w]; w2++) { + FFPsyBand *band0 = &s->psy.ch[s->cur_channel+0].psy_bands[(w+w2)*16+g]; + FFPsyBand *band1 = &s->psy.ch[s->cur_channel+1].psy_bands[(w+w2)*16+g]; + int is_band_type, is_sf_idx = FFMAX(1, sce0->sf_idx[w*16+g]-4); + float e01_34 = phase*pos_pow34(ener1/ener0); + float maxval, dist_spec_err = 0.0f; + float minthr = FFMIN(band0->threshold, band1->threshold); + for (i = 0; i < sce0->ics.swb_sizes[g]; i++) + IS[i] = (L[start+(w+w2)*128+i] + phase*R[start+(w+w2)*128+i])*sqrt(ener0/ener01); + s->abs_pow34(L34, &L[start+(w+w2)*128], sce0->ics.swb_sizes[g]); + s->abs_pow34(R34, &R[start+(w+w2)*128], sce0->ics.swb_sizes[g]); + s->abs_pow34(I34, IS, sce0->ics.swb_sizes[g]); + maxval = find_max_val(1, sce0->ics.swb_sizes[g], I34); + is_band_type = find_min_book(maxval, is_sf_idx); + dist1 += quantize_band_cost(s, &L[start + (w+w2)*128], L34, + sce0->ics.swb_sizes[g], + sce0->sf_idx[w*16+g], + sce0->band_type[w*16+g], + s->lambda / band0->threshold, INFINITY, NULL, NULL, 0); + dist1 += quantize_band_cost(s, &R[start + (w+w2)*128], R34, + sce1->ics.swb_sizes[g], + sce1->sf_idx[w*16+g], + sce1->band_type[w*16+g], + s->lambda / band1->threshold, INFINITY, NULL, NULL, 0); + dist2 += quantize_band_cost(s, IS, I34, sce0->ics.swb_sizes[g], + is_sf_idx, is_band_type, + s->lambda / minthr, INFINITY, NULL, NULL, 0); + for (i = 0; i < sce0->ics.swb_sizes[g]; i++) { + dist_spec_err += (L34[i] - I34[i])*(L34[i] - I34[i]); + dist_spec_err += (R34[i] - I34[i]*e01_34)*(R34[i] - I34[i]*e01_34); + } + dist_spec_err *= s->lambda / minthr; + dist2 += dist_spec_err; + } + + is_error.pass = dist2 <= dist1; + is_error.phase = phase; + is_error.error = dist2 - dist1; + is_error.dist1 = dist1; + is_error.dist2 = dist2; + is_error.ener01 = ener01; + + return is_error; +} + +void ff_aac_search_for_is(AACEncContext *s, AVCodecContext *avctx, ChannelElement *cpe) +{ + SingleChannelElement *sce0 = &cpe->ch[0]; + SingleChannelElement *sce1 = &cpe->ch[1]; + int start = 0, count = 0, w, w2, g, i, prev_sf1 = -1, prev_bt = -1, prev_is = 0; + const float freq_mult = avctx->sample_rate/(1024.0f/sce0->ics.num_windows)/2.0f; + uint8_t nextband1[128]; + + if (!cpe->common_window) + return; + + /** Scout out next nonzero bands */ + ff_init_nextband_map(sce1, nextband1); + + for (w = 0; w < sce0->ics.num_windows; w += sce0->ics.group_len[w]) { + start = 0; + for (g = 0; g < sce0->ics.num_swb; g++) { + if (start*freq_mult > INT_STEREO_LOW_LIMIT*(s->lambda/170.0f) && + cpe->ch[0].band_type[w*16+g] != NOISE_BT && !cpe->ch[0].zeroes[w*16+g] && + cpe->ch[1].band_type[w*16+g] != NOISE_BT && !cpe->ch[1].zeroes[w*16+g] && + ff_sfdelta_can_remove_band(sce1, nextband1, prev_sf1, w*16+g)) { + float ener0 = 0.0f, ener1 = 0.0f, ener01 = 0.0f, ener01p = 0.0f; + struct AACISError ph_err1, ph_err2, *best; + for (w2 = 0; w2 < sce0->ics.group_len[w]; w2++) { + for (i = 0; i < sce0->ics.swb_sizes[g]; i++) { + float coef0 = sce0->coeffs[start+(w+w2)*128+i]; + float coef1 = sce1->coeffs[start+(w+w2)*128+i]; + ener0 += coef0*coef0; + ener1 += coef1*coef1; + ener01 += (coef0 + coef1)*(coef0 + coef1); + ener01p += (coef0 - coef1)*(coef0 - coef1); + } + } + ph_err1 = ff_aac_is_encoding_err(s, cpe, start, w, g, + ener0, ener1, ener01p, 0, -1); + ph_err2 = ff_aac_is_encoding_err(s, cpe, start, w, g, + ener0, ener1, ener01, 0, +1); + best = (ph_err1.pass && ph_err1.error < ph_err2.error) ? &ph_err1 : &ph_err2; + if (best->pass) { + cpe->is_mask[w*16+g] = 1; + cpe->ms_mask[w*16+g] = 0; + cpe->ch[0].is_ener[w*16+g] = sqrt(ener0 / best->ener01); + cpe->ch[1].is_ener[w*16+g] = ener0/ener1; + cpe->ch[1].band_type[w*16+g] = (best->phase > 0) ? INTENSITY_BT : INTENSITY_BT2; + if (prev_is && prev_bt != cpe->ch[1].band_type[w*16+g]) { + /** Flip M/S mask and pick the other CB, since it encodes more efficiently */ + cpe->ms_mask[w*16+g] = 1; + cpe->ch[1].band_type[w*16+g] = (best->phase > 0) ? INTENSITY_BT2 : INTENSITY_BT; + } + prev_bt = cpe->ch[1].band_type[w*16+g]; + count++; + } + } + if (!sce1->zeroes[w*16+g] && sce1->band_type[w*16+g] < RESERVED_BT) + prev_sf1 = sce1->sf_idx[w*16+g]; + prev_is = cpe->is_mask[w*16+g]; + start += sce0->ics.swb_sizes[g]; + } + } + cpe->is_mode = !!count; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_is.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_is.h new file mode 100644 index 0000000000..269fd1a9c9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_is.h @@ -0,0 +1,51 @@ +/* + * AAC encoder intensity stereo + * Copyright (C) 2015 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder Intensity Stereo + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#ifndef AVCODEC_AACENC_IS_H +#define AVCODEC_AACENC_IS_H + +#include "aacenc.h" + +/** Frequency in Hz for lower limit of intensity stereo **/ +#define INT_STEREO_LOW_LIMIT 6100 + +struct AACISError { + int pass; /* 1 if dist2 <= dist1 */ + int phase; /* -1 or +1 */ + float error; /* fabs(dist1 - dist2) */ + float dist1; /* From original coeffs */ + float dist2; /* From IS'd coeffs */ + float ener01; +}; + +struct AACISError ff_aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe, + int start, int w, int g, float ener0, + float ener1, float ener01, + int use_pcoeffs, int phase); +void ff_aac_search_for_is(AACEncContext *s, AVCodecContext *avctx, ChannelElement *cpe); + +#endif /* AVCODEC_AACENC_IS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_ltp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_ltp.c new file mode 100644 index 0000000000..f77f0b6a72 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_ltp.c @@ -0,0 +1,236 @@ +/* + * AAC encoder long term prediction extension + * Copyright (C) 2015 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder long term prediction extension + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#include "aacenc_ltp.h" +#include "aacenc_quantization.h" +#include "aacenc_utils.h" + +/** + * Encode LTP data. + */ +void ff_aac_encode_ltp_info(AACEncContext *s, SingleChannelElement *sce, + int common_window) +{ + int i; + IndividualChannelStream *ics = &sce->ics; + if (s->profile != FF_PROFILE_AAC_LTP || !ics->predictor_present) + return; + if (common_window) + put_bits(&s->pb, 1, 0); + put_bits(&s->pb, 1, ics->ltp.present); + if (!ics->ltp.present) + return; + put_bits(&s->pb, 11, ics->ltp.lag); + put_bits(&s->pb, 3, ics->ltp.coef_idx); + for (i = 0; i < FFMIN(ics->max_sfb, MAX_LTP_LONG_SFB); i++) + put_bits(&s->pb, 1, ics->ltp.used[i]); +} + +void ff_aac_ltp_insert_new_frame(AACEncContext *s) +{ + int i, ch, tag, chans, cur_channel, start_ch = 0; + ChannelElement *cpe; + SingleChannelElement *sce; + for (i = 0; i < s->chan_map[0]; i++) { + cpe = &s->cpe[i]; + tag = s->chan_map[i+1]; + chans = tag == TYPE_CPE ? 2 : 1; + for (ch = 0; ch < chans; ch++) { + sce = &cpe->ch[ch]; + cur_channel = start_ch + ch; + /* New sample + overlap */ + memcpy(&sce->ltp_state[0], &sce->ltp_state[1024], 1024*sizeof(sce->ltp_state[0])); + memcpy(&sce->ltp_state[1024], &s->planar_samples[cur_channel][2048], 1024*sizeof(sce->ltp_state[0])); + memcpy(&sce->ltp_state[2048], &sce->ret_buf[0], 1024*sizeof(sce->ltp_state[0])); + sce->ics.ltp.lag = 0; + } + start_ch += chans; + } +} + +static void get_lag(float *buf, const float *new, LongTermPrediction *ltp) +{ + int i, j, lag = 0, max_corr = 0; + float max_ratio = 0.0f; + for (i = 0; i < 2048; i++) { + float corr, s0 = 0.0f, s1 = 0.0f; + const int start = FFMAX(0, i - 1024); + for (j = start; j < 2048; j++) { + const int idx = j - i + 1024; + s0 += new[j]*buf[idx]; + s1 += buf[idx]*buf[idx]; + } + corr = s1 > 0.0f ? s0/sqrt(s1) : 0.0f; + if (corr > max_corr) { + max_corr = corr; + lag = i; + max_ratio = corr/(2048-start); + } + } + ltp->lag = FFMAX(av_clip_uintp2(lag, 11), 0); + ltp->coef_idx = quant_array_idx(max_ratio, ltp_coef, 8); + ltp->coef = ltp_coef[ltp->coef_idx]; +} + +static void generate_samples(float *buf, LongTermPrediction *ltp) +{ + int i, samples_num = 2048; + if (!ltp->lag) { + ltp->present = 0; + return; + } else if (ltp->lag < 1024) { + samples_num = ltp->lag + 1024; + } + for (i = 0; i < samples_num; i++) + buf[i] = ltp->coef*buf[i + 2048 - ltp->lag]; + memset(&buf[i], 0, (2048 - i)*sizeof(float)); +} + +/** + * Process LTP parameters + * @see Patent WO2006070265A1 + */ +void ff_aac_update_ltp(AACEncContext *s, SingleChannelElement *sce) +{ + float *pred_signal = &sce->ltp_state[0]; + const float *samples = &s->planar_samples[s->cur_channel][1024]; + + if (s->profile != FF_PROFILE_AAC_LTP) + return; + + /* Calculate lag */ + get_lag(pred_signal, samples, &sce->ics.ltp); + generate_samples(pred_signal, &sce->ics.ltp); +} + +void ff_aac_adjust_common_ltp(AACEncContext *s, ChannelElement *cpe) +{ + int sfb, count = 0; + SingleChannelElement *sce0 = &cpe->ch[0]; + SingleChannelElement *sce1 = &cpe->ch[1]; + + if (!cpe->common_window || + sce0->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE || + sce1->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + sce0->ics.ltp.present = 0; + return; + } + + for (sfb = 0; sfb < FFMIN(sce0->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++) { + int sum = sce0->ics.ltp.used[sfb] + sce1->ics.ltp.used[sfb]; + if (sum != 2) { + sce0->ics.ltp.used[sfb] = 0; + } else { + count++; + } + } + + sce0->ics.ltp.present = !!count; + sce0->ics.predictor_present = !!count; +} + +/** + * Mark LTP sfb's + */ +void ff_aac_search_for_ltp(AACEncContext *s, SingleChannelElement *sce, + int common_window) +{ + int w, g, w2, i, start = 0, count = 0; + int saved_bits = -(15 + FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB)); + float *C34 = &s->scoefs[128*0], *PCD = &s->scoefs[128*1]; + float *PCD34 = &s->scoefs[128*2]; + const int max_ltp = FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); + + if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + if (sce->ics.ltp.lag) { + memset(&sce->ltp_state[0], 0, 3072*sizeof(sce->ltp_state[0])); + memset(&sce->ics.ltp, 0, sizeof(LongTermPrediction)); + } + return; + } + + if (!sce->ics.ltp.lag || s->lambda > 120.0f) + return; + + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + start = 0; + for (g = 0; g < sce->ics.num_swb; g++) { + int bits1 = 0, bits2 = 0; + float dist1 = 0.0f, dist2 = 0.0f; + if (w*16+g > max_ltp) { + start += sce->ics.swb_sizes[g]; + continue; + } + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + int bits_tmp1, bits_tmp2; + FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g]; + for (i = 0; i < sce->ics.swb_sizes[g]; i++) + PCD[i] = sce->coeffs[start+(w+w2)*128+i] - sce->lcoeffs[start+(w+w2)*128+i]; + s->abs_pow34(C34, &sce->coeffs[start+(w+w2)*128], sce->ics.swb_sizes[g]); + s->abs_pow34(PCD34, PCD, sce->ics.swb_sizes[g]); + dist1 += quantize_band_cost(s, &sce->coeffs[start+(w+w2)*128], C34, sce->ics.swb_sizes[g], + sce->sf_idx[(w+w2)*16+g], sce->band_type[(w+w2)*16+g], + s->lambda/band->threshold, INFINITY, &bits_tmp1, NULL, 0); + dist2 += quantize_band_cost(s, PCD, PCD34, sce->ics.swb_sizes[g], + sce->sf_idx[(w+w2)*16+g], + sce->band_type[(w+w2)*16+g], + s->lambda/band->threshold, INFINITY, &bits_tmp2, NULL, 0); + bits1 += bits_tmp1; + bits2 += bits_tmp2; + } + if (dist2 < dist1 && bits2 < bits1) { + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) + for (i = 0; i < sce->ics.swb_sizes[g]; i++) + sce->coeffs[start+(w+w2)*128+i] -= sce->lcoeffs[start+(w+w2)*128+i]; + sce->ics.ltp.used[w*16+g] = 1; + saved_bits += bits1 - bits2; + count++; + } + start += sce->ics.swb_sizes[g]; + } + } + + sce->ics.ltp.present = !!count && (saved_bits >= 0); + sce->ics.predictor_present = !!sce->ics.ltp.present; + + /* Reset any marked sfbs */ + if (!sce->ics.ltp.present && !!count) { + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + start = 0; + for (g = 0; g < sce->ics.num_swb; g++) { + if (sce->ics.ltp.used[w*16+g]) { + for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) { + for (i = 0; i < sce->ics.swb_sizes[g]; i++) { + sce->coeffs[start+(w+w2)*128+i] += sce->lcoeffs[start+(w+w2)*128+i]; + } + } + } + start += sce->ics.swb_sizes[g]; + } + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_ltp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_ltp.h new file mode 100644 index 0000000000..7276878427 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_ltp.h @@ -0,0 +1,41 @@ +/* + * AAC encoder long term prediction extension + * Copyright (C) 2015 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder long term prediction extension + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#ifndef AVCODEC_AACENC_LTP_H +#define AVCODEC_AACENC_LTP_H + +#include "aacenc.h" + +void ff_aac_encode_ltp_info(AACEncContext *s, SingleChannelElement *sce, + int common_window); +void ff_aac_update_ltp(AACEncContext *s, SingleChannelElement *sce); +void ff_aac_adjust_common_ltp(AACEncContext *s, ChannelElement *cpe); +void ff_aac_ltp_insert_new_frame(AACEncContext *s); +void ff_aac_search_for_ltp(AACEncContext *s, SingleChannelElement *sce, + int common_window); + +#endif /* AVCODEC_AACENC_LTP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_pred.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_pred.c new file mode 100644 index 0000000000..d111192f06 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_pred.c @@ -0,0 +1,347 @@ +/* + * AAC encoder main-type prediction + * Copyright (C) 2015 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder main-type prediction + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#include "aactab.h" +#include "aacenc_pred.h" +#include "aacenc_utils.h" +#include "aacenc_is.h" /* <- Needed for common window distortions */ +#include "aacenc_quantization.h" + +#define RESTORE_PRED(sce, sfb) \ + if (sce->ics.prediction_used[sfb]) {\ + sce->ics.prediction_used[sfb] = 0;\ + sce->band_type[sfb] = sce->band_alt[sfb];\ + } + +static inline float flt16_round(float pf) +{ + union av_intfloat32 tmp; + tmp.f = pf; + tmp.i = (tmp.i + 0x00008000U) & 0xFFFF0000U; + return tmp.f; +} + +static inline float flt16_even(float pf) +{ + union av_intfloat32 tmp; + tmp.f = pf; + tmp.i = (tmp.i + 0x00007FFFU + (tmp.i & 0x00010000U >> 16)) & 0xFFFF0000U; + return tmp.f; +} + +static inline float flt16_trunc(float pf) +{ + union av_intfloat32 pun; + pun.f = pf; + pun.i &= 0xFFFF0000U; + return pun.f; +} + +static inline void predict(PredictorState *ps, float *coef, float *rcoef, int set) +{ + float k2; + const float a = 0.953125; // 61.0 / 64 + const float alpha = 0.90625; // 29.0 / 32 + const float k1 = ps->k1; + const float r0 = ps->r0, r1 = ps->r1; + const float cor0 = ps->cor0, cor1 = ps->cor1; + const float var0 = ps->var0, var1 = ps->var1; + const float e0 = *coef - ps->x_est; + const float e1 = e0 - k1 * r0; + + if (set) + *coef = e0; + + ps->cor1 = flt16_trunc(alpha * cor1 + r1 * e1); + ps->var1 = flt16_trunc(alpha * var1 + 0.5f * (r1 * r1 + e1 * e1)); + ps->cor0 = flt16_trunc(alpha * cor0 + r0 * e0); + ps->var0 = flt16_trunc(alpha * var0 + 0.5f * (r0 * r0 + e0 * e0)); + ps->r1 = flt16_trunc(a * (r0 - k1 * e0)); + ps->r0 = flt16_trunc(a * e0); + + /* Prediction for next frame */ + ps->k1 = ps->var0 > 1 ? ps->cor0 * flt16_even(a / ps->var0) : 0; + k2 = ps->var1 > 1 ? ps->cor1 * flt16_even(a / ps->var1) : 0; + *rcoef = ps->x_est = flt16_round(ps->k1*ps->r0 + k2*ps->r1); +} + +static inline void reset_predict_state(PredictorState *ps) +{ + ps->r0 = 0.0f; + ps->r1 = 0.0f; + ps->k1 = 0.0f; + ps->cor0 = 0.0f; + ps->cor1 = 0.0f; + ps->var0 = 1.0f; + ps->var1 = 1.0f; + ps->x_est = 0.0f; +} + +static inline void reset_all_predictors(PredictorState *ps) +{ + int i; + for (i = 0; i < MAX_PREDICTORS; i++) + reset_predict_state(&ps[i]); +} + +static inline void reset_predictor_group(SingleChannelElement *sce, int group_num) +{ + int i; + PredictorState *ps = sce->predictor_state; + for (i = group_num - 1; i < MAX_PREDICTORS; i += 30) + reset_predict_state(&ps[i]); +} + +void ff_aac_apply_main_pred(AACEncContext *s, SingleChannelElement *sce) +{ + int sfb, k; + const int pmax = FFMIN(sce->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); + + if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) { + for (sfb = 0; sfb < pmax; sfb++) { + for (k = sce->ics.swb_offset[sfb]; k < sce->ics.swb_offset[sfb + 1]; k++) { + predict(&sce->predictor_state[k], &sce->coeffs[k], &sce->prcoeffs[k], + sce->ics.predictor_present && sce->ics.prediction_used[sfb]); + } + } + if (sce->ics.predictor_reset_group) { + reset_predictor_group(sce, sce->ics.predictor_reset_group); + } + } else { + reset_all_predictors(sce->predictor_state); + } +} + +/* If inc = 0 you can check if this returns 0 to see if you can reset freely */ +static inline int update_counters(IndividualChannelStream *ics, int inc) +{ + int i; + for (i = 1; i < 31; i++) { + ics->predictor_reset_count[i] += inc; + if (ics->predictor_reset_count[i] > PRED_RESET_FRAME_MIN) + return i; /* Reset this immediately */ + } + return 0; +} + +void ff_aac_adjust_common_pred(AACEncContext *s, ChannelElement *cpe) +{ + int start, w, w2, g, i, count = 0; + SingleChannelElement *sce0 = &cpe->ch[0]; + SingleChannelElement *sce1 = &cpe->ch[1]; + const int pmax0 = FFMIN(sce0->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); + const int pmax1 = FFMIN(sce1->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); + const int pmax = FFMIN(pmax0, pmax1); + + if (!cpe->common_window || + sce0->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE || + sce1->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) + return; + + for (w = 0; w < sce0->ics.num_windows; w += sce0->ics.group_len[w]) { + start = 0; + for (g = 0; g < sce0->ics.num_swb; g++) { + int sfb = w*16+g; + int sum = sce0->ics.prediction_used[sfb] + sce1->ics.prediction_used[sfb]; + float ener0 = 0.0f, ener1 = 0.0f, ener01 = 0.0f; + struct AACISError ph_err1, ph_err2, *erf; + if (sfb < PRED_SFB_START || sfb > pmax || sum != 2) { + RESTORE_PRED(sce0, sfb); + RESTORE_PRED(sce1, sfb); + start += sce0->ics.swb_sizes[g]; + continue; + } + for (w2 = 0; w2 < sce0->ics.group_len[w]; w2++) { + for (i = 0; i < sce0->ics.swb_sizes[g]; i++) { + float coef0 = sce0->pcoeffs[start+(w+w2)*128+i]; + float coef1 = sce1->pcoeffs[start+(w+w2)*128+i]; + ener0 += coef0*coef0; + ener1 += coef1*coef1; + ener01 += (coef0 + coef1)*(coef0 + coef1); + } + } + ph_err1 = ff_aac_is_encoding_err(s, cpe, start, w, g, + ener0, ener1, ener01, 1, -1); + ph_err2 = ff_aac_is_encoding_err(s, cpe, start, w, g, + ener0, ener1, ener01, 1, +1); + erf = ph_err1.error < ph_err2.error ? &ph_err1 : &ph_err2; + if (erf->pass) { + sce0->ics.prediction_used[sfb] = 1; + sce1->ics.prediction_used[sfb] = 1; + count++; + } else { + RESTORE_PRED(sce0, sfb); + RESTORE_PRED(sce1, sfb); + } + start += sce0->ics.swb_sizes[g]; + } + } + + sce1->ics.predictor_present = sce0->ics.predictor_present = !!count; +} + +static void update_pred_resets(SingleChannelElement *sce) +{ + int i, max_group_id_c, max_frame = 0; + float avg_frame = 0.0f; + IndividualChannelStream *ics = &sce->ics; + + /* Update the counters and immediately update any frame behind schedule */ + if ((ics->predictor_reset_group = update_counters(&sce->ics, 1))) + return; + + for (i = 1; i < 31; i++) { + /* Count-based */ + if (ics->predictor_reset_count[i] > max_frame) { + max_group_id_c = i; + max_frame = ics->predictor_reset_count[i]; + } + avg_frame = (ics->predictor_reset_count[i] + avg_frame)/2; + } + + if (max_frame > PRED_RESET_MIN) { + ics->predictor_reset_group = max_group_id_c; + } else { + ics->predictor_reset_group = 0; + } +} + +void ff_aac_search_for_pred(AACEncContext *s, SingleChannelElement *sce) +{ + int sfb, i, count = 0, cost_coeffs = 0, cost_pred = 0; + const int pmax = FFMIN(sce->ics.max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); + float *O34 = &s->scoefs[128*0], *P34 = &s->scoefs[128*1]; + float *SENT = &s->scoefs[128*2], *S34 = &s->scoefs[128*3]; + float *QERR = &s->scoefs[128*4]; + + if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + sce->ics.predictor_present = 0; + return; + } + + if (!sce->ics.predictor_initialized) { + reset_all_predictors(sce->predictor_state); + sce->ics.predictor_initialized = 1; + memcpy(sce->prcoeffs, sce->coeffs, 1024*sizeof(float)); + for (i = 1; i < 31; i++) + sce->ics.predictor_reset_count[i] = i; + } + + update_pred_resets(sce); + memcpy(sce->band_alt, sce->band_type, sizeof(sce->band_type)); + + for (sfb = PRED_SFB_START; sfb < pmax; sfb++) { + int cost1, cost2, cb_p; + float dist1, dist2, dist_spec_err = 0.0f; + const int cb_n = sce->zeroes[sfb] ? 0 : sce->band_type[sfb]; + const int cb_min = sce->zeroes[sfb] ? 0 : 1; + const int cb_max = sce->zeroes[sfb] ? 0 : RESERVED_BT; + const int start_coef = sce->ics.swb_offset[sfb]; + const int num_coeffs = sce->ics.swb_offset[sfb + 1] - start_coef; + const FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[sfb]; + + if (start_coef + num_coeffs > MAX_PREDICTORS || + (s->cur_channel && sce->band_type[sfb] >= INTENSITY_BT2) || + sce->band_type[sfb] == NOISE_BT) + continue; + + /* Normal coefficients */ + s->abs_pow34(O34, &sce->coeffs[start_coef], num_coeffs); + dist1 = quantize_and_encode_band_cost(s, NULL, &sce->coeffs[start_coef], NULL, + O34, num_coeffs, sce->sf_idx[sfb], + cb_n, s->lambda / band->threshold, INFINITY, &cost1, NULL, 0); + cost_coeffs += cost1; + + /* Encoded coefficients - needed for #bits, band type and quant. error */ + for (i = 0; i < num_coeffs; i++) + SENT[i] = sce->coeffs[start_coef + i] - sce->prcoeffs[start_coef + i]; + s->abs_pow34(S34, SENT, num_coeffs); + if (cb_n < RESERVED_BT) + cb_p = av_clip(find_min_book(find_max_val(1, num_coeffs, S34), sce->sf_idx[sfb]), cb_min, cb_max); + else + cb_p = cb_n; + quantize_and_encode_band_cost(s, NULL, SENT, QERR, S34, num_coeffs, + sce->sf_idx[sfb], cb_p, s->lambda / band->threshold, INFINITY, + &cost2, NULL, 0); + + /* Reconstructed coefficients - needed for distortion measurements */ + for (i = 0; i < num_coeffs; i++) + sce->prcoeffs[start_coef + i] += QERR[i] != 0.0f ? (sce->prcoeffs[start_coef + i] - QERR[i]) : 0.0f; + s->abs_pow34(P34, &sce->prcoeffs[start_coef], num_coeffs); + if (cb_n < RESERVED_BT) + cb_p = av_clip(find_min_book(find_max_val(1, num_coeffs, P34), sce->sf_idx[sfb]), cb_min, cb_max); + else + cb_p = cb_n; + dist2 = quantize_and_encode_band_cost(s, NULL, &sce->prcoeffs[start_coef], NULL, + P34, num_coeffs, sce->sf_idx[sfb], + cb_p, s->lambda / band->threshold, INFINITY, NULL, NULL, 0); + for (i = 0; i < num_coeffs; i++) + dist_spec_err += (O34[i] - P34[i])*(O34[i] - P34[i]); + dist_spec_err *= s->lambda / band->threshold; + dist2 += dist_spec_err; + + if (dist2 <= dist1 && cb_p <= cb_n) { + cost_pred += cost2; + sce->ics.prediction_used[sfb] = 1; + sce->band_alt[sfb] = cb_n; + sce->band_type[sfb] = cb_p; + count++; + } else { + cost_pred += cost1; + sce->band_alt[sfb] = cb_p; + } + } + + if (count && cost_coeffs < cost_pred) { + count = 0; + for (sfb = PRED_SFB_START; sfb < pmax; sfb++) + RESTORE_PRED(sce, sfb); + memset(&sce->ics.prediction_used, 0, sizeof(sce->ics.prediction_used)); + } + + sce->ics.predictor_present = !!count; +} + +/** + * Encoder predictors data. + */ +void ff_aac_encode_main_pred(AACEncContext *s, SingleChannelElement *sce) +{ + int sfb; + IndividualChannelStream *ics = &sce->ics; + const int pmax = FFMIN(ics->max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]); + + if (s->profile != FF_PROFILE_AAC_MAIN || + !ics->predictor_present) + return; + + put_bits(&s->pb, 1, !!ics->predictor_reset_group); + if (ics->predictor_reset_group) + put_bits(&s->pb, 5, ics->predictor_reset_group); + for (sfb = 0; sfb < pmax; sfb++) + put_bits(&s->pb, 1, ics->prediction_used[sfb]); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_pred.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_pred.h new file mode 100644 index 0000000000..aa305f45a5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_pred.h @@ -0,0 +1,47 @@ +/* + * AAC encoder main-type prediction + * Copyright (C) 2015 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder main-type prediction + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#ifndef AVCODEC_AACENC_PRED_H +#define AVCODEC_AACENC_PRED_H + +#include "aacenc.h" + +/* Every predictor group needs to get reset at least once in this many frames */ +#define PRED_RESET_FRAME_MIN 240 + +/* Any frame with less than this amount of frames since last reset is ok */ +#define PRED_RESET_MIN 64 + +/* Raise to filter any low frequency artifacts due to prediction */ +#define PRED_SFB_START 10 + +void ff_aac_apply_main_pred(AACEncContext *s, SingleChannelElement *sce); +void ff_aac_adjust_common_pred(AACEncContext *s, ChannelElement *cpe); +void ff_aac_search_for_pred(AACEncContext *s, SingleChannelElement *sce); +void ff_aac_encode_main_pred(AACEncContext *s, SingleChannelElement *sce); + +#endif /* AVCODEC_AACENC_PRED_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_quantization.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_quantization.h new file mode 100644 index 0000000000..fc5a46b875 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_quantization.h @@ -0,0 +1,283 @@ +/* + * AAC encoder quantizer + * Copyright (C) 2015 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder quantizer + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#ifndef AVCODEC_AACENC_QUANTIZATION_H +#define AVCODEC_AACENC_QUANTIZATION_H + +#include "aactab.h" +#include "aacenc.h" +#include "aacenctab.h" +#include "aacenc_utils.h" + +/** + * Calculate rate distortion cost for quantizing with given codebook + * + * @return quantization distortion + */ +static av_always_inline float quantize_and_encode_band_cost_template( + struct AACEncContext *s, + PutBitContext *pb, const float *in, float *out, + const float *scaled, int size, int scale_idx, + int cb, const float lambda, const float uplim, + int *bits, float *energy, int BT_ZERO, int BT_UNSIGNED, + int BT_PAIR, int BT_ESC, int BT_NOISE, int BT_STEREO, + const float ROUNDING) +{ + const int q_idx = POW_SF2_ZERO - scale_idx + SCALE_ONE_POS - SCALE_DIV_512; + const float Q = ff_aac_pow2sf_tab [q_idx]; + const float Q34 = ff_aac_pow34sf_tab[q_idx]; + const float IQ = ff_aac_pow2sf_tab [POW_SF2_ZERO + scale_idx - SCALE_ONE_POS + SCALE_DIV_512]; + const float CLIPPED_ESCAPE = 165140.0f*IQ; + int i, j; + float cost = 0; + float qenergy = 0; + const int dim = BT_PAIR ? 2 : 4; + int resbits = 0; + int off; + + if (BT_ZERO || BT_NOISE || BT_STEREO) { + for (i = 0; i < size; i++) + cost += in[i]*in[i]; + if (bits) + *bits = 0; + if (energy) + *energy = qenergy; + if (out) { + for (i = 0; i < size; i += dim) + for (j = 0; j < dim; j++) + out[i+j] = 0.0f; + } + return cost * lambda; + } + if (!scaled) { + s->abs_pow34(s->scoefs, in, size); + scaled = s->scoefs; + } + s->quant_bands(s->qcoefs, in, scaled, size, !BT_UNSIGNED, aac_cb_maxval[cb], Q34, ROUNDING); + if (BT_UNSIGNED) { + off = 0; + } else { + off = aac_cb_maxval[cb]; + } + for (i = 0; i < size; i += dim) { + const float *vec; + int *quants = s->qcoefs + i; + int curidx = 0; + int curbits; + float quantized, rd = 0.0f; + for (j = 0; j < dim; j++) { + curidx *= aac_cb_range[cb]; + curidx += quants[j] + off; + } + curbits = ff_aac_spectral_bits[cb-1][curidx]; + vec = &ff_aac_codebook_vectors[cb-1][curidx*dim]; + if (BT_UNSIGNED) { + for (j = 0; j < dim; j++) { + float t = fabsf(in[i+j]); + float di; + if (BT_ESC && vec[j] == 64.0f) { //FIXME: slow + if (t >= CLIPPED_ESCAPE) { + quantized = CLIPPED_ESCAPE; + curbits += 21; + } else { + int c = av_clip_uintp2(quant(t, Q, ROUNDING), 13); + quantized = c*cbrtf(c)*IQ; + curbits += av_log2(c)*2 - 4 + 1; + } + } else { + quantized = vec[j]*IQ; + } + di = t - quantized; + if (out) + out[i+j] = in[i+j] >= 0 ? quantized : -quantized; + if (vec[j] != 0.0f) + curbits++; + qenergy += quantized*quantized; + rd += di*di; + } + } else { + for (j = 0; j < dim; j++) { + quantized = vec[j]*IQ; + qenergy += quantized*quantized; + if (out) + out[i+j] = quantized; + rd += (in[i+j] - quantized)*(in[i+j] - quantized); + } + } + cost += rd * lambda + curbits; + resbits += curbits; + if (cost >= uplim) + return uplim; + if (pb) { + put_bits(pb, ff_aac_spectral_bits[cb-1][curidx], ff_aac_spectral_codes[cb-1][curidx]); + if (BT_UNSIGNED) + for (j = 0; j < dim; j++) + if (ff_aac_codebook_vectors[cb-1][curidx*dim+j] != 0.0f) + put_bits(pb, 1, in[i+j] < 0.0f); + if (BT_ESC) { + for (j = 0; j < 2; j++) { + if (ff_aac_codebook_vectors[cb-1][curidx*2+j] == 64.0f) { + int coef = av_clip_uintp2(quant(fabsf(in[i+j]), Q, ROUNDING), 13); + int len = av_log2(coef); + + put_bits(pb, len - 4 + 1, (1 << (len - 4 + 1)) - 2); + put_sbits(pb, len, coef); + } + } + } + } + } + + if (bits) + *bits = resbits; + if (energy) + *energy = qenergy; + return cost; +} + +static inline float quantize_and_encode_band_cost_NONE(struct AACEncContext *s, PutBitContext *pb, + const float *in, float *quant, const float *scaled, + int size, int scale_idx, int cb, + const float lambda, const float uplim, + int *bits, float *energy) { + av_assert0(0); + return 0.0f; +} + +#define QUANTIZE_AND_ENCODE_BAND_COST_FUNC(NAME, BT_ZERO, BT_UNSIGNED, BT_PAIR, BT_ESC, BT_NOISE, BT_STEREO, ROUNDING) \ +static float quantize_and_encode_band_cost_ ## NAME( \ + struct AACEncContext *s, \ + PutBitContext *pb, const float *in, float *quant, \ + const float *scaled, int size, int scale_idx, \ + int cb, const float lambda, const float uplim, \ + int *bits, float *energy) { \ + return quantize_and_encode_band_cost_template( \ + s, pb, in, quant, scaled, size, scale_idx, \ + BT_ESC ? ESC_BT : cb, lambda, uplim, bits, energy, \ + BT_ZERO, BT_UNSIGNED, BT_PAIR, BT_ESC, BT_NOISE, BT_STEREO, \ + ROUNDING); \ +} + +QUANTIZE_AND_ENCODE_BAND_COST_FUNC(ZERO, 1, 0, 0, 0, 0, 0, ROUND_STANDARD) +QUANTIZE_AND_ENCODE_BAND_COST_FUNC(SQUAD, 0, 0, 0, 0, 0, 0, ROUND_STANDARD) +QUANTIZE_AND_ENCODE_BAND_COST_FUNC(UQUAD, 0, 1, 0, 0, 0, 0, ROUND_STANDARD) +QUANTIZE_AND_ENCODE_BAND_COST_FUNC(SPAIR, 0, 0, 1, 0, 0, 0, ROUND_STANDARD) +QUANTIZE_AND_ENCODE_BAND_COST_FUNC(UPAIR, 0, 1, 1, 0, 0, 0, ROUND_STANDARD) +QUANTIZE_AND_ENCODE_BAND_COST_FUNC(ESC, 0, 1, 1, 1, 0, 0, ROUND_STANDARD) +QUANTIZE_AND_ENCODE_BAND_COST_FUNC(ESC_RTZ, 0, 1, 1, 1, 0, 0, ROUND_TO_ZERO) +QUANTIZE_AND_ENCODE_BAND_COST_FUNC(NOISE, 0, 0, 0, 0, 1, 0, ROUND_STANDARD) +QUANTIZE_AND_ENCODE_BAND_COST_FUNC(STEREO,0, 0, 0, 0, 0, 1, ROUND_STANDARD) + +static float (*const quantize_and_encode_band_cost_arr[])( + struct AACEncContext *s, + PutBitContext *pb, const float *in, float *quant, + const float *scaled, int size, int scale_idx, + int cb, const float lambda, const float uplim, + int *bits, float *energy) = { + quantize_and_encode_band_cost_ZERO, + quantize_and_encode_band_cost_SQUAD, + quantize_and_encode_band_cost_SQUAD, + quantize_and_encode_band_cost_UQUAD, + quantize_and_encode_band_cost_UQUAD, + quantize_and_encode_band_cost_SPAIR, + quantize_and_encode_band_cost_SPAIR, + quantize_and_encode_band_cost_UPAIR, + quantize_and_encode_band_cost_UPAIR, + quantize_and_encode_band_cost_UPAIR, + quantize_and_encode_band_cost_UPAIR, + quantize_and_encode_band_cost_ESC, + quantize_and_encode_band_cost_NONE, /* CB 12 doesn't exist */ + quantize_and_encode_band_cost_NOISE, + quantize_and_encode_band_cost_STEREO, + quantize_and_encode_band_cost_STEREO, +}; + +static float (*const quantize_and_encode_band_cost_rtz_arr[])( + struct AACEncContext *s, + PutBitContext *pb, const float *in, float *quant, + const float *scaled, int size, int scale_idx, + int cb, const float lambda, const float uplim, + int *bits, float *energy) = { + quantize_and_encode_band_cost_ZERO, + quantize_and_encode_band_cost_SQUAD, + quantize_and_encode_band_cost_SQUAD, + quantize_and_encode_band_cost_UQUAD, + quantize_and_encode_band_cost_UQUAD, + quantize_and_encode_band_cost_SPAIR, + quantize_and_encode_band_cost_SPAIR, + quantize_and_encode_band_cost_UPAIR, + quantize_and_encode_band_cost_UPAIR, + quantize_and_encode_band_cost_UPAIR, + quantize_and_encode_band_cost_UPAIR, + quantize_and_encode_band_cost_ESC_RTZ, + quantize_and_encode_band_cost_NONE, /* CB 12 doesn't exist */ + quantize_and_encode_band_cost_NOISE, + quantize_and_encode_band_cost_STEREO, + quantize_and_encode_band_cost_STEREO, +}; + +#define quantize_and_encode_band_cost( \ + s, pb, in, quant, scaled, size, scale_idx, cb, \ + lambda, uplim, bits, energy, rtz) \ + ((rtz) ? quantize_and_encode_band_cost_rtz_arr : quantize_and_encode_band_cost_arr)[cb]( \ + s, pb, in, quant, scaled, size, scale_idx, cb, \ + lambda, uplim, bits, energy) + +static inline float quantize_band_cost(struct AACEncContext *s, const float *in, + const float *scaled, int size, int scale_idx, + int cb, const float lambda, const float uplim, + int *bits, float *energy, int rtz) +{ + return quantize_and_encode_band_cost(s, NULL, in, NULL, scaled, size, scale_idx, + cb, lambda, uplim, bits, energy, rtz); +} + +static inline int quantize_band_cost_bits(struct AACEncContext *s, const float *in, + const float *scaled, int size, int scale_idx, + int cb, const float lambda, const float uplim, + int *bits, float *energy, int rtz) +{ + int auxbits; + quantize_and_encode_band_cost(s, NULL, in, NULL, scaled, size, scale_idx, + cb, 0.0f, uplim, &auxbits, energy, rtz); + if (bits) { + *bits = auxbits; + } + return auxbits; +} + +static inline void quantize_and_encode_band(struct AACEncContext *s, PutBitContext *pb, + const float *in, float *out, int size, int scale_idx, + int cb, const float lambda, int rtz) +{ + quantize_and_encode_band_cost(s, pb, in, out, NULL, size, scale_idx, cb, lambda, + INFINITY, NULL, NULL, rtz); +} + +#include "aacenc_quantization_misc.h" + +#endif /* AVCODEC_AACENC_QUANTIZATION_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_quantization_misc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_quantization_misc.h new file mode 100644 index 0000000000..28676ca8d5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_quantization_misc.h @@ -0,0 +1,53 @@ +/* + * AAC encoder quantization + * Copyright (C) 2015 Claudio Freire + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder quantization misc reusable function templates + * @author Claudio Freire ( klaussfreire gmail com ) + */ + +#ifndef AVCODEC_AACENC_QUANTIZATION_MISC_H +#define AVCODEC_AACENC_QUANTIZATION_MISC_H + +static inline float quantize_band_cost_cached(struct AACEncContext *s, int w, int g, const float *in, + const float *scaled, int size, int scale_idx, + int cb, const float lambda, const float uplim, + int *bits, float *energy, int rtz) +{ + AACQuantizeBandCostCacheEntry *entry; + av_assert1(scale_idx >= 0 && scale_idx < 256); + entry = &s->quantize_band_cost_cache[scale_idx][w*16+g]; + if (entry->generation != s->quantize_band_cost_cache_generation || entry->cb != cb || entry->rtz != rtz) { + entry->rd = quantize_band_cost(s, in, scaled, size, scale_idx, + cb, lambda, uplim, &entry->bits, &entry->energy, rtz); + entry->cb = cb; + entry->rtz = rtz; + entry->generation = s->quantize_band_cost_cache_generation; + } + if (bits) + *bits = entry->bits; + if (energy) + *energy = entry->energy; + return entry->rd; +} + +#endif /* AVCODEC_AACENC_QUANTIZATION_MISC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_tns.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_tns.c new file mode 100644 index 0000000000..2ffe1f8de8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_tns.c @@ -0,0 +1,215 @@ +/* + * AAC encoder TNS + * Copyright (C) 2015 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder temporal noise shaping + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#include "libavutil/libm.h" +#include "aacenc.h" +#include "aacenc_tns.h" +#include "aactab.h" +#include "aacenc_utils.h" +#include "aacenc_quantization.h" + +/* Could be set to 3 to save an additional bit at the cost of little quality */ +#define TNS_Q_BITS 4 + +/* Coefficient resolution in short windows */ +#define TNS_Q_BITS_IS8 4 + +/* We really need the bits we save here elsewhere */ +#define TNS_ENABLE_COEF_COMPRESSION + +/* TNS will only be used if the LPC gain is within these margins */ +#define TNS_GAIN_THRESHOLD_LOW 1.4f +#define TNS_GAIN_THRESHOLD_HIGH 1.16f*TNS_GAIN_THRESHOLD_LOW + +static inline int compress_coeffs(int *coef, int order, int c_bits) +{ + int i; + const int low_idx = c_bits ? 4 : 2; + const int shift_val = c_bits ? 8 : 4; + const int high_idx = c_bits ? 11 : 5; +#ifndef TNS_ENABLE_COEF_COMPRESSION + return 0; +#endif /* TNS_ENABLE_COEF_COMPRESSION */ + for (i = 0; i < order; i++) + if (coef[i] >= low_idx && coef[i] <= high_idx) + return 0; + for (i = 0; i < order; i++) + coef[i] -= (coef[i] > high_idx) ? shift_val : 0; + return 1; +} + +/** + * Encode TNS data. + * Coefficient compression is simply not lossless as it should be + * on any decoder tested and as such is not active. + */ +void ff_aac_encode_tns_info(AACEncContext *s, SingleChannelElement *sce) +{ + TemporalNoiseShaping *tns = &sce->tns; + int i, w, filt, coef_compress = 0, coef_len; + const int is8 = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE; + const int c_bits = is8 ? TNS_Q_BITS_IS8 == 4 : TNS_Q_BITS == 4; + + if (!sce->tns.present) + return; + + for (i = 0; i < sce->ics.num_windows; i++) { + put_bits(&s->pb, 2 - is8, sce->tns.n_filt[i]); + if (!tns->n_filt[i]) + continue; + put_bits(&s->pb, 1, c_bits); + for (filt = 0; filt < tns->n_filt[i]; filt++) { + put_bits(&s->pb, 6 - 2 * is8, tns->length[i][filt]); + put_bits(&s->pb, 5 - 2 * is8, tns->order[i][filt]); + if (!tns->order[i][filt]) + continue; + put_bits(&s->pb, 1, tns->direction[i][filt]); + coef_compress = compress_coeffs(tns->coef_idx[i][filt], + tns->order[i][filt], c_bits); + put_bits(&s->pb, 1, coef_compress); + coef_len = c_bits + 3 - coef_compress; + for (w = 0; w < tns->order[i][filt]; w++) + put_bits(&s->pb, coef_len, tns->coef_idx[i][filt][w]); + } + } +} + +/* Apply TNS filter */ +void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce) +{ + TemporalNoiseShaping *tns = &sce->tns; + IndividualChannelStream *ics = &sce->ics; + int w, filt, m, i, top, order, bottom, start, end, size, inc; + const int mmm = FFMIN(ics->tns_max_bands, ics->max_sfb); + float lpc[TNS_MAX_ORDER]; + + for (w = 0; w < ics->num_windows; w++) { + bottom = ics->num_swb; + for (filt = 0; filt < tns->n_filt[w]; filt++) { + top = bottom; + bottom = FFMAX(0, top - tns->length[w][filt]); + order = tns->order[w][filt]; + if (order == 0) + continue; + + // tns_decode_coef + compute_lpc_coefs(tns->coef[w][filt], order, lpc, 0, 0, 0); + + start = ics->swb_offset[FFMIN(bottom, mmm)]; + end = ics->swb_offset[FFMIN( top, mmm)]; + if ((size = end - start) <= 0) + continue; + if (tns->direction[w][filt]) { + inc = -1; + start = end - 1; + } else { + inc = 1; + } + start += w * 128; + + /* AR filter */ + for (m = 0; m < size; m++, start += inc) { + for (i = 1; i <= FFMIN(m, order); i++) { + sce->coeffs[start] += lpc[i-1]*sce->pcoeffs[start - i*inc]; + } + } + } + } +} + +/* + * c_bits - 1 if 4 bit coefficients, 0 if 3 bit coefficients + */ +static inline void quantize_coefs(double *coef, int *idx, float *lpc, int order, + int c_bits) +{ + int i; + const float *quant_arr = tns_tmp2_map[c_bits]; + for (i = 0; i < order; i++) { + idx[i] = quant_array_idx(coef[i], quant_arr, c_bits ? 16 : 8); + lpc[i] = quant_arr[idx[i]]; + } +} + +/* + * 3 bits per coefficient with 8 short windows + */ +void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce) +{ + TemporalNoiseShaping *tns = &sce->tns; + int w, g, count = 0; + double gain, coefs[MAX_LPC_ORDER]; + const int mmm = FFMIN(sce->ics.tns_max_bands, sce->ics.max_sfb); + const int is8 = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE; + const int c_bits = is8 ? TNS_Q_BITS_IS8 == 4 : TNS_Q_BITS == 4; + const int sfb_start = av_clip(tns_min_sfb[is8][s->samplerate_index], 0, mmm); + const int sfb_end = av_clip(sce->ics.num_swb, 0, mmm); + const int order = is8 ? 7 : s->profile == FF_PROFILE_AAC_LOW ? 12 : TNS_MAX_ORDER; + const int slant = sce->ics.window_sequence[0] == LONG_STOP_SEQUENCE ? 1 : + sce->ics.window_sequence[0] == LONG_START_SEQUENCE ? 0 : 2; + const int sfb_len = sfb_end - sfb_start; + const int coef_len = sce->ics.swb_offset[sfb_end] - sce->ics.swb_offset[sfb_start]; + + if (coef_len <= 0 || sfb_len <= 0) { + sce->tns.present = 0; + return; + } + + for (w = 0; w < sce->ics.num_windows; w++) { + float en[2] = {0.0f, 0.0f}; + int oc_start = 0, os_start = 0; + int coef_start = sce->ics.swb_offset[sfb_start]; + + for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) { + FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g]; + if (g > sfb_start + (sfb_len/2)) + en[1] += band->energy; + else + en[0] += band->energy; + } + + /* LPC */ + gain = ff_lpc_calc_ref_coefs_f(&s->lpc, &sce->coeffs[w*128 + coef_start], + coef_len, order, coefs); + + if (!order || !isfinite(gain) || gain < TNS_GAIN_THRESHOLD_LOW || gain > TNS_GAIN_THRESHOLD_HIGH) + continue; + + tns->n_filt[w] = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3; + for (g = 0; g < tns->n_filt[w]; g++) { + tns->direction[w][g] = slant != 2 ? slant : en[g] < en[!g]; + tns->order[w][g] = g < tns->n_filt[w] ? order/tns->n_filt[w] : order - oc_start; + tns->length[w][g] = g < tns->n_filt[w] ? sfb_len/tns->n_filt[w] : sfb_len - os_start; + quantize_coefs(&coefs[oc_start], tns->coef_idx[w][g], tns->coef[w][g], + tns->order[w][g], c_bits); + oc_start += tns->order[w][g]; + os_start += tns->length[w][g]; + } + count++; + } + sce->tns.present = !!count; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_tns.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_tns.h new file mode 100644 index 0000000000..466738dd16 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_tns.h @@ -0,0 +1,37 @@ +/* + * AAC encoder TNS + * Copyright (C) 2015 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder temporal noise shaping + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#ifndef AVCODEC_AACENC_TNS_H +#define AVCODEC_AACENC_TNS_H + +#include "aacenc.h" + +void ff_aac_encode_tns_info(AACEncContext *s, SingleChannelElement *sce); +void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce); +void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce); + +#endif /* AVCODEC_AACENC_TNS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_utils.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_utils.h new file mode 100644 index 0000000000..bef4c103f3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenc_utils.h @@ -0,0 +1,279 @@ +/* + * AAC encoder utilities + * Copyright (C) 2015 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder utilities + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#ifndef AVCODEC_AACENC_UTILS_H +#define AVCODEC_AACENC_UTILS_H + +#include "libavutil/ffmath.h" +#include "aac.h" +#include "aacenctab.h" +#include "aactab.h" + +#define ROUND_STANDARD 0.4054f +#define ROUND_TO_ZERO 0.1054f +#define C_QUANT 0.4054f + +static inline void abs_pow34_v(float *out, const float *in, const int size) +{ + int i; + for (i = 0; i < size; i++) { + float a = fabsf(in[i]); + out[i] = sqrtf(a * sqrtf(a)); + } +} + +static inline float pos_pow34(float a) +{ + return sqrtf(a * sqrtf(a)); +} + +/** + * Quantize one coefficient. + * @return absolute value of the quantized coefficient + * @see 3GPP TS26.403 5.6.2 "Scalefactor determination" + */ +static inline int quant(float coef, const float Q, const float rounding) +{ + float a = coef * Q; + return sqrtf(a * sqrtf(a)) + rounding; +} + +static inline void quantize_bands(int *out, const float *in, const float *scaled, + int size, int is_signed, int maxval, const float Q34, + const float rounding) +{ + int i; + for (i = 0; i < size; i++) { + float qc = scaled[i] * Q34; + int tmp = (int)FFMIN(qc + rounding, (float)maxval); + if (is_signed && in[i] < 0.0f) { + tmp = -tmp; + } + out[i] = tmp; + } +} + +static inline float find_max_val(int group_len, int swb_size, const float *scaled) +{ + float maxval = 0.0f; + int w2, i; + for (w2 = 0; w2 < group_len; w2++) { + for (i = 0; i < swb_size; i++) { + maxval = FFMAX(maxval, scaled[w2*128+i]); + } + } + return maxval; +} + +static inline int find_min_book(float maxval, int sf) +{ + float Q34 = ff_aac_pow34sf_tab[POW_SF2_ZERO - sf + SCALE_ONE_POS - SCALE_DIV_512]; + int qmaxval, cb; + qmaxval = maxval * Q34 + C_QUANT; + if (qmaxval >= (FF_ARRAY_ELEMS(aac_maxval_cb))) + cb = 11; + else + cb = aac_maxval_cb[qmaxval]; + return cb; +} + +static inline float find_form_factor(int group_len, int swb_size, float thresh, + const float *scaled, float nzslope) { + const float iswb_size = 1.0f / swb_size; + const float iswb_sizem1 = 1.0f / (swb_size - 1); + const float ethresh = thresh; + float form = 0.0f, weight = 0.0f; + int w2, i; + for (w2 = 0; w2 < group_len; w2++) { + float e = 0.0f, e2 = 0.0f, var = 0.0f, maxval = 0.0f; + float nzl = 0; + for (i = 0; i < swb_size; i++) { + float s = fabsf(scaled[w2*128+i]); + maxval = FFMAX(maxval, s); + e += s; + e2 += s *= s; + /* We really don't want a hard non-zero-line count, since + * even below-threshold lines do add up towards band spectral power. + * So, fall steeply towards zero, but smoothly + */ + if (s >= ethresh) { + nzl += 1.0f; + } else { + if (nzslope == 2.f) + nzl += (s / ethresh) * (s / ethresh); + else + nzl += ff_fast_powf(s / ethresh, nzslope); + } + } + if (e2 > thresh) { + float frm; + e *= iswb_size; + + /** compute variance */ + for (i = 0; i < swb_size; i++) { + float d = fabsf(scaled[w2*128+i]) - e; + var += d*d; + } + var = sqrtf(var * iswb_sizem1); + + e2 *= iswb_size; + frm = e / FFMIN(e+4*var,maxval); + form += e2 * sqrtf(frm) / FFMAX(0.5f,nzl); + weight += e2; + } + } + if (weight > 0) { + return form / weight; + } else { + return 1.0f; + } +} + +/** Return the minimum scalefactor where the quantized coef does not clip. */ +static inline uint8_t coef2minsf(float coef) +{ + return av_clip_uint8(log2f(coef)*4 - 69 + SCALE_ONE_POS - SCALE_DIV_512); +} + +/** Return the maximum scalefactor where the quantized coef is not zero. */ +static inline uint8_t coef2maxsf(float coef) +{ + return av_clip_uint8(log2f(coef)*4 + 6 + SCALE_ONE_POS - SCALE_DIV_512); +} + +/* + * Returns the closest possible index to an array of float values, given a value. + */ +static inline int quant_array_idx(const float val, const float *arr, const int num) +{ + int i, index = 0; + float quant_min_err = INFINITY; + for (i = 0; i < num; i++) { + float error = (val - arr[i])*(val - arr[i]); + if (error < quant_min_err) { + quant_min_err = error; + index = i; + } + } + return index; +} + +/** + * approximates exp10f(-3.0f*(0.5f + 0.5f * cosf(FFMIN(b,15.5f) / 15.5f))) + */ +static av_always_inline float bval2bmax(float b) +{ + return 0.001f + 0.0035f * (b*b*b) / (15.5f*15.5f*15.5f); +} + +/* + * Compute a nextband map to be used with SF delta constraint utilities. + * The nextband array should contain 128 elements, and positions that don't + * map to valid, nonzero bands of the form w*16+g (with w being the initial + * window of the window group, only) are left indetermined. + */ +static inline void ff_init_nextband_map(const SingleChannelElement *sce, uint8_t *nextband) +{ + unsigned char prevband = 0; + int w, g; + /** Just a safe default */ + for (g = 0; g < 128; g++) + nextband[g] = g; + + /** Now really navigate the nonzero band chain */ + for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) { + for (g = 0; g < sce->ics.num_swb; g++) { + if (!sce->zeroes[w*16+g] && sce->band_type[w*16+g] < RESERVED_BT) + prevband = nextband[prevband] = w*16+g; + } + } + nextband[prevband] = prevband; /* terminate */ +} + +/* + * Updates nextband to reflect a removed band (equivalent to + * calling ff_init_nextband_map after marking a band as zero) + */ +static inline void ff_nextband_remove(uint8_t *nextband, int prevband, int band) +{ + nextband[prevband] = nextband[band]; +} + +/* + * Checks whether the specified band could be removed without inducing + * scalefactor delta that violates SF delta encoding constraints. + * prev_sf has to be the scalefactor of the previous nonzero, nonspecial + * band, in encoding order, or negative if there was no such band. + */ +static inline int ff_sfdelta_can_remove_band(const SingleChannelElement *sce, + const uint8_t *nextband, int prev_sf, int band) +{ + return prev_sf >= 0 + && sce->sf_idx[nextband[band]] >= (prev_sf - SCALE_MAX_DIFF) + && sce->sf_idx[nextband[band]] <= (prev_sf + SCALE_MAX_DIFF); +} + +/* + * Checks whether the specified band's scalefactor could be replaced + * with another one without violating SF delta encoding constraints. + * prev_sf has to be the scalefactor of the previous nonzero, nonsepcial + * band, in encoding order, or negative if there was no such band. + */ +static inline int ff_sfdelta_can_replace(const SingleChannelElement *sce, + const uint8_t *nextband, int prev_sf, int new_sf, int band) +{ + return new_sf >= (prev_sf - SCALE_MAX_DIFF) + && new_sf <= (prev_sf + SCALE_MAX_DIFF) + && sce->sf_idx[nextband[band]] >= (new_sf - SCALE_MAX_DIFF) + && sce->sf_idx[nextband[band]] <= (new_sf + SCALE_MAX_DIFF); +} + +/** + * linear congruential pseudorandom number generator + * + * @param previous_val pointer to the current state of the generator + * + * @return Returns a 32-bit pseudorandom integer + */ +static av_always_inline int lcg_random(unsigned previous_val) +{ + union { unsigned u; int s; } v = { previous_val * 1664525u + 1013904223 }; + return v.s; +} + +#define ERROR_IF(cond, ...) \ + if (cond) { \ + av_log(avctx, AV_LOG_ERROR, __VA_ARGS__); \ + return AVERROR(EINVAL); \ + } + +#define WARN_IF(cond, ...) \ + if (cond) { \ + av_log(avctx, AV_LOG_WARNING, __VA_ARGS__); \ + } + +#endif /* AVCODEC_AACENC_UTILS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacencdsp.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacencdsp.asm new file mode 100644 index 0000000000..97af571ec8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacencdsp.asm @@ -0,0 +1,86 @@ +;****************************************************************************** +;* SIMD optimized AAC encoder DSP functions +;* +;* Copyright (C) 2016 Rostislav Pehlivanov +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA + +float_abs_mask: times 4 dd 0x7fffffff + +SECTION .text + +;******************************************************************* +;void ff_abs_pow34(float *out, const float *in, const int size); +;******************************************************************* +INIT_XMM sse +cglobal abs_pow34, 3, 3, 3, out, in, size + mova m2, [float_abs_mask] + shl sizeq, 2 + add inq, sizeq + add outq, sizeq + neg sizeq +.loop: + andps m0, m2, [inq+sizeq] + sqrtps m1, m0 + mulps m0, m1 + sqrtps m0, m0 + mova [outq+sizeq], m0 + add sizeq, mmsize + jl .loop + RET + +;******************************************************************* +;void ff_aac_quantize_bands(int *out, const float *in, const float *scaled, +; int size, int is_signed, int maxval, const float Q34, +; const float rounding) +;******************************************************************* +INIT_XMM sse2 +cglobal aac_quantize_bands, 5, 5, 6, out, in, scaled, size, is_signed, maxval, Q34, rounding +%if UNIX64 == 0 + movss m0, Q34m + movss m1, roundingm + cvtsi2ss m3, dword maxvalm +%else + cvtsi2ss m3, maxvald +%endif + shufps m0, m0, 0 + shufps m1, m1, 0 + shufps m3, m3, 0 + shl is_signedd, 31 + movd m4, is_signedd + shufps m4, m4, 0 + shl sized, 2 + add inq, sizeq + add outq, sizeq + add scaledq, sizeq + neg sizeq +.loop: + mulps m2, m0, [scaledq+sizeq] + addps m2, m1 + minps m2, m3 + andps m5, m4, [inq+sizeq] + orps m2, m5 + cvttps2dq m2, m2 + mova [outq+sizeq], m2 + add sizeq, mmsize + jl .loop + RET diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacencdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacencdsp_init.c new file mode 100644 index 0000000000..d761c3c5e6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacencdsp_init.c @@ -0,0 +1,43 @@ +/* + * AAC encoder assembly optimizations + * Copyright (C) 2016 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/float_dsp.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/aacenc.h" + +void ff_abs_pow34_sse(float *out, const float *in, const int size); + +void ff_aac_quantize_bands_sse2(int *out, const float *in, const float *scaled, + int size, int is_signed, int maxval, const float Q34, + const float rounding); + +av_cold void ff_aac_dsp_init_x86(AACEncContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE(cpu_flags)) + s->abs_pow34 = ff_abs_pow34_sse; + + if (EXTERNAL_SSE2(cpu_flags)) + s->quant_bands = ff_aac_quantize_bands_sse2; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenctab.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenctab.c new file mode 100644 index 0000000000..f3d70fbe31 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenctab.c @@ -0,0 +1,108 @@ +/* + * AAC encoder data + * Copyright (c) 2015 Rostislav Pehlivanov ( atomnuker gmail com ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "aacenctab.h" + +static const uint8_t swb_size_128_96[] = { + 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 +}; + +static const uint8_t swb_size_128_64[] = { + 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 +}; + +static const uint8_t swb_size_128_48[] = { + 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16 +}; + +static const uint8_t swb_size_128_24[] = { + 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 16, 16, 20 +}; + +static const uint8_t swb_size_128_16[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 12, 12, 16, 20, 20 +}; + +static const uint8_t swb_size_128_8[] = { + 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 12, 16, 20, 20 +}; + +static const uint8_t swb_size_1024_96[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, + 12, 12, 12, 12, 12, 16, 16, 24, 28, 36, 44, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 +}; + +static const uint8_t swb_size_1024_64[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, + 12, 12, 12, 16, 16, 16, 20, 24, 24, 28, 36, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40 +}; + +static const uint8_t swb_size_1024_48[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, + 12, 12, 12, 12, 16, 16, 20, 20, 24, 24, 28, 28, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 96 +}; + +static const uint8_t swb_size_1024_32[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, + 12, 12, 12, 12, 16, 16, 20, 20, 24, 24, 28, 28, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 +}; + +static const uint8_t swb_size_1024_24[] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 12, 12, 12, 12, 16, 16, 16, 20, 20, 24, 24, 28, 28, + 32, 36, 36, 40, 44, 48, 52, 52, 64, 64, 64, 64, 64 +}; + +static const uint8_t swb_size_1024_16[] = { + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 20, 20, 20, 24, 24, 28, 28, + 32, 36, 40, 40, 44, 48, 52, 56, 60, 64, 64, 64 +}; + +static const uint8_t swb_size_1024_8[] = { + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 16, 16, 16, 16, 16, 16, 16, 20, 20, 20, 20, 24, 24, 24, 28, 28, + 32, 36, 36, 40, 44, 48, 52, 56, 60, 64, 80 +}; + +const uint8_t *ff_aac_swb_size_128[] = { + swb_size_128_96, swb_size_128_96, swb_size_128_64, + swb_size_128_48, swb_size_128_48, swb_size_128_48, + swb_size_128_24, swb_size_128_24, swb_size_128_16, + swb_size_128_16, swb_size_128_16, swb_size_128_8, + swb_size_128_8 +}; + +const uint8_t *ff_aac_swb_size_1024[] = { + swb_size_1024_96, swb_size_1024_96, swb_size_1024_64, + swb_size_1024_48, swb_size_1024_48, swb_size_1024_32, + swb_size_1024_24, swb_size_1024_24, swb_size_1024_16, + swb_size_1024_16, swb_size_1024_16, swb_size_1024_8, + swb_size_1024_8 +}; + +const int ff_aac_swb_size_128_len = FF_ARRAY_ELEMS(ff_aac_swb_size_128); +const int ff_aac_swb_size_1024_len = FF_ARRAY_ELEMS(ff_aac_swb_size_1024); diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenctab.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenctab.h new file mode 100644 index 0000000000..64932d709f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacenctab.h @@ -0,0 +1,139 @@ +/* + * AAC encoder data + * Copyright (c) 2015 Rostislav Pehlivanov ( atomnuker gmail com ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder data + * @author Rostislav Pehlivanov ( atomnuker gmail com ) + */ + +#ifndef AVCODEC_AACENCTAB_H +#define AVCODEC_AACENCTAB_H + +#include "aac.h" + +/** Total number of usable codebooks **/ +#define CB_TOT 12 + +/** Total number of codebooks, including special ones **/ +#define CB_TOT_ALL 15 + +#define AAC_MAX_CHANNELS 16 + +extern const uint8_t *ff_aac_swb_size_1024[]; +extern const int ff_aac_swb_size_1024_len; +extern const uint8_t *ff_aac_swb_size_128[]; +extern const int ff_aac_swb_size_128_len; + +/* Supported layouts without using a PCE */ +static const int64_t aac_normal_chan_layouts[7] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0_BACK, + AV_CH_LAYOUT_5POINT1_BACK, + AV_CH_LAYOUT_7POINT1, +}; + +/** default channel configurations */ +static const uint8_t aac_chan_configs[AAC_MAX_CHANNELS][6] = { + {1, TYPE_SCE}, // 1 channel - single channel element + {1, TYPE_CPE}, // 2 channels - channel pair + {2, TYPE_SCE, TYPE_CPE}, // 3 channels - center + stereo + {3, TYPE_SCE, TYPE_CPE, TYPE_SCE}, // 4 channels - front center + stereo + back center + {3, TYPE_SCE, TYPE_CPE, TYPE_CPE}, // 5 channels - front center + stereo + back stereo + {4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE}, // 6 channels - front center + stereo + back stereo + LFE + {0}, // 7 channels - invalid without PCE + {5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE}, // 8 channels - front center + front stereo + side stereo + back stereo + LFE +}; + +/** + * Table to remap channels from libavcodec's default order to AAC order. + */ +static const uint8_t aac_chan_maps[AAC_MAX_CHANNELS][AAC_MAX_CHANNELS] = { + { 0 }, + { 0, 1 }, + { 2, 0, 1 }, + { 2, 0, 1, 3 }, + { 2, 0, 1, 3, 4 }, + { 2, 0, 1, 4, 5, 3 }, + { 0 }, + { 2, 0, 1, 6, 7, 4, 5, 3 }, +}; + +/* duplicated from avpriv_mpeg4audio_sample_rates to avoid shared build + * failures */ +static const int mpeg4audio_sample_rates[16] = { + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000, 7350 +}; + +/** bits needed to code codebook run value for long windows */ +static const uint8_t run_value_bits_long[64] = { + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 15 +}; + +/** bits needed to code codebook run value for short windows */ +static const uint8_t run_value_bits_short[16] = { + 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 9 +}; + +/* TNS starting SFBs for long and short windows */ +static const uint8_t tns_min_sfb_short[16] = { + 2, 2, 2, 3, 3, 4, 6, 6, 8, 10, 10, 12, 12, 12, 12, 12 +}; + +static const uint8_t tns_min_sfb_long[16] = { + 12, 13, 15, 16, 17, 20, 25, 26, 24, 28, 30, 31, 31, 31, 31, 31 +}; + +static const uint8_t * const tns_min_sfb[2] = { + tns_min_sfb_long, tns_min_sfb_short +}; + +static const uint8_t * const run_value_bits[2] = { + run_value_bits_long, run_value_bits_short +}; + +/** Map to convert values from BandCodingPath index to a codebook index **/ +static const uint8_t aac_cb_out_map[CB_TOT_ALL] = {0,1,2,3,4,5,6,7,8,9,10,11,13,14,15}; +/** Inverse map to convert from codebooks to BandCodingPath indices **/ +static const uint8_t aac_cb_in_map[CB_TOT_ALL+1] = {0,1,2,3,4,5,6,7,8,9,10,11,0,12,13,14}; + +static const uint8_t aac_cb_range [12] = {0, 3, 3, 3, 3, 9, 9, 8, 8, 13, 13, 17}; +static const uint8_t aac_cb_maxval[12] = {0, 1, 1, 2, 2, 4, 4, 7, 7, 12, 12, 16}; + +static const unsigned char aac_maxval_cb[] = { + 0, 1, 3, 5, 5, 7, 7, 7, 9, 9, 9, 9, 9, 11 +}; + +static const int aacenc_profiles[] = { + FF_PROFILE_AAC_MAIN, + FF_PROFILE_AAC_LOW, + FF_PROFILE_AAC_LTP, + FF_PROFILE_MPEG2_AAC_LOW, +}; + +#endif /* AVCODEC_AACENCTAB_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps.c new file mode 100644 index 0000000000..d5dca64b0f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps.c @@ -0,0 +1,1046 @@ +/* + * MPEG-4 Parametric Stereo decoding functions + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Note: Rounding-to-nearest used unless otherwise stated + * + */ + +#include +#include "libavutil/common.h" +#include "libavutil/mathematics.h" +#include "avcodec.h" +#include "get_bits.h" +#include "aacps.h" +#if USE_FIXED +#include "aacps_fixed_tablegen.h" +#else +#include "libavutil/internal.h" +#include "aacps_tablegen.h" +#endif /* USE_FIXED */ +#include "aacpsdata.c" + +#define PS_BASELINE 0 ///< Operate in Baseline PS mode + ///< Baseline implies 10 or 20 stereo bands, + ///< mixing mode A, and no ipd/opd + +#define numQMFSlots 32 //numTimeSlots * RATE + +static const int8_t num_env_tab[2][4] = { + { 0, 1, 2, 4, }, + { 1, 2, 3, 4, }, +}; + +static const int8_t nr_iidicc_par_tab[] = { + 10, 20, 34, 10, 20, 34, +}; + +static const int8_t nr_iidopd_par_tab[] = { + 5, 11, 17, 5, 11, 17, +}; + +enum { + huff_iid_df1, + huff_iid_dt1, + huff_iid_df0, + huff_iid_dt0, + huff_icc_df, + huff_icc_dt, + huff_ipd_df, + huff_ipd_dt, + huff_opd_df, + huff_opd_dt, +}; + +static const int huff_iid[] = { + huff_iid_df0, + huff_iid_df1, + huff_iid_dt0, + huff_iid_dt1, +}; + +static VLC vlc_ps[10]; + +#define READ_PAR_DATA(PAR, OFFSET, MASK, ERR_CONDITION) \ +/** \ + * Read Inter-channel Intensity Difference/Inter-Channel Coherence/ \ + * Inter-channel Phase Difference/Overall Phase Difference parameters from the \ + * bitstream. \ + * \ + * @param avctx contains the current codec context \ + * @param gb pointer to the input bitstream \ + * @param ps pointer to the Parametric Stereo context \ + * @param PAR pointer to the parameter to be read \ + * @param e envelope to decode \ + * @param dt 1: time delta-coded, 0: frequency delta-coded \ + */ \ +static int read_ ## PAR ## _data(AVCodecContext *avctx, GetBitContext *gb, PSContext *ps, \ + int8_t (*PAR)[PS_MAX_NR_IIDICC], int table_idx, int e, int dt) \ +{ \ + int b, num = ps->nr_ ## PAR ## _par; \ + VLC_TYPE (*vlc_table)[2] = vlc_ps[table_idx].table; \ + if (dt) { \ + int e_prev = e ? e - 1 : ps->num_env_old - 1; \ + e_prev = FFMAX(e_prev, 0); \ + for (b = 0; b < num; b++) { \ + int val = PAR[e_prev][b] + get_vlc2(gb, vlc_table, 9, 3) - OFFSET; \ + if (MASK) val &= MASK; \ + PAR[e][b] = val; \ + if (ERR_CONDITION) \ + goto err; \ + } \ + } else { \ + int val = 0; \ + for (b = 0; b < num; b++) { \ + val += get_vlc2(gb, vlc_table, 9, 3) - OFFSET; \ + if (MASK) val &= MASK; \ + PAR[e][b] = val; \ + if (ERR_CONDITION) \ + goto err; \ + } \ + } \ + return 0; \ +err: \ + av_log(avctx, AV_LOG_ERROR, "illegal "#PAR"\n"); \ + return AVERROR_INVALIDDATA; \ +} + +READ_PAR_DATA(iid, huff_offset[table_idx], 0, FFABS(ps->iid_par[e][b]) > 7 + 8 * ps->iid_quant) +READ_PAR_DATA(icc, huff_offset[table_idx], 0, ps->icc_par[e][b] > 7U) +READ_PAR_DATA(ipdopd, 0, 0x07, 0) + +static int ps_read_extension_data(GetBitContext *gb, PSContext *ps, int ps_extension_id) +{ + int e; + int count = get_bits_count(gb); + + if (ps_extension_id) + return 0; + + ps->enable_ipdopd = get_bits1(gb); + if (ps->enable_ipdopd) { + for (e = 0; e < ps->num_env; e++) { + int dt = get_bits1(gb); + read_ipdopd_data(NULL, gb, ps, ps->ipd_par, dt ? huff_ipd_dt : huff_ipd_df, e, dt); + dt = get_bits1(gb); + read_ipdopd_data(NULL, gb, ps, ps->opd_par, dt ? huff_opd_dt : huff_opd_df, e, dt); + } + } + skip_bits1(gb); //reserved_ps + return get_bits_count(gb) - count; +} + +static void ipdopd_reset(int8_t *ipd_hist, int8_t *opd_hist) +{ + int i; + for (i = 0; i < PS_MAX_NR_IPDOPD; i++) { + opd_hist[i] = 0; + ipd_hist[i] = 0; + } +} + +int AAC_RENAME(ff_ps_read_data)(AVCodecContext *avctx, GetBitContext *gb_host, PSContext *ps, int bits_left) +{ + int e; + int bit_count_start = get_bits_count(gb_host); + int header; + int bits_consumed; + GetBitContext gbc = *gb_host, *gb = &gbc; + + header = get_bits1(gb); + if (header) { //enable_ps_header + ps->enable_iid = get_bits1(gb); + if (ps->enable_iid) { + int iid_mode = get_bits(gb, 3); + if (iid_mode > 5) { + av_log(avctx, AV_LOG_ERROR, "iid_mode %d is reserved.\n", + iid_mode); + goto err; + } + ps->nr_iid_par = nr_iidicc_par_tab[iid_mode]; + ps->iid_quant = iid_mode > 2; + ps->nr_ipdopd_par = nr_iidopd_par_tab[iid_mode]; + } + ps->enable_icc = get_bits1(gb); + if (ps->enable_icc) { + ps->icc_mode = get_bits(gb, 3); + if (ps->icc_mode > 5) { + av_log(avctx, AV_LOG_ERROR, "icc_mode %d is reserved.\n", + ps->icc_mode); + goto err; + } + ps->nr_icc_par = nr_iidicc_par_tab[ps->icc_mode]; + } + ps->enable_ext = get_bits1(gb); + } + + ps->frame_class = get_bits1(gb); + ps->num_env_old = ps->num_env; + ps->num_env = num_env_tab[ps->frame_class][get_bits(gb, 2)]; + + ps->border_position[0] = -1; + if (ps->frame_class) { + for (e = 1; e <= ps->num_env; e++) { + ps->border_position[e] = get_bits(gb, 5); + if (ps->border_position[e] < ps->border_position[e-1]) { + av_log(avctx, AV_LOG_ERROR, "border_position non monotone.\n"); + goto err; + } + } + } else + for (e = 1; e <= ps->num_env; e++) + ps->border_position[e] = (e * numQMFSlots >> ff_log2_tab[ps->num_env]) - 1; + + if (ps->enable_iid) { + for (e = 0; e < ps->num_env; e++) { + int dt = get_bits1(gb); + if (read_iid_data(avctx, gb, ps, ps->iid_par, huff_iid[2*dt+ps->iid_quant], e, dt)) + goto err; + } + } else + memset(ps->iid_par, 0, sizeof(ps->iid_par)); + + if (ps->enable_icc) + for (e = 0; e < ps->num_env; e++) { + int dt = get_bits1(gb); + if (read_icc_data(avctx, gb, ps, ps->icc_par, dt ? huff_icc_dt : huff_icc_df, e, dt)) + goto err; + } + else + memset(ps->icc_par, 0, sizeof(ps->icc_par)); + + if (ps->enable_ext) { + int cnt = get_bits(gb, 4); + if (cnt == 15) { + cnt += get_bits(gb, 8); + } + cnt *= 8; + while (cnt > 7) { + int ps_extension_id = get_bits(gb, 2); + cnt -= 2 + ps_read_extension_data(gb, ps, ps_extension_id); + } + if (cnt < 0) { + av_log(avctx, AV_LOG_ERROR, "ps extension overflow %d\n", cnt); + goto err; + } + skip_bits(gb, cnt); + } + + ps->enable_ipdopd &= !PS_BASELINE; + + //Fix up envelopes + if (!ps->num_env || ps->border_position[ps->num_env] < numQMFSlots - 1) { + //Create a fake envelope + int source = ps->num_env ? ps->num_env - 1 : ps->num_env_old - 1; + int b; + if (source >= 0 && source != ps->num_env) { + if (ps->enable_iid) { + memcpy(ps->iid_par+ps->num_env, ps->iid_par+source, sizeof(ps->iid_par[0])); + } + if (ps->enable_icc) { + memcpy(ps->icc_par+ps->num_env, ps->icc_par+source, sizeof(ps->icc_par[0])); + } + if (ps->enable_ipdopd) { + memcpy(ps->ipd_par+ps->num_env, ps->ipd_par+source, sizeof(ps->ipd_par[0])); + memcpy(ps->opd_par+ps->num_env, ps->opd_par+source, sizeof(ps->opd_par[0])); + } + } + if (ps->enable_iid){ + for (b = 0; b < ps->nr_iid_par; b++) { + if (FFABS(ps->iid_par[ps->num_env][b]) > 7 + 8 * ps->iid_quant) { + av_log(avctx, AV_LOG_ERROR, "iid_par invalid\n"); + goto err; + } + } + } + if (ps->enable_icc){ + for (b = 0; b < ps->nr_iid_par; b++) { + if (ps->icc_par[ps->num_env][b] > 7U) { + av_log(avctx, AV_LOG_ERROR, "icc_par invalid\n"); + goto err; + } + } + } + ps->num_env++; + ps->border_position[ps->num_env] = numQMFSlots - 1; + } + + + ps->is34bands_old = ps->is34bands; + if (!PS_BASELINE && (ps->enable_iid || ps->enable_icc)) + ps->is34bands = (ps->enable_iid && ps->nr_iid_par == 34) || + (ps->enable_icc && ps->nr_icc_par == 34); + + //Baseline + if (!ps->enable_ipdopd) { + memset(ps->ipd_par, 0, sizeof(ps->ipd_par)); + memset(ps->opd_par, 0, sizeof(ps->opd_par)); + } + + if (header) + ps->start = 1; + + bits_consumed = get_bits_count(gb) - bit_count_start; + if (bits_consumed <= bits_left) { + skip_bits_long(gb_host, bits_consumed); + return bits_consumed; + } + av_log(avctx, AV_LOG_ERROR, "Expected to read %d PS bits actually read %d.\n", bits_left, bits_consumed); +err: + ps->start = 0; + skip_bits_long(gb_host, bits_left); + memset(ps->iid_par, 0, sizeof(ps->iid_par)); + memset(ps->icc_par, 0, sizeof(ps->icc_par)); + memset(ps->ipd_par, 0, sizeof(ps->ipd_par)); + memset(ps->opd_par, 0, sizeof(ps->opd_par)); + return bits_left; +} + +/** Split one subband into 2 subsubbands with a symmetric real filter. + * The filter must have its non-center even coefficients equal to zero. */ +static void hybrid2_re(INTFLOAT (*in)[2], INTFLOAT (*out)[32][2], const INTFLOAT filter[8], int len, int reverse) +{ + int i, j; + for (i = 0; i < len; i++, in++) { + INT64FLOAT re_in = AAC_MUL31(filter[6], in[6][0]); //real inphase + INT64FLOAT re_op = 0.0f; //real out of phase + INT64FLOAT im_in = AAC_MUL31(filter[6], in[6][1]); //imag inphase + INT64FLOAT im_op = 0.0f; //imag out of phase + for (j = 0; j < 6; j += 2) { + re_op += (INT64FLOAT)filter[j+1] * (in[j+1][0] + in[12-j-1][0]); + im_op += (INT64FLOAT)filter[j+1] * (in[j+1][1] + in[12-j-1][1]); + } + +#if USE_FIXED + re_op = (re_op + 0x40000000) >> 31; + im_op = (im_op + 0x40000000) >> 31; +#endif /* USE_FIXED */ + + out[ reverse][i][0] = (INTFLOAT)(re_in + re_op); + out[ reverse][i][1] = (INTFLOAT)(im_in + im_op); + out[!reverse][i][0] = (INTFLOAT)(re_in - re_op); + out[!reverse][i][1] = (INTFLOAT)(im_in - im_op); + } +} + +/** Split one subband into 6 subsubbands with a complex filter */ +static void hybrid6_cx(PSDSPContext *dsp, INTFLOAT (*in)[2], INTFLOAT (*out)[32][2], + TABLE_CONST INTFLOAT (*filter)[8][2], int len) +{ + int i; + int N = 8; + LOCAL_ALIGNED_16(INTFLOAT, temp, [8], [2]); + + for (i = 0; i < len; i++, in++) { + dsp->hybrid_analysis(temp, in, (const INTFLOAT (*)[8][2]) filter, 1, N); + out[0][i][0] = temp[6][0]; + out[0][i][1] = temp[6][1]; + out[1][i][0] = temp[7][0]; + out[1][i][1] = temp[7][1]; + out[2][i][0] = temp[0][0]; + out[2][i][1] = temp[0][1]; + out[3][i][0] = temp[1][0]; + out[3][i][1] = temp[1][1]; + out[4][i][0] = temp[2][0] + temp[5][0]; + out[4][i][1] = temp[2][1] + temp[5][1]; + out[5][i][0] = temp[3][0] + temp[4][0]; + out[5][i][1] = temp[3][1] + temp[4][1]; + } +} + +static void hybrid4_8_12_cx(PSDSPContext *dsp, + INTFLOAT (*in)[2], INTFLOAT (*out)[32][2], + TABLE_CONST INTFLOAT (*filter)[8][2], int N, int len) +{ + int i; + + for (i = 0; i < len; i++, in++) { + dsp->hybrid_analysis(out[0] + i, in, (const INTFLOAT (*)[8][2]) filter, 32, N); + } +} + +static void hybrid_analysis(PSDSPContext *dsp, INTFLOAT out[91][32][2], + INTFLOAT in[5][44][2], INTFLOAT L[2][38][64], + int is34, int len) +{ + int i, j; + for (i = 0; i < 5; i++) { + for (j = 0; j < 38; j++) { + in[i][j+6][0] = L[0][j][i]; + in[i][j+6][1] = L[1][j][i]; + } + } + if (is34) { + hybrid4_8_12_cx(dsp, in[0], out, f34_0_12, 12, len); + hybrid4_8_12_cx(dsp, in[1], out+12, f34_1_8, 8, len); + hybrid4_8_12_cx(dsp, in[2], out+20, f34_2_4, 4, len); + hybrid4_8_12_cx(dsp, in[3], out+24, f34_2_4, 4, len); + hybrid4_8_12_cx(dsp, in[4], out+28, f34_2_4, 4, len); + dsp->hybrid_analysis_ileave(out + 27, L, 5, len); + } else { + hybrid6_cx(dsp, in[0], out, f20_0_8, len); + hybrid2_re(in[1], out+6, g1_Q2, len, 1); + hybrid2_re(in[2], out+8, g1_Q2, len, 0); + dsp->hybrid_analysis_ileave(out + 7, L, 3, len); + } + //update in_buf + for (i = 0; i < 5; i++) { + memcpy(in[i], in[i]+32, 6 * sizeof(in[i][0])); + } +} + +static void hybrid_synthesis(PSDSPContext *dsp, INTFLOAT out[2][38][64], + INTFLOAT in[91][32][2], int is34, int len) +{ + int i, n; + if (is34) { + for (n = 0; n < len; n++) { + memset(out[0][n], 0, 5*sizeof(out[0][n][0])); + memset(out[1][n], 0, 5*sizeof(out[1][n][0])); + for (i = 0; i < 12; i++) { + out[0][n][0] += in[ i][n][0]; + out[1][n][0] += in[ i][n][1]; + } + for (i = 0; i < 8; i++) { + out[0][n][1] += in[12+i][n][0]; + out[1][n][1] += in[12+i][n][1]; + } + for (i = 0; i < 4; i++) { + out[0][n][2] += in[20+i][n][0]; + out[1][n][2] += in[20+i][n][1]; + out[0][n][3] += in[24+i][n][0]; + out[1][n][3] += in[24+i][n][1]; + out[0][n][4] += in[28+i][n][0]; + out[1][n][4] += in[28+i][n][1]; + } + } + dsp->hybrid_synthesis_deint(out, in + 27, 5, len); + } else { + for (n = 0; n < len; n++) { + out[0][n][0] = in[0][n][0] + in[1][n][0] + in[2][n][0] + + in[3][n][0] + in[4][n][0] + in[5][n][0]; + out[1][n][0] = in[0][n][1] + in[1][n][1] + in[2][n][1] + + in[3][n][1] + in[4][n][1] + in[5][n][1]; + out[0][n][1] = in[6][n][0] + in[7][n][0]; + out[1][n][1] = in[6][n][1] + in[7][n][1]; + out[0][n][2] = in[8][n][0] + in[9][n][0]; + out[1][n][2] = in[8][n][1] + in[9][n][1]; + } + dsp->hybrid_synthesis_deint(out, in + 7, 3, len); + } +} + +/// All-pass filter decay slope +#define DECAY_SLOPE Q30(0.05f) +/// Number of frequency bands that can be addressed by the parameter index, b(k) +static const int NR_PAR_BANDS[] = { 20, 34 }; +static const int NR_IPDOPD_BANDS[] = { 11, 17 }; +/// Number of frequency bands that can be addressed by the sub subband index, k +static const int NR_BANDS[] = { 71, 91 }; +/// Start frequency band for the all-pass filter decay slope +static const int DECAY_CUTOFF[] = { 10, 32 }; +/// Number of all-pass filer bands +static const int NR_ALLPASS_BANDS[] = { 30, 50 }; +/// First stereo band using the short one sample delay +static const int SHORT_DELAY_BAND[] = { 42, 62 }; + +/** Table 8.46 */ +static void map_idx_10_to_20(int8_t *par_mapped, const int8_t *par, int full) +{ + int b; + if (full) + b = 9; + else { + b = 4; + par_mapped[10] = 0; + } + for (; b >= 0; b--) { + par_mapped[2*b+1] = par_mapped[2*b] = par[b]; + } +} + +static void map_idx_34_to_20(int8_t *par_mapped, const int8_t *par, int full) +{ + par_mapped[ 0] = (2*par[ 0] + par[ 1]) / 3; + par_mapped[ 1] = ( par[ 1] + 2*par[ 2]) / 3; + par_mapped[ 2] = (2*par[ 3] + par[ 4]) / 3; + par_mapped[ 3] = ( par[ 4] + 2*par[ 5]) / 3; + par_mapped[ 4] = ( par[ 6] + par[ 7]) / 2; + par_mapped[ 5] = ( par[ 8] + par[ 9]) / 2; + par_mapped[ 6] = par[10]; + par_mapped[ 7] = par[11]; + par_mapped[ 8] = ( par[12] + par[13]) / 2; + par_mapped[ 9] = ( par[14] + par[15]) / 2; + par_mapped[10] = par[16]; + if (full) { + par_mapped[11] = par[17]; + par_mapped[12] = par[18]; + par_mapped[13] = par[19]; + par_mapped[14] = ( par[20] + par[21]) / 2; + par_mapped[15] = ( par[22] + par[23]) / 2; + par_mapped[16] = ( par[24] + par[25]) / 2; + par_mapped[17] = ( par[26] + par[27]) / 2; + par_mapped[18] = ( par[28] + par[29] + par[30] + par[31]) / 4; + par_mapped[19] = ( par[32] + par[33]) / 2; + } +} + +static void map_val_34_to_20(INTFLOAT par[PS_MAX_NR_IIDICC]) +{ +#if USE_FIXED + par[ 0] = (int)(((int64_t)(par[ 0] + (unsigned)(par[ 1]>>1)) * 1431655765 + \ + 0x40000000) >> 31); + par[ 1] = (int)(((int64_t)((par[ 1]>>1) + (unsigned)par[ 2]) * 1431655765 + \ + 0x40000000) >> 31); + par[ 2] = (int)(((int64_t)(par[ 3] + (unsigned)(par[ 4]>>1)) * 1431655765 + \ + 0x40000000) >> 31); + par[ 3] = (int)(((int64_t)((par[ 4]>>1) + (unsigned)par[ 5]) * 1431655765 + \ + 0x40000000) >> 31); +#else + par[ 0] = (2*par[ 0] + par[ 1]) * 0.33333333f; + par[ 1] = ( par[ 1] + 2*par[ 2]) * 0.33333333f; + par[ 2] = (2*par[ 3] + par[ 4]) * 0.33333333f; + par[ 3] = ( par[ 4] + 2*par[ 5]) * 0.33333333f; +#endif /* USE_FIXED */ + par[ 4] = AAC_HALF_SUM(par[ 6], par[ 7]); + par[ 5] = AAC_HALF_SUM(par[ 8], par[ 9]); + par[ 6] = par[10]; + par[ 7] = par[11]; + par[ 8] = AAC_HALF_SUM(par[12], par[13]); + par[ 9] = AAC_HALF_SUM(par[14], par[15]); + par[10] = par[16]; + par[11] = par[17]; + par[12] = par[18]; + par[13] = par[19]; + par[14] = AAC_HALF_SUM(par[20], par[21]); + par[15] = AAC_HALF_SUM(par[22], par[23]); + par[16] = AAC_HALF_SUM(par[24], par[25]); + par[17] = AAC_HALF_SUM(par[26], par[27]); +#if USE_FIXED + par[18] = (((par[28]+2)>>2) + ((par[29]+2)>>2) + ((par[30]+2)>>2) + ((par[31]+2)>>2)); +#else + par[18] = ( par[28] + par[29] + par[30] + par[31]) * 0.25f; +#endif /* USE_FIXED */ + par[19] = AAC_HALF_SUM(par[32], par[33]); +} + +static void map_idx_10_to_34(int8_t *par_mapped, const int8_t *par, int full) +{ + if (full) { + par_mapped[33] = par[9]; + par_mapped[32] = par[9]; + par_mapped[31] = par[9]; + par_mapped[30] = par[9]; + par_mapped[29] = par[9]; + par_mapped[28] = par[9]; + par_mapped[27] = par[8]; + par_mapped[26] = par[8]; + par_mapped[25] = par[8]; + par_mapped[24] = par[8]; + par_mapped[23] = par[7]; + par_mapped[22] = par[7]; + par_mapped[21] = par[7]; + par_mapped[20] = par[7]; + par_mapped[19] = par[6]; + par_mapped[18] = par[6]; + par_mapped[17] = par[5]; + par_mapped[16] = par[5]; + } else { + par_mapped[16] = 0; + } + par_mapped[15] = par[4]; + par_mapped[14] = par[4]; + par_mapped[13] = par[4]; + par_mapped[12] = par[4]; + par_mapped[11] = par[3]; + par_mapped[10] = par[3]; + par_mapped[ 9] = par[2]; + par_mapped[ 8] = par[2]; + par_mapped[ 7] = par[2]; + par_mapped[ 6] = par[2]; + par_mapped[ 5] = par[1]; + par_mapped[ 4] = par[1]; + par_mapped[ 3] = par[1]; + par_mapped[ 2] = par[0]; + par_mapped[ 1] = par[0]; + par_mapped[ 0] = par[0]; +} + +static void map_idx_20_to_34(int8_t *par_mapped, const int8_t *par, int full) +{ + if (full) { + par_mapped[33] = par[19]; + par_mapped[32] = par[19]; + par_mapped[31] = par[18]; + par_mapped[30] = par[18]; + par_mapped[29] = par[18]; + par_mapped[28] = par[18]; + par_mapped[27] = par[17]; + par_mapped[26] = par[17]; + par_mapped[25] = par[16]; + par_mapped[24] = par[16]; + par_mapped[23] = par[15]; + par_mapped[22] = par[15]; + par_mapped[21] = par[14]; + par_mapped[20] = par[14]; + par_mapped[19] = par[13]; + par_mapped[18] = par[12]; + par_mapped[17] = par[11]; + } + par_mapped[16] = par[10]; + par_mapped[15] = par[ 9]; + par_mapped[14] = par[ 9]; + par_mapped[13] = par[ 8]; + par_mapped[12] = par[ 8]; + par_mapped[11] = par[ 7]; + par_mapped[10] = par[ 6]; + par_mapped[ 9] = par[ 5]; + par_mapped[ 8] = par[ 5]; + par_mapped[ 7] = par[ 4]; + par_mapped[ 6] = par[ 4]; + par_mapped[ 5] = par[ 3]; + par_mapped[ 4] = (par[ 2] + par[ 3]) / 2; + par_mapped[ 3] = par[ 2]; + par_mapped[ 2] = par[ 1]; + par_mapped[ 1] = (par[ 0] + par[ 1]) / 2; + par_mapped[ 0] = par[ 0]; +} + +static void map_val_20_to_34(INTFLOAT par[PS_MAX_NR_IIDICC]) +{ + par[33] = par[19]; + par[32] = par[19]; + par[31] = par[18]; + par[30] = par[18]; + par[29] = par[18]; + par[28] = par[18]; + par[27] = par[17]; + par[26] = par[17]; + par[25] = par[16]; + par[24] = par[16]; + par[23] = par[15]; + par[22] = par[15]; + par[21] = par[14]; + par[20] = par[14]; + par[19] = par[13]; + par[18] = par[12]; + par[17] = par[11]; + par[16] = par[10]; + par[15] = par[ 9]; + par[14] = par[ 9]; + par[13] = par[ 8]; + par[12] = par[ 8]; + par[11] = par[ 7]; + par[10] = par[ 6]; + par[ 9] = par[ 5]; + par[ 8] = par[ 5]; + par[ 7] = par[ 4]; + par[ 6] = par[ 4]; + par[ 5] = par[ 3]; + par[ 4] = AAC_HALF_SUM(par[ 2], par[ 3]); + par[ 3] = par[ 2]; + par[ 2] = par[ 1]; + par[ 1] = AAC_HALF_SUM(par[ 0], par[ 1]); +} + +static void decorrelation(PSContext *ps, INTFLOAT (*out)[32][2], const INTFLOAT (*s)[32][2], int is34) +{ + LOCAL_ALIGNED_16(INTFLOAT, power, [34], [PS_QMF_TIME_SLOTS]); + LOCAL_ALIGNED_16(INTFLOAT, transient_gain, [34], [PS_QMF_TIME_SLOTS]); + INTFLOAT *peak_decay_nrg = ps->peak_decay_nrg; + INTFLOAT *power_smooth = ps->power_smooth; + INTFLOAT *peak_decay_diff_smooth = ps->peak_decay_diff_smooth; + INTFLOAT (*delay)[PS_QMF_TIME_SLOTS + PS_MAX_DELAY][2] = ps->delay; + INTFLOAT (*ap_delay)[PS_AP_LINKS][PS_QMF_TIME_SLOTS + PS_MAX_AP_DELAY][2] = ps->ap_delay; +#if !USE_FIXED + const float transient_impact = 1.5f; + const float a_smooth = 0.25f; ///< Smoothing coefficient +#endif /* USE_FIXED */ + const int8_t *k_to_i = is34 ? k_to_i_34 : k_to_i_20; + int i, k, m, n; + int n0 = 0, nL = 32; + const INTFLOAT peak_decay_factor = Q31(0.76592833836465f); + + memset(power, 0, 34 * sizeof(*power)); + + if (is34 != ps->is34bands_old) { + memset(ps->peak_decay_nrg, 0, sizeof(ps->peak_decay_nrg)); + memset(ps->power_smooth, 0, sizeof(ps->power_smooth)); + memset(ps->peak_decay_diff_smooth, 0, sizeof(ps->peak_decay_diff_smooth)); + memset(ps->delay, 0, sizeof(ps->delay)); + memset(ps->ap_delay, 0, sizeof(ps->ap_delay)); + } + + for (k = 0; k < NR_BANDS[is34]; k++) { + int i = k_to_i[k]; + ps->dsp.add_squares(power[i], s[k], nL - n0); + } + + //Transient detection +#if USE_FIXED + for (i = 0; i < NR_PAR_BANDS[is34]; i++) { + for (n = n0; n < nL; n++) { + int decayed_peak; + decayed_peak = (int)(((int64_t)peak_decay_factor * \ + peak_decay_nrg[i] + 0x40000000) >> 31); + peak_decay_nrg[i] = FFMAX(decayed_peak, power[i][n]); + power_smooth[i] += (power[i][n] + 2LL - power_smooth[i]) >> 2; + peak_decay_diff_smooth[i] += (peak_decay_nrg[i] + 2LL - power[i][n] - \ + peak_decay_diff_smooth[i]) >> 2; + + if (peak_decay_diff_smooth[i]) { + transient_gain[i][n] = FFMIN(power_smooth[i]*43691LL / peak_decay_diff_smooth[i], 1<<16); + } else + transient_gain[i][n] = 1 << 16; + } + } +#else + for (i = 0; i < NR_PAR_BANDS[is34]; i++) { + for (n = n0; n < nL; n++) { + float decayed_peak = peak_decay_factor * peak_decay_nrg[i]; + float denom; + peak_decay_nrg[i] = FFMAX(decayed_peak, power[i][n]); + power_smooth[i] += a_smooth * (power[i][n] - power_smooth[i]); + peak_decay_diff_smooth[i] += a_smooth * (peak_decay_nrg[i] - power[i][n] - peak_decay_diff_smooth[i]); + denom = transient_impact * peak_decay_diff_smooth[i]; + transient_gain[i][n] = (denom > power_smooth[i]) ? + power_smooth[i] / denom : 1.0f; + } + } + +#endif /* USE_FIXED */ + //Decorrelation and transient reduction + // PS_AP_LINKS - 1 + // ----- + // | | Q_fract_allpass[k][m]*z^-link_delay[m] - a[m]*g_decay_slope[k] + //H[k][z] = z^-2 * phi_fract[k] * | | ---------------------------------------------------------------- + // | | 1 - a[m]*g_decay_slope[k]*Q_fract_allpass[k][m]*z^-link_delay[m] + // m = 0 + //d[k][z] (out) = transient_gain_mapped[k][z] * H[k][z] * s[k][z] + for (k = 0; k < NR_ALLPASS_BANDS[is34]; k++) { + int b = k_to_i[k]; +#if USE_FIXED + int g_decay_slope; + + if (k - DECAY_CUTOFF[is34] <= 0) { + g_decay_slope = 1 << 30; + } + else if (k - DECAY_CUTOFF[is34] >= 20) { + g_decay_slope = 0; + } + else { + g_decay_slope = (1 << 30) - DECAY_SLOPE * (k - DECAY_CUTOFF[is34]); + } +#else + float g_decay_slope = 1.f - DECAY_SLOPE * (k - DECAY_CUTOFF[is34]); + g_decay_slope = av_clipf(g_decay_slope, 0.f, 1.f); +#endif /* USE_FIXED */ + memcpy(delay[k], delay[k]+nL, PS_MAX_DELAY*sizeof(delay[k][0])); + memcpy(delay[k]+PS_MAX_DELAY, s[k], numQMFSlots*sizeof(delay[k][0])); + for (m = 0; m < PS_AP_LINKS; m++) { + memcpy(ap_delay[k][m], ap_delay[k][m]+numQMFSlots, 5*sizeof(ap_delay[k][m][0])); + } + ps->dsp.decorrelate(out[k], delay[k] + PS_MAX_DELAY - 2, ap_delay[k], + phi_fract[is34][k], + (const INTFLOAT (*)[2]) Q_fract_allpass[is34][k], + transient_gain[b], g_decay_slope, nL - n0); + } + for (; k < SHORT_DELAY_BAND[is34]; k++) { + int i = k_to_i[k]; + memcpy(delay[k], delay[k]+nL, PS_MAX_DELAY*sizeof(delay[k][0])); + memcpy(delay[k]+PS_MAX_DELAY, s[k], numQMFSlots*sizeof(delay[k][0])); + //H = delay 14 + ps->dsp.mul_pair_single(out[k], delay[k] + PS_MAX_DELAY - 14, + transient_gain[i], nL - n0); + } + for (; k < NR_BANDS[is34]; k++) { + int i = k_to_i[k]; + memcpy(delay[k], delay[k]+nL, PS_MAX_DELAY*sizeof(delay[k][0])); + memcpy(delay[k]+PS_MAX_DELAY, s[k], numQMFSlots*sizeof(delay[k][0])); + //H = delay 1 + ps->dsp.mul_pair_single(out[k], delay[k] + PS_MAX_DELAY - 1, + transient_gain[i], nL - n0); + } +} + +static void remap34(int8_t (**p_par_mapped)[PS_MAX_NR_IIDICC], + int8_t (*par)[PS_MAX_NR_IIDICC], + int num_par, int num_env, int full) +{ + int8_t (*par_mapped)[PS_MAX_NR_IIDICC] = *p_par_mapped; + int e; + if (num_par == 20 || num_par == 11) { + for (e = 0; e < num_env; e++) { + map_idx_20_to_34(par_mapped[e], par[e], full); + } + } else if (num_par == 10 || num_par == 5) { + for (e = 0; e < num_env; e++) { + map_idx_10_to_34(par_mapped[e], par[e], full); + } + } else { + *p_par_mapped = par; + } +} + +static void remap20(int8_t (**p_par_mapped)[PS_MAX_NR_IIDICC], + int8_t (*par)[PS_MAX_NR_IIDICC], + int num_par, int num_env, int full) +{ + int8_t (*par_mapped)[PS_MAX_NR_IIDICC] = *p_par_mapped; + int e; + if (num_par == 34 || num_par == 17) { + for (e = 0; e < num_env; e++) { + map_idx_34_to_20(par_mapped[e], par[e], full); + } + } else if (num_par == 10 || num_par == 5) { + for (e = 0; e < num_env; e++) { + map_idx_10_to_20(par_mapped[e], par[e], full); + } + } else { + *p_par_mapped = par; + } +} + +static void stereo_processing(PSContext *ps, INTFLOAT (*l)[32][2], INTFLOAT (*r)[32][2], int is34) +{ + int e, b, k; + + INTFLOAT (*H11)[PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC] = ps->H11; + INTFLOAT (*H12)[PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC] = ps->H12; + INTFLOAT (*H21)[PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC] = ps->H21; + INTFLOAT (*H22)[PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC] = ps->H22; + int8_t *opd_hist = ps->opd_hist; + int8_t *ipd_hist = ps->ipd_hist; + int8_t iid_mapped_buf[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC]; + int8_t icc_mapped_buf[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC]; + int8_t ipd_mapped_buf[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC]; + int8_t opd_mapped_buf[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC]; + int8_t (*iid_mapped)[PS_MAX_NR_IIDICC] = iid_mapped_buf; + int8_t (*icc_mapped)[PS_MAX_NR_IIDICC] = icc_mapped_buf; + int8_t (*ipd_mapped)[PS_MAX_NR_IIDICC] = ipd_mapped_buf; + int8_t (*opd_mapped)[PS_MAX_NR_IIDICC] = opd_mapped_buf; + const int8_t *k_to_i = is34 ? k_to_i_34 : k_to_i_20; + TABLE_CONST INTFLOAT (*H_LUT)[8][4] = (PS_BASELINE || ps->icc_mode < 3) ? HA : HB; + + //Remapping + if (ps->num_env_old) { + memcpy(H11[0][0], H11[0][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H11[0][0][0])); + memcpy(H11[1][0], H11[1][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H11[1][0][0])); + memcpy(H12[0][0], H12[0][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H12[0][0][0])); + memcpy(H12[1][0], H12[1][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H12[1][0][0])); + memcpy(H21[0][0], H21[0][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H21[0][0][0])); + memcpy(H21[1][0], H21[1][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H21[1][0][0])); + memcpy(H22[0][0], H22[0][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H22[0][0][0])); + memcpy(H22[1][0], H22[1][ps->num_env_old], PS_MAX_NR_IIDICC*sizeof(H22[1][0][0])); + } + + if (is34) { + remap34(&iid_mapped, ps->iid_par, ps->nr_iid_par, ps->num_env, 1); + remap34(&icc_mapped, ps->icc_par, ps->nr_icc_par, ps->num_env, 1); + if (ps->enable_ipdopd) { + remap34(&ipd_mapped, ps->ipd_par, ps->nr_ipdopd_par, ps->num_env, 0); + remap34(&opd_mapped, ps->opd_par, ps->nr_ipdopd_par, ps->num_env, 0); + } + if (!ps->is34bands_old) { + map_val_20_to_34(H11[0][0]); + map_val_20_to_34(H11[1][0]); + map_val_20_to_34(H12[0][0]); + map_val_20_to_34(H12[1][0]); + map_val_20_to_34(H21[0][0]); + map_val_20_to_34(H21[1][0]); + map_val_20_to_34(H22[0][0]); + map_val_20_to_34(H22[1][0]); + ipdopd_reset(ipd_hist, opd_hist); + } + } else { + remap20(&iid_mapped, ps->iid_par, ps->nr_iid_par, ps->num_env, 1); + remap20(&icc_mapped, ps->icc_par, ps->nr_icc_par, ps->num_env, 1); + if (ps->enable_ipdopd) { + remap20(&ipd_mapped, ps->ipd_par, ps->nr_ipdopd_par, ps->num_env, 0); + remap20(&opd_mapped, ps->opd_par, ps->nr_ipdopd_par, ps->num_env, 0); + } + if (ps->is34bands_old) { + map_val_34_to_20(H11[0][0]); + map_val_34_to_20(H11[1][0]); + map_val_34_to_20(H12[0][0]); + map_val_34_to_20(H12[1][0]); + map_val_34_to_20(H21[0][0]); + map_val_34_to_20(H21[1][0]); + map_val_34_to_20(H22[0][0]); + map_val_34_to_20(H22[1][0]); + ipdopd_reset(ipd_hist, opd_hist); + } + } + + //Mixing + for (e = 0; e < ps->num_env; e++) { + for (b = 0; b < NR_PAR_BANDS[is34]; b++) { + INTFLOAT h11, h12, h21, h22; + h11 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][0]; + h12 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][1]; + h21 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][2]; + h22 = H_LUT[iid_mapped[e][b] + 7 + 23 * ps->iid_quant][icc_mapped[e][b]][3]; + + if (!PS_BASELINE && ps->enable_ipdopd && b < NR_IPDOPD_BANDS[is34]) { + //The spec say says to only run this smoother when enable_ipdopd + //is set but the reference decoder appears to run it constantly + INTFLOAT h11i, h12i, h21i, h22i; + INTFLOAT ipd_adj_re, ipd_adj_im; + int opd_idx = opd_hist[b] * 8 + opd_mapped[e][b]; + int ipd_idx = ipd_hist[b] * 8 + ipd_mapped[e][b]; + INTFLOAT opd_re = pd_re_smooth[opd_idx]; + INTFLOAT opd_im = pd_im_smooth[opd_idx]; + INTFLOAT ipd_re = pd_re_smooth[ipd_idx]; + INTFLOAT ipd_im = pd_im_smooth[ipd_idx]; + opd_hist[b] = opd_idx & 0x3F; + ipd_hist[b] = ipd_idx & 0x3F; + + ipd_adj_re = AAC_MADD30(opd_re, ipd_re, opd_im, ipd_im); + ipd_adj_im = AAC_MSUB30(opd_im, ipd_re, opd_re, ipd_im); + h11i = AAC_MUL30(h11, opd_im); + h11 = AAC_MUL30(h11, opd_re); + h12i = AAC_MUL30(h12, ipd_adj_im); + h12 = AAC_MUL30(h12, ipd_adj_re); + h21i = AAC_MUL30(h21, opd_im); + h21 = AAC_MUL30(h21, opd_re); + h22i = AAC_MUL30(h22, ipd_adj_im); + h22 = AAC_MUL30(h22, ipd_adj_re); + H11[1][e+1][b] = h11i; + H12[1][e+1][b] = h12i; + H21[1][e+1][b] = h21i; + H22[1][e+1][b] = h22i; + } + H11[0][e+1][b] = h11; + H12[0][e+1][b] = h12; + H21[0][e+1][b] = h21; + H22[0][e+1][b] = h22; + } + for (k = 0; k < NR_BANDS[is34]; k++) { + LOCAL_ALIGNED_16(INTFLOAT, h, [2], [4]); + LOCAL_ALIGNED_16(INTFLOAT, h_step, [2], [4]); + int start = ps->border_position[e]; + int stop = ps->border_position[e+1]; + INTFLOAT width = Q30(1.f) / ((stop - start) ? (stop - start) : 1); +#if USE_FIXED + width = FFMIN(2U*width, INT_MAX); +#endif + b = k_to_i[k]; + h[0][0] = H11[0][e][b]; + h[0][1] = H12[0][e][b]; + h[0][2] = H21[0][e][b]; + h[0][3] = H22[0][e][b]; + if (!PS_BASELINE && ps->enable_ipdopd) { + //Is this necessary? ps_04_new seems unchanged + if ((is34 && k <= 13 && k >= 9) || (!is34 && k <= 1)) { + h[1][0] = -H11[1][e][b]; + h[1][1] = -H12[1][e][b]; + h[1][2] = -H21[1][e][b]; + h[1][3] = -H22[1][e][b]; + } else { + h[1][0] = H11[1][e][b]; + h[1][1] = H12[1][e][b]; + h[1][2] = H21[1][e][b]; + h[1][3] = H22[1][e][b]; + } + } + //Interpolation + h_step[0][0] = AAC_MSUB31_V3(H11[0][e+1][b], h[0][0], width); + h_step[0][1] = AAC_MSUB31_V3(H12[0][e+1][b], h[0][1], width); + h_step[0][2] = AAC_MSUB31_V3(H21[0][e+1][b], h[0][2], width); + h_step[0][3] = AAC_MSUB31_V3(H22[0][e+1][b], h[0][3], width); + if (!PS_BASELINE && ps->enable_ipdopd) { + h_step[1][0] = AAC_MSUB31_V3(H11[1][e+1][b], h[1][0], width); + h_step[1][1] = AAC_MSUB31_V3(H12[1][e+1][b], h[1][1], width); + h_step[1][2] = AAC_MSUB31_V3(H21[1][e+1][b], h[1][2], width); + h_step[1][3] = AAC_MSUB31_V3(H22[1][e+1][b], h[1][3], width); + } + if (stop - start) + ps->dsp.stereo_interpolate[!PS_BASELINE && ps->enable_ipdopd]( + l[k] + 1 + start, r[k] + 1 + start, + h, h_step, stop - start); + } + } +} + +int AAC_RENAME(ff_ps_apply)(AVCodecContext *avctx, PSContext *ps, INTFLOAT L[2][38][64], INTFLOAT R[2][38][64], int top) +{ + INTFLOAT (*Lbuf)[32][2] = ps->Lbuf; + INTFLOAT (*Rbuf)[32][2] = ps->Rbuf; + const int len = 32; + int is34 = ps->is34bands; + + top += NR_BANDS[is34] - 64; + memset(ps->delay+top, 0, (NR_BANDS[is34] - top)*sizeof(ps->delay[0])); + if (top < NR_ALLPASS_BANDS[is34]) + memset(ps->ap_delay + top, 0, (NR_ALLPASS_BANDS[is34] - top)*sizeof(ps->ap_delay[0])); + + hybrid_analysis(&ps->dsp, Lbuf, ps->in_buf, L, is34, len); + decorrelation(ps, Rbuf, (const INTFLOAT (*)[32][2]) Lbuf, is34); + stereo_processing(ps, Lbuf, Rbuf, is34); + hybrid_synthesis(&ps->dsp, L, Lbuf, is34, len); + hybrid_synthesis(&ps->dsp, R, Rbuf, is34, len); + + return 0; +} + +#define PS_INIT_VLC_STATIC(num, size) \ + INIT_VLC_STATIC(&vlc_ps[num], 9, ps_tmp[num].table_size / ps_tmp[num].elem_size, \ + ps_tmp[num].ps_bits, 1, 1, \ + ps_tmp[num].ps_codes, ps_tmp[num].elem_size, ps_tmp[num].elem_size, \ + size); + +#define PS_VLC_ROW(name) \ + { name ## _codes, name ## _bits, sizeof(name ## _codes), sizeof(name ## _codes[0]) } + +av_cold void AAC_RENAME(ff_ps_init)(void) { + // Syntax initialization + static const struct { + const void *ps_codes, *ps_bits; + const unsigned int table_size, elem_size; + } ps_tmp[] = { + PS_VLC_ROW(huff_iid_df1), + PS_VLC_ROW(huff_iid_dt1), + PS_VLC_ROW(huff_iid_df0), + PS_VLC_ROW(huff_iid_dt0), + PS_VLC_ROW(huff_icc_df), + PS_VLC_ROW(huff_icc_dt), + PS_VLC_ROW(huff_ipd_df), + PS_VLC_ROW(huff_ipd_dt), + PS_VLC_ROW(huff_opd_df), + PS_VLC_ROW(huff_opd_dt), + }; + + PS_INIT_VLC_STATIC(0, 1544); + PS_INIT_VLC_STATIC(1, 832); + PS_INIT_VLC_STATIC(2, 1024); + PS_INIT_VLC_STATIC(3, 1036); + PS_INIT_VLC_STATIC(4, 544); + PS_INIT_VLC_STATIC(5, 544); + PS_INIT_VLC_STATIC(6, 512); + PS_INIT_VLC_STATIC(7, 512); + PS_INIT_VLC_STATIC(8, 512); + PS_INIT_VLC_STATIC(9, 512); + + ps_tableinit(); +} + +av_cold void AAC_RENAME(ff_ps_ctx_init)(PSContext *ps) +{ + AAC_RENAME(ff_psdsp_init)(&ps->dsp); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps.h new file mode 100644 index 0000000000..61edce3549 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps.h @@ -0,0 +1,86 @@ +/* + * MPEG-4 Parametric Stereo definitions and declarations + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AACPS_H +#define AVCODEC_AACPS_H + +#include + +#include "aacpsdsp.h" +#include "avcodec.h" +#include "get_bits.h" + +#define PS_MAX_NUM_ENV 5 +#define PS_MAX_NR_IIDICC 34 +#define PS_MAX_NR_IPDOPD 17 +#define PS_MAX_SSB 91 +#define PS_MAX_AP_BANDS 50 +#define PS_QMF_TIME_SLOTS 32 +#define PS_MAX_DELAY 14 +#define PS_AP_LINKS 3 +#define PS_MAX_AP_DELAY 5 + +typedef struct PSContext { + int start; + int enable_iid; + int iid_quant; + int nr_iid_par; + int nr_ipdopd_par; + int enable_icc; + int icc_mode; + int nr_icc_par; + int enable_ext; + int frame_class; + int num_env_old; + int num_env; + int enable_ipdopd; + int border_position[PS_MAX_NUM_ENV+1]; + int8_t iid_par[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC]; ///< Inter-channel Intensity Difference Parameters + int8_t icc_par[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC]; ///< Inter-Channel Coherence Parameters + /* ipd/opd is iid/icc sized so that the same functions can handle both */ + int8_t ipd_par[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC]; ///< Inter-channel Phase Difference Parameters + int8_t opd_par[PS_MAX_NUM_ENV][PS_MAX_NR_IIDICC]; ///< Overall Phase Difference Parameters + int is34bands; + int is34bands_old; + + DECLARE_ALIGNED(16, INTFLOAT, in_buf)[5][44][2]; + DECLARE_ALIGNED(16, INTFLOAT, delay)[PS_MAX_SSB][PS_QMF_TIME_SLOTS + PS_MAX_DELAY][2]; + DECLARE_ALIGNED(16, INTFLOAT, ap_delay)[PS_MAX_AP_BANDS][PS_AP_LINKS][PS_QMF_TIME_SLOTS + PS_MAX_AP_DELAY][2]; + DECLARE_ALIGNED(16, INTFLOAT, peak_decay_nrg)[34]; + DECLARE_ALIGNED(16, INTFLOAT, power_smooth)[34]; + DECLARE_ALIGNED(16, INTFLOAT, peak_decay_diff_smooth)[34]; + DECLARE_ALIGNED(16, INTFLOAT, H11)[2][PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC]; + DECLARE_ALIGNED(16, INTFLOAT, H12)[2][PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC]; + DECLARE_ALIGNED(16, INTFLOAT, H21)[2][PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC]; + DECLARE_ALIGNED(16, INTFLOAT, H22)[2][PS_MAX_NUM_ENV+1][PS_MAX_NR_IIDICC]; + DECLARE_ALIGNED(16, INTFLOAT, Lbuf)[91][32][2]; + DECLARE_ALIGNED(16, INTFLOAT, Rbuf)[91][32][2]; + int8_t opd_hist[PS_MAX_NR_IIDICC]; + int8_t ipd_hist[PS_MAX_NR_IIDICC]; + PSDSPContext dsp; +} PSContext; + +void AAC_RENAME(ff_ps_init)(void); +void AAC_RENAME(ff_ps_ctx_init)(PSContext *ps); +int AAC_RENAME(ff_ps_read_data)(AVCodecContext *avctx, GetBitContext *gb, PSContext *ps, int bits_left); +int AAC_RENAME(ff_ps_apply)(AVCodecContext *avctx, PSContext *ps, INTFLOAT L[2][38][64], INTFLOAT R[2][38][64], int top); + +#endif /* AVCODEC_AACPS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed.c new file mode 100644 index 0000000000..46af21339a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed.c @@ -0,0 +1,24 @@ +/* + * MPEG-4 Parametric Stereo decoding functions + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 1 + +#include "aacps.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed_tablegen.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed_tablegen.c new file mode 100644 index 0000000000..9e306991f0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed_tablegen.c @@ -0,0 +1,24 @@ +/* + * Generate a header file for hardcoded Parametric Stereo tables + * + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 1 +#include "aacps_tablegen_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed_tablegen.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed_tablegen.h new file mode 100644 index 0000000000..8b82deb596 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_fixed_tablegen.h @@ -0,0 +1,403 @@ +/* + * Header file for hardcoded Parametric Stereo tables + * + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Note: Rounding-to-nearest used unless otherwise stated + * + */ + +#ifndef AVCODEC_AACPS_FIXED_TABLEGEN_H +#define AVCODEC_AACPS_FIXED_TABLEGEN_H + +#include +#include + +#if CONFIG_HARDCODED_TABLES +#define ps_tableinit() +#define TABLE_CONST const +#include "libavcodec/aacps_fixed_tables.h" +#else +#include "libavutil/common.h" +#include "libavutil/mathematics.h" +#include "libavutil/mem.h" + +#include "aac_defines.h" +#include "libavutil/softfloat.h" +#define NR_ALLPASS_BANDS20 30 +#define NR_ALLPASS_BANDS34 50 +#define PS_AP_LINKS 3 +#define TABLE_CONST +static int pd_re_smooth[8*8*8]; +static int pd_im_smooth[8*8*8]; +static int HA[46][8][4]; +static int HB[46][8][4]; +static DECLARE_ALIGNED(16, int, f20_0_8) [ 8][8][2]; +static DECLARE_ALIGNED(16, int, f34_0_12)[12][8][2]; +static DECLARE_ALIGNED(16, int, f34_1_8) [ 8][8][2]; +static DECLARE_ALIGNED(16, int, f34_2_4) [ 4][8][2]; +static TABLE_CONST DECLARE_ALIGNED(16, int, Q_fract_allpass)[2][50][3][2]; +static DECLARE_ALIGNED(16, int, phi_fract)[2][50][2]; + +static const int g0_Q8[] = { + Q31(0.00746082949812f), Q31(0.02270420949825f), Q31(0.04546865930473f), Q31(0.07266113929591f), + Q31(0.09885108575264f), Q31(0.11793710567217f), Q31(0.125f) +}; + +static const int g0_Q12[] = { + Q31(0.04081179924692f), Q31(0.03812810994926f), Q31(0.05144908135699f), Q31(0.06399831151592f), + Q31(0.07428313801106f), Q31(0.08100347892914f), Q31(0.08333333333333f) +}; + +static const int g1_Q8[] = { + Q31(0.01565675600122f), Q31(0.03752716391991f), Q31(0.05417891378782f), Q31(0.08417044116767f), + Q31(0.10307344158036f), Q31(0.12222452249753f), Q31(0.125f) +}; + +static const int g2_Q4[] = { + Q31(-0.05908211155639f), Q31(-0.04871498374946f), Q31(0.0f), Q31(0.07778723915851f), + Q31( 0.16486303567403f), Q31( 0.23279856662996f), Q31(0.25f) +}; + +static const int sintbl_4[4] = { 0, 1073741824, 0, -1073741824 }; +static const int costbl_4[4] = { 1073741824, 0, -1073741824, 0 }; +static const int sintbl_8[8] = { 0, 759250125, 1073741824, 759250125, + 0, -759250125, -1073741824, -759250125 }; +static const int costbl_8[8] = { 1073741824, 759250125, 0, -759250125, + -1073741824, -759250125, 0, 759250125 }; +static const int sintbl_12[12] = { 0, 536870912, 929887697, 1073741824, + 929887697, 536870912, 0, -536870912, + -929887697, -1073741824, -929887697, -536870912 }; +static const int costbl_12[12] = { 1073741824, 929887697, 536870912, 0, + -536870912, -929887697, -1073741824, -929887697, + -536870912, 0, 536870912, 929887697 }; + +static void make_filters_from_proto(int (*filter)[8][2], const int *proto, int bands) +{ + + const int *sinptr, *cosptr; + int s, c, sinhalf, coshalf; + int q, n; + + if (bands == 4) { + sinptr = sintbl_4; + cosptr = costbl_4; + sinhalf = 759250125; + coshalf = 759250125; + } else if (bands == 8) { + sinptr = sintbl_8; + cosptr = costbl_8; + sinhalf = 410903207; + coshalf = 992008094; + } else { + sinptr = sintbl_12; + cosptr = costbl_12; + sinhalf = 277904834; + coshalf = 1037154959; + } + + for (q = 0; q < bands; q++) { + for (n = 0; n < 7; n++) { + int theta = (q*(n-6) + (n>>1) - 3) % bands; + + if (theta < 0) + theta += bands; + s = sinptr[theta]; + c = cosptr[theta]; + + if (n & 1) { + theta = (int)(((int64_t)c * coshalf - (int64_t)s * sinhalf + 0x20000000) >> 30); + s = (int)(((int64_t)s * coshalf + (int64_t)c * sinhalf + 0x20000000) >> 30); + c = theta; + } + filter[q][n][0] = (int)(((int64_t)proto[n] * c + 0x20000000) >> 30); + filter[q][n][1] = -(int)(((int64_t)proto[n] * s + 0x20000000) >> 30); + } + } +} + +static void ps_tableinit(void) +{ + static const int ipdopd_sin[] = { Q30(0), Q30(M_SQRT1_2), Q30(1), Q30( M_SQRT1_2), Q30( 0), Q30(-M_SQRT1_2), Q30(-1), Q30(-M_SQRT1_2) }; + static const int ipdopd_cos[] = { Q30(1), Q30(M_SQRT1_2), Q30(0), Q30(-M_SQRT1_2), Q30(-1), Q30(-M_SQRT1_2), Q30( 0), Q30( M_SQRT1_2) }; + int pd0, pd1, pd2; + int idx; + + static const int alpha_tab[] = + { + Q30(1.5146213770f/M_PI), Q30(1.5181334019f/M_PI), Q30(1.5234849453f/M_PI), Q30(1.5369486809f/M_PI), Q30(1.5500687361f/M_PI), Q30(1.5679757595f/M_PI), + Q30(1.4455626011f/M_PI), Q30(1.4531552792f/M_PI), Q30(1.4648091793f/M_PI), Q30(1.4945238829f/M_PI), Q30(1.5239057541f/M_PI), Q30(1.5644006729f/M_PI), + Q30(1.3738563061f/M_PI), Q30(1.3851221800f/M_PI), Q30(1.4026404619f/M_PI), Q30(1.4484288692f/M_PI), Q30(1.4949874878f/M_PI), Q30(1.5604078770f/M_PI), + Q30(1.2645189762f/M_PI), Q30(1.2796478271f/M_PI), Q30(1.3038636446f/M_PI), Q30(1.3710125685f/M_PI), Q30(1.4443849325f/M_PI), Q30(1.5532352924f/M_PI), + Q30(1.1507037878f/M_PI), Q30(1.1669205427f/M_PI), Q30(1.1938756704f/M_PI), Q30(1.2754167318f/M_PI), Q30(1.3761177063f/M_PI), Q30(1.5429240465f/M_PI), + Q30(1.0079245567f/M_PI), Q30(1.0208238363f/M_PI), Q30(1.0433073044f/M_PI), Q30(1.1208510399f/M_PI), Q30(1.2424604893f/M_PI), Q30(1.5185726881f/M_PI), + Q30(0.8995233774f/M_PI), Q30(0.9069069624f/M_PI), Q30(0.9201194048f/M_PI), Q30(0.9698365927f/M_PI), Q30(1.0671583414f/M_PI), Q30(1.4647934437f/M_PI), + Q30(0.7853981853f/M_PI), Q30(0.7853981853f/M_PI), Q30(0.7853981853f/M_PI), Q30(0.7853981853f/M_PI), Q30(0.7853981853f/M_PI), Q30(0.7853981853f/M_PI), + Q30(0.6712729335f/M_PI), Q30(0.6638893485f/M_PI), Q30(0.6506769061f/M_PI), Q30(0.6009597182f/M_PI), Q30(0.5036380291f/M_PI), Q30(0.1060028747f/M_PI), + Q30(0.5628717542f/M_PI), Q30(0.5499725342f/M_PI), Q30(0.5274890065f/M_PI), Q30(0.4499453008f/M_PI), Q30(0.3283358216f/M_PI), Q30(0.0522236861f/M_PI), + Q30(0.4200925827f/M_PI), Q30(0.4038758278f/M_PI), Q30(0.3769206405f/M_PI), Q30(0.2953795493f/M_PI), Q30(0.1946786791f/M_PI), Q30(0.0278722942f/M_PI), + Q30(0.3062773645f/M_PI), Q30(0.2911485136f/M_PI), Q30(0.2669326365f/M_PI), Q30(0.1997837722f/M_PI), Q30(0.1264114529f/M_PI), Q30(0.0175609849f/M_PI), + Q30(0.1969399750f/M_PI), Q30(0.1856741160f/M_PI), Q30(0.1681558639f/M_PI), Q30(0.1223674342f/M_PI), Q30(0.0758088827f/M_PI), Q30(0.0103884479f/M_PI), + Q30(0.1252337098f/M_PI), Q30(0.1176410317f/M_PI), Q30(0.1059871912f/M_PI), Q30(0.0762724727f/M_PI), Q30(0.0468905345f/M_PI), Q30(0.0063956482f/M_PI), + Q30(0.0561749674f/M_PI), Q30(0.0526629239f/M_PI), Q30(0.0473113805f/M_PI), Q30(0.0338476151f/M_PI), Q30(0.0207276177f/M_PI), Q30(0.0028205961f/M_PI), + Q30(1.5676341057f/M_PI), Q30(1.5678333044f/M_PI), Q30(1.5681363344f/M_PI), Q30(1.5688960552f/M_PI), Q30(1.5696337223f/M_PI), Q30(1.5706381798f/M_PI), + Q30(1.5651730299f/M_PI), Q30(1.5655272007f/M_PI), Q30(1.5660660267f/M_PI), Q30(1.5674170256f/M_PI), Q30(1.5687289238f/M_PI), Q30(1.5705151558f/M_PI), + Q30(1.5607966185f/M_PI), Q30(1.5614265203f/M_PI), Q30(1.5623844862f/M_PI), Q30(1.5647867918f/M_PI), Q30(1.5671195984f/M_PI), Q30(1.5702962875f/M_PI), + Q30(1.5530153513f/M_PI), Q30(1.5541347265f/M_PI), Q30(1.5558375120f/M_PI), Q30(1.5601085424f/M_PI), Q30(1.5642569065f/M_PI), Q30(1.5699069500f/M_PI), + Q30(1.5391840935f/M_PI), Q30(1.5411708355f/M_PI), Q30(1.5441943407f/M_PI), Q30(1.5517836809f/M_PI), Q30(1.5591609478f/M_PI), Q30(1.5692136288f/M_PI), + Q30(1.5146213770f/M_PI), Q30(1.5181334019f/M_PI), Q30(1.5234849453f/M_PI), Q30(1.5369486809f/M_PI), Q30(1.5500687361f/M_PI), Q30(1.5679757595f/M_PI), + Q30(1.4915299416f/M_PI), Q30(1.4964480400f/M_PI), Q30(1.5039558411f/M_PI), Q30(1.5229074955f/M_PI), Q30(1.5414420366f/M_PI), Q30(1.5667995214f/M_PI), + Q30(1.4590617418f/M_PI), Q30(1.4658898115f/M_PI), Q30(1.4763505459f/M_PI), Q30(1.5029321909f/M_PI), Q30(1.5291173458f/M_PI), Q30(1.5651149750f/M_PI), + Q30(1.4136143923f/M_PI), Q30(1.4229322672f/M_PI), Q30(1.4373078346f/M_PI), Q30(1.4743183851f/M_PI), Q30(1.5113102198f/M_PI), Q30(1.5626684427f/M_PI), + Q30(1.3505556583f/M_PI), Q30(1.3628427982f/M_PI), Q30(1.3820509911f/M_PI), Q30(1.4327841997f/M_PI), Q30(1.4850014448f/M_PI), Q30(1.5590143204f/M_PI), + Q30(1.2645189762f/M_PI), Q30(1.2796478271f/M_PI), Q30(1.3038636446f/M_PI), Q30(1.3710125685f/M_PI), Q30(1.4443849325f/M_PI), Q30(1.5532352924f/M_PI), + Q30(1.1919227839f/M_PI), Q30(1.2081253529f/M_PI), Q30(1.2346779108f/M_PI), Q30(1.3123005629f/M_PI), Q30(1.4034168720f/M_PI), Q30(1.5471596718f/M_PI), + Q30(1.1061993837f/M_PI), Q30(1.1219338179f/M_PI), Q30(1.1484941244f/M_PI), Q30(1.2320860624f/M_PI), Q30(1.3421301842f/M_PI), Q30(1.5373806953f/M_PI), + Q30(1.0079245567f/M_PI), Q30(1.0208238363f/M_PI), Q30(1.0433073044f/M_PI), Q30(1.1208510399f/M_PI), Q30(1.2424604893f/M_PI), Q30(1.5185726881f/M_PI), + Q30(0.8995233774f/M_PI), Q30(0.9069069624f/M_PI), Q30(0.9201194048f/M_PI), Q30(0.9698365927f/M_PI), Q30(1.0671583414f/M_PI), Q30(1.4647934437f/M_PI), + Q30(0.7853981853f/M_PI), Q30(0.7853981853f/M_PI), Q30(0.7853981853f/M_PI), Q30(0.7853981853f/M_PI), Q30(0.7853981853f/M_PI), Q30(0.7853981853f/M_PI), + Q30(0.6712729335f/M_PI), Q30(0.6638893485f/M_PI), Q30(0.6506769061f/M_PI), Q30(0.6009597182f/M_PI), Q30(0.5036380291f/M_PI), Q30(0.1060028747f/M_PI), + Q30(0.5628717542f/M_PI), Q30(0.5499725342f/M_PI), Q30(0.5274890065f/M_PI), Q30(0.4499453008f/M_PI), Q30(0.3283358216f/M_PI), Q30(0.0522236861f/M_PI), + Q30(0.4645969570f/M_PI), Q30(0.4488625824f/M_PI), Q30(0.4223022461f/M_PI), Q30(0.3387103081f/M_PI), Q30(0.2286661267f/M_PI), Q30(0.0334156826f/M_PI), + Q30(0.3788735867f/M_PI), Q30(0.3626709878f/M_PI), Q30(0.3361184299f/M_PI), Q30(0.2584958076f/M_PI), Q30(0.1673794836f/M_PI), Q30(0.0236366931f/M_PI), + Q30(0.3062773645f/M_PI), Q30(0.2911485136f/M_PI), Q30(0.2669326365f/M_PI), Q30(0.1997837722f/M_PI), Q30(0.1264114529f/M_PI), Q30(0.0175609849f/M_PI), + Q30(0.2202406377f/M_PI), Q30(0.2079535723f/M_PI), Q30(0.1887452900f/M_PI), Q30(0.1380121708f/M_PI), Q30(0.0857949182f/M_PI), Q30(0.0117820343f/M_PI), + Q30(0.1571819335f/M_PI), Q30(0.1478640437f/M_PI), Q30(0.1334884763f/M_PI), Q30(0.0964778885f/M_PI), Q30(0.0594860613f/M_PI), Q30(0.0081279324f/M_PI), + Q30(0.1117345318f/M_PI), Q30(0.1049065739f/M_PI), Q30(0.0944457650f/M_PI), Q30(0.0678641573f/M_PI), Q30(0.0416790098f/M_PI), Q30(0.0056813755f/M_PI), + Q30(0.0792663917f/M_PI), Q30(0.0743482932f/M_PI), Q30(0.0668405443f/M_PI), Q30(0.0478888862f/M_PI), Q30(0.0293543357f/M_PI), Q30(0.0039967746f/M_PI), + Q30(0.0561749674f/M_PI), Q30(0.0526629239f/M_PI), Q30(0.0473113805f/M_PI), Q30(0.0338476151f/M_PI), Q30(0.0207276177f/M_PI), Q30(0.0028205961f/M_PI), + Q30(0.0316122435f/M_PI), Q30(0.0296254847f/M_PI), Q30(0.0266019460f/M_PI), Q30(0.0190126132f/M_PI), Q30(0.0116353342f/M_PI), Q30(0.0015827164f/M_PI), + Q30(0.0177809205f/M_PI), Q30(0.0166615788f/M_PI), Q30(0.0149587989f/M_PI), Q30(0.0106877899f/M_PI), Q30(0.0065393616f/M_PI), Q30(0.0008894200f/M_PI), + Q30(0.0099996664f/M_PI), Q30(0.0093698399f/M_PI), Q30(0.0084118480f/M_PI), Q30(0.0060095116f/M_PI), Q30(0.0036767013f/M_PI), Q30(0.0005000498f/M_PI), + Q30(0.0056233541f/M_PI), Q30(0.0052691097f/M_PI), Q30(0.0047303112f/M_PI), Q30(0.0033792770f/M_PI), Q30(0.0020674451f/M_PI), Q30(0.0002811795f/M_PI), + Q30(0.0031622672f/M_PI), Q30(0.0029630491f/M_PI), Q30(0.0026600463f/M_PI), Q30(0.0019002859f/M_PI), Q30(0.0011625893f/M_PI), Q30(0.0001581155f/M_PI) + }; + + static const int gamma_tab[] = + { + Q30(0.0000000000f/M_PI), Q30(0.0195873566f/M_PI), Q30(0.0303316917f/M_PI), Q30(0.0448668823f/M_PI), Q30(0.0522258915f/M_PI), Q30(0.0561044961f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0433459543f/M_PI), Q30(0.0672172382f/M_PI), Q30(0.0997167900f/M_PI), Q30(0.1162951663f/M_PI), Q30(0.1250736862f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0672341362f/M_PI), Q30(0.1045235619f/M_PI), Q30(0.1558904350f/M_PI), Q30(0.1824723780f/M_PI), Q30(0.1966800541f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1011129096f/M_PI), Q30(0.1580764502f/M_PI), Q30(0.2387557179f/M_PI), Q30(0.2820728719f/M_PI), Q30(0.3058380187f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1315985769f/M_PI), Q30(0.2072522491f/M_PI), Q30(0.3188187480f/M_PI), Q30(0.3825501204f/M_PI), Q30(0.4193951190f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1603866369f/M_PI), Q30(0.2549437582f/M_PI), Q30(0.4029446840f/M_PI), Q30(0.4980689585f/M_PI), Q30(0.5615641475f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1736015975f/M_PI), Q30(0.2773745656f/M_PI), Q30(0.4461984038f/M_PI), Q30(0.5666890144f/M_PI), Q30(0.6686112881f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1784276664f/M_PI), Q30(0.2856673002f/M_PI), Q30(0.4630723596f/M_PI), Q30(0.5971632004f/M_PI), Q30(0.7603877187f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1736015975f/M_PI), Q30(0.2773745656f/M_PI), Q30(0.4461984038f/M_PI), Q30(0.5666890144f/M_PI), Q30(0.6686112881f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1603866369f/M_PI), Q30(0.2549437582f/M_PI), Q30(0.4029446840f/M_PI), Q30(0.4980689585f/M_PI), Q30(0.5615641475f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1315985769f/M_PI), Q30(0.2072522491f/M_PI), Q30(0.3188187480f/M_PI), Q30(0.3825501204f/M_PI), Q30(0.4193951190f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1011129096f/M_PI), Q30(0.1580764502f/M_PI), Q30(0.2387557179f/M_PI), Q30(0.2820728719f/M_PI), Q30(0.3058380187f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0672341362f/M_PI), Q30(0.1045235619f/M_PI), Q30(0.1558904350f/M_PI), Q30(0.1824723780f/M_PI), Q30(0.1966800541f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0433459543f/M_PI), Q30(0.0672172382f/M_PI), Q30(0.0997167900f/M_PI), Q30(0.1162951663f/M_PI), Q30(0.1250736862f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0195873566f/M_PI), Q30(0.0303316917f/M_PI), Q30(0.0448668823f/M_PI), Q30(0.0522258915f/M_PI), Q30(0.0561044961f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0011053939f/M_PI), Q30(0.0017089852f/M_PI), Q30(0.0025254129f/M_PI), Q30(0.0029398468f/M_PI), Q30(0.0031597170f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0019607407f/M_PI), Q30(0.0030395309f/M_PI), Q30(0.0044951206f/M_PI), Q30(0.0052305623f/M_PI), Q30(0.0056152637f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0034913034f/M_PI), Q30(0.0054070661f/M_PI), Q30(0.0079917293f/M_PI), Q30(0.0092999367f/M_PI), Q30(0.0099875759f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0062100487f/M_PI), Q30(0.0096135242f/M_PI), Q30(0.0142110568f/M_PI), Q30(0.0165348612f/M_PI), Q30(0.0177587029f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0110366223f/M_PI), Q30(0.0170863140f/M_PI), Q30(0.0252620988f/M_PI), Q30(0.0293955617f/M_PI), Q30(0.0315726399f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0195873566f/M_PI), Q30(0.0303316917f/M_PI), Q30(0.0448668823f/M_PI), Q30(0.0522258915f/M_PI), Q30(0.0561044961f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0275881495f/M_PI), Q30(0.0427365713f/M_PI), Q30(0.0632618815f/M_PI), Q30(0.0736731067f/M_PI), Q30(0.0791663304f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0387469754f/M_PI), Q30(0.0600636788f/M_PI), Q30(0.0890387669f/M_PI), Q30(0.1037906483f/M_PI), Q30(0.1115923747f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0541138873f/M_PI), Q30(0.0839984417f/M_PI), Q30(0.1248718798f/M_PI), Q30(0.1458375156f/M_PI), Q30(0.1569785923f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0747506917f/M_PI), Q30(0.1163287833f/M_PI), Q30(0.1738867164f/M_PI), Q30(0.2038587779f/M_PI), Q30(0.2199459076f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1011129096f/M_PI), Q30(0.1580764502f/M_PI), Q30(0.2387557179f/M_PI), Q30(0.2820728719f/M_PI), Q30(0.3058380187f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1212290376f/M_PI), Q30(0.1903949380f/M_PI), Q30(0.2907958031f/M_PI), Q30(0.3466993868f/M_PI), Q30(0.3782821596f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1418247074f/M_PI), Q30(0.2240308374f/M_PI), Q30(0.3474813402f/M_PI), Q30(0.4202919006f/M_PI), Q30(0.4637607038f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1603866369f/M_PI), Q30(0.2549437582f/M_PI), Q30(0.4029446840f/M_PI), Q30(0.4980689585f/M_PI), Q30(0.5615641475f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1736015975f/M_PI), Q30(0.2773745656f/M_PI), Q30(0.4461984038f/M_PI), Q30(0.5666890144f/M_PI), Q30(0.6686112881f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1784276664f/M_PI), Q30(0.2856673002f/M_PI), Q30(0.4630723596f/M_PI), Q30(0.5971632004f/M_PI), Q30(0.7603877187f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1736015975f/M_PI), Q30(0.2773745656f/M_PI), Q30(0.4461984038f/M_PI), Q30(0.5666890144f/M_PI), Q30(0.6686112881f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1603866369f/M_PI), Q30(0.2549437582f/M_PI), Q30(0.4029446840f/M_PI), Q30(0.4980689585f/M_PI), Q30(0.5615641475f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1418247074f/M_PI), Q30(0.2240308374f/M_PI), Q30(0.3474813402f/M_PI), Q30(0.4202919006f/M_PI), Q30(0.4637607038f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1212290376f/M_PI), Q30(0.1903949380f/M_PI), Q30(0.2907958031f/M_PI), Q30(0.3466993868f/M_PI), Q30(0.3782821596f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.1011129096f/M_PI), Q30(0.1580764502f/M_PI), Q30(0.2387557179f/M_PI), Q30(0.2820728719f/M_PI), Q30(0.3058380187f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0747506917f/M_PI), Q30(0.1163287833f/M_PI), Q30(0.1738867164f/M_PI), Q30(0.2038587779f/M_PI), Q30(0.2199459076f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0541138873f/M_PI), Q30(0.0839984417f/M_PI), Q30(0.1248718798f/M_PI), Q30(0.1458375156f/M_PI), Q30(0.1569785923f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0387469754f/M_PI), Q30(0.0600636788f/M_PI), Q30(0.0890387669f/M_PI), Q30(0.1037906483f/M_PI), Q30(0.1115923747f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0275881495f/M_PI), Q30(0.0427365713f/M_PI), Q30(0.0632618815f/M_PI), Q30(0.0736731067f/M_PI), Q30(0.0791663304f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0195873566f/M_PI), Q30(0.0303316917f/M_PI), Q30(0.0448668823f/M_PI), Q30(0.0522258915f/M_PI), Q30(0.0561044961f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0110366223f/M_PI), Q30(0.0170863140f/M_PI), Q30(0.0252620988f/M_PI), Q30(0.0293955617f/M_PI), Q30(0.0315726399f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0062100487f/M_PI), Q30(0.0096135242f/M_PI), Q30(0.0142110568f/M_PI), Q30(0.0165348612f/M_PI), Q30(0.0177587029f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0034913034f/M_PI), Q30(0.0054070661f/M_PI), Q30(0.0079917293f/M_PI), Q30(0.0092999367f/M_PI), Q30(0.0099875759f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0019607407f/M_PI), Q30(0.0030395309f/M_PI), Q30(0.0044951206f/M_PI), Q30(0.0052305623f/M_PI), Q30(0.0056152637f/M_PI), + Q30(0.0000000000f/M_PI), Q30(0.0011053939f/M_PI), Q30(0.0017089852f/M_PI), Q30(0.0025254129f/M_PI), Q30(0.0029398468f/M_PI), Q30(0.0031597170f/M_PI) + }; + + static const int iid_par_dequant_c1[] = { + //iid_par_dequant_default + Q30(1.41198278375959f), Q30(1.40313815268360f), Q30(1.38687670404960f), Q30(1.34839972492648f), + Q30(1.29124937110028f), Q30(1.19603741667993f), Q30(1.10737240362323f), Q30(1), + Q30(0.87961716655242f), Q30(0.75464859232732f), Q30(0.57677990744575f), Q30(0.42640143271122f), + Q30(0.27671828230984f), Q30(0.17664462766713f), Q30(0.07940162697653f), + //iid_par_dequant_fine + Q30(1.41420649135832f), Q30(1.41419120222364f), Q30(1.41414285699784f), Q30(1.41399000859438f), + Q30(1.41350698548044f), Q30(1.41198278375959f), Q30(1.40977302262355f), Q30(1.40539479488545f), + Q30(1.39677960498402f), Q30(1.38005309967827f), Q30(1.34839972492648f), Q30(1.31392017367631f), + Q30(1.26431008149654f), Q30(1.19603741667993f), Q30(1.10737240362323f), Q30(1), + Q30(0.87961716655242f), Q30(0.75464859232732f), Q30(0.63365607219232f), Q30(0.52308104267543f), + Q30(0.42640143271122f), Q30(0.30895540465965f), Q30(0.22137464873077f), Q30(0.15768788954414f), + Q30(0.11198225164225f), Q30(0.07940162697653f), Q30(0.04469901562677f), Q30(0.02514469318284f), + Q30(0.01414142856998f), Q30(0.00795258154731f), Q30(0.00447211359449f), + }; + + static const int acos_icc_invq[] = { + Q31(0), Q31(0.178427635f/M_PI), Q31(0.28566733f/M_PI), Q31(0.46307236f/M_PI), Q31(0.59716315f/M_PI), Q31(0.78539816f/M_PI), Q31(1.10030855f/M_PI), Q31(1.57079633f/M_PI) + }; + int iid, icc; + + int k, m; + static const int8_t f_center_20[] = { + -3, -1, 1, 3, 5, 7, 10, 14, 18, 22, + }; + static const int32_t f_center_34[] = { + Q31( 2/768.0),Q31( 6/768.0),Q31(10/768.0),Q31(14/768.0),Q31( 18/768.0),Q31( 22/768.0),Q31( 26/768.0),Q31(30/768.0), + Q31( 34/768.0),Q31(-10/768.0),Q31(-6/768.0),Q31(-2/768.0),Q31( 51/768.0),Q31( 57/768.0),Q31( 15/768.0),Q31(21/768.0), + Q31( 27/768.0),Q31( 33/768.0),Q31(39/768.0),Q31(45/768.0),Q31( 54/768.0),Q31( 66/768.0),Q31( 78/768.0),Q31(42/768.0), + Q31(102/768.0),Q31( 66/768.0),Q31(78/768.0),Q31(90/768.0),Q31(102/768.0),Q31(114/768.0),Q31(126/768.0),Q31(90/768.0) + }; + static const int fractional_delay_links[] = { Q31(0.43f), Q31(0.75f), Q31(0.347f) }; + const int fractional_delay_gain = Q31(0.39f); + + for (pd0 = 0; pd0 < 8; pd0++) { + int pd0_re = (ipdopd_cos[pd0]+2)>>2; + int pd0_im = (ipdopd_sin[pd0]+2)>>2; + for (pd1 = 0; pd1 < 8; pd1++) { + int pd1_re = ipdopd_cos[pd1] >> 1; + int pd1_im = ipdopd_sin[pd1] >> 1; + for (pd2 = 0; pd2 < 8; pd2++) { + int shift, round; + int pd2_re = ipdopd_cos[pd2]; + int pd2_im = ipdopd_sin[pd2]; + int re_smooth = pd0_re + pd1_re + pd2_re; + int im_smooth = pd0_im + pd1_im + pd2_im; + + SoftFloat pd_mag = av_int2sf(((ipdopd_cos[(pd0-pd1)&7]+8)>>4) + ((ipdopd_cos[(pd0-pd2)&7]+4)>>3) + + ((ipdopd_cos[(pd1-pd2)&7]+2)>>2) + 0x15000000, 28); + pd_mag = av_div_sf(FLOAT_1, av_sqrt_sf(pd_mag)); + shift = 30 - pd_mag.exp; + round = 1 << (shift-1); + pd_re_smooth[pd0*64+pd1*8+pd2] = (int)(((int64_t)re_smooth * pd_mag.mant + round) >> shift); + pd_im_smooth[pd0*64+pd1*8+pd2] = (int)(((int64_t)im_smooth * pd_mag.mant + round) >> shift); + } + } + } + + idx = 0; + for (iid = 0; iid < 46; iid++) { + int c1, c2; + + c1 = iid_par_dequant_c1[iid]; + if (iid < 15) + c2 = iid_par_dequant_c1[14-iid]; + else + c2 = iid_par_dequant_c1[60-iid]; + + for (icc = 0; icc < 8; icc++) { + /*if (PS_BASELINE || ps->icc_mode < 3)*/{ + int alpha, beta; + int ca, sa, cb, sb; + + alpha = acos_icc_invq[icc]; + beta = (int)(((int64_t)alpha * 1518500250 + 0x40000000) >> 31); + alpha >>= 1; + beta = (int)(((int64_t)beta * (c1 - c2) + 0x40000000) >> 31); + av_sincos_sf(beta + alpha, &sa, &ca); + av_sincos_sf(beta - alpha, &sb, &cb); + + HA[iid][icc][0] = (int)(((int64_t)c2 * ca + 0x20000000) >> 30); + HA[iid][icc][1] = (int)(((int64_t)c1 * cb + 0x20000000) >> 30); + HA[iid][icc][2] = (int)(((int64_t)c2 * sa + 0x20000000) >> 30); + HA[iid][icc][3] = (int)(((int64_t)c1 * sb + 0x20000000) >> 30); + } /* else */ { + int alpha_int, gamma_int; + int alpha_c_int, alpha_s_int, gamma_c_int, gamma_s_int; + + alpha_int = alpha_tab[idx]; + gamma_int = gamma_tab[idx]; + + av_sincos_sf(alpha_int, &alpha_s_int, &alpha_c_int); + av_sincos_sf(gamma_int, &gamma_s_int, &gamma_c_int); + + alpha_c_int = (int)(((int64_t)alpha_c_int * 1518500250 + 0x20000000) >> 30); + alpha_s_int = (int)(((int64_t)alpha_s_int * 1518500250 + 0x20000000) >> 30); + + HB[iid][icc][0] = (int)(((int64_t)alpha_c_int * gamma_c_int + 0x20000000) >> 30); + HB[iid][icc][1] = (int)(((int64_t)alpha_s_int * gamma_c_int + 0x20000000) >> 30); + HB[iid][icc][2] = -(int)(((int64_t)alpha_s_int * gamma_s_int + 0x20000000) >> 30); + HB[iid][icc][3] = (int)(((int64_t)alpha_c_int * gamma_s_int + 0x20000000) >> 30); + } + + if (icc < 5 || icc > 6) + idx++; + } + } + + for (k = 0; k < NR_ALLPASS_BANDS20; k++) { + int theta; + int64_t f_center; + int c, s; + + if (k < FF_ARRAY_ELEMS(f_center_20)) + f_center = f_center_20[k]; + else + f_center = (k << 3) - 52; + + for (m = 0; m < PS_AP_LINKS; m++) { + theta = (int)(((int64_t)fractional_delay_links[m] * f_center + 8) >> 4); + av_sincos_sf(-theta, &s, &c); + Q_fract_allpass[0][k][m][0] = c; + Q_fract_allpass[0][k][m][1] = s; + } + + theta = (int)(((int64_t)fractional_delay_gain * f_center + 8) >> 4); + av_sincos_sf(-theta, &s, &c); + phi_fract[0][k][0] = c; + phi_fract[0][k][1] = s; + } + + for (k = 0; k < NR_ALLPASS_BANDS34; k++) { + int theta, f_center; + int c, s; + + if (k < FF_ARRAY_ELEMS(f_center_34)) + f_center = f_center_34[k]; + else + f_center = ((int64_t)k << 26) - (53 << 25); + + for (m = 0; m < PS_AP_LINKS; m++) { + theta = (int)(((int64_t)fractional_delay_links[m] * f_center + 0x10000000) >> 27); + av_sincos_sf(-theta, &s, &c); + Q_fract_allpass[1][k][m][0] = c; + Q_fract_allpass[1][k][m][1] = s; + } + + theta = (int)(((int64_t)fractional_delay_gain * f_center + 0x10000000) >> 27); + av_sincos_sf(-theta, &s, &c); + phi_fract[1][k][0] = c; + phi_fract[1][k][1] = s; + } + + make_filters_from_proto(f20_0_8, g0_Q8, 8); + make_filters_from_proto(f34_0_12, g0_Q12, 12); + make_filters_from_proto(f34_1_8, g1_Q8, 8); + make_filters_from_proto(f34_2_4, g2_Q4, 4); +} +#endif /* CONFIG_HARDCODED_TABLES */ + +#endif /* AVCODEC_AACPS_FIXED_TABLEGEN_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_float.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_float.c new file mode 100644 index 0000000000..73259c10fb --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_float.c @@ -0,0 +1,24 @@ +/* + * MPEG-4 Parametric Stereo decoding functions + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 0 + +#include "aacps.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen.c new file mode 100644 index 0000000000..26a6752faa --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen.c @@ -0,0 +1,24 @@ +/* + * Generate a header file for hardcoded Parametric Stereo tables + * + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 0 +#include "aacps_tablegen_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen.h new file mode 100644 index 0000000000..0ac4f68d68 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen.h @@ -0,0 +1,217 @@ +/* + * Header file for hardcoded Parametric Stereo tables + * + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AACPS_TABLEGEN_H +#define AVCODEC_AACPS_TABLEGEN_H + +#include +#include + +#if CONFIG_HARDCODED_TABLES +#define ps_tableinit() +#define TABLE_CONST const +#include "libavcodec/aacps_tables.h" +#else +#include "libavutil/common.h" +#include "libavutil/libm.h" +#include "libavutil/mathematics.h" +#include "libavutil/mem.h" +#define NR_ALLPASS_BANDS20 30 +#define NR_ALLPASS_BANDS34 50 +#define PS_AP_LINKS 3 +#define TABLE_CONST +static float pd_re_smooth[8*8*8]; +static float pd_im_smooth[8*8*8]; +static float HA[46][8][4]; +static float HB[46][8][4]; +static DECLARE_ALIGNED(16, float, f20_0_8) [ 8][8][2]; +static DECLARE_ALIGNED(16, float, f34_0_12)[12][8][2]; +static DECLARE_ALIGNED(16, float, f34_1_8) [ 8][8][2]; +static DECLARE_ALIGNED(16, float, f34_2_4) [ 4][8][2]; +static TABLE_CONST DECLARE_ALIGNED(16, float, Q_fract_allpass)[2][50][3][2]; +static DECLARE_ALIGNED(16, float, phi_fract)[2][50][2]; + +static const float g0_Q8[] = { + 0.00746082949812f, 0.02270420949825f, 0.04546865930473f, 0.07266113929591f, + 0.09885108575264f, 0.11793710567217f, 0.125f +}; + +static const float g0_Q12[] = { + 0.04081179924692f, 0.03812810994926f, 0.05144908135699f, 0.06399831151592f, + 0.07428313801106f, 0.08100347892914f, 0.08333333333333f +}; + +static const float g1_Q8[] = { + 0.01565675600122f, 0.03752716391991f, 0.05417891378782f, 0.08417044116767f, + 0.10307344158036f, 0.12222452249753f, 0.125f +}; + +static const float g2_Q4[] = { + -0.05908211155639f, -0.04871498374946f, 0.0f, 0.07778723915851f, + 0.16486303567403f, 0.23279856662996f, 0.25f +}; + +static av_cold void make_filters_from_proto(float (*filter)[8][2], const float *proto, int bands) +{ + int q, n; + for (q = 0; q < bands; q++) { + for (n = 0; n < 7; n++) { + double theta = 2 * M_PI * (q + 0.5) * (n - 6) / bands; + filter[q][n][0] = proto[n] * cos(theta); + filter[q][n][1] = proto[n] * -sin(theta); + } + } +} + +static av_cold void ps_tableinit(void) +{ + static const float ipdopd_sin[] = { 0, M_SQRT1_2, 1, M_SQRT1_2, 0, -M_SQRT1_2, -1, -M_SQRT1_2 }; + static const float ipdopd_cos[] = { 1, M_SQRT1_2, 0, -M_SQRT1_2, -1, -M_SQRT1_2, 0, M_SQRT1_2 }; + int pd0, pd1, pd2; + + static const float iid_par_dequant[] = { + //iid_par_dequant_default + 0.05623413251903, 0.12589254117942, 0.19952623149689, 0.31622776601684, + 0.44668359215096, 0.63095734448019, 0.79432823472428, 1, + 1.25892541179417, 1.58489319246111, 2.23872113856834, 3.16227766016838, + 5.01187233627272, 7.94328234724282, 17.7827941003892, + //iid_par_dequant_fine + 0.00316227766017, 0.00562341325190, 0.01, 0.01778279410039, + 0.03162277660168, 0.05623413251903, 0.07943282347243, 0.11220184543020, + 0.15848931924611, 0.22387211385683, 0.31622776601684, 0.39810717055350, + 0.50118723362727, 0.63095734448019, 0.79432823472428, 1, + 1.25892541179417, 1.58489319246111, 1.99526231496888, 2.51188643150958, + 3.16227766016838, 4.46683592150963, 6.30957344480193, 8.91250938133745, + 12.5892541179417, 17.7827941003892, 31.6227766016838, 56.2341325190349, + 100, 177.827941003892, 316.227766016837, + }; + static const float icc_invq[] = { + 1, 0.937, 0.84118, 0.60092, 0.36764, 0, -0.589, -1 + }; + static const float acos_icc_invq[] = { + 0, 0.35685527, 0.57133466, 0.92614472, 1.1943263, M_PI/2, 2.2006171, M_PI + }; + int iid, icc; + + int k, m; + static const int8_t f_center_20[] = { + -3, -1, 1, 3, 5, 7, 10, 14, 18, 22, + }; + static const int8_t f_center_34[] = { + 2, 6, 10, 14, 18, 22, 26, 30, + 34,-10, -6, -2, 51, 57, 15, 21, + 27, 33, 39, 45, 54, 66, 78, 42, + 102, 66, 78, 90,102,114,126, 90, + }; + static const float fractional_delay_links[] = { 0.43f, 0.75f, 0.347f }; + const float fractional_delay_gain = 0.39f; + + for (pd0 = 0; pd0 < 8; pd0++) { + float pd0_re = ipdopd_cos[pd0]; + float pd0_im = ipdopd_sin[pd0]; + for (pd1 = 0; pd1 < 8; pd1++) { + float pd1_re = ipdopd_cos[pd1]; + float pd1_im = ipdopd_sin[pd1]; + for (pd2 = 0; pd2 < 8; pd2++) { + float pd2_re = ipdopd_cos[pd2]; + float pd2_im = ipdopd_sin[pd2]; + float re_smooth = 0.25f * pd0_re + 0.5f * pd1_re + pd2_re; + float im_smooth = 0.25f * pd0_im + 0.5f * pd1_im + pd2_im; + float pd_mag = 1 / hypot(im_smooth, re_smooth); + pd_re_smooth[pd0*64+pd1*8+pd2] = re_smooth * pd_mag; + pd_im_smooth[pd0*64+pd1*8+pd2] = im_smooth * pd_mag; + } + } + } + + for (iid = 0; iid < 46; iid++) { + float c = iid_par_dequant[iid]; ///< Linear Inter-channel Intensity Difference + float c1 = (float)M_SQRT2 / sqrtf(1.0f + c*c); + float c2 = c * c1; + for (icc = 0; icc < 8; icc++) { + /*if (PS_BASELINE || ps->icc_mode < 3)*/ { + float alpha = 0.5f * acos_icc_invq[icc]; + float beta = alpha * (c1 - c2) * (float)M_SQRT1_2; + HA[iid][icc][0] = c2 * cosf(beta + alpha); + HA[iid][icc][1] = c1 * cosf(beta - alpha); + HA[iid][icc][2] = c2 * sinf(beta + alpha); + HA[iid][icc][3] = c1 * sinf(beta - alpha); + } /* else */ { + float alpha, gamma, mu, rho; + float alpha_c, alpha_s, gamma_c, gamma_s; + rho = FFMAX(icc_invq[icc], 0.05f); + alpha = 0.5f * atan2f(2.0f * c * rho, c*c - 1.0f); + mu = c + 1.0f / c; + mu = sqrtf(1 + (4 * rho * rho - 4)/(mu * mu)); + gamma = atanf(sqrtf((1.0f - mu)/(1.0f + mu))); + if (alpha < 0) alpha += M_PI/2; + alpha_c = cosf(alpha); + alpha_s = sinf(alpha); + gamma_c = cosf(gamma); + gamma_s = sinf(gamma); + HB[iid][icc][0] = M_SQRT2 * alpha_c * gamma_c; + HB[iid][icc][1] = M_SQRT2 * alpha_s * gamma_c; + HB[iid][icc][2] = -M_SQRT2 * alpha_s * gamma_s; + HB[iid][icc][3] = M_SQRT2 * alpha_c * gamma_s; + } + } + } + + for (k = 0; k < NR_ALLPASS_BANDS20; k++) { + double f_center, theta; + if (k < FF_ARRAY_ELEMS(f_center_20)) + f_center = f_center_20[k] * 0.125; + else + f_center = k - 6.5f; + for (m = 0; m < PS_AP_LINKS; m++) { + theta = -M_PI * fractional_delay_links[m] * f_center; + Q_fract_allpass[0][k][m][0] = cos(theta); + Q_fract_allpass[0][k][m][1] = sin(theta); + } + theta = -M_PI*fractional_delay_gain*f_center; + phi_fract[0][k][0] = cos(theta); + phi_fract[0][k][1] = sin(theta); + } + for (k = 0; k < NR_ALLPASS_BANDS34; k++) { + double f_center, theta; + if (k < FF_ARRAY_ELEMS(f_center_34)) + f_center = f_center_34[k] / 24.0; + else + f_center = k - 26.5f; + for (m = 0; m < PS_AP_LINKS; m++) { + theta = -M_PI * fractional_delay_links[m] * f_center; + Q_fract_allpass[1][k][m][0] = cos(theta); + Q_fract_allpass[1][k][m][1] = sin(theta); + } + theta = -M_PI*fractional_delay_gain*f_center; + phi_fract[1][k][0] = cos(theta); + phi_fract[1][k][1] = sin(theta); + } + + make_filters_from_proto(f20_0_8, g0_Q8, 8); + make_filters_from_proto(f34_0_12, g0_Q12, 12); + make_filters_from_proto(f34_1_8, g1_Q8, 8); + make_filters_from_proto(f34_2_4, g2_Q4, 4); +} +#endif /* CONFIG_HARDCODED_TABLES */ + +#endif /* AVCODEC_AACPS_TABLEGEN_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen_template.c new file mode 100644 index 0000000000..341bd44409 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacps_tablegen_template.c @@ -0,0 +1,107 @@ +/* + * Generate a header file for hardcoded Parametric Stereo tables + * + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#define CONFIG_HARDCODED_TABLES 0 +#include "aac_defines.h" + +#if USE_FIXED +#define TYPE_NAME "int32_t" +typedef int32_t INT32FLOAT; +#define ARRAY_RENAME(x) write_int32_t_ ## x +#define ARRAY_URENAME(x) write_uint32_t_ ## x +#include "aacps_fixed_tablegen.h" +#else +#define TYPE_NAME "float" +typedef float INT32FLOAT; +#define ARRAY_RENAME(x) write_float_ ## x +#define ARRAY_URENAME(x) write_float_ ## x +#include "aacps_tablegen.h" +#endif /* USE_FIXED */ +#include "tableprint.h" + +void ARRAY_RENAME(3d_array) (const void *p, int b, int c, int d) +{ + int i; + const INT32FLOAT *f = p; + for (i = 0; i < b; i++) { + printf("{\n"); + ARRAY_URENAME(2d_array)(f, c, d); + printf("},\n"); + f += c * d; + } +} + +void ARRAY_RENAME(4d_array) (const void *p, int a, int b, int c, int d) +{ + int i; + const INT32FLOAT *f = p; + for (i = 0; i < a; i++) { + printf("{\n"); + ARRAY_RENAME(3d_array)(f, b, c, d); + printf("},\n"); + f += b * c * d; + } +} + +int main(void) +{ + ps_tableinit(); + + write_fileheader(); + + printf("static const %s pd_re_smooth[8*8*8] = {\n", TYPE_NAME); + ARRAY_RENAME(array)(pd_re_smooth, 8*8*8); + printf("};\n"); + printf("static const %s pd_im_smooth[8*8*8] = {\n", TYPE_NAME); + ARRAY_RENAME(array)(pd_im_smooth, 8*8*8); + printf("};\n"); + + printf("static const %s HA[46][8][4] = {\n", TYPE_NAME); + ARRAY_RENAME(3d_array)(HA, 46, 8, 4); + printf("};\n"); + printf("static const %s HB[46][8][4] = {\n", TYPE_NAME); + ARRAY_RENAME(3d_array)(HB, 46, 8, 4); + printf("};\n"); + + printf("static const DECLARE_ALIGNED(16, %s, f20_0_8)[8][8][2] = {\n", TYPE_NAME); + ARRAY_RENAME(3d_array)(f20_0_8, 8, 8, 2); + printf("};\n"); + printf("static const DECLARE_ALIGNED(16, %s, f34_0_12)[12][8][2] = {\n", TYPE_NAME); + ARRAY_RENAME(3d_array)(f34_0_12, 12, 8, 2); + printf("};\n"); + printf("static const DECLARE_ALIGNED(16, %s, f34_1_8)[8][8][2] = {\n", TYPE_NAME); + ARRAY_RENAME(3d_array)(f34_1_8, 8, 8, 2); + printf("};\n"); + printf("static const DECLARE_ALIGNED(16, %s, f34_2_4)[4][8][2] = {\n", TYPE_NAME); + ARRAY_RENAME(3d_array)(f34_2_4, 4, 8, 2); + printf("};\n"); + + printf("static const DECLARE_ALIGNED(16, %s, Q_fract_allpass)[2][50][3][2] = {\n", TYPE_NAME); + ARRAY_RENAME(4d_array)(Q_fract_allpass, 2, 50, 3, 2); + printf("};\n"); + printf("static const DECLARE_ALIGNED(16, %s, phi_fract)[2][50][2] = {\n", TYPE_NAME); + ARRAY_RENAME(3d_array)(phi_fract, 2, 50, 2); + printf("};\n"); + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdata.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdata.c new file mode 100644 index 0000000000..5c1a1b0f88 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdata.c @@ -0,0 +1,163 @@ +/* + * MPEG-4 Parametric Stereo data tables + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static const uint8_t huff_iid_df1_bits[] = { + 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 18, 17, 17, 16, 16, 15, 14, 14, + 13, 12, 12, 11, 10, 10, 8, 7, 6, 5, 4, 3, 1, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 16, 16, 17, 17, 18, 17, 18, 18, + 18, 18, 18, 18, 18, 18, 18, +}; + +static const uint32_t huff_iid_df1_codes[] = { + 0x01FEB4, 0x01FEB5, 0x01FD76, 0x01FD77, 0x01FD74, 0x01FD75, 0x01FE8A, + 0x01FE8B, 0x01FE88, 0x00FE80, 0x01FEB6, 0x00FE82, 0x00FEB8, 0x007F42, + 0x007FAE, 0x003FAF, 0x001FD1, 0x001FE9, 0x000FE9, 0x0007EA, 0x0007FB, + 0x0003FB, 0x0001FB, 0x0001FF, 0x00007C, 0x00003C, 0x00001C, 0x00000C, + 0x000000, 0x000001, 0x000001, 0x000002, 0x000001, 0x00000D, 0x00001D, + 0x00003D, 0x00007D, 0x0000FC, 0x0001FC, 0x0003FC, 0x0003F4, 0x0007EB, + 0x000FEA, 0x001FEA, 0x001FD6, 0x003FD0, 0x007FAF, 0x007F43, 0x00FEB9, + 0x00FE83, 0x01FEB7, 0x00FE81, 0x01FE89, 0x01FE8E, 0x01FE8F, 0x01FE8C, + 0x01FE8D, 0x01FEB2, 0x01FEB3, 0x01FEB0, 0x01FEB1, +}; + +static const uint8_t huff_iid_dt1_bits[] = { + 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 13, + 13, 13, 12, 12, 11, 10, 9, 9, 7, 6, 5, 3, 1, 2, 5, 6, 7, 8, + 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, +}; + +static const uint16_t huff_iid_dt1_codes[] = { + 0x004ED4, 0x004ED5, 0x004ECE, 0x004ECF, 0x004ECC, 0x004ED6, 0x004ED8, + 0x004F46, 0x004F60, 0x002718, 0x002719, 0x002764, 0x002765, 0x00276D, + 0x0027B1, 0x0013B7, 0x0013D6, 0x0009C7, 0x0009E9, 0x0009ED, 0x0004EE, + 0x0004F7, 0x000278, 0x000139, 0x00009A, 0x00009F, 0x000020, 0x000011, + 0x00000A, 0x000003, 0x000001, 0x000000, 0x00000B, 0x000012, 0x000021, + 0x00004C, 0x00009B, 0x00013A, 0x000279, 0x000270, 0x0004EF, 0x0004E2, + 0x0009EA, 0x0009D8, 0x0013D7, 0x0013D0, 0x0027B2, 0x0027A2, 0x00271A, + 0x00271B, 0x004F66, 0x004F67, 0x004F61, 0x004F47, 0x004ED9, 0x004ED7, + 0x004ECD, 0x004ED2, 0x004ED3, 0x004ED0, 0x004ED1, +}; + +static const uint8_t huff_iid_df0_bits[] = { + 17, 17, 17, 17, 16, 15, 13, 10, 9, 7, 6, 5, 4, 3, 1, 3, 4, 5, + 6, 6, 8, 11, 13, 14, 14, 15, 17, 18, 18, +}; + +static const uint32_t huff_iid_df0_codes[] = { + 0x01FFFB, 0x01FFFC, 0x01FFFD, 0x01FFFA, 0x00FFFC, 0x007FFC, 0x001FFD, + 0x0003FE, 0x0001FE, 0x00007E, 0x00003C, 0x00001D, 0x00000D, 0x000005, + 0x000000, 0x000004, 0x00000C, 0x00001C, 0x00003D, 0x00003E, 0x0000FE, + 0x0007FE, 0x001FFC, 0x003FFC, 0x003FFD, 0x007FFD, 0x01FFFE, 0x03FFFE, + 0x03FFFF, +}; + +static const uint8_t huff_iid_dt0_bits[] = { + 19, 19, 19, 20, 20, 20, 17, 15, 12, 10, 8, 6, 4, 2, 1, 3, 5, 7, + 9, 11, 13, 14, 17, 19, 20, 20, 20, 20, 20, +}; + +static const uint32_t huff_iid_dt0_codes[] = { + 0x07FFF9, 0x07FFFA, 0x07FFFB, 0x0FFFF8, 0x0FFFF9, 0x0FFFFA, 0x01FFFD, + 0x007FFE, 0x000FFE, 0x0003FE, 0x0000FE, 0x00003E, 0x00000E, 0x000002, + 0x000000, 0x000006, 0x00001E, 0x00007E, 0x0001FE, 0x0007FE, 0x001FFE, + 0x003FFE, 0x01FFFC, 0x07FFF8, 0x0FFFFB, 0x0FFFFC, 0x0FFFFD, 0x0FFFFE, + 0x0FFFFF, +}; + +static const uint8_t huff_icc_df_bits[] = { + 14, 14, 12, 10, 7, 5, 3, 1, 2, 4, 6, 8, 9, 11, 13, +}; + +static const uint16_t huff_icc_df_codes[] = { + 0x3FFF, 0x3FFE, 0x0FFE, 0x03FE, 0x007E, 0x001E, 0x0006, 0x0000, + 0x0002, 0x000E, 0x003E, 0x00FE, 0x01FE, 0x07FE, 0x1FFE, +}; + +static const uint8_t huff_icc_dt_bits[] = { + 14, 13, 11, 9, 7, 5, 3, 1, 2, 4, 6, 8, 10, 12, 14, +}; + +static const uint16_t huff_icc_dt_codes[] = { + 0x3FFE, 0x1FFE, 0x07FE, 0x01FE, 0x007E, 0x001E, 0x0006, 0x0000, + 0x0002, 0x000E, 0x003E, 0x00FE, 0x03FE, 0x0FFE, 0x3FFF, +}; + +static const uint8_t huff_ipd_df_bits[] = { + 1, 3, 4, 4, 4, 4, 4, 4, +}; + +static const uint8_t huff_ipd_df_codes[] = { + 0x01, 0x00, 0x06, 0x04, 0x02, 0x03, 0x05, 0x07, +}; + +static const uint8_t huff_ipd_dt_bits[] = { + 1, 3, 4, 5, 5, 4, 4, 3, +}; + +static const uint8_t huff_ipd_dt_codes[] = { + 0x01, 0x02, 0x02, 0x03, 0x02, 0x00, 0x03, 0x03, +}; + +static const uint8_t huff_opd_df_bits[] = { + 1, 3, 4, 4, 5, 5, 4, 3, +}; + +static const uint8_t huff_opd_df_codes[] = { + 0x01, 0x01, 0x06, 0x04, 0x0F, 0x0E, 0x05, 0x00, +}; + +static const uint8_t huff_opd_dt_bits[] = { + 1, 3, 4, 5, 5, 4, 4, 3, +}; + +static const uint8_t huff_opd_dt_codes[] = { + 0x01, 0x02, 0x01, 0x07, 0x06, 0x00, 0x02, 0x03, +}; + +static const int8_t huff_offset[] = { + 30, 30, + 14, 14, + 7, 7, + 0, 0, + 0, 0, +}; + +///Table 8.48 +static const int8_t k_to_i_20[] = { + 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, 15, + 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19 +}; +///Table 8.49 +static const int8_t k_to_i_34[] = { + 0, 1, 2, 3, 4, 5, 6, 6, 7, 2, 1, 0, 10, 10, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 9, 14, 11, 12, 13, 14, 15, 16, 13, 16, 17, 18, 19, 20, 21, + 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29, + 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33 +}; + +static const INTFLOAT g1_Q2[] = { + Q31(0.0f), Q31(0.01899487526049f), Q31(0.0f), Q31(-0.07293139167538f), + Q31(0.0f), Q31(0.30596630545168f), Q31(0.5f) +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp.asm new file mode 100644 index 0000000000..4acd087c85 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp.asm @@ -0,0 +1,487 @@ +;****************************************************************************** +;* SIMD optimized MPEG-4 Parametric Stereo decoding functions +;* +;* Copyright (C) 2015 James Almer +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA + +ps_p1m1p1m1: dd 0, 0x80000000, 0, 0x80000000 + +SECTION .text + +;************************************************************************* +;void ff_ps_add_squares_(float *dst, const float (*src)[2], int n); +;************************************************************************* +%macro PS_ADD_SQUARES 1 +cglobal ps_add_squares, 3, 3, %1, dst, src, n + shl nd, 3 + add srcq, nq + neg nq + +align 16 +.loop: + movaps m0, [srcq+nq] + movaps m1, [srcq+nq+mmsize] + mulps m0, m0 + mulps m1, m1 + HADDPS m0, m1, m2 + addps m0, [dstq] + movaps [dstq], m0 + add dstq, mmsize + add nq, mmsize*2 + jl .loop + REP_RET +%endmacro + +INIT_XMM sse +PS_ADD_SQUARES 2 +INIT_XMM sse3 +PS_ADD_SQUARES 3 + +;******************************************************************* +;void ff_ps_mul_pair_single_sse(float (*dst)[2], float (*src0)[2], +; float *src1, int n); +;******************************************************************* +INIT_XMM sse +cglobal ps_mul_pair_single, 4, 4, 4, dst, src1, src2, n + shl nd, 3 + add src1q, nq + add dstq, nq + neg nq + +align 16 +.loop: + movu m0, [src1q+nq] + movu m1, [src1q+nq+mmsize] + mova m2, [src2q] + mova m3, m2 + unpcklps m2, m2 + unpckhps m3, m3 + mulps m0, m2 + mulps m1, m3 + mova [dstq+nq], m0 + mova [dstq+nq+mmsize], m1 + add src2q, mmsize + add nq, mmsize*2 + jl .loop + REP_RET + +;*********************************************************************** +;void ff_ps_stereo_interpolate_sse3(float (*l)[2], float (*r)[2], +; float h[2][4], float h_step[2][4], +; int len); +;*********************************************************************** +INIT_XMM sse3 +cglobal ps_stereo_interpolate, 5, 5, 6, l, r, h, h_step, n + movaps m0, [hq] + movaps m1, [h_stepq] + unpcklps m4, m0, m0 + unpckhps m0, m0 + unpcklps m5, m1, m1 + unpckhps m1, m1 + shl nd, 3 + add lq, nq + add rq, nq + neg nq + +align 16 +.loop: + addps m4, m5 + addps m0, m1 + movddup m2, [lq+nq] + movddup m3, [rq+nq] + mulps m2, m4 + mulps m3, m0 + addps m2, m3 + movsd [lq+nq], m2 + movhps [rq+nq], m2 + add nq, 8 + jl .loop + REP_RET + +;*************************************************************************** +;void ps_stereo_interpolate_ipdopd_sse3(float (*l)[2], float (*r)[2], +; float h[2][4], float h_step[2][4], +; int len); +;*************************************************************************** +INIT_XMM sse3 +cglobal ps_stereo_interpolate_ipdopd, 5, 5, 10, l, r, h, h_step, n + movaps m0, [hq] + movaps m1, [hq+mmsize] +%if ARCH_X86_64 + movaps m8, [h_stepq] + movaps m9, [h_stepq+mmsize] + %define H_STEP0 m8 + %define H_STEP1 m9 +%else + %define H_STEP0 [h_stepq] + %define H_STEP1 [h_stepq+mmsize] +%endif + shl nd, 3 + add lq, nq + add rq, nq + neg nq + +align 16 +.loop: + addps m0, H_STEP0 + addps m1, H_STEP1 + movddup m2, [lq+nq] + movddup m3, [rq+nq] + shufps m4, m2, m2, q2301 + shufps m5, m3, m3, q2301 + unpcklps m6, m0, m0 + unpckhps m7, m0, m0 + mulps m2, m6 + mulps m3, m7 + unpcklps m6, m1, m1 + unpckhps m7, m1, m1 + mulps m4, m6 + mulps m5, m7 + addps m2, m3 + addsubps m2, m4 + addsubps m2, m5 + movsd [lq+nq], m2 + movhps [rq+nq], m2 + add nq, 8 + jl .loop + REP_RET + +;********************************************************** +;void ps_hybrid_analysis_ileave_sse(float out[2][38][64], +; float (*in)[32][2], +; int i, int len) +;********************************************************** +INIT_XMM sse +cglobal ps_hybrid_analysis_ileave, 3, 7, 5, out, in, i, len, in0, in1, tmp + movsxdifnidn iq, id + mov lend, 32 << 3 + lea inq, [inq+iq*4] + mov tmpd, id + shl tmpd, 8 + add outq, tmpq + mov tmpd, 64 + sub tmpd, id + mov id, tmpd + + test id, 1 + jne .loop4 + test id, 2 + jne .loop8 + +align 16 +.loop16: + mov in0q, inq + mov in1q, 38*64*4 + add in1q, in0q + mov tmpd, lend + +.inner_loop16: + movaps m0, [in0q] + movaps m1, [in1q] + movaps m2, [in0q+lenq] + movaps m3, [in1q+lenq] + TRANSPOSE4x4PS 0, 1, 2, 3, 4 + movaps [outq], m0 + movaps [outq+lenq], m1 + movaps [outq+lenq*2], m2 + movaps [outq+3*32*2*4], m3 + lea in0q, [in0q+lenq*2] + lea in1q, [in1q+lenq*2] + add outq, mmsize + sub tmpd, mmsize + jg .inner_loop16 + add inq, 16 + add outq, 3*32*2*4 + sub id, 4 + jg .loop16 + RET + +align 16 +.loop8: + mov in0q, inq + mov in1q, 38*64*4 + add in1q, in0q + mov tmpd, lend + +.inner_loop8: + movlps m0, [in0q] + movlps m1, [in1q] + movhps m0, [in0q+lenq] + movhps m1, [in1q+lenq] + SBUTTERFLYPS 0, 1, 2 + SBUTTERFLYPD 0, 1, 2 + movaps [outq], m0 + movaps [outq+lenq], m1 + lea in0q, [in0q+lenq*2] + lea in1q, [in1q+lenq*2] + add outq, mmsize + sub tmpd, mmsize + jg .inner_loop8 + add inq, 8 + add outq, lenq + sub id, 2 + jg .loop16 + RET + +align 16 +.loop4: + mov in0q, inq + mov in1q, 38*64*4 + add in1q, in0q + mov tmpd, lend + +.inner_loop4: + movss m0, [in0q] + movss m1, [in1q] + movss m2, [in0q+lenq] + movss m3, [in1q+lenq] + movlhps m0, m1 + movlhps m2, m3 + shufps m0, m2, q2020 + movaps [outq], m0 + lea in0q, [in0q+lenq*2] + lea in1q, [in1q+lenq*2] + add outq, mmsize + sub tmpd, mmsize + jg .inner_loop4 + add inq, 4 + sub id, 1 + test id, 2 + jne .loop8 + cmp id, 4 + jge .loop16 + RET + +;*********************************************************** +;void ps_hybrid_synthesis_deint_sse4(float out[2][38][64], +; float (*in)[32][2], +; int i, int len) +;*********************************************************** +%macro HYBRID_SYNTHESIS_DEINT 0 +cglobal ps_hybrid_synthesis_deint, 3, 7, 5, out, in, i, len, out0, out1, tmp +%if cpuflag(sse4) +%define MOVH movsd +%else +%define MOVH movlps +%endif + movsxdifnidn iq, id + mov lend, 32 << 3 + lea outq, [outq+iq*4] + mov tmpd, id + shl tmpd, 8 + add inq, tmpq + mov tmpd, 64 + sub tmpd, id + mov id, tmpd + + test id, 1 + jne .loop4 + test id, 2 + jne .loop8 + +align 16 +.loop16: + mov out0q, outq + mov out1q, 38*64*4 + add out1q, out0q + mov tmpd, lend + +.inner_loop16: + movaps m0, [inq] + movaps m1, [inq+lenq] + movaps m2, [inq+lenq*2] + movaps m3, [inq+3*32*2*4] + TRANSPOSE4x4PS 0, 1, 2, 3, 4 + movaps [out0q], m0 + movaps [out1q], m1 + movaps [out0q+lenq], m2 + movaps [out1q+lenq], m3 + lea out0q, [out0q+lenq*2] + lea out1q, [out1q+lenq*2] + add inq, mmsize + sub tmpd, mmsize + jg .inner_loop16 + add outq, 16 + add inq, 3*32*2*4 + sub id, 4 + jg .loop16 + RET + +align 16 +.loop8: + mov out0q, outq + mov out1q, 38*64*4 + add out1q, out0q + mov tmpd, lend + +.inner_loop8: + movaps m0, [inq] + movaps m1, [inq+lenq] + SBUTTERFLYPS 0, 1, 2 + SBUTTERFLYPD 0, 1, 2 + MOVH [out0q], m0 + MOVH [out1q], m1 + movhps [out0q+lenq], m0 + movhps [out1q+lenq], m1 + lea out0q, [out0q+lenq*2] + lea out1q, [out1q+lenq*2] + add inq, mmsize + sub tmpd, mmsize + jg .inner_loop8 + add outq, 8 + add inq, lenq + sub id, 2 + jg .loop16 + RET + +align 16 +.loop4: + mov out0q, outq + mov out1q, 38*64*4 + add out1q, out0q + mov tmpd, lend + +.inner_loop4: + movaps m0, [inq] + movss [out0q], m0 +%if cpuflag(sse4) + extractps [out1q], m0, 1 + extractps [out0q+lenq], m0, 2 + extractps [out1q+lenq], m0, 3 +%else + movhlps m1, m0 + movss [out0q+lenq], m1 + shufps m0, m0, 0xb1 + movss [out1q], m0 + movhlps m1, m0 + movss [out1q+lenq], m1 +%endif + lea out0q, [out0q+lenq*2] + lea out1q, [out1q+lenq*2] + add inq, mmsize + sub tmpd, mmsize + jg .inner_loop4 + add outq, 4 + sub id, 1 + test id, 2 + jne .loop8 + cmp id, 4 + jge .loop16 + RET +%endmacro + +INIT_XMM sse +HYBRID_SYNTHESIS_DEINT +INIT_XMM sse4 +HYBRID_SYNTHESIS_DEINT + +;******************************************************************* +;void ff_ps_hybrid_analysis_(float (*out)[2], float (*in)[2], +; const float (*filter)[8][2], +; ptrdiff_t stride, int n); +;******************************************************************* +%macro PS_HYBRID_ANALYSIS_LOOP 3 + movu %1, [inq+mmsize*%3] + movu m1, [inq+mmsize*(5-%3)+8] +%if cpuflag(sse3) + pshufd %2, %1, q2301 + pshufd m4, m1, q0123 + pshufd m1, m1, q1032 + pshufd m2, [filterq+nq+mmsize*%3], q2301 + addsubps %2, m4 + addsubps %1, m1 +%else + mova m2, [filterq+nq+mmsize*%3] + mova %2, %1 + mova m4, m1 + shufps %2, %2, q2301 + shufps m4, m4, q0123 + shufps m1, m1, q1032 + shufps m2, m2, q2301 + xorps m4, m7 + xorps m1, m7 + subps %2, m4 + subps %1, m1 +%endif + mulps %2, m2 + mulps %1, m2 +%if %3 + addps m3, %2 + addps m0, %1 +%endif +%endmacro + +%macro PS_HYBRID_ANALYSIS 0 +cglobal ps_hybrid_analysis, 5, 5, 8, out, in, filter, stride, n +%if cpuflag(sse3) +%define MOVH movsd +%else +%define MOVH movlps +%endif + shl strideq, 3 + shl nd, 6 + add filterq, nq + neg nq + mova m7, [ps_p1m1p1m1] + +align 16 +.loop: + PS_HYBRID_ANALYSIS_LOOP m0, m3, 0 + PS_HYBRID_ANALYSIS_LOOP m5, m6, 1 + PS_HYBRID_ANALYSIS_LOOP m5, m6, 2 + +%if cpuflag(sse3) + pshufd m3, m3, q2301 + xorps m0, m7 + hsubps m3, m0 + pshufd m1, m3, q0020 + pshufd m3, m3, q0031 + addps m1, m3 + movsd m2, [inq+6*8] +%else + mova m1, m3 + mova m2, m0 + shufps m1, m1, q2301 + shufps m2, m2, q2301 + subps m1, m3 + addps m2, m0 + unpcklps m3, m1, m2 + unpckhps m1, m2 + addps m1, m3 + movu m2, [inq+6*8] ; faster than movlps and no risk of overread +%endif + movss m3, [filterq+nq+8*6] + SPLATD m3 + mulps m2, m3 + addps m1, m2 + MOVH [outq], m1 + add outq, strideq + add nq, 64 + jl .loop + REP_RET +%endmacro + +INIT_XMM sse +PS_HYBRID_ANALYSIS +INIT_XMM sse3 +PS_HYBRID_ANALYSIS diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp.h new file mode 100644 index 0000000000..917ac5303f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AACPSDSP_H +#define AVCODEC_AACPSDSP_H + +#include + +#include "aac_defines.h" + +#define PS_QMF_TIME_SLOTS 32 +#define PS_AP_LINKS 3 +#define PS_MAX_AP_DELAY 5 + +typedef struct PSDSPContext { + void (*add_squares)(INTFLOAT *dst, const INTFLOAT (*src)[2], int n); + void (*mul_pair_single)(INTFLOAT (*dst)[2], INTFLOAT (*src0)[2], INTFLOAT *src1, + int n); + void (*hybrid_analysis)(INTFLOAT (*out)[2], INTFLOAT (*in)[2], + const INTFLOAT (*filter)[8][2], + ptrdiff_t stride, int n); + void (*hybrid_analysis_ileave)(INTFLOAT (*out)[32][2], INTFLOAT L[2][38][64], + int i, int len); + void (*hybrid_synthesis_deint)(INTFLOAT out[2][38][64], INTFLOAT (*in)[32][2], + int i, int len); + void (*decorrelate)(INTFLOAT (*out)[2], INTFLOAT (*delay)[2], + INTFLOAT (*ap_delay)[PS_QMF_TIME_SLOTS+PS_MAX_AP_DELAY][2], + const INTFLOAT phi_fract[2], const INTFLOAT (*Q_fract)[2], + const INTFLOAT *transient_gain, + INTFLOAT g_decay_slope, + int len); + void (*stereo_interpolate[2])(INTFLOAT (*l)[2], INTFLOAT (*r)[2], + INTFLOAT h[2][4], INTFLOAT h_step[2][4], + int len); +} PSDSPContext; + +void AAC_RENAME(ff_psdsp_init)(PSDSPContext *s); +void ff_psdsp_init_arm(PSDSPContext *s); +void ff_psdsp_init_aarch64(PSDSPContext *s); +void ff_psdsp_init_mips(PSDSPContext *s); +void ff_psdsp_init_x86(PSDSPContext *s); + +#endif /* AVCODEC_AACPSDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_fixed.c new file mode 100644 index 0000000000..2413295113 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_fixed.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 1 + +#include "aacpsdsp_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_float.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_float.c new file mode 100644 index 0000000000..99aa650acf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_float.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 0 + +#include "aacpsdsp_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_init.c new file mode 100644 index 0000000000..21f00efa24 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_init.c @@ -0,0 +1,72 @@ +/* + * SIMD optimized MPEG-4 Parametric Stereo decoding functions + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" + +#include "libavutil/x86/cpu.h" +#include "libavutil/attributes.h" +#include "libavcodec/aacpsdsp.h" + +void ff_ps_add_squares_sse (float *dst, const float (*src)[2], int n); +void ff_ps_add_squares_sse3 (float *dst, const float (*src)[2], int n); +void ff_ps_mul_pair_single_sse (float (*dst)[2], float (*src0)[2], + float *src1, int n); +void ff_ps_hybrid_analysis_sse (float (*out)[2], float (*in)[2], + const float (*filter)[8][2], + ptrdiff_t stride, int n); +void ff_ps_hybrid_analysis_sse3(float (*out)[2], float (*in)[2], + const float (*filter)[8][2], + ptrdiff_t stride, int n); +void ff_ps_stereo_interpolate_sse3(float (*l)[2], float (*r)[2], + float h[2][4], float h_step[2][4], + int len); +void ff_ps_stereo_interpolate_ipdopd_sse3(float (*l)[2], float (*r)[2], + float h[2][4], float h_step[2][4], + int len); +void ff_ps_hybrid_synthesis_deint_sse(float out[2][38][64], float (*in)[32][2], + int i, int len); +void ff_ps_hybrid_synthesis_deint_sse4(float out[2][38][64], float (*in)[32][2], + int i, int len); +void ff_ps_hybrid_analysis_ileave_sse(float (*out)[32][2], float L[2][38][64], + int i, int len); + +av_cold void ff_psdsp_init_x86(PSDSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE(cpu_flags)) { + s->add_squares = ff_ps_add_squares_sse; + s->mul_pair_single = ff_ps_mul_pair_single_sse; + s->hybrid_analysis_ileave = ff_ps_hybrid_analysis_ileave_sse; + s->hybrid_synthesis_deint = ff_ps_hybrid_synthesis_deint_sse; + s->hybrid_analysis = ff_ps_hybrid_analysis_sse; + } + if (EXTERNAL_SSE3(cpu_flags)) { + s->add_squares = ff_ps_add_squares_sse3; + s->stereo_interpolate[0] = ff_ps_stereo_interpolate_sse3; + s->stereo_interpolate[1] = ff_ps_stereo_interpolate_ipdopd_sse3; + s->hybrid_analysis = ff_ps_hybrid_analysis_sse3; + } + if (EXTERNAL_SSE4(cpu_flags)) { + s->hybrid_synthesis_deint = ff_ps_hybrid_synthesis_deint_sse4; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_template.c new file mode 100644 index 0000000000..eef8adc7e2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsdsp_template.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Note: Rounding-to-nearest used unless otherwise stated + * + */ +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "aacpsdsp.h" + +static void ps_add_squares_c(INTFLOAT *dst, const INTFLOAT (*src)[2], int n) +{ + int i; + for (i = 0; i < n; i++) + dst[i] += (UINTFLOAT)AAC_MADD28(src[i][0], src[i][0], src[i][1], src[i][1]); +} + +static void ps_mul_pair_single_c(INTFLOAT (*dst)[2], INTFLOAT (*src0)[2], INTFLOAT *src1, + int n) +{ + int i; + for (i = 0; i < n; i++) { + dst[i][0] = AAC_MUL16(src0[i][0], src1[i]); + dst[i][1] = AAC_MUL16(src0[i][1], src1[i]); + } +} + +static void ps_hybrid_analysis_c(INTFLOAT (*out)[2], INTFLOAT (*in)[2], + const INTFLOAT (*filter)[8][2], + ptrdiff_t stride, int n) +{ + int i, j; + + for (i = 0; i < n; i++) { + INT64FLOAT sum_re = (INT64FLOAT)filter[i][6][0] * in[6][0]; + INT64FLOAT sum_im = (INT64FLOAT)filter[i][6][0] * in[6][1]; + + for (j = 0; j < 6; j++) { + INT64FLOAT in0_re = in[j][0]; + INT64FLOAT in0_im = in[j][1]; + INT64FLOAT in1_re = in[12-j][0]; + INT64FLOAT in1_im = in[12-j][1]; + sum_re += (INT64FLOAT)filter[i][j][0] * (in0_re + in1_re) - + (INT64FLOAT)filter[i][j][1] * (in0_im - in1_im); + sum_im += (INT64FLOAT)filter[i][j][0] * (in0_im + in1_im) + + (INT64FLOAT)filter[i][j][1] * (in0_re - in1_re); + } +#if USE_FIXED + out[i * stride][0] = (int)((sum_re + 0x40000000) >> 31); + out[i * stride][1] = (int)((sum_im + 0x40000000) >> 31); +#else + out[i * stride][0] = sum_re; + out[i * stride][1] = sum_im; +#endif /* USE_FIXED */ + } +} + +static void ps_hybrid_analysis_ileave_c(INTFLOAT (*out)[32][2], INTFLOAT L[2][38][64], + int i, int len) +{ + int j; + + for (; i < 64; i++) { + for (j = 0; j < len; j++) { + out[i][j][0] = L[0][j][i]; + out[i][j][1] = L[1][j][i]; + } + } +} + +static void ps_hybrid_synthesis_deint_c(INTFLOAT out[2][38][64], + INTFLOAT (*in)[32][2], + int i, int len) +{ + int n; + + for (; i < 64; i++) { + for (n = 0; n < len; n++) { + out[0][n][i] = in[i][n][0]; + out[1][n][i] = in[i][n][1]; + } + } +} + +static void ps_decorrelate_c(INTFLOAT (*out)[2], INTFLOAT (*delay)[2], + INTFLOAT (*ap_delay)[PS_QMF_TIME_SLOTS + PS_MAX_AP_DELAY][2], + const INTFLOAT phi_fract[2], const INTFLOAT (*Q_fract)[2], + const INTFLOAT *transient_gain, + INTFLOAT g_decay_slope, + int len) +{ + static const INTFLOAT a[] = { Q31(0.65143905753106f), + Q31(0.56471812200776f), + Q31(0.48954165955695f) }; + INTFLOAT ag[PS_AP_LINKS]; + int m, n; + + for (m = 0; m < PS_AP_LINKS; m++) + ag[m] = AAC_MUL30(a[m], g_decay_slope); + + for (n = 0; n < len; n++) { + INTFLOAT in_re = AAC_MSUB30(delay[n][0], phi_fract[0], delay[n][1], phi_fract[1]); + INTFLOAT in_im = AAC_MADD30(delay[n][0], phi_fract[1], delay[n][1], phi_fract[0]); + for (m = 0; m < PS_AP_LINKS; m++) { + INTFLOAT a_re = AAC_MUL31(ag[m], in_re); + INTFLOAT a_im = AAC_MUL31(ag[m], in_im); + INTFLOAT link_delay_re = ap_delay[m][n+2-m][0]; + INTFLOAT link_delay_im = ap_delay[m][n+2-m][1]; + INTFLOAT fractional_delay_re = Q_fract[m][0]; + INTFLOAT fractional_delay_im = Q_fract[m][1]; + INTFLOAT apd_re = in_re; + INTFLOAT apd_im = in_im; + in_re = AAC_MSUB30(link_delay_re, fractional_delay_re, + link_delay_im, fractional_delay_im); + in_re -= (UINTFLOAT)a_re; + in_im = AAC_MADD30(link_delay_re, fractional_delay_im, + link_delay_im, fractional_delay_re); + in_im -= (UINTFLOAT)a_im; + ap_delay[m][n+5][0] = apd_re + (UINTFLOAT)AAC_MUL31(ag[m], in_re); + ap_delay[m][n+5][1] = apd_im + (UINTFLOAT)AAC_MUL31(ag[m], in_im); + } + out[n][0] = AAC_MUL16(transient_gain[n], in_re); + out[n][1] = AAC_MUL16(transient_gain[n], in_im); + } +} + +static void ps_stereo_interpolate_c(INTFLOAT (*l)[2], INTFLOAT (*r)[2], + INTFLOAT h[2][4], INTFLOAT h_step[2][4], + int len) +{ + INTFLOAT h0 = h[0][0]; + INTFLOAT h1 = h[0][1]; + INTFLOAT h2 = h[0][2]; + INTFLOAT h3 = h[0][3]; + UINTFLOAT hs0 = h_step[0][0]; + UINTFLOAT hs1 = h_step[0][1]; + UINTFLOAT hs2 = h_step[0][2]; + UINTFLOAT hs3 = h_step[0][3]; + int n; + + for (n = 0; n < len; n++) { + //l is s, r is d + INTFLOAT l_re = l[n][0]; + INTFLOAT l_im = l[n][1]; + INTFLOAT r_re = r[n][0]; + INTFLOAT r_im = r[n][1]; + h0 += hs0; + h1 += hs1; + h2 += hs2; + h3 += hs3; + l[n][0] = AAC_MADD30(h0, l_re, h2, r_re); + l[n][1] = AAC_MADD30(h0, l_im, h2, r_im); + r[n][0] = AAC_MADD30(h1, l_re, h3, r_re); + r[n][1] = AAC_MADD30(h1, l_im, h3, r_im); + } +} + +static void ps_stereo_interpolate_ipdopd_c(INTFLOAT (*l)[2], INTFLOAT (*r)[2], + INTFLOAT h[2][4], INTFLOAT h_step[2][4], + int len) +{ + INTFLOAT h00 = h[0][0], h10 = h[1][0]; + INTFLOAT h01 = h[0][1], h11 = h[1][1]; + INTFLOAT h02 = h[0][2], h12 = h[1][2]; + INTFLOAT h03 = h[0][3], h13 = h[1][3]; + UINTFLOAT hs00 = h_step[0][0], hs10 = h_step[1][0]; + UINTFLOAT hs01 = h_step[0][1], hs11 = h_step[1][1]; + UINTFLOAT hs02 = h_step[0][2], hs12 = h_step[1][2]; + UINTFLOAT hs03 = h_step[0][3], hs13 = h_step[1][3]; + int n; + + for (n = 0; n < len; n++) { + //l is s, r is d + INTFLOAT l_re = l[n][0]; + INTFLOAT l_im = l[n][1]; + INTFLOAT r_re = r[n][0]; + INTFLOAT r_im = r[n][1]; + h00 += hs00; + h01 += hs01; + h02 += hs02; + h03 += hs03; + h10 += hs10; + h11 += hs11; + h12 += hs12; + h13 += hs13; + + l[n][0] = AAC_MSUB30_V8(h00, l_re, h02, r_re, h10, l_im, h12, r_im); + l[n][1] = AAC_MADD30_V8(h00, l_im, h02, r_im, h10, l_re, h12, r_re); + r[n][0] = AAC_MSUB30_V8(h01, l_re, h03, r_re, h11, l_im, h13, r_im); + r[n][1] = AAC_MADD30_V8(h01, l_im, h03, r_im, h11, l_re, h13, r_re); + } +} + +av_cold void AAC_RENAME(ff_psdsp_init)(PSDSPContext *s) +{ + s->add_squares = ps_add_squares_c; + s->mul_pair_single = ps_mul_pair_single_c; + s->hybrid_analysis = ps_hybrid_analysis_c; + s->hybrid_analysis_ileave = ps_hybrid_analysis_ileave_c; + s->hybrid_synthesis_deint = ps_hybrid_synthesis_deint_c; + s->decorrelate = ps_decorrelate_c; + s->stereo_interpolate[0] = ps_stereo_interpolate_c; + s->stereo_interpolate[1] = ps_stereo_interpolate_ipdopd_c; + +#if !USE_FIXED + if (ARCH_ARM) + ff_psdsp_init_arm(s); + if (ARCH_AARCH64) + ff_psdsp_init_aarch64(s); + if (ARCH_MIPS) + ff_psdsp_init_mips(s); + if (ARCH_X86) + ff_psdsp_init_x86(s); +#endif /* !USE_FIXED */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsy.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsy.c new file mode 100644 index 0000000000..fca692cb15 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacpsy.c @@ -0,0 +1,1025 @@ +/* + * AAC encoder psychoacoustic model + * Copyright (C) 2008 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC encoder psychoacoustic model + */ + +#include "libavutil/attributes.h" +#include "libavutil/ffmath.h" + +#include "avcodec.h" +#include "aactab.h" +#include "psymodel.h" + +/*********************************** + * TODOs: + * try other bitrate controlling mechanism (maybe use ratecontrol.c?) + * control quality for quality-based output + **********************************/ + +/** + * constants for 3GPP AAC psychoacoustic model + * @{ + */ +#define PSY_3GPP_THR_SPREAD_HI 1.5f // spreading factor for low-to-hi threshold spreading (15 dB/Bark) +#define PSY_3GPP_THR_SPREAD_LOW 3.0f // spreading factor for hi-to-low threshold spreading (30 dB/Bark) +/* spreading factor for low-to-hi energy spreading, long block, > 22kbps/channel (20dB/Bark) */ +#define PSY_3GPP_EN_SPREAD_HI_L1 2.0f +/* spreading factor for low-to-hi energy spreading, long block, <= 22kbps/channel (15dB/Bark) */ +#define PSY_3GPP_EN_SPREAD_HI_L2 1.5f +/* spreading factor for low-to-hi energy spreading, short block (15 dB/Bark) */ +#define PSY_3GPP_EN_SPREAD_HI_S 1.5f +/* spreading factor for hi-to-low energy spreading, long block (30dB/Bark) */ +#define PSY_3GPP_EN_SPREAD_LOW_L 3.0f +/* spreading factor for hi-to-low energy spreading, short block (20dB/Bark) */ +#define PSY_3GPP_EN_SPREAD_LOW_S 2.0f + +#define PSY_3GPP_RPEMIN 0.01f +#define PSY_3GPP_RPELEV 2.0f + +#define PSY_3GPP_C1 3.0f /* log2(8) */ +#define PSY_3GPP_C2 1.3219281f /* log2(2.5) */ +#define PSY_3GPP_C3 0.55935729f /* 1 - C2 / C1 */ + +#define PSY_SNR_1DB 7.9432821e-1f /* -1dB */ +#define PSY_SNR_25DB 3.1622776e-3f /* -25dB */ + +#define PSY_3GPP_SAVE_SLOPE_L -0.46666667f +#define PSY_3GPP_SAVE_SLOPE_S -0.36363637f +#define PSY_3GPP_SAVE_ADD_L -0.84285712f +#define PSY_3GPP_SAVE_ADD_S -0.75f +#define PSY_3GPP_SPEND_SLOPE_L 0.66666669f +#define PSY_3GPP_SPEND_SLOPE_S 0.81818181f +#define PSY_3GPP_SPEND_ADD_L -0.35f +#define PSY_3GPP_SPEND_ADD_S -0.26111111f +#define PSY_3GPP_CLIP_LO_L 0.2f +#define PSY_3GPP_CLIP_LO_S 0.2f +#define PSY_3GPP_CLIP_HI_L 0.95f +#define PSY_3GPP_CLIP_HI_S 0.75f + +#define PSY_3GPP_AH_THR_LONG 0.5f +#define PSY_3GPP_AH_THR_SHORT 0.63f + +#define PSY_PE_FORGET_SLOPE 511 + +enum { + PSY_3GPP_AH_NONE, + PSY_3GPP_AH_INACTIVE, + PSY_3GPP_AH_ACTIVE +}; + +#define PSY_3GPP_BITS_TO_PE(bits) ((bits) * 1.18f) +#define PSY_3GPP_PE_TO_BITS(bits) ((bits) / 1.18f) + +/* LAME psy model constants */ +#define PSY_LAME_FIR_LEN 21 ///< LAME psy model FIR order +#define AAC_BLOCK_SIZE_LONG 1024 ///< long block size +#define AAC_BLOCK_SIZE_SHORT 128 ///< short block size +#define AAC_NUM_BLOCKS_SHORT 8 ///< number of blocks in a short sequence +#define PSY_LAME_NUM_SUBBLOCKS 3 ///< Number of sub-blocks in each short block + +/** + * @} + */ + +/** + * information for single band used by 3GPP TS26.403-inspired psychoacoustic model + */ +typedef struct AacPsyBand{ + float energy; ///< band energy + float thr; ///< energy threshold + float thr_quiet; ///< threshold in quiet + float nz_lines; ///< number of non-zero spectral lines + float active_lines; ///< number of active spectral lines + float pe; ///< perceptual entropy + float pe_const; ///< constant part of the PE calculation + float norm_fac; ///< normalization factor for linearization + int avoid_holes; ///< hole avoidance flag +}AacPsyBand; + +/** + * single/pair channel context for psychoacoustic model + */ +typedef struct AacPsyChannel{ + AacPsyBand band[128]; ///< bands information + AacPsyBand prev_band[128]; ///< bands information from the previous frame + + float win_energy; ///< sliding average of channel energy + float iir_state[2]; ///< hi-pass IIR filter state + uint8_t next_grouping; ///< stored grouping scheme for the next frame (in case of 8 short window sequence) + enum WindowSequence next_window_seq; ///< window sequence to be used in the next frame + /* LAME psy model specific members */ + float attack_threshold; ///< attack threshold for this channel + float prev_energy_subshort[AAC_NUM_BLOCKS_SHORT * PSY_LAME_NUM_SUBBLOCKS]; + int prev_attack; ///< attack value for the last short block in the previous sequence +}AacPsyChannel; + +/** + * psychoacoustic model frame type-dependent coefficients + */ +typedef struct AacPsyCoeffs{ + float ath; ///< absolute threshold of hearing per bands + float barks; ///< Bark value for each spectral band in long frame + float spread_low[2]; ///< spreading factor for low-to-high threshold spreading in long frame + float spread_hi [2]; ///< spreading factor for high-to-low threshold spreading in long frame + float min_snr; ///< minimal SNR +}AacPsyCoeffs; + +/** + * 3GPP TS26.403-inspired psychoacoustic model specific data + */ +typedef struct AacPsyContext{ + int chan_bitrate; ///< bitrate per channel + int frame_bits; ///< average bits per frame + int fill_level; ///< bit reservoir fill level + struct { + float min; ///< minimum allowed PE for bit factor calculation + float max; ///< maximum allowed PE for bit factor calculation + float previous; ///< allowed PE of the previous frame + float correction; ///< PE correction factor + } pe; + AacPsyCoeffs psy_coef[2][64]; + AacPsyChannel *ch; + float global_quality; ///< normalized global quality taken from avctx +}AacPsyContext; + +/** + * LAME psy model preset struct + */ +typedef struct PsyLamePreset { + int quality; ///< Quality to map the rest of the vaules to. + /* This is overloaded to be both kbps per channel in ABR mode, and + * requested quality in constant quality mode. + */ + float st_lrm; ///< short threshold for L, R, and M channels +} PsyLamePreset; + +/** + * LAME psy model preset table for ABR + */ +static const PsyLamePreset psy_abr_map[] = { +/* TODO: Tuning. These were taken from LAME. */ +/* kbps/ch st_lrm */ + { 8, 6.60}, + { 16, 6.60}, + { 24, 6.60}, + { 32, 6.60}, + { 40, 6.60}, + { 48, 6.60}, + { 56, 6.60}, + { 64, 6.40}, + { 80, 6.00}, + { 96, 5.60}, + {112, 5.20}, + {128, 5.20}, + {160, 5.20} +}; + +/** +* LAME psy model preset table for constant quality +*/ +static const PsyLamePreset psy_vbr_map[] = { +/* vbr_q st_lrm */ + { 0, 4.20}, + { 1, 4.20}, + { 2, 4.20}, + { 3, 4.20}, + { 4, 4.20}, + { 5, 4.20}, + { 6, 4.20}, + { 7, 4.20}, + { 8, 4.20}, + { 9, 4.20}, + {10, 4.20} +}; + +/** + * LAME psy model FIR coefficient table + */ +static const float psy_fir_coeffs[] = { + -8.65163e-18 * 2, -0.00851586 * 2, -6.74764e-18 * 2, 0.0209036 * 2, + -3.36639e-17 * 2, -0.0438162 * 2, -1.54175e-17 * 2, 0.0931738 * 2, + -5.52212e-17 * 2, -0.313819 * 2 +}; + +#if ARCH_MIPS +# include "mips/aacpsy_mips.h" +#endif /* ARCH_MIPS */ + +/** + * Calculate the ABR attack threshold from the above LAME psymodel table. + */ +static float lame_calc_attack_threshold(int bitrate) +{ + /* Assume max bitrate to start with */ + int lower_range = 12, upper_range = 12; + int lower_range_kbps = psy_abr_map[12].quality; + int upper_range_kbps = psy_abr_map[12].quality; + int i; + + /* Determine which bitrates the value specified falls between. + * If the loop ends without breaking our above assumption of 320kbps was correct. + */ + for (i = 1; i < 13; i++) { + if (FFMAX(bitrate, psy_abr_map[i].quality) != bitrate) { + upper_range = i; + upper_range_kbps = psy_abr_map[i ].quality; + lower_range = i - 1; + lower_range_kbps = psy_abr_map[i - 1].quality; + break; /* Upper range found */ + } + } + + /* Determine which range the value specified is closer to */ + if ((upper_range_kbps - bitrate) > (bitrate - lower_range_kbps)) + return psy_abr_map[lower_range].st_lrm; + return psy_abr_map[upper_range].st_lrm; +} + +/** + * LAME psy model specific initialization + */ +static av_cold void lame_window_init(AacPsyContext *ctx, AVCodecContext *avctx) +{ + int i, j; + + for (i = 0; i < avctx->channels; i++) { + AacPsyChannel *pch = &ctx->ch[i]; + + if (avctx->flags & AV_CODEC_FLAG_QSCALE) + pch->attack_threshold = psy_vbr_map[avctx->global_quality / FF_QP2LAMBDA].st_lrm; + else + pch->attack_threshold = lame_calc_attack_threshold(avctx->bit_rate / avctx->channels / 1000); + + for (j = 0; j < AAC_NUM_BLOCKS_SHORT * PSY_LAME_NUM_SUBBLOCKS; j++) + pch->prev_energy_subshort[j] = 10.0f; + } +} + +/** + * Calculate Bark value for given line. + */ +static av_cold float calc_bark(float f) +{ + return 13.3f * atanf(0.00076f * f) + 3.5f * atanf((f / 7500.0f) * (f / 7500.0f)); +} + +#define ATH_ADD 4 +/** + * Calculate ATH value for given frequency. + * Borrowed from Lame. + */ +static av_cold float ath(float f, float add) +{ + f /= 1000.0f; + return 3.64 * pow(f, -0.8) + - 6.8 * exp(-0.6 * (f - 3.4) * (f - 3.4)) + + 6.0 * exp(-0.15 * (f - 8.7) * (f - 8.7)) + + (0.6 + 0.04 * add) * 0.001 * f * f * f * f; +} + +static av_cold int psy_3gpp_init(FFPsyContext *ctx) { + AacPsyContext *pctx; + float bark; + int i, j, g, start; + float prev, minscale, minath, minsnr, pe_min; + int chan_bitrate = ctx->avctx->bit_rate / ((ctx->avctx->flags & AV_CODEC_FLAG_QSCALE) ? 2.0f : ctx->avctx->channels); + + const int bandwidth = ctx->cutoff ? ctx->cutoff : AAC_CUTOFF(ctx->avctx); + const float num_bark = calc_bark((float)bandwidth); + + ctx->model_priv_data = av_mallocz(sizeof(AacPsyContext)); + if (!ctx->model_priv_data) + return AVERROR(ENOMEM); + pctx = ctx->model_priv_data; + pctx->global_quality = (ctx->avctx->global_quality ? ctx->avctx->global_quality : 120) * 0.01f; + + if (ctx->avctx->flags & AV_CODEC_FLAG_QSCALE) { + /* Use the target average bitrate to compute spread parameters */ + chan_bitrate = (int)(chan_bitrate / 120.0 * (ctx->avctx->global_quality ? ctx->avctx->global_quality : 120)); + } + + pctx->chan_bitrate = chan_bitrate; + pctx->frame_bits = FFMIN(2560, chan_bitrate * AAC_BLOCK_SIZE_LONG / ctx->avctx->sample_rate); + pctx->pe.min = 8.0f * AAC_BLOCK_SIZE_LONG * bandwidth / (ctx->avctx->sample_rate * 2.0f); + pctx->pe.max = 12.0f * AAC_BLOCK_SIZE_LONG * bandwidth / (ctx->avctx->sample_rate * 2.0f); + ctx->bitres.size = 6144 - pctx->frame_bits; + ctx->bitres.size -= ctx->bitres.size % 8; + pctx->fill_level = ctx->bitres.size; + minath = ath(3410 - 0.733 * ATH_ADD, ATH_ADD); + for (j = 0; j < 2; j++) { + AacPsyCoeffs *coeffs = pctx->psy_coef[j]; + const uint8_t *band_sizes = ctx->bands[j]; + float line_to_frequency = ctx->avctx->sample_rate / (j ? 256.f : 2048.0f); + float avg_chan_bits = chan_bitrate * (j ? 128.0f : 1024.0f) / ctx->avctx->sample_rate; + /* reference encoder uses 2.4% here instead of 60% like the spec says */ + float bark_pe = 0.024f * PSY_3GPP_BITS_TO_PE(avg_chan_bits) / num_bark; + float en_spread_low = j ? PSY_3GPP_EN_SPREAD_LOW_S : PSY_3GPP_EN_SPREAD_LOW_L; + /* High energy spreading for long blocks <= 22kbps/channel and short blocks are the same. */ + float en_spread_hi = (j || (chan_bitrate <= 22.0f)) ? PSY_3GPP_EN_SPREAD_HI_S : PSY_3GPP_EN_SPREAD_HI_L1; + + i = 0; + prev = 0.0; + for (g = 0; g < ctx->num_bands[j]; g++) { + i += band_sizes[g]; + bark = calc_bark((i-1) * line_to_frequency); + coeffs[g].barks = (bark + prev) / 2.0; + prev = bark; + } + for (g = 0; g < ctx->num_bands[j] - 1; g++) { + AacPsyCoeffs *coeff = &coeffs[g]; + float bark_width = coeffs[g+1].barks - coeffs->barks; + coeff->spread_low[0] = ff_exp10(-bark_width * PSY_3GPP_THR_SPREAD_LOW); + coeff->spread_hi [0] = ff_exp10(-bark_width * PSY_3GPP_THR_SPREAD_HI); + coeff->spread_low[1] = ff_exp10(-bark_width * en_spread_low); + coeff->spread_hi [1] = ff_exp10(-bark_width * en_spread_hi); + pe_min = bark_pe * bark_width; + minsnr = exp2(pe_min / band_sizes[g]) - 1.5f; + coeff->min_snr = av_clipf(1.0f / minsnr, PSY_SNR_25DB, PSY_SNR_1DB); + } + start = 0; + for (g = 0; g < ctx->num_bands[j]; g++) { + minscale = ath(start * line_to_frequency, ATH_ADD); + for (i = 1; i < band_sizes[g]; i++) + minscale = FFMIN(minscale, ath((start + i) * line_to_frequency, ATH_ADD)); + coeffs[g].ath = minscale - minath; + start += band_sizes[g]; + } + } + + pctx->ch = av_mallocz_array(ctx->avctx->channels, sizeof(AacPsyChannel)); + if (!pctx->ch) { + av_freep(&ctx->model_priv_data); + return AVERROR(ENOMEM); + } + + lame_window_init(pctx, ctx->avctx); + + return 0; +} + +/** + * IIR filter used in block switching decision + */ +static float iir_filter(int in, float state[2]) +{ + float ret; + + ret = 0.7548f * (in - state[0]) + 0.5095f * state[1]; + state[0] = in; + state[1] = ret; + return ret; +} + +/** + * window grouping information stored as bits (0 - new group, 1 - group continues) + */ +static const uint8_t window_grouping[9] = { + 0xB6, 0x6C, 0xD8, 0xB2, 0x66, 0xC6, 0x96, 0x36, 0x36 +}; + +/** + * Tell encoder which window types to use. + * @see 3GPP TS26.403 5.4.1 "Blockswitching" + */ +static av_unused FFPsyWindowInfo psy_3gpp_window(FFPsyContext *ctx, + const int16_t *audio, + const int16_t *la, + int channel, int prev_type) +{ + int i, j; + int br = ((AacPsyContext*)ctx->model_priv_data)->chan_bitrate; + int attack_ratio = br <= 16000 ? 18 : 10; + AacPsyContext *pctx = (AacPsyContext*) ctx->model_priv_data; + AacPsyChannel *pch = &pctx->ch[channel]; + uint8_t grouping = 0; + int next_type = pch->next_window_seq; + FFPsyWindowInfo wi = { { 0 } }; + + if (la) { + float s[8], v; + int switch_to_eight = 0; + float sum = 0.0, sum2 = 0.0; + int attack_n = 0; + int stay_short = 0; + for (i = 0; i < 8; i++) { + for (j = 0; j < 128; j++) { + v = iir_filter(la[i*128+j], pch->iir_state); + sum += v*v; + } + s[i] = sum; + sum2 += sum; + } + for (i = 0; i < 8; i++) { + if (s[i] > pch->win_energy * attack_ratio) { + attack_n = i + 1; + switch_to_eight = 1; + break; + } + } + pch->win_energy = pch->win_energy*7/8 + sum2/64; + + wi.window_type[1] = prev_type; + switch (prev_type) { + case ONLY_LONG_SEQUENCE: + wi.window_type[0] = switch_to_eight ? LONG_START_SEQUENCE : ONLY_LONG_SEQUENCE; + next_type = switch_to_eight ? EIGHT_SHORT_SEQUENCE : ONLY_LONG_SEQUENCE; + break; + case LONG_START_SEQUENCE: + wi.window_type[0] = EIGHT_SHORT_SEQUENCE; + grouping = pch->next_grouping; + next_type = switch_to_eight ? EIGHT_SHORT_SEQUENCE : LONG_STOP_SEQUENCE; + break; + case LONG_STOP_SEQUENCE: + wi.window_type[0] = switch_to_eight ? LONG_START_SEQUENCE : ONLY_LONG_SEQUENCE; + next_type = switch_to_eight ? EIGHT_SHORT_SEQUENCE : ONLY_LONG_SEQUENCE; + break; + case EIGHT_SHORT_SEQUENCE: + stay_short = next_type == EIGHT_SHORT_SEQUENCE || switch_to_eight; + wi.window_type[0] = stay_short ? EIGHT_SHORT_SEQUENCE : LONG_STOP_SEQUENCE; + grouping = next_type == EIGHT_SHORT_SEQUENCE ? pch->next_grouping : 0; + next_type = switch_to_eight ? EIGHT_SHORT_SEQUENCE : LONG_STOP_SEQUENCE; + break; + } + + pch->next_grouping = window_grouping[attack_n]; + pch->next_window_seq = next_type; + } else { + for (i = 0; i < 3; i++) + wi.window_type[i] = prev_type; + grouping = (prev_type == EIGHT_SHORT_SEQUENCE) ? window_grouping[0] : 0; + } + + wi.window_shape = 1; + if (wi.window_type[0] != EIGHT_SHORT_SEQUENCE) { + wi.num_windows = 1; + wi.grouping[0] = 1; + } else { + int lastgrp = 0; + wi.num_windows = 8; + for (i = 0; i < 8; i++) { + if (!((grouping >> i) & 1)) + lastgrp = i; + wi.grouping[lastgrp]++; + } + } + + return wi; +} + +/* 5.6.1.2 "Calculation of Bit Demand" */ +static int calc_bit_demand(AacPsyContext *ctx, float pe, int bits, int size, + int short_window) +{ + const float bitsave_slope = short_window ? PSY_3GPP_SAVE_SLOPE_S : PSY_3GPP_SAVE_SLOPE_L; + const float bitsave_add = short_window ? PSY_3GPP_SAVE_ADD_S : PSY_3GPP_SAVE_ADD_L; + const float bitspend_slope = short_window ? PSY_3GPP_SPEND_SLOPE_S : PSY_3GPP_SPEND_SLOPE_L; + const float bitspend_add = short_window ? PSY_3GPP_SPEND_ADD_S : PSY_3GPP_SPEND_ADD_L; + const float clip_low = short_window ? PSY_3GPP_CLIP_LO_S : PSY_3GPP_CLIP_LO_L; + const float clip_high = short_window ? PSY_3GPP_CLIP_HI_S : PSY_3GPP_CLIP_HI_L; + float clipped_pe, bit_save, bit_spend, bit_factor, fill_level, forgetful_min_pe; + + ctx->fill_level += ctx->frame_bits - bits; + ctx->fill_level = av_clip(ctx->fill_level, 0, size); + fill_level = av_clipf((float)ctx->fill_level / size, clip_low, clip_high); + clipped_pe = av_clipf(pe, ctx->pe.min, ctx->pe.max); + bit_save = (fill_level + bitsave_add) * bitsave_slope; + assert(bit_save <= 0.3f && bit_save >= -0.05000001f); + bit_spend = (fill_level + bitspend_add) * bitspend_slope; + assert(bit_spend <= 0.5f && bit_spend >= -0.1f); + /* The bit factor graph in the spec is obviously incorrect. + * bit_spend + ((bit_spend - bit_spend))... + * The reference encoder subtracts everything from 1, but also seems incorrect. + * 1 - bit_save + ((bit_spend + bit_save))... + * Hopefully below is correct. + */ + bit_factor = 1.0f - bit_save + ((bit_spend - bit_save) / (ctx->pe.max - ctx->pe.min)) * (clipped_pe - ctx->pe.min); + /* NOTE: The reference encoder attempts to center pe max/min around the current pe. + * Here we do that by slowly forgetting pe.min when pe stays in a range that makes + * it unlikely (ie: above the mean) + */ + ctx->pe.max = FFMAX(pe, ctx->pe.max); + forgetful_min_pe = ((ctx->pe.min * PSY_PE_FORGET_SLOPE) + + FFMAX(ctx->pe.min, pe * (pe / ctx->pe.max))) / (PSY_PE_FORGET_SLOPE + 1); + ctx->pe.min = FFMIN(pe, forgetful_min_pe); + + /* NOTE: allocate a minimum of 1/8th average frame bits, to avoid + * reservoir starvation from producing zero-bit frames + */ + return FFMIN( + ctx->frame_bits * bit_factor, + FFMAX(ctx->frame_bits + size - bits, ctx->frame_bits / 8)); +} + +static float calc_pe_3gpp(AacPsyBand *band) +{ + float pe, a; + + band->pe = 0.0f; + band->pe_const = 0.0f; + band->active_lines = 0.0f; + if (band->energy > band->thr) { + a = log2f(band->energy); + pe = a - log2f(band->thr); + band->active_lines = band->nz_lines; + if (pe < PSY_3GPP_C1) { + pe = pe * PSY_3GPP_C3 + PSY_3GPP_C2; + a = a * PSY_3GPP_C3 + PSY_3GPP_C2; + band->active_lines *= PSY_3GPP_C3; + } + band->pe = pe * band->nz_lines; + band->pe_const = a * band->nz_lines; + } + + return band->pe; +} + +static float calc_reduction_3gpp(float a, float desired_pe, float pe, + float active_lines) +{ + float thr_avg, reduction; + + if(active_lines == 0.0) + return 0; + + thr_avg = exp2f((a - pe) / (4.0f * active_lines)); + reduction = exp2f((a - desired_pe) / (4.0f * active_lines)) - thr_avg; + + return FFMAX(reduction, 0.0f); +} + +static float calc_reduced_thr_3gpp(AacPsyBand *band, float min_snr, + float reduction) +{ + float thr = band->thr; + + if (band->energy > thr) { + thr = sqrtf(thr); + thr = sqrtf(thr) + reduction; + thr *= thr; + thr *= thr; + + /* This deviates from the 3GPP spec to match the reference encoder. + * It performs min(thr_reduced, max(thr, energy/min_snr)) only for bands + * that have hole avoidance on (active or inactive). It always reduces the + * threshold of bands with hole avoidance off. + */ + if (thr > band->energy * min_snr && band->avoid_holes != PSY_3GPP_AH_NONE) { + thr = FFMAX(band->thr, band->energy * min_snr); + band->avoid_holes = PSY_3GPP_AH_ACTIVE; + } + } + + return thr; +} + +#ifndef calc_thr_3gpp +static void calc_thr_3gpp(const FFPsyWindowInfo *wi, const int num_bands, AacPsyChannel *pch, + const uint8_t *band_sizes, const float *coefs, const int cutoff) +{ + int i, w, g; + int start = 0, wstart = 0; + for (w = 0; w < wi->num_windows*16; w += 16) { + wstart = 0; + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &pch->band[w+g]; + + float form_factor = 0.0f; + float Temp; + band->energy = 0.0f; + if (wstart < cutoff) { + for (i = 0; i < band_sizes[g]; i++) { + band->energy += coefs[start+i] * coefs[start+i]; + form_factor += sqrtf(fabs(coefs[start+i])); + } + } + Temp = band->energy > 0 ? sqrtf((float)band_sizes[g] / band->energy) : 0; + band->thr = band->energy * 0.001258925f; + band->nz_lines = form_factor * sqrtf(Temp); + + start += band_sizes[g]; + wstart += band_sizes[g]; + } + } +} +#endif /* calc_thr_3gpp */ + +#ifndef psy_hp_filter +static void psy_hp_filter(const float *firbuf, float *hpfsmpl, const float *psy_fir_coeffs) +{ + int i, j; + for (i = 0; i < AAC_BLOCK_SIZE_LONG; i++) { + float sum1, sum2; + sum1 = firbuf[i + (PSY_LAME_FIR_LEN - 1) / 2]; + sum2 = 0.0; + for (j = 0; j < ((PSY_LAME_FIR_LEN - 1) / 2) - 1; j += 2) { + sum1 += psy_fir_coeffs[j] * (firbuf[i + j] + firbuf[i + PSY_LAME_FIR_LEN - j]); + sum2 += psy_fir_coeffs[j + 1] * (firbuf[i + j + 1] + firbuf[i + PSY_LAME_FIR_LEN - j - 1]); + } + /* NOTE: The LAME psymodel expects it's input in the range -32768 to 32768. + * Tuning this for normalized floats would be difficult. */ + hpfsmpl[i] = (sum1 + sum2) * 32768.0f; + } +} +#endif /* psy_hp_filter */ + +/** + * Calculate band thresholds as suggested in 3GPP TS26.403 + */ +static void psy_3gpp_analyze_channel(FFPsyContext *ctx, int channel, + const float *coefs, const FFPsyWindowInfo *wi) +{ + AacPsyContext *pctx = (AacPsyContext*) ctx->model_priv_data; + AacPsyChannel *pch = &pctx->ch[channel]; + int i, w, g; + float desired_bits, desired_pe, delta_pe, reduction= NAN, spread_en[128] = {0}; + float a = 0.0f, active_lines = 0.0f, norm_fac = 0.0f; + float pe = pctx->chan_bitrate > 32000 ? 0.0f : FFMAX(50.0f, 100.0f - pctx->chan_bitrate * 100.0f / 32000.0f); + const int num_bands = ctx->num_bands[wi->num_windows == 8]; + const uint8_t *band_sizes = ctx->bands[wi->num_windows == 8]; + AacPsyCoeffs *coeffs = pctx->psy_coef[wi->num_windows == 8]; + const float avoid_hole_thr = wi->num_windows == 8 ? PSY_3GPP_AH_THR_SHORT : PSY_3GPP_AH_THR_LONG; + const int bandwidth = ctx->cutoff ? ctx->cutoff : AAC_CUTOFF(ctx->avctx); + const int cutoff = bandwidth * 2048 / wi->num_windows / ctx->avctx->sample_rate; + + //calculate energies, initial thresholds and related values - 5.4.2 "Threshold Calculation" + calc_thr_3gpp(wi, num_bands, pch, band_sizes, coefs, cutoff); + + //modify thresholds and energies - spread, threshold in quiet, pre-echo control + for (w = 0; w < wi->num_windows*16; w += 16) { + AacPsyBand *bands = &pch->band[w]; + + /* 5.4.2.3 "Spreading" & 5.4.3 "Spread Energy Calculation" */ + spread_en[0] = bands[0].energy; + for (g = 1; g < num_bands; g++) { + bands[g].thr = FFMAX(bands[g].thr, bands[g-1].thr * coeffs[g].spread_hi[0]); + spread_en[w+g] = FFMAX(bands[g].energy, spread_en[w+g-1] * coeffs[g].spread_hi[1]); + } + for (g = num_bands - 2; g >= 0; g--) { + bands[g].thr = FFMAX(bands[g].thr, bands[g+1].thr * coeffs[g].spread_low[0]); + spread_en[w+g] = FFMAX(spread_en[w+g], spread_en[w+g+1] * coeffs[g].spread_low[1]); + } + //5.4.2.4 "Threshold in quiet" + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &bands[g]; + + band->thr_quiet = band->thr = FFMAX(band->thr, coeffs[g].ath); + //5.4.2.5 "Pre-echo control" + if (!(wi->window_type[0] == LONG_STOP_SEQUENCE || (!w && wi->window_type[1] == LONG_START_SEQUENCE))) + band->thr = FFMAX(PSY_3GPP_RPEMIN*band->thr, FFMIN(band->thr, + PSY_3GPP_RPELEV*pch->prev_band[w+g].thr_quiet)); + + /* 5.6.1.3.1 "Preparatory steps of the perceptual entropy calculation" */ + pe += calc_pe_3gpp(band); + a += band->pe_const; + active_lines += band->active_lines; + + /* 5.6.1.3.3 "Selection of the bands for avoidance of holes" */ + if (spread_en[w+g] * avoid_hole_thr > band->energy || coeffs[g].min_snr > 1.0f) + band->avoid_holes = PSY_3GPP_AH_NONE; + else + band->avoid_holes = PSY_3GPP_AH_INACTIVE; + } + } + + /* 5.6.1.3.2 "Calculation of the desired perceptual entropy" */ + ctx->ch[channel].entropy = pe; + if (ctx->avctx->flags & AV_CODEC_FLAG_QSCALE) { + /* (2.5 * 120) achieves almost transparent rate, and we want to give + * ample room downwards, so we make that equivalent to QSCALE=2.4 + */ + desired_pe = pe * (ctx->avctx->global_quality ? ctx->avctx->global_quality : 120) / (2 * 2.5f * 120.0f); + desired_bits = FFMIN(2560, PSY_3GPP_PE_TO_BITS(desired_pe)); + desired_pe = PSY_3GPP_BITS_TO_PE(desired_bits); // reflect clipping + + /* PE slope smoothing */ + if (ctx->bitres.bits > 0) { + desired_bits = FFMIN(2560, PSY_3GPP_PE_TO_BITS(desired_pe)); + desired_pe = PSY_3GPP_BITS_TO_PE(desired_bits); // reflect clipping + } + + pctx->pe.max = FFMAX(pe, pctx->pe.max); + pctx->pe.min = FFMIN(pe, pctx->pe.min); + } else { + desired_bits = calc_bit_demand(pctx, pe, ctx->bitres.bits, ctx->bitres.size, wi->num_windows == 8); + desired_pe = PSY_3GPP_BITS_TO_PE(desired_bits); + + /* NOTE: PE correction is kept simple. During initial testing it had very + * little effect on the final bitrate. Probably a good idea to come + * back and do more testing later. + */ + if (ctx->bitres.bits > 0) + desired_pe *= av_clipf(pctx->pe.previous / PSY_3GPP_BITS_TO_PE(ctx->bitres.bits), + 0.85f, 1.15f); + } + pctx->pe.previous = PSY_3GPP_BITS_TO_PE(desired_bits); + ctx->bitres.alloc = desired_bits; + + if (desired_pe < pe) { + /* 5.6.1.3.4 "First Estimation of the reduction value" */ + for (w = 0; w < wi->num_windows*16; w += 16) { + reduction = calc_reduction_3gpp(a, desired_pe, pe, active_lines); + pe = 0.0f; + a = 0.0f; + active_lines = 0.0f; + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &pch->band[w+g]; + + band->thr = calc_reduced_thr_3gpp(band, coeffs[g].min_snr, reduction); + /* recalculate PE */ + pe += calc_pe_3gpp(band); + a += band->pe_const; + active_lines += band->active_lines; + } + } + + /* 5.6.1.3.5 "Second Estimation of the reduction value" */ + for (i = 0; i < 2; i++) { + float pe_no_ah = 0.0f, desired_pe_no_ah; + active_lines = a = 0.0f; + for (w = 0; w < wi->num_windows*16; w += 16) { + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &pch->band[w+g]; + + if (band->avoid_holes != PSY_3GPP_AH_ACTIVE) { + pe_no_ah += band->pe; + a += band->pe_const; + active_lines += band->active_lines; + } + } + } + desired_pe_no_ah = FFMAX(desired_pe - (pe - pe_no_ah), 0.0f); + if (active_lines > 0.0f) + reduction = calc_reduction_3gpp(a, desired_pe_no_ah, pe_no_ah, active_lines); + + pe = 0.0f; + for (w = 0; w < wi->num_windows*16; w += 16) { + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &pch->band[w+g]; + + if (active_lines > 0.0f) + band->thr = calc_reduced_thr_3gpp(band, coeffs[g].min_snr, reduction); + pe += calc_pe_3gpp(band); + if (band->thr > 0.0f) + band->norm_fac = band->active_lines / band->thr; + else + band->norm_fac = 0.0f; + norm_fac += band->norm_fac; + } + } + delta_pe = desired_pe - pe; + if (fabs(delta_pe) > 0.05f * desired_pe) + break; + } + + if (pe < 1.15f * desired_pe) { + /* 6.6.1.3.6 "Final threshold modification by linearization" */ + norm_fac = 1.0f / norm_fac; + for (w = 0; w < wi->num_windows*16; w += 16) { + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &pch->band[w+g]; + + if (band->active_lines > 0.5f) { + float delta_sfb_pe = band->norm_fac * norm_fac * delta_pe; + float thr = band->thr; + + thr *= exp2f(delta_sfb_pe / band->active_lines); + if (thr > coeffs[g].min_snr * band->energy && band->avoid_holes == PSY_3GPP_AH_INACTIVE) + thr = FFMAX(band->thr, coeffs[g].min_snr * band->energy); + band->thr = thr; + } + } + } + } else { + /* 5.6.1.3.7 "Further perceptual entropy reduction" */ + g = num_bands; + while (pe > desired_pe && g--) { + for (w = 0; w < wi->num_windows*16; w+= 16) { + AacPsyBand *band = &pch->band[w+g]; + if (band->avoid_holes != PSY_3GPP_AH_NONE && coeffs[g].min_snr < PSY_SNR_1DB) { + coeffs[g].min_snr = PSY_SNR_1DB; + band->thr = band->energy * PSY_SNR_1DB; + pe += band->active_lines * 1.5f - band->pe; + } + } + } + /* TODO: allow more holes (unused without mid/side) */ + } + } + + for (w = 0; w < wi->num_windows*16; w += 16) { + for (g = 0; g < num_bands; g++) { + AacPsyBand *band = &pch->band[w+g]; + FFPsyBand *psy_band = &ctx->ch[channel].psy_bands[w+g]; + + psy_band->threshold = band->thr; + psy_band->energy = band->energy; + psy_band->spread = band->active_lines * 2.0f / band_sizes[g]; + psy_band->bits = PSY_3GPP_PE_TO_BITS(band->pe); + } + } + + memcpy(pch->prev_band, pch->band, sizeof(pch->band)); +} + +static void psy_3gpp_analyze(FFPsyContext *ctx, int channel, + const float **coeffs, const FFPsyWindowInfo *wi) +{ + int ch; + FFPsyChannelGroup *group = ff_psy_find_group(ctx, channel); + + for (ch = 0; ch < group->num_ch; ch++) + psy_3gpp_analyze_channel(ctx, channel + ch, coeffs[ch], &wi[ch]); +} + +static av_cold void psy_3gpp_end(FFPsyContext *apc) +{ + AacPsyContext *pctx = (AacPsyContext*) apc->model_priv_data; + av_freep(&pctx->ch); + av_freep(&apc->model_priv_data); +} + +static void lame_apply_block_type(AacPsyChannel *ctx, FFPsyWindowInfo *wi, int uselongblock) +{ + int blocktype = ONLY_LONG_SEQUENCE; + if (uselongblock) { + if (ctx->next_window_seq == EIGHT_SHORT_SEQUENCE) + blocktype = LONG_STOP_SEQUENCE; + } else { + blocktype = EIGHT_SHORT_SEQUENCE; + if (ctx->next_window_seq == ONLY_LONG_SEQUENCE) + ctx->next_window_seq = LONG_START_SEQUENCE; + if (ctx->next_window_seq == LONG_STOP_SEQUENCE) + ctx->next_window_seq = EIGHT_SHORT_SEQUENCE; + } + + wi->window_type[0] = ctx->next_window_seq; + ctx->next_window_seq = blocktype; +} + +static FFPsyWindowInfo psy_lame_window(FFPsyContext *ctx, const float *audio, + const float *la, int channel, int prev_type) +{ + AacPsyContext *pctx = (AacPsyContext*) ctx->model_priv_data; + AacPsyChannel *pch = &pctx->ch[channel]; + int grouping = 0; + int uselongblock = 1; + int attacks[AAC_NUM_BLOCKS_SHORT + 1] = { 0 }; + int i; + FFPsyWindowInfo wi = { { 0 } }; + + if (la) { + float hpfsmpl[AAC_BLOCK_SIZE_LONG]; + const float *pf = hpfsmpl; + float attack_intensity[(AAC_NUM_BLOCKS_SHORT + 1) * PSY_LAME_NUM_SUBBLOCKS]; + float energy_subshort[(AAC_NUM_BLOCKS_SHORT + 1) * PSY_LAME_NUM_SUBBLOCKS]; + float energy_short[AAC_NUM_BLOCKS_SHORT + 1] = { 0 }; + const float *firbuf = la + (AAC_BLOCK_SIZE_SHORT/4 - PSY_LAME_FIR_LEN); + int att_sum = 0; + + /* LAME comment: apply high pass filter of fs/4 */ + psy_hp_filter(firbuf, hpfsmpl, psy_fir_coeffs); + + /* Calculate the energies of each sub-shortblock */ + for (i = 0; i < PSY_LAME_NUM_SUBBLOCKS; i++) { + energy_subshort[i] = pch->prev_energy_subshort[i + ((AAC_NUM_BLOCKS_SHORT - 1) * PSY_LAME_NUM_SUBBLOCKS)]; + assert(pch->prev_energy_subshort[i + ((AAC_NUM_BLOCKS_SHORT - 2) * PSY_LAME_NUM_SUBBLOCKS + 1)] > 0); + attack_intensity[i] = energy_subshort[i] / pch->prev_energy_subshort[i + ((AAC_NUM_BLOCKS_SHORT - 2) * PSY_LAME_NUM_SUBBLOCKS + 1)]; + energy_short[0] += energy_subshort[i]; + } + + for (i = 0; i < AAC_NUM_BLOCKS_SHORT * PSY_LAME_NUM_SUBBLOCKS; i++) { + const float *const pfe = pf + AAC_BLOCK_SIZE_LONG / (AAC_NUM_BLOCKS_SHORT * PSY_LAME_NUM_SUBBLOCKS); + float p = 1.0f; + for (; pf < pfe; pf++) + p = FFMAX(p, fabsf(*pf)); + pch->prev_energy_subshort[i] = energy_subshort[i + PSY_LAME_NUM_SUBBLOCKS] = p; + energy_short[1 + i / PSY_LAME_NUM_SUBBLOCKS] += p; + /* NOTE: The indexes below are [i + 3 - 2] in the LAME source. + * Obviously the 3 and 2 have some significance, or this would be just [i + 1] + * (which is what we use here). What the 3 stands for is ambiguous, as it is both + * number of short blocks, and the number of sub-short blocks. + * It seems that LAME is comparing each sub-block to sub-block + 1 in the + * previous block. + */ + if (p > energy_subshort[i + 1]) + p = p / energy_subshort[i + 1]; + else if (energy_subshort[i + 1] > p * 10.0f) + p = energy_subshort[i + 1] / (p * 10.0f); + else + p = 0.0; + attack_intensity[i + PSY_LAME_NUM_SUBBLOCKS] = p; + } + + /* compare energy between sub-short blocks */ + for (i = 0; i < (AAC_NUM_BLOCKS_SHORT + 1) * PSY_LAME_NUM_SUBBLOCKS; i++) + if (!attacks[i / PSY_LAME_NUM_SUBBLOCKS]) + if (attack_intensity[i] > pch->attack_threshold) + attacks[i / PSY_LAME_NUM_SUBBLOCKS] = (i % PSY_LAME_NUM_SUBBLOCKS) + 1; + + /* should have energy change between short blocks, in order to avoid periodic signals */ + /* Good samples to show the effect are Trumpet test songs */ + /* GB: tuned (1) to avoid too many short blocks for test sample TRUMPET */ + /* RH: tuned (2) to let enough short blocks through for test sample FSOL and SNAPS */ + for (i = 1; i < AAC_NUM_BLOCKS_SHORT + 1; i++) { + const float u = energy_short[i - 1]; + const float v = energy_short[i]; + const float m = FFMAX(u, v); + if (m < 40000) { /* (2) */ + if (u < 1.7f * v && v < 1.7f * u) { /* (1) */ + if (i == 1 && attacks[0] < attacks[i]) + attacks[0] = 0; + attacks[i] = 0; + } + } + att_sum += attacks[i]; + } + + if (attacks[0] <= pch->prev_attack) + attacks[0] = 0; + + att_sum += attacks[0]; + /* 3 below indicates the previous attack happened in the last sub-block of the previous sequence */ + if (pch->prev_attack == 3 || att_sum) { + uselongblock = 0; + + for (i = 1; i < AAC_NUM_BLOCKS_SHORT + 1; i++) + if (attacks[i] && attacks[i-1]) + attacks[i] = 0; + } + } else { + /* We have no lookahead info, so just use same type as the previous sequence. */ + uselongblock = !(prev_type == EIGHT_SHORT_SEQUENCE); + } + + lame_apply_block_type(pch, &wi, uselongblock); + + wi.window_type[1] = prev_type; + if (wi.window_type[0] != EIGHT_SHORT_SEQUENCE) { + + wi.num_windows = 1; + wi.grouping[0] = 1; + if (wi.window_type[0] == LONG_START_SEQUENCE) + wi.window_shape = 0; + else + wi.window_shape = 1; + + } else { + int lastgrp = 0; + + wi.num_windows = 8; + wi.window_shape = 0; + for (i = 0; i < 8; i++) { + if (!((pch->next_grouping >> i) & 1)) + lastgrp = i; + wi.grouping[lastgrp]++; + } + } + + /* Determine grouping, based on the location of the first attack, and save for + * the next frame. + * FIXME: Move this to analysis. + * TODO: Tune groupings depending on attack location + * TODO: Handle more than one attack in a group + */ + for (i = 0; i < 9; i++) { + if (attacks[i]) { + grouping = i; + break; + } + } + pch->next_grouping = window_grouping[grouping]; + + pch->prev_attack = attacks[8]; + + return wi; +} + +const FFPsyModel ff_aac_psy_model = +{ + .name = "3GPP TS 26.403-inspired model", + .init = psy_3gpp_init, + .window = psy_lame_window, + .analyze = psy_3gpp_analyze, + .end = psy_3gpp_end, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr.c new file mode 100644 index 0000000000..1d2a8d472d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr.c @@ -0,0 +1,370 @@ +/* + * AAC Spectral Band Replication decoding functions + * Copyright (c) 2008-2009 Robert Swain ( rob opendot cl ) + * Copyright (c) 2009-2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC Spectral Band Replication decoding functions + * @author Robert Swain ( rob opendot cl ) + */ +#define USE_FIXED 0 + +#include "aac.h" +#include "sbr.h" +#include "aacsbr.h" +#include "aacsbrdata.h" +#include "aacsbr_tablegen.h" +#include "fft.h" +#include "internal.h" +#include "aacps.h" +#include "sbrdsp.h" +#include "libavutil/internal.h" +#include "libavutil/libm.h" +#include "libavutil/avassert.h" + +#include +#include +#include + +#if ARCH_MIPS +#include "mips/aacsbr_mips.h" +#endif /* ARCH_MIPS */ + +static VLC vlc_sbr[10]; +static void aacsbr_func_ptr_init(AACSBRContext *c); + +static void make_bands(int16_t* bands, int start, int stop, int num_bands) +{ + int k, previous, present; + float base, prod; + + base = powf((float)stop / start, 1.0f / num_bands); + prod = start; + previous = start; + + for (k = 0; k < num_bands-1; k++) { + prod *= base; + present = lrintf(prod); + bands[k] = present - previous; + previous = present; + } + bands[num_bands-1] = stop - previous; +} + +/// Dequantization and stereo decoding (14496-3 sp04 p203) +static void sbr_dequant(SpectralBandReplication *sbr, int id_aac) +{ + int k, e; + int ch; + static const double exp2_tab[2] = {1, M_SQRT2}; + if (id_aac == TYPE_CPE && sbr->bs_coupling) { + int pan_offset = sbr->data[0].bs_amp_res ? 12 : 24; + for (e = 1; e <= sbr->data[0].bs_num_env; e++) { + for (k = 0; k < sbr->n[sbr->data[0].bs_freq_res[e]]; k++) { + float temp1, temp2, fac; + if (sbr->data[0].bs_amp_res) { + temp1 = ff_exp2fi(sbr->data[0].env_facs_q[e][k] + 7); + temp2 = ff_exp2fi(pan_offset - sbr->data[1].env_facs_q[e][k]); + } + else { + temp1 = ff_exp2fi((sbr->data[0].env_facs_q[e][k]>>1) + 7) * + exp2_tab[sbr->data[0].env_facs_q[e][k] & 1]; + temp2 = ff_exp2fi((pan_offset - sbr->data[1].env_facs_q[e][k])>>1) * + exp2_tab[(pan_offset - sbr->data[1].env_facs_q[e][k]) & 1]; + } + if (temp1 > 1E20) { + av_log(NULL, AV_LOG_ERROR, "envelope scalefactor overflow in dequant\n"); + temp1 = 1; + } + fac = temp1 / (1.0f + temp2); + sbr->data[0].env_facs[e][k] = fac; + sbr->data[1].env_facs[e][k] = fac * temp2; + } + } + for (e = 1; e <= sbr->data[0].bs_num_noise; e++) { + for (k = 0; k < sbr->n_q; k++) { + float temp1 = ff_exp2fi(NOISE_FLOOR_OFFSET - sbr->data[0].noise_facs_q[e][k] + 1); + float temp2 = ff_exp2fi(12 - sbr->data[1].noise_facs_q[e][k]); + float fac; + av_assert0(temp1 <= 1E20); + fac = temp1 / (1.0f + temp2); + sbr->data[0].noise_facs[e][k] = fac; + sbr->data[1].noise_facs[e][k] = fac * temp2; + } + } + } else { // SCE or one non-coupled CPE + for (ch = 0; ch < (id_aac == TYPE_CPE) + 1; ch++) { + for (e = 1; e <= sbr->data[ch].bs_num_env; e++) + for (k = 0; k < sbr->n[sbr->data[ch].bs_freq_res[e]]; k++){ + if (sbr->data[ch].bs_amp_res) + sbr->data[ch].env_facs[e][k] = ff_exp2fi(sbr->data[ch].env_facs_q[e][k] + 6); + else + sbr->data[ch].env_facs[e][k] = ff_exp2fi((sbr->data[ch].env_facs_q[e][k]>>1) + 6) + * exp2_tab[sbr->data[ch].env_facs_q[e][k] & 1]; + if (sbr->data[ch].env_facs[e][k] > 1E20) { + av_log(NULL, AV_LOG_ERROR, "envelope scalefactor overflow in dequant\n"); + sbr->data[ch].env_facs[e][k] = 1; + } + } + + for (e = 1; e <= sbr->data[ch].bs_num_noise; e++) + for (k = 0; k < sbr->n_q; k++) + sbr->data[ch].noise_facs[e][k] = + ff_exp2fi(NOISE_FLOOR_OFFSET - sbr->data[ch].noise_facs_q[e][k]); + } + } +} + +/** High Frequency Generation (14496-3 sp04 p214+) and Inverse Filtering + * (14496-3 sp04 p214) + * Warning: This routine does not seem numerically stable. + */ +static void sbr_hf_inverse_filter(SBRDSPContext *dsp, + float (*alpha0)[2], float (*alpha1)[2], + const float X_low[32][40][2], int k0) +{ + int k; + for (k = 0; k < k0; k++) { + LOCAL_ALIGNED_16(float, phi, [3], [2][2]); + float dk; + + dsp->autocorrelate(X_low[k], phi); + + dk = phi[2][1][0] * phi[1][0][0] - + (phi[1][1][0] * phi[1][1][0] + phi[1][1][1] * phi[1][1][1]) / 1.000001f; + + if (!dk) { + alpha1[k][0] = 0; + alpha1[k][1] = 0; + } else { + float temp_real, temp_im; + temp_real = phi[0][0][0] * phi[1][1][0] - + phi[0][0][1] * phi[1][1][1] - + phi[0][1][0] * phi[1][0][0]; + temp_im = phi[0][0][0] * phi[1][1][1] + + phi[0][0][1] * phi[1][1][0] - + phi[0][1][1] * phi[1][0][0]; + + alpha1[k][0] = temp_real / dk; + alpha1[k][1] = temp_im / dk; + } + + if (!phi[1][0][0]) { + alpha0[k][0] = 0; + alpha0[k][1] = 0; + } else { + float temp_real, temp_im; + temp_real = phi[0][0][0] + alpha1[k][0] * phi[1][1][0] + + alpha1[k][1] * phi[1][1][1]; + temp_im = phi[0][0][1] + alpha1[k][1] * phi[1][1][0] - + alpha1[k][0] * phi[1][1][1]; + + alpha0[k][0] = -temp_real / phi[1][0][0]; + alpha0[k][1] = -temp_im / phi[1][0][0]; + } + + if (alpha1[k][0] * alpha1[k][0] + alpha1[k][1] * alpha1[k][1] >= 16.0f || + alpha0[k][0] * alpha0[k][0] + alpha0[k][1] * alpha0[k][1] >= 16.0f) { + alpha1[k][0] = 0; + alpha1[k][1] = 0; + alpha0[k][0] = 0; + alpha0[k][1] = 0; + } + } +} + +/// Chirp Factors (14496-3 sp04 p214) +static void sbr_chirp(SpectralBandReplication *sbr, SBRData *ch_data) +{ + int i; + float new_bw; + static const float bw_tab[] = { 0.0f, 0.75f, 0.9f, 0.98f }; + + for (i = 0; i < sbr->n_q; i++) { + if (ch_data->bs_invf_mode[0][i] + ch_data->bs_invf_mode[1][i] == 1) { + new_bw = 0.6f; + } else + new_bw = bw_tab[ch_data->bs_invf_mode[0][i]]; + + if (new_bw < ch_data->bw_array[i]) { + new_bw = 0.75f * new_bw + 0.25f * ch_data->bw_array[i]; + } else + new_bw = 0.90625f * new_bw + 0.09375f * ch_data->bw_array[i]; + ch_data->bw_array[i] = new_bw < 0.015625f ? 0.0f : new_bw; + } +} + +/** + * Calculation of levels of additional HF signal components (14496-3 sp04 p219) + * and Calculation of gain (14496-3 sp04 p219) + */ +static void sbr_gain_calc(AACContext *ac, SpectralBandReplication *sbr, + SBRData *ch_data, const int e_a[2]) +{ + int e, k, m; + // max gain limits : -3dB, 0dB, 3dB, inf dB (limiter off) + static const float limgain[4] = { 0.70795, 1.0, 1.41254, 10000000000 }; + + for (e = 0; e < ch_data->bs_num_env; e++) { + int delta = !((e == e_a[1]) || (e == e_a[0])); + for (k = 0; k < sbr->n_lim; k++) { + float gain_boost, gain_max; + float sum[2] = { 0.0f, 0.0f }; + for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { + const float temp = sbr->e_origmapped[e][m] / (1.0f + sbr->q_mapped[e][m]); + sbr->q_m[e][m] = sqrtf(temp * sbr->q_mapped[e][m]); + sbr->s_m[e][m] = sqrtf(temp * ch_data->s_indexmapped[e + 1][m]); + if (!sbr->s_mapped[e][m]) { + sbr->gain[e][m] = sqrtf(sbr->e_origmapped[e][m] / + ((1.0f + sbr->e_curr[e][m]) * + (1.0f + sbr->q_mapped[e][m] * delta))); + } else { + sbr->gain[e][m] = sqrtf(sbr->e_origmapped[e][m] * sbr->q_mapped[e][m] / + ((1.0f + sbr->e_curr[e][m]) * + (1.0f + sbr->q_mapped[e][m]))); + } + sbr->gain[e][m] += FLT_MIN; + } + for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { + sum[0] += sbr->e_origmapped[e][m]; + sum[1] += sbr->e_curr[e][m]; + } + gain_max = limgain[sbr->bs_limiter_gains] * sqrtf((FLT_EPSILON + sum[0]) / (FLT_EPSILON + sum[1])); + gain_max = FFMIN(100000.f, gain_max); + for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { + float q_m_max = sbr->q_m[e][m] * gain_max / sbr->gain[e][m]; + sbr->q_m[e][m] = FFMIN(sbr->q_m[e][m], q_m_max); + sbr->gain[e][m] = FFMIN(sbr->gain[e][m], gain_max); + } + sum[0] = sum[1] = 0.0f; + for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { + sum[0] += sbr->e_origmapped[e][m]; + sum[1] += sbr->e_curr[e][m] * sbr->gain[e][m] * sbr->gain[e][m] + + sbr->s_m[e][m] * sbr->s_m[e][m] + + (delta && !sbr->s_m[e][m]) * sbr->q_m[e][m] * sbr->q_m[e][m]; + } + gain_boost = sqrtf((FLT_EPSILON + sum[0]) / (FLT_EPSILON + sum[1])); + gain_boost = FFMIN(1.584893192f, gain_boost); + for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { + sbr->gain[e][m] *= gain_boost; + sbr->q_m[e][m] *= gain_boost; + sbr->s_m[e][m] *= gain_boost; + } + } + } +} + +/// Assembling HF Signals (14496-3 sp04 p220) +static void sbr_hf_assemble(float Y1[38][64][2], + const float X_high[64][40][2], + SpectralBandReplication *sbr, SBRData *ch_data, + const int e_a[2]) +{ + int e, i, j, m; + const int h_SL = 4 * !sbr->bs_smoothing_mode; + const int kx = sbr->kx[1]; + const int m_max = sbr->m[1]; + static const float h_smooth[5] = { + 0.33333333333333, + 0.30150283239582, + 0.21816949906249, + 0.11516383427084, + 0.03183050093751, + }; + float (*g_temp)[48] = ch_data->g_temp, (*q_temp)[48] = ch_data->q_temp; + int indexnoise = ch_data->f_indexnoise; + int indexsine = ch_data->f_indexsine; + + if (sbr->reset) { + for (i = 0; i < h_SL; i++) { + memcpy(g_temp[i + 2*ch_data->t_env[0]], sbr->gain[0], m_max * sizeof(sbr->gain[0][0])); + memcpy(q_temp[i + 2*ch_data->t_env[0]], sbr->q_m[0], m_max * sizeof(sbr->q_m[0][0])); + } + } else if (h_SL) { + for (i = 0; i < 4; i++) { + memcpy(g_temp[i + 2 * ch_data->t_env[0]], + g_temp[i + 2 * ch_data->t_env_num_env_old], + sizeof(g_temp[0])); + memcpy(q_temp[i + 2 * ch_data->t_env[0]], + q_temp[i + 2 * ch_data->t_env_num_env_old], + sizeof(q_temp[0])); + } + } + + for (e = 0; e < ch_data->bs_num_env; e++) { + for (i = 2 * ch_data->t_env[e]; i < 2 * ch_data->t_env[e + 1]; i++) { + memcpy(g_temp[h_SL + i], sbr->gain[e], m_max * sizeof(sbr->gain[0][0])); + memcpy(q_temp[h_SL + i], sbr->q_m[e], m_max * sizeof(sbr->q_m[0][0])); + } + } + + for (e = 0; e < ch_data->bs_num_env; e++) { + for (i = 2 * ch_data->t_env[e]; i < 2 * ch_data->t_env[e + 1]; i++) { + LOCAL_ALIGNED_16(float, g_filt_tab, [48]); + LOCAL_ALIGNED_16(float, q_filt_tab, [48]); + float *g_filt, *q_filt; + + if (h_SL && e != e_a[0] && e != e_a[1]) { + g_filt = g_filt_tab; + q_filt = q_filt_tab; + for (m = 0; m < m_max; m++) { + const int idx1 = i + h_SL; + g_filt[m] = 0.0f; + q_filt[m] = 0.0f; + for (j = 0; j <= h_SL; j++) { + g_filt[m] += g_temp[idx1 - j][m] * h_smooth[j]; + q_filt[m] += q_temp[idx1 - j][m] * h_smooth[j]; + } + } + } else { + g_filt = g_temp[i + h_SL]; + q_filt = q_temp[i]; + } + + sbr->dsp.hf_g_filt(Y1[i] + kx, X_high + kx, g_filt, m_max, + i + ENVELOPE_ADJUSTMENT_OFFSET); + + if (e != e_a[0] && e != e_a[1]) { + sbr->dsp.hf_apply_noise[indexsine](Y1[i] + kx, sbr->s_m[e], + q_filt, indexnoise, + kx, m_max); + } else { + int idx = indexsine&1; + int A = (1-((indexsine+(kx & 1))&2)); + int B = (A^(-idx)) + idx; + float *out = &Y1[i][kx][idx]; + float *in = sbr->s_m[e]; + for (m = 0; m+1 < m_max; m+=2) { + out[2*m ] += in[m ] * A; + out[2*m+2] += in[m+1] * B; + } + if(m_max&1) + out[2*m ] += in[m ] * A; + } + indexnoise = (indexnoise + m_max) & 0x1ff; + indexsine = (indexsine + 1) & 3; + } + } + ch_data->f_indexnoise = indexnoise; + ch_data->f_indexsine = indexsine; +} + +#include "aacsbr_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr.h new file mode 100644 index 0000000000..dd8b66c7bb --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr.h @@ -0,0 +1,96 @@ +/* + * AAC Spectral Band Replication function declarations + * Copyright (c) 2008-2009 Robert Swain ( rob opendot cl ) + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC Spectral Band Replication function declarations + * @author Robert Swain ( rob opendot cl ) + */ + +#ifndef AVCODEC_AACSBR_H +#define AVCODEC_AACSBR_H + +#include "get_bits.h" +#include "aac.h" +#include "sbr.h" + +#define ENVELOPE_ADJUSTMENT_OFFSET 2 +#define NOISE_FLOOR_OFFSET 6 + +/** + * SBR VLC tables + */ +enum { + T_HUFFMAN_ENV_1_5DB, + F_HUFFMAN_ENV_1_5DB, + T_HUFFMAN_ENV_BAL_1_5DB, + F_HUFFMAN_ENV_BAL_1_5DB, + T_HUFFMAN_ENV_3_0DB, + F_HUFFMAN_ENV_3_0DB, + T_HUFFMAN_ENV_BAL_3_0DB, + F_HUFFMAN_ENV_BAL_3_0DB, + T_HUFFMAN_NOISE_3_0DB, + T_HUFFMAN_NOISE_BAL_3_0DB, +}; + +/** + * bs_frame_class - frame class of current SBR frame (14496-3 sp04 p98) + */ +enum { + FIXFIX, + FIXVAR, + VARFIX, + VARVAR, +}; + +enum { + EXTENSION_ID_PS = 2, +}; + +static const int8_t vlc_sbr_lav[10] = + { 60, 60, 24, 24, 31, 31, 12, 12, 31, 12 }; + +#define SBR_INIT_VLC_STATIC(num, size) \ + INIT_VLC_STATIC(&vlc_sbr[num], 9, sbr_tmp[num].table_size / sbr_tmp[num].elem_size, \ + sbr_tmp[num].sbr_bits , 1, 1, \ + sbr_tmp[num].sbr_codes, sbr_tmp[num].elem_size, sbr_tmp[num].elem_size, \ + size) + +#define SBR_VLC_ROW(name) \ + { name ## _codes, name ## _bits, sizeof(name ## _codes), sizeof(name ## _codes[0]) } + +/** Initialize SBR. */ +void AAC_RENAME(ff_aac_sbr_init)(void); +/** Initialize one SBR context. */ +void AAC_RENAME(ff_aac_sbr_ctx_init)(AACContext *ac, SpectralBandReplication *sbr, int id_aac); +/** Close one SBR context. */ +void AAC_RENAME(ff_aac_sbr_ctx_close)(SpectralBandReplication *sbr); +/** Decode one SBR element. */ +int AAC_RENAME(ff_decode_sbr_extension)(AACContext *ac, SpectralBandReplication *sbr, + GetBitContext *gb, int crc, int cnt, int id_aac); +/** Apply one SBR element to one AAC element. */ +void AAC_RENAME(ff_sbr_apply)(AACContext *ac, SpectralBandReplication *sbr, int id_aac, + INTFLOAT* L, INTFLOAT *R); + +void ff_aacsbr_func_ptr_init_mips(AACSBRContext *c); + +#endif /* AVCODEC_AACSBR_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_fixed.c new file mode 100644 index 0000000000..59cbba10ff --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_fixed.c @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * AAC Spectral Band Replication decoding functions (fixed-point) + * Copyright (c) 2008-2009 Robert Swain ( rob opendot cl ) + * Copyright (c) 2009-2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC Spectral Band Replication decoding functions (fixed-point) + * Note: Rounding-to-nearest used unless otherwise stated + * @author Robert Swain ( rob opendot cl ) + * @author Stanislav Ocovaj ( stanislav.ocovaj imgtec com ) + */ +#define USE_FIXED 1 + +#include "aac.h" +#include "sbr.h" +#include "aacsbr.h" +#include "aacsbrdata.h" +#include "aacsbr_fixed_tablegen.h" +#include "fft.h" +#include "aacps.h" +#include "sbrdsp.h" +#include "libavutil/internal.h" +#include "libavutil/libm.h" +#include "libavutil/avassert.h" + +#include +#include +#include + +static VLC vlc_sbr[10]; +static void aacsbr_func_ptr_init(AACSBRContext *c); +static const int CONST_LN2 = Q31(0.6931471806/256); // ln(2)/256 +static const int CONST_RECIP_LN2 = Q31(0.7213475204); // 0.5/ln(2) +static const int CONST_076923 = Q31(0.76923076923076923077f); + +static const int fixed_log_table[10] = +{ + Q31(1.0/2), Q31(1.0/3), Q31(1.0/4), Q31(1.0/5), Q31(1.0/6), + Q31(1.0/7), Q31(1.0/8), Q31(1.0/9), Q31(1.0/10), Q31(1.0/11) +}; + +static int fixed_log(int x) +{ + int i, ret, xpow, tmp; + + ret = x; + xpow = x; + for (i=0; i<10; i+=2){ + xpow = (int)(((int64_t)xpow * x + 0x40000000) >> 31); + tmp = (int)(((int64_t)xpow * fixed_log_table[i] + 0x40000000) >> 31); + ret -= tmp; + + xpow = (int)(((int64_t)xpow * x + 0x40000000) >> 31); + tmp = (int)(((int64_t)xpow * fixed_log_table[i+1] + 0x40000000) >> 31); + ret += tmp; + } + + return ret; +} + +static const int fixed_exp_table[7] = +{ + Q31(1.0/2), Q31(1.0/6), Q31(1.0/24), Q31(1.0/120), + Q31(1.0/720), Q31(1.0/5040), Q31(1.0/40320) +}; + +static int fixed_exp(int x) +{ + int i, ret, xpow, tmp; + + ret = 0x800000 + x; + xpow = x; + for (i=0; i<7; i++){ + xpow = (int)(((int64_t)xpow * x + 0x400000) >> 23); + tmp = (int)(((int64_t)xpow * fixed_exp_table[i] + 0x40000000) >> 31); + ret += tmp; + } + + return ret; +} + +static void make_bands(int16_t* bands, int start, int stop, int num_bands) +{ + int k, previous, present; + int base, prod, nz = 0; + + base = (stop << 23) / start; + while (base < 0x40000000){ + base <<= 1; + nz++; + } + base = fixed_log(base - 0x80000000); + base = (((base + 0x80) >> 8) + (8-nz)*CONST_LN2) / num_bands; + base = fixed_exp(base); + + previous = start; + prod = start << 23; + + for (k = 0; k < num_bands-1; k++) { + prod = (int)(((int64_t)prod * base + 0x400000) >> 23); + present = (prod + 0x400000) >> 23; + bands[k] = present - previous; + previous = present; + } + bands[num_bands-1] = stop - previous; +} + +/// Dequantization and stereo decoding (14496-3 sp04 p203) +static void sbr_dequant(SpectralBandReplication *sbr, int id_aac) +{ + int k, e; + int ch; + + if (id_aac == TYPE_CPE && sbr->bs_coupling) { + int alpha = sbr->data[0].bs_amp_res ? 2 : 1; + int pan_offset = sbr->data[0].bs_amp_res ? 12 : 24; + for (e = 1; e <= sbr->data[0].bs_num_env; e++) { + for (k = 0; k < sbr->n[sbr->data[0].bs_freq_res[e]]; k++) { + SoftFloat temp1, temp2, fac; + + temp1.exp = sbr->data[0].env_facs_q[e][k] * alpha + 14; + if (temp1.exp & 1) + temp1.mant = 759250125; + else + temp1.mant = 0x20000000; + temp1.exp = (temp1.exp >> 1) + 1; + if (temp1.exp > 66) { // temp1 > 1E20 + av_log(NULL, AV_LOG_ERROR, "envelope scalefactor overflow in dequant\n"); + temp1 = FLOAT_1; + } + + temp2.exp = (pan_offset - sbr->data[1].env_facs_q[e][k]) * alpha; + if (temp2.exp & 1) + temp2.mant = 759250125; + else + temp2.mant = 0x20000000; + temp2.exp = (temp2.exp >> 1) + 1; + fac = av_div_sf(temp1, av_add_sf(FLOAT_1, temp2)); + sbr->data[0].env_facs[e][k] = fac; + sbr->data[1].env_facs[e][k] = av_mul_sf(fac, temp2); + } + } + for (e = 1; e <= sbr->data[0].bs_num_noise; e++) { + for (k = 0; k < sbr->n_q; k++) { + SoftFloat temp1, temp2, fac; + + temp1.exp = NOISE_FLOOR_OFFSET - \ + sbr->data[0].noise_facs_q[e][k] + 2; + temp1.mant = 0x20000000; + av_assert0(temp1.exp <= 66); + temp2.exp = 12 - sbr->data[1].noise_facs_q[e][k] + 1; + temp2.mant = 0x20000000; + fac = av_div_sf(temp1, av_add_sf(FLOAT_1, temp2)); + sbr->data[0].noise_facs[e][k] = fac; + sbr->data[1].noise_facs[e][k] = av_mul_sf(fac, temp2); + } + } + } else { // SCE or one non-coupled CPE + for (ch = 0; ch < (id_aac == TYPE_CPE) + 1; ch++) { + int alpha = sbr->data[ch].bs_amp_res ? 2 : 1; + for (e = 1; e <= sbr->data[ch].bs_num_env; e++) + for (k = 0; k < sbr->n[sbr->data[ch].bs_freq_res[e]]; k++){ + SoftFloat temp1; + + temp1.exp = alpha * sbr->data[ch].env_facs_q[e][k] + 12; + if (temp1.exp & 1) + temp1.mant = 759250125; + else + temp1.mant = 0x20000000; + temp1.exp = (temp1.exp >> 1) + 1; + if (temp1.exp > 66) { // temp1 > 1E20 + av_log(NULL, AV_LOG_ERROR, "envelope scalefactor overflow in dequant\n"); + temp1 = FLOAT_1; + } + sbr->data[ch].env_facs[e][k] = temp1; + } + for (e = 1; e <= sbr->data[ch].bs_num_noise; e++) + for (k = 0; k < sbr->n_q; k++){ + sbr->data[ch].noise_facs[e][k].exp = NOISE_FLOOR_OFFSET - \ + sbr->data[ch].noise_facs_q[e][k] + 1; + sbr->data[ch].noise_facs[e][k].mant = 0x20000000; + } + } + } +} + +/** High Frequency Generation (14496-3 sp04 p214+) and Inverse Filtering + * (14496-3 sp04 p214) + * Warning: This routine does not seem numerically stable. + */ +static void sbr_hf_inverse_filter(SBRDSPContext *dsp, + int (*alpha0)[2], int (*alpha1)[2], + const int X_low[32][40][2], int k0) +{ + int k; + int shift, round; + + for (k = 0; k < k0; k++) { + SoftFloat phi[3][2][2]; + SoftFloat a00, a01, a10, a11; + SoftFloat dk; + + dsp->autocorrelate(X_low[k], phi); + + dk = av_sub_sf(av_mul_sf(phi[2][1][0], phi[1][0][0]), + av_mul_sf(av_add_sf(av_mul_sf(phi[1][1][0], phi[1][1][0]), + av_mul_sf(phi[1][1][1], phi[1][1][1])), FLOAT_0999999)); + + if (!dk.mant) { + a10 = FLOAT_0; + a11 = FLOAT_0; + } else { + SoftFloat temp_real, temp_im; + temp_real = av_sub_sf(av_sub_sf(av_mul_sf(phi[0][0][0], phi[1][1][0]), + av_mul_sf(phi[0][0][1], phi[1][1][1])), + av_mul_sf(phi[0][1][0], phi[1][0][0])); + temp_im = av_sub_sf(av_add_sf(av_mul_sf(phi[0][0][0], phi[1][1][1]), + av_mul_sf(phi[0][0][1], phi[1][1][0])), + av_mul_sf(phi[0][1][1], phi[1][0][0])); + + a10 = av_div_sf(temp_real, dk); + a11 = av_div_sf(temp_im, dk); + } + + if (!phi[1][0][0].mant) { + a00 = FLOAT_0; + a01 = FLOAT_0; + } else { + SoftFloat temp_real, temp_im; + temp_real = av_add_sf(phi[0][0][0], + av_add_sf(av_mul_sf(a10, phi[1][1][0]), + av_mul_sf(a11, phi[1][1][1]))); + temp_im = av_add_sf(phi[0][0][1], + av_sub_sf(av_mul_sf(a11, phi[1][1][0]), + av_mul_sf(a10, phi[1][1][1]))); + + temp_real.mant = -temp_real.mant; + temp_im.mant = -temp_im.mant; + a00 = av_div_sf(temp_real, phi[1][0][0]); + a01 = av_div_sf(temp_im, phi[1][0][0]); + } + + shift = a00.exp; + if (shift >= 3) + alpha0[k][0] = 0x7fffffff; + else if (shift <= -30) + alpha0[k][0] = 0; + else { + shift = 1-shift; + if (shift <= 0) + alpha0[k][0] = a00.mant * (1<<-shift); + else { + round = 1 << (shift-1); + alpha0[k][0] = (a00.mant + round) >> shift; + } + } + + shift = a01.exp; + if (shift >= 3) + alpha0[k][1] = 0x7fffffff; + else if (shift <= -30) + alpha0[k][1] = 0; + else { + shift = 1-shift; + if (shift <= 0) + alpha0[k][1] = a01.mant * (1<<-shift); + else { + round = 1 << (shift-1); + alpha0[k][1] = (a01.mant + round) >> shift; + } + } + shift = a10.exp; + if (shift >= 3) + alpha1[k][0] = 0x7fffffff; + else if (shift <= -30) + alpha1[k][0] = 0; + else { + shift = 1-shift; + if (shift <= 0) + alpha1[k][0] = a10.mant * (1<<-shift); + else { + round = 1 << (shift-1); + alpha1[k][0] = (a10.mant + round) >> shift; + } + } + + shift = a11.exp; + if (shift >= 3) + alpha1[k][1] = 0x7fffffff; + else if (shift <= -30) + alpha1[k][1] = 0; + else { + shift = 1-shift; + if (shift <= 0) + alpha1[k][1] = a11.mant * (1<<-shift); + else { + round = 1 << (shift-1); + alpha1[k][1] = (a11.mant + round) >> shift; + } + } + + shift = (int)(((int64_t)(alpha1[k][0]>>1) * (alpha1[k][0]>>1) + \ + (int64_t)(alpha1[k][1]>>1) * (alpha1[k][1]>>1) + \ + 0x40000000) >> 31); + if (shift >= 0x20000000){ + alpha1[k][0] = 0; + alpha1[k][1] = 0; + alpha0[k][0] = 0; + alpha0[k][1] = 0; + } + + shift = (int)(((int64_t)(alpha0[k][0]>>1) * (alpha0[k][0]>>1) + \ + (int64_t)(alpha0[k][1]>>1) * (alpha0[k][1]>>1) + \ + 0x40000000) >> 31); + if (shift >= 0x20000000){ + alpha1[k][0] = 0; + alpha1[k][1] = 0; + alpha0[k][0] = 0; + alpha0[k][1] = 0; + } + } +} + +/// Chirp Factors (14496-3 sp04 p214) +static void sbr_chirp(SpectralBandReplication *sbr, SBRData *ch_data) +{ + int i; + int new_bw; + static const int bw_tab[] = { 0, 1610612736, 1932735283, 2104533975 }; + int64_t accu; + + for (i = 0; i < sbr->n_q; i++) { + if (ch_data->bs_invf_mode[0][i] + ch_data->bs_invf_mode[1][i] == 1) + new_bw = 1288490189; + else + new_bw = bw_tab[ch_data->bs_invf_mode[0][i]]; + + if (new_bw < ch_data->bw_array[i]){ + accu = (int64_t)new_bw * 1610612736; + accu += (int64_t)ch_data->bw_array[i] * 0x20000000; + new_bw = (int)((accu + 0x40000000) >> 31); + } else { + accu = (int64_t)new_bw * 1946157056; + accu += (int64_t)ch_data->bw_array[i] * 201326592; + new_bw = (int)((accu + 0x40000000) >> 31); + } + ch_data->bw_array[i] = new_bw < 0x2000000 ? 0 : new_bw; + } +} + +/** + * Calculation of levels of additional HF signal components (14496-3 sp04 p219) + * and Calculation of gain (14496-3 sp04 p219) + */ +static void sbr_gain_calc(AACContext *ac, SpectralBandReplication *sbr, + SBRData *ch_data, const int e_a[2]) +{ + int e, k, m; + // max gain limits : -3dB, 0dB, 3dB, inf dB (limiter off) + static const SoftFloat limgain[4] = { { 760155524, 0 }, { 0x20000000, 1 }, + { 758351638, 1 }, { 625000000, 34 } }; + + for (e = 0; e < ch_data->bs_num_env; e++) { + int delta = !((e == e_a[1]) || (e == e_a[0])); + for (k = 0; k < sbr->n_lim; k++) { + SoftFloat gain_boost, gain_max; + SoftFloat sum[2]; + sum[0] = sum[1] = FLOAT_0; + for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { + const SoftFloat temp = av_div_sf(sbr->e_origmapped[e][m], + av_add_sf(FLOAT_1, sbr->q_mapped[e][m])); + sbr->q_m[e][m] = av_sqrt_sf(av_mul_sf(temp, sbr->q_mapped[e][m])); + sbr->s_m[e][m] = av_sqrt_sf(av_mul_sf(temp, av_int2sf(ch_data->s_indexmapped[e + 1][m], 0))); + if (!sbr->s_mapped[e][m]) { + if (delta) { + sbr->gain[e][m] = av_sqrt_sf(av_div_sf(sbr->e_origmapped[e][m], + av_mul_sf(av_add_sf(FLOAT_1, sbr->e_curr[e][m]), + av_add_sf(FLOAT_1, sbr->q_mapped[e][m])))); + } else { + sbr->gain[e][m] = av_sqrt_sf(av_div_sf(sbr->e_origmapped[e][m], + av_add_sf(FLOAT_1, sbr->e_curr[e][m]))); + } + } else { + sbr->gain[e][m] = av_sqrt_sf( + av_div_sf( + av_mul_sf(sbr->e_origmapped[e][m], sbr->q_mapped[e][m]), + av_mul_sf( + av_add_sf(FLOAT_1, sbr->e_curr[e][m]), + av_add_sf(FLOAT_1, sbr->q_mapped[e][m])))); + } + sbr->gain[e][m] = av_add_sf(sbr->gain[e][m], FLOAT_MIN); + } + for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { + sum[0] = av_add_sf(sum[0], sbr->e_origmapped[e][m]); + sum[1] = av_add_sf(sum[1], sbr->e_curr[e][m]); + } + gain_max = av_mul_sf(limgain[sbr->bs_limiter_gains], + av_sqrt_sf( + av_div_sf( + av_add_sf(FLOAT_EPSILON, sum[0]), + av_add_sf(FLOAT_EPSILON, sum[1])))); + if (av_gt_sf(gain_max, FLOAT_100000)) + gain_max = FLOAT_100000; + for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { + SoftFloat q_m_max = av_div_sf( + av_mul_sf(sbr->q_m[e][m], gain_max), + sbr->gain[e][m]); + if (av_gt_sf(sbr->q_m[e][m], q_m_max)) + sbr->q_m[e][m] = q_m_max; + if (av_gt_sf(sbr->gain[e][m], gain_max)) + sbr->gain[e][m] = gain_max; + } + sum[0] = sum[1] = FLOAT_0; + for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { + sum[0] = av_add_sf(sum[0], sbr->e_origmapped[e][m]); + sum[1] = av_add_sf(sum[1], + av_mul_sf( + av_mul_sf(sbr->e_curr[e][m], + sbr->gain[e][m]), + sbr->gain[e][m])); + sum[1] = av_add_sf(sum[1], + av_mul_sf(sbr->s_m[e][m], sbr->s_m[e][m])); + if (delta && !sbr->s_m[e][m].mant) + sum[1] = av_add_sf(sum[1], + av_mul_sf(sbr->q_m[e][m], sbr->q_m[e][m])); + } + gain_boost = av_sqrt_sf( + av_div_sf( + av_add_sf(FLOAT_EPSILON, sum[0]), + av_add_sf(FLOAT_EPSILON, sum[1]))); + if (av_gt_sf(gain_boost, FLOAT_1584893192)) + gain_boost = FLOAT_1584893192; + + for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { + sbr->gain[e][m] = av_mul_sf(sbr->gain[e][m], gain_boost); + sbr->q_m[e][m] = av_mul_sf(sbr->q_m[e][m], gain_boost); + sbr->s_m[e][m] = av_mul_sf(sbr->s_m[e][m], gain_boost); + } + } + } +} + +/// Assembling HF Signals (14496-3 sp04 p220) +static void sbr_hf_assemble(int Y1[38][64][2], + const int X_high[64][40][2], + SpectralBandReplication *sbr, SBRData *ch_data, + const int e_a[2]) +{ + int e, i, j, m; + const int h_SL = 4 * !sbr->bs_smoothing_mode; + const int kx = sbr->kx[1]; + const int m_max = sbr->m[1]; + static const SoftFloat h_smooth[5] = { + { 715827883, -1 }, + { 647472402, -1 }, + { 937030863, -2 }, + { 989249804, -3 }, + { 546843842, -4 }, + }; + SoftFloat (*g_temp)[48] = ch_data->g_temp, (*q_temp)[48] = ch_data->q_temp; + int indexnoise = ch_data->f_indexnoise; + int indexsine = ch_data->f_indexsine; + + if (sbr->reset) { + for (i = 0; i < h_SL; i++) { + memcpy(g_temp[i + 2*ch_data->t_env[0]], sbr->gain[0], m_max * sizeof(sbr->gain[0][0])); + memcpy(q_temp[i + 2*ch_data->t_env[0]], sbr->q_m[0], m_max * sizeof(sbr->q_m[0][0])); + } + } else if (h_SL) { + for (i = 0; i < 4; i++) { + memcpy(g_temp[i + 2 * ch_data->t_env[0]], + g_temp[i + 2 * ch_data->t_env_num_env_old], + sizeof(g_temp[0])); + memcpy(q_temp[i + 2 * ch_data->t_env[0]], + q_temp[i + 2 * ch_data->t_env_num_env_old], + sizeof(q_temp[0])); + } + } + + for (e = 0; e < ch_data->bs_num_env; e++) { + for (i = 2 * ch_data->t_env[e]; i < 2 * ch_data->t_env[e + 1]; i++) { + memcpy(g_temp[h_SL + i], sbr->gain[e], m_max * sizeof(sbr->gain[0][0])); + memcpy(q_temp[h_SL + i], sbr->q_m[e], m_max * sizeof(sbr->q_m[0][0])); + } + } + + for (e = 0; e < ch_data->bs_num_env; e++) { + for (i = 2 * ch_data->t_env[e]; i < 2 * ch_data->t_env[e + 1]; i++) { + SoftFloat g_filt_tab[48]; + SoftFloat q_filt_tab[48]; + SoftFloat *g_filt, *q_filt; + + if (h_SL && e != e_a[0] && e != e_a[1]) { + g_filt = g_filt_tab; + q_filt = q_filt_tab; + for (m = 0; m < m_max; m++) { + const int idx1 = i + h_SL; + g_filt[m].mant = g_filt[m].exp = 0; + q_filt[m].mant = q_filt[m].exp = 0; + for (j = 0; j <= h_SL; j++) { + g_filt[m] = av_add_sf(g_filt[m], + av_mul_sf(g_temp[idx1 - j][m], + h_smooth[j])); + q_filt[m] = av_add_sf(q_filt[m], + av_mul_sf(q_temp[idx1 - j][m], + h_smooth[j])); + } + } + } else { + g_filt = g_temp[i + h_SL]; + q_filt = q_temp[i]; + } + + sbr->dsp.hf_g_filt(Y1[i] + kx, X_high + kx, g_filt, m_max, + i + ENVELOPE_ADJUSTMENT_OFFSET); + + if (e != e_a[0] && e != e_a[1]) { + sbr->dsp.hf_apply_noise[indexsine](Y1[i] + kx, sbr->s_m[e], + q_filt, indexnoise, + kx, m_max); + } else { + int idx = indexsine&1; + int A = (1-((indexsine+(kx & 1))&2)); + int B = (A^(-idx)) + idx; + unsigned *out = &Y1[i][kx][idx]; + int shift; + unsigned round; + + SoftFloat *in = sbr->s_m[e]; + for (m = 0; m+1 < m_max; m+=2) { + int shift2; + shift = 22 - in[m ].exp; + shift2= 22 - in[m+1].exp; + if (shift < 1 || shift2 < 1) { + av_log(NULL, AV_LOG_ERROR, "Overflow in sbr_hf_assemble, shift=%d,%d\n", shift, shift2); + return; + } + if (shift < 32) { + round = 1 << (shift-1); + out[2*m ] += (int)(in[m ].mant * A + round) >> shift; + } + + if (shift2 < 32) { + round = 1 << (shift2-1); + out[2*m+2] += (int)(in[m+1].mant * B + round) >> shift2; + } + } + if(m_max&1) + { + shift = 22 - in[m ].exp; + if (shift < 1) { + av_log(NULL, AV_LOG_ERROR, "Overflow in sbr_hf_assemble, shift=%d\n", shift); + return; + } else if (shift < 32) { + round = 1 << (shift-1); + out[2*m ] += (int)(in[m ].mant * A + round) >> shift; + } + } + } + indexnoise = (indexnoise + m_max) & 0x1ff; + indexsine = (indexsine + 1) & 3; + } + } + ch_data->f_indexnoise = indexnoise; + ch_data->f_indexsine = indexsine; +} + +#include "aacsbr_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_fixed_tablegen.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_fixed_tablegen.h new file mode 100644 index 0000000000..3fcf0204c3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_fixed_tablegen.h @@ -0,0 +1,28 @@ +/* + * Header file for hardcoded AAC SBR windows + * + * Copyright (c) 2014 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AACSBR_FIXED_TABLEGEN_H +#define AVCODEC_AACSBR_FIXED_TABLEGEN_H + +#include "aacsbr_tablegen_common.h" + +#endif /* AVCODEC_AACSBR_FIXED_TABLEGEN_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_tablegen.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_tablegen.h new file mode 100644 index 0000000000..242a963557 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_tablegen.h @@ -0,0 +1,28 @@ +/* + * Header file for hardcoded AAC SBR windows + * + * Copyright (c) 2014 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AACSBR_TABLEGEN_H +#define AVCODEC_AACSBR_TABLEGEN_H + +#include "aacsbr_tablegen_common.h" + +#endif /* AVCODEC_AACSBR_TABLEGEN_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_tablegen_common.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_tablegen_common.h new file mode 100644 index 0000000000..8e0dd9e1fd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_tablegen_common.h @@ -0,0 +1,114 @@ +/* + * Header file for hardcoded AAC SBR windows + * + * Copyright (c) 2014 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AACSBR_TABLEGEN_COMMON_H +#define AVCODEC_AACSBR_TABLEGEN_COMMON_H +#include "aac_defines.h" +#include "libavutil/mem.h" + +///< window coefficients for analysis/synthesis QMF banks +static DECLARE_ALIGNED(32, INTFLOAT, sbr_qmf_window_ds)[320]; +static DECLARE_ALIGNED(32, INTFLOAT, sbr_qmf_window_us)[640] = { + Q31( 0.0000000000f), Q31(-0.0005525286f), Q31(-0.0005617692f), Q31(-0.0004947518f), + Q31(-0.0004875227f), Q31(-0.0004893791f), Q31(-0.0005040714f), Q31(-0.0005226564f), + Q31(-0.0005466565f), Q31(-0.0005677802f), Q31(-0.0005870930f), Q31(-0.0006132747f), + Q31(-0.0006312493f), Q31(-0.0006540333f), Q31(-0.0006777690f), Q31(-0.0006941614f), + Q31(-0.0007157736f), Q31(-0.0007255043f), Q31(-0.0007440941f), Q31(-0.0007490598f), + Q31(-0.0007681371f), Q31(-0.0007724848f), Q31(-0.0007834332f), Q31(-0.0007779869f), + Q31(-0.0007803664f), Q31(-0.0007801449f), Q31(-0.0007757977f), Q31(-0.0007630793f), + Q31(-0.0007530001f), Q31(-0.0007319357f), Q31(-0.0007215391f), Q31(-0.0006917937f), + Q31(-0.0006650415f), Q31(-0.0006341594f), Q31(-0.0005946118f), Q31(-0.0005564576f), + Q31(-0.0005145572f), Q31(-0.0004606325f), Q31(-0.0004095121f), Q31(-0.0003501175f), + Q31(-0.0002896981f), Q31(-0.0002098337f), Q31(-0.0001446380f), Q31(-0.0000617334f), + Q31( 0.0000134949f), Q31( 0.0001094383f), Q31( 0.0002043017f), Q31( 0.0002949531f), + Q31( 0.0004026540f), Q31( 0.0005107388f), Q31( 0.0006239376f), Q31( 0.0007458025f), + Q31( 0.0008608443f), Q31( 0.0009885988f), Q31( 0.0011250155f), Q31( 0.0012577884f), + Q31( 0.0013902494f), Q31( 0.0015443219f), Q31( 0.0016868083f), Q31( 0.0018348265f), + Q31( 0.0019841140f), Q31( 0.0021461583f), Q31( 0.0023017254f), Q31( 0.0024625616f), + Q31( 0.0026201758f), Q31( 0.0027870464f), Q31( 0.0029469447f), Q31( 0.0031125420f), + Q31( 0.0032739613f), Q31( 0.0034418874f), Q31( 0.0036008268f), Q31( 0.0037603922f), + Q31( 0.0039207432f), Q31( 0.0040819753f), Q31( 0.0042264269f), Q31( 0.0043730719f), + Q31( 0.0045209852f), Q31( 0.0046606460f), Q31( 0.0047932560f), Q31( 0.0049137603f), + Q31( 0.0050393022f), Q31( 0.0051407353f), Q31( 0.0052461166f), Q31( 0.0053471681f), + Q31( 0.0054196775f), Q31( 0.0054876040f), Q31( 0.0055475714f), Q31( 0.0055938023f), + Q31( 0.0056220643f), Q31( 0.0056455196f), Q31( 0.0056389199f), Q31( 0.0056266114f), + Q31( 0.0055917128f), Q31( 0.0055404363f), Q31( 0.0054753783f), Q31( 0.0053838975f), + Q31( 0.0052715758f), Q31( 0.0051382275f), Q31( 0.0049839687f), Q31( 0.0048109469f), + Q31( 0.0046039530f), Q31( 0.0043801861f), Q31( 0.0041251642f), Q31( 0.0038456408f), + Q31( 0.0035401246f), Q31( 0.0032091885f), Q31( 0.0028446757f), Q31( 0.0024508540f), + Q31( 0.0020274176f), Q31( 0.0015784682f), Q31( 0.0010902329f), Q31( 0.0005832264f), + Q31( 0.0000276045f), Q31(-0.0005464280f), Q31(-0.0011568135f), Q31(-0.0018039472f), + Q31(-0.0024826723f), Q31(-0.0031933778f), Q31(-0.0039401124f), Q31(-0.0047222596f), + Q31(-0.0055337211f), Q31(-0.0063792293f), Q31(-0.0072615816f), Q31(-0.0081798233f), + Q31(-0.0091325329f), Q31(-0.0101150215f), Q31(-0.0111315548f), Q31(-0.0121849995f), + Q31( 0.0132718220f), Q31( 0.0143904666f), Q31( 0.0155405553f), Q31( 0.0167324712f), + Q31( 0.0179433381f), Q31( 0.0191872431f), Q31( 0.0204531793f), Q31( 0.0217467550f), + Q31( 0.0230680169f), Q31( 0.0244160992f), Q31( 0.0257875847f), Q31( 0.0271859429f), + Q31( 0.0286072173f), Q31( 0.0300502657f), Q31( 0.0315017608f), Q31( 0.0329754081f), + Q31( 0.0344620948f), Q31( 0.0359697560f), Q31( 0.0374812850f), Q31( 0.0390053679f), + Q31( 0.0405349170f), Q31( 0.0420649094f), Q31( 0.0436097542f), Q31( 0.0451488405f), + Q31( 0.0466843027f), Q31( 0.0482165720f), Q31( 0.0497385755f), Q31( 0.0512556155f), + Q31( 0.0527630746f), Q31( 0.0542452768f), Q31( 0.0557173648f), Q31( 0.0571616450f), + Q31( 0.0585915683f), Q31( 0.0599837480f), Q31( 0.0613455171f), Q31( 0.0626857808f), + Q31( 0.0639715898f), Q31( 0.0652247106f), Q31( 0.0664367512f), Q31( 0.0676075985f), + Q31( 0.0687043828f), Q31( 0.0697630244f), Q31( 0.0707628710f), Q31( 0.0717002673f), + Q31( 0.0725682583f), Q31( 0.0733620255f), Q31( 0.0741003642f), Q31( 0.0747452558f), + Q31( 0.0753137336f), Q31( 0.0758008358f), Q31( 0.0761992479f), Q31( 0.0764992170f), + Q31( 0.0767093490f), Q31( 0.0768173975f), Q31( 0.0768230011f), Q31( 0.0767204924f), + Q31( 0.0765050718f), Q31( 0.0761748321f), Q31( 0.0757305756f), Q31( 0.0751576255f), + Q31( 0.0744664394f), Q31( 0.0736406005f), Q31( 0.0726774642f), Q31( 0.0715826364f), + Q31( 0.0703533073f), Q31( 0.0689664013f), Q31( 0.0674525021f), Q31( 0.0657690668f), + Q31( 0.0639444805f), Q31( 0.0619602779f), Q31( 0.0598166570f), Q31( 0.0575152691f), + Q31( 0.0550460034f), Q31( 0.0524093821f), Q31( 0.0495978676f), Q31( 0.0466303305f), + Q31( 0.0434768782f), Q31( 0.0401458278f), Q31( 0.0366418116f), Q31( 0.0329583930f), + Q31( 0.0290824006f), Q31( 0.0250307561f), Q31( 0.0207997072f), Q31( 0.0163701258f), + Q31( 0.0117623832f), Q31( 0.0069636862f), Q31( 0.0019765601f), Q31(-0.0032086896f), + Q31(-0.0085711749f), Q31(-0.0141288827f), Q31(-0.0198834129f), Q31(-0.0258227288f), + Q31(-0.0319531274f), Q31(-0.0382776572f), Q31(-0.0447806821f), Q31(-0.0514804176f), + Q31(-0.0583705326f), Q31(-0.0654409853f), Q31(-0.0726943300f), Q31(-0.0801372934f), + Q31(-0.0877547536f), Q31(-0.0955533352f), Q31(-0.1035329531f), Q31(-0.1116826931f), + Q31(-0.1200077984f), Q31(-0.1285002850f), Q31(-0.1371551761f), Q31(-0.1459766491f), + Q31(-0.1549607071f), Q31(-0.1640958855f), Q31(-0.1733808172f), Q31(-0.1828172548f), + Q31(-0.1923966745f), Q31(-0.2021250176f), Q31(-0.2119735853f), Q31(-0.2219652696f), + Q31(-0.2320690870f), Q31(-0.2423016884f), Q31(-0.2526480309f), Q31(-0.2631053299f), + Q31(-0.2736634040f), Q31(-0.2843214189f), Q31(-0.2950716717f), Q31(-0.3059098575f), + Q31(-0.3168278913f), Q31(-0.3278113727f), Q31(-0.3388722693f), Q31(-0.3499914122f), + Q31( 0.3611589903f), Q31( 0.3723795546f), Q31( 0.3836350013f), Q31( 0.3949211761f), + Q31( 0.4062317676f), Q31( 0.4175696896f), Q31( 0.4289119920f), Q31( 0.4402553754f), + Q31( 0.4515996535f), Q31( 0.4629308085f), Q31( 0.4742453214f), Q31( 0.4855253091f), + Q31( 0.4967708254f), Q31( 0.5079817500f), Q31( 0.5191234970f), Q31( 0.5302240895f), + Q31( 0.5412553448f), Q31( 0.5522051258f), Q31( 0.5630789140f), Q31( 0.5738524131f), + Q31( 0.5845403235f), Q31( 0.5951123086f), Q31( 0.6055783538f), Q31( 0.6159109932f), + Q31( 0.6261242695f), Q31( 0.6361980107f), Q31( 0.6461269695f), Q31( 0.6559016302f), + Q31( 0.6655139880f), Q31( 0.6749663190f), Q31( 0.6842353293f), Q31( 0.6933282376f), + Q31( 0.7022388719f), Q31( 0.7109410426f), Q31( 0.7194462634f), Q31( 0.7277448900f), + Q31( 0.7358211758f), Q31( 0.7436827863f), Q31( 0.7513137456f), Q31( 0.7587080760f), + Q31( 0.7658674865f), Q31( 0.7727780881f), Q31( 0.7794287519f), Q31( 0.7858353120f), + Q31( 0.7919735841f), Q31( 0.7978466413f), Q31( 0.8034485751f), Q31( 0.8087695004f), + Q31( 0.8138191270f), Q31( 0.8185776004f), Q31( 0.8230419890f), Q31( 0.8272275347f), + Q31( 0.8311038457f), Q31( 0.8346937361f), Q31( 0.8379717337f), Q31( 0.8409541392f), + Q31( 0.8436238281f), Q31( 0.8459818469f), Q31( 0.8480315777f), Q31( 0.8497805198f), + Q31( 0.8511971524f), Q31( 0.8523047035f), Q31( 0.8531020949f), Q31( 0.8535720573f), + Q31( 0.8537385600f), +}; + +#endif /* AVCODEC_AACSBR_TABLEGEN_COMMON_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_template.c new file mode 100644 index 0000000000..821615f2ab --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbr_template.c @@ -0,0 +1,1583 @@ +/* + * AAC Spectral Band Replication decoding functions + * Copyright (c) 2008-2009 Robert Swain ( rob opendot cl ) + * Copyright (c) 2009-2010 Alex Converse + * + * Fixed point code + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC Spectral Band Replication decoding functions + * @author Robert Swain ( rob opendot cl ) + * @author Stanislav Ocovaj ( stanislav.ocovaj@imgtec.com ) + * @author Zoran Basaric ( zoran.basaric@imgtec.com ) + */ + +#include "libavutil/qsort.h" + +static av_cold void aacsbr_tableinit(void) +{ + int n; + for (n = 1; n < 320; n++) + sbr_qmf_window_us[320 + n] = sbr_qmf_window_us[320 - n]; + sbr_qmf_window_us[384] = -sbr_qmf_window_us[384]; + sbr_qmf_window_us[512] = -sbr_qmf_window_us[512]; + + for (n = 0; n < 320; n++) + sbr_qmf_window_ds[n] = sbr_qmf_window_us[2*n]; +} + +av_cold void AAC_RENAME(ff_aac_sbr_init)(void) +{ + static const struct { + const void *sbr_codes, *sbr_bits; + const unsigned int table_size, elem_size; + } sbr_tmp[] = { + SBR_VLC_ROW(t_huffman_env_1_5dB), + SBR_VLC_ROW(f_huffman_env_1_5dB), + SBR_VLC_ROW(t_huffman_env_bal_1_5dB), + SBR_VLC_ROW(f_huffman_env_bal_1_5dB), + SBR_VLC_ROW(t_huffman_env_3_0dB), + SBR_VLC_ROW(f_huffman_env_3_0dB), + SBR_VLC_ROW(t_huffman_env_bal_3_0dB), + SBR_VLC_ROW(f_huffman_env_bal_3_0dB), + SBR_VLC_ROW(t_huffman_noise_3_0dB), + SBR_VLC_ROW(t_huffman_noise_bal_3_0dB), + }; + + // SBR VLC table initialization + SBR_INIT_VLC_STATIC(0, 1098); + SBR_INIT_VLC_STATIC(1, 1092); + SBR_INIT_VLC_STATIC(2, 768); + SBR_INIT_VLC_STATIC(3, 1026); + SBR_INIT_VLC_STATIC(4, 1058); + SBR_INIT_VLC_STATIC(5, 1052); + SBR_INIT_VLC_STATIC(6, 544); + SBR_INIT_VLC_STATIC(7, 544); + SBR_INIT_VLC_STATIC(8, 592); + SBR_INIT_VLC_STATIC(9, 512); + + aacsbr_tableinit(); + + AAC_RENAME(ff_ps_init)(); +} + +/** Places SBR in pure upsampling mode. */ +static void sbr_turnoff(SpectralBandReplication *sbr) { + sbr->start = 0; + sbr->ready_for_dequant = 0; + // Init defults used in pure upsampling mode + sbr->kx[1] = 32; //Typo in spec, kx' inits to 32 + sbr->m[1] = 0; + // Reset values for first SBR header + sbr->data[0].e_a[1] = sbr->data[1].e_a[1] = -1; + memset(&sbr->spectrum_params, -1, sizeof(SpectrumParameters)); +} + +av_cold void AAC_RENAME(ff_aac_sbr_ctx_init)(AACContext *ac, SpectralBandReplication *sbr, int id_aac) +{ + if(sbr->mdct.mdct_bits) + return; + sbr->kx[0] = sbr->kx[1]; + sbr->id_aac = id_aac; + sbr_turnoff(sbr); + sbr->data[0].synthesis_filterbank_samples_offset = SBR_SYNTHESIS_BUF_SIZE - (1280 - 128); + sbr->data[1].synthesis_filterbank_samples_offset = SBR_SYNTHESIS_BUF_SIZE - (1280 - 128); + /* SBR requires samples to be scaled to +/-32768.0 to work correctly. + * mdct scale factors are adjusted to scale up from +/-1.0 at analysis + * and scale back down at synthesis. */ + AAC_RENAME_32(ff_mdct_init)(&sbr->mdct, 7, 1, 1.0 / (64 * 32768.0)); + AAC_RENAME_32(ff_mdct_init)(&sbr->mdct_ana, 7, 1, -2.0 * 32768.0); + AAC_RENAME(ff_ps_ctx_init)(&sbr->ps); + AAC_RENAME(ff_sbrdsp_init)(&sbr->dsp); + aacsbr_func_ptr_init(&sbr->c); +} + +av_cold void AAC_RENAME(ff_aac_sbr_ctx_close)(SpectralBandReplication *sbr) +{ + AAC_RENAME_32(ff_mdct_end)(&sbr->mdct); + AAC_RENAME_32(ff_mdct_end)(&sbr->mdct_ana); +} + +static int qsort_comparison_function_int16(const void *a, const void *b) +{ + return *(const int16_t *)a - *(const int16_t *)b; +} + +static inline int in_table_int16(const int16_t *table, int last_el, int16_t needle) +{ + int i; + for (i = 0; i <= last_el; i++) + if (table[i] == needle) + return 1; + return 0; +} + +/// Limiter Frequency Band Table (14496-3 sp04 p198) +static void sbr_make_f_tablelim(SpectralBandReplication *sbr) +{ + int k; + if (sbr->bs_limiter_bands > 0) { + static const INTFLOAT bands_warped[3] = { Q23(1.32715174233856803909f), //2^(0.49/1.2) + Q23(1.18509277094158210129f), //2^(0.49/2) + Q23(1.11987160404675912501f) }; //2^(0.49/3) + const INTFLOAT lim_bands_per_octave_warped = bands_warped[sbr->bs_limiter_bands - 1]; + int16_t patch_borders[7]; + uint16_t *in = sbr->f_tablelim + 1, *out = sbr->f_tablelim; + + patch_borders[0] = sbr->kx[1]; + for (k = 1; k <= sbr->num_patches; k++) + patch_borders[k] = patch_borders[k-1] + sbr->patch_num_subbands[k-1]; + + memcpy(sbr->f_tablelim, sbr->f_tablelow, + (sbr->n[0] + 1) * sizeof(sbr->f_tablelow[0])); + if (sbr->num_patches > 1) + memcpy(sbr->f_tablelim + sbr->n[0] + 1, patch_borders + 1, + (sbr->num_patches - 1) * sizeof(patch_borders[0])); + + AV_QSORT(sbr->f_tablelim, sbr->num_patches + sbr->n[0], + uint16_t, + qsort_comparison_function_int16); + + sbr->n_lim = sbr->n[0] + sbr->num_patches - 1; + while (out < sbr->f_tablelim + sbr->n_lim) { +#if USE_FIXED + if ((*in << 23) >= *out * lim_bands_per_octave_warped) { +#else + if (*in >= *out * lim_bands_per_octave_warped) { +#endif /* USE_FIXED */ + *++out = *in++; + } else if (*in == *out || + !in_table_int16(patch_borders, sbr->num_patches, *in)) { + in++; + sbr->n_lim--; + } else if (!in_table_int16(patch_borders, sbr->num_patches, *out)) { + *out = *in++; + sbr->n_lim--; + } else { + *++out = *in++; + } + } + } else { + sbr->f_tablelim[0] = sbr->f_tablelow[0]; + sbr->f_tablelim[1] = sbr->f_tablelow[sbr->n[0]]; + sbr->n_lim = 1; + } +} + +static unsigned int read_sbr_header(SpectralBandReplication *sbr, GetBitContext *gb) +{ + unsigned int cnt = get_bits_count(gb); + uint8_t bs_header_extra_1; + uint8_t bs_header_extra_2; + int old_bs_limiter_bands = sbr->bs_limiter_bands; + SpectrumParameters old_spectrum_params; + + sbr->start = 1; + sbr->ready_for_dequant = 0; + + // Save last spectrum parameters variables to compare to new ones + memcpy(&old_spectrum_params, &sbr->spectrum_params, sizeof(SpectrumParameters)); + + sbr->bs_amp_res_header = get_bits1(gb); + sbr->spectrum_params.bs_start_freq = get_bits(gb, 4); + sbr->spectrum_params.bs_stop_freq = get_bits(gb, 4); + sbr->spectrum_params.bs_xover_band = get_bits(gb, 3); + skip_bits(gb, 2); // bs_reserved + + bs_header_extra_1 = get_bits1(gb); + bs_header_extra_2 = get_bits1(gb); + + if (bs_header_extra_1) { + sbr->spectrum_params.bs_freq_scale = get_bits(gb, 2); + sbr->spectrum_params.bs_alter_scale = get_bits1(gb); + sbr->spectrum_params.bs_noise_bands = get_bits(gb, 2); + } else { + sbr->spectrum_params.bs_freq_scale = 2; + sbr->spectrum_params.bs_alter_scale = 1; + sbr->spectrum_params.bs_noise_bands = 2; + } + + // Check if spectrum parameters changed + if (memcmp(&old_spectrum_params, &sbr->spectrum_params, sizeof(SpectrumParameters))) + sbr->reset = 1; + + if (bs_header_extra_2) { + sbr->bs_limiter_bands = get_bits(gb, 2); + sbr->bs_limiter_gains = get_bits(gb, 2); + sbr->bs_interpol_freq = get_bits1(gb); + sbr->bs_smoothing_mode = get_bits1(gb); + } else { + sbr->bs_limiter_bands = 2; + sbr->bs_limiter_gains = 2; + sbr->bs_interpol_freq = 1; + sbr->bs_smoothing_mode = 1; + } + + if (sbr->bs_limiter_bands != old_bs_limiter_bands && !sbr->reset) + sbr_make_f_tablelim(sbr); + + return get_bits_count(gb) - cnt; +} + +static int array_min_int16(const int16_t *array, int nel) +{ + int i, min = array[0]; + for (i = 1; i < nel; i++) + min = FFMIN(array[i], min); + return min; +} + +static int check_n_master(AVCodecContext *avctx, int n_master, int bs_xover_band) +{ + // Requirements (14496-3 sp04 p205) + if (n_master <= 0) { + av_log(avctx, AV_LOG_ERROR, "Invalid n_master: %d\n", n_master); + return -1; + } + if (bs_xover_band >= n_master) { + av_log(avctx, AV_LOG_ERROR, + "Invalid bitstream, crossover band index beyond array bounds: %d\n", + bs_xover_band); + return -1; + } + return 0; +} + +/// Master Frequency Band Table (14496-3 sp04 p194) +static int sbr_make_f_master(AACContext *ac, SpectralBandReplication *sbr, + SpectrumParameters *spectrum) +{ + unsigned int temp, max_qmf_subbands = 0; + unsigned int start_min, stop_min; + int k; + const int8_t *sbr_offset_ptr; + int16_t stop_dk[13]; + + switch (sbr->sample_rate) { + case 16000: + sbr_offset_ptr = sbr_offset[0]; + break; + case 22050: + sbr_offset_ptr = sbr_offset[1]; + break; + case 24000: + sbr_offset_ptr = sbr_offset[2]; + break; + case 32000: + sbr_offset_ptr = sbr_offset[3]; + break; + case 44100: case 48000: case 64000: + sbr_offset_ptr = sbr_offset[4]; + break; + case 88200: case 96000: case 128000: case 176400: case 192000: + sbr_offset_ptr = sbr_offset[5]; + break; + default: + av_log(ac->avctx, AV_LOG_ERROR, + "Unsupported sample rate for SBR: %d\n", sbr->sample_rate); + return -1; + } + + if (sbr->sample_rate < 32000) { + temp = 3000; + } else if (sbr->sample_rate < 64000) { + temp = 4000; + } else + temp = 5000; + + start_min = ((temp << 7) + (sbr->sample_rate >> 1)) / sbr->sample_rate; + stop_min = ((temp << 8) + (sbr->sample_rate >> 1)) / sbr->sample_rate; + + sbr->k[0] = start_min + sbr_offset_ptr[spectrum->bs_start_freq]; + + if (spectrum->bs_stop_freq < 14) { + sbr->k[2] = stop_min; + make_bands(stop_dk, stop_min, 64, 13); + AV_QSORT(stop_dk, 13, int16_t, qsort_comparison_function_int16); + for (k = 0; k < spectrum->bs_stop_freq; k++) + sbr->k[2] += stop_dk[k]; + } else if (spectrum->bs_stop_freq == 14) { + sbr->k[2] = 2*sbr->k[0]; + } else if (spectrum->bs_stop_freq == 15) { + sbr->k[2] = 3*sbr->k[0]; + } else { + av_log(ac->avctx, AV_LOG_ERROR, + "Invalid bs_stop_freq: %d\n", spectrum->bs_stop_freq); + return -1; + } + sbr->k[2] = FFMIN(64, sbr->k[2]); + + // Requirements (14496-3 sp04 p205) + if (sbr->sample_rate <= 32000) { + max_qmf_subbands = 48; + } else if (sbr->sample_rate == 44100) { + max_qmf_subbands = 35; + } else if (sbr->sample_rate >= 48000) + max_qmf_subbands = 32; + else + av_assert0(0); + + if (sbr->k[2] - sbr->k[0] > max_qmf_subbands) { + av_log(ac->avctx, AV_LOG_ERROR, + "Invalid bitstream, too many QMF subbands: %d\n", sbr->k[2] - sbr->k[0]); + return -1; + } + + if (!spectrum->bs_freq_scale) { + int dk, k2diff; + + dk = spectrum->bs_alter_scale + 1; + sbr->n_master = ((sbr->k[2] - sbr->k[0] + (dk&2)) >> dk) << 1; + if (check_n_master(ac->avctx, sbr->n_master, sbr->spectrum_params.bs_xover_band)) + return -1; + + for (k = 1; k <= sbr->n_master; k++) + sbr->f_master[k] = dk; + + k2diff = sbr->k[2] - sbr->k[0] - sbr->n_master * dk; + if (k2diff < 0) { + sbr->f_master[1]--; + sbr->f_master[2]-= (k2diff < -1); + } else if (k2diff) { + sbr->f_master[sbr->n_master]++; + } + + sbr->f_master[0] = sbr->k[0]; + for (k = 1; k <= sbr->n_master; k++) + sbr->f_master[k] += sbr->f_master[k - 1]; + + } else { + int half_bands = 7 - spectrum->bs_freq_scale; // bs_freq_scale = {1,2,3} + int two_regions, num_bands_0; + int vdk0_max, vdk1_min; + int16_t vk0[49]; +#if USE_FIXED + int tmp, nz = 0; +#endif /* USE_FIXED */ + + if (49 * sbr->k[2] > 110 * sbr->k[0]) { + two_regions = 1; + sbr->k[1] = 2 * sbr->k[0]; + } else { + two_regions = 0; + sbr->k[1] = sbr->k[2]; + } + +#if USE_FIXED + tmp = (sbr->k[1] << 23) / sbr->k[0]; + while (tmp < 0x40000000) { + tmp <<= 1; + nz++; + } + tmp = fixed_log(tmp - 0x80000000); + tmp = (int)(((int64_t)tmp * CONST_RECIP_LN2 + 0x20000000) >> 30); + tmp = (((tmp + 0x80) >> 8) + ((8 - nz) << 23)) * half_bands; + num_bands_0 = ((tmp + 0x400000) >> 23) * 2; +#else + num_bands_0 = lrintf(half_bands * log2f(sbr->k[1] / (float)sbr->k[0])) * 2; +#endif /* USE_FIXED */ + + if (num_bands_0 <= 0) { // Requirements (14496-3 sp04 p205) + av_log(ac->avctx, AV_LOG_ERROR, "Invalid num_bands_0: %d\n", num_bands_0); + return -1; + } + + vk0[0] = 0; + + make_bands(vk0+1, sbr->k[0], sbr->k[1], num_bands_0); + + AV_QSORT(vk0 + 1, num_bands_0, int16_t, qsort_comparison_function_int16); + vdk0_max = vk0[num_bands_0]; + + vk0[0] = sbr->k[0]; + for (k = 1; k <= num_bands_0; k++) { + if (vk0[k] <= 0) { // Requirements (14496-3 sp04 p205) + av_log(ac->avctx, AV_LOG_ERROR, "Invalid vDk0[%d]: %d\n", k, vk0[k]); + return -1; + } + vk0[k] += vk0[k-1]; + } + + if (two_regions) { + int16_t vk1[49]; +#if USE_FIXED + int num_bands_1; + + tmp = (sbr->k[2] << 23) / sbr->k[1]; + nz = 0; + while (tmp < 0x40000000) { + tmp <<= 1; + nz++; + } + tmp = fixed_log(tmp - 0x80000000); + tmp = (int)(((int64_t)tmp * CONST_RECIP_LN2 + 0x20000000) >> 30); + tmp = (((tmp + 0x80) >> 8) + ((8 - nz) << 23)) * half_bands; + if (spectrum->bs_alter_scale) + tmp = (int)(((int64_t)tmp * CONST_076923 + 0x40000000) >> 31); + num_bands_1 = ((tmp + 0x400000) >> 23) * 2; +#else + float invwarp = spectrum->bs_alter_scale ? 0.76923076923076923077f + : 1.0f; // bs_alter_scale = {0,1} + int num_bands_1 = lrintf(half_bands * invwarp * + log2f(sbr->k[2] / (float)sbr->k[1])) * 2; +#endif /* USE_FIXED */ + make_bands(vk1+1, sbr->k[1], sbr->k[2], num_bands_1); + + vdk1_min = array_min_int16(vk1 + 1, num_bands_1); + + if (vdk1_min < vdk0_max) { + int change; + AV_QSORT(vk1 + 1, num_bands_1, int16_t, qsort_comparison_function_int16); + change = FFMIN(vdk0_max - vk1[1], (vk1[num_bands_1] - vk1[1]) >> 1); + vk1[1] += change; + vk1[num_bands_1] -= change; + } + + AV_QSORT(vk1 + 1, num_bands_1, int16_t, qsort_comparison_function_int16); + + vk1[0] = sbr->k[1]; + for (k = 1; k <= num_bands_1; k++) { + if (vk1[k] <= 0) { // Requirements (14496-3 sp04 p205) + av_log(ac->avctx, AV_LOG_ERROR, "Invalid vDk1[%d]: %d\n", k, vk1[k]); + return -1; + } + vk1[k] += vk1[k-1]; + } + + sbr->n_master = num_bands_0 + num_bands_1; + if (check_n_master(ac->avctx, sbr->n_master, sbr->spectrum_params.bs_xover_band)) + return -1; + memcpy(&sbr->f_master[0], vk0, + (num_bands_0 + 1) * sizeof(sbr->f_master[0])); + memcpy(&sbr->f_master[num_bands_0 + 1], vk1 + 1, + num_bands_1 * sizeof(sbr->f_master[0])); + + } else { + sbr->n_master = num_bands_0; + if (check_n_master(ac->avctx, sbr->n_master, sbr->spectrum_params.bs_xover_band)) + return -1; + memcpy(sbr->f_master, vk0, (num_bands_0 + 1) * sizeof(sbr->f_master[0])); + } + } + + return 0; +} + +/// High Frequency Generation - Patch Construction (14496-3 sp04 p216 fig. 4.46) +static int sbr_hf_calc_npatches(AACContext *ac, SpectralBandReplication *sbr) +{ + int i, k, last_k = -1, last_msb = -1, sb = 0; + int msb = sbr->k[0]; + int usb = sbr->kx[1]; + int goal_sb = ((1000 << 11) + (sbr->sample_rate >> 1)) / sbr->sample_rate; + + sbr->num_patches = 0; + + if (goal_sb < sbr->kx[1] + sbr->m[1]) { + for (k = 0; sbr->f_master[k] < goal_sb; k++) ; + } else + k = sbr->n_master; + + do { + int odd = 0; + if (k == last_k && msb == last_msb) { + av_log(ac->avctx, AV_LOG_ERROR, "patch construction failed\n"); + return AVERROR_INVALIDDATA; + } + last_k = k; + last_msb = msb; + for (i = k; i == k || sb > (sbr->k[0] - 1 + msb - odd); i--) { + sb = sbr->f_master[i]; + odd = (sb + sbr->k[0]) & 1; + } + + // Requirements (14496-3 sp04 p205) sets the maximum number of patches to 5. + // After this check the final number of patches can still be six which is + // illegal however the Coding Technologies decoder check stream has a final + // count of 6 patches + if (sbr->num_patches > 5) { + av_log(ac->avctx, AV_LOG_ERROR, "Too many patches: %d\n", sbr->num_patches); + return -1; + } + + sbr->patch_num_subbands[sbr->num_patches] = FFMAX(sb - usb, 0); + sbr->patch_start_subband[sbr->num_patches] = sbr->k[0] - odd - sbr->patch_num_subbands[sbr->num_patches]; + + if (sbr->patch_num_subbands[sbr->num_patches] > 0) { + usb = sb; + msb = sb; + sbr->num_patches++; + } else + msb = sbr->kx[1]; + + if (sbr->f_master[k] - sb < 3) + k = sbr->n_master; + } while (sb != sbr->kx[1] + sbr->m[1]); + + if (sbr->num_patches > 1 && + sbr->patch_num_subbands[sbr->num_patches - 1] < 3) + sbr->num_patches--; + + return 0; +} + +/// Derived Frequency Band Tables (14496-3 sp04 p197) +static int sbr_make_f_derived(AACContext *ac, SpectralBandReplication *sbr) +{ + int k, temp; +#if USE_FIXED + int nz = 0; +#endif /* USE_FIXED */ + + sbr->n[1] = sbr->n_master - sbr->spectrum_params.bs_xover_band; + sbr->n[0] = (sbr->n[1] + 1) >> 1; + + memcpy(sbr->f_tablehigh, &sbr->f_master[sbr->spectrum_params.bs_xover_band], + (sbr->n[1] + 1) * sizeof(sbr->f_master[0])); + sbr->m[1] = sbr->f_tablehigh[sbr->n[1]] - sbr->f_tablehigh[0]; + sbr->kx[1] = sbr->f_tablehigh[0]; + + // Requirements (14496-3 sp04 p205) + if (sbr->kx[1] + sbr->m[1] > 64) { + av_log(ac->avctx, AV_LOG_ERROR, + "Stop frequency border too high: %d\n", sbr->kx[1] + sbr->m[1]); + return -1; + } + if (sbr->kx[1] > 32) { + av_log(ac->avctx, AV_LOG_ERROR, "Start frequency border too high: %d\n", sbr->kx[1]); + return -1; + } + + sbr->f_tablelow[0] = sbr->f_tablehigh[0]; + temp = sbr->n[1] & 1; + for (k = 1; k <= sbr->n[0]; k++) + sbr->f_tablelow[k] = sbr->f_tablehigh[2 * k - temp]; +#if USE_FIXED + temp = (sbr->k[2] << 23) / sbr->kx[1]; + while (temp < 0x40000000) { + temp <<= 1; + nz++; + } + temp = fixed_log(temp - 0x80000000); + temp = (int)(((int64_t)temp * CONST_RECIP_LN2 + 0x20000000) >> 30); + temp = (((temp + 0x80) >> 8) + ((8 - nz) << 23)) * sbr->spectrum_params.bs_noise_bands; + + sbr->n_q = (temp + 0x400000) >> 23; + if (sbr->n_q < 1) + sbr->n_q = 1; +#else + sbr->n_q = FFMAX(1, lrintf(sbr->spectrum_params.bs_noise_bands * + log2f(sbr->k[2] / (float)sbr->kx[1]))); // 0 <= bs_noise_bands <= 3 +#endif /* USE_FIXED */ + + if (sbr->n_q > 5) { + av_log(ac->avctx, AV_LOG_ERROR, "Too many noise floor scale factors: %d\n", sbr->n_q); + return -1; + } + + sbr->f_tablenoise[0] = sbr->f_tablelow[0]; + temp = 0; + for (k = 1; k <= sbr->n_q; k++) { + temp += (sbr->n[0] - temp) / (sbr->n_q + 1 - k); + sbr->f_tablenoise[k] = sbr->f_tablelow[temp]; + } + + if (sbr_hf_calc_npatches(ac, sbr) < 0) + return -1; + + sbr_make_f_tablelim(sbr); + + sbr->data[0].f_indexnoise = 0; + sbr->data[1].f_indexnoise = 0; + + return 0; +} + +static av_always_inline void get_bits1_vector(GetBitContext *gb, uint8_t *vec, + int elements) +{ + int i; + for (i = 0; i < elements; i++) { + vec[i] = get_bits1(gb); + } +} + +/** ceil(log2(index+1)) */ +static const int8_t ceil_log2[] = { + 0, 1, 2, 2, 3, 3, +}; + +static int read_sbr_grid(AACContext *ac, SpectralBandReplication *sbr, + GetBitContext *gb, SBRData *ch_data) +{ + int i; + int bs_pointer = 0; + // frameLengthFlag ? 15 : 16; 960 sample length frames unsupported; this value is numTimeSlots + int abs_bord_trail = 16; + int num_rel_lead, num_rel_trail; + unsigned bs_num_env_old = ch_data->bs_num_env; + int bs_frame_class, bs_num_env; + + ch_data->bs_freq_res[0] = ch_data->bs_freq_res[ch_data->bs_num_env]; + ch_data->bs_amp_res = sbr->bs_amp_res_header; + ch_data->t_env_num_env_old = ch_data->t_env[bs_num_env_old]; + + switch (bs_frame_class = get_bits(gb, 2)) { + case FIXFIX: + bs_num_env = 1 << get_bits(gb, 2); + if (bs_num_env > 4) { + av_log(ac->avctx, AV_LOG_ERROR, + "Invalid bitstream, too many SBR envelopes in FIXFIX type SBR frame: %d\n", + bs_num_env); + return -1; + } + ch_data->bs_num_env = bs_num_env; + num_rel_lead = ch_data->bs_num_env - 1; + if (ch_data->bs_num_env == 1) + ch_data->bs_amp_res = 0; + + + ch_data->t_env[0] = 0; + ch_data->t_env[ch_data->bs_num_env] = abs_bord_trail; + + abs_bord_trail = (abs_bord_trail + (ch_data->bs_num_env >> 1)) / + ch_data->bs_num_env; + for (i = 0; i < num_rel_lead; i++) + ch_data->t_env[i + 1] = ch_data->t_env[i] + abs_bord_trail; + + ch_data->bs_freq_res[1] = get_bits1(gb); + for (i = 1; i < ch_data->bs_num_env; i++) + ch_data->bs_freq_res[i + 1] = ch_data->bs_freq_res[1]; + break; + case FIXVAR: + abs_bord_trail += get_bits(gb, 2); + num_rel_trail = get_bits(gb, 2); + ch_data->bs_num_env = num_rel_trail + 1; + ch_data->t_env[0] = 0; + ch_data->t_env[ch_data->bs_num_env] = abs_bord_trail; + + for (i = 0; i < num_rel_trail; i++) + ch_data->t_env[ch_data->bs_num_env - 1 - i] = + ch_data->t_env[ch_data->bs_num_env - i] - 2 * get_bits(gb, 2) - 2; + + bs_pointer = get_bits(gb, ceil_log2[ch_data->bs_num_env]); + + for (i = 0; i < ch_data->bs_num_env; i++) + ch_data->bs_freq_res[ch_data->bs_num_env - i] = get_bits1(gb); + break; + case VARFIX: + ch_data->t_env[0] = get_bits(gb, 2); + num_rel_lead = get_bits(gb, 2); + ch_data->bs_num_env = num_rel_lead + 1; + ch_data->t_env[ch_data->bs_num_env] = abs_bord_trail; + + for (i = 0; i < num_rel_lead; i++) + ch_data->t_env[i + 1] = ch_data->t_env[i] + 2 * get_bits(gb, 2) + 2; + + bs_pointer = get_bits(gb, ceil_log2[ch_data->bs_num_env]); + + get_bits1_vector(gb, ch_data->bs_freq_res + 1, ch_data->bs_num_env); + break; + case VARVAR: + ch_data->t_env[0] = get_bits(gb, 2); + abs_bord_trail += get_bits(gb, 2); + num_rel_lead = get_bits(gb, 2); + num_rel_trail = get_bits(gb, 2); + bs_num_env = num_rel_lead + num_rel_trail + 1; + + if (bs_num_env > 5) { + av_log(ac->avctx, AV_LOG_ERROR, + "Invalid bitstream, too many SBR envelopes in VARVAR type SBR frame: %d\n", + bs_num_env); + return -1; + } + ch_data->bs_num_env = bs_num_env; + + ch_data->t_env[ch_data->bs_num_env] = abs_bord_trail; + + for (i = 0; i < num_rel_lead; i++) + ch_data->t_env[i + 1] = ch_data->t_env[i] + 2 * get_bits(gb, 2) + 2; + for (i = 0; i < num_rel_trail; i++) + ch_data->t_env[ch_data->bs_num_env - 1 - i] = + ch_data->t_env[ch_data->bs_num_env - i] - 2 * get_bits(gb, 2) - 2; + + bs_pointer = get_bits(gb, ceil_log2[ch_data->bs_num_env]); + + get_bits1_vector(gb, ch_data->bs_freq_res + 1, ch_data->bs_num_env); + break; + } + ch_data->bs_frame_class = bs_frame_class; + + av_assert0(bs_pointer >= 0); + if (bs_pointer > ch_data->bs_num_env + 1) { + av_log(ac->avctx, AV_LOG_ERROR, + "Invalid bitstream, bs_pointer points to a middle noise border outside the time borders table: %d\n", + bs_pointer); + return -1; + } + + for (i = 1; i <= ch_data->bs_num_env; i++) { + if (ch_data->t_env[i-1] >= ch_data->t_env[i]) { + av_log(ac->avctx, AV_LOG_ERROR, "Not strictly monotone time borders\n"); + return -1; + } + } + + ch_data->bs_num_noise = (ch_data->bs_num_env > 1) + 1; + + ch_data->t_q[0] = ch_data->t_env[0]; + ch_data->t_q[ch_data->bs_num_noise] = ch_data->t_env[ch_data->bs_num_env]; + if (ch_data->bs_num_noise > 1) { + int idx; + if (ch_data->bs_frame_class == FIXFIX) { + idx = ch_data->bs_num_env >> 1; + } else if (ch_data->bs_frame_class & 1) { // FIXVAR or VARVAR + idx = ch_data->bs_num_env - FFMAX(bs_pointer - 1, 1); + } else { // VARFIX + if (!bs_pointer) + idx = 1; + else if (bs_pointer == 1) + idx = ch_data->bs_num_env - 1; + else // bs_pointer > 1 + idx = bs_pointer - 1; + } + ch_data->t_q[1] = ch_data->t_env[idx]; + } + + ch_data->e_a[0] = -(ch_data->e_a[1] != bs_num_env_old); // l_APrev + ch_data->e_a[1] = -1; + if ((ch_data->bs_frame_class & 1) && bs_pointer) { // FIXVAR or VARVAR and bs_pointer != 0 + ch_data->e_a[1] = ch_data->bs_num_env + 1 - bs_pointer; + } else if ((ch_data->bs_frame_class == 2) && (bs_pointer > 1)) // VARFIX and bs_pointer > 1 + ch_data->e_a[1] = bs_pointer - 1; + + return 0; +} + +static void copy_sbr_grid(SBRData *dst, const SBRData *src) { + //These variables are saved from the previous frame rather than copied + dst->bs_freq_res[0] = dst->bs_freq_res[dst->bs_num_env]; + dst->t_env_num_env_old = dst->t_env[dst->bs_num_env]; + dst->e_a[0] = -(dst->e_a[1] != dst->bs_num_env); + + //These variables are read from the bitstream and therefore copied + memcpy(dst->bs_freq_res+1, src->bs_freq_res+1, sizeof(dst->bs_freq_res)-sizeof(*dst->bs_freq_res)); + memcpy(dst->t_env, src->t_env, sizeof(dst->t_env)); + memcpy(dst->t_q, src->t_q, sizeof(dst->t_q)); + dst->bs_num_env = src->bs_num_env; + dst->bs_amp_res = src->bs_amp_res; + dst->bs_num_noise = src->bs_num_noise; + dst->bs_frame_class = src->bs_frame_class; + dst->e_a[1] = src->e_a[1]; +} + +/// Read how the envelope and noise floor data is delta coded +static void read_sbr_dtdf(SpectralBandReplication *sbr, GetBitContext *gb, + SBRData *ch_data) +{ + get_bits1_vector(gb, ch_data->bs_df_env, ch_data->bs_num_env); + get_bits1_vector(gb, ch_data->bs_df_noise, ch_data->bs_num_noise); +} + +/// Read inverse filtering data +static void read_sbr_invf(SpectralBandReplication *sbr, GetBitContext *gb, + SBRData *ch_data) +{ + int i; + + memcpy(ch_data->bs_invf_mode[1], ch_data->bs_invf_mode[0], 5 * sizeof(uint8_t)); + for (i = 0; i < sbr->n_q; i++) + ch_data->bs_invf_mode[0][i] = get_bits(gb, 2); +} + +static int read_sbr_envelope(AACContext *ac, SpectralBandReplication *sbr, GetBitContext *gb, + SBRData *ch_data, int ch) +{ + int bits; + int i, j, k; + VLC_TYPE (*t_huff)[2], (*f_huff)[2]; + int t_lav, f_lav; + const int delta = (ch == 1 && sbr->bs_coupling == 1) + 1; + const int odd = sbr->n[1] & 1; + + if (sbr->bs_coupling && ch) { + if (ch_data->bs_amp_res) { + bits = 5; + t_huff = vlc_sbr[T_HUFFMAN_ENV_BAL_3_0DB].table; + t_lav = vlc_sbr_lav[T_HUFFMAN_ENV_BAL_3_0DB]; + f_huff = vlc_sbr[F_HUFFMAN_ENV_BAL_3_0DB].table; + f_lav = vlc_sbr_lav[F_HUFFMAN_ENV_BAL_3_0DB]; + } else { + bits = 6; + t_huff = vlc_sbr[T_HUFFMAN_ENV_BAL_1_5DB].table; + t_lav = vlc_sbr_lav[T_HUFFMAN_ENV_BAL_1_5DB]; + f_huff = vlc_sbr[F_HUFFMAN_ENV_BAL_1_5DB].table; + f_lav = vlc_sbr_lav[F_HUFFMAN_ENV_BAL_1_5DB]; + } + } else { + if (ch_data->bs_amp_res) { + bits = 6; + t_huff = vlc_sbr[T_HUFFMAN_ENV_3_0DB].table; + t_lav = vlc_sbr_lav[T_HUFFMAN_ENV_3_0DB]; + f_huff = vlc_sbr[F_HUFFMAN_ENV_3_0DB].table; + f_lav = vlc_sbr_lav[F_HUFFMAN_ENV_3_0DB]; + } else { + bits = 7; + t_huff = vlc_sbr[T_HUFFMAN_ENV_1_5DB].table; + t_lav = vlc_sbr_lav[T_HUFFMAN_ENV_1_5DB]; + f_huff = vlc_sbr[F_HUFFMAN_ENV_1_5DB].table; + f_lav = vlc_sbr_lav[F_HUFFMAN_ENV_1_5DB]; + } + } + + for (i = 0; i < ch_data->bs_num_env; i++) { + if (ch_data->bs_df_env[i]) { + // bs_freq_res[0] == bs_freq_res[bs_num_env] from prev frame + if (ch_data->bs_freq_res[i + 1] == ch_data->bs_freq_res[i]) { + for (j = 0; j < sbr->n[ch_data->bs_freq_res[i + 1]]; j++) { + ch_data->env_facs_q[i + 1][j] = ch_data->env_facs_q[i][j] + delta * (get_vlc2(gb, t_huff, 9, 3) - t_lav); + if (ch_data->env_facs_q[i + 1][j] > 127U) { + av_log(ac->avctx, AV_LOG_ERROR, "env_facs_q %d is invalid\n", ch_data->env_facs_q[i + 1][j]); + return AVERROR_INVALIDDATA; + } + } + } else if (ch_data->bs_freq_res[i + 1]) { + for (j = 0; j < sbr->n[ch_data->bs_freq_res[i + 1]]; j++) { + k = (j + odd) >> 1; // find k such that f_tablelow[k] <= f_tablehigh[j] < f_tablelow[k + 1] + ch_data->env_facs_q[i + 1][j] = ch_data->env_facs_q[i][k] + delta * (get_vlc2(gb, t_huff, 9, 3) - t_lav); + if (ch_data->env_facs_q[i + 1][j] > 127U) { + av_log(ac->avctx, AV_LOG_ERROR, "env_facs_q %d is invalid\n", ch_data->env_facs_q[i + 1][j]); + return AVERROR_INVALIDDATA; + } + } + } else { + for (j = 0; j < sbr->n[ch_data->bs_freq_res[i + 1]]; j++) { + k = j ? 2*j - odd : 0; // find k such that f_tablehigh[k] == f_tablelow[j] + ch_data->env_facs_q[i + 1][j] = ch_data->env_facs_q[i][k] + delta * (get_vlc2(gb, t_huff, 9, 3) - t_lav); + if (ch_data->env_facs_q[i + 1][j] > 127U) { + av_log(ac->avctx, AV_LOG_ERROR, "env_facs_q %d is invalid\n", ch_data->env_facs_q[i + 1][j]); + return AVERROR_INVALIDDATA; + } + } + } + } else { + ch_data->env_facs_q[i + 1][0] = delta * get_bits(gb, bits); // bs_env_start_value_balance + for (j = 1; j < sbr->n[ch_data->bs_freq_res[i + 1]]; j++) { + ch_data->env_facs_q[i + 1][j] = ch_data->env_facs_q[i + 1][j - 1] + delta * (get_vlc2(gb, f_huff, 9, 3) - f_lav); + if (ch_data->env_facs_q[i + 1][j] > 127U) { + av_log(ac->avctx, AV_LOG_ERROR, "env_facs_q %d is invalid\n", ch_data->env_facs_q[i + 1][j]); + return AVERROR_INVALIDDATA; + } + } + } + } + + //assign 0th elements of env_facs_q from last elements + memcpy(ch_data->env_facs_q[0], ch_data->env_facs_q[ch_data->bs_num_env], + sizeof(ch_data->env_facs_q[0])); + + return 0; +} + +static int read_sbr_noise(AACContext *ac, SpectralBandReplication *sbr, GetBitContext *gb, + SBRData *ch_data, int ch) +{ + int i, j; + VLC_TYPE (*t_huff)[2], (*f_huff)[2]; + int t_lav, f_lav; + int delta = (ch == 1 && sbr->bs_coupling == 1) + 1; + + if (sbr->bs_coupling && ch) { + t_huff = vlc_sbr[T_HUFFMAN_NOISE_BAL_3_0DB].table; + t_lav = vlc_sbr_lav[T_HUFFMAN_NOISE_BAL_3_0DB]; + f_huff = vlc_sbr[F_HUFFMAN_ENV_BAL_3_0DB].table; + f_lav = vlc_sbr_lav[F_HUFFMAN_ENV_BAL_3_0DB]; + } else { + t_huff = vlc_sbr[T_HUFFMAN_NOISE_3_0DB].table; + t_lav = vlc_sbr_lav[T_HUFFMAN_NOISE_3_0DB]; + f_huff = vlc_sbr[F_HUFFMAN_ENV_3_0DB].table; + f_lav = vlc_sbr_lav[F_HUFFMAN_ENV_3_0DB]; + } + + for (i = 0; i < ch_data->bs_num_noise; i++) { + if (ch_data->bs_df_noise[i]) { + for (j = 0; j < sbr->n_q; j++) { + ch_data->noise_facs_q[i + 1][j] = ch_data->noise_facs_q[i][j] + delta * (get_vlc2(gb, t_huff, 9, 2) - t_lav); + if (ch_data->noise_facs_q[i + 1][j] > 30U) { + av_log(ac->avctx, AV_LOG_ERROR, "noise_facs_q %d is invalid\n", ch_data->noise_facs_q[i + 1][j]); + return AVERROR_INVALIDDATA; + } + } + } else { + ch_data->noise_facs_q[i + 1][0] = delta * get_bits(gb, 5); // bs_noise_start_value_balance or bs_noise_start_value_level + for (j = 1; j < sbr->n_q; j++) { + ch_data->noise_facs_q[i + 1][j] = ch_data->noise_facs_q[i + 1][j - 1] + delta * (get_vlc2(gb, f_huff, 9, 3) - f_lav); + if (ch_data->noise_facs_q[i + 1][j] > 30U) { + av_log(ac->avctx, AV_LOG_ERROR, "noise_facs_q %d is invalid\n", ch_data->noise_facs_q[i + 1][j]); + return AVERROR_INVALIDDATA; + } + } + } + } + + //assign 0th elements of noise_facs_q from last elements + memcpy(ch_data->noise_facs_q[0], ch_data->noise_facs_q[ch_data->bs_num_noise], + sizeof(ch_data->noise_facs_q[0])); + return 0; +} + +static void read_sbr_extension(AACContext *ac, SpectralBandReplication *sbr, + GetBitContext *gb, + int bs_extension_id, int *num_bits_left) +{ + switch (bs_extension_id) { + case EXTENSION_ID_PS: + if (!ac->oc[1].m4ac.ps) { + av_log(ac->avctx, AV_LOG_ERROR, "Parametric Stereo signaled to be not-present but was found in the bitstream.\n"); + skip_bits_long(gb, *num_bits_left); // bs_fill_bits + *num_bits_left = 0; + } else { + *num_bits_left -= AAC_RENAME(ff_ps_read_data)(ac->avctx, gb, &sbr->ps, *num_bits_left); + ac->avctx->profile = FF_PROFILE_AAC_HE_V2; + } + break; + default: + // some files contain 0-padding + if (bs_extension_id || *num_bits_left > 16 || show_bits(gb, *num_bits_left)) + avpriv_request_sample(ac->avctx, "Reserved SBR extensions"); + skip_bits_long(gb, *num_bits_left); // bs_fill_bits + *num_bits_left = 0; + break; + } +} + +static int read_sbr_single_channel_element(AACContext *ac, + SpectralBandReplication *sbr, + GetBitContext *gb) +{ + int ret; + + if (get_bits1(gb)) // bs_data_extra + skip_bits(gb, 4); // bs_reserved + + if (read_sbr_grid(ac, sbr, gb, &sbr->data[0])) + return -1; + read_sbr_dtdf(sbr, gb, &sbr->data[0]); + read_sbr_invf(sbr, gb, &sbr->data[0]); + if((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + if((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + + if ((sbr->data[0].bs_add_harmonic_flag = get_bits1(gb))) + get_bits1_vector(gb, sbr->data[0].bs_add_harmonic, sbr->n[1]); + + return 0; +} + +static int read_sbr_channel_pair_element(AACContext *ac, + SpectralBandReplication *sbr, + GetBitContext *gb) +{ + int ret; + + if (get_bits1(gb)) // bs_data_extra + skip_bits(gb, 8); // bs_reserved + + if ((sbr->bs_coupling = get_bits1(gb))) { + if (read_sbr_grid(ac, sbr, gb, &sbr->data[0])) + return -1; + copy_sbr_grid(&sbr->data[1], &sbr->data[0]); + read_sbr_dtdf(sbr, gb, &sbr->data[0]); + read_sbr_dtdf(sbr, gb, &sbr->data[1]); + read_sbr_invf(sbr, gb, &sbr->data[0]); + memcpy(sbr->data[1].bs_invf_mode[1], sbr->data[1].bs_invf_mode[0], sizeof(sbr->data[1].bs_invf_mode[0])); + memcpy(sbr->data[1].bs_invf_mode[0], sbr->data[0].bs_invf_mode[0], sizeof(sbr->data[1].bs_invf_mode[0])); + if((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + if((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + if((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[1], 1)) < 0) + return ret; + if((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[1], 1)) < 0) + return ret; + } else { + if (read_sbr_grid(ac, sbr, gb, &sbr->data[0]) || + read_sbr_grid(ac, sbr, gb, &sbr->data[1])) + return -1; + read_sbr_dtdf(sbr, gb, &sbr->data[0]); + read_sbr_dtdf(sbr, gb, &sbr->data[1]); + read_sbr_invf(sbr, gb, &sbr->data[0]); + read_sbr_invf(sbr, gb, &sbr->data[1]); + if((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + if((ret = read_sbr_envelope(ac, sbr, gb, &sbr->data[1], 1)) < 0) + return ret; + if((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[0], 0)) < 0) + return ret; + if((ret = read_sbr_noise(ac, sbr, gb, &sbr->data[1], 1)) < 0) + return ret; + } + + if ((sbr->data[0].bs_add_harmonic_flag = get_bits1(gb))) + get_bits1_vector(gb, sbr->data[0].bs_add_harmonic, sbr->n[1]); + if ((sbr->data[1].bs_add_harmonic_flag = get_bits1(gb))) + get_bits1_vector(gb, sbr->data[1].bs_add_harmonic, sbr->n[1]); + + return 0; +} + +static unsigned int read_sbr_data(AACContext *ac, SpectralBandReplication *sbr, + GetBitContext *gb, int id_aac) +{ + unsigned int cnt = get_bits_count(gb); + + sbr->id_aac = id_aac; + sbr->ready_for_dequant = 1; + + if (id_aac == TYPE_SCE || id_aac == TYPE_CCE) { + if (read_sbr_single_channel_element(ac, sbr, gb)) { + sbr_turnoff(sbr); + return get_bits_count(gb) - cnt; + } + } else if (id_aac == TYPE_CPE) { + if (read_sbr_channel_pair_element(ac, sbr, gb)) { + sbr_turnoff(sbr); + return get_bits_count(gb) - cnt; + } + } else { + av_log(ac->avctx, AV_LOG_ERROR, + "Invalid bitstream - cannot apply SBR to element type %d\n", id_aac); + sbr_turnoff(sbr); + return get_bits_count(gb) - cnt; + } + if (get_bits1(gb)) { // bs_extended_data + int num_bits_left = get_bits(gb, 4); // bs_extension_size + if (num_bits_left == 15) + num_bits_left += get_bits(gb, 8); // bs_esc_count + + num_bits_left <<= 3; + while (num_bits_left > 7) { + num_bits_left -= 2; + read_sbr_extension(ac, sbr, gb, get_bits(gb, 2), &num_bits_left); // bs_extension_id + } + if (num_bits_left < 0) { + av_log(ac->avctx, AV_LOG_ERROR, "SBR Extension over read.\n"); + } + if (num_bits_left > 0) + skip_bits(gb, num_bits_left); + } + + return get_bits_count(gb) - cnt; +} + +static void sbr_reset(AACContext *ac, SpectralBandReplication *sbr) +{ + int err; + err = sbr_make_f_master(ac, sbr, &sbr->spectrum_params); + if (err >= 0) + err = sbr_make_f_derived(ac, sbr); + if (err < 0) { + av_log(ac->avctx, AV_LOG_ERROR, + "SBR reset failed. Switching SBR to pure upsampling mode.\n"); + sbr_turnoff(sbr); + } +} + +/** + * Decode Spectral Band Replication extension data; reference: table 4.55. + * + * @param crc flag indicating the presence of CRC checksum + * @param cnt length of TYPE_FIL syntactic element in bytes + * + * @return Returns number of bytes consumed from the TYPE_FIL element. + */ +int AAC_RENAME(ff_decode_sbr_extension)(AACContext *ac, SpectralBandReplication *sbr, + GetBitContext *gb_host, int crc, int cnt, int id_aac) +{ + unsigned int num_sbr_bits = 0, num_align_bits; + unsigned bytes_read; + GetBitContext gbc = *gb_host, *gb = &gbc; + skip_bits_long(gb_host, cnt*8 - 4); + + sbr->reset = 0; + + if (!sbr->sample_rate) + sbr->sample_rate = 2 * ac->oc[1].m4ac.sample_rate; //TODO use the nominal sample rate for arbitrary sample rate support + if (!ac->oc[1].m4ac.ext_sample_rate) + ac->oc[1].m4ac.ext_sample_rate = 2 * ac->oc[1].m4ac.sample_rate; + + if (crc) { + skip_bits(gb, 10); // bs_sbr_crc_bits; TODO - implement CRC check + num_sbr_bits += 10; + } + + //Save some state from the previous frame. + sbr->kx[0] = sbr->kx[1]; + sbr->m[0] = sbr->m[1]; + sbr->kx_and_m_pushed = 1; + + num_sbr_bits++; + if (get_bits1(gb)) // bs_header_flag + num_sbr_bits += read_sbr_header(sbr, gb); + + if (sbr->reset) + sbr_reset(ac, sbr); + + if (sbr->start) + num_sbr_bits += read_sbr_data(ac, sbr, gb, id_aac); + + num_align_bits = ((cnt << 3) - 4 - num_sbr_bits) & 7; + bytes_read = ((num_sbr_bits + num_align_bits + 4) >> 3); + + if (bytes_read > cnt) { + av_log(ac->avctx, AV_LOG_ERROR, + "Expected to read %d SBR bytes actually read %d.\n", cnt, bytes_read); + sbr_turnoff(sbr); + } + return cnt; +} + +/** + * Analysis QMF Bank (14496-3 sp04 p206) + * + * @param x pointer to the beginning of the first sample window + * @param W array of complex-valued samples split into subbands + */ +#ifndef sbr_qmf_analysis +#if USE_FIXED +static void sbr_qmf_analysis(AVFixedDSPContext *dsp, FFTContext *mdct, +#else +static void sbr_qmf_analysis(AVFloatDSPContext *dsp, FFTContext *mdct, +#endif /* USE_FIXED */ + SBRDSPContext *sbrdsp, const INTFLOAT *in, INTFLOAT *x, + INTFLOAT z[320], INTFLOAT W[2][32][32][2], int buf_idx) +{ + int i; +#if USE_FIXED + int j; +#endif + memcpy(x , x+1024, (320-32)*sizeof(x[0])); + memcpy(x+288, in, 1024*sizeof(x[0])); + for (i = 0; i < 32; i++) { // numTimeSlots*RATE = 16*2 as 960 sample frames + // are not supported + dsp->vector_fmul_reverse(z, sbr_qmf_window_ds, x, 320); + sbrdsp->sum64x5(z); + sbrdsp->qmf_pre_shuffle(z); +#if USE_FIXED + for (j = 64; j < 128; j++) { + if (z[j] > 1<<24) { + av_log(NULL, AV_LOG_WARNING, + "sbr_qmf_analysis: value %09d too large, setting to %09d\n", + z[j], 1<<24); + z[j] = 1<<24; + } else if (z[j] < -(1<<24)) { + av_log(NULL, AV_LOG_WARNING, + "sbr_qmf_analysis: value %09d too small, setting to %09d\n", + z[j], -(1<<24)); + z[j] = -(1<<24); + } + } +#endif + mdct->imdct_half(mdct, z, z+64); + sbrdsp->qmf_post_shuffle(W[buf_idx][i], z); + x += 32; + } +} +#endif + +/** + * Synthesis QMF Bank (14496-3 sp04 p206) and Downsampled Synthesis QMF Bank + * (14496-3 sp04 p206) + */ +#ifndef sbr_qmf_synthesis +static void sbr_qmf_synthesis(FFTContext *mdct, +#if USE_FIXED + SBRDSPContext *sbrdsp, AVFixedDSPContext *dsp, +#else + SBRDSPContext *sbrdsp, AVFloatDSPContext *dsp, +#endif /* USE_FIXED */ + INTFLOAT *out, INTFLOAT X[2][38][64], + INTFLOAT mdct_buf[2][64], + INTFLOAT *v0, int *v_off, const unsigned int div) +{ + int i, n; + const INTFLOAT *sbr_qmf_window = div ? sbr_qmf_window_ds : sbr_qmf_window_us; + const int step = 128 >> div; + INTFLOAT *v; + for (i = 0; i < 32; i++) { + if (*v_off < step) { + int saved_samples = (1280 - 128) >> div; + memcpy(&v0[SBR_SYNTHESIS_BUF_SIZE - saved_samples], v0, saved_samples * sizeof(INTFLOAT)); + *v_off = SBR_SYNTHESIS_BUF_SIZE - saved_samples - step; + } else { + *v_off -= step; + } + v = v0 + *v_off; + if (div) { + for (n = 0; n < 32; n++) { + X[0][i][ n] = -X[0][i][n]; + X[0][i][32+n] = X[1][i][31-n]; + } + mdct->imdct_half(mdct, mdct_buf[0], X[0][i]); + sbrdsp->qmf_deint_neg(v, mdct_buf[0]); + } else { + sbrdsp->neg_odd_64(X[1][i]); + mdct->imdct_half(mdct, mdct_buf[0], X[0][i]); + mdct->imdct_half(mdct, mdct_buf[1], X[1][i]); + sbrdsp->qmf_deint_bfly(v, mdct_buf[1], mdct_buf[0]); + } + dsp->vector_fmul (out, v , sbr_qmf_window , 64 >> div); + dsp->vector_fmul_add(out, v + ( 192 >> div), sbr_qmf_window + ( 64 >> div), out , 64 >> div); + dsp->vector_fmul_add(out, v + ( 256 >> div), sbr_qmf_window + (128 >> div), out , 64 >> div); + dsp->vector_fmul_add(out, v + ( 448 >> div), sbr_qmf_window + (192 >> div), out , 64 >> div); + dsp->vector_fmul_add(out, v + ( 512 >> div), sbr_qmf_window + (256 >> div), out , 64 >> div); + dsp->vector_fmul_add(out, v + ( 704 >> div), sbr_qmf_window + (320 >> div), out , 64 >> div); + dsp->vector_fmul_add(out, v + ( 768 >> div), sbr_qmf_window + (384 >> div), out , 64 >> div); + dsp->vector_fmul_add(out, v + ( 960 >> div), sbr_qmf_window + (448 >> div), out , 64 >> div); + dsp->vector_fmul_add(out, v + (1024 >> div), sbr_qmf_window + (512 >> div), out , 64 >> div); + dsp->vector_fmul_add(out, v + (1216 >> div), sbr_qmf_window + (576 >> div), out , 64 >> div); + out += 64 >> div; + } +} +#endif + +/// Generate the subband filtered lowband +static int sbr_lf_gen(AACContext *ac, SpectralBandReplication *sbr, + INTFLOAT X_low[32][40][2], const INTFLOAT W[2][32][32][2], + int buf_idx) +{ + int i, k; + const int t_HFGen = 8; + const int i_f = 32; + memset(X_low, 0, 32*sizeof(*X_low)); + for (k = 0; k < sbr->kx[1]; k++) { + for (i = t_HFGen; i < i_f + t_HFGen; i++) { + X_low[k][i][0] = W[buf_idx][i - t_HFGen][k][0]; + X_low[k][i][1] = W[buf_idx][i - t_HFGen][k][1]; + } + } + buf_idx = 1-buf_idx; + for (k = 0; k < sbr->kx[0]; k++) { + for (i = 0; i < t_HFGen; i++) { + X_low[k][i][0] = W[buf_idx][i + i_f - t_HFGen][k][0]; + X_low[k][i][1] = W[buf_idx][i + i_f - t_HFGen][k][1]; + } + } + return 0; +} + +/// High Frequency Generator (14496-3 sp04 p215) +static int sbr_hf_gen(AACContext *ac, SpectralBandReplication *sbr, + INTFLOAT X_high[64][40][2], const INTFLOAT X_low[32][40][2], + const INTFLOAT (*alpha0)[2], const INTFLOAT (*alpha1)[2], + const INTFLOAT bw_array[5], const uint8_t *t_env, + int bs_num_env) +{ + int j, x; + int g = 0; + int k = sbr->kx[1]; + for (j = 0; j < sbr->num_patches; j++) { + for (x = 0; x < sbr->patch_num_subbands[j]; x++, k++) { + const int p = sbr->patch_start_subband[j] + x; + while (g <= sbr->n_q && k >= sbr->f_tablenoise[g]) + g++; + g--; + + if (g < 0) { + av_log(ac->avctx, AV_LOG_ERROR, + "ERROR : no subband found for frequency %d\n", k); + return -1; + } + + sbr->dsp.hf_gen(X_high[k] + ENVELOPE_ADJUSTMENT_OFFSET, + X_low[p] + ENVELOPE_ADJUSTMENT_OFFSET, + alpha0[p], alpha1[p], bw_array[g], + 2 * t_env[0], 2 * t_env[bs_num_env]); + } + } + if (k < sbr->m[1] + sbr->kx[1]) + memset(X_high + k, 0, (sbr->m[1] + sbr->kx[1] - k) * sizeof(*X_high)); + + return 0; +} + +/// Generate the subband filtered lowband +static int sbr_x_gen(SpectralBandReplication *sbr, INTFLOAT X[2][38][64], + const INTFLOAT Y0[38][64][2], const INTFLOAT Y1[38][64][2], + const INTFLOAT X_low[32][40][2], int ch) +{ + int k, i; + const int i_f = 32; + const int i_Temp = FFMAX(2*sbr->data[ch].t_env_num_env_old - i_f, 0); + memset(X, 0, 2*sizeof(*X)); + for (k = 0; k < sbr->kx[0]; k++) { + for (i = 0; i < i_Temp; i++) { + X[0][i][k] = X_low[k][i + ENVELOPE_ADJUSTMENT_OFFSET][0]; + X[1][i][k] = X_low[k][i + ENVELOPE_ADJUSTMENT_OFFSET][1]; + } + } + for (; k < sbr->kx[0] + sbr->m[0]; k++) { + for (i = 0; i < i_Temp; i++) { + X[0][i][k] = Y0[i + i_f][k][0]; + X[1][i][k] = Y0[i + i_f][k][1]; + } + } + + for (k = 0; k < sbr->kx[1]; k++) { + for (i = i_Temp; i < 38; i++) { + X[0][i][k] = X_low[k][i + ENVELOPE_ADJUSTMENT_OFFSET][0]; + X[1][i][k] = X_low[k][i + ENVELOPE_ADJUSTMENT_OFFSET][1]; + } + } + for (; k < sbr->kx[1] + sbr->m[1]; k++) { + for (i = i_Temp; i < i_f; i++) { + X[0][i][k] = Y1[i][k][0]; + X[1][i][k] = Y1[i][k][1]; + } + } + return 0; +} + +/** High Frequency Adjustment (14496-3 sp04 p217) and Mapping + * (14496-3 sp04 p217) + */ +static int sbr_mapping(AACContext *ac, SpectralBandReplication *sbr, + SBRData *ch_data, int e_a[2]) +{ + int e, i, m; + + memset(ch_data->s_indexmapped[1], 0, 7*sizeof(ch_data->s_indexmapped[1])); + for (e = 0; e < ch_data->bs_num_env; e++) { + const unsigned int ilim = sbr->n[ch_data->bs_freq_res[e + 1]]; + uint16_t *table = ch_data->bs_freq_res[e + 1] ? sbr->f_tablehigh : sbr->f_tablelow; + int k; + + if (sbr->kx[1] != table[0]) { + av_log(ac->avctx, AV_LOG_ERROR, "kx != f_table{high,low}[0]. " + "Derived frequency tables were not regenerated.\n"); + sbr_turnoff(sbr); + return AVERROR_BUG; + } + for (i = 0; i < ilim; i++) + for (m = table[i]; m < table[i + 1]; m++) + sbr->e_origmapped[e][m - sbr->kx[1]] = ch_data->env_facs[e+1][i]; + + // ch_data->bs_num_noise > 1 => 2 noise floors + k = (ch_data->bs_num_noise > 1) && (ch_data->t_env[e] >= ch_data->t_q[1]); + for (i = 0; i < sbr->n_q; i++) + for (m = sbr->f_tablenoise[i]; m < sbr->f_tablenoise[i + 1]; m++) + sbr->q_mapped[e][m - sbr->kx[1]] = ch_data->noise_facs[k+1][i]; + + for (i = 0; i < sbr->n[1]; i++) { + if (ch_data->bs_add_harmonic_flag) { + const unsigned int m_midpoint = + (sbr->f_tablehigh[i] + sbr->f_tablehigh[i + 1]) >> 1; + + ch_data->s_indexmapped[e + 1][m_midpoint - sbr->kx[1]] = ch_data->bs_add_harmonic[i] * + (e >= e_a[1] || (ch_data->s_indexmapped[0][m_midpoint - sbr->kx[1]] == 1)); + } + } + + for (i = 0; i < ilim; i++) { + int additional_sinusoid_present = 0; + for (m = table[i]; m < table[i + 1]; m++) { + if (ch_data->s_indexmapped[e + 1][m - sbr->kx[1]]) { + additional_sinusoid_present = 1; + break; + } + } + memset(&sbr->s_mapped[e][table[i] - sbr->kx[1]], additional_sinusoid_present, + (table[i + 1] - table[i]) * sizeof(sbr->s_mapped[e][0])); + } + } + + memcpy(ch_data->s_indexmapped[0], ch_data->s_indexmapped[ch_data->bs_num_env], sizeof(ch_data->s_indexmapped[0])); + return 0; +} + +/// Estimation of current envelope (14496-3 sp04 p218) +static void sbr_env_estimate(AAC_FLOAT (*e_curr)[48], INTFLOAT X_high[64][40][2], + SpectralBandReplication *sbr, SBRData *ch_data) +{ + int e, m; + int kx1 = sbr->kx[1]; + + if (sbr->bs_interpol_freq) { + for (e = 0; e < ch_data->bs_num_env; e++) { +#if USE_FIXED + const SoftFloat recip_env_size = av_int2sf(0x20000000 / (ch_data->t_env[e + 1] - ch_data->t_env[e]), 30); +#else + const float recip_env_size = 0.5f / (ch_data->t_env[e + 1] - ch_data->t_env[e]); +#endif /* USE_FIXED */ + int ilb = ch_data->t_env[e] * 2 + ENVELOPE_ADJUSTMENT_OFFSET; + int iub = ch_data->t_env[e + 1] * 2 + ENVELOPE_ADJUSTMENT_OFFSET; + + for (m = 0; m < sbr->m[1]; m++) { + AAC_FLOAT sum = sbr->dsp.sum_square(X_high[m+kx1] + ilb, iub - ilb); +#if USE_FIXED + e_curr[e][m] = av_mul_sf(sum, recip_env_size); +#else + e_curr[e][m] = sum * recip_env_size; +#endif /* USE_FIXED */ + } + } + } else { + int k, p; + + for (e = 0; e < ch_data->bs_num_env; e++) { + const int env_size = 2 * (ch_data->t_env[e + 1] - ch_data->t_env[e]); + int ilb = ch_data->t_env[e] * 2 + ENVELOPE_ADJUSTMENT_OFFSET; + int iub = ch_data->t_env[e + 1] * 2 + ENVELOPE_ADJUSTMENT_OFFSET; + const uint16_t *table = ch_data->bs_freq_res[e + 1] ? sbr->f_tablehigh : sbr->f_tablelow; + + for (p = 0; p < sbr->n[ch_data->bs_freq_res[e + 1]]; p++) { +#if USE_FIXED + SoftFloat sum = FLOAT_0; + const SoftFloat den = av_int2sf(0x20000000 / (env_size * (table[p + 1] - table[p])), 29); + for (k = table[p]; k < table[p + 1]; k++) { + sum = av_add_sf(sum, sbr->dsp.sum_square(X_high[k] + ilb, iub - ilb)); + } + sum = av_mul_sf(sum, den); +#else + float sum = 0.0f; + const int den = env_size * (table[p + 1] - table[p]); + + for (k = table[p]; k < table[p + 1]; k++) { + sum += sbr->dsp.sum_square(X_high[k] + ilb, iub - ilb); + } + sum /= den; +#endif /* USE_FIXED */ + for (k = table[p]; k < table[p + 1]; k++) { + e_curr[e][k - kx1] = sum; + } + } + } + } +} + +void AAC_RENAME(ff_sbr_apply)(AACContext *ac, SpectralBandReplication *sbr, int id_aac, + INTFLOAT* L, INTFLOAT* R) +{ + int downsampled = ac->oc[1].m4ac.ext_sample_rate < sbr->sample_rate; + int ch; + int nch = (id_aac == TYPE_CPE) ? 2 : 1; + int err; + + if (id_aac != sbr->id_aac) { + av_log(ac->avctx, id_aac == TYPE_LFE ? AV_LOG_VERBOSE : AV_LOG_WARNING, + "element type mismatch %d != %d\n", id_aac, sbr->id_aac); + sbr_turnoff(sbr); + } + + if (sbr->start && !sbr->ready_for_dequant) { + av_log(ac->avctx, AV_LOG_ERROR, + "No quantized data read for sbr_dequant.\n"); + sbr_turnoff(sbr); + } + + if (!sbr->kx_and_m_pushed) { + sbr->kx[0] = sbr->kx[1]; + sbr->m[0] = sbr->m[1]; + } else { + sbr->kx_and_m_pushed = 0; + } + + if (sbr->start) { + sbr_dequant(sbr, id_aac); + sbr->ready_for_dequant = 0; + } + for (ch = 0; ch < nch; ch++) { + /* decode channel */ + sbr_qmf_analysis(ac->fdsp, &sbr->mdct_ana, &sbr->dsp, ch ? R : L, sbr->data[ch].analysis_filterbank_samples, + (INTFLOAT*)sbr->qmf_filter_scratch, + sbr->data[ch].W, sbr->data[ch].Ypos); + sbr->c.sbr_lf_gen(ac, sbr, sbr->X_low, + (const INTFLOAT (*)[32][32][2]) sbr->data[ch].W, + sbr->data[ch].Ypos); + sbr->data[ch].Ypos ^= 1; + if (sbr->start) { + sbr->c.sbr_hf_inverse_filter(&sbr->dsp, sbr->alpha0, sbr->alpha1, + (const INTFLOAT (*)[40][2]) sbr->X_low, sbr->k[0]); + sbr_chirp(sbr, &sbr->data[ch]); + av_assert0(sbr->data[ch].bs_num_env > 0); + sbr_hf_gen(ac, sbr, sbr->X_high, + (const INTFLOAT (*)[40][2]) sbr->X_low, + (const INTFLOAT (*)[2]) sbr->alpha0, + (const INTFLOAT (*)[2]) sbr->alpha1, + sbr->data[ch].bw_array, sbr->data[ch].t_env, + sbr->data[ch].bs_num_env); + + // hf_adj + err = sbr_mapping(ac, sbr, &sbr->data[ch], sbr->data[ch].e_a); + if (!err) { + sbr_env_estimate(sbr->e_curr, sbr->X_high, sbr, &sbr->data[ch]); + sbr_gain_calc(ac, sbr, &sbr->data[ch], sbr->data[ch].e_a); + sbr->c.sbr_hf_assemble(sbr->data[ch].Y[sbr->data[ch].Ypos], + (const INTFLOAT (*)[40][2]) sbr->X_high, + sbr, &sbr->data[ch], + sbr->data[ch].e_a); + } + } + + /* synthesis */ + sbr->c.sbr_x_gen(sbr, sbr->X[ch], + (const INTFLOAT (*)[64][2]) sbr->data[ch].Y[1-sbr->data[ch].Ypos], + (const INTFLOAT (*)[64][2]) sbr->data[ch].Y[ sbr->data[ch].Ypos], + (const INTFLOAT (*)[40][2]) sbr->X_low, ch); + } + + if (ac->oc[1].m4ac.ps == 1) { + if (sbr->ps.start) { + AAC_RENAME(ff_ps_apply)(ac->avctx, &sbr->ps, sbr->X[0], sbr->X[1], sbr->kx[1] + sbr->m[1]); + } else { + memcpy(sbr->X[1], sbr->X[0], sizeof(sbr->X[0])); + } + nch = 2; + } + + sbr_qmf_synthesis(&sbr->mdct, &sbr->dsp, ac->fdsp, + L, sbr->X[0], sbr->qmf_filter_scratch, + sbr->data[0].synthesis_filterbank_samples, + &sbr->data[0].synthesis_filterbank_samples_offset, + downsampled); + if (nch == 2) + sbr_qmf_synthesis(&sbr->mdct, &sbr->dsp, ac->fdsp, + R, sbr->X[1], sbr->qmf_filter_scratch, + sbr->data[1].synthesis_filterbank_samples, + &sbr->data[1].synthesis_filterbank_samples_offset, + downsampled); +} + +static void aacsbr_func_ptr_init(AACSBRContext *c) +{ + c->sbr_lf_gen = sbr_lf_gen; + c->sbr_hf_assemble = sbr_hf_assemble; + c->sbr_x_gen = sbr_x_gen; + c->sbr_hf_inverse_filter = sbr_hf_inverse_filter; + +#if !USE_FIXED + if(ARCH_MIPS) + ff_aacsbr_func_ptr_init_mips(c); +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbrdata.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbrdata.h new file mode 100644 index 0000000000..4ff8fae913 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aacsbrdata.h @@ -0,0 +1,535 @@ +/* + * AAC Spectral Band Replication decoding data + * Copyright (c) 2008-2009 Robert Swain ( rob opendot cl ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC Spectral Band Replication decoding data + * @author Robert Swain ( rob opendot cl ) + */ + +#ifndef AVCODEC_AACSBRDATA_H +#define AVCODEC_AACSBRDATA_H + +#include +#include "libavutil/mem.h" +#include "aac_defines.h" + +///< Huffman tables for SBR + +static const uint8_t t_huffman_env_1_5dB_bits[121] = { + 18, 18, 18, 18, 18, 18, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 17, 18, 16, 17, 18, 17, + 16, 16, 16, 16, 15, 14, 14, 13, + 13, 12, 11, 10, 9, 8, 7, 6, + 5, 4, 3, 2, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 12, 13, 14, + 14, 15, 16, 17, 16, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, +}; + +static const uint32_t t_huffman_env_1_5dB_codes[121] = { + 0x3ffd6, 0x3ffd7, 0x3ffd8, 0x3ffd9, 0x3ffda, 0x3ffdb, 0x7ffb8, 0x7ffb9, + 0x7ffba, 0x7ffbb, 0x7ffbc, 0x7ffbd, 0x7ffbe, 0x7ffbf, 0x7ffc0, 0x7ffc1, + 0x7ffc2, 0x7ffc3, 0x7ffc4, 0x7ffc5, 0x7ffc6, 0x7ffc7, 0x7ffc8, 0x7ffc9, + 0x7ffca, 0x7ffcb, 0x7ffcc, 0x7ffcd, 0x7ffce, 0x7ffcf, 0x7ffd0, 0x7ffd1, + 0x7ffd2, 0x7ffd3, 0x1ffe6, 0x3ffd4, 0x0fff0, 0x1ffe9, 0x3ffd5, 0x1ffe7, + 0x0fff1, 0x0ffec, 0x0ffed, 0x0ffee, 0x07ff4, 0x03ff9, 0x03ff7, 0x01ffa, + 0x01ff9, 0x00ffb, 0x007fc, 0x003fc, 0x001fd, 0x000fd, 0x0007d, 0x0003d, + 0x0001d, 0x0000d, 0x00005, 0x00001, 0x00000, 0x00004, 0x0000c, 0x0001c, + 0x0003c, 0x0007c, 0x000fc, 0x001fc, 0x003fd, 0x00ffa, 0x01ff8, 0x03ff6, + 0x03ff8, 0x07ff5, 0x0ffef, 0x1ffe8, 0x0fff2, 0x7ffd4, 0x7ffd5, 0x7ffd6, + 0x7ffd7, 0x7ffd8, 0x7ffd9, 0x7ffda, 0x7ffdb, 0x7ffdc, 0x7ffdd, 0x7ffde, + 0x7ffdf, 0x7ffe0, 0x7ffe1, 0x7ffe2, 0x7ffe3, 0x7ffe4, 0x7ffe5, 0x7ffe6, + 0x7ffe7, 0x7ffe8, 0x7ffe9, 0x7ffea, 0x7ffeb, 0x7ffec, 0x7ffed, 0x7ffee, + 0x7ffef, 0x7fff0, 0x7fff1, 0x7fff2, 0x7fff3, 0x7fff4, 0x7fff5, 0x7fff6, + 0x7fff7, 0x7fff8, 0x7fff9, 0x7fffa, 0x7fffb, 0x7fffc, 0x7fffd, 0x7fffe, + 0x7ffff, +}; + +static const uint8_t f_huffman_env_1_5dB_bits[121] = { + 19, 19, 20, 20, 20, 20, 20, 20, + 20, 19, 20, 20, 20, 20, 19, 20, + 19, 19, 20, 18, 20, 20, 20, 19, + 20, 20, 20, 19, 20, 19, 18, 19, + 18, 18, 17, 18, 17, 17, 17, 16, + 16, 16, 15, 15, 14, 13, 13, 12, + 12, 11, 10, 9, 9, 8, 7, 6, + 5, 4, 3, 2, 2, 3, 4, 5, + 6, 8, 8, 9, 10, 11, 11, 11, + 12, 12, 13, 13, 14, 14, 16, 16, + 17, 17, 18, 18, 18, 18, 18, 18, + 18, 20, 19, 20, 20, 20, 20, 20, + 20, 19, 20, 20, 20, 20, 19, 20, + 18, 20, 20, 19, 19, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, + 20, +}; + +static const uint32_t f_huffman_env_1_5dB_codes[121] = { + 0x7ffe7, 0x7ffe8, 0xfffd2, 0xfffd3, 0xfffd4, 0xfffd5, 0xfffd6, 0xfffd7, + 0xfffd8, 0x7ffda, 0xfffd9, 0xfffda, 0xfffdb, 0xfffdc, 0x7ffdb, 0xfffdd, + 0x7ffdc, 0x7ffdd, 0xfffde, 0x3ffe4, 0xfffdf, 0xfffe0, 0xfffe1, 0x7ffde, + 0xfffe2, 0xfffe3, 0xfffe4, 0x7ffdf, 0xfffe5, 0x7ffe0, 0x3ffe8, 0x7ffe1, + 0x3ffe0, 0x3ffe9, 0x1ffef, 0x3ffe5, 0x1ffec, 0x1ffed, 0x1ffee, 0x0fff4, + 0x0fff3, 0x0fff0, 0x07ff7, 0x07ff6, 0x03ffa, 0x01ffa, 0x01ff9, 0x00ffa, + 0x00ff8, 0x007f9, 0x003fb, 0x001fc, 0x001fa, 0x000fb, 0x0007c, 0x0003c, + 0x0001c, 0x0000c, 0x00005, 0x00001, 0x00000, 0x00004, 0x0000d, 0x0001d, + 0x0003d, 0x000fa, 0x000fc, 0x001fb, 0x003fa, 0x007f8, 0x007fa, 0x007fb, + 0x00ff9, 0x00ffb, 0x01ff8, 0x01ffb, 0x03ff8, 0x03ff9, 0x0fff1, 0x0fff2, + 0x1ffea, 0x1ffeb, 0x3ffe1, 0x3ffe2, 0x3ffea, 0x3ffe3, 0x3ffe6, 0x3ffe7, + 0x3ffeb, 0xfffe6, 0x7ffe2, 0xfffe7, 0xfffe8, 0xfffe9, 0xfffea, 0xfffeb, + 0xfffec, 0x7ffe3, 0xfffed, 0xfffee, 0xfffef, 0xffff0, 0x7ffe4, 0xffff1, + 0x3ffec, 0xffff2, 0xffff3, 0x7ffe5, 0x7ffe6, 0xffff4, 0xffff5, 0xffff6, + 0xffff7, 0xffff8, 0xffff9, 0xffffa, 0xffffb, 0xffffc, 0xffffd, 0xffffe, + 0xfffff, +}; + +static const uint8_t t_huffman_env_bal_1_5dB_bits[49] = { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 12, 11, 9, 7, 5, 3, + 1, 2, 4, 6, 8, 11, 12, 15, + 16, 16, 16, 16, 16, 16, 16, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, +}; + +static const uint32_t t_huffman_env_bal_1_5dB_codes[49] = { + 0x0ffe4, 0x0ffe5, 0x0ffe6, 0x0ffe7, 0x0ffe8, 0x0ffe9, 0x0ffea, 0x0ffeb, + 0x0ffec, 0x0ffed, 0x0ffee, 0x0ffef, 0x0fff0, 0x0fff1, 0x0fff2, 0x0fff3, + 0x0fff4, 0x0ffe2, 0x00ffc, 0x007fc, 0x001fe, 0x0007e, 0x0001e, 0x00006, + 0x00000, 0x00002, 0x0000e, 0x0003e, 0x000fe, 0x007fd, 0x00ffd, 0x07ff0, + 0x0ffe3, 0x0fff5, 0x0fff6, 0x0fff7, 0x0fff8, 0x0fff9, 0x0fffa, 0x1fff6, + 0x1fff7, 0x1fff8, 0x1fff9, 0x1fffa, 0x1fffb, 0x1fffc, 0x1fffd, 0x1fffe, + 0x1ffff, +}; + +static const uint8_t f_huffman_env_bal_1_5dB_bits[49] = { + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 16, + 17, 14, 11, 11, 8, 7, 4, 2, + 1, 3, 5, 6, 9, 11, 12, 15, + 16, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 19, + 19, +}; + +static const uint32_t f_huffman_env_bal_1_5dB_codes[49] = { + 0x3ffe2, 0x3ffe3, 0x3ffe4, 0x3ffe5, 0x3ffe6, 0x3ffe7, 0x3ffe8, 0x3ffe9, + 0x3ffea, 0x3ffeb, 0x3ffec, 0x3ffed, 0x3ffee, 0x3ffef, 0x3fff0, 0x0fff7, + 0x1fff0, 0x03ffc, 0x007fe, 0x007fc, 0x000fe, 0x0007e, 0x0000e, 0x00002, + 0x00000, 0x00006, 0x0001e, 0x0003e, 0x001fe, 0x007fd, 0x00ffe, 0x07ffa, + 0x0fff6, 0x3fff1, 0x3fff2, 0x3fff3, 0x3fff4, 0x3fff5, 0x3fff6, 0x3fff7, + 0x3fff8, 0x3fff9, 0x3fffa, 0x3fffb, 0x3fffc, 0x3fffd, 0x3fffe, 0x7fffe, + 0x7ffff, +}; + +static const uint8_t t_huffman_env_3_0dB_bits[63] = { + 18, 18, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 17, 16, 16, 16, 14, 14, 14, + 13, 12, 11, 8, 6, 4, 2, 1, + 3, 5, 7, 9, 11, 13, 14, 14, + 15, 16, 17, 18, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, +}; + +static const uint32_t t_huffman_env_3_0dB_codes[63] = { + 0x3ffed, 0x3ffee, 0x7ffde, 0x7ffdf, 0x7ffe0, 0x7ffe1, 0x7ffe2, 0x7ffe3, + 0x7ffe4, 0x7ffe5, 0x7ffe6, 0x7ffe7, 0x7ffe8, 0x7ffe9, 0x7ffea, 0x7ffeb, + 0x7ffec, 0x1fff4, 0x0fff7, 0x0fff9, 0x0fff8, 0x03ffb, 0x03ffa, 0x03ff8, + 0x01ffa, 0x00ffc, 0x007fc, 0x000fe, 0x0003e, 0x0000e, 0x00002, 0x00000, + 0x00006, 0x0001e, 0x0007e, 0x001fe, 0x007fd, 0x01ffb, 0x03ff9, 0x03ffc, + 0x07ffa, 0x0fff6, 0x1fff5, 0x3ffec, 0x7ffed, 0x7ffee, 0x7ffef, 0x7fff0, + 0x7fff1, 0x7fff2, 0x7fff3, 0x7fff4, 0x7fff5, 0x7fff6, 0x7fff7, 0x7fff8, + 0x7fff9, 0x7fffa, 0x7fffb, 0x7fffc, 0x7fffd, 0x7fffe, 0x7ffff, +}; + +static const uint8_t f_huffman_env_3_0dB_bits[63] = { + 20, 20, 20, 20, 20, 20, 20, 18, + 19, 19, 19, 19, 18, 18, 20, 19, + 17, 18, 17, 16, 16, 15, 14, 12, + 11, 10, 9, 8, 6, 4, 2, 1, + 3, 5, 8, 9, 10, 11, 12, 13, + 14, 15, 15, 16, 16, 17, 17, 18, + 18, 18, 20, 19, 19, 19, 20, 19, + 19, 20, 20, 20, 20, 20, 20, +}; + +static const uint32_t f_huffman_env_3_0dB_codes[63] = { + 0xffff0, 0xffff1, 0xffff2, 0xffff3, 0xffff4, 0xffff5, 0xffff6, 0x3fff3, + 0x7fff5, 0x7ffee, 0x7ffef, 0x7fff6, 0x3fff4, 0x3fff2, 0xffff7, 0x7fff0, + 0x1fff5, 0x3fff0, 0x1fff4, 0x0fff7, 0x0fff6, 0x07ff8, 0x03ffb, 0x00ffd, + 0x007fd, 0x003fd, 0x001fd, 0x000fd, 0x0003e, 0x0000e, 0x00002, 0x00000, + 0x00006, 0x0001e, 0x000fc, 0x001fc, 0x003fc, 0x007fc, 0x00ffc, 0x01ffc, + 0x03ffa, 0x07ff9, 0x07ffa, 0x0fff8, 0x0fff9, 0x1fff6, 0x1fff7, 0x3fff5, + 0x3fff6, 0x3fff1, 0xffff8, 0x7fff1, 0x7fff2, 0x7fff3, 0xffff9, 0x7fff7, + 0x7fff4, 0xffffa, 0xffffb, 0xffffc, 0xffffd, 0xffffe, 0xfffff, +}; + +static const uint8_t t_huffman_env_bal_3_0dB_bits[25] = { + 13, 13, 13, 13, 13, 13, 13, 12, + 8, 7, 4, 3, 1, 2, 5, 6, + 9, 13, 13, 13, 13, 13, 13, 14, + 14, +}; + +static const uint16_t t_huffman_env_bal_3_0dB_codes[25] = { + 0x1ff2, 0x1ff3, 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, 0x1ff8, 0x0ff8, + 0x00fe, 0x007e, 0x000e, 0x0006, 0x0000, 0x0002, 0x001e, 0x003e, + 0x01fe, 0x1ff9, 0x1ffa, 0x1ffb, 0x1ffc, 0x1ffd, 0x1ffe, 0x3ffe, + 0x3fff, +}; + +static const uint8_t f_huffman_env_bal_3_0dB_bits[25] = { + 13, 13, 13, 13, 13, 14, 14, 11, + 8, 7, 4, 2, 1, 3, 5, 6, + 9, 12, 13, 14, 14, 14, 14, 14, + 14, +}; + +static const uint16_t f_huffman_env_bal_3_0dB_codes[25] = { + 0x1ff7, 0x1ff8, 0x1ff9, 0x1ffa, 0x1ffb, 0x3ff8, 0x3ff9, 0x07fc, + 0x00fe, 0x007e, 0x000e, 0x0002, 0x0000, 0x0006, 0x001e, 0x003e, + 0x01fe, 0x0ffa, 0x1ff6, 0x3ffa, 0x3ffb, 0x3ffc, 0x3ffd, 0x3ffe, + 0x3fff, +}; + +static const uint8_t t_huffman_noise_3_0dB_bits[63] = { + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 11, 8, 6, 4, 3, 1, + 2, 5, 8, 10, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 14, 14, +}; + +static const uint16_t t_huffman_noise_3_0dB_codes[63] = { + 0x1fce, 0x1fcf, 0x1fd0, 0x1fd1, 0x1fd2, 0x1fd3, 0x1fd4, 0x1fd5, + 0x1fd6, 0x1fd7, 0x1fd8, 0x1fd9, 0x1fda, 0x1fdb, 0x1fdc, 0x1fdd, + 0x1fde, 0x1fdf, 0x1fe0, 0x1fe1, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe5, + 0x1fe6, 0x1fe7, 0x07f2, 0x00fd, 0x003e, 0x000e, 0x0006, 0x0000, + 0x0002, 0x001e, 0x00fc, 0x03f8, 0x1fcc, 0x1fe8, 0x1fe9, 0x1fea, + 0x1feb, 0x1fec, 0x1fcd, 0x1fed, 0x1fee, 0x1fef, 0x1ff0, 0x1ff1, + 0x1ff2, 0x1ff3, 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, 0x1ff8, 0x1ff9, + 0x1ffa, 0x1ffb, 0x1ffc, 0x1ffd, 0x1ffe, 0x3ffe, 0x3fff, +}; + +static const uint8_t t_huffman_noise_bal_3_0dB_bits[25] = { + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 5, 2, 1, 3, 6, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, +}; + +static const uint8_t t_huffman_noise_bal_3_0dB_codes[25] = { + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, + 0xf4, 0xf5, 0x1c, 0x02, 0x00, 0x06, 0x3a, 0xf6, + 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, + 0xff, +}; + +static const int8_t sbr_offset[6][16] = { + {-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}, // fs_sbr = 16000 Hz + {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13}, // fs_sbr = 22050 Hz + {-5, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16}, // fs_sbr = 24000 Hz + {-6, -4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16}, // fs_sbr = 32000 Hz + {-4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20}, // 44100 Hz <= fs_sbr <= 64000 Hz + {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24}, // 64000 Hz < fs_sbr +}; + +/* First eight entries repeated at end to simplify SIMD implementations. */ +const DECLARE_ALIGNED(16, INTFLOAT, AAC_RENAME(ff_sbr_noise_table))[][2] = { +{Q31(-0.99948153278296f), Q31(-0.59483417516607f)}, {Q31( 0.97113454393991f), Q31(-0.67528515225647f)}, +{Q31( 0.14130051758487f), Q31(-0.95090983575689f)}, {Q31(-0.47005496701697f), Q31(-0.37340549728647f)}, +{Q31( 0.80705063769351f), Q31( 0.29653668284408f)}, {Q31(-0.38981478896926f), Q31( 0.89572605717087f)}, +{Q31(-0.01053049862020f), Q31(-0.66959058036166f)}, {Q31(-0.91266367957293f), Q31(-0.11522938140034f)}, +{Q31( 0.54840422910309f), Q31( 0.75221367176302f)}, {Q31( 0.40009252867955f), Q31(-0.98929400334421f)}, +{Q31(-0.99867974711855f), Q31(-0.88147068645358f)}, {Q31(-0.95531076805040f), Q31( 0.90908757154593f)}, +{Q31(-0.45725933317144f), Q31(-0.56716323646760f)}, {Q31(-0.72929675029275f), Q31(-0.98008272727324f)}, +{Q31( 0.75622801399036f), Q31( 0.20950329995549f)}, {Q31( 0.07069442601050f), Q31(-0.78247898470706f)}, +{Q31( 0.74496252926055f), Q31(-0.91169004445807f)}, {Q31(-0.96440182703856f), Q31(-0.94739918296622f)}, +{Q31( 0.30424629369539f), Q31(-0.49438267012479f)}, {Q31( 0.66565033746925f), Q31( 0.64652935542491f)}, +{Q31( 0.91697008020594f), Q31( 0.17514097332009f)}, {Q31(-0.70774918760427f), Q31( 0.52548653416543f)}, +{Q31(-0.70051415345560f), Q31(-0.45340028808763f)}, {Q31(-0.99496513054797f), Q31(-0.90071908066973f)}, +{Q31( 0.98164490790123f), Q31(-0.77463155528697f)}, {Q31(-0.54671580548181f), Q31(-0.02570928536004f)}, +{Q31(-0.01689629065389f), Q31( 0.00287506445732f)}, {Q31(-0.86110349531986f), Q31( 0.42548583726477f)}, +{Q31(-0.98892980586032f), Q31(-0.87881132267556f)}, {Q31( 0.51756627678691f), Q31( 0.66926784710139f)}, +{Q31(-0.99635026409640f), Q31(-0.58107730574765f)}, {Q31(-0.99969370862163f), Q31( 0.98369989360250f)}, +{Q31( 0.55266258627194f), Q31( 0.59449057465591f)}, {Q31( 0.34581177741673f), Q31( 0.94879421061866f)}, +{Q31( 0.62664209577999f), Q31(-0.74402970906471f)}, {Q31(-0.77149701404973f), Q31(-0.33883658042801f)}, +{Q31(-0.91592244254432f), Q31( 0.03687901376713f)}, {Q31(-0.76285492357887f), Q31(-0.91371867919124f)}, +{Q31( 0.79788337195331f), Q31(-0.93180971199849f)}, {Q31( 0.54473080610200f), Q31(-0.11919206037186f)}, +{Q31(-0.85639281671058f), Q31( 0.42429854760451f)}, {Q31(-0.92882402971423f), Q31( 0.27871809078609f)}, +{Q31(-0.11708371046774f), Q31(-0.99800843444966f)}, {Q31( 0.21356749817493f), Q31(-0.90716295627033f)}, +{Q31(-0.76191692573909f), Q31( 0.99768118356265f)}, {Q31( 0.98111043100884f), Q31(-0.95854459734407f)}, +{Q31(-0.85913269895572f), Q31( 0.95766566168880f)}, {Q31(-0.93307242253692f), Q31( 0.49431757696466f)}, +{Q31( 0.30485754879632f), Q31(-0.70540034357529f)}, {Q31( 0.85289650925190f), Q31( 0.46766131791044f)}, +{Q31( 0.91328082618125f), Q31(-0.99839597361769f)}, {Q31(-0.05890199924154f), Q31( 0.70741827819497f)}, +{Q31( 0.28398686150148f), Q31( 0.34633555702188f)}, {Q31( 0.95258164539612f), Q31(-0.54893416026939f)}, +{Q31(-0.78566324168507f), Q31(-0.75568541079691f)}, {Q31(-0.95789495447877f), Q31(-0.20423194696966f)}, +{Q31( 0.82411158711197f), Q31( 0.96654618432562f)}, {Q31(-0.65185446735885f), Q31(-0.88734990773289f)}, +{Q31(-0.93643603134666f), Q31( 0.99870790442385f)}, {Q31( 0.91427159529618f), Q31(-0.98290505544444f)}, +{Q31(-0.70395684036886f), Q31( 0.58796798221039f)}, {Q31( 0.00563771969365f), Q31( 0.61768196727244f)}, +{Q31( 0.89065051931895f), Q31( 0.52783352697585f)}, {Q31(-0.68683707712762f), Q31( 0.80806944710339f)}, +{Q31( 0.72165342518718f), Q31(-0.69259857349564f)}, {Q31(-0.62928247730667f), Q31( 0.13627037407335f)}, +{Q31( 0.29938434065514f), Q31(-0.46051329682246f)}, {Q31(-0.91781958879280f), Q31(-0.74012716684186f)}, +{Q31( 0.99298717043688f), Q31( 0.40816610075661f)}, {Q31( 0.82368298622748f), Q31(-0.74036047190173f)}, +{Q31(-0.98512833386833f), Q31(-0.99972330709594f)}, {Q31(-0.95915368242257f), Q31(-0.99237800466040f)}, +{Q31(-0.21411126572790f), Q31(-0.93424819052545f)}, {Q31(-0.68821476106884f), Q31(-0.26892306315457f)}, +{Q31( 0.91851997982317f), Q31( 0.09358228901785f)}, {Q31(-0.96062769559127f), Q31( 0.36099095133739f)}, +{Q31( 0.51646184922287f), Q31(-0.71373332873917f)}, {Q31( 0.61130721139669f), Q31( 0.46950141175917f)}, +{Q31( 0.47336129371299f), Q31(-0.27333178296162f)}, {Q31( 0.90998308703519f), Q31( 0.96715662938132f)}, +{Q31( 0.44844799194357f), Q31( 0.99211574628306f)}, {Q31( 0.66614891079092f), Q31( 0.96590176169121f)}, +{Q31( 0.74922239129237f), Q31(-0.89879858826087f)}, {Q31(-0.99571588506485f), Q31( 0.52785521494349f)}, +{Q31( 0.97401082477563f), Q31(-0.16855870075190f)}, {Q31( 0.72683747733879f), Q31(-0.48060774432251f)}, +{Q31( 0.95432193457128f), Q31( 0.68849603408441f)}, {Q31(-0.72962208425191f), Q31(-0.76608443420917f)}, +{Q31(-0.85359479233537f), Q31( 0.88738125901579f)}, {Q31(-0.81412430338535f), Q31(-0.97480768049637f)}, +{Q31(-0.87930772356786f), Q31( 0.74748307690436f)}, {Q31(-0.71573331064977f), Q31(-0.98570608178923f)}, +{Q31( 0.83524300028228f), Q31( 0.83702537075163f)}, {Q31(-0.48086065601423f), Q31(-0.98848504923531f)}, +{Q31( 0.97139128574778f), Q31( 0.80093621198236f)}, {Q31( 0.51992825347895f), Q31( 0.80247631400510f)}, +{Q31(-0.00848591195325f), Q31(-0.76670128000486f)}, {Q31(-0.70294374303036f), Q31( 0.55359910445577f)}, +{Q31(-0.95894428168140f), Q31(-0.43265504344783f)}, {Q31( 0.97079252950321f), Q31( 0.09325857238682f)}, +{Q31(-0.92404293670797f), Q31( 0.85507704027855f)}, {Q31(-0.69506469500450f), Q31( 0.98633412625459f)}, +{Q31( 0.26559203620024f), Q31( 0.73314307966524f)}, {Q31( 0.28038443336943f), Q31( 0.14537913654427f)}, +{Q31(-0.74138124825523f), Q31( 0.99310339807762f)}, {Q31(-0.01752795995444f), Q31(-0.82616635284178f)}, +{Q31(-0.55126773094930f), Q31(-0.98898543862153f)}, {Q31( 0.97960898850996f), Q31(-0.94021446752851f)}, +{Q31(-0.99196309146936f), Q31( 0.67019017358456f)}, {Q31(-0.67684928085260f), Q31( 0.12631491649378f)}, +{Q31( 0.09140039465500f), Q31(-0.20537731453108f)}, {Q31(-0.71658965751996f), Q31(-0.97788200391224f)}, +{Q31( 0.81014640078925f), Q31( 0.53722648362443f)}, {Q31( 0.40616991671205f), Q31(-0.26469008598449f)}, +{Q31(-0.67680188682972f), Q31( 0.94502052337695f)}, {Q31( 0.86849774348749f), Q31(-0.18333598647899f)}, +{Q31(-0.99500381284851f), Q31(-0.02634122068550f)}, {Q31( 0.84329189340667f), Q31( 0.10406957462213f)}, +{Q31(-0.09215968531446f), Q31( 0.69540012101253f)}, {Q31( 0.99956173327206f), Q31(-0.12358542001404f)}, +{Q31(-0.79732779473535f), Q31(-0.91582524736159f)}, {Q31( 0.96349973642406f), Q31( 0.96640458041000f)}, +{Q31(-0.79942778496547f), Q31( 0.64323902822857f)}, {Q31(-0.11566039853896f), Q31( 0.28587846253726f)}, +{Q31(-0.39922954514662f), Q31( 0.94129601616966f)}, {Q31( 0.99089197565987f), Q31(-0.92062625581587f)}, +{Q31( 0.28631285179909f), Q31(-0.91035047143603f)}, {Q31(-0.83302725605608f), Q31(-0.67330410892084f)}, +{Q31( 0.95404443402072f), Q31( 0.49162765398743f)}, {Q31(-0.06449863579434f), Q31( 0.03250560813135f)}, +{Q31(-0.99575054486311f), Q31( 0.42389784469507f)}, {Q31(-0.65501142790847f), Q31( 0.82546114655624f)}, +{Q31(-0.81254441908887f), Q31(-0.51627234660629f)}, {Q31(-0.99646369485481f), Q31( 0.84490533520752f)}, +{Q31( 0.00287840603348f), Q31( 0.64768261158166f)}, {Q31( 0.70176989408455f), Q31(-0.20453028573322f)}, +{Q31( 0.96361882270190f), Q31( 0.40706967140989f)}, {Q31(-0.68883758192426f), Q31( 0.91338958840772f)}, +{Q31(-0.34875585502238f), Q31( 0.71472290693300f)}, {Q31( 0.91980081243087f), Q31( 0.66507455644919f)}, +{Q31(-0.99009048343881f), Q31( 0.85868021604848f)}, {Q31( 0.68865791458395f), Q31( 0.55660316809678f)}, +{Q31(-0.99484402129368f), Q31(-0.20052559254934f)}, {Q31( 0.94214511408023f), Q31(-0.99696425367461f)}, +{Q31(-0.67414626793544f), Q31( 0.49548221180078f)}, {Q31(-0.47339353684664f), Q31(-0.85904328834047f)}, +{Q31( 0.14323651387360f), Q31(-0.94145598222488f)}, {Q31(-0.29268293575672f), Q31( 0.05759224927952f)}, +{Q31( 0.43793861458754f), Q31(-0.78904969892724f)}, {Q31(-0.36345126374441f), Q31( 0.64874435357162f)}, +{Q31(-0.08750604656825f), Q31( 0.97686944362527f)}, {Q31(-0.96495267812511f), Q31(-0.53960305946511f)}, +{Q31( 0.55526940659947f), Q31( 0.78891523734774f)}, {Q31( 0.73538215752630f), Q31( 0.96452072373404f)}, +{Q31(-0.30889773919437f), Q31(-0.80664389776860f)}, {Q31( 0.03574995626194f), Q31(-0.97325616900959f)}, +{Q31( 0.98720684660488f), Q31( 0.48409133691962f)}, {Q31(-0.81689296271203f), Q31(-0.90827703628298f)}, +{Q31( 0.67866860118215f), Q31( 0.81284503870856f)}, {Q31(-0.15808569732583f), Q31( 0.85279555024382f)}, +{Q31( 0.80723395114371f), Q31(-0.24717418514605f)}, {Q31( 0.47788757329038f), Q31(-0.46333147839295f)}, +{Q31( 0.96367554763201f), Q31( 0.38486749303242f)}, {Q31(-0.99143875716818f), Q31(-0.24945277239809f)}, +{Q31( 0.83081876925833f), Q31(-0.94780851414763f)}, {Q31(-0.58753191905341f), Q31( 0.01290772389163f)}, +{Q31( 0.95538108220960f), Q31(-0.85557052096538f)}, {Q31(-0.96490920476211f), Q31(-0.64020970923102f)}, +{Q31(-0.97327101028521f), Q31( 0.12378128133110f)}, {Q31( 0.91400366022124f), Q31( 0.57972471346930f)}, +{Q31(-0.99925837363824f), Q31( 0.71084847864067f)}, {Q31(-0.86875903507313f), Q31(-0.20291699203564f)}, +{Q31(-0.26240034795124f), Q31(-0.68264554369108f)}, {Q31(-0.24664412953388f), Q31(-0.87642273115183f)}, +{Q31( 0.02416275806869f), Q31( 0.27192914288905f)}, {Q31( 0.82068619590515f), Q31(-0.85087787994476f)}, +{Q31( 0.88547373760759f), Q31(-0.89636802901469f)}, {Q31(-0.18173078152226f), Q31(-0.26152145156800f)}, +{Q31( 0.09355476558534f), Q31( 0.54845123045604f)}, {Q31(-0.54668414224090f), Q31( 0.95980774020221f)}, +{Q31( 0.37050990604091f), Q31(-0.59910140383171f)}, {Q31(-0.70373594262891f), Q31( 0.91227665827081f)}, +{Q31(-0.34600785879594f), Q31(-0.99441426144200f)}, {Q31(-0.68774481731008f), Q31(-0.30238837956299f)}, +{Q31(-0.26843291251234f), Q31( 0.83115668004362f)}, {Q31( 0.49072334613242f), Q31(-0.45359708737775f)}, +{Q31( 0.38975993093975f), Q31( 0.95515358099121f)}, {Q31(-0.97757125224150f), Q31( 0.05305894580606f)}, +{Q31(-0.17325552859616f), Q31(-0.92770672250494f)}, {Q31( 0.99948035025744f), Q31( 0.58285545563426f)}, +{Q31(-0.64946246527458f), Q31( 0.68645507104960f)}, {Q31(-0.12016920576437f), Q31(-0.57147322153312f)}, +{Q31(-0.58947456517751f), Q31(-0.34847132454388f)}, {Q31(-0.41815140454465f), Q31( 0.16276422358861f)}, +{Q31( 0.99885650204884f), Q31( 0.11136095490444f)}, {Q31(-0.56649614128386f), Q31(-0.90494866361587f)}, +{Q31( 0.94138021032330f), Q31( 0.35281916733018f)}, {Q31(-0.75725076534641f), Q31( 0.53650549640587f)}, +{Q31( 0.20541973692630f), Q31(-0.94435144369918f)}, {Q31( 0.99980371023351f), Q31( 0.79835913565599f)}, +{Q31( 0.29078277605775f), Q31( 0.35393777921520f)}, {Q31(-0.62858772103030f), Q31( 0.38765693387102f)}, +{Q31( 0.43440904467688f), Q31(-0.98546330463232f)}, {Q31(-0.98298583762390f), Q31( 0.21021524625209f)}, +{Q31( 0.19513029146934f), Q31(-0.94239832251867f)}, {Q31(-0.95476662400101f), Q31( 0.98364554179143f)}, +{Q31( 0.93379635304810f), Q31(-0.70881994583682f)}, {Q31(-0.85235410573336f), Q31(-0.08342347966410f)}, +{Q31(-0.86425093011245f), Q31(-0.45795025029466f)}, {Q31( 0.38879779059045f), Q31( 0.97274429344593f)}, +{Q31( 0.92045124735495f), Q31(-0.62433652524220f)}, {Q31( 0.89162532251878f), Q31( 0.54950955570563f)}, +{Q31(-0.36834336949252f), Q31( 0.96458298020975f)}, {Q31( 0.93891760988045f), Q31(-0.89968353740388f)}, +{Q31( 0.99267657565094f), Q31(-0.03757034316958f)}, {Q31(-0.94063471614176f), Q31( 0.41332338538963f)}, +{Q31( 0.99740224117019f), Q31(-0.16830494996370f)}, {Q31(-0.35899413170555f), Q31(-0.46633226649613f)}, +{Q31( 0.05237237274947f), Q31(-0.25640361602661f)}, {Q31( 0.36703583957424f), Q31(-0.38653265641875f)}, +{Q31( 0.91653180367913f), Q31(-0.30587628726597f)}, {Q31( 0.69000803499316f), Q31( 0.90952171386132f)}, +{Q31(-0.38658751133527f), Q31( 0.99501571208985f)}, {Q31(-0.29250814029851f), Q31( 0.37444994344615f)}, +{Q31(-0.60182204677608f), Q31( 0.86779651036123f)}, {Q31(-0.97418588163217f), Q31( 0.96468523666475f)}, +{Q31( 0.88461574003963f), Q31( 0.57508405276414f)}, {Q31( 0.05198933055162f), Q31( 0.21269661669964f)}, +{Q31(-0.53499621979720f), Q31( 0.97241553731237f)}, {Q31(-0.49429560226497f), Q31( 0.98183865291903f)}, +{Q31(-0.98935142339139f), Q31(-0.40249159006933f)}, {Q31(-0.98081380091130f), Q31(-0.72856895534041f)}, +{Q31(-0.27338148835532f), Q31( 0.99950922447209f)}, {Q31( 0.06310802338302f), Q31(-0.54539587529618f)}, +{Q31(-0.20461677199539f), Q31(-0.14209977628489f)}, {Q31( 0.66223843141647f), Q31( 0.72528579940326f)}, +{Q31(-0.84764345483665f), Q31( 0.02372316801261f)}, {Q31(-0.89039863483811f), Q31( 0.88866581484602f)}, +{Q31( 0.95903308477986f), Q31( 0.76744927173873f)}, {Q31( 0.73504123909879f), Q31(-0.03747203173192f)}, +{Q31(-0.31744434966056f), Q31(-0.36834111883652f)}, {Q31(-0.34110827591623f), Q31( 0.40211222807691f)}, +{Q31( 0.47803883714199f), Q31(-0.39423219786288f)}, {Q31( 0.98299195879514f), Q31( 0.01989791390047f)}, +{Q31(-0.30963073129751f), Q31(-0.18076720599336f)}, {Q31( 0.99992588229018f), Q31(-0.26281872094289f)}, +{Q31(-0.93149731080767f), Q31(-0.98313162570490f)}, {Q31( 0.99923472302773f), Q31(-0.80142993767554f)}, +{Q31(-0.26024169633417f), Q31(-0.75999759855752f)}, {Q31(-0.35712514743563f), Q31( 0.19298963768574f)}, +{Q31(-0.99899084509530f), Q31( 0.74645156992493f)}, {Q31( 0.86557171579452f), Q31( 0.55593866696299f)}, +{Q31( 0.33408042438752f), Q31( 0.86185953874709f)}, {Q31( 0.99010736374716f), Q31( 0.04602397576623f)}, +{Q31(-0.66694269691195f), Q31(-0.91643611810148f)}, {Q31( 0.64016792079480f), Q31( 0.15649530836856f)}, +{Q31( 0.99570534804836f), Q31( 0.45844586038111f)}, {Q31(-0.63431466947340f), Q31( 0.21079116459234f)}, +{Q31(-0.07706847005931f), Q31(-0.89581437101329f)}, {Q31( 0.98590090577724f), Q31( 0.88241721133981f)}, +{Q31( 0.80099335254678f), Q31(-0.36851896710853f)}, {Q31( 0.78368131392666f), Q31( 0.45506999802597f)}, +{Q31( 0.08707806671691f), Q31( 0.80938994918745f)}, {Q31(-0.86811883080712f), Q31( 0.39347308654705f)}, +{Q31(-0.39466529740375f), Q31(-0.66809432114456f)}, {Q31( 0.97875325649683f), Q31(-0.72467840967746f)}, +{Q31(-0.95038560288864f), Q31( 0.89563219587625f)}, {Q31( 0.17005239424212f), Q31( 0.54683053962658f)}, +{Q31(-0.76910792026848f), Q31(-0.96226617549298f)}, {Q31( 0.99743281016846f), Q31( 0.42697157037567f)}, +{Q31( 0.95437383549973f), Q31( 0.97002324109952f)}, {Q31( 0.99578905365569f), Q31(-0.54106826257356f)}, +{Q31( 0.28058259829990f), Q31(-0.85361420634036f)}, {Q31( 0.85256524470573f), Q31(-0.64567607735589f)}, +{Q31(-0.50608540105128f), Q31(-0.65846015480300f)}, {Q31(-0.97210735183243f), Q31(-0.23095213067791f)}, +{Q31( 0.95424048234441f), Q31(-0.99240147091219f)}, {Q31(-0.96926570524023f), Q31( 0.73775654896574f)}, +{Q31( 0.30872163214726f), Q31( 0.41514960556126f)}, {Q31(-0.24523839572639f), Q31( 0.63206633394807f)}, +{Q31(-0.33813265086024f), Q31(-0.38661779441897f)}, {Q31(-0.05826828420146f), Q31(-0.06940774188029f)}, +{Q31(-0.22898461455054f), Q31( 0.97054853316316f)}, {Q31(-0.18509915019881f), Q31( 0.47565762892084f)}, +{Q31(-0.10488238045009f), Q31(-0.87769947402394f)}, {Q31(-0.71886586182037f), Q31( 0.78030982480538f)}, +{Q31( 0.99793873738654f), Q31( 0.90041310491497f)}, {Q31( 0.57563307626120f), Q31(-0.91034337352097f)}, +{Q31( 0.28909646383717f), Q31( 0.96307783970534f)}, {Q31( 0.42188998312520f), Q31( 0.48148651230437f)}, +{Q31( 0.93335049681047f), Q31(-0.43537023883588f)}, {Q31(-0.97087374418267f), Q31( 0.86636445711364f)}, +{Q31( 0.36722871286923f), Q31( 0.65291654172961f)}, {Q31(-0.81093025665696f), Q31( 0.08778370229363f)}, +{Q31(-0.26240603062237f), Q31(-0.92774095379098f)}, {Q31( 0.83996497984604f), Q31( 0.55839849139647f)}, +{Q31(-0.99909615720225f), Q31(-0.96024605713970f)}, {Q31( 0.74649464155061f), Q31( 0.12144893606462f)}, +{Q31(-0.74774595569805f), Q31(-0.26898062008959f)}, {Q31( 0.95781667469567f), Q31(-0.79047927052628f)}, +{Q31( 0.95472308713099f), Q31(-0.08588776019550f)}, {Q31( 0.48708332746299f), Q31( 0.99999041579432f)}, +{Q31( 0.46332038247497f), Q31( 0.10964126185063f)}, {Q31(-0.76497004940162f), Q31( 0.89210929242238f)}, +{Q31( 0.57397389364339f), Q31( 0.35289703373760f)}, {Q31( 0.75374316974495f), Q31( 0.96705214651335f)}, +{Q31(-0.59174397685714f), Q31(-0.89405370422752f)}, {Q31( 0.75087906691890f), Q31(-0.29612672982396f)}, +{Q31(-0.98607857336230f), Q31( 0.25034911730023f)}, {Q31(-0.40761056640505f), Q31(-0.90045573444695f)}, +{Q31( 0.66929266740477f), Q31( 0.98629493401748f)}, {Q31(-0.97463695257310f), Q31(-0.00190223301301f)}, +{Q31( 0.90145509409859f), Q31( 0.99781390365446f)}, {Q31(-0.87259289048043f), Q31( 0.99233587353666f)}, +{Q31(-0.91529461447692f), Q31(-0.15698707534206f)}, {Q31(-0.03305738840705f), Q31(-0.37205262859764f)}, +{Q31( 0.07223051368337f), Q31(-0.88805001733626f)}, {Q31( 0.99498012188353f), Q31( 0.97094358113387f)}, +{Q31(-0.74904939500519f), Q31( 0.99985483641521f)}, {Q31( 0.04585228574211f), Q31( 0.99812337444082f)}, +{Q31(-0.89054954257993f), Q31(-0.31791913188064f)}, {Q31(-0.83782144651251f), Q31( 0.97637632547466f)}, +{Q31( 0.33454804933804f), Q31(-0.86231516800408f)}, {Q31(-0.99707579362824f), Q31( 0.93237990079441f)}, +{Q31(-0.22827527843994f), Q31( 0.18874759397997f)}, {Q31( 0.67248046289143f), Q31(-0.03646211390569f)}, +{Q31(-0.05146538187944f), Q31(-0.92599700120679f)}, {Q31( 0.99947295749905f), Q31( 0.93625229707912f)}, +{Q31( 0.66951124390363f), Q31( 0.98905825623893f)}, {Q31(-0.99602956559179f), Q31(-0.44654715757688f)}, +{Q31( 0.82104905483590f), Q31( 0.99540741724928f)}, {Q31( 0.99186510988782f), Q31( 0.72023001312947f)}, +{Q31(-0.65284592392918f), Q31( 0.52186723253637f)}, {Q31( 0.93885443798188f), Q31(-0.74895312615259f)}, +{Q31( 0.96735248738388f), Q31( 0.90891816978629f)}, {Q31(-0.22225968841114f), Q31( 0.57124029781228f)}, +{Q31(-0.44132783753414f), Q31(-0.92688840659280f)}, {Q31(-0.85694974219574f), Q31( 0.88844532719844f)}, +{Q31( 0.91783042091762f), Q31(-0.46356892383970f)}, {Q31( 0.72556974415690f), Q31(-0.99899555770747f)}, +{Q31(-0.99711581834508f), Q31( 0.58211560180426f)}, {Q31( 0.77638976371966f), Q31( 0.94321834873819f)}, +{Q31( 0.07717324253925f), Q31( 0.58638399856595f)}, {Q31(-0.56049829194163f), Q31( 0.82522301569036f)}, +{Q31( 0.98398893639988f), Q31( 0.39467440420569f)}, {Q31( 0.47546946844938f), Q31( 0.68613044836811f)}, +{Q31( 0.65675089314631f), Q31( 0.18331637134880f)}, {Q31( 0.03273375457980f), Q31(-0.74933109564108f)}, +{Q31(-0.38684144784738f), Q31( 0.51337349030406f)}, {Q31(-0.97346267944545f), Q31(-0.96549364384098f)}, +{Q31(-0.53282156061942f), Q31(-0.91423265091354f)}, {Q31( 0.99817310731176f), Q31( 0.61133572482148f)}, +{Q31(-0.50254500772635f), Q31(-0.88829338134294f)}, {Q31( 0.01995873238855f), Q31( 0.85223515096765f)}, +{Q31( 0.99930381973804f), Q31( 0.94578896296649f)}, {Q31( 0.82907767600783f), Q31(-0.06323442598128f)}, +{Q31(-0.58660709669728f), Q31( 0.96840773806582f)}, {Q31(-0.17573736667267f), Q31(-0.48166920859485f)}, +{Q31( 0.83434292401346f), Q31(-0.13023450646997f)}, {Q31( 0.05946491307025f), Q31( 0.20511047074866f)}, +{Q31( 0.81505484574602f), Q31(-0.94685947861369f)}, {Q31(-0.44976380954860f), Q31( 0.40894572671545f)}, +{Q31(-0.89746474625671f), Q31( 0.99846578838537f)}, {Q31( 0.39677256130792f), Q31(-0.74854668609359f)}, +{Q31(-0.07588948563079f), Q31( 0.74096214084170f)}, {Q31( 0.76343198951445f), Q31( 0.41746629422634f)}, +{Q31(-0.74490104699626f), Q31( 0.94725911744610f)}, {Q31( 0.64880119792759f), Q31( 0.41336660830571f)}, +{Q31( 0.62319537462542f), Q31(-0.93098313552599f)}, {Q31( 0.42215817594807f), Q31(-0.07712787385208f)}, +{Q31( 0.02704554141885f), Q31(-0.05417518053666f)}, {Q31( 0.80001773566818f), Q31( 0.91542195141039f)}, +{Q31(-0.79351832348816f), Q31(-0.36208897989136f)}, {Q31( 0.63872359151636f), Q31( 0.08128252493444f)}, +{Q31( 0.52890520960295f), Q31( 0.60048872455592f)}, {Q31( 0.74238552914587f), Q31( 0.04491915291044f)}, +{Q31( 0.99096131449250f), Q31(-0.19451182854402f)}, {Q31(-0.80412329643109f), Q31(-0.88513818199457f)}, +{Q31(-0.64612616129736f), Q31( 0.72198674804544f)}, {Q31( 0.11657770663191f), Q31(-0.83662833815041f)}, +{Q31(-0.95053182488101f), Q31(-0.96939905138082f)}, {Q31(-0.62228872928622f), Q31( 0.82767262846661f)}, +{Q31( 0.03004475787316f), Q31(-0.99738896333384f)}, {Q31(-0.97987214341034f), Q31( 0.36526129686425f)}, +{Q31(-0.99986980746200f), Q31(-0.36021610299715f)}, {Q31( 0.89110648599879f), Q31(-0.97894250343044f)}, +{Q31( 0.10407960510582f), Q31( 0.77357793811619f)}, {Q31( 0.95964737821728f), Q31(-0.35435818285502f)}, +{Q31( 0.50843233159162f), Q31( 0.96107691266205f)}, {Q31( 0.17006334670615f), Q31(-0.76854025314829f)}, +{Q31( 0.25872675063360f), Q31( 0.99893303933816f)}, {Q31(-0.01115998681937f), Q31( 0.98496019742444f)}, +{Q31(-0.79598702973261f), Q31( 0.97138411318894f)}, {Q31(-0.99264708948101f), Q31(-0.99542822402536f)}, +{Q31(-0.99829663752818f), Q31( 0.01877138824311f)}, {Q31(-0.70801016548184f), Q31( 0.33680685948117f)}, +{Q31(-0.70467057786826f), Q31( 0.93272777501857f)}, {Q31( 0.99846021905254f), Q31(-0.98725746254433f)}, +{Q31(-0.63364968534650f), Q31(-0.16473594423746f)}, {Q31(-0.16258217500792f), Q31(-0.95939125400802f)}, +{Q31(-0.43645594360633f), Q31(-0.94805030113284f)}, {Q31(-0.99848471702976f), Q31( 0.96245166923809f)}, +{Q31(-0.16796458968998f), Q31(-0.98987511890470f)}, {Q31(-0.87979225745213f), Q31(-0.71725725041680f)}, +{Q31( 0.44183099021786f), Q31(-0.93568974498761f)}, {Q31( 0.93310180125532f), Q31(-0.99913308068246f)}, +{Q31(-0.93941931782002f), Q31(-0.56409379640356f)}, {Q31(-0.88590003188677f), Q31( 0.47624600491382f)}, +{Q31( 0.99971463703691f), Q31(-0.83889954253462f)}, {Q31(-0.75376385639978f), Q31( 0.00814643438625f)}, +{Q31( 0.93887685615875f), Q31(-0.11284528204636f)}, {Q31( 0.85126435782309f), Q31( 0.52349251543547f)}, +{Q31( 0.39701421446381f), Q31( 0.81779634174316f)}, {Q31(-0.37024464187437f), Q31(-0.87071656222959f)}, +{Q31(-0.36024828242896f), Q31( 0.34655735648287f)}, {Q31(-0.93388812549209f), Q31(-0.84476541096429f)}, +{Q31(-0.65298804552119f), Q31(-0.18439575450921f)}, {Q31( 0.11960319006843f), Q31( 0.99899346780168f)}, +{Q31( 0.94292565553160f), Q31( 0.83163906518293f)}, {Q31( 0.75081145286948f), Q31(-0.35533223142265f)}, +{Q31( 0.56721979748394f), Q31(-0.24076836414499f)}, {Q31( 0.46857766746029f), Q31(-0.30140233457198f)}, +{Q31( 0.97312313923635f), Q31(-0.99548191630031f)}, {Q31(-0.38299976567017f), Q31( 0.98516909715427f)}, +{Q31( 0.41025800019463f), Q31( 0.02116736935734f)}, {Q31( 0.09638062008048f), Q31( 0.04411984381457f)}, +{Q31(-0.85283249275397f), Q31( 0.91475563922421f)}, {Q31( 0.88866808958124f), Q31(-0.99735267083226f)}, +{Q31(-0.48202429536989f), Q31(-0.96805608884164f)}, {Q31( 0.27572582416567f), Q31( 0.58634753335832f)}, +{Q31(-0.65889129659168f), Q31( 0.58835634138583f)}, {Q31( 0.98838086953732f), Q31( 0.99994349600236f)}, +{Q31(-0.20651349620689f), Q31( 0.54593044066355f)}, {Q31(-0.62126416356920f), Q31(-0.59893681700392f)}, +{Q31( 0.20320105410437f), Q31(-0.86879180355289f)}, {Q31(-0.97790548600584f), Q31( 0.96290806999242f)}, +{Q31( 0.11112534735126f), Q31( 0.21484763313301f)}, {Q31(-0.41368337314182f), Q31( 0.28216837680365f)}, +{Q31( 0.24133038992960f), Q31( 0.51294362630238f)}, {Q31(-0.66393410674885f), Q31(-0.08249679629081f)}, +{Q31(-0.53697829178752f), Q31(-0.97649903936228f)}, {Q31(-0.97224737889348f), Q31( 0.22081333579837f)}, +{Q31( 0.87392477144549f), Q31(-0.12796173740361f)}, {Q31( 0.19050361015753f), Q31( 0.01602615387195f)}, +{Q31(-0.46353441212724f), Q31(-0.95249041539006f)}, {Q31(-0.07064096339021f), Q31(-0.94479803205886f)}, +{Q31(-0.92444085484466f), Q31(-0.10457590187436f)}, {Q31(-0.83822593578728f), Q31(-0.01695043208885f)}, +{Q31( 0.75214681811150f), Q31(-0.99955681042665f)}, {Q31(-0.42102998829339f), Q31( 0.99720941999394f)}, +{Q31(-0.72094786237696f), Q31(-0.35008961934255f)}, {Q31( 0.78843311019251f), Q31( 0.52851398958271f)}, +{Q31( 0.97394027897442f), Q31(-0.26695944086561f)}, {Q31( 0.99206463477946f), Q31(-0.57010120849429f)}, +{Q31( 0.76789609461795f), Q31(-0.76519356730966f)}, {Q31(-0.82002421836409f), Q31(-0.73530179553767f)}, +{Q31( 0.81924990025724f), Q31( 0.99698425250579f)}, {Q31(-0.26719850873357f), Q31( 0.68903369776193f)}, +{Q31(-0.43311260380975f), Q31( 0.85321815947490f)}, {Q31( 0.99194979673836f), Q31( 0.91876249766422f)}, +{Q31(-0.80692001248487f), Q31(-0.32627540663214f)}, {Q31( 0.43080003649976f), Q31(-0.21919095636638f)}, +{Q31( 0.67709491937357f), Q31(-0.95478075822906f)}, {Q31( 0.56151770568316f), Q31(-0.70693811747778f)}, +{Q31( 0.10831862810749f), Q31(-0.08628837174592f)}, {Q31( 0.91229417540436f), Q31(-0.65987351408410f)}, +{Q31(-0.48972893932274f), Q31( 0.56289246362686f)}, {Q31(-0.89033658689697f), Q31(-0.71656563987082f)}, +{Q31( 0.65269447475094f), Q31( 0.65916004833932f)}, {Q31( 0.67439478141121f), Q31(-0.81684380846796f)}, +{Q31(-0.47770832416973f), Q31(-0.16789556203025f)}, {Q31(-0.99715979260878f), Q31(-0.93565784007648f)}, +{Q31(-0.90889593602546f), Q31( 0.62034397054380f)}, {Q31(-0.06618622548177f), Q31(-0.23812217221359f)}, +{Q31( 0.99430266919728f), Q31( 0.18812555317553f)}, {Q31( 0.97686402381843f), Q31(-0.28664534366620f)}, +{Q31( 0.94813650221268f), Q31(-0.97506640027128f)}, {Q31(-0.95434497492853f), Q31(-0.79607978501983f)}, +{Q31(-0.49104783137150f), Q31( 0.32895214359663f)}, {Q31( 0.99881175120751f), Q31( 0.88993983831354f)}, +{Q31( 0.50449166760303f), Q31(-0.85995072408434f)}, {Q31( 0.47162891065108f), Q31(-0.18680204049569f)}, +{Q31(-0.62081581361840f), Q31( 0.75000676218956f)}, {Q31(-0.43867015250812f), Q31( 0.99998069244322f)}, +{Q31( 0.98630563232075f), Q31(-0.53578899600662f)}, {Q31(-0.61510362277374f), Q31(-0.89515019899997f)}, +{Q31(-0.03841517601843f), Q31(-0.69888815681179f)}, {Q31(-0.30102157304644f), Q31(-0.07667808922205f)}, +{Q31( 0.41881284182683f), Q31( 0.02188098922282f)}, {Q31(-0.86135454941237f), Q31( 0.98947480909359f)}, +{Q31( 0.67226861393788f), Q31(-0.13494389011014f)}, {Q31(-0.70737398842068f), Q31(-0.76547349325992f)}, +{Q31( 0.94044946687963f), Q31( 0.09026201157416f)}, {Q31(-0.82386352534327f), Q31( 0.08924768823676f)}, +{Q31(-0.32070666698656f), Q31( 0.50143421908753f)}, {Q31( 0.57593163224487f), Q31(-0.98966422921509f)}, +{Q31(-0.36326018419965f), Q31( 0.07440243123228f)}, {Q31( 0.99979044674350f), Q31(-0.14130287347405f)}, +{Q31(-0.92366023326932f), Q31(-0.97979298068180f)}, {Q31(-0.44607178518598f), Q31(-0.54233252016394f)}, +{Q31( 0.44226800932956f), Q31( 0.71326756742752f)}, {Q31( 0.03671907158312f), Q31( 0.63606389366675f)}, +{Q31( 0.52175424682195f), Q31(-0.85396826735705f)}, {Q31(-0.94701139690956f), Q31(-0.01826348194255f)}, +{Q31(-0.98759606946049f), Q31( 0.82288714303073f)}, {Q31( 0.87434794743625f), Q31( 0.89399495655433f)}, +{Q31(-0.93412041758744f), Q31( 0.41374052024363f)}, {Q31( 0.96063943315511f), Q31( 0.93116709541280f)}, +{Q31( 0.97534253457837f), Q31( 0.86150930812689f)}, {Q31( 0.99642466504163f), Q31( 0.70190043427512f)}, +{Q31(-0.94705089665984f), Q31(-0.29580042814306f)}, {Q31( 0.91599807087376f), Q31(-0.98147830385781f)}, +// Start of duplicated table +{Q31(-0.99948153278296f), Q31(-0.59483417516607f)}, {Q31( 0.97113454393991f), Q31(-0.67528515225647f)}, +{Q31( 0.14130051758487f), Q31(-0.95090983575689f)}, {Q31(-0.47005496701697f), Q31(-0.37340549728647f)}, +{Q31( 0.80705063769351f), Q31( 0.29653668284408f)}, {Q31(-0.38981478896926f), Q31( 0.89572605717087f)}, +{Q31(-0.01053049862020f), Q31(-0.66959058036166f)}, {Q31(-0.91266367957293f), Q31(-0.11522938140034f)}, +}; + +#endif /* AVCODEC_AACSBRDATA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aactab.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aactab.c new file mode 100644 index 0000000000..df551b058f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aactab.c @@ -0,0 +1,3282 @@ +/* + * AAC data + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC data + * @author Oded Shimon ( ods15 ods15 dyndns org ) + * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) + */ + +#include "libavutil/mem.h" +#include "aac.h" + +#include + +float ff_aac_pow2sf_tab[428]; +float ff_aac_pow34sf_tab[428]; + +DECLARE_ALIGNED(32, float, ff_aac_kbd_long_1024)[1024]; +DECLARE_ALIGNED(32, float, ff_aac_kbd_short_128)[128]; +DECLARE_ALIGNED(32, float, ff_aac_kbd_long_960)[960]; +DECLARE_ALIGNED(32, float, ff_aac_kbd_short_120)[120]; +DECLARE_ALIGNED(32, int, ff_aac_kbd_long_1024_fixed)[1024]; +DECLARE_ALIGNED(32, int, ff_aac_kbd_short_128_fixed)[128]; + +const uint8_t ff_aac_num_swb_1024[] = { + 41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40, 40 +}; + +const uint8_t ff_aac_num_swb_960[] = { + 40, 40, 46, 49, 49, 49, 46, 46, 42, 42, 42, 40, 40 +}; + +const uint8_t ff_aac_num_swb_512[] = { + 0, 0, 0, 36, 36, 37, 31, 31, 0, 0, 0, 0, 0 +}; + +const uint8_t ff_aac_num_swb_480[] = { + 0, 0, 0, 35, 35, 37, 30, 30, 0, 0, 0, 0, 0 +}; + +const uint8_t ff_aac_num_swb_128[] = { + 12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15 +}; + +const uint8_t ff_aac_num_swb_120[] = { + 12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15 +}; + +const uint8_t ff_aac_pred_sfb_max[] = { + 33, 33, 38, 40, 40, 40, 41, 41, 37, 37, 37, 34, 34 +}; + +const uint32_t ff_aac_scalefactor_code[121] = { + 0x3ffe8, 0x3ffe6, 0x3ffe7, 0x3ffe5, 0x7fff5, 0x7fff1, 0x7ffed, 0x7fff6, + 0x7ffee, 0x7ffef, 0x7fff0, 0x7fffc, 0x7fffd, 0x7ffff, 0x7fffe, 0x7fff7, + 0x7fff8, 0x7fffb, 0x7fff9, 0x3ffe4, 0x7fffa, 0x3ffe3, 0x1ffef, 0x1fff0, + 0x0fff5, 0x1ffee, 0x0fff2, 0x0fff3, 0x0fff4, 0x0fff1, 0x07ff6, 0x07ff7, + 0x03ff9, 0x03ff5, 0x03ff7, 0x03ff3, 0x03ff6, 0x03ff2, 0x01ff7, 0x01ff5, + 0x00ff9, 0x00ff7, 0x00ff6, 0x007f9, 0x00ff4, 0x007f8, 0x003f9, 0x003f7, + 0x003f5, 0x001f8, 0x001f7, 0x000fa, 0x000f8, 0x000f6, 0x00079, 0x0003a, + 0x00038, 0x0001a, 0x0000b, 0x00004, 0x00000, 0x0000a, 0x0000c, 0x0001b, + 0x00039, 0x0003b, 0x00078, 0x0007a, 0x000f7, 0x000f9, 0x001f6, 0x001f9, + 0x003f4, 0x003f6, 0x003f8, 0x007f5, 0x007f4, 0x007f6, 0x007f7, 0x00ff5, + 0x00ff8, 0x01ff4, 0x01ff6, 0x01ff8, 0x03ff8, 0x03ff4, 0x0fff0, 0x07ff4, + 0x0fff6, 0x07ff5, 0x3ffe2, 0x7ffd9, 0x7ffda, 0x7ffdb, 0x7ffdc, 0x7ffdd, + 0x7ffde, 0x7ffd8, 0x7ffd2, 0x7ffd3, 0x7ffd4, 0x7ffd5, 0x7ffd6, 0x7fff2, + 0x7ffdf, 0x7ffe7, 0x7ffe8, 0x7ffe9, 0x7ffea, 0x7ffeb, 0x7ffe6, 0x7ffe0, + 0x7ffe1, 0x7ffe2, 0x7ffe3, 0x7ffe4, 0x7ffe5, 0x7ffd7, 0x7ffec, 0x7fff4, + 0x7fff3, +}; + +const uint8_t ff_aac_scalefactor_bits[121] = { + 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 18, 19, 18, 17, 17, 16, 17, 16, 16, 16, 16, 15, 15, + 14, 14, 14, 14, 14, 14, 13, 13, 12, 12, 12, 11, 12, 11, 10, 10, + 10, 9, 9, 8, 8, 8, 7, 6, 6, 5, 4, 3, 1, 4, 4, 5, + 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12, + 12, 13, 13, 13, 14, 14, 16, 15, 16, 15, 18, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, +}; + +static const uint16_t codes1[81] = { + 0x7f8, 0x1f1, 0x7fd, 0x3f5, 0x068, 0x3f0, 0x7f7, 0x1ec, + 0x7f5, 0x3f1, 0x072, 0x3f4, 0x074, 0x011, 0x076, 0x1eb, + 0x06c, 0x3f6, 0x7fc, 0x1e1, 0x7f1, 0x1f0, 0x061, 0x1f6, + 0x7f2, 0x1ea, 0x7fb, 0x1f2, 0x069, 0x1ed, 0x077, 0x017, + 0x06f, 0x1e6, 0x064, 0x1e5, 0x067, 0x015, 0x062, 0x012, + 0x000, 0x014, 0x065, 0x016, 0x06d, 0x1e9, 0x063, 0x1e4, + 0x06b, 0x013, 0x071, 0x1e3, 0x070, 0x1f3, 0x7fe, 0x1e7, + 0x7f3, 0x1ef, 0x060, 0x1ee, 0x7f0, 0x1e2, 0x7fa, 0x3f3, + 0x06a, 0x1e8, 0x075, 0x010, 0x073, 0x1f4, 0x06e, 0x3f7, + 0x7f6, 0x1e0, 0x7f9, 0x3f2, 0x066, 0x1f5, 0x7ff, 0x1f7, + 0x7f4, +}; + +static const uint8_t bits1[81] = { + 11, 9, 11, 10, 7, 10, 11, 9, 11, 10, 7, 10, 7, 5, 7, 9, + 7, 10, 11, 9, 11, 9, 7, 9, 11, 9, 11, 9, 7, 9, 7, 5, + 7, 9, 7, 9, 7, 5, 7, 5, 1, 5, 7, 5, 7, 9, 7, 9, + 7, 5, 7, 9, 7, 9, 11, 9, 11, 9, 7, 9, 11, 9, 11, 10, + 7, 9, 7, 5, 7, 9, 7, 10, 11, 9, 11, 10, 7, 9, 11, 9, + 11, +}; + +static const uint16_t codes2[81] = { + 0x1f3, 0x06f, 0x1fd, 0x0eb, 0x023, 0x0ea, 0x1f7, 0x0e8, + 0x1fa, 0x0f2, 0x02d, 0x070, 0x020, 0x006, 0x02b, 0x06e, + 0x028, 0x0e9, 0x1f9, 0x066, 0x0f8, 0x0e7, 0x01b, 0x0f1, + 0x1f4, 0x06b, 0x1f5, 0x0ec, 0x02a, 0x06c, 0x02c, 0x00a, + 0x027, 0x067, 0x01a, 0x0f5, 0x024, 0x008, 0x01f, 0x009, + 0x000, 0x007, 0x01d, 0x00b, 0x030, 0x0ef, 0x01c, 0x064, + 0x01e, 0x00c, 0x029, 0x0f3, 0x02f, 0x0f0, 0x1fc, 0x071, + 0x1f2, 0x0f4, 0x021, 0x0e6, 0x0f7, 0x068, 0x1f8, 0x0ee, + 0x022, 0x065, 0x031, 0x002, 0x026, 0x0ed, 0x025, 0x06a, + 0x1fb, 0x072, 0x1fe, 0x069, 0x02e, 0x0f6, 0x1ff, 0x06d, + 0x1f6, +}; + +static const uint8_t bits2[81] = { + 9, 7, 9, 8, 6, 8, 9, 8, 9, 8, 6, 7, 6, 5, 6, 7, + 6, 8, 9, 7, 8, 8, 6, 8, 9, 7, 9, 8, 6, 7, 6, 5, + 6, 7, 6, 8, 6, 5, 6, 5, 3, 5, 6, 5, 6, 8, 6, 7, + 6, 5, 6, 8, 6, 8, 9, 7, 9, 8, 6, 8, 8, 7, 9, 8, + 6, 7, 6, 4, 6, 8, 6, 7, 9, 7, 9, 7, 6, 8, 9, 7, + 9, +}; + +static const uint16_t codes3[81] = { + 0x0000, 0x0009, 0x00ef, 0x000b, 0x0019, 0x00f0, 0x01eb, 0x01e6, + 0x03f2, 0x000a, 0x0035, 0x01ef, 0x0034, 0x0037, 0x01e9, 0x01ed, + 0x01e7, 0x03f3, 0x01ee, 0x03ed, 0x1ffa, 0x01ec, 0x01f2, 0x07f9, + 0x07f8, 0x03f8, 0x0ff8, 0x0008, 0x0038, 0x03f6, 0x0036, 0x0075, + 0x03f1, 0x03eb, 0x03ec, 0x0ff4, 0x0018, 0x0076, 0x07f4, 0x0039, + 0x0074, 0x03ef, 0x01f3, 0x01f4, 0x07f6, 0x01e8, 0x03ea, 0x1ffc, + 0x00f2, 0x01f1, 0x0ffb, 0x03f5, 0x07f3, 0x0ffc, 0x00ee, 0x03f7, + 0x7ffe, 0x01f0, 0x07f5, 0x7ffd, 0x1ffb, 0x3ffa, 0xffff, 0x00f1, + 0x03f0, 0x3ffc, 0x01ea, 0x03ee, 0x3ffb, 0x0ff6, 0x0ffa, 0x7ffc, + 0x07f2, 0x0ff5, 0xfffe, 0x03f4, 0x07f7, 0x7ffb, 0x0ff7, 0x0ff9, + 0x7ffa, +}; + +static const uint8_t bits3[81] = { + 1, 4, 8, 4, 5, 8, 9, 9, 10, 4, 6, 9, 6, 6, 9, 9, + 9, 10, 9, 10, 13, 9, 9, 11, 11, 10, 12, 4, 6, 10, 6, 7, + 10, 10, 10, 12, 5, 7, 11, 6, 7, 10, 9, 9, 11, 9, 10, 13, + 8, 9, 12, 10, 11, 12, 8, 10, 15, 9, 11, 15, 13, 14, 16, 8, + 10, 14, 9, 10, 14, 12, 12, 15, 11, 12, 16, 10, 11, 15, 12, 12, + 15, +}; + +static const uint16_t codes4[81] = { + 0x007, 0x016, 0x0f6, 0x018, 0x008, 0x0ef, 0x1ef, 0x0f3, + 0x7f8, 0x019, 0x017, 0x0ed, 0x015, 0x001, 0x0e2, 0x0f0, + 0x070, 0x3f0, 0x1ee, 0x0f1, 0x7fa, 0x0ee, 0x0e4, 0x3f2, + 0x7f6, 0x3ef, 0x7fd, 0x005, 0x014, 0x0f2, 0x009, 0x004, + 0x0e5, 0x0f4, 0x0e8, 0x3f4, 0x006, 0x002, 0x0e7, 0x003, + 0x000, 0x06b, 0x0e3, 0x069, 0x1f3, 0x0eb, 0x0e6, 0x3f6, + 0x06e, 0x06a, 0x1f4, 0x3ec, 0x1f0, 0x3f9, 0x0f5, 0x0ec, + 0x7fb, 0x0ea, 0x06f, 0x3f7, 0x7f9, 0x3f3, 0xfff, 0x0e9, + 0x06d, 0x3f8, 0x06c, 0x068, 0x1f5, 0x3ee, 0x1f2, 0x7f4, + 0x7f7, 0x3f1, 0xffe, 0x3ed, 0x1f1, 0x7f5, 0x7fe, 0x3f5, + 0x7fc, +}; + +static const uint8_t bits4[81] = { + 4, 5, 8, 5, 4, 8, 9, 8, 11, 5, 5, 8, 5, 4, 8, 8, + 7, 10, 9, 8, 11, 8, 8, 10, 11, 10, 11, 4, 5, 8, 4, 4, + 8, 8, 8, 10, 4, 4, 8, 4, 4, 7, 8, 7, 9, 8, 8, 10, + 7, 7, 9, 10, 9, 10, 8, 8, 11, 8, 7, 10, 11, 10, 12, 8, + 7, 10, 7, 7, 9, 10, 9, 11, 11, 10, 12, 10, 9, 11, 11, 10, + 11, +}; + +static const uint16_t codes5[81] = { + 0x1fff, 0x0ff7, 0x07f4, 0x07e8, 0x03f1, 0x07ee, 0x07f9, 0x0ff8, + 0x1ffd, 0x0ffd, 0x07f1, 0x03e8, 0x01e8, 0x00f0, 0x01ec, 0x03ee, + 0x07f2, 0x0ffa, 0x0ff4, 0x03ef, 0x01f2, 0x00e8, 0x0070, 0x00ec, + 0x01f0, 0x03ea, 0x07f3, 0x07eb, 0x01eb, 0x00ea, 0x001a, 0x0008, + 0x0019, 0x00ee, 0x01ef, 0x07ed, 0x03f0, 0x00f2, 0x0073, 0x000b, + 0x0000, 0x000a, 0x0071, 0x00f3, 0x07e9, 0x07ef, 0x01ee, 0x00ef, + 0x0018, 0x0009, 0x001b, 0x00eb, 0x01e9, 0x07ec, 0x07f6, 0x03eb, + 0x01f3, 0x00ed, 0x0072, 0x00e9, 0x01f1, 0x03ed, 0x07f7, 0x0ff6, + 0x07f0, 0x03e9, 0x01ed, 0x00f1, 0x01ea, 0x03ec, 0x07f8, 0x0ff9, + 0x1ffc, 0x0ffc, 0x0ff5, 0x07ea, 0x03f3, 0x03f2, 0x07f5, 0x0ffb, + 0x1ffe, +}; + +static const uint8_t bits5[81] = { + 13, 12, 11, 11, 10, 11, 11, 12, 13, 12, 11, 10, 9, 8, 9, 10, + 11, 12, 12, 10, 9, 8, 7, 8, 9, 10, 11, 11, 9, 8, 5, 4, + 5, 8, 9, 11, 10, 8, 7, 4, 1, 4, 7, 8, 11, 11, 9, 8, + 5, 4, 5, 8, 9, 11, 11, 10, 9, 8, 7, 8, 9, 10, 11, 12, + 11, 10, 9, 8, 9, 10, 11, 12, 13, 12, 12, 11, 10, 10, 11, 12, + 13, +}; + +static const uint16_t codes6[81] = { + 0x7fe, 0x3fd, 0x1f1, 0x1eb, 0x1f4, 0x1ea, 0x1f0, 0x3fc, + 0x7fd, 0x3f6, 0x1e5, 0x0ea, 0x06c, 0x071, 0x068, 0x0f0, + 0x1e6, 0x3f7, 0x1f3, 0x0ef, 0x032, 0x027, 0x028, 0x026, + 0x031, 0x0eb, 0x1f7, 0x1e8, 0x06f, 0x02e, 0x008, 0x004, + 0x006, 0x029, 0x06b, 0x1ee, 0x1ef, 0x072, 0x02d, 0x002, + 0x000, 0x003, 0x02f, 0x073, 0x1fa, 0x1e7, 0x06e, 0x02b, + 0x007, 0x001, 0x005, 0x02c, 0x06d, 0x1ec, 0x1f9, 0x0ee, + 0x030, 0x024, 0x02a, 0x025, 0x033, 0x0ec, 0x1f2, 0x3f8, + 0x1e4, 0x0ed, 0x06a, 0x070, 0x069, 0x074, 0x0f1, 0x3fa, + 0x7ff, 0x3f9, 0x1f6, 0x1ed, 0x1f8, 0x1e9, 0x1f5, 0x3fb, + 0x7fc, +}; + +static const uint8_t bits6[81] = { + 11, 10, 9, 9, 9, 9, 9, 10, 11, 10, 9, 8, 7, 7, 7, 8, + 9, 10, 9, 8, 6, 6, 6, 6, 6, 8, 9, 9, 7, 6, 4, 4, + 4, 6, 7, 9, 9, 7, 6, 4, 4, 4, 6, 7, 9, 9, 7, 6, + 4, 4, 4, 6, 7, 9, 9, 8, 6, 6, 6, 6, 6, 8, 9, 10, + 9, 8, 7, 7, 7, 7, 8, 10, 11, 10, 9, 9, 9, 9, 9, 10, + 11, +}; + +static const uint16_t codes7[64] = { + 0x000, 0x005, 0x037, 0x074, 0x0f2, 0x1eb, 0x3ed, 0x7f7, + 0x004, 0x00c, 0x035, 0x071, 0x0ec, 0x0ee, 0x1ee, 0x1f5, + 0x036, 0x034, 0x072, 0x0ea, 0x0f1, 0x1e9, 0x1f3, 0x3f5, + 0x073, 0x070, 0x0eb, 0x0f0, 0x1f1, 0x1f0, 0x3ec, 0x3fa, + 0x0f3, 0x0ed, 0x1e8, 0x1ef, 0x3ef, 0x3f1, 0x3f9, 0x7fb, + 0x1ed, 0x0ef, 0x1ea, 0x1f2, 0x3f3, 0x3f8, 0x7f9, 0x7fc, + 0x3ee, 0x1ec, 0x1f4, 0x3f4, 0x3f7, 0x7f8, 0xffd, 0xffe, + 0x7f6, 0x3f0, 0x3f2, 0x3f6, 0x7fa, 0x7fd, 0xffc, 0xfff, +}; + +static const uint8_t bits7[64] = { + 1, 3, 6, 7, 8, 9, 10, 11, 3, 4, 6, 7, 8, 8, 9, 9, + 6, 6, 7, 8, 8, 9, 9, 10, 7, 7, 8, 8, 9, 9, 10, 10, + 8, 8, 9, 9, 10, 10, 10, 11, 9, 8, 9, 9, 10, 10, 11, 11, + 10, 9, 9, 10, 10, 11, 12, 12, 11, 10, 10, 10, 11, 11, 12, 12, +}; + +static const uint16_t codes8[64] = { + 0x00e, 0x005, 0x010, 0x030, 0x06f, 0x0f1, 0x1fa, 0x3fe, + 0x003, 0x000, 0x004, 0x012, 0x02c, 0x06a, 0x075, 0x0f8, + 0x00f, 0x002, 0x006, 0x014, 0x02e, 0x069, 0x072, 0x0f5, + 0x02f, 0x011, 0x013, 0x02a, 0x032, 0x06c, 0x0ec, 0x0fa, + 0x071, 0x02b, 0x02d, 0x031, 0x06d, 0x070, 0x0f2, 0x1f9, + 0x0ef, 0x068, 0x033, 0x06b, 0x06e, 0x0ee, 0x0f9, 0x3fc, + 0x1f8, 0x074, 0x073, 0x0ed, 0x0f0, 0x0f6, 0x1f6, 0x1fd, + 0x3fd, 0x0f3, 0x0f4, 0x0f7, 0x1f7, 0x1fb, 0x1fc, 0x3ff, +}; + +static const uint8_t bits8[64] = { + 5, 4, 5, 6, 7, 8, 9, 10, 4, 3, 4, 5, 6, 7, 7, 8, + 5, 4, 4, 5, 6, 7, 7, 8, 6, 5, 5, 6, 6, 7, 8, 8, + 7, 6, 6, 6, 7, 7, 8, 9, 8, 7, 6, 7, 7, 8, 8, 10, + 9, 7, 7, 8, 8, 8, 9, 9, 10, 8, 8, 8, 9, 9, 9, 10, +}; + +static const uint16_t codes9[169] = { + 0x0000, 0x0005, 0x0037, 0x00e7, 0x01de, 0x03ce, 0x03d9, 0x07c8, + 0x07cd, 0x0fc8, 0x0fdd, 0x1fe4, 0x1fec, 0x0004, 0x000c, 0x0035, + 0x0072, 0x00ea, 0x00ed, 0x01e2, 0x03d1, 0x03d3, 0x03e0, 0x07d8, + 0x0fcf, 0x0fd5, 0x0036, 0x0034, 0x0071, 0x00e8, 0x00ec, 0x01e1, + 0x03cf, 0x03dd, 0x03db, 0x07d0, 0x0fc7, 0x0fd4, 0x0fe4, 0x00e6, + 0x0070, 0x00e9, 0x01dd, 0x01e3, 0x03d2, 0x03dc, 0x07cc, 0x07ca, + 0x07de, 0x0fd8, 0x0fea, 0x1fdb, 0x01df, 0x00eb, 0x01dc, 0x01e6, + 0x03d5, 0x03de, 0x07cb, 0x07dd, 0x07dc, 0x0fcd, 0x0fe2, 0x0fe7, + 0x1fe1, 0x03d0, 0x01e0, 0x01e4, 0x03d6, 0x07c5, 0x07d1, 0x07db, + 0x0fd2, 0x07e0, 0x0fd9, 0x0feb, 0x1fe3, 0x1fe9, 0x07c4, 0x01e5, + 0x03d7, 0x07c6, 0x07cf, 0x07da, 0x0fcb, 0x0fda, 0x0fe3, 0x0fe9, + 0x1fe6, 0x1ff3, 0x1ff7, 0x07d3, 0x03d8, 0x03e1, 0x07d4, 0x07d9, + 0x0fd3, 0x0fde, 0x1fdd, 0x1fd9, 0x1fe2, 0x1fea, 0x1ff1, 0x1ff6, + 0x07d2, 0x03d4, 0x03da, 0x07c7, 0x07d7, 0x07e2, 0x0fce, 0x0fdb, + 0x1fd8, 0x1fee, 0x3ff0, 0x1ff4, 0x3ff2, 0x07e1, 0x03df, 0x07c9, + 0x07d6, 0x0fca, 0x0fd0, 0x0fe5, 0x0fe6, 0x1feb, 0x1fef, 0x3ff3, + 0x3ff4, 0x3ff5, 0x0fe0, 0x07ce, 0x07d5, 0x0fc6, 0x0fd1, 0x0fe1, + 0x1fe0, 0x1fe8, 0x1ff0, 0x3ff1, 0x3ff8, 0x3ff6, 0x7ffc, 0x0fe8, + 0x07df, 0x0fc9, 0x0fd7, 0x0fdc, 0x1fdc, 0x1fdf, 0x1fed, 0x1ff5, + 0x3ff9, 0x3ffb, 0x7ffd, 0x7ffe, 0x1fe7, 0x0fcc, 0x0fd6, 0x0fdf, + 0x1fde, 0x1fda, 0x1fe5, 0x1ff2, 0x3ffa, 0x3ff7, 0x3ffc, 0x3ffd, + 0x7fff, +}; + +static const uint8_t bits9[169] = { + 1, 3, 6, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 3, 4, 6, + 7, 8, 8, 9, 10, 10, 10, 11, 12, 12, 6, 6, 7, 8, 8, 9, + 10, 10, 10, 11, 12, 12, 12, 8, 7, 8, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 13, 9, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, + 13, 10, 9, 9, 10, 11, 11, 11, 12, 11, 12, 12, 13, 13, 11, 9, + 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 11, 10, 10, 11, 11, + 12, 12, 13, 13, 13, 13, 13, 13, 11, 10, 10, 11, 11, 11, 12, 12, + 13, 13, 14, 13, 14, 11, 10, 11, 11, 12, 12, 12, 12, 13, 13, 14, + 14, 14, 12, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 12, + 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15, 13, 12, 12, 12, + 13, 13, 13, 13, 14, 14, 14, 14, 15, +}; + +static const uint16_t codes10[169] = { + 0x022, 0x008, 0x01d, 0x026, 0x05f, 0x0d3, 0x1cf, 0x3d0, + 0x3d7, 0x3ed, 0x7f0, 0x7f6, 0xffd, 0x007, 0x000, 0x001, + 0x009, 0x020, 0x054, 0x060, 0x0d5, 0x0dc, 0x1d4, 0x3cd, + 0x3de, 0x7e7, 0x01c, 0x002, 0x006, 0x00c, 0x01e, 0x028, + 0x05b, 0x0cd, 0x0d9, 0x1ce, 0x1dc, 0x3d9, 0x3f1, 0x025, + 0x00b, 0x00a, 0x00d, 0x024, 0x057, 0x061, 0x0cc, 0x0dd, + 0x1cc, 0x1de, 0x3d3, 0x3e7, 0x05d, 0x021, 0x01f, 0x023, + 0x027, 0x059, 0x064, 0x0d8, 0x0df, 0x1d2, 0x1e2, 0x3dd, + 0x3ee, 0x0d1, 0x055, 0x029, 0x056, 0x058, 0x062, 0x0ce, + 0x0e0, 0x0e2, 0x1da, 0x3d4, 0x3e3, 0x7eb, 0x1c9, 0x05e, + 0x05a, 0x05c, 0x063, 0x0ca, 0x0da, 0x1c7, 0x1ca, 0x1e0, + 0x3db, 0x3e8, 0x7ec, 0x1e3, 0x0d2, 0x0cb, 0x0d0, 0x0d7, + 0x0db, 0x1c6, 0x1d5, 0x1d8, 0x3ca, 0x3da, 0x7ea, 0x7f1, + 0x1e1, 0x0d4, 0x0cf, 0x0d6, 0x0de, 0x0e1, 0x1d0, 0x1d6, + 0x3d1, 0x3d5, 0x3f2, 0x7ee, 0x7fb, 0x3e9, 0x1cd, 0x1c8, + 0x1cb, 0x1d1, 0x1d7, 0x1df, 0x3cf, 0x3e0, 0x3ef, 0x7e6, + 0x7f8, 0xffa, 0x3eb, 0x1dd, 0x1d3, 0x1d9, 0x1db, 0x3d2, + 0x3cc, 0x3dc, 0x3ea, 0x7ed, 0x7f3, 0x7f9, 0xff9, 0x7f2, + 0x3ce, 0x1e4, 0x3cb, 0x3d8, 0x3d6, 0x3e2, 0x3e5, 0x7e8, + 0x7f4, 0x7f5, 0x7f7, 0xffb, 0x7fa, 0x3ec, 0x3df, 0x3e1, + 0x3e4, 0x3e6, 0x3f0, 0x7e9, 0x7ef, 0xff8, 0xffe, 0xffc, + 0xfff, +}; + +static const uint8_t bits10[169] = { + 6, 5, 6, 6, 7, 8, 9, 10, 10, 10, 11, 11, 12, 5, 4, 4, + 5, 6, 7, 7, 8, 8, 9, 10, 10, 11, 6, 4, 5, 5, 6, 6, + 7, 8, 8, 9, 9, 10, 10, 6, 5, 5, 5, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 7, 6, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 8, 7, 6, 7, 7, 7, 8, 8, 8, 9, 10, 10, 11, 9, 7, + 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 9, 8, 8, 8, 8, + 8, 9, 9, 9, 10, 10, 11, 11, 9, 8, 8, 8, 8, 8, 9, 9, + 10, 10, 10, 11, 11, 10, 9, 9, 9, 9, 9, 9, 10, 10, 10, 11, + 11, 12, 10, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 11, + 10, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 11, 10, 10, 10, + 10, 10, 10, 11, 11, 12, 12, 12, 12, +}; + +static const uint16_t codes11[289] = { + 0x000, 0x006, 0x019, 0x03d, 0x09c, 0x0c6, 0x1a7, 0x390, + 0x3c2, 0x3df, 0x7e6, 0x7f3, 0xffb, 0x7ec, 0xffa, 0xffe, + 0x38e, 0x005, 0x001, 0x008, 0x014, 0x037, 0x042, 0x092, + 0x0af, 0x191, 0x1a5, 0x1b5, 0x39e, 0x3c0, 0x3a2, 0x3cd, + 0x7d6, 0x0ae, 0x017, 0x007, 0x009, 0x018, 0x039, 0x040, + 0x08e, 0x0a3, 0x0b8, 0x199, 0x1ac, 0x1c1, 0x3b1, 0x396, + 0x3be, 0x3ca, 0x09d, 0x03c, 0x015, 0x016, 0x01a, 0x03b, + 0x044, 0x091, 0x0a5, 0x0be, 0x196, 0x1ae, 0x1b9, 0x3a1, + 0x391, 0x3a5, 0x3d5, 0x094, 0x09a, 0x036, 0x038, 0x03a, + 0x041, 0x08c, 0x09b, 0x0b0, 0x0c3, 0x19e, 0x1ab, 0x1bc, + 0x39f, 0x38f, 0x3a9, 0x3cf, 0x093, 0x0bf, 0x03e, 0x03f, + 0x043, 0x045, 0x09e, 0x0a7, 0x0b9, 0x194, 0x1a2, 0x1ba, + 0x1c3, 0x3a6, 0x3a7, 0x3bb, 0x3d4, 0x09f, 0x1a0, 0x08f, + 0x08d, 0x090, 0x098, 0x0a6, 0x0b6, 0x0c4, 0x19f, 0x1af, + 0x1bf, 0x399, 0x3bf, 0x3b4, 0x3c9, 0x3e7, 0x0a8, 0x1b6, + 0x0ab, 0x0a4, 0x0aa, 0x0b2, 0x0c2, 0x0c5, 0x198, 0x1a4, + 0x1b8, 0x38c, 0x3a4, 0x3c4, 0x3c6, 0x3dd, 0x3e8, 0x0ad, + 0x3af, 0x192, 0x0bd, 0x0bc, 0x18e, 0x197, 0x19a, 0x1a3, + 0x1b1, 0x38d, 0x398, 0x3b7, 0x3d3, 0x3d1, 0x3db, 0x7dd, + 0x0b4, 0x3de, 0x1a9, 0x19b, 0x19c, 0x1a1, 0x1aa, 0x1ad, + 0x1b3, 0x38b, 0x3b2, 0x3b8, 0x3ce, 0x3e1, 0x3e0, 0x7d2, + 0x7e5, 0x0b7, 0x7e3, 0x1bb, 0x1a8, 0x1a6, 0x1b0, 0x1b2, + 0x1b7, 0x39b, 0x39a, 0x3ba, 0x3b5, 0x3d6, 0x7d7, 0x3e4, + 0x7d8, 0x7ea, 0x0ba, 0x7e8, 0x3a0, 0x1bd, 0x1b4, 0x38a, + 0x1c4, 0x392, 0x3aa, 0x3b0, 0x3bc, 0x3d7, 0x7d4, 0x7dc, + 0x7db, 0x7d5, 0x7f0, 0x0c1, 0x7fb, 0x3c8, 0x3a3, 0x395, + 0x39d, 0x3ac, 0x3ae, 0x3c5, 0x3d8, 0x3e2, 0x3e6, 0x7e4, + 0x7e7, 0x7e0, 0x7e9, 0x7f7, 0x190, 0x7f2, 0x393, 0x1be, + 0x1c0, 0x394, 0x397, 0x3ad, 0x3c3, 0x3c1, 0x3d2, 0x7da, + 0x7d9, 0x7df, 0x7eb, 0x7f4, 0x7fa, 0x195, 0x7f8, 0x3bd, + 0x39c, 0x3ab, 0x3a8, 0x3b3, 0x3b9, 0x3d0, 0x3e3, 0x3e5, + 0x7e2, 0x7de, 0x7ed, 0x7f1, 0x7f9, 0x7fc, 0x193, 0xffd, + 0x3dc, 0x3b6, 0x3c7, 0x3cc, 0x3cb, 0x3d9, 0x3da, 0x7d3, + 0x7e1, 0x7ee, 0x7ef, 0x7f5, 0x7f6, 0xffc, 0xfff, 0x19d, + 0x1c2, 0x0b5, 0x0a1, 0x096, 0x097, 0x095, 0x099, 0x0a0, + 0x0a2, 0x0ac, 0x0a9, 0x0b1, 0x0b3, 0x0bb, 0x0c0, 0x18f, + 0x004, +}; + +static const uint8_t bits11[289] = { + 4, 5, 6, 7, 8, 8, 9, 10, 10, 10, 11, 11, 12, 11, 12, 12, + 10, 5, 4, 5, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, + 11, 8, 6, 5, 5, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, + 10, 10, 8, 7, 6, 6, 6, 7, 7, 8, 8, 8, 9, 9, 9, 10, + 10, 10, 10, 8, 8, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, + 10, 10, 10, 10, 8, 8, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, + 9, 10, 10, 10, 10, 8, 9, 8, 8, 8, 8, 8, 8, 8, 9, 9, + 9, 10, 10, 10, 10, 10, 8, 9, 8, 8, 8, 8, 8, 8, 9, 9, + 9, 10, 10, 10, 10, 10, 10, 8, 10, 9, 8, 8, 9, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 10, 11, 8, 10, 9, 9, 9, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 10, 11, 11, 8, 11, 9, 9, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 11, 10, 11, 11, 8, 11, 10, 9, 9, 10, + 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 8, 11, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 9, 11, 10, 9, + 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 9, 11, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 9, 12, + 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 9, + 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 5, +}; + +const uint16_t * const ff_aac_spectral_codes[11] = { + codes1, codes2, codes3, codes4, codes5, codes6, codes7, codes8, + codes9, codes10, codes11, +}; + +const uint8_t * const ff_aac_spectral_bits[11] = { + bits1, bits2, bits3, bits4, bits5, bits6, bits7, bits8, + bits9, bits10, bits11, +}; + +const uint16_t ff_aac_spectral_sizes[11] = { + 81, 81, 81, 81, 81, 81, 64, 64, 169, 169, 289, +}; + +/* NOTE: + * 64.0f is a special value indicating the existence of an escape code in the + * bitstream. + */ +static const DECLARE_ALIGNED(16, float, codebook_vector0)[324] = { + -1.0000000, -1.0000000, -1.0000000, -1.0000000, + -1.0000000, -1.0000000, -1.0000000, 0.0000000, + -1.0000000, -1.0000000, -1.0000000, 1.0000000, + -1.0000000, -1.0000000, 0.0000000, -1.0000000, + -1.0000000, -1.0000000, 0.0000000, 0.0000000, + -1.0000000, -1.0000000, 0.0000000, 1.0000000, + -1.0000000, -1.0000000, 1.0000000, -1.0000000, + -1.0000000, -1.0000000, 1.0000000, 0.0000000, + -1.0000000, -1.0000000, 1.0000000, 1.0000000, + -1.0000000, 0.0000000, -1.0000000, -1.0000000, + -1.0000000, 0.0000000, -1.0000000, 0.0000000, + -1.0000000, 0.0000000, -1.0000000, 1.0000000, + -1.0000000, 0.0000000, 0.0000000, -1.0000000, + -1.0000000, 0.0000000, 0.0000000, 0.0000000, + -1.0000000, 0.0000000, 0.0000000, 1.0000000, + -1.0000000, 0.0000000, 1.0000000, -1.0000000, + -1.0000000, 0.0000000, 1.0000000, 0.0000000, + -1.0000000, 0.0000000, 1.0000000, 1.0000000, + -1.0000000, 1.0000000, -1.0000000, -1.0000000, + -1.0000000, 1.0000000, -1.0000000, 0.0000000, + -1.0000000, 1.0000000, -1.0000000, 1.0000000, + -1.0000000, 1.0000000, 0.0000000, -1.0000000, + -1.0000000, 1.0000000, 0.0000000, 0.0000000, + -1.0000000, 1.0000000, 0.0000000, 1.0000000, + -1.0000000, 1.0000000, 1.0000000, -1.0000000, + -1.0000000, 1.0000000, 1.0000000, 0.0000000, + -1.0000000, 1.0000000, 1.0000000, 1.0000000, + 0.0000000, -1.0000000, -1.0000000, -1.0000000, + 0.0000000, -1.0000000, -1.0000000, 0.0000000, + 0.0000000, -1.0000000, -1.0000000, 1.0000000, + 0.0000000, -1.0000000, 0.0000000, -1.0000000, + 0.0000000, -1.0000000, 0.0000000, 0.0000000, + 0.0000000, -1.0000000, 0.0000000, 1.0000000, + 0.0000000, -1.0000000, 1.0000000, -1.0000000, + 0.0000000, -1.0000000, 1.0000000, 0.0000000, + 0.0000000, -1.0000000, 1.0000000, 1.0000000, + 0.0000000, 0.0000000, -1.0000000, -1.0000000, + 0.0000000, 0.0000000, -1.0000000, 0.0000000, + 0.0000000, 0.0000000, -1.0000000, 1.0000000, + 0.0000000, 0.0000000, 0.0000000, -1.0000000, + 0.0000000, 0.0000000, 0.0000000, 0.0000000, + 0.0000000, 0.0000000, 0.0000000, 1.0000000, + 0.0000000, 0.0000000, 1.0000000, -1.0000000, + 0.0000000, 0.0000000, 1.0000000, 0.0000000, + 0.0000000, 0.0000000, 1.0000000, 1.0000000, + 0.0000000, 1.0000000, -1.0000000, -1.0000000, + 0.0000000, 1.0000000, -1.0000000, 0.0000000, + 0.0000000, 1.0000000, -1.0000000, 1.0000000, + 0.0000000, 1.0000000, 0.0000000, -1.0000000, + 0.0000000, 1.0000000, 0.0000000, 0.0000000, + 0.0000000, 1.0000000, 0.0000000, 1.0000000, + 0.0000000, 1.0000000, 1.0000000, -1.0000000, + 0.0000000, 1.0000000, 1.0000000, 0.0000000, + 0.0000000, 1.0000000, 1.0000000, 1.0000000, + 1.0000000, -1.0000000, -1.0000000, -1.0000000, + 1.0000000, -1.0000000, -1.0000000, 0.0000000, + 1.0000000, -1.0000000, -1.0000000, 1.0000000, + 1.0000000, -1.0000000, 0.0000000, -1.0000000, + 1.0000000, -1.0000000, 0.0000000, 0.0000000, + 1.0000000, -1.0000000, 0.0000000, 1.0000000, + 1.0000000, -1.0000000, 1.0000000, -1.0000000, + 1.0000000, -1.0000000, 1.0000000, 0.0000000, + 1.0000000, -1.0000000, 1.0000000, 1.0000000, + 1.0000000, 0.0000000, -1.0000000, -1.0000000, + 1.0000000, 0.0000000, -1.0000000, 0.0000000, + 1.0000000, 0.0000000, -1.0000000, 1.0000000, + 1.0000000, 0.0000000, 0.0000000, -1.0000000, + 1.0000000, 0.0000000, 0.0000000, 0.0000000, + 1.0000000, 0.0000000, 0.0000000, 1.0000000, + 1.0000000, 0.0000000, 1.0000000, -1.0000000, + 1.0000000, 0.0000000, 1.0000000, 0.0000000, + 1.0000000, 0.0000000, 1.0000000, 1.0000000, + 1.0000000, 1.0000000, -1.0000000, -1.0000000, + 1.0000000, 1.0000000, -1.0000000, 0.0000000, + 1.0000000, 1.0000000, -1.0000000, 1.0000000, + 1.0000000, 1.0000000, 0.0000000, -1.0000000, + 1.0000000, 1.0000000, 0.0000000, 0.0000000, + 1.0000000, 1.0000000, 0.0000000, 1.0000000, + 1.0000000, 1.0000000, 1.0000000, -1.0000000, + 1.0000000, 1.0000000, 1.0000000, 0.0000000, + 1.0000000, 1.0000000, 1.0000000, 1.0000000, +}; + +static const DECLARE_ALIGNED(16, float, codebook_vector2)[324] = { + 0.0000000, 0.0000000, 0.0000000, 0.0000000, + 0.0000000, 0.0000000, 0.0000000, 1.0000000, + 0.0000000, 0.0000000, 0.0000000, 2.5198421, + 0.0000000, 0.0000000, 1.0000000, 0.0000000, + 0.0000000, 0.0000000, 1.0000000, 1.0000000, + 0.0000000, 0.0000000, 1.0000000, 2.5198421, + 0.0000000, 0.0000000, 2.5198421, 0.0000000, + 0.0000000, 0.0000000, 2.5198421, 1.0000000, + 0.0000000, 0.0000000, 2.5198421, 2.5198421, + 0.0000000, 1.0000000, 0.0000000, 0.0000000, + 0.0000000, 1.0000000, 0.0000000, 1.0000000, + 0.0000000, 1.0000000, 0.0000000, 2.5198421, + 0.0000000, 1.0000000, 1.0000000, 0.0000000, + 0.0000000, 1.0000000, 1.0000000, 1.0000000, + 0.0000000, 1.0000000, 1.0000000, 2.5198421, + 0.0000000, 1.0000000, 2.5198421, 0.0000000, + 0.0000000, 1.0000000, 2.5198421, 1.0000000, + 0.0000000, 1.0000000, 2.5198421, 2.5198421, + 0.0000000, 2.5198421, 0.0000000, 0.0000000, + 0.0000000, 2.5198421, 0.0000000, 1.0000000, + 0.0000000, 2.5198421, 0.0000000, 2.5198421, + 0.0000000, 2.5198421, 1.0000000, 0.0000000, + 0.0000000, 2.5198421, 1.0000000, 1.0000000, + 0.0000000, 2.5198421, 1.0000000, 2.5198421, + 0.0000000, 2.5198421, 2.5198421, 0.0000000, + 0.0000000, 2.5198421, 2.5198421, 1.0000000, + 0.0000000, 2.5198421, 2.5198421, 2.5198421, + 1.0000000, 0.0000000, 0.0000000, 0.0000000, + 1.0000000, 0.0000000, 0.0000000, 1.0000000, + 1.0000000, 0.0000000, 0.0000000, 2.5198421, + 1.0000000, 0.0000000, 1.0000000, 0.0000000, + 1.0000000, 0.0000000, 1.0000000, 1.0000000, + 1.0000000, 0.0000000, 1.0000000, 2.5198421, + 1.0000000, 0.0000000, 2.5198421, 0.0000000, + 1.0000000, 0.0000000, 2.5198421, 1.0000000, + 1.0000000, 0.0000000, 2.5198421, 2.5198421, + 1.0000000, 1.0000000, 0.0000000, 0.0000000, + 1.0000000, 1.0000000, 0.0000000, 1.0000000, + 1.0000000, 1.0000000, 0.0000000, 2.5198421, + 1.0000000, 1.0000000, 1.0000000, 0.0000000, + 1.0000000, 1.0000000, 1.0000000, 1.0000000, + 1.0000000, 1.0000000, 1.0000000, 2.5198421, + 1.0000000, 1.0000000, 2.5198421, 0.0000000, + 1.0000000, 1.0000000, 2.5198421, 1.0000000, + 1.0000000, 1.0000000, 2.5198421, 2.5198421, + 1.0000000, 2.5198421, 0.0000000, 0.0000000, + 1.0000000, 2.5198421, 0.0000000, 1.0000000, + 1.0000000, 2.5198421, 0.0000000, 2.5198421, + 1.0000000, 2.5198421, 1.0000000, 0.0000000, + 1.0000000, 2.5198421, 1.0000000, 1.0000000, + 1.0000000, 2.5198421, 1.0000000, 2.5198421, + 1.0000000, 2.5198421, 2.5198421, 0.0000000, + 1.0000000, 2.5198421, 2.5198421, 1.0000000, + 1.0000000, 2.5198421, 2.5198421, 2.5198421, + 2.5198421, 0.0000000, 0.0000000, 0.0000000, + 2.5198421, 0.0000000, 0.0000000, 1.0000000, + 2.5198421, 0.0000000, 0.0000000, 2.5198421, + 2.5198421, 0.0000000, 1.0000000, 0.0000000, + 2.5198421, 0.0000000, 1.0000000, 1.0000000, + 2.5198421, 0.0000000, 1.0000000, 2.5198421, + 2.5198421, 0.0000000, 2.5198421, 0.0000000, + 2.5198421, 0.0000000, 2.5198421, 1.0000000, + 2.5198421, 0.0000000, 2.5198421, 2.5198421, + 2.5198421, 1.0000000, 0.0000000, 0.0000000, + 2.5198421, 1.0000000, 0.0000000, 1.0000000, + 2.5198421, 1.0000000, 0.0000000, 2.5198421, + 2.5198421, 1.0000000, 1.0000000, 0.0000000, + 2.5198421, 1.0000000, 1.0000000, 1.0000000, + 2.5198421, 1.0000000, 1.0000000, 2.5198421, + 2.5198421, 1.0000000, 2.5198421, 0.0000000, + 2.5198421, 1.0000000, 2.5198421, 1.0000000, + 2.5198421, 1.0000000, 2.5198421, 2.5198421, + 2.5198421, 2.5198421, 0.0000000, 0.0000000, + 2.5198421, 2.5198421, 0.0000000, 1.0000000, + 2.5198421, 2.5198421, 0.0000000, 2.5198421, + 2.5198421, 2.5198421, 1.0000000, 0.0000000, + 2.5198421, 2.5198421, 1.0000000, 1.0000000, + 2.5198421, 2.5198421, 1.0000000, 2.5198421, + 2.5198421, 2.5198421, 2.5198421, 0.0000000, + 2.5198421, 2.5198421, 2.5198421, 1.0000000, + 2.5198421, 2.5198421, 2.5198421, 2.5198421, +}; + +static const DECLARE_ALIGNED(16, float, codebook_vector4)[162] = { + -6.3496042, -6.3496042, -6.3496042, -4.3267487, + -6.3496042, -2.5198421, -6.3496042, -1.0000000, + -6.3496042, 0.0000000, -6.3496042, 1.0000000, + -6.3496042, 2.5198421, -6.3496042, 4.3267487, + -6.3496042, 6.3496042, -4.3267487, -6.3496042, + -4.3267487, -4.3267487, -4.3267487, -2.5198421, + -4.3267487, -1.0000000, -4.3267487, 0.0000000, + -4.3267487, 1.0000000, -4.3267487, 2.5198421, + -4.3267487, 4.3267487, -4.3267487, 6.3496042, + -2.5198421, -6.3496042, -2.5198421, -4.3267487, + -2.5198421, -2.5198421, -2.5198421, -1.0000000, + -2.5198421, 0.0000000, -2.5198421, 1.0000000, + -2.5198421, 2.5198421, -2.5198421, 4.3267487, + -2.5198421, 6.3496042, -1.0000000, -6.3496042, + -1.0000000, -4.3267487, -1.0000000, -2.5198421, + -1.0000000, -1.0000000, -1.0000000, 0.0000000, + -1.0000000, 1.0000000, -1.0000000, 2.5198421, + -1.0000000, 4.3267487, -1.0000000, 6.3496042, + 0.0000000, -6.3496042, 0.0000000, -4.3267487, + 0.0000000, -2.5198421, 0.0000000, -1.0000000, + 0.0000000, 0.0000000, 0.0000000, 1.0000000, + 0.0000000, 2.5198421, 0.0000000, 4.3267487, + 0.0000000, 6.3496042, 1.0000000, -6.3496042, + 1.0000000, -4.3267487, 1.0000000, -2.5198421, + 1.0000000, -1.0000000, 1.0000000, 0.0000000, + 1.0000000, 1.0000000, 1.0000000, 2.5198421, + 1.0000000, 4.3267487, 1.0000000, 6.3496042, + 2.5198421, -6.3496042, 2.5198421, -4.3267487, + 2.5198421, -2.5198421, 2.5198421, -1.0000000, + 2.5198421, 0.0000000, 2.5198421, 1.0000000, + 2.5198421, 2.5198421, 2.5198421, 4.3267487, + 2.5198421, 6.3496042, 4.3267487, -6.3496042, + 4.3267487, -4.3267487, 4.3267487, -2.5198421, + 4.3267487, -1.0000000, 4.3267487, 0.0000000, + 4.3267487, 1.0000000, 4.3267487, 2.5198421, + 4.3267487, 4.3267487, 4.3267487, 6.3496042, + 6.3496042, -6.3496042, 6.3496042, -4.3267487, + 6.3496042, -2.5198421, 6.3496042, -1.0000000, + 6.3496042, 0.0000000, 6.3496042, 1.0000000, + 6.3496042, 2.5198421, 6.3496042, 4.3267487, + 6.3496042, 6.3496042, +}; + +static const DECLARE_ALIGNED(16, float, codebook_vector6)[128] = { + 0.0000000, 0.0000000, 0.0000000, 1.0000000, + 0.0000000, 2.5198421, 0.0000000, 4.3267487, + 0.0000000, 6.3496042, 0.0000000, 8.5498797, + 0.0000000, 10.9027236, 0.0000000, 13.3905183, + 1.0000000, 0.0000000, 1.0000000, 1.0000000, + 1.0000000, 2.5198421, 1.0000000, 4.3267487, + 1.0000000, 6.3496042, 1.0000000, 8.5498797, + 1.0000000, 10.9027236, 1.0000000, 13.3905183, + 2.5198421, 0.0000000, 2.5198421, 1.0000000, + 2.5198421, 2.5198421, 2.5198421, 4.3267487, + 2.5198421, 6.3496042, 2.5198421, 8.5498797, + 2.5198421, 10.9027236, 2.5198421, 13.3905183, + 4.3267487, 0.0000000, 4.3267487, 1.0000000, + 4.3267487, 2.5198421, 4.3267487, 4.3267487, + 4.3267487, 6.3496042, 4.3267487, 8.5498797, + 4.3267487, 10.9027236, 4.3267487, 13.3905183, + 6.3496042, 0.0000000, 6.3496042, 1.0000000, + 6.3496042, 2.5198421, 6.3496042, 4.3267487, + 6.3496042, 6.3496042, 6.3496042, 8.5498797, + 6.3496042, 10.9027236, 6.3496042, 13.3905183, + 8.5498797, 0.0000000, 8.5498797, 1.0000000, + 8.5498797, 2.5198421, 8.5498797, 4.3267487, + 8.5498797, 6.3496042, 8.5498797, 8.5498797, + 8.5498797, 10.9027236, 8.5498797, 13.3905183, + 10.9027236, 0.0000000, 10.9027236, 1.0000000, + 10.9027236, 2.5198421, 10.9027236, 4.3267487, + 10.9027236, 6.3496042, 10.9027236, 8.5498797, + 10.9027236, 10.9027236, 10.9027236, 13.3905183, + 13.3905183, 0.0000000, 13.3905183, 1.0000000, + 13.3905183, 2.5198421, 13.3905183, 4.3267487, + 13.3905183, 6.3496042, 13.3905183, 8.5498797, + 13.3905183, 10.9027236, 13.3905183, 13.3905183, +}; + +static const DECLARE_ALIGNED(16, float, codebook_vector8)[338] = { + 0.0000000, 0.0000000, 0.0000000, 1.0000000, + 0.0000000, 2.5198421, 0.0000000, 4.3267487, + 0.0000000, 6.3496042, 0.0000000, 8.5498797, + 0.0000000, 10.9027236, 0.0000000, 13.3905183, + 0.0000000, 16.0000000, 0.0000000, 18.7207544, + 0.0000000, 21.5443469, 0.0000000, 24.4637810, + 0.0000000, 27.4731418, 1.0000000, 0.0000000, + 1.0000000, 1.0000000, 1.0000000, 2.5198421, + 1.0000000, 4.3267487, 1.0000000, 6.3496042, + 1.0000000, 8.5498797, 1.0000000, 10.9027236, + 1.0000000, 13.3905183, 1.0000000, 16.0000000, + 1.0000000, 18.7207544, 1.0000000, 21.5443469, + 1.0000000, 24.4637810, 1.0000000, 27.4731418, + 2.5198421, 0.0000000, 2.5198421, 1.0000000, + 2.5198421, 2.5198421, 2.5198421, 4.3267487, + 2.5198421, 6.3496042, 2.5198421, 8.5498797, + 2.5198421, 10.9027236, 2.5198421, 13.3905183, + 2.5198421, 16.0000000, 2.5198421, 18.7207544, + 2.5198421, 21.5443469, 2.5198421, 24.4637810, + 2.5198421, 27.4731418, 4.3267487, 0.0000000, + 4.3267487, 1.0000000, 4.3267487, 2.5198421, + 4.3267487, 4.3267487, 4.3267487, 6.3496042, + 4.3267487, 8.5498797, 4.3267487, 10.9027236, + 4.3267487, 13.3905183, 4.3267487, 16.0000000, + 4.3267487, 18.7207544, 4.3267487, 21.5443469, + 4.3267487, 24.4637810, 4.3267487, 27.4731418, + 6.3496042, 0.0000000, 6.3496042, 1.0000000, + 6.3496042, 2.5198421, 6.3496042, 4.3267487, + 6.3496042, 6.3496042, 6.3496042, 8.5498797, + 6.3496042, 10.9027236, 6.3496042, 13.3905183, + 6.3496042, 16.0000000, 6.3496042, 18.7207544, + 6.3496042, 21.5443469, 6.3496042, 24.4637810, + 6.3496042, 27.4731418, 8.5498797, 0.0000000, + 8.5498797, 1.0000000, 8.5498797, 2.5198421, + 8.5498797, 4.3267487, 8.5498797, 6.3496042, + 8.5498797, 8.5498797, 8.5498797, 10.9027236, + 8.5498797, 13.3905183, 8.5498797, 16.0000000, + 8.5498797, 18.7207544, 8.5498797, 21.5443469, + 8.5498797, 24.4637810, 8.5498797, 27.4731418, + 10.9027236, 0.0000000, 10.9027236, 1.0000000, + 10.9027236, 2.5198421, 10.9027236, 4.3267487, + 10.9027236, 6.3496042, 10.9027236, 8.5498797, + 10.9027236, 10.9027236, 10.9027236, 13.3905183, + 10.9027236, 16.0000000, 10.9027236, 18.7207544, + 10.9027236, 21.5443469, 10.9027236, 24.4637810, + 10.9027236, 27.4731418, 13.3905183, 0.0000000, + 13.3905183, 1.0000000, 13.3905183, 2.5198421, + 13.3905183, 4.3267487, 13.3905183, 6.3496042, + 13.3905183, 8.5498797, 13.3905183, 10.9027236, + 13.3905183, 13.3905183, 13.3905183, 16.0000000, + 13.3905183, 18.7207544, 13.3905183, 21.5443469, + 13.3905183, 24.4637810, 13.3905183, 27.4731418, + 16.0000000, 0.0000000, 16.0000000, 1.0000000, + 16.0000000, 2.5198421, 16.0000000, 4.3267487, + 16.0000000, 6.3496042, 16.0000000, 8.5498797, + 16.0000000, 10.9027236, 16.0000000, 13.3905183, + 16.0000000, 16.0000000, 16.0000000, 18.7207544, + 16.0000000, 21.5443469, 16.0000000, 24.4637810, + 16.0000000, 27.4731418, 18.7207544, 0.0000000, + 18.7207544, 1.0000000, 18.7207544, 2.5198421, + 18.7207544, 4.3267487, 18.7207544, 6.3496042, + 18.7207544, 8.5498797, 18.7207544, 10.9027236, + 18.7207544, 13.3905183, 18.7207544, 16.0000000, + 18.7207544, 18.7207544, 18.7207544, 21.5443469, + 18.7207544, 24.4637810, 18.7207544, 27.4731418, + 21.5443469, 0.0000000, 21.5443469, 1.0000000, + 21.5443469, 2.5198421, 21.5443469, 4.3267487, + 21.5443469, 6.3496042, 21.5443469, 8.5498797, + 21.5443469, 10.9027236, 21.5443469, 13.3905183, + 21.5443469, 16.0000000, 21.5443469, 18.7207544, + 21.5443469, 21.5443469, 21.5443469, 24.4637810, + 21.5443469, 27.4731418, 24.4637810, 0.0000000, + 24.4637810, 1.0000000, 24.4637810, 2.5198421, + 24.4637810, 4.3267487, 24.4637810, 6.3496042, + 24.4637810, 8.5498797, 24.4637810, 10.9027236, + 24.4637810, 13.3905183, 24.4637810, 16.0000000, + 24.4637810, 18.7207544, 24.4637810, 21.5443469, + 24.4637810, 24.4637810, 24.4637810, 27.4731418, + 27.4731418, 0.0000000, 27.4731418, 1.0000000, + 27.4731418, 2.5198421, 27.4731418, 4.3267487, + 27.4731418, 6.3496042, 27.4731418, 8.5498797, + 27.4731418, 10.9027236, 27.4731418, 13.3905183, + 27.4731418, 16.0000000, 27.4731418, 18.7207544, + 27.4731418, 21.5443469, 27.4731418, 24.4637810, + 27.4731418, 27.4731418, +}; + +static const DECLARE_ALIGNED(16, float, codebook_vector10)[578] = { + 0.0000000, 0.0000000, 0.0000000, 1.0000000, + 0.0000000, 2.5198421, 0.0000000, 4.3267487, + 0.0000000, 6.3496042, 0.0000000, 8.5498797, + 0.0000000, 10.9027236, 0.0000000, 13.3905183, + 0.0000000, 16.0000000, 0.0000000, 18.7207544, + 0.0000000, 21.5443469, 0.0000000, 24.4637810, + 0.0000000, 27.4731418, 0.0000000, 30.5673509, + 0.0000000, 33.7419917, 0.0000000, 36.9931811, + 0.0000000, 64.0f, 1.0000000, 0.0000000, + 1.0000000, 1.0000000, 1.0000000, 2.5198421, + 1.0000000, 4.3267487, 1.0000000, 6.3496042, + 1.0000000, 8.5498797, 1.0000000, 10.9027236, + 1.0000000, 13.3905183, 1.0000000, 16.0000000, + 1.0000000, 18.7207544, 1.0000000, 21.5443469, + 1.0000000, 24.4637810, 1.0000000, 27.4731418, + 1.0000000, 30.5673509, 1.0000000, 33.7419917, + 1.0000000, 36.9931811, 1.0000000, 64.0f, + 2.5198421, 0.0000000, 2.5198421, 1.0000000, + 2.5198421, 2.5198421, 2.5198421, 4.3267487, + 2.5198421, 6.3496042, 2.5198421, 8.5498797, + 2.5198421, 10.9027236, 2.5198421, 13.3905183, + 2.5198421, 16.0000000, 2.5198421, 18.7207544, + 2.5198421, 21.5443469, 2.5198421, 24.4637810, + 2.5198421, 27.4731418, 2.5198421, 30.5673509, + 2.5198421, 33.7419917, 2.5198421, 36.9931811, + 2.5198421, 64.0f, 4.3267487, 0.0000000, + 4.3267487, 1.0000000, 4.3267487, 2.5198421, + 4.3267487, 4.3267487, 4.3267487, 6.3496042, + 4.3267487, 8.5498797, 4.3267487, 10.9027236, + 4.3267487, 13.3905183, 4.3267487, 16.0000000, + 4.3267487, 18.7207544, 4.3267487, 21.5443469, + 4.3267487, 24.4637810, 4.3267487, 27.4731418, + 4.3267487, 30.5673509, 4.3267487, 33.7419917, + 4.3267487, 36.9931811, 4.3267487, 64.0f, + 6.3496042, 0.0000000, 6.3496042, 1.0000000, + 6.3496042, 2.5198421, 6.3496042, 4.3267487, + 6.3496042, 6.3496042, 6.3496042, 8.5498797, + 6.3496042, 10.9027236, 6.3496042, 13.3905183, + 6.3496042, 16.0000000, 6.3496042, 18.7207544, + 6.3496042, 21.5443469, 6.3496042, 24.4637810, + 6.3496042, 27.4731418, 6.3496042, 30.5673509, + 6.3496042, 33.7419917, 6.3496042, 36.9931811, + 6.3496042, 64.0f, 8.5498797, 0.0000000, + 8.5498797, 1.0000000, 8.5498797, 2.5198421, + 8.5498797, 4.3267487, 8.5498797, 6.3496042, + 8.5498797, 8.5498797, 8.5498797, 10.9027236, + 8.5498797, 13.3905183, 8.5498797, 16.0000000, + 8.5498797, 18.7207544, 8.5498797, 21.5443469, + 8.5498797, 24.4637810, 8.5498797, 27.4731418, + 8.5498797, 30.5673509, 8.5498797, 33.7419917, + 8.5498797, 36.9931811, 8.5498797, 64.0f, + 10.9027236, 0.0000000, 10.9027236, 1.0000000, + 10.9027236, 2.5198421, 10.9027236, 4.3267487, + 10.9027236, 6.3496042, 10.9027236, 8.5498797, + 10.9027236, 10.9027236, 10.9027236, 13.3905183, + 10.9027236, 16.0000000, 10.9027236, 18.7207544, + 10.9027236, 21.5443469, 10.9027236, 24.4637810, + 10.9027236, 27.4731418, 10.9027236, 30.5673509, + 10.9027236, 33.7419917, 10.9027236, 36.9931811, + 10.9027236, 64.0f, 13.3905183, 0.0000000, + 13.3905183, 1.0000000, 13.3905183, 2.5198421, + 13.3905183, 4.3267487, 13.3905183, 6.3496042, + 13.3905183, 8.5498797, 13.3905183, 10.9027236, + 13.3905183, 13.3905183, 13.3905183, 16.0000000, + 13.3905183, 18.7207544, 13.3905183, 21.5443469, + 13.3905183, 24.4637810, 13.3905183, 27.4731418, + 13.3905183, 30.5673509, 13.3905183, 33.7419917, + 13.3905183, 36.9931811, 13.3905183, 64.0f, + 16.0000000, 0.0000000, 16.0000000, 1.0000000, + 16.0000000, 2.5198421, 16.0000000, 4.3267487, + 16.0000000, 6.3496042, 16.0000000, 8.5498797, + 16.0000000, 10.9027236, 16.0000000, 13.3905183, + 16.0000000, 16.0000000, 16.0000000, 18.7207544, + 16.0000000, 21.5443469, 16.0000000, 24.4637810, + 16.0000000, 27.4731418, 16.0000000, 30.5673509, + 16.0000000, 33.7419917, 16.0000000, 36.9931811, + 16.0000000, 64.0f, 18.7207544, 0.0000000, + 18.7207544, 1.0000000, 18.7207544, 2.5198421, + 18.7207544, 4.3267487, 18.7207544, 6.3496042, + 18.7207544, 8.5498797, 18.7207544, 10.9027236, + 18.7207544, 13.3905183, 18.7207544, 16.0000000, + 18.7207544, 18.7207544, 18.7207544, 21.5443469, + 18.7207544, 24.4637810, 18.7207544, 27.4731418, + 18.7207544, 30.5673509, 18.7207544, 33.7419917, + 18.7207544, 36.9931811, 18.7207544, 64.0f, + 21.5443469, 0.0000000, 21.5443469, 1.0000000, + 21.5443469, 2.5198421, 21.5443469, 4.3267487, + 21.5443469, 6.3496042, 21.5443469, 8.5498797, + 21.5443469, 10.9027236, 21.5443469, 13.3905183, + 21.5443469, 16.0000000, 21.5443469, 18.7207544, + 21.5443469, 21.5443469, 21.5443469, 24.4637810, + 21.5443469, 27.4731418, 21.5443469, 30.5673509, + 21.5443469, 33.7419917, 21.5443469, 36.9931811, + 21.5443469, 64.0f, 24.4637810, 0.0000000, + 24.4637810, 1.0000000, 24.4637810, 2.5198421, + 24.4637810, 4.3267487, 24.4637810, 6.3496042, + 24.4637810, 8.5498797, 24.4637810, 10.9027236, + 24.4637810, 13.3905183, 24.4637810, 16.0000000, + 24.4637810, 18.7207544, 24.4637810, 21.5443469, + 24.4637810, 24.4637810, 24.4637810, 27.4731418, + 24.4637810, 30.5673509, 24.4637810, 33.7419917, + 24.4637810, 36.9931811, 24.4637810, 64.0f, + 27.4731418, 0.0000000, 27.4731418, 1.0000000, + 27.4731418, 2.5198421, 27.4731418, 4.3267487, + 27.4731418, 6.3496042, 27.4731418, 8.5498797, + 27.4731418, 10.9027236, 27.4731418, 13.3905183, + 27.4731418, 16.0000000, 27.4731418, 18.7207544, + 27.4731418, 21.5443469, 27.4731418, 24.4637810, + 27.4731418, 27.4731418, 27.4731418, 30.5673509, + 27.4731418, 33.7419917, 27.4731418, 36.9931811, + 27.4731418, 64.0f, 30.5673509, 0.0000000, + 30.5673509, 1.0000000, 30.5673509, 2.5198421, + 30.5673509, 4.3267487, 30.5673509, 6.3496042, + 30.5673509, 8.5498797, 30.5673509, 10.9027236, + 30.5673509, 13.3905183, 30.5673509, 16.0000000, + 30.5673509, 18.7207544, 30.5673509, 21.5443469, + 30.5673509, 24.4637810, 30.5673509, 27.4731418, + 30.5673509, 30.5673509, 30.5673509, 33.7419917, + 30.5673509, 36.9931811, 30.5673509, 64.0f, + 33.7419917, 0.0000000, 33.7419917, 1.0000000, + 33.7419917, 2.5198421, 33.7419917, 4.3267487, + 33.7419917, 6.3496042, 33.7419917, 8.5498797, + 33.7419917, 10.9027236, 33.7419917, 13.3905183, + 33.7419917, 16.0000000, 33.7419917, 18.7207544, + 33.7419917, 21.5443469, 33.7419917, 24.4637810, + 33.7419917, 27.4731418, 33.7419917, 30.5673509, + 33.7419917, 33.7419917, 33.7419917, 36.9931811, + 33.7419917, 64.0f, 36.9931811, 0.0000000, + 36.9931811, 1.0000000, 36.9931811, 2.5198421, + 36.9931811, 4.3267487, 36.9931811, 6.3496042, + 36.9931811, 8.5498797, 36.9931811, 10.9027236, + 36.9931811, 13.3905183, 36.9931811, 16.0000000, + 36.9931811, 18.7207544, 36.9931811, 21.5443469, + 36.9931811, 24.4637810, 36.9931811, 27.4731418, + 36.9931811, 30.5673509, 36.9931811, 33.7419917, + 36.9931811, 36.9931811, 36.9931811, 64.0f, + 64.0f, 0.0000000, 64.0f, 1.0000000, + 64.0f, 2.5198421, 64.0f, 4.3267487, + 64.0f, 6.3496042, 64.0f, 8.5498797, + 64.0f, 10.9027236, 64.0f, 13.3905183, + 64.0f, 16.0000000, 64.0f, 18.7207544, + 64.0f, 21.5443469, 64.0f, 24.4637810, + 64.0f, 27.4731418, 64.0f, 30.5673509, + 64.0f, 33.7419917, 64.0f, 36.9931811, + 64.0f, 64.0f, +}; + +const float * const ff_aac_codebook_vectors[] = { + codebook_vector0, codebook_vector0, codebook_vector2, + codebook_vector2, codebook_vector4, codebook_vector4, + codebook_vector6, codebook_vector6, codebook_vector8, + codebook_vector8, codebook_vector10, +}; + +static const float codebook_vector0_vals[] = { + -1.0000000, 0.0000000, 1.0000000 +}; + +/* + * bits 0:1, 2:3, 4:5, 6:7 index into _vals array + * 8:11 number of non-zero values + * 12:15 bit mask of non-zero values + */ +static const uint16_t codebook_vector02_idx[] = { + 0x0000, 0x8140, 0x8180, 0x4110, 0xc250, 0xc290, 0x4120, 0xc260, 0xc2a0, + 0x2104, 0xa244, 0xa284, 0x6214, 0xe354, 0xe394, 0x6224, 0xe364, 0xe3a4, + 0x2108, 0xa248, 0xa288, 0x6218, 0xe358, 0xe398, 0x6228, 0xe368, 0xe3a8, + 0x1101, 0x9241, 0x9281, 0x5211, 0xd351, 0xd391, 0x5221, 0xd361, 0xd3a1, + 0x3205, 0xb345, 0xb385, 0x7315, 0xf455, 0xf495, 0x7325, 0xf465, 0xf4a5, + 0x3209, 0xb349, 0xb389, 0x7319, 0xf459, 0xf499, 0x7329, 0xf469, 0xf4a9, + 0x1102, 0x9242, 0x9282, 0x5212, 0xd352, 0xd392, 0x5222, 0xd362, 0xd3a2, + 0x3206, 0xb346, 0xb386, 0x7316, 0xf456, 0xf496, 0x7326, 0xf466, 0xf4a6, + 0x320a, 0xb34a, 0xb38a, 0x731a, 0xf45a, 0xf49a, 0x732a, 0xf46a, 0xf4aa, +}; + +static const float codebook_vector4_vals[] = { + -6.3496042, -4.3267487, + -2.5198421, -1.0000000, + 0.0000000, 1.0000000, + 2.5198421, 4.3267487, + 6.3496042, +}; + +/* + * bits 0:3, 4:7 index into _vals array + */ +static const uint16_t codebook_vector4_idx[] = { + 0x0000, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, + 0x0001, 0x0011, 0x0021, 0x0031, 0x0041, 0x0051, 0x0061, 0x0071, 0x0081, + 0x0002, 0x0012, 0x0022, 0x0032, 0x0042, 0x0052, 0x0062, 0x0072, 0x0082, + 0x0003, 0x0013, 0x0023, 0x0033, 0x0043, 0x0053, 0x0063, 0x0073, 0x0083, + 0x0004, 0x0014, 0x0024, 0x0034, 0x0044, 0x0054, 0x0064, 0x0074, 0x0084, + 0x0005, 0x0015, 0x0025, 0x0035, 0x0045, 0x0055, 0x0065, 0x0075, 0x0085, + 0x0006, 0x0016, 0x0026, 0x0036, 0x0046, 0x0056, 0x0066, 0x0076, 0x0086, + 0x0007, 0x0017, 0x0027, 0x0037, 0x0047, 0x0057, 0x0067, 0x0077, 0x0087, + 0x0008, 0x0018, 0x0028, 0x0038, 0x0048, 0x0058, 0x0068, 0x0078, 0x0088, +}; + +/* + * bits 0:3, 4:7 index into _vals array + * 8:11 number of non-zero values + * 12:15 1: only second value non-zero + * 0: other cases + */ +static const uint16_t codebook_vector6_idx[] = { + 0x0000, 0x0110, 0x0120, 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, + 0x1101, 0x0211, 0x0221, 0x0231, 0x0241, 0x0251, 0x0261, 0x0271, + 0x1102, 0x0212, 0x0222, 0x0232, 0x0242, 0x0252, 0x0262, 0x0272, + 0x1103, 0x0213, 0x0223, 0x0233, 0x0243, 0x0253, 0x0263, 0x0273, + 0x1104, 0x0214, 0x0224, 0x0234, 0x0244, 0x0254, 0x0264, 0x0274, + 0x1105, 0x0215, 0x0225, 0x0235, 0x0245, 0x0255, 0x0265, 0x0275, + 0x1106, 0x0216, 0x0226, 0x0236, 0x0246, 0x0256, 0x0266, 0x0276, + 0x1107, 0x0217, 0x0227, 0x0237, 0x0247, 0x0257, 0x0267, 0x0277, +}; + +/* + * bits 0:3, 4:7 index into _vals array + * 8:11 number of non-zero values + * 12:15 1: only second value non-zero + * 0: other cases + */ +static const uint16_t codebook_vector8_idx[] = { + 0x0000, 0x0110, 0x0120, 0x0130, 0x0140, 0x0150, 0x0160, + 0x0170, 0x0180, 0x0190, 0x01a0, 0x01b0, 0x01c0, + 0x1101, 0x0211, 0x0221, 0x0231, 0x0241, 0x0251, 0x0261, + 0x0271, 0x0281, 0x0291, 0x02a1, 0x02b1, 0x02c1, + 0x1102, 0x0212, 0x0222, 0x0232, 0x0242, 0x0252, 0x0262, + 0x0272, 0x0282, 0x0292, 0x02a2, 0x02b2, 0x02c2, + 0x1103, 0x0213, 0x0223, 0x0233, 0x0243, 0x0253, 0x0263, + 0x0273, 0x0283, 0x0293, 0x02a3, 0x02b3, 0x02c3, + 0x1104, 0x0214, 0x0224, 0x0234, 0x0244, 0x0254, 0x0264, + 0x0274, 0x0284, 0x0294, 0x02a4, 0x02b4, 0x02c4, + 0x1105, 0x0215, 0x0225, 0x0235, 0x0245, 0x0255, 0x0265, + 0x0275, 0x0285, 0x0295, 0x02a5, 0x02b5, 0x02c5, + 0x1106, 0x0216, 0x0226, 0x0236, 0x0246, 0x0256, 0x0266, + 0x0276, 0x0286, 0x0296, 0x02a6, 0x02b6, 0x02c6, + 0x1107, 0x0217, 0x0227, 0x0237, 0x0247, 0x0257, 0x0267, + 0x0277, 0x0287, 0x0297, 0x02a7, 0x02b7, 0x02c7, + 0x1108, 0x0218, 0x0228, 0x0238, 0x0248, 0x0258, 0x0268, + 0x0278, 0x0288, 0x0298, 0x02a8, 0x02b8, 0x02c8, + 0x1109, 0x0219, 0x0229, 0x0239, 0x0249, 0x0259, 0x0269, + 0x0279, 0x0289, 0x0299, 0x02a9, 0x02b9, 0x02c9, + 0x110a, 0x021a, 0x022a, 0x023a, 0x024a, 0x025a, 0x026a, + 0x027a, 0x028a, 0x029a, 0x02aa, 0x02ba, 0x02ca, + 0x110b, 0x021b, 0x022b, 0x023b, 0x024b, 0x025b, 0x026b, + 0x027b, 0x028b, 0x029b, 0x02ab, 0x02bb, 0x02cb, + 0x110c, 0x021c, 0x022c, 0x023c, 0x024c, 0x025c, 0x026c, + 0x027c, 0x028c, 0x029c, 0x02ac, 0x02bc, 0x02cc, +}; + +static const float codebook_vector10_vals[] = { + 0.0000000, 1.0000000, + 2.5198421, 4.3267487, + 6.3496042, 8.5498797, + 10.9027236, 13.3905183, + 16.0000000, 18.7207544, + 21.5443469, 24.4637810, + 27.4731418, 30.5673509, + 33.7419917, 36.9931811, +}; + +/* + * bits 0:3, 4:7 index into _vals array + * 8:9 bit mask of escape-coded entries + * 12:15 number of non-zero values + */ +static const uint16_t codebook_vector10_idx[] = { + 0x0000, 0x1010, 0x1020, 0x1030, 0x1040, 0x1050, 0x1060, 0x1070, + 0x1080, 0x1090, 0x10a0, 0x10b0, 0x10c0, 0x10d0, 0x10e0, 0x10f0, 0x1200, + 0x1001, 0x2011, 0x2021, 0x2031, 0x2041, 0x2051, 0x2061, 0x2071, + 0x2081, 0x2091, 0x20a1, 0x20b1, 0x20c1, 0x20d1, 0x20e1, 0x20f1, 0x2201, + 0x1002, 0x2012, 0x2022, 0x2032, 0x2042, 0x2052, 0x2062, 0x2072, + 0x2082, 0x2092, 0x20a2, 0x20b2, 0x20c2, 0x20d2, 0x20e2, 0x20f2, 0x2202, + 0x1003, 0x2013, 0x2023, 0x2033, 0x2043, 0x2053, 0x2063, 0x2073, + 0x2083, 0x2093, 0x20a3, 0x20b3, 0x20c3, 0x20d3, 0x20e3, 0x20f3, 0x2203, + 0x1004, 0x2014, 0x2024, 0x2034, 0x2044, 0x2054, 0x2064, 0x2074, + 0x2084, 0x2094, 0x20a4, 0x20b4, 0x20c4, 0x20d4, 0x20e4, 0x20f4, 0x2204, + 0x1005, 0x2015, 0x2025, 0x2035, 0x2045, 0x2055, 0x2065, 0x2075, + 0x2085, 0x2095, 0x20a5, 0x20b5, 0x20c5, 0x20d5, 0x20e5, 0x20f5, 0x2205, + 0x1006, 0x2016, 0x2026, 0x2036, 0x2046, 0x2056, 0x2066, 0x2076, + 0x2086, 0x2096, 0x20a6, 0x20b6, 0x20c6, 0x20d6, 0x20e6, 0x20f6, 0x2206, + 0x1007, 0x2017, 0x2027, 0x2037, 0x2047, 0x2057, 0x2067, 0x2077, + 0x2087, 0x2097, 0x20a7, 0x20b7, 0x20c7, 0x20d7, 0x20e7, 0x20f7, 0x2207, + 0x1008, 0x2018, 0x2028, 0x2038, 0x2048, 0x2058, 0x2068, 0x2078, + 0x2088, 0x2098, 0x20a8, 0x20b8, 0x20c8, 0x20d8, 0x20e8, 0x20f8, 0x2208, + 0x1009, 0x2019, 0x2029, 0x2039, 0x2049, 0x2059, 0x2069, 0x2079, + 0x2089, 0x2099, 0x20a9, 0x20b9, 0x20c9, 0x20d9, 0x20e9, 0x20f9, 0x2209, + 0x100a, 0x201a, 0x202a, 0x203a, 0x204a, 0x205a, 0x206a, 0x207a, + 0x208a, 0x209a, 0x20aa, 0x20ba, 0x20ca, 0x20da, 0x20ea, 0x20fa, 0x220a, + 0x100b, 0x201b, 0x202b, 0x203b, 0x204b, 0x205b, 0x206b, 0x207b, + 0x208b, 0x209b, 0x20ab, 0x20bb, 0x20cb, 0x20db, 0x20eb, 0x20fb, 0x220b, + 0x100c, 0x201c, 0x202c, 0x203c, 0x204c, 0x205c, 0x206c, 0x207c, + 0x208c, 0x209c, 0x20ac, 0x20bc, 0x20cc, 0x20dc, 0x20ec, 0x20fc, 0x220c, + 0x100d, 0x201d, 0x202d, 0x203d, 0x204d, 0x205d, 0x206d, 0x207d, + 0x208d, 0x209d, 0x20ad, 0x20bd, 0x20cd, 0x20dd, 0x20ed, 0x20fd, 0x220d, + 0x100e, 0x201e, 0x202e, 0x203e, 0x204e, 0x205e, 0x206e, 0x207e, + 0x208e, 0x209e, 0x20ae, 0x20be, 0x20ce, 0x20de, 0x20ee, 0x20fe, 0x220e, + 0x100f, 0x201f, 0x202f, 0x203f, 0x204f, 0x205f, 0x206f, 0x207f, + 0x208f, 0x209f, 0x20af, 0x20bf, 0x20cf, 0x20df, 0x20ef, 0x20ff, 0x220f, + 0x1100, 0x2110, 0x2120, 0x2130, 0x2140, 0x2150, 0x2160, 0x2170, + 0x2180, 0x2190, 0x21a0, 0x21b0, 0x21c0, 0x21d0, 0x21e0, 0x21f0, 0x2300, +}; + +const float *const ff_aac_codebook_vector_vals[] = { + codebook_vector0_vals, codebook_vector0_vals, + codebook_vector10_vals, codebook_vector10_vals, + codebook_vector4_vals, codebook_vector4_vals, + codebook_vector10_vals, codebook_vector10_vals, + codebook_vector10_vals, codebook_vector10_vals, + codebook_vector10_vals, +}; + +const uint16_t *const ff_aac_codebook_vector_idx[] = { + codebook_vector02_idx, codebook_vector02_idx, + codebook_vector02_idx, codebook_vector02_idx, + codebook_vector4_idx, codebook_vector4_idx, + codebook_vector6_idx, codebook_vector6_idx, + codebook_vector8_idx, codebook_vector8_idx, + codebook_vector10_idx, +}; + +/* @name swb_offsets + * Sample offset into the window indicating the beginning of a scalefactor + * window band + * + * scalefactor window band - term for scalefactor bands within a window, + * given in Table 4.110 to Table 4.128. + * + * scalefactor band - a set of spectral coefficients which are scaled by one + * scalefactor. In case of EIGHT_SHORT_SEQUENCE and grouping a scalefactor band + * may contain several scalefactor window bands of corresponding frequency. For + * all other window_sequences scalefactor bands and scalefactor window bands are + * identical. + * @{ + */ + +static const uint16_t swb_offset_1024_96[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 64, + 72, 80, 88, 96, 108, 120, 132, 144, + 156, 172, 188, 212, 240, 276, 320, 384, + 448, 512, 576, 640, 704, 768, 832, 896, + 960, 1024 +}; + +static const uint16_t swb_offset_128_96[] = { + 0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 128 +}; + +static const uint16_t swb_offset_1024_64[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 64, + 72, 80, 88, 100, 112, 124, 140, 156, + 172, 192, 216, 240, 268, 304, 344, 384, + 424, 464, 504, 544, 584, 624, 664, 704, + 744, 784, 824, 864, 904, 944, 984, 1024 +}; + +static const uint16_t swb_offset_1024_48[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 48, 56, 64, 72, 80, + 88, 96, 108, 120, 132, 144, 160, 176, + 196, 216, 240, 264, 292, 320, 352, 384, + 416, 448, 480, 512, 544, 576, 608, 640, + 672, 704, 736, 768, 800, 832, 864, 896, + 928, 1024 +}; + +static const uint16_t swb_offset_512_48[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60, + 68, 76, 84, 92, 100, 112, 124, 136, + 148, 164, 184, 208, 236, 268, 300, 332, + 364, 396, 428, 460, 512 +}; + +static const uint16_t swb_offset_480_48[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 64, + 72, 80, 88, 96, 108, 120, 132, 144, + 156, 172, 188, 212, 240, 272, 304, 336, + 368, 400, 432, 480 +}; + +static const uint16_t swb_offset_128_48[] = { + 0, 4, 8, 12, 16, 20, 28, 36, + 44, 56, 68, 80, 96, 112, 128 +}; + +static const uint16_t swb_offset_1024_32[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 48, 56, 64, 72, 80, + 88, 96, 108, 120, 132, 144, 160, 176, + 196, 216, 240, 264, 292, 320, 352, 384, + 416, 448, 480, 512, 544, 576, 608, 640, + 672, 704, 736, 768, 800, 832, 864, 896, + 928, 960, 992, 1024 +}; + +static const uint16_t swb_offset_512_32[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 64, + 72, 80, 88, 96, 108, 120, 132, 144, + 160, 176, 192, 212, 236, 260, 288, 320, + 352, 384, 416, 448, 480, 512 +}; + +static const uint16_t swb_offset_480_32[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60, + 64, 72, 80, 88, 96, 104, 112, 124, + 136, 148, 164, 180, 200, 224, 256, 288, + 320, 352, 384, 416, 448, 480 + }; + +static const uint16_t swb_offset_1024_24[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 52, 60, 68, 76, + 84, 92, 100, 108, 116, 124, 136, 148, + 160, 172, 188, 204, 220, 240, 260, 284, + 308, 336, 364, 396, 432, 468, 508, 552, + 600, 652, 704, 768, 832, 896, 960, 1024 +}; + +static const uint16_t swb_offset_512_24[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 52, 60, 68, 80, + 92, 104, 120, 140, 164, 192, 224, 256, + 288, 320, 352, 384, 416, 448, 480, 512, +}; + +static const uint16_t swb_offset_480_24[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 36, 40, 44, 52, 60, 68, 80, + 92, 104, 120, 140, 164, 192, 224, 256, + 288, 320, 352, 384, 416, 448, 480 +}; + +static const uint16_t swb_offset_128_24[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 36, 44, 52, 64, 76, 92, 108, 128 +}; + +static const uint16_t swb_offset_1024_16[] = { + 0, 8, 16, 24, 32, 40, 48, 56, + 64, 72, 80, 88, 100, 112, 124, 136, + 148, 160, 172, 184, 196, 212, 228, 244, + 260, 280, 300, 320, 344, 368, 396, 424, + 456, 492, 532, 572, 616, 664, 716, 772, + 832, 896, 960, 1024 +}; + +static const uint16_t swb_offset_128_16[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 32, 40, 48, 60, 72, 88, 108, 128 +}; + +static const uint16_t swb_offset_1024_8[] = { + 0, 12, 24, 36, 48, 60, 72, 84, + 96, 108, 120, 132, 144, 156, 172, 188, + 204, 220, 236, 252, 268, 288, 308, 328, + 348, 372, 396, 420, 448, 476, 508, 544, + 580, 620, 664, 712, 764, 820, 880, 944, + 1024 +}; + +static const uint16_t swb_offset_128_8[] = { + 0, 4, 8, 12, 16, 20, 24, 28, + 36, 44, 52, 60, 72, 88, 108, 128 +}; + +static const uint16_t swb_offset_960_96[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 48, 52, 56, 64, 72, 80, 88, 96, + 108, 120, 132, 144, 156, 172, 188, 212, 240, 276, + 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, + 960 +}; + +static const uint16_t swb_offset_960_64[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 48, 52, 56, 64, 72, 80, 88, 100, + 112, 124, 140, 156, 172, 192, 216, 240, 268, 304, + 344, 384, 424, 464, 504, 544, 584, 624, 664, 704, + 744, 784, 824, 864, 904, 944, 960 +}; + +static const uint16_t swb_offset_960_48[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 48, 56, 64, 72, 80, 88, 96, 108, 120, + 132, 144, 160, 176, 196, 216, 240, 264, 292, 320, + 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, + 672, 704, 736, 768, 800, 832, 864, 896, 928, 960 +}; + +static const uint16_t swb_offset_960_32[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 48, 56, 64, 72, 80, 88, 96, 108, 120, + 132, 144, 160, 176, 196, 216, 240, 264, 292, 320, + 352, 384, 416, 448, 480, 512, 544, 576, 608, 640, + 672, 704, 736, 768, 800, 832, 864, 896, 928, 960 +}; + +static const uint16_t swb_offset_960_24[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, + 40, 44, 52, 60, 68, 76, 84, 92, 100, 108, + 116, 124, 136, 148, 160, 172, 188, 204, 220, 240, + 260, 284, 308, 336, 364, 396, 432, 468, 508, 552, + 600, 652, 704, 768, 832, 896, 960 +}; + +static const uint16_t swb_offset_960_16[] = +{ + 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, + 80, 88, 100, 112, 124, 136, 148, 160, 172, 184, + 196, 212, 228, 244, 260, 280, 300, 320, 344, 368, + 396, 424, 456, 492, 532, 572, 616, 664, 716, 772, + 832, 896, 960 +}; + +static const uint16_t swb_offset_960_8[] = +{ + 0, 12, 24, 36, 48, 60, 72, 84, 96, 108, + 120, 132, 144, 156, 172, 188, 204, 220, 236, 252, + 268, 288, 308, 328, 348, 372, 396, 420, 448, 476, + 508, 544, 580, 620, 664, 712, 764, 820, 880, 944, + 960 +}; + + +static const uint16_t swb_offset_120_96[] = +{ + 0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 120 +}; + +static const uint16_t swb_offset_120_64[] = +{ + 0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 120 +}; + +static const uint16_t swb_offset_120_48[] = +{ + 0, 4, 8, 12, 16, 20, 28, 36, 44, 56, 68, 80, 96, 112, 120 +}; + +static const uint16_t swb_offset_120_24[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 64, 76, 92, 108, 120 +}; + +static const uint16_t swb_offset_120_16[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 60, 72, 88, 108, 120 +}; + +static const uint16_t swb_offset_120_8[] = +{ + 0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 60, 72, 88, 108, 120 +}; + +const uint16_t * const ff_swb_offset_1024[] = { + swb_offset_1024_96, swb_offset_1024_96, swb_offset_1024_64, + swb_offset_1024_48, swb_offset_1024_48, swb_offset_1024_32, + swb_offset_1024_24, swb_offset_1024_24, swb_offset_1024_16, + swb_offset_1024_16, swb_offset_1024_16, swb_offset_1024_8, + swb_offset_1024_8 +}; + +const uint16_t * const ff_swb_offset_960[] = { + swb_offset_960_96, swb_offset_960_96, swb_offset_960_64, + swb_offset_960_48, swb_offset_960_48, swb_offset_960_32, + swb_offset_960_24, swb_offset_960_24, swb_offset_960_16, + swb_offset_960_16, swb_offset_960_16, swb_offset_960_8, + swb_offset_960_8 +}; + +const uint16_t * const ff_swb_offset_512[] = { + NULL, NULL, NULL, + swb_offset_512_48, swb_offset_512_48, swb_offset_512_32, + swb_offset_512_24, swb_offset_512_24, NULL, + NULL, NULL, NULL, + NULL +}; + +const uint16_t * const ff_swb_offset_480[] = { + NULL, NULL, NULL, + swb_offset_480_48, swb_offset_480_48, swb_offset_480_32, + swb_offset_480_24, swb_offset_480_24, NULL, + NULL, NULL, NULL, + NULL +}; + +const uint16_t * const ff_swb_offset_128[] = { + /* The last entry on the following row is swb_offset_128_64 but is a + duplicate of swb_offset_128_96. */ + swb_offset_128_96, swb_offset_128_96, swb_offset_128_96, + swb_offset_128_48, swb_offset_128_48, swb_offset_128_48, + swb_offset_128_24, swb_offset_128_24, swb_offset_128_16, + swb_offset_128_16, swb_offset_128_16, swb_offset_128_8, + swb_offset_128_8 +}; + +const uint16_t * const ff_swb_offset_120[] = { + swb_offset_120_96, swb_offset_120_96, swb_offset_120_96, + swb_offset_120_48, swb_offset_120_48, swb_offset_120_48, + swb_offset_120_24, swb_offset_120_24, swb_offset_120_16, + swb_offset_120_16, swb_offset_120_16, swb_offset_120_8, + swb_offset_120_8 +}; + +// @} + +/* @name ff_tns_max_bands + * The maximum number of scalefactor bands on which TNS can operate for the long + * and short transforms respectively. The index to these tables is related to + * the sample rate of the audio. + * @{ + */ +const uint8_t ff_tns_max_bands_1024[] = { + 31, 31, 34, 40, 42, 51, 46, 46, 42, 42, 42, 39, 39 +}; + +const uint8_t ff_tns_max_bands_512[] = { + 0, 0, 0, 31, 32, 37, 31, 31, 0, 0, 0, 0, 0 +}; + +const uint8_t ff_tns_max_bands_480[] = { + 0, 0, 0, 31, 32, 37, 30, 30, 0, 0, 0, 0, 0 +}; + +const uint8_t ff_tns_max_bands_128[] = { + 9, 9, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14 +}; +// @} + +const DECLARE_ALIGNED(32, float, ff_aac_eld_window_512)[1920] = { + 0.00338834, 0.00567745, 0.00847677, 0.01172641, + 0.01532555, 0.01917664, 0.02318809, 0.02729259, + 0.03144503, 0.03560261, 0.03972499, 0.04379783, + 0.04783094, 0.05183357, 0.05581342, 0.05977723, + 0.06373173, 0.06768364, 0.07163937, 0.07559976, + 0.07956096, 0.08352024, 0.08747623, 0.09143035, + 0.09538618, 0.09934771, 0.10331917, 0.10730456, + 0.11130697, 0.11532867, 0.11937133, 0.12343922, + 0.12753911, 0.13167705, 0.13585812, 0.14008529, + 0.14435986, 0.14868291, 0.15305531, 0.15747594, + 0.16194193, 0.16645070, 0.17099991, 0.17558633, + 0.18020600, 0.18485548, 0.18953191, 0.19423322, + 0.19895800, 0.20370512, 0.20847374, 0.21326312, + 0.21807244, 0.22290083, 0.22774742, 0.23261210, + 0.23749542, 0.24239767, 0.24731889, 0.25225887, + 0.25721719, 0.26219330, 0.26718648, 0.27219630, + 0.27722262, 0.28226514, 0.28732336, 0.29239628, + 0.29748247, 0.30258055, 0.30768914, 0.31280508, + 0.31792385, 0.32304172, 0.32815579, 0.33326397, + 0.33836470, 0.34345661, 0.34853868, 0.35361188, + 0.35867865, 0.36374072, 0.36879900, 0.37385347, + 0.37890349, 0.38394836, 0.38898730, 0.39401912, + 0.39904236, 0.40405575, 0.40905820, 0.41404819, + 0.41902398, 0.42398423, 0.42892805, 0.43385441, + 0.43876210, 0.44365014, 0.44851786, 0.45336632, + 0.45819759, 0.46301302, 0.46781309, 0.47259722, + 0.47736435, 0.48211365, 0.48684450, 0.49155594, + 0.49624679, 0.50091636, 0.50556440, 0.51019132, + 0.51479771, 0.51938391, 0.52394998, 0.52849587, + 0.53302151, 0.53752680, 0.54201160, 0.54647575, + 0.55091916, 0.55534181, 0.55974376, 0.56412513, + 0.56848615, 0.57282710, 0.57714834, 0.58145030, + 0.58492489, 0.58918511, 0.59342326, 0.59763936, + 0.60183347, 0.60600561, 0.61015581, 0.61428412, + 0.61839056, 0.62247517, 0.62653799, 0.63057912, + 0.63459872, 0.63859697, 0.64257403, 0.64653001, + 0.65046495, 0.65437887, 0.65827181, 0.66214383, + 0.66599499, 0.66982535, 0.67363499, 0.67742394, + 0.68119219, 0.68493972, 0.68866653, 0.69237258, + 0.69605778, 0.69972207, 0.70336537, 0.70698758, + 0.71058862, 0.71416837, 0.71772674, 0.72126361, + 0.72477889, 0.72827246, 0.73174419, 0.73519392, + 0.73862141, 0.74202643, 0.74540874, 0.74876817, + 0.75210458, 0.75541785, 0.75870785, 0.76197437, + 0.76521709, 0.76843570, 0.77162988, 0.77479939, + 0.77794403, 0.78106359, 0.78415789, 0.78722670, + 0.79026979, 0.79328694, 0.79627791, 0.79924244, + 0.80218027, 0.80509112, 0.80797472, 0.81083081, + 0.81365915, 0.81645949, 0.81923160, 0.82197528, + 0.82469037, 0.82737673, 0.83003419, 0.83266262, + 0.83526186, 0.83783176, 0.84037217, 0.84288297, + 0.84536401, 0.84781517, 0.85023632, 0.85262739, + 0.85498836, 0.85731921, 0.85961993, 0.86189052, + 0.86413101, 0.86634140, 0.86852173, 0.87067211, + 0.87279275, 0.87488384, 0.87694559, 0.87897824, + 0.88098206, 0.88295729, 0.88490423, 0.88682332, + 0.88871519, 0.89058048, 0.89241983, 0.89423391, + 0.89602338, 0.89778893, 0.89953126, 0.90125142, + 0.90295086, 0.90463104, 0.90629341, 0.90793946, + 0.90957067, 0.91118856, 0.91279464, 0.91439073, + 0.91597898, 0.91756153, 0.91914049, 0.92071690, + 0.92229070, 0.92386182, 0.92542993, 0.92698946, + 0.92852960, 0.93003929, 0.93150727, 0.93291739, + 0.93424863, 0.93547974, 0.93658982, 0.93756587, + 0.93894072, 0.93922780, 0.93955477, 0.93991290, + 0.94029104, 0.94067794, 0.94106258, 0.94144084, + 0.94181549, 0.94218963, 0.94256628, 0.94294662, + 0.94332998, 0.94371562, 0.94410280, 0.94449122, + 0.94488106, 0.94527249, 0.94566568, 0.94606074, + 0.94645772, 0.94685665, 0.94725759, 0.94766054, + 0.94806547, 0.94847234, 0.94888115, 0.94929190, + 0.94970469, 0.95011960, 0.95053672, 0.95095604, + 0.95137751, 0.95180105, 0.95222658, 0.95265413, + 0.95308380, 0.95351571, 0.95394994, 0.95438653, + 0.95482538, 0.95526643, 0.95570958, 0.95615486, + 0.95660234, 0.95705214, 0.95750433, 0.95795892, + 0.95841582, 0.95887493, 0.95933616, 0.95979949, + 0.96026500, 0.96073277, 0.96120286, 0.96167526, + 0.96214986, 0.96262655, 0.96310522, 0.96358586, + 0.96406853, 0.96455330, 0.96504026, 0.96552936, + 0.96602051, 0.96651360, 0.96700850, 0.96750520, + 0.96800376, 0.96850424, 0.96900670, 0.96951112, + 0.97001738, 0.97052533, 0.97103488, 0.97154597, + 0.97205867, 0.97257304, 0.97308915, 0.97360694, + 0.97412631, 0.97464711, 0.97516923, 0.97569262, + 0.97621735, 0.97674350, 0.97727111, 0.97780016, + 0.97833051, 0.97886205, 0.97939463, 0.97992823, + 0.98046291, 0.98099875, 0.98153580, 0.98207405, + 0.98261337, 0.98315364, 0.98369474, 0.98423664, + 0.98477941, 0.98532311, 0.98586780, 0.98641348, + 0.98696003, 0.98750734, 0.98805530, 0.98860389, + 0.98915320, 0.98970328, 0.99025423, 0.99080602, + 0.99135855, 0.99191171, 0.99246541, 0.99301962, + 0.99357443, 0.99412992, 0.99468617, 0.99524320, + 0.99580092, 0.99635926, 0.99691814, 0.99747748, + 0.99803721, 0.99859725, 0.99915752, 0.99971793, + 1.00028215, 1.00084319, 1.00140472, 1.00196665, + 1.00252889, 1.00309139, 1.00365404, 1.00421679, + 1.00477954, 1.00534221, 1.00590474, 1.00646713, + 1.00702945, 1.00759179, 1.00815424, 1.00871678, + 1.00927930, 1.00984169, 1.01040384, 1.01096575, + 1.01152747, 1.01208910, 1.01265070, 1.01321226, + 1.01377365, 1.01433478, 1.01489551, 1.01545584, + 1.01601582, 1.01657553, 1.01713502, 1.01769427, + 1.01825316, 1.01881154, 1.01936929, 1.01992639, + 1.02048289, 1.02103888, 1.02159441, 1.02214945, + 1.02270387, 1.02325751, 1.02381025, 1.02436204, + 1.02491295, 1.02546304, 1.02601238, 1.02656092, + 1.02710853, 1.02765508, 1.02820041, 1.02874449, + 1.02928737, 1.02982913, 1.03036981, 1.03090937, + 1.03144768, 1.03198460, 1.03252000, 1.03305384, + 1.03358617, 1.03411707, 1.03464659, 1.03517470, + 1.03570128, 1.03622620, 1.03674934, 1.03727066, + 1.03779024, 1.03830815, 1.03882446, 1.03933914, + 1.03985206, 1.04036312, 1.04087217, 1.04137920, + 1.04188428, 1.04238748, 1.04288888, 1.04338845, + 1.04388610, 1.04438170, 1.04487515, 1.04536645, + 1.04585569, 1.04634297, 1.04682838, 1.04731192, + 1.04779350, 1.04827303, 1.04875042, 1.04922568, + 1.04969891, 1.05017022, 1.05063974, 1.05110746, + 1.05157332, 1.05203721, 1.05249907, 1.05295889, + 1.05341676, 1.05387277, 1.05432700, 1.05477948, + 1.05523018, 1.05567906, 1.05612608, 1.05657124, + 1.05701459, 1.05745616, 1.05789601, 1.05833426, + 1.05877109, 1.05920669, 1.05964125, 1.06007444, + 1.06050542, 1.06093335, 1.06135746, 1.06177909, + 1.06220164, 1.06262858, 1.06306309, 1.06350050, + 1.06392837, 1.06433391, 1.06470443, 1.06502996, + 1.06481076, 1.06469765, 1.06445004, 1.06408002, + 1.06361382, 1.06307719, 1.06249453, 1.06188365, + 1.06125612, 1.06062291, 1.05999418, 1.05937132, + 1.05874726, 1.05811486, 1.05746728, 1.05680000, + 1.05611070, 1.05539715, 1.05465735, 1.05389329, + 1.05311083, 1.05231578, 1.05151372, 1.05070811, + 1.04990044, 1.04909210, 1.04828434, 1.04747647, + 1.04666590, 1.04585003, 1.04502628, 1.04419009, + 1.04333499, 1.04245452, 1.04154244, 1.04059452, + 1.03960846, 1.03858207, 1.03751326, 1.03640189, + 1.03524976, 1.03405868, 1.03283047, 1.03156812, + 1.03027574, 1.02895743, 1.02761717, 1.02625804, + 1.02488222, 1.02349184, 1.02208892, 1.02067450, + 1.01924861, 1.01781123, 1.01636229, 1.01490045, + 1.01342315, 1.01192778, 1.01041175, 1.00887284, + 1.00730915, 1.00571882, 1.00409996, 1.00245032, + 1.00076734, 0.99904842, 0.99729101, 0.99549380, + 0.99365664, 0.99177946, 0.98986234, 0.98791024, + 0.98593294, 0.98394037, 0.98194226, 0.97994532, + 0.97795324, 0.97596955, 0.97399748, 0.97203326, + 0.97006624, 0.96808546, 0.96608018, 0.96404416, + 0.96197556, 0.95987276, 0.95773420, 0.95556018, + 0.95335291, 0.95111462, 0.94884764, 0.94655663, + 0.94424858, 0.94193055, 0.93960953, 0.93729154, + 0.93498157, 0.93268456, 0.93040503, 0.92813771, + 0.92586755, 0.92357910, 0.92125731, 0.91889642, + 0.91649998, 0.91407191, 0.91161623, 0.90913975, + 0.90665202, 0.90416271, 0.90168115, 0.89920934, + 0.89674189, 0.89427312, 0.89179743, 0.88931147, + 0.88681415, 0.88430445, 0.88178141, 0.87924528, + 0.87669753, 0.87413966, 0.87157318, 0.86899958, + 0.86642037, 0.86383703, 0.86125106, 0.85866393, + 0.85604236, 0.85344385, 0.85083093, 0.84820550, + 0.84556943, 0.84292458, 0.84027278, 0.83761586, + 0.83495565, 0.83229393, 0.82963243, 0.82697135, + 0.82430933, 0.82164496, 0.81897669, 0.81630017, + 0.81360822, 0.81089355, 0.80814924, 0.80537741, + 0.80258920, 0.79979611, 0.79700954, 0.79423813, + 0.79148780, 0.78876432, 0.78607290, 0.78340590, + 0.78074288, 0.77806279, 0.77534514, 0.77258187, + 0.76977737, 0.76693654, 0.76406441, 0.76116851, + 0.75825892, 0.75534582, 0.75243924, 0.74954634, + 0.74667135, 0.74381840, 0.74099145, 0.73819147, + 0.73541641, 0.73266408, 0.72993193, 0.72720913, + 0.72447661, 0.72171494, 0.71890515, 0.71603932, + 0.71312056, 0.71015250, 0.70713900, 0.70409084, + 0.70102565, 0.69796137, 0.69491556, 0.69189772, + 0.68890931, 0.68595141, 0.68302498, 0.68012852, + 0.67725801, 0.67440936, 0.67157841, 0.66876081, + 0.66595195, 0.66314722, 0.66034194, 0.65753027, + 0.65470525, 0.65185984, 0.64898709, 0.64608214, + 0.64314221, 0.64016460, 0.63714680, 0.63409034, + 0.63100082, 0.62788400, 0.62474577, 0.62159473, + 0.61844225, 0.61529977, 0.61217866, 0.60908811, + 0.60603510, 0.60302654, 0.60006916, 0.59716588, + 0.59431580, 0.59151787, 0.58877068, 0.58606495, + 0.58338353, 0.58070891, 0.57802356, 0.57530864, + 0.57254404, 0.56970958, 0.56678577, 0.56376860, + 0.56066951, 0.55750064, 0.55427451, 0.55101301, + 0.54774732, 0.54450907, 0.54132936, 0.53822744, + 0.53521072, 0.53228613, 0.52945979, 0.52671997, + 0.52403708, 0.52138072, 0.51872085, 0.51603570, + 0.51331170, 0.51053560, 0.50769466, 0.50478931, + 0.50183308, 0.49884001, 0.49582406, 0.49279905, + 0.48985748, 0.48679641, 0.48379429, 0.48085363, + 0.47796576, 0.47512151, 0.47231151, 0.46952402, + 0.46674486, 0.46395978, 0.46115496, 0.45832607, + 0.45547830, 0.45261727, 0.44974866, 0.44688011, + 0.44402125, 0.44118178, 0.43837094, 0.43558772, + 0.43282082, 0.43005847, 0.42728913, 0.42450572, + 0.42170567, 0.41888658, 0.41604633, 0.41318897, + 0.41032472, 0.40746405, 0.40461724, 0.40178943, + 0.39898066, 0.39619073, 0.39341940, 0.39066519, + 0.38792536, 0.38519713, 0.38247773, 0.37976476, + 0.37705620, 0.37435006, 0.37164438, 0.36893869, + 0.36623396, 0.36353124, 0.36083153, 0.35813533, + 0.35544262, 0.35275338, 0.35006755, 0.34738530, + 0.34470699, 0.34203296, 0.33936359, 0.33669922, + 0.33404027, 0.33138711, 0.32874013, 0.32609944, + 0.32346493, 0.32083645, 0.31821388, 0.31559703, + 0.31298573, 0.31037987, 0.30777941, 0.30518446, + 0.30259525, 0.30001202, 0.29743499, 0.29486428, + 0.29229989, 0.28974179, 0.28718997, 0.28464452, + 0.28210562, 0.27957346, 0.27704820, 0.27452992, + 0.27201854, 0.26951399, 0.26701622, 0.26452533, + 0.26204158, 0.25956526, 0.25709662, 0.25463583, + 0.25218294, 0.24973798, 0.24730100, 0.24487207, + 0.24245133, 0.24003893, 0.23763500, 0.23523959, + 0.23285262, 0.23047401, 0.22810369, 0.22574170, + 0.22338818, 0.22104329, 0.21870719, 0.21637986, + 0.21406117, 0.21175095, 0.20944904, 0.20715535, + 0.20486987, 0.20259261, 0.20032356, 0.19806259, + 0.19580944, 0.19356385, 0.19132556, 0.18909442, + 0.18687040, 0.18465350, 0.18244372, 0.18024164, + 0.17804841, 0.17586521, 0.17369322, 0.17153360, + 0.16938755, 0.16725622, 0.16514081, 0.16304247, + 0.16098974, 0.15896561, 0.15696026, 0.15497259, + 0.15300151, 0.15104590, 0.14910466, 0.14717666, + 0.14526081, 0.14335599, 0.14146111, 0.13957570, + 0.13769993, 0.13583399, 0.13397806, 0.13213229, + 0.13029682, 0.12847178, 0.12665729, 0.12485353, + 0.12306074, 0.12127916, 0.11950900, 0.11775043, + 0.11600347, 0.11426820, 0.11254464, 0.11083292, + 0.10913318, 0.10744559, 0.10577028, 0.10410733, + 0.10245672, 0.10081842, 0.09919240, 0.09757872, + 0.09597750, 0.09438884, 0.09281288, 0.09124964, + 0.08969907, 0.08816111, 0.08663570, 0.08512288, + 0.08362274, 0.08213540, 0.08066096, 0.07919944, + 0.07775076, 0.07631484, 0.07489161, 0.07348108, + 0.07208335, 0.07069851, 0.06932666, 0.06796781, + 0.06662187, 0.06528874, 0.06396833, 0.06266065, + 0.06136578, 0.06008380, 0.05881480, 0.05755876, + 0.05631557, 0.05508511, 0.05386728, 0.05266206, + 0.05146951, 0.05028971, 0.04912272, 0.04796855, + 0.04682709, 0.04569825, 0.04458194, 0.04347817, + 0.04238704, 0.04130868, 0.04024318, 0.03919056, + 0.03815071, 0.03712352, 0.03610890, 0.03510679, + 0.03411720, 0.03314013, 0.03217560, 0.03122343, + 0.03028332, 0.02935494, 0.02843799, 0.02753230, + 0.02663788, 0.02575472, 0.02488283, 0.02402232, + 0.02317341, 0.02233631, 0.02151124, 0.02069866, + 0.01989922, 0.01911359, 0.01834241, 0.01758563, + 0.01684248, 0.01611219, 0.01539397, 0.01468726, + 0.01399167, 0.01330687, 0.01263250, 0.01196871, + 0.01131609, 0.01067527, 0.01004684, 0.00943077, + 0.00882641, 0.00823307, 0.00765011, 0.00707735, + 0.00651513, 0.00596377, 0.00542364, 0.00489514, + 0.00437884, 0.00387530, 0.00338509, 0.00290795, + 0.00244282, 0.00198860, 0.00154417, 0.00110825, + 0.00067934, 0.00025589, -0.00016357, -0.00057897, + -0.00098865, -0.00139089, -0.00178397, -0.00216547, + -0.00253230, -0.00288133, -0.00320955, -0.00351626, + -0.00380315, -0.00407198, -0.00432457, -0.00456373, + -0.00479326, -0.00501699, -0.00523871, -0.00546066, + -0.00568360, -0.00590821, -0.00613508, -0.00636311, + -0.00658944, -0.00681117, -0.00702540, -0.00722982, + -0.00742268, -0.00760226, -0.00776687, -0.00791580, + -0.00804933, -0.00816774, -0.00827139, -0.00836122, + -0.00843882, -0.00850583, -0.00856383, -0.00861430, + -0.00865853, -0.00869781, -0.00873344, -0.00876633, + -0.00879707, -0.00882622, -0.00885433, -0.00888132, + -0.00890652, -0.00892925, -0.00894881, -0.00896446, + -0.00897541, -0.00898088, -0.00898010, -0.00897234, + -0.00895696, -0.00893330, -0.00890076, -0.00885914, + -0.00880875, -0.00874987, -0.00868282, -0.00860825, + -0.00852716, -0.00844055, -0.00834941, -0.00825485, + -0.00815807, -0.00806025, -0.00796253, -0.00786519, + -0.00776767, -0.00766937, -0.00756971, -0.00746790, + -0.00736305, -0.00725422, -0.00714055, -0.00702161, + -0.00689746, -0.00676816, -0.00663381, -0.00649489, + -0.00635230, -0.00620694, -0.00605969, -0.00591116, + -0.00576167, -0.00561155, -0.00546110, -0.00531037, + -0.00515917, -0.00500732, -0.00485462, -0.00470075, + -0.00454530, -0.00438786, -0.00422805, -0.00406594, + -0.00390204, -0.00373686, -0.00357091, -0.00340448, + -0.00323770, -0.00307066, -0.00290344, -0.00273610, + -0.00256867, -0.00240117, -0.00223365, -0.00206614, + -0.00189866, -0.00173123, -0.00156390, -0.00139674, + -0.00122989, -0.00106351, -0.00089772, -0.00073267, + -0.00056849, -0.00040530, -0.00024324, -0.00008241, + 0.00008214, 0.00024102, 0.00039922, 0.00055660, + 0.00071299, 0.00086826, 0.00102224, 0.00117480, + 0.00132579, 0.00147507, 0.00162252, 0.00176804, + 0.00191161, 0.00205319, 0.00219277, 0.00233029, + 0.00246567, 0.00259886, 0.00272975, 0.00285832, + 0.00298453, 0.00310839, 0.00322990, 0.00334886, + 0.00346494, 0.00357778, 0.00368706, 0.00379273, + 0.00389501, 0.00399411, 0.00409020, 0.00418350, + 0.00427419, 0.00436249, 0.00444858, 0.00453250, + 0.00461411, 0.00469328, 0.00476988, 0.00484356, + 0.00491375, 0.00497987, 0.00504139, 0.00509806, + 0.00514990, 0.00519693, 0.00523920, 0.00527700, + 0.00531083, 0.00534122, 0.00536864, 0.00539357, + 0.00541649, 0.00543785, 0.00545809, 0.00547713, + 0.00549441, 0.00550936, 0.00552146, 0.00553017, + 0.00553494, 0.00553524, 0.00553058, 0.00552065, + 0.00550536, 0.00548459, 0.00545828, 0.00542662, + 0.00539007, 0.00534910, 0.00530415, 0.00525568, + 0.00520417, 0.00515009, 0.00509387, 0.00503595, + 0.00497674, 0.00491665, 0.00485605, 0.00479503, + 0.00473336, 0.00467082, 0.00460721, 0.00454216, + 0.00447517, 0.00440575, 0.00433344, 0.00425768, + 0.00417786, 0.00409336, 0.00400363, 0.00390837, + 0.00380759, 0.00370130, 0.00358952, 0.00347268, + 0.00335157, 0.00322699, 0.00309975, 0.00297088, + 0.00284164, 0.00271328, 0.00258700, 0.00246328, + 0.00234195, 0.00222281, 0.00210562, 0.00198958, + 0.00187331, 0.00175546, 0.00163474, 0.00151020, + 0.00138130, 0.00124750, 0.00110831, 0.00096411, + 0.00081611, 0.00066554, 0.00051363, 0.00036134, + 0.00020940, 0.00005853, -0.00009058, -0.00023783, + -0.00038368, -0.00052861, -0.00067310, -0.00081757, + -0.00096237, -0.00110786, -0.00125442, -0.00140210, + -0.00155065, -0.00169984, -0.00184940, -0.00199910, + -0.00214872, -0.00229798, -0.00244664, -0.00259462, + -0.00274205, -0.00288912, -0.00303596, -0.00318259, + -0.00332890, -0.00347480, -0.00362024, -0.00376519, + -0.00390962, -0.00405345, -0.00419658, -0.00433902, + -0.00448085, -0.00462219, -0.00476309, -0.00490357, + -0.00504361, -0.00518321, -0.00532243, -0.00546132, + -0.00559988, -0.00573811, -0.00587602, -0.00601363, + -0.00615094, -0.00628795, -0.00642466, -0.00656111, + -0.00669737, -0.00683352, -0.00696963, -0.00710578, + -0.00724208, -0.00737862, -0.00751554, -0.00765295, + -0.00779098, -0.00792976, -0.00806941, -0.00821006, + -0.00835183, -0.00849485, -0.00863926, -0.00878522, + -0.00893293, -0.00908260, -0.00923444, -0.00938864, + -0.00954537, -0.00970482, -0.00986715, -0.01003173, + -0.01019711, -0.01036164, -0.01052357, -0.01068184, + -0.01083622, -0.01098652, -0.01113252, -0.01127409, + -0.01141114, -0.01154358, -0.01167135, -0.01179439, + -0.01191268, -0.01202619, -0.01213493, -0.01223891, + -0.01233817, -0.01243275, -0.01252272, -0.01260815, + -0.01268915, -0.01276583, -0.01283832, -0.01290685, + -0.01297171, -0.01303320, -0.01309168, -0.01314722, + -0.01319969, -0.01324889, -0.01329466, -0.01333693, + -0.01337577, -0.01341125, -0.01344345, -0.01347243, + -0.01349823, -0.01352089, -0.01354045, -0.01355700, + -0.01357068, -0.01358164, -0.01359003, -0.01359587, + -0.01359901, -0.01359931, -0.01359661, -0.01359087, + -0.01358219, -0.01357065, -0.01355637, -0.01353935, + -0.01351949, -0.01349670, -0.01347088, -0.01344214, + -0.01341078, -0.01337715, -0.01334158, -0.01330442, + -0.01326601, -0.01322671, -0.01318689, -0.01314692, + -0.01310123, -0.01306470, -0.01302556, -0.01298381, + -0.01293948, -0.01289255, -0.01284305, -0.01279095, + -0.01273625, -0.01267893, -0.01261897, -0.01255632, + -0.01249096, -0.01242283, -0.01235190, -0.01227827, + -0.01220213, -0.01212366, -0.01204304, -0.01196032, + -0.01187543, -0.01178829, -0.01169884, -0.01160718, + -0.01151352, -0.01141809, -0.01132111, -0.01122272, + -0.01112304, -0.01102217, -0.01092022, -0.01081730, + -0.01071355, -0.01060912, -0.01050411, -0.01039854, + -0.01029227, -0.01018521, -0.01007727, -0.00996859, + -0.00985959, -0.00975063, -0.00964208, -0.00953420, + -0.00942723, -0.00932135, -0.00921677, -0.00911364, + -0.00901208, -0.00891220, -0.00881412, -0.00871792, + -0.00862369, -0.00853153, -0.00844149, -0.00835360, + -0.00826785, -0.00818422, -0.00810267, -0.00802312, + -0.00794547, -0.00786959, -0.00779533, -0.00772165, + -0.00764673, -0.00756886, -0.00748649, -0.00739905, + -0.00730681, -0.00721006, -0.00710910, -0.00700419, + -0.00689559, -0.00678354, -0.00666829, -0.00655007, + -0.00642916, -0.00630579, -0.00618022, -0.00605267, + -0.00592333, -0.00579240, -0.00566006, -0.00552651, + -0.00539194, -0.00525653, -0.00512047, -0.00498390, + -0.00484693, -0.00470969, -0.00457228, -0.00443482, + -0.00429746, -0.00416034, -0.00402359, -0.00388738, + -0.00375185, -0.00361718, -0.00348350, -0.00335100, + -0.00321991, -0.00309043, -0.00296276, -0.00283698, + -0.00271307, -0.00259098, -0.00247066, -0.00235210, + -0.00223531, -0.00212030, -0.00200709, -0.00189576, + -0.00178647, -0.00167936, -0.00157457, -0.00147216, + -0.00137205, -0.00127418, -0.00117849, -0.00108498, + -0.00099375, -0.00090486, -0.00081840, -0.00073444, + -0.00065309, -0.00057445, -0.00049860, -0.00042551, + -0.00035503, -0.00028700, -0.00022125, -0.00015761, + -0.00009588, -0.00003583, 0.00002272, 0.00007975, + 0.00013501, 0.00018828, 0.00023933, 0.00028784, + 0.00033342, 0.00037572, 0.00041438, 0.00044939, + 0.00048103, 0.00050958, 0.00053533, 0.00055869, + 0.00058015, 0.00060022, 0.00061935, 0.00063781, + 0.00065568, 0.00067303, 0.00068991, 0.00070619, + 0.00072155, 0.00073567, 0.00074826, 0.00075912, + 0.00076811, 0.00077509, 0.00077997, 0.00078275, + 0.00078351, 0.00078237, 0.00077943, 0.00077484, + 0.00076884, 0.00076160, 0.00075335, 0.00074423, + 0.00073442, 0.00072404, 0.00071323, 0.00070209, + 0.00069068, 0.00067906, 0.00066728, 0.00065534, + 0.00064321, 0.00063086, 0.00061824, 0.00060534, + 0.00059211, 0.00057855, 0.00056462, 0.00055033, + 0.00053566, 0.00052063, 0.00050522, 0.00048949, + 0.00047349, 0.00045728, 0.00044092, 0.00042447, + 0.00040803, 0.00039166, 0.00037544, 0.00035943, + 0.00034371, 0.00032833, 0.00031333, 0.00029874, + 0.00028452, 0.00027067, 0.00025715, 0.00024395, + 0.00023104, 0.00021842, 0.00020606, 0.00019398, + 0.00018218, 0.00017069, 0.00015953, 0.00014871, + 0.00013827, 0.00012823, 0.00011861, 0.00010942, + 0.00010067, 0.00009236, 0.00008448, 0.00007703, + 0.00006999, 0.00006337, 0.00005714, 0.00005129, + 0.00004583, 0.00004072, 0.00003597, 0.00003157, + 0.00002752, 0.00002380, 0.00002042, 0.00001736, + 0.00001461, 0.00001215, 0.00000998, 0.00000807, + 0.00000641, 0.00000499, 0.00000378, 0.00000278, + 0.00000196, 0.00000132, 0.00000082, 0.00000046, + 0.00000020, 0.00000005, -0.00000003, -0.00000006, + -0.00000004, -0.00000001, 0.00000001, 0.00000001, + 0.00000001, 0.00000001, -0.00000001, -0.00000004, + -0.00000005, -0.00000003, 0.00000005, 0.00000020, + 0.00000043, 0.00000077, 0.00000123, 0.00000183, + 0.00000257, 0.00000348, 0.00000455, 0.00000581, + 0.00000727, 0.00000893, 0.00001080, 0.00001290, + 0.00001522, 0.00001778, 0.00002057, 0.00002362, + 0.00002691, 0.00003044, 0.00003422, 0.00003824, + 0.00004250, 0.00004701, 0.00005176, 0.00005676, + 0.00006200, 0.00006749, 0.00007322, 0.00007920, + 0.00008541, 0.00009186, 0.00009854, 0.00010543, + 0.00011251, 0.00011975, 0.00012714, 0.00013465, + 0.00014227, 0.00014997, 0.00015775, 0.00016558, + 0.00017348, 0.00018144, 0.00018947, 0.00019756, + 0.00020573, 0.00021399, 0.00022233, 0.00023076, + 0.00023924, 0.00024773, 0.00025621, 0.00026462, + 0.00027293, 0.00028108, 0.00028904, 0.00029675, + 0.00030419, 0.00031132, 0.00031810, 0.00032453, + 0.00033061, 0.00033632, 0.00034169, 0.00034672, + 0.00035142, 0.00035580, 0.00035988, 0.00036369, + 0.00036723, 0.00037053, 0.00037361, 0.00037647, + 0.00037909, 0.00038145, 0.00038352, 0.00038527, + 0.00038663, 0.00038757, 0.00038801, 0.00038790, + 0.00038717, 0.00038572, 0.00038350, 0.00038044, + 0.00037651, 0.00037170, 0.00036597, 0.00035936, + 0.00035191, 0.00034370, 0.00033480, 0.00032531, + 0.00031537, 0.00030512, 0.00029470, 0.00028417, + 0.00027354, 0.00026279, 0.00025191, 0.00024081, + 0.00022933, 0.00021731, 0.00020458, 0.00019101, + 0.00017654, 0.00016106, 0.00014452, 0.00012694, + 0.00010848, 0.00008929, 0.00006953, 0.00004935, + 0.00002884, 0.00000813, -0.00001268, -0.00003357, + -0.00005457, -0.00007574, -0.00009714, -0.00011882, + -0.00014082, -0.00016318, -0.00018595, -0.00020912, + -0.00023265, -0.00025650, -0.00028060, -0.00030492, + -0.00032941, -0.00035400, -0.00037865, -0.00040333, + -0.00042804, -0.00045279, -0.00047759, -0.00050243, + -0.00052728, -0.00055209, -0.00057685, -0.00060153, + -0.00062611, -0.00065056, -0.00067485, -0.00069895, + -0.00072287, -0.00074660, -0.00077013, -0.00079345, + -0.00081653, -0.00083936, -0.00086192, -0.00088421, + -0.00090619, -0.00092786, -0.00094919, -0.00097017, + -0.00099077, -0.00101098, -0.00103077, -0.00105012, + -0.00106904, -0.00108750, -0.00110549, -0.00112301, + -0.00114005, -0.00115660, -0.00117265, -0.00118821, + -0.00120325, -0.00121779, -0.00123180, -0.00124528, + -0.00125822, -0.00127061, -0.00128243, -0.00129368, + -0.00130435, -0.00131445, -0.00132395, -0.00133285, + -0.00134113, -0.00134878, -0.00135577, -0.00136215, + -0.00136797, -0.00137333, -0.00137834, -0.00138305, + -0.00138748, -0.00139163, -0.00139551, -0.00139913, + -0.00140249, -0.00140559, -0.00140844, -0.00141102, + -0.00141334, -0.00141538, -0.00141714, -0.00141861, + -0.00141978, -0.00142064, -0.00142117, -0.00142138, + -0.00142125, -0.00142077, -0.00141992, -0.00141870, + -0.00141710, -0.00141510, -0.00141268, -0.00140986, + -0.00140663, -0.00140301, -0.00139900, -0.00139460, + -0.00138981, -0.00138464, -0.00137908, -0.00137313, + -0.00136680, -0.00136010, -0.00135301, -0.00134555, + -0.00133772, -0.00132952, -0.00132095, -0.00131201, + -0.00130272, -0.00129307, -0.00128309, -0.00127277, + -0.00126211, -0.00125113, -0.00123981, -0.00122817, + -0.00121622, -0.00120397, -0.00119141, -0.00117859, + -0.00116552, -0.00115223, -0.00113877, -0.00112517, + -0.00111144, -0.00109764, -0.00108377, -0.00106989, +}; + +/* Q30 representation of ff_aac_eld_window_512 table */ +const DECLARE_ALIGNED(32, int, ff_aac_eld_window_512_fixed)[1920] = { + 0x003783ba, 0x005d04f4, 0x008ae226, 0x00c02021, + 0x00fb1804, 0x013a30a8, 0x017be9e6, 0x01bf296c, + 0x02033204, 0x0247502c, 0x028adab0, 0x02cd9568, + 0x030fa980, 0x03513dc0, 0x03927274, 0x03d363e0, + 0x04142e40, 0x0454edc0, 0x0495bd48, 0x04d6a060, + 0x051786d8, 0x05586548, 0x059935e8, 0x05d9feb0, + 0x061acea0, 0x065bb680, 0x069cc800, 0x06de13f0, + 0x071fa748, 0x07618b80, 0x07a3c7a8, 0x07e66da0, + 0x082999d0, 0x086d6590, 0x08b1e640, 0x08f72850, + 0x093d3120, 0x09840550, 0x09cba880, 0x0a1415f0, + 0x0a5d41b0, 0x0aa720d0, 0x0af1a9a0, 0x0b3cce70, + 0x0b887ec0, 0x0bd4ac10, 0x0c214a70, 0x0c6e5130, + 0x0cbbba50, 0x0d098130, 0x0d57a240, 0x0da61a60, + 0x0df4e620, 0x0e4401d0, 0x0e9369f0, 0x0ee31de0, + 0x0f332000, 0x0f837180, 0x0fd412a0, 0x10250260, + 0x10763f20, 0x10c7c660, 0x11199560, 0x116baa00, + 0x11be0400, 0x1210a1c0, 0x12638180, 0x12b69ee0, + 0x1309f3e0, 0x135d7ac0, 0x13b12dc0, 0x1404ffa0, + 0x1458dd40, 0x14acb720, 0x15008120, 0x15543260, + 0x15a7c460, 0x15fb3160, 0x164e7520, 0x16a193c0, + 0x16f49740, 0x17478720, 0x179a6720, 0x17ed3720, + 0x183ff460, 0x18929c20, 0x18e52b00, 0x19379c00, + 0x1989e900, 0x19dc0ca0, 0x1a2e0280, 0x1a7fc400, + 0x1ad14a00, 0x1b228ec0, 0x1b738ea0, 0x1bc44540, + 0x1c14ada0, 0x1c64c380, 0x1cb48440, 0x1d03f420, + 0x1d531c00, 0x1da20160, 0x1df0a660, 0x1e3f0860, + 0x1e8d2340, 0x1edaf340, 0x1f2875e0, 0x1f75a700, + 0x1fc281e0, 0x200f0380, 0x205b2ac0, 0x20a6f980, + 0x20f27200, 0x213d9600, 0x21886580, 0x21d2e040, + 0x221d0640, 0x2266d6c0, 0x22b05180, 0x22f97580, + 0x23424280, 0x238ab880, 0x23d2d780, 0x241aa040, + 0x246213c0, 0x24a93300, 0x24efff80, 0x25367b40, + 0x256f68c0, 0x25b53580, 0x25faa580, 0x263fb940, + 0x26847080, 0x26c8cbc0, 0x270ccb00, 0x27506e40, + 0x2793b600, 0x27d6a200, 0x281932c0, 0x285b6880, + 0x289d4400, 0x28dec5c0, 0x291feec0, 0x2960bf80, + 0x29a137c0, 0x29e15800, 0x2a212000, 0x2a609080, + 0x2a9fa980, 0x2ade6b40, 0x2b1cd600, 0x2b5aea00, + 0x2b98a740, 0x2bd60d80, 0x2c131cc0, 0x2c4fd500, + 0x2c8c3600, 0x2cc83f00, 0x2d03f040, 0x2d3f48c0, + 0x2d7a48c0, 0x2db4ef40, 0x2def3c40, 0x2e292ec0, + 0x2e62c700, 0x2e9c0400, 0x2ed4e580, 0x2f0d6ac0, + 0x2f4592c0, 0x2f7d5c80, 0x2fb4c6c0, 0x2febd140, + 0x30227b40, 0x3058c400, 0x308eab40, 0x30c43040, + 0x30f95100, 0x312e0d00, 0x31626240, 0x31965040, + 0x31c9d5c0, 0x31fcf240, 0x322fa480, 0x3261ec00, + 0x3293c7c0, 0x32c53680, 0x32f63780, 0x3326c9c0, + 0x3356ec00, 0x33869d00, 0x33b5db80, 0x33e4a700, + 0x3412fdc0, 0x3440df40, 0x346e4a80, 0x349b3e40, + 0x34c7ba00, 0x34f3bd80, 0x351f47c0, 0x354a5840, + 0x3574ee40, 0x359f0900, 0x35c8a840, 0x35f1cb80, + 0x361a71c0, 0x36429a80, 0x366a4580, 0x36917280, + 0x36b82100, 0x36de5180, 0x37040340, 0x372936c0, + 0x374dec40, 0x37722340, 0x3795dc40, 0x37b91780, + 0x37dbd600, 0x37fe18c0, 0x381fe080, 0x38412e00, + 0x38620280, 0x38825f40, 0x38a24540, 0x38c1b680, + 0x38e0b5c0, 0x38ff4540, 0x391d6800, 0x393b20c0, + 0x39587280, 0x39755fc0, 0x3991eb80, 0x39ae1a80, + 0x39c9f280, 0x39e57980, 0x3a00b600, 0x3a1bae00, + 0x3a366800, 0x3a50e9c0, 0x3a6b3a40, 0x3a8560c0, + 0x3a9f6640, 0x3ab95400, 0x3ad332c0, 0x3aed0680, + 0x3b06cf80, 0x3b208d40, 0x3b3a3e80, 0x3b53cb80, + 0x3b6d0780, 0x3b85c380, 0x3b9dd0c0, 0x3bb4eb40, + 0x3bcabac0, 0x3bdee680, 0x3bf11680, 0x3c011440, + 0x3c179ac0, 0x3c1c4f00, 0x3c21aa40, 0x3c278880, + 0x3c2dba80, 0x3c341140, 0x3c3a5e80, 0x3c409100, + 0x3c46b480, 0x3c4cd5c0, 0x3c530180, 0x3c593cc0, + 0x3c5f84c0, 0x3c65d640, 0x3c6c2e40, 0x3c728b40, + 0x3c78ee80, 0x3c7f5840, 0x3c85c940, 0x3c8c4240, + 0x3c92c380, 0x3c994cc0, 0x3c9fde40, 0x3ca67880, + 0x3cad1ac0, 0x3cb3c540, 0x3cba7800, 0x3cc132c0, + 0x3cc7f640, 0x3ccec280, 0x3cd59800, 0x3cdc76c0, + 0x3ce35e80, 0x3cea4f00, 0x3cf147c0, 0x3cf84900, + 0x3cff5340, 0x3d0666c0, 0x3d0d8400, 0x3d14ab40, + 0x3d1bdc00, 0x3d2315c0, 0x3d2a5880, 0x3d31a440, + 0x3d38f900, 0x3d405780, 0x3d47c040, 0x3d4f3300, + 0x3d56af40, 0x3d5e3500, 0x3d65c380, 0x3d6d5ac0, + 0x3d74fb40, 0x3d7ca540, 0x3d845900, 0x3d8c1680, + 0x3d93dd00, 0x3d9bac80, 0x3da38400, 0x3dab6400, + 0x3db34c80, 0x3dbb3dc0, 0x3dc33840, 0x3dcb3bc0, + 0x3dd347c0, 0x3ddb5bc0, 0x3de37780, 0x3deb9b00, + 0x3df3c600, 0x3dfbf940, 0x3e0434c0, 0x3e0c7840, + 0x3e14c3c0, 0x3e1d1640, 0x3e256f80, 0x3e2dcf40, + 0x3e363580, 0x3e3ea300, 0x3e4717c0, 0x3e4f9380, + 0x3e581600, 0x3e609e40, 0x3e692c40, 0x3e71bf80, + 0x3e7a5840, 0x3e82f740, 0x3e8b9c40, 0x3e944700, + 0x3e9cf780, 0x3ea5ad00, 0x3eae66c0, 0x3eb72500, + 0x3ebfe780, 0x3ec8af00, 0x3ed17b80, 0x3eda4d00, + 0x3ee32340, 0x3eebfd40, 0x3ef4dac0, 0x3efdbbc0, + 0x3f06a040, 0x3f0f88c0, 0x3f187540, 0x3f216600, + 0x3f2a5a80, 0x3f335200, 0x3f3c4c40, 0x3f454940, + 0x3f4e4940, 0x3f574c80, 0x3f605340, 0x3f695dc0, + 0x3f726b40, 0x3f7b7b40, 0x3f848dc0, 0x3f8da240, + 0x3f96b940, 0x3f9fd300, 0x3fa8f040, 0x3fb21080, + 0x3fbb33c0, 0x3fc459c0, 0x3fcd81c0, 0x3fd6abc0, + 0x3fdfd780, 0x3fe90480, 0x3ff23280, 0x3ffb6100, + 0x40049f80, 0x400dd080, 0x40170400, 0x40203880, + 0x40296f00, 0x4032a600, 0x403bde00, 0x40451680, + 0x404e4f00, 0x40578700, 0x4060be80, 0x4069f500, + 0x40732b80, 0x407c6280, 0x40859980, 0x408ed100, + 0x40980800, 0x40a13f00, 0x40aa7500, 0x40b3a980, + 0x40bcdd80, 0x40c61180, 0x40cf4500, 0x40d87800, + 0x40e1ab00, 0x40eadc80, 0x40f40c80, 0x40fd3a80, + 0x41066700, 0x410f9300, 0x4118bd80, 0x4121e700, + 0x412b0f80, 0x41343580, 0x413d5880, 0x41467980, + 0x414f9780, 0x4158b380, 0x4161cd80, 0x416ae580, + 0x4173fb00, 0x417d0d00, 0x41861b80, 0x418f2600, + 0x41982c80, 0x41a12f80, 0x41aa3000, 0x41b32c80, + 0x41bc2580, 0x41c51a00, 0x41ce0900, 0x41d6f300, + 0x41dfd800, 0x41e8b880, 0x41f19400, 0x41fa6b80, + 0x42033d00, 0x420c0900, 0x4214cf00, 0x421d8e00, + 0x42264680, 0x422ef980, 0x4237a680, 0x42404d80, + 0x4248ee00, 0x42518780, 0x425a1a00, 0x4262a480, + 0x426b2800, 0x4273a400, 0x427c1980, 0x42848880, + 0x428cef80, 0x42954f00, 0x429da680, 0x42a5f500, + 0x42ae3b80, 0x42b67a00, 0x42beb100, 0x42c6e080, + 0x42cf0780, 0x42d72680, 0x42df3c00, 0x42e74880, + 0x42ef4c80, 0x42f74880, 0x42ff3c80, 0x43072880, + 0x430f0c80, 0x4316e800, 0x431eba00, 0x43268380, + 0x432e4480, 0x4335fd00, 0x433dae80, 0x43455800, + 0x434cfa00, 0x43549400, 0x435c2500, 0x4363ad80, + 0x436b2e00, 0x4372a700, 0x437a1800, 0x43818200, + 0x4388e400, 0x43903f00, 0x43979200, 0x439edd00, + 0x43a62080, 0x43ad5c80, 0x43b49180, 0x43bbbf80, + 0x43c2e800, 0x43ca0b00, 0x43d12980, 0x43d84280, + 0x43df5200, 0x43e65500, 0x43ed4800, 0x43f43080, + 0x43fb1c80, 0x44021b80, 0x44093a00, 0x44106480, + 0x44176700, 0x441e0c00, 0x44241e00, 0x44297380, + 0x4425dc00, 0x44240180, 0x441ff300, 0x4419e300, + 0x44123f80, 0x44097500, 0x43ffe900, 0x43f5e700, + 0x43eb9f00, 0x43e13f00, 0x43d6f200, 0x43ccbd80, + 0x43c28400, 0x43b82780, 0x43ad8b00, 0x43a29c80, + 0x43975180, 0x438ba080, 0x437f8180, 0x4372fd00, + 0x43662b00, 0x43592480, 0x434c0000, 0x433ecd00, + 0x43319180, 0x43245300, 0x43171700, 0x4309da80, + 0x42fc9300, 0x42ef3500, 0x42e1b600, 0x42d40280, + 0x42c60000, 0x42b79300, 0x42a8a180, 0x42991a00, + 0x4288f200, 0x42782100, 0x42669e00, 0x42546880, + 0x42418800, 0x422e0480, 0x4219e500, 0x42053680, + 0x41f00980, 0x41da7080, 0x41c47b00, 0x41ae3600, + 0x4197ab80, 0x4180e400, 0x4169e780, 0x4152bb00, + 0x413b5e80, 0x4123d180, 0x410c1480, 0x40f42100, + 0x40dbed00, 0x40c36c80, 0x40aa9600, 0x40915f80, + 0x4077c100, 0x405db280, 0x40432c80, 0x40282580, + 0x400c9280, 0x3ff068c0, 0x3fd39dc0, 0x3fb62bc0, + 0x3f981200, 0x3f795080, 0x3f59e780, 0x3f39ebc0, + 0x3f198680, 0x3ef8e100, 0x3ed82440, 0x3eb76c80, + 0x3e96c940, 0x3e764900, 0x3e55f980, 0x3e35cb00, + 0x3e1590c0, 0x3df51cc0, 0x3dd44200, 0x3db2e640, + 0x3d910200, 0x3d6e8e40, 0x3d4b8480, 0x3d27e600, + 0x3d03bc00, 0x3cdf0fc0, 0x3cb9eb80, 0x3c946240, + 0x3c6e9180, 0x3c489700, 0x3c229000, 0x3bfc95c0, + 0x3bd6bd00, 0x3bb11a80, 0x3b8bc180, 0x3b669bc0, + 0x3b416a00, 0x3b1beb80, 0x3af5e140, 0x3acf3300, + 0x3aa7ef80, 0x3a802780, 0x3a57eb80, 0x3a2f5880, + 0x3a069640, 0x39ddcd40, 0x39b524c0, 0x398ca540, + 0x39643800, 0x393bc540, 0x39133580, 0x38ea7ac0, + 0x38c19040, 0x389871c0, 0x386f1b40, 0x38458e00, + 0x381bd000, 0x37f1e780, 0x37c7db00, 0x379db080, + 0x37736e80, 0x37491b00, 0x371ebcc0, 0x36f45980, + 0x36c96600, 0x369ed300, 0x36740380, 0x3648ffc0, + 0x361dcf40, 0x35f27a00, 0x35c70780, 0x359b7f80, + 0x356fe9c0, 0x35444dc0, 0x3518b280, 0x34ed1940, + 0x34c17c00, 0x3495d4c0, 0x346a1d40, 0x343e4300, + 0x34122840, 0x33e5ae00, 0x33b8b780, 0x338b4dc0, + 0x335d9f00, 0x332fdc00, 0x33023440, 0x32d4cc40, + 0x32a7bc80, 0x327b1d40, 0x324f04c0, 0x32235280, + 0x31f7b100, 0x31cbc7c0, 0x319f4140, 0x3171fb40, + 0x31440840, 0x31157d00, 0x30e66e80, 0x30b6fc40, + 0x30875080, 0x30579600, 0x3027f700, 0x2ff89140, + 0x2fc976c0, 0x2f9ab880, 0x2f6c6780, 0x2f3e8780, + 0x2f111000, 0x2ee3f800, 0x2eb73480, 0x2e8a9840, + 0x2e5dd340, 0x2e3093c0, 0x2e028ac0, 0x2dd39680, + 0x2da3c480, 0x2d732380, 0x2d41c400, 0x2d0fd300, + 0x2cdd9ac0, 0x2cab6640, 0x2c797f00, 0x2c480d40, + 0x2c171700, 0x2be6a0c0, 0x2bb6ae80, 0x2b8739c0, + 0x2b583200, 0x2b298600, 0x2afb2400, 0x2accfa40, + 0x2a9ef500, 0x2a710100, 0x2a430ac0, 0x2a14f9c0, + 0x29e6b0c0, 0x29b81240, 0x29890140, 0x29596900, + 0x29293e00, 0x28f87500, 0x28c70340, 0x2894efc0, + 0x28625140, 0x282f4040, 0x27fbd5c0, 0x27c83540, + 0x27948ec0, 0x27611240, 0x272def80, 0x26fb4cc0, + 0x26c94780, 0x2697fcc0, 0x26678880, 0x2637f740, + 0x26094540, 0x25db6dc0, 0x25ae6b40, 0x25821680, + 0x255627c0, 0x252a55c0, 0x24fe5680, 0x24d1db40, + 0x24a48fc0, 0x24761f40, 0x244637c0, 0x2414c900, + 0x23e20240, 0x23ae1740, 0x23793bc0, 0x2343cc00, + 0x230e4ac0, 0x22d93c80, 0x22a52400, 0x22725180, + 0x2240e480, 0x2210f9c0, 0x21e2ab40, 0x21b5c7c0, + 0x2189d2c0, 0x215e4d40, 0x2132b900, 0x2106ba80, + 0x20da1940, 0x20ac9d80, 0x207e11c0, 0x204e77c0, + 0x201e0880, 0x1fecfea0, 0x1fbb94e0, 0x1f8a0500, + 0x1f59d340, 0x1f27ac20, 0x1ef67c60, 0x1ec64e40, + 0x1e96fdc0, 0x1e686400, 0x1e3a5a00, 0x1e0cae80, + 0x1ddf25e0, 0x1db18460, 0x1d839020, 0x1d5536e0, + 0x1d268e80, 0x1cf7ae60, 0x1cc8aea0, 0x1c99af00, + 0x1c6ad820, 0x1c3c5280, 0x1c0e4500, 0x1be0ab60, + 0x1bb35620, 0x1b861400, 0x1b58b480, 0x1b2b1a00, + 0x1afd39c0, 0x1acf09a0, 0x1aa080c0, 0x1a71b020, + 0x1a42c2a0, 0x1a13e420, 0x19e53fc0, 0x19b6eb00, + 0x1988e620, 0x195b3060, 0x192dc8a0, 0x1900a8a0, + 0x18d3c4e0, 0x18a711e0, 0x187a83e0, 0x184e10e0, + 0x1821b060, 0x17f55a00, 0x17c90580, 0x179cb100, + 0x177060a0, 0x17441880, 0x1717dd20, 0x16ebb080, + 0x16bf9260, 0x169382e0, 0x166781c0, 0x163b8f80, + 0x160fade0, 0x15e3de40, 0x15b82220, 0x158c7ae0, + 0x1560ea80, 0x15357240, 0x150a1400, 0x14ded020, + 0x14b3a640, 0x148895a0, 0x145d9dc0, 0x1432bde0, + 0x1407f540, 0x13dd4380, 0x13b2a860, 0x13882460, + 0x135db880, 0x133365a0, 0x13092cc0, 0x12df0e60, + 0x12b50aa0, 0x128b2120, 0x12615200, 0x12379da0, + 0x120e04c0, 0x11e48820, 0x11bb2860, 0x1191e600, + 0x1168c080, 0x113fb7a0, 0x1116cb40, 0x10edfba0, + 0x10c54a00, 0x109cb7a0, 0x10744560, 0x104bf420, + 0x1023c3e0, 0x0ffbb500, 0x0fd3c790, 0x0fabfbe0, + 0x0f845290, 0x0f5ccc40, 0x0f356970, 0x0f0e2a60, + 0x0ee70eb0, 0x0ec01610, 0x0e994040, 0x0e728d50, + 0x0e4bfdf0, 0x0e2592c0, 0x0dff4c70, 0x0dd92af0, + 0x0db32da0, 0x0d8d53e0, 0x0d679cf0, 0x0d420880, + 0x0d1c9680, 0x0cf74700, 0x0cd219f0, 0x0cad0eb0, + 0x0c882450, 0x0c6359a0, 0x0c3ead90, 0x0c1a1f80, + 0x0bf5af40, 0x0bd15cf0, 0x0bad2870, 0x0b891440, + 0x0b652530, 0x0b416020, 0x0b1dca30, 0x0afa6810, + 0x0ad73ee0, 0x0ab45370, 0x0a91aac0, 0x0a6f49b0, + 0x0a4da7f0, 0x0a2c7e20, 0x0a0ba310, 0x09eb1220, + 0x09cac6e0, 0x09aabc70, 0x098aee40, 0x096b57a0, + 0x094bf400, 0x092cbea0, 0x090db2e0, 0x08eecef0, + 0x08d01360, 0x08b18110, 0x089318b0, 0x0874db00, + 0x0856c880, 0x0838e1b0, 0x081b2730, 0x07fd99a8, + 0x07e03a28, 0x07c309a8, 0x07a60910, 0x07893918, + 0x076c99d0, 0x07502b90, 0x0733ee70, 0x0717e2f8, + 0x06fc09b8, 0x06e06378, 0x06c4f0b8, 0x06a9b1c8, + 0x068ea6a0, 0x0673cf18, 0x06592b18, 0x063ebad0, + 0x06247ed0, 0x060a7780, 0x05f0a570, 0x05d708b8, + 0x05bda128, 0x05a46e80, 0x058b7078, 0x0572a740, + 0x055a1330, 0x0541b4d8, 0x05298c98, 0x05119a88, + 0x04f9de50, 0x04e257a0, 0x04cb0630, 0x04b3ea00, + 0x049d0378, 0x04865308, 0x046fd918, 0x045995a8, + 0x04438860, 0x042db0d0, 0x04180ea0, 0x0402a1d0, + 0x03ed6abc, 0x03d869b8, 0x03c39f28, 0x03af0af0, + 0x039aaca0, 0x038683b4, 0x03728fc0, 0x035ed0b0, + 0x034b46c4, 0x0337f254, 0x0324d3a0, 0x0311eab0, + 0x02ff370c, 0x02ecb85c, 0x02da6e34, 0x02c858a8, + 0x02b67820, 0x02a4cd28, 0x02935820, 0x02821920, + 0x02710fac, 0x02603b54, 0x024f9bb4, 0x023f308c, + 0x022ef9e8, 0x021ef7c8, 0x020f2a40, 0x01ff908e, + 0x01f02974, 0x01e0f38a, 0x01d1ed94, 0x01c316d6, + 0x01b46f5e, 0x01a5f720, 0x0197ae28, 0x018994ea, + 0x017bac54, 0x016df546, 0x016070ae, 0x01532078, + 0x01460760, 0x01392834, 0x012c85a4, 0x01201f7a, + 0x0113f27c, 0x0107fb6c, 0x00fc36fd, 0x00f0a2d5, + 0x00e53d51, 0x00da050f, 0x00cef88c, 0x00c41869, + 0x00b9671f, 0x00aee754, 0x00a49b80, 0x009a8384, + 0x00909ca6, 0x0086e400, 0x007d56e3, 0x0073f48e, + 0x006abe70, 0x0061b5de, 0x0058dc65, 0x005033b4, + 0x0047be30, 0x003f7e30, 0x00377619, 0x002fa4d4, + 0x002805ee, 0x002094cb, 0x00194cb8, 0x00122856, + 0x000b215c, 0x00043148, 0xfffd51f0, 0xfff683a0, + 0xffefcd4d, 0xffe9362f, 0xffe2c57d, 0xffdc855c, + 0xffd682c4, 0xffd0cad4, 0xffcb6a2c, 0xffc663bc, + 0xffc1b06f, 0xffbd48e1, 0xffb92570, 0xffb53a54, + 0xffb1779c, 0xffadcd38, 0xffaa2b42, 0xffa68855, + 0xffa2e141, 0xff9f332c, 0xff9b7b9c, 0xff97bf2e, + 0xff9409e2, 0xff9067e2, 0xff8ce556, 0xff898bf0, + 0xff866306, 0xff8371d0, 0xff80bf63, 0xff7e4eba, + 0xff7c1eaa, 0xff7a2e04, 0xff787b47, 0xff770280, + 0xff75bd06, 0xff74a3f7, 0xff73b0b2, 0xff72dd02, + 0xff72237e, 0xff717ebe, 0xff70e94c, 0xff705f59, + 0xff6fde6a, 0xff6f6426, 0xff6eee40, 0xff6e7d0b, + 0xff6e1359, 0xff6db403, 0xff6d61f8, 0xff6d2054, + 0xff6cf267, 0xff6cdb76, 0xff6cdebb, 0xff6cff47, + 0xff6d3fc9, 0xff6da306, 0xff6e2b82, 0xff6eda13, + 0xff6fad6d, 0xff70a463, 0xff71bd9d, 0xff72f662, + 0xff744a80, 0xff75b5c4, 0xff773409, 0xff78c0a6, + 0xff7a5693, 0xff7bf0dc, 0xff7d8abb, 0xff7f2301, + 0xff80bc08, 0xff825854, 0xff83fa56, 0xff85a55c, + 0xff875d22, 0xff892598, 0xff8b025d, 0xff8cf53c, + 0xff8efdf4, 0xff911c48, 0xff934fc9, 0xff959675, + 0xff97ec86, 0xff9a4e35, 0xff9cb7d2, 0xff9f26cc, + 0xffa199ce, 0xffa40f74, 0xffa6867c, 0xffa8feb2, + 0xffab78e0, 0xffadf5c7, 0xffb07640, 0xffb2fba0, + 0xffb587a2, 0xffb81bfb, 0xffbaba46, 0xffbd6236, + 0xffc011a8, 0xffc2c679, 0xffc57e84, 0xffc83894, + 0xffcaf41a, 0xffcdb0b8, 0xffd06e17, 0xffd32bf7, + 0xffd5ea38, 0xffd8a8c3, 0xffdb6764, 0xffde25fb, + 0xffe0e471, 0xffe3a2b2, 0xffe66087, 0xffe91da6, + 0xffebd978, 0xffee9351, 0xfff14ab0, 0xfff3fef6, + 0xfff6af94, 0xfff95c0c, 0xfffc03c7, 0xfffea659, + 0x00015885, 0x0003f2e9, 0x00068a73, 0x00091e8d, + 0x000bae7f, 0x000e39bf, 0x0010bf96, 0x00133f78, + 0x0015b8c4, 0x00182ae4, 0x001a9558, 0x001cf7b2, + 0x001f51e0, 0x0021a3b4, 0x0023ed25, 0x00262df2, + 0x002865c5, 0x002a9469, 0x002cb967, 0x002ed4aa, + 0x0030e607, 0x0032ed88, 0x0034eb2f, 0x0036de23, + 0x0038c503, 0x003a9e4c, 0x003c68a6, 0x003e23dd, + 0x003fd0db, 0x00417083, 0x0043038b, 0x00448adf, + 0x00460740, 0x0047799c, 0x0048e2b2, 0x004a42af, + 0x004b98fb, 0x004ce50b, 0x004e2654, 0x004f5b5d, + 0x005081c3, 0x00519716, 0x00529920, 0x005386d0, + 0x0054603f, 0x00552581, 0x0055d6cc, 0x00567558, + 0x0057033c, 0x005782b4, 0x0057f5b6, 0x00585e46, + 0x0058be68, 0x005917ff, 0x00596ce4, 0x0059bcc0, + 0x005a053a, 0x005a43ee, 0x005a76ae, 0x005a9b37, + 0x005aaf38, 0x005ab07a, 0x005a9cef, 0x005a7349, + 0x005a3328, 0x0059dc0a, 0x00596db0, 0x0058e8e5, + 0x00584f98, 0x0057a3c0, 0x0056e738, 0x00561bec, + 0x005543df, 0x0054610b, 0x0053753e, 0x0052824e, + 0x005189f6, 0x00508dec, 0x004f8fc0, 0x004e8fd0, + 0x004d8d26, 0x004c86d7, 0x004b7c0a, 0x004a6b33, + 0x00495239, 0x00482f0e, 0x0046ffc4, 0x0045c201, + 0x00447337, 0x004310cc, 0x00419871, 0x004008e4, + 0x003e6231, 0x003ca460, 0x003acf8a, 0x0038e57a, + 0x0036e981, 0x0034defa, 0x0032c94b, 0x0030acc6, + 0x002e8eb4, 0x002c7452, 0x002a62aa, 0x00285bbf, + 0x00265eda, 0x00246b24, 0x00227f9c, 0x002098e7, + 0x001eb13b, 0x001cc2ef, 0x001ac899, 0x0018be3d, + 0x0016a198, 0x00147065, 0x00122897, 0x000fcbc5, + 0x000d5f03, 0x000ae77a, 0x00086a52, 0x0005eb92, + 0x00036e4a, 0x0000f57e, 0xfffe8414, 0xfffc1a78, + 0xfff9b6bb, 0xfff756d9, 0xfff4f8d0, 0xfff29add, + 0xfff03b87, 0xffedd94c, 0xffeb7295, 0xffe9072b, + 0xffe6981a, 0xffe4265b, 0xffe1b30e, 0xffdf3f2b, + 0xffdccb9e, 0xffda5993, 0xffd7ea0c, 0xffd57d60, + 0xffd31302, 0xffd0aa27, 0xffce4243, 0xffcbdb40, + 0xffc97595, 0xffc711a2, 0xffc4af9d, 0xffc24fa6, + 0xffbff1de, 0xffbd9699, 0xffbb3e44, 0xffb8e8d5, + 0xffb695f4, 0xffb44522, 0xffb1f627, 0xffafa8f0, + 0xffad5d91, 0xffab140a, 0xffa8cc1c, 0xffa68590, + 0xffa44066, 0xffa1fca0, 0xff9fba30, 0xff9d7902, + 0xff9b3916, 0xff98fa6d, 0xff96bd06, 0xff9480b6, + 0xff924532, 0xff900a24, 0xff8dcf41, 0xff8b9433, + 0xff895884, 0xff871bd3, 0xff84dd8a, 0xff829d34, + 0xff805a43, 0xff7e142d, 0xff7bca71, 0xff797c83, + 0xff7729e3, 0xff74d204, 0xff727451, 0xff70101e, + 0xff6da493, 0xff6b30d1, 0xff68b3f4, 0xff662d31, + 0xff639bd1, 0xff60ff09, 0xff5e562c, 0xff5ba3e0, + 0xff58ee39, 0xff563c22, 0xff5394f3, 0xff50fd1e, + 0xff4e7599, 0xff4bff32, 0xff499ad4, 0xff47490a, + 0xff450a36, 0xff42deb7, 0xff40c6cf, 0xff3ec2be, + 0xff3cd299, 0xff3af681, 0xff392e6a, 0xff377a4a, + 0xff35d9f7, 0xff344d44, 0xff32d3e8, 0xff316d96, + 0xff3019d9, 0xff2ed83a, 0xff2da82f, 0xff2c88bf, + 0xff2b78b4, 0xff2a76cc, 0xff298184, 0xff289890, + 0xff27bc7d, 0xff26ee21, 0xff262e28, 0xff257cdc, + 0xff24d9f4, 0xff244524, 0xff23be15, 0xff234488, + 0xff22d852, 0xff227947, 0xff22273d, 0xff21e1d2, + 0xff21a871, 0xff217a79, 0xff215748, 0xff213eca, + 0xff21319e, 0xff21305c, 0xff213baf, 0xff2153c2, + 0xff21782b, 0xff21a892, 0xff21e477, 0xff222bda, + 0xff227f26, 0xff22debd, 0xff234b09, 0xff23c394, + 0xff24471d, 0xff24d42b, 0xff25695c, 0xff260538, + 0xff26a652, 0xff274b28, 0xff27f22d, 0xff2899d2, + 0xff295975, 0xff29f2ad, 0xff2a96d7, 0xff2b45f4, + 0xff2bffe3, 0xff2cc4ba, 0xff2d9458, 0xff2e6ede, + 0xff2f544c, 0xff3044b7, 0xff314034, 0xff3246fa, + 0xff33591e, 0xff3476e0, 0xff35a060, 0xff36d534, + 0xff38148f, 0xff395daf, 0xff3aafd4, 0xff3c0ac8, + 0xff3d6ed6, 0xff3edc54, 0xff405382, 0xff41d3f5, + 0xff435ccc, 0xff44ed0f, 0xff4683d3, 0xff482080, + 0xff49c297, 0xff4b69ab, 0xff4d1547, 0xff4ec4f5, + 0xff50781d, 0xff522e20, 0xff53e692, 0xff55a15d, + 0xff575f17, 0xff592022, 0xff5ae4de, 0xff5cacb4, + 0xff5e75e2, 0xff603ee5, 0xff62062f, 0xff63caab, + 0xff658b55, 0xff67476d, 0xff68fe11, 0xff6aaea0, + 0xff6c5899, 0xff6dfb86, 0xff6f96e7, 0xff712a65, + 0xff72b59f, 0xff74382b, 0xff75b1d3, 0xff772276, + 0xff788a20, 0xff79e8e5, 0xff7b3ef0, 0xff7c8c98, + 0xff7dd249, 0xff7f108c, 0xff804804, 0xff817d0e, + 0xff82b74a, 0xff83fde6, 0xff855762, 0xff86c622, + 0xff884904, 0xff89ded1, 0xff8b8646, 0xff8d3e4c, + 0xff8f05cc, 0xff90dbc6, 0xff92bf2a, 0xff94af04, + 0xff96aa26, 0xff98af9a, 0xff9abe48, 0xff9cd543, + 0xff9ef3c1, 0xffa118ea, 0xffa343fd, 0xffa57423, + 0xffa7a890, 0xffa9e084, 0xffac1b31, 0xffae5802, + 0xffb09680, 0xffb2d621, 0xffb51678, 0xffb75704, + 0xffb99726, 0xffbbd645, 0xffbe13d7, 0xffc04f26, + 0xffc2879a, 0xffc4bc72, 0xffc6ed24, 0xffc918e3, + 0xffcb3eb8, 0xffcd5dcc, 0xffcf7549, 0xffd184d8, + 0xffd38c8f, 0xffd58ca4, 0xffd7854d, 0xffd97694, + 0xffdb606e, 0xffdd42d1, 0xffdf1da8, 0xffe0f09b, + 0xffe2bb00, 0xffe47c41, 0xffe633c6, 0xffe7e150, + 0xffe98534, 0xffeb1fb4, 0xffecb10e, 0xffee3944, + 0xffefb7e9, 0xfff12cbe, 0xfff29762, 0xfff3f789, + 0xfff54cbe, 0xfff69695, 0xfff7d4b8, 0xfff90748, + 0xfffa2ee5, 0xfffb4c3c, 0xfffc6003, 0xfffd6af0, + 0xfffe6dda, 0xffff69b8, 0x00005f4b, 0x00014e7f, + 0x00023646, 0x000315b4, 0x0003ebd3, 0x0004b74a, + 0x00057677, 0x000627e2, 0x0006ca09, 0x00075ce1, + 0x0007e196, 0x00085955, 0x0008c556, 0x00092751, + 0x00098153, 0x0009d581, 0x000a25be, 0x000a732b, + 0x000abe1f, 0x000b06e4, 0x000b4db1, 0x000b91fa, + 0x000bd266, 0x000c0da0, 0x000c426e, 0x000c6ffb, + 0x000c95b0, 0x000cb2f7, 0x000cc76e, 0x000cd317, + 0x000cd647, 0x000cd17f, 0x000cc52b, 0x000cb1ea, + 0x000c98c0, 0x000c7a62, 0x000c57c7, 0x000c3187, + 0x000c0862, 0x000bdcd8, 0x000baf81, 0x000b80c7, + 0x000b50ec, 0x000b202f, 0x000aeec6, 0x000abcb2, + 0x000a89d2, 0x000a5605, 0x000a2116, 0x0009eafb, + 0x0009b37d, 0x00097a9d, 0x00094030, 0x00090440, + 0x0008c6b9, 0x000887ae, 0x0008470c, 0x00080512, + 0x0007c1f6, 0x00077df9, 0x0007395a, 0x0006f45b, + 0x0006af67, 0x00066abe, 0x000626b6, 0x0005e38f, + 0x0005a1a0, 0x0005611e, 0x00052234, 0x0004e502, + 0x0004a95d, 0x00046f46, 0x00043691, 0x0003ff33, + 0x0003c90d, 0x0003941f, 0x00036047, 0x00032d9c, + 0x0002fc1e, 0x0002cbed, 0x00029d1e, 0x00026fbc, + 0x000243f2, 0x000219d6, 0x0001f17d, 0x0001caf1, + 0x0001a63e, 0x00018363, 0x00016256, 0x00014316, + 0x0001258f, 0x000109cb, 0x0000efaa, 0x0000d720, + 0x0000c03a, 0x0000aacb, 0x000096de, 0x0000846a, + 0x0000736d, 0x000063d3, 0x000055a6, 0x000048d0, + 0x00003d47, 0x000032f6, 0x000029dc, 0x000021d9, + 0x00001ae3, 0x000014ee, 0x00000fdb, 0x00000ba9, + 0x00000839, 0x00000589, 0x00000370, 0x000001ee, + 0x000000d7, 0x00000036, 0xffffffe0, 0xffffffc0, + 0xffffffd5, 0xfffffff5, 0x0000000b, 0x0000000b, + 0x0000000b, 0x0000000b, 0xfffffff5, 0xffffffd5, + 0xffffffca, 0xffffffe0, 0x00000036, 0x000000d7, + 0x000001ce, 0x0000033b, 0x00000529, 0x000007ad, + 0x00000ac8, 0x00000e99, 0x00001316, 0x0000185e, + 0x00001e7e, 0x00002575, 0x00002d4c, 0x0000361b, + 0x00003fd6, 0x00004a93, 0x00005647, 0x00006312, + 0x000070de, 0x00007fad, 0x00008f87, 0x0000a064, + 0x0000b242, 0x0000c52d, 0x0000d919, 0x0000ee12, + 0x0001040c, 0x00011b13, 0x0001331b, 0x00014c30, + 0x0001663c, 0x0001814a, 0x00019d4f, 0x0001ba35, + 0x0001d7e7, 0x0001f645, 0x00021544, 0x000234c3, + 0x000254b9, 0x00027505, 0x000295a7, 0x0002b67e, + 0x0002d7a1, 0x0002f904, 0x00031ab2, 0x00033ca0, + 0x00035ee5, 0x0003818a, 0x0003a485, 0x0003c7e1, + 0x0003eb72, 0x00040f0e, 0x0004329f, 0x000455e6, + 0x000478c0, 0x00049aef, 0x0004bc52, 0x0004dca9, + 0x0004fbde, 0x000519c5, 0x00053635, 0x0005512d, + 0x00056aae, 0x000582a1, 0x00059927, 0x0005ae40, + 0x0005c1f6, 0x0005d455, 0x0005e572, 0x0005f56d, + 0x00060446, 0x0006121e, 0x00061f09, 0x00062b08, + 0x00063605, 0x00063feb, 0x00064899, 0x00064ff0, + 0x000655a5, 0x00065996, 0x00065b6f, 0x00065af8, + 0x000657e9, 0x000651d4, 0x00064884, 0x00063bae, + 0x00062b33, 0x00061706, 0x0005fefd, 0x0005e344, + 0x0005c404, 0x0005a195, 0x00057c41, 0x00055473, + 0x00052ac2, 0x0004ffc4, 0x0004d410, 0x0004a7e5, + 0x00047b4f, 0x00044e39, 0x00042096, 0x0003f208, + 0x0003c1e1, 0x00038f77, 0x00035a12, 0x00032127, + 0x0002e476, 0x0002a389, 0x00025e29, 0x0002146d, + 0x0001c700, 0x00017682, 0x000123a1, 0x0000cefd, + 0x000078f7, 0x0000221a, 0xffffcad1, 0xffff7332, + 0xffff1b1e, 0xfffec253, 0xfffe6891, 0xfffe0da2, + 0xfffdb15c, 0xfffd5393, 0xfffcf412, 0xfffc92e3, + 0xfffc3032, 0xfffbcc29, 0xfffb6714, 0xfffb0113, + 0xfffa9a5b, 0xfffa3337, 0xfff9cbd4, 0xfff96450, + 0xfff8fcac, 0xfff894dc, 0xfff82cd8, 0xfff7c4a8, + 0xfff75c6d, 0xfff6f45e, 0xfff68c84, 0xfff62500, + 0xfff5bde8, 0xfff5575a, 0xfff4f179, 0xfff48c64, + 0xfff42810, 0xfff3c488, 0xfff361d7, 0xfff30008, + 0xfff29f3a, 0xfff23f78, 0xfff1e0d8, 0xfff1835b, + 0xfff1272a, 0xfff0cc46, 0xfff072cf, 0xfff01ad0, + 0xffefc469, 0xffef6fa4, 0xffef1ca3, 0xffeecb7a, + 0xffee7c1f, 0xffee2eb2, 0xffede33d, 0xffed99c1, + 0xffed5249, 0xffed0cde, 0xffecc98d, 0xffec8849, + 0xffec4934, 0xffec0c38, 0xffebd175, 0xffeb98eb, + 0xffeb62a4, 0xffeb2ead, 0xffeafd19, 0xffeacdea, + 0xffeaa129, 0xffea76cc, 0xffea4ef4, 0xffea299f, + 0xffea06e5, 0xffe9e6ce, 0xffe9c97d, 0xffe9aebb, + 0xffe99651, 0xffe97fd6, 0xffe96ad3, 0xffe95711, + 0xffe9447d, 0xffe93315, 0xffe922ce, 0xffe913a0, + 0xffe90588, 0xffe8f887, 0xffe8ec93, 0xffe8e1c1, + 0xffe8d806, 0xffe8cf77, 0xffe8c816, 0xffe8c1eb, + 0xffe8bd03, 0xffe8b967, 0xffe8b72e, 0xffe8b64d, + 0xffe8b6d8, 0xffe8b8dc, 0xffe8bc6c, 0xffe8c18a, + 0xffe8c840, 0xffe8d0a4, 0xffe8daca, 0xffe8e69e, + 0xffe8f42a, 0xffe9035a, 0xffe9142b, 0xffe926a0, + 0xffe93ab7, 0xffe95066, 0xffe967b8, 0xffe980ad, + 0xffe99b3a, 0xffe9b754, 0xffe9d511, 0xffe9f45b, + 0xffea1532, 0xffea3797, 0xffea5b89, 0xffea8108, + 0xffeaa7ff, 0xffead079, 0xffeafa55, 0xffeb259e, + 0xffeb5254, 0xffeb8061, 0xffebafdc, 0xffebe0ae, + 0xffec12ce, 0xffec462f, 0xffec7add, 0xffecb0a3, + 0xffece774, 0xffed1f32, 0xffed57a7, 0xffed90b2, + 0xffedca48, 0xffee042a, 0xffee3e57, 0xffee788e, +}; + +const DECLARE_ALIGNED(32, float, ff_aac_eld_window_480)[1800] = { + 0.00101191, 0.00440397, 0.00718669, 0.01072130, + 0.01459757, 0.01875954, 0.02308987, 0.02751541, + 0.03198130, 0.03643738, 0.04085290, 0.04522835, + 0.04957620, 0.05390454, 0.05821503, 0.06251214, + 0.06680463, 0.07109582, 0.07538014, 0.07965207, + 0.08390857, 0.08815177, 0.09238785, 0.09662163, + 0.10085860, 0.10510892, 0.10938110, 0.11367819, + 0.11800355, 0.12236410, 0.12676834, 0.13122384, + 0.13573476, 0.14030106, 0.14492340, 0.14960315, + 0.15433828, 0.15912396, 0.16395663, 0.16883310, + 0.17374837, 0.17869679, 0.18367394, 0.18867661, + 0.19370368, 0.19875413, 0.20382641, 0.20892055, + 0.21403775, 0.21917761, 0.22433899, 0.22952250, + 0.23472991, 0.23996189, 0.24521859, 0.25049930, + 0.25580312, 0.26112942, 0.26647748, 0.27184703, + 0.27723785, 0.28264967, 0.28808086, 0.29352832, + 0.29898979, 0.30446379, 0.30994292, 0.31541664, + 0.32087942, 0.32632772, 0.33176291, 0.33718641, + 0.34259612, 0.34799346, 0.35338857, 0.35878843, + 0.36419504, 0.36960630, 0.37501567, 0.38042067, + 0.38582069, 0.39121276, 0.39659312, 0.40195993, + 0.40731155, 0.41264382, 0.41795277, 0.42323670, + 0.42849480, 0.43372753, 0.43893452, 0.44411398, + 0.44927117, 0.45441882, 0.45956191, 0.46470167, + 0.46983016, 0.47493636, 0.48001827, 0.48507480, + 0.49010240, 0.49509781, 0.50005986, 0.50499037, + 0.50989790, 0.51478708, 0.51965805, 0.52450975, + 0.52933955, 0.53414668, 0.53893113, 0.54369178, + 0.54842731, 0.55313757, 0.55782259, 0.56248253, + 0.56711762, 0.57172819, 0.57631468, 0.58087761, + 0.58719976, 0.59173064, 0.59623644, 0.60071719, + 0.60517294, 0.60960372, 0.61400958, 0.61839056, + 0.62274670, 0.62707805, 0.63138475, 0.63566700, + 0.63992500, 0.64415895, 0.64836893, 0.65255499, + 0.65671715, 0.66085548, 0.66497005, 0.66906094, + 0.67312824, 0.67717199, 0.68119219, 0.68518882, + 0.68916187, 0.69311129, 0.69703698, 0.70093884, + 0.70481679, 0.70867071, 0.71250047, 0.71630596, + 0.72008705, 0.72384360, 0.72757549, 0.73128256, + 0.73496463, 0.73862141, 0.74225263, 0.74585799, + 0.74943730, 0.75299039, 0.75651711, 0.76001729, + 0.76349062, 0.76693670, 0.77035516, 0.77374564, + 0.77710790, 0.78044169, 0.78374678, 0.78702291, + 0.79026979, 0.79348715, 0.79667471, 0.79983215, + 0.80295914, 0.80605536, 0.80912047, 0.81215417, + 0.81515616, 0.81812616, 0.82106389, 0.82396915, + 0.82684176, 0.82968154, 0.83248830, 0.83526186, + 0.83800204, 0.84070866, 0.84338156, 0.84602058, + 0.84862556, 0.85119636, 0.85373292, 0.85623523, + 0.85870326, 0.86113701, 0.86353649, 0.86590173, + 0.86823275, 0.87052968, 0.87279275, 0.87502220, + 0.87721829, 0.87938130, 0.88151157, 0.88360940, + 0.88567517, 0.88770954, 0.88971328, 0.89168716, + 0.89363199, 0.89554856, 0.89743771, 0.89930025, + 0.90113740, 0.90295086, 0.90474240, 0.90651380, + 0.90826684, 0.91000335, 0.91172515, 0.91343416, + 0.91513276, 0.91682357, 0.91850924, 0.92019170, + 0.92187129, 0.92354778, 0.92522116, 0.92688597, + 0.92852960, 0.93013861, 0.93169897, 0.93319114, + 0.93458502, 0.93587626, 0.93694276, 0.93825562, + 0.93882222, 0.93910780, 0.93944183, 0.93981497, + 0.94021434, 0.94062629, 0.94103714, 0.94144084, + 0.94184042, 0.94223966, 0.94264206, 0.94304859, + 0.94345831, 0.94387033, 0.94428390, 0.94469895, + 0.94511572, 0.94553441, 0.94595520, 0.94637816, + 0.94680335, 0.94723080, 0.94766054, 0.94809253, + 0.94852674, 0.94896314, 0.94940178, 0.94984276, + 0.95028618, 0.95073213, 0.95118056, 0.95163139, + 0.95208451, 0.95253992, 0.95299770, 0.95345799, + 0.95392092, 0.95438653, 0.95485472, 0.95532539, + 0.95579847, 0.95627397, 0.95675201, 0.95723273, + 0.95771618, 0.95820232, 0.95869103, 0.95918218, + 0.95967573, 0.96017172, 0.96067026, 0.96117144, + 0.96167526, 0.96218157, 0.96269026, 0.96320119, + 0.96371437, 0.96422988, 0.96474782, 0.96526824, + 0.96579106, 0.96631614, 0.96684334, 0.96737257, + 0.96790390, 0.96843740, 0.96897315, 0.96951112, + 0.97005119, 0.97059318, 0.97113697, 0.97168253, + 0.97222994, 0.97277928, 0.97333058, 0.97388375, + 0.97443863, 0.97499505, 0.97555292, 0.97611230, + 0.97667326, 0.97723589, 0.97780016, 0.97836591, + 0.97893300, 0.97950127, 0.98007071, 0.98064139, + 0.98121342, 0.98178684, 0.98236156, 0.98293743, + 0.98351428, 0.98409205, 0.98467078, 0.98525056, + 0.98583146, 0.98641348, 0.98699650, 0.98758037, + 0.98816497, 0.98875030, 0.98933647, 0.98992356, + 0.99051163, 0.99110062, 0.99169038, 0.99228079, + 0.99287177, 0.99346341, 0.99405581, 0.99464907, + 0.99524320, 0.99583812, 0.99643375, 0.99702997, + 0.99762671, 0.99822386, 0.99882134, 0.99941903, + 1.00058131, 1.00118006, 1.00177930, 1.00237893, + 1.00297887, 1.00357902, 1.00417927, 1.00477954, + 1.00537972, 1.00597973, 1.00657959, 1.00717940, + 1.00777926, 1.00837925, 1.00897929, 1.00957926, + 1.01017901, 1.01077847, 1.01137769, 1.01197678, + 1.01257582, 1.01317482, 1.01377365, 1.01437217, + 1.01497025, 1.01556786, 1.01616510, 1.01676205, + 1.01735876, 1.01795514, 1.01855103, 1.01914627, + 1.01974076, 1.02033455, 1.02092772, 1.02152037, + 1.02211247, 1.02270387, 1.02329439, 1.02388387, + 1.02447229, 1.02505972, 1.02564624, 1.02623190, + 1.02681660, 1.02740017, 1.02798242, 1.02856326, + 1.02914272, 1.02972087, 1.03029778, 1.03087344, + 1.03144768, 1.03202035, 1.03259127, 1.03316042, + 1.03372788, 1.03429373, 1.03485801, 1.03542064, + 1.03598146, 1.03654030, 1.03709708, 1.03765185, + 1.03820470, 1.03875571, 1.03930488, 1.03985206, + 1.04039712, 1.04093989, 1.04148037, 1.04201865, + 1.04255481, 1.04308893, 1.04362093, 1.04415068, + 1.04467803, 1.04520292, 1.04572542, 1.04624566, + 1.04676376, 1.04727974, 1.04779350, 1.04830493, + 1.04881391, 1.04932048, 1.04982477, 1.05032693, + 1.05082705, 1.05132510, 1.05182098, 1.05231457, + 1.05280584, 1.05329485, 1.05378171, 1.05426654, + 1.05474937, 1.05523018, 1.05570892, 1.05618554, + 1.05666005, 1.05713251, 1.05760297, 1.05807149, + 1.05853828, 1.05900355, 1.05946756, 1.05993024, + 1.06039075, 1.06084806, 1.06130111, 1.06175099, + 1.06220164, 1.06265732, 1.06312146, 1.06358726, + 1.06403924, 1.06446186, 1.06484048, 1.06516440, + 1.06527864, 1.06498077, 1.06470196, 1.06425743, + 1.06372091, 1.06311464, 1.06246622, 1.06179277, + 1.06110808, 1.06042455, 1.05974495, 1.05906206, + 1.05836706, 1.05765243, 1.05691470, 1.05615178, + 1.05536069, 1.05454152, 1.05370030, 1.05284445, + 1.05198094, 1.05111433, 1.05024634, 1.04937859, + 1.04851245, 1.04764614, 1.04677586, 1.04589855, + 1.04501046, 1.04410500, 1.04317417, 1.04221010, + 1.04120649, 1.04016012, 1.03906851, 1.03792894, + 1.03674090, 1.03550649, 1.03422800, 1.03290769, + 1.03154944, 1.03015834, 1.02873938, 1.02729712, + 1.02583470, 1.02435463, 1.02285952, 1.02135114, + 1.01982974, 1.01829520, 1.01674752, 1.01518534, + 1.01360559, 1.01200510, 1.01038076, 1.00872996, + 1.00705045, 1.00533999, 1.00359618, 1.00181613, + 0.99999673, 0.99813477, 0.99622793, 0.99427571, + 0.99227814, 0.99023501, 0.98815128, 0.98603857, + 0.98390898, 0.98177413, 0.97964151, 0.97751528, + 0.97539999, 0.97329751, 0.97119933, 0.96909179, + 0.96696152, 0.96479824, 0.96259840, 0.96036028, + 0.95808180, 0.95576295, 0.95340622, 0.95101436, + 0.94859030, 0.94614009, 0.94367232, 0.94119555, + 0.93871796, 0.93624630, 0.93378636, 0.93134465, + 0.92892076, 0.92649974, 0.92406255, 0.92159041, + 0.91907411, 0.91651711, 0.91392425, 0.91130056, + 0.90865471, 0.90599838, 0.90334350, 0.90069934, + 0.89806435, 0.89543132, 0.89279335, 0.89014496, + 0.88748403, 0.88480945, 0.88211997, 0.87941558, + 0.87669794, 0.87396891, 0.87123030, 0.86848394, + 0.86573164, 0.86297523, 0.86021649, 0.85745725, + 0.85474342, 0.85193656, 0.84911455, 0.84627969, + 0.84343424, 0.84058046, 0.83772057, 0.83485680, + 0.83199134, 0.82912621, 0.82626143, 0.82339529, + 0.82052619, 0.81765147, 0.81476433, 0.81185593, + 0.80891701, 0.80594452, 0.80294885, 0.79994431, + 0.79694485, 0.79396166, 0.79100220, 0.78807349, + 0.78518123, 0.78231422, 0.77944709, 0.77655407, + 0.77361369, 0.77062281, 0.76758806, 0.76451506, + 0.76141145, 0.75828860, 0.75515892, 0.75203479, + 0.74892561, 0.74583682, 0.74277342, 0.73974008, + 0.73673754, 0.73376310, 0.73081444, 0.72788616, + 0.72496070, 0.72201426, 0.71902283, 0.71596990, + 0.71285541, 0.70968427, 0.70646064, 0.70319589, + 0.69991077, 0.69662714, 0.69336592, 0.69013742, + 0.68694302, 0.68378420, 0.68066143, 0.67757157, + 0.67450951, 0.67147030, 0.66844879, 0.66543949, + 0.66243677, 0.65943505, 0.65642754, 0.65340591, + 0.65036160, 0.64728630, 0.64417440, 0.64102268, + 0.63782771, 0.63458757, 0.63130628, 0.62799109, + 0.62464879, 0.62128816, 0.61792203, 0.61456438, + 0.61122915, 0.60792802, 0.60466971, 0.60146257, + 0.59831460, 0.59522876, 0.59220375, 0.58923859, + 0.58632936, 0.58346064, 0.58061078, 0.57775874, + 0.57488246, 0.57195790, 0.56896078, 0.56586637, + 0.56266594, 0.55937186, 0.55599898, 0.55256299, + 0.54909184, 0.54562376, 0.54219742, 0.53884728, + 0.53559047, 0.53243453, 0.52938894, 0.52645052, + 0.52358958, 0.52076862, 0.51795080, 0.51510761, + 0.51222179, 0.50927733, 0.50625944, 0.50317073, + 0.50002767, 0.49685021, 0.49364116, 0.49048690, + 0.48726128, 0.48404889, 0.48090875, 0.47783482, + 0.47481564, 0.47184024, 0.46889391, 0.46595836, + 0.46301611, 0.46005089, 0.45705924, 0.45404822, + 0.45102447, 0.44799543, 0.44497138, 0.44196397, + 0.43898547, 0.43604105, 0.43312057, 0.43020942, + 0.42729337, 0.42436272, 0.42141388, 0.41844400, + 0.41545081, 0.41244014, 0.40942464, 0.40641716, + 0.40342874, 0.40046292, 0.39751923, 0.39459758, + 0.39169692, 0.38881435, 0.38594643, 0.38308980, + 0.38024146, 0.37739896, 0.37455986, 0.37172187, + 0.36888463, 0.36604937, 0.36321735, 0.36038967, + 0.35756668, 0.35474832, 0.35193455, 0.34912542, + 0.34632129, 0.34352258, 0.34072974, 0.33794323, + 0.33516354, 0.33239114, 0.32962648, 0.32686967, + 0.32412042, 0.32137919, 0.31864044, 0.31588373, + 0.31309909, 0.31028631, 0.30745528, 0.30462678, + 0.30180656, 0.29899424, 0.29619082, 0.29339717, + 0.29061333, 0.28783935, 0.28507563, 0.28232266, + 0.27958067, 0.27684984, 0.27413017, 0.27142157, + 0.26872396, 0.26603737, 0.26336211, 0.26069855, + 0.25804700, 0.25540830, 0.25278329, 0.25017211, + 0.24757451, 0.24498713, 0.24240740, 0.23983550, + 0.23727200, 0.23471866, 0.23217624, 0.22964458, + 0.22712346, 0.22461258, 0.22211202, 0.21962197, + 0.21714290, 0.21467522, 0.21221877, 0.20977323, + 0.20733693, 0.20490860, 0.20248823, 0.20007615, + 0.19767358, 0.19528091, 0.19289781, 0.19052347, + 0.18815661, 0.18579693, 0.18344441, 0.18110010, + 0.17876595, 0.17644344, 0.17413400, 0.17183905, + 0.16956003, 0.16729836, 0.16505547, 0.16283278, + 0.15990780, 0.15776021, 0.15563325, 0.15352557, + 0.15143584, 0.14936270, 0.14730481, 0.14526081, + 0.14322937, 0.14120918, 0.13919977, 0.13720138, + 0.13521422, 0.13323852, 0.13127445, 0.12932216, + 0.12738181, 0.12545358, 0.12353773, 0.12163457, + 0.11974436, 0.11786730, 0.11600347, 0.11415293, + 0.11231573, 0.11049201, 0.10868196, 0.10688578, + 0.10510362, 0.10333551, 0.10158143, 0.09984133, + 0.09811524, 0.09640327, 0.09470556, 0.09302228, + 0.09135347, 0.08969907, 0.08805903, 0.08643326, + 0.08482183, 0.08322486, 0.08164249, 0.08007481, + 0.07852179, 0.07698335, 0.07545938, 0.07394984, + 0.07245482, 0.07097444, 0.06950883, 0.06805800, + 0.06662187, 0.06520031, 0.06379324, 0.06240065, + 0.06102266, 0.05965936, 0.05831084, 0.05697701, + 0.05565775, 0.05435290, 0.05306239, 0.05178628, + 0.05052464, 0.04927758, 0.04804510, 0.04682709, + 0.04562344, 0.04443405, 0.04325893, 0.04209822, + 0.04095208, 0.03982059, 0.03870371, 0.03760131, + 0.03651325, 0.03543944, 0.03437987, 0.03333454, + 0.03230348, 0.03128653, 0.03028332, 0.02929346, + 0.02831658, 0.02735252, 0.02640127, 0.02546283, + 0.02453725, 0.02362471, 0.02272547, 0.02183980, + 0.02096810, 0.02011108, 0.01926957, 0.01844439, + 0.01763565, 0.01684248, 0.01606394, 0.01529909, + 0.01454726, 0.01380802, 0.01308092, 0.01236569, + 0.01166273, 0.01097281, 0.01029671, 0.00963479, + 0.00898646, 0.00835089, 0.00772725, 0.00711521, + 0.00651513, 0.00592741, 0.00535249, 0.00479089, + 0.00424328, 0.00371041, 0.00319271, 0.00268947, + 0.00219928, 0.00172084, 0.00125271, 0.00079311, + 0.00034023, -0.00010786, -0.00055144, -0.00098865, + -0.00141741, -0.00183557, -0.00224010, -0.00262725, + -0.00299314, -0.00333475, -0.00365250, -0.00394867, + -0.00422533, -0.00448528, -0.00473278, -0.00497252, + -0.00520916, -0.00544584, -0.00568360, -0.00592326, + -0.00616547, -0.00640861, -0.00664914, -0.00688354, + -0.00710845, -0.00732136, -0.00752022, -0.00770289, + -0.00786789, -0.00801521, -0.00814526, -0.00825839, + -0.00835563, -0.00843882, -0.00850996, -0.00857097, + -0.00862360, -0.00866943, -0.00871004, -0.00874688, + -0.00878091, -0.00881277, -0.00884320, -0.00887248, + -0.00890002, -0.00892494, -0.00894641, -0.00896355, + -0.00897541, -0.00898104, -0.00897948, -0.00896990, + -0.00895149, -0.00892346, -0.00888519, -0.00883670, + -0.00877839, -0.00871058, -0.00863388, -0.00854936, + -0.00845826, -0.00836179, -0.00826124, -0.00815807, + -0.00805372, -0.00794953, -0.00784572, -0.00774156, + -0.00763634, -0.00752929, -0.00741941, -0.00730556, + -0.00718664, -0.00706184, -0.00693107, -0.00679443, + -0.00665200, -0.00650428, -0.00635230, -0.00619718, + -0.00603995, -0.00588133, -0.00572169, -0.00556143, + -0.00540085, -0.00523988, -0.00507828, -0.00491582, + -0.00475220, -0.00458693, -0.00441953, -0.00424950, + -0.00407681, -0.00390204, -0.00372581, -0.00354874, + -0.00337115, -0.00319318, -0.00301494, -0.00283652, + -0.00265797, -0.00247934, -0.00230066, -0.00212197, + -0.00194331, -0.00176471, -0.00158620, -0.00140787, + -0.00122989, -0.00105244, -0.00087567, -0.00069976, + -0.00052487, -0.00035115, -0.00017875, -0.00000782, + 0.00000779, 0.00017701, 0.00034552, 0.00051313, + 0.00067966, 0.00084492, 0.00100873, 0.00117093, + 0.00133133, 0.00148978, 0.00164611, 0.00180023, + 0.00195211, 0.00210172, 0.00224898, 0.00239383, + 0.00253618, 0.00267593, 0.00281306, 0.00294756, + 0.00307942, 0.00320864, 0.00333502, 0.00345816, + 0.00357762, 0.00369297, 0.00380414, 0.00391140, + 0.00401499, 0.00411524, 0.00421242, 0.00430678, + 0.00439859, 0.00448799, 0.00457487, 0.00465908, + 0.00474045, 0.00481857, 0.00489277, 0.00496235, + 0.00502666, 0.00508546, 0.00513877, 0.00518662, + 0.00522904, 0.00526648, 0.00529956, 0.00532895, + 0.00535532, 0.00537929, 0.00540141, 0.00542228, + 0.00544196, 0.00545981, 0.00547515, 0.00548726, + 0.00549542, 0.00549899, 0.00549732, 0.00548986, + 0.00547633, 0.00545664, 0.00543067, 0.00539849, + 0.00536061, 0.00531757, 0.00526993, 0.00521822, + 0.00516300, 0.00510485, 0.00504432, 0.00498194, + 0.00491822, 0.00485364, 0.00478862, 0.00472309, + 0.00465675, 0.00458939, 0.00452067, 0.00445003, + 0.00437688, 0.00430063, 0.00422062, 0.00413609, + 0.00404632, 0.00395060, 0.00384863, 0.00374044, + 0.00362600, 0.00350540, 0.00337934, 0.00324885, + 0.00311486, 0.00297849, 0.00284122, 0.00270458, + 0.00257013, 0.00243867, 0.00231005, 0.00218399, + 0.00206023, 0.00193766, 0.00181460, 0.00168938, + 0.00156050, 0.00142701, 0.00128830, 0.00114365, + 0.00099297, 0.00083752, 0.00067884, 0.00051845, + 0.00035760, 0.00019720, 0.00003813, -0.00011885, + -0.00027375, -0.00042718, -0.00057975, -0.00073204, + -0.00088453, -0.00103767, -0.00119192, -0.00134747, + -0.00150411, -0.00166151, -0.00181932, -0.00197723, + -0.00213493, -0.00229210, -0.00244849, -0.00260415, + -0.00275928, -0.00291410, -0.00306879, -0.00322332, + -0.00337759, -0.00353145, -0.00368470, -0.00383722, + -0.00398892, -0.00413972, -0.00428967, -0.00443889, + -0.00458749, -0.00473571, -0.00488366, -0.00503137, + -0.00517887, -0.00532610, -0.00547302, -0.00561965, + -0.00576598, -0.00591199, -0.00605766, -0.00620300, + -0.00634801, -0.00649273, -0.00663727, -0.00678170, + -0.00692617, -0.00707084, -0.00721583, -0.00736129, + -0.00750735, -0.00765415, -0.00780184, -0.00795059, + -0.00810058, -0.00825195, -0.00840487, -0.00855950, + -0.00871607, -0.00887480, -0.00903596, -0.00919978, + -0.00936650, -0.00953635, -0.00970931, -0.00988421, + -0.01005916, -0.01023208, -0.01040130, -0.01056627, + -0.01072678, -0.01088259, -0.01103348, -0.01117933, + -0.01132004, -0.01145552, -0.01158573, -0.01171065, + -0.01183025, -0.01194454, -0.01205352, -0.01215722, + -0.01225572, -0.01234911, -0.01243749, -0.01252102, + -0.01259985, -0.01267419, -0.01274437, -0.01281078, + -0.01287379, -0.01293350, -0.01298972, -0.01304224, + -0.01309086, -0.01313556, -0.01317644, -0.01321357, + -0.01324707, -0.01327697, -0.01330334, -0.01332622, + -0.01334570, -0.01336194, -0.01337510, -0.01338538, + -0.01339276, -0.01339708, -0.01339816, -0.01339584, + -0.01339014, -0.01338116, -0.01336903, -0.01335382, + -0.01333545, -0.01331381, -0.01328876, -0.01326033, + -0.01322880, -0.01319457, -0.01315806, -0.01311968, + -0.01307987, -0.01303906, -0.01299769, -0.01295623, + -0.01308207, -0.01304153, -0.01299802, -0.01295155, + -0.01290215, -0.01284980, -0.01279450, -0.01273625, + -0.01267501, -0.01261077, -0.01254347, -0.01247306, + -0.01239950, -0.01232277, -0.01224304, -0.01216055, + -0.01207554, -0.01198813, -0.01189829, -0.01180590, + -0.01171090, -0.01161335, -0.01151352, -0.01141167, + -0.01130807, -0.01120289, -0.01109626, -0.01098830, + -0.01087916, -0.01076898, -0.01065793, -0.01054618, + -0.01043380, -0.01032068, -0.01020670, -0.01009171, + -0.00997585, -0.00985959, -0.00974338, -0.00962765, + -0.00951273, -0.00939888, -0.00928634, -0.00917534, + -0.00906604, -0.00895860, -0.00885313, -0.00874977, + -0.00864862, -0.00854979, -0.00845337, -0.00835939, + -0.00826785, -0.00817872, -0.00809195, -0.00800745, + -0.00792506, -0.00784469, -0.00776588, -0.00768695, + -0.00760568, -0.00752004, -0.00742875, -0.00733186, + -0.00722976, -0.00712279, -0.00701130, -0.00689559, + -0.00677595, -0.00665269, -0.00652610, -0.00639649, + -0.00626417, -0.00612943, -0.00599252, -0.00585368, + -0.00571315, -0.00557115, -0.00542792, -0.00528367, + -0.00513864, -0.00499301, -0.00484693, -0.00470054, + -0.00455395, -0.00440733, -0.00426086, -0.00411471, + -0.00396904, -0.00382404, -0.00367991, -0.00353684, + -0.00339502, -0.00325472, -0.00311618, -0.00297967, + -0.00284531, -0.00271307, -0.00258290, -0.00245475, + -0.00232860, -0.00220447, -0.00208236, -0.00196233, + -0.00184450, -0.00172906, -0.00161620, -0.00150603, + -0.00139852, -0.00129358, -0.00119112, -0.00109115, + -0.00099375, -0.00089902, -0.00080705, -0.00071796, + -0.00063185, -0.00054886, -0.00046904, -0.00039231, + -0.00031845, -0.00024728, -0.00017860, -0.00011216, + -0.00004771, 0.00001500, 0.00007600, 0.00013501, + 0.00019176, 0.00024595, 0.00029720, 0.00034504, + 0.00038902, 0.00042881, 0.00046456, 0.00049662, + 0.00052534, 0.00055114, 0.00057459, 0.00059629, + 0.00061684, 0.00063660, 0.00065568, 0.00067417, + 0.00069213, 0.00070935, 0.00072545, 0.00074005, + 0.00075283, 0.00076356, 0.00077209, 0.00077828, + 0.00078205, 0.00078350, 0.00078275, 0.00077992, + 0.00077520, 0.00076884, 0.00076108, 0.00075218, + 0.00074232, 0.00073170, 0.00072048, 0.00070881, + 0.00069680, 0.00068450, 0.00067201, 0.00065934, + 0.00064647, 0.00063335, 0.00061994, 0.00060621, + 0.00059211, 0.00057763, 0.00056274, 0.00054743, + 0.00053169, 0.00051553, 0.00049897, 0.00048206, + 0.00046487, 0.00044748, 0.00042996, 0.00041241, + 0.00039492, 0.00037759, 0.00036049, 0.00034371, + 0.00032732, 0.00031137, 0.00029587, 0.00028079, + 0.00026612, 0.00025183, 0.00023789, 0.00022428, + 0.00021097, 0.00019797, 0.00018530, 0.00017297, + 0.00016100, 0.00014942, 0.00013827, 0.00012757, + 0.00011736, 0.00010764, 0.00009841, 0.00008969, + 0.00008145, 0.00007369, 0.00006641, 0.00005958, + 0.00005320, 0.00004725, 0.00004171, 0.00003659, + 0.00003186, 0.00002752, 0.00002357, 0.00001999, + 0.00001679, 0.00001392, 0.00001140, 0.00000918, + 0.00000726, 0.00000562, 0.00000424, 0.00000309, + 0.00000217, 0.00000143, 0.00000088, 0.00000048, + 0.00000020, 0.00000004, -0.00000004, -0.00000006, + -0.00000004, -0.00000000, 0.00000002, 0.00000000, + 0.00000000, 0.00000002, -0.00000000, -0.00000004, + -0.00000005, -0.00000004, 0.00000004, 0.00000019, + 0.00000045, 0.00000083, 0.00000134, 0.00000201, + 0.00000285, 0.00000387, 0.00000510, 0.00000654, + 0.00000821, 0.00001011, 0.00001227, 0.00001468, + 0.00001735, 0.00002030, 0.00002352, 0.00002702, + 0.00003080, 0.00003486, 0.00003918, 0.00004379, + 0.00004866, 0.00005382, 0.00005924, 0.00006495, + 0.00007093, 0.00007719, 0.00008373, 0.00009053, + 0.00009758, 0.00010488, 0.00011240, 0.00012010, + 0.00012796, 0.00013596, 0.00014406, 0.00015226, + 0.00016053, 0.00016886, 0.00017725, 0.00018571, + 0.00019424, 0.00020286, 0.00021156, 0.00022037, + 0.00022928, 0.00023825, 0.00024724, 0.00025621, + 0.00026509, 0.00027385, 0.00028241, 0.00029072, + 0.00029874, 0.00030643, 0.00031374, 0.00032065, + 0.00032715, 0.00033325, 0.00033895, 0.00034425, + 0.00034917, 0.00035374, 0.00035796, 0.00036187, + 0.00036549, 0.00036883, 0.00037194, 0.00037479, + 0.00037736, 0.00037963, 0.00038154, 0.00038306, + 0.00038411, 0.00038462, 0.00038453, 0.00038373, + 0.00038213, 0.00037965, 0.00037621, 0.00037179, + 0.00036636, 0.00035989, 0.00035244, 0.00034407, + 0.00033488, 0.00032497, 0.00031449, 0.00030361, + 0.00029252, 0.00028133, 0.00027003, 0.00025862, + 0.00024706, 0.00023524, 0.00022297, 0.00021004, + 0.00019626, 0.00018150, 0.00016566, 0.00014864, + 0.00013041, 0.00011112, 0.00009096, 0.00007014, + 0.00004884, 0.00002718, 0.00000530, -0.00001667, + -0.00003871, -0.00006090, -0.00008331, -0.00010600, + -0.00012902, -0.00015244, -0.00017631, -0.00020065, + -0.00022541, -0.00025052, -0.00027594, -0.00030159, + -0.00032740, -0.00035332, -0.00037928, -0.00040527, + -0.00043131, -0.00045741, -0.00048357, -0.00050978, + -0.00053599, -0.00056217, -0.00058827, -0.00061423, + -0.00064002, -0.00066562, -0.00069100, -0.00071616, + -0.00074110, -0.00076584, -0.00079036, -0.00081465, + -0.00083869, -0.00086245, -0.00088590, -0.00090901, + -0.00093176, -0.00095413, -0.00097608, -0.00099758, + -0.00101862, -0.00103918, -0.00105924, -0.00107879, + -0.00109783, -0.00111635, -0.00113434, -0.00115181, + -0.00116873, -0.00118510, -0.00120091, -0.00121615, + -0.00123082, -0.00124490, -0.00125838, -0.00127125, + -0.00128350, -0.00129511, -0.00130610, -0.00131643, + -0.00132610, -0.00133509, -0.00134334, -0.00135069, + -0.00135711, -0.00136272, -0.00136768, -0.00137225, + -0.00137649, -0.00138042, -0.00138404, -0.00138737, + -0.00139041, -0.00139317, -0.00139565, -0.00139785, + -0.00139976, -0.00140137, -0.00140267, -0.00140366, + -0.00140432, -0.00140464, -0.00140461, -0.00140423, + -0.00140347, -0.00140235, -0.00140084, -0.00139894, + -0.00139664, -0.00139388, -0.00139065, -0.00138694, + -0.00138278, -0.00137818, -0.00137317, -0.00136772, + -0.00136185, -0.00135556, -0.00134884, -0.00134170, + -0.00133415, -0.00132619, -0.00131784, -0.00130908, + -0.00129991, -0.00129031, -0.00128031, -0.00126990, + -0.00125912, -0.00124797, -0.00123645, -0.00122458, + -0.00121233, -0.00119972, -0.00118676, -0.00117347, + -0.00115988, -0.00114605, -0.00113200, -0.00111778, + -0.00110343, -0.00108898, -0.00107448, -0.00105995, +}; + +const DECLARE_ALIGNED(32, int, ff_aac_eld_window_480_fixed)[1800] = { + 0x00109442, 0x00482797, 0x0075bf2a, 0x00afa864, + 0x00ef2aa5, 0x01335b36, 0x017a4df0, 0x01c2cffe, + 0x020bfb4c, 0x0254fd74, 0x029d557c, 0x02e50574, + 0x032c41a8, 0x03732c08, 0x03b9cb88, 0x040032e8, + 0x044686f0, 0x048cd578, 0x04d30738, 0x05190500, + 0x055ec210, 0x05a44750, 0x05e9aeb8, 0x062f0c80, + 0x067477a0, 0x06ba1ac0, 0x07001998, 0x074680e0, + 0x078d5ec0, 0x07d4d038, 0x081cf8f0, 0x0865f8b0, + 0x08afe0e0, 0x08fab150, 0x09466cd0, 0x09931910, + 0x09e0adb0, 0x0a2f1640, 0x0a7e43f0, 0x0ace2960, + 0x0b1eb180, 0x0b6fc4b0, 0x0bc15050, 0x0c134710, + 0x0c65a420, 0x0cb86340, 0x0d0b7df0, 0x0d5ef450, + 0x0db2cb60, 0x0e070180, 0x0e5b91f0, 0x0eb07f20, + 0x0f05d0a0, 0x0f5b8920, 0x0fb1a950, 0x10082e40, + 0x105f1400, 0x10b65820, 0x110df780, 0x1165f120, + 0x11be43e0, 0x1216eea0, 0x126feac0, 0x12c92b00, + 0x1322a620, 0x137c55c0, 0x13d61ae0, 0x142fc940, + 0x148949e0, 0x14e28da0, 0x153b9a80, 0x15947640, + 0x15ed1840, 0x16458660, 0x169deb20, 0x16f663c0, + 0x174ef8c0, 0x17a7a120, 0x180041c0, 0x1858d000, + 0x18b14940, 0x1909a140, 0x1961c820, 0x19b9b620, + 0x1a116480, 0x1a68c1a0, 0x1abfbd00, 0x1b164f60, + 0x1b6c7580, 0x1bc23120, 0x1c1780e0, 0x1c6c5d00, + 0x1cc0dbe0, 0x1d1532a0, 0x1d697660, 0x1dbdac20, + 0x1e11b280, 0x1e655b80, 0x1eb89e80, 0x1f0b7720, + 0x1f5dd680, 0x1fafaec0, 0x2000fb00, 0x2051c340, + 0x20a22ac0, 0x20f24580, 0x214213c0, 0x21919140, + 0x21e0b300, 0x222f7580, 0x227dd900, 0x22cbd880, + 0x23196ec0, 0x23669b00, 0x23b35d80, 0x23ffb6c0, + 0x244ba7c0, 0x249731c0, 0x24e25700, 0x252d1940, + 0x2594ae40, 0x25deea40, 0x2628bd00, 0x26722680, + 0x26bb2740, 0x2703bf40, 0x274beec0, 0x2793b600, + 0x27db1500, 0x28220c00, 0x28689b80, 0x28aec4c0, + 0x28f48800, 0x2939e680, 0x297ee080, 0x29c37600, + 0x2a07a740, 0x2a4b74c0, 0x2a8ede80, 0x2ad1e500, + 0x2b148880, 0x2b56c940, 0x2b98a740, 0x2bda2240, + 0x2c1b3a80, 0x2c5bef80, 0x2c9c4100, 0x2cdc2e80, + 0x2d1bb800, 0x2d5adc80, 0x2d999b80, 0x2dd7f500, + 0x2e15e800, 0x2e537400, 0x2e9098c0, 0x2ecd5540, + 0x2f09a900, 0x2f4592c0, 0x2f811140, 0x2fbc2340, + 0x2ff6c7c0, 0x3030fe80, 0x306ac6c0, 0x30a41f80, + 0x30dd07c0, 0x31157dc0, 0x314d7fc0, 0x31850c80, + 0x31bc22c0, 0x31f2c1c0, 0x3228e840, 0x325e9540, + 0x3293c7c0, 0x32c87e40, 0x32fcb800, 0x33307340, + 0x3363aec0, 0x33966940, 0x33c8a140, 0x33fa5580, + 0x342b84c0, 0x345c2dc0, 0x348c4f80, 0x34bbe900, + 0x34eaf9c0, 0x35198080, 0x35477d00, 0x3574ee40, + 0x35a1d340, 0x35ce2bc0, 0x35f9f6c0, 0x36253380, + 0x364fe180, 0x367a0040, 0x36a38f80, 0x36cc8ec0, + 0x36f4fe80, 0x371cde80, 0x37442e80, 0x376aef00, + 0x37912000, 0x37b6c200, 0x37dbd600, 0x38005d00, + 0x38245840, 0x3847c880, 0x386aaf80, 0x388d0e80, + 0x38aee700, 0x38d03bc0, 0x38f11000, 0x39116700, + 0x39314440, 0x3950ab00, 0x396f9e80, 0x398e22c0, + 0x39ac3c40, 0x39c9f280, 0x39e74cc0, 0x3a045280, + 0x3a210b40, 0x3a3d7ec0, 0x3a59b480, 0x3a75b480, + 0x3a918900, 0x3aad3cc0, 0x3ac8db00, 0x3ae46bc0, + 0x3afff080, 0x3b1b6840, 0x3b36d2c0, 0x3b521980, + 0x3b6d0780, 0x3b876400, 0x3ba0f4c0, 0x3bb96740, + 0x3bd03dc0, 0x3be56580, 0x3bf6dec0, 0x3c0c6140, + 0x3c15a9c0, 0x3c1a5780, 0x3c1fd0c0, 0x3c25edc0, + 0x3c2c78c0, 0x3c333880, 0x3c39f3c0, 0x3c409100, + 0x3c471d00, 0x3c4da780, 0x3c543f40, 0x3c5ae880, + 0x3c619f00, 0x3c685f00, 0x3c6f25c0, 0x3c75f280, + 0x3c7cc6c0, 0x3c83a2c0, 0x3c8a87c0, 0x3c9175c0, + 0x3c986d00, 0x3c9f6e00, 0x3ca67880, 0x3cad8c40, + 0x3cb4a980, 0x3cbbd000, 0x3cc2ffc0, 0x3cca3940, + 0x3cd17d40, 0x3cd8cb80, 0x3ce02480, 0x3ce78740, + 0x3ceef3c0, 0x3cf66a00, 0x3cfdea00, 0x3d0574c0, + 0x3d0d0a40, 0x3d14ab40, 0x3d1c5700, 0x3d240d00, + 0x3d2bcd40, 0x3d3397c0, 0x3d3b6cc0, 0x3d434d00, + 0x3d4b38c0, 0x3d532fc0, 0x3d5b3180, 0x3d633dc0, + 0x3d6b53c0, 0x3d737400, 0x3d7b9f00, 0x3d83d540, + 0x3d8c1680, 0x3d946200, 0x3d9cb780, 0x3da51680, + 0x3dad7f00, 0x3db5f140, 0x3dbe6dc0, 0x3dc6f480, + 0x3dcf8540, 0x3dd81fc0, 0x3de0c300, 0x3de96ec0, + 0x3df22340, 0x3dfae0c0, 0x3e03a800, 0x3e0c7840, + 0x3e155180, 0x3e1e32c0, 0x3e271bc0, 0x3e300c00, + 0x3e390400, 0x3e420400, 0x3e4b0c40, 0x3e541c80, + 0x3e5d33c0, 0x3e6651c0, 0x3e6f7580, 0x3e789fc0, + 0x3e81d080, 0x3e8b0880, 0x3e944700, 0x3e9d8c00, + 0x3ea6d680, 0x3eb02600, 0x3eb97a80, 0x3ec2d400, + 0x3ecc3340, 0x3ed59880, 0x3edf0300, 0x3ee87280, + 0x3ef1e600, 0x3efb5d40, 0x3f04d880, 0x3f0e5840, + 0x3f17dcc0, 0x3f216600, 0x3f2af340, 0x3f348440, + 0x3f3e1840, 0x3f47af40, 0x3f514a00, 0x3f5ae840, + 0x3f648b00, 0x3f6e3140, 0x3f77db00, 0x3f818740, + 0x3f8b3600, 0x3f94e780, 0x3f9e9c40, 0x3fa85480, + 0x3fb21080, 0x3fbbcfc0, 0x3fc59200, 0x3fcf56c0, + 0x3fd91dc0, 0x3fe2e640, 0x3fecb040, 0x3ff67b40, + 0x40098600, 0x40135580, 0x401d2700, 0x4026fa00, + 0x4030ce80, 0x403aa380, 0x40447900, 0x404e4f00, + 0x40582400, 0x4061f900, 0x406bcd00, 0x4075a080, + 0x407f7480, 0x40894900, 0x40931e00, 0x409cf280, + 0x40a6c600, 0x40b09800, 0x40ba6980, 0x40c43a80, + 0x40ce0b00, 0x40d7db00, 0x40e1ab00, 0x40eb7980, + 0x40f54600, 0x40ff1080, 0x4108d980, 0x4112a100, + 0x411c6800, 0x41262d80, 0x412ff080, 0x4139b180, + 0x41436e80, 0x414d2980, 0x4156e100, 0x41609700, + 0x416a4a80, 0x4173fb00, 0x417da800, 0x41875000, + 0x4190f400, 0x419a9400, 0x41a43000, 0x41adc880, + 0x41b75d00, 0x41c0ec80, 0x41ca7700, 0x41d3fb00, + 0x41dd7980, 0x41e6f280, 0x41f06600, 0x41f9d480, + 0x42033d00, 0x420c9f00, 0x4215f980, 0x421f4d00, + 0x42289900, 0x4231de80, 0x423b1d00, 0x42445500, + 0x424d8500, 0x4256ad00, 0x425fcc80, 0x4268e380, + 0x4271f200, 0x427af900, 0x4283f880, 0x428cef80, + 0x4295de00, 0x429ec280, 0x42a79d80, 0x42b06f00, + 0x42b93800, 0x42c1f800, 0x42caaf80, 0x42d35d80, + 0x42dc0100, 0x42e49b00, 0x42ed2a80, 0x42f5b080, + 0x42fe2d80, 0x4306a180, 0x430f0c80, 0x43176d80, + 0x431fc480, 0x43281100, 0x43305400, 0x43388e80, + 0x4340c000, 0x4348e900, 0x43510900, 0x43591f00, + 0x43612b80, 0x43692f00, 0x43712900, 0x43791a80, + 0x43810380, 0x4388e400, 0x4390bc00, 0x43988b00, + 0x43a05180, 0x43a80f00, 0x43afc480, 0x43b77180, + 0x43bf1780, 0x43c6b700, 0x43ce5100, 0x43d5e580, + 0x43dd7100, 0x43e4ef80, 0x43ec5b80, 0x43f3ba80, + 0x43fb1c80, 0x44029400, 0x440a2e80, 0x4411d080, + 0x44193800, 0x44202480, 0x44265880, 0x442ba780, + 0x442d8680, 0x4428a500, 0x44241380, 0x441ccb00, + 0x44140100, 0x440a1200, 0x43ff7280, 0x43f46980, + 0x43e93200, 0x43ddff00, 0x43d2dc80, 0x43c7ac00, + 0x43bc4900, 0x43b09400, 0x43a47d80, 0x4397fd80, + 0x438b0780, 0x437d9b80, 0x436fd380, 0x4361cd80, + 0x4353a800, 0x43457500, 0x43373c80, 0x43290500, + 0x431ad400, 0x430ca280, 0x42fe6000, 0x42f00080, + 0x42e17380, 0x42d29e00, 0x42c35d80, 0x42b39200, + 0x42a32080, 0x4291fc00, 0x42801900, 0x426d6d80, + 0x4259f680, 0x4245bd00, 0x4230ca80, 0x421b2900, + 0x4204e800, 0x41ee1d00, 0x41d6dd80, 0x41bf3c80, + 0x41a74680, 0x418f0680, 0x41768800, 0x415dd100, + 0x4144e400, 0x412bbf80, 0x41126400, 0x40f8cc00, + 0x40deea00, 0x40c4b100, 0x40aa1400, 0x408f0800, + 0x40738380, 0x40577d80, 0x403aeb80, 0x401dc180, + 0x3ffff240, 0x3fe170c0, 0x3fc232c0, 0x3fa23680, + 0x3f817c40, 0x3f6002c0, 0x3f3ddec0, 0x3f1b4180, + 0x3ef85d40, 0x3ed56340, 0x3eb27240, 0x3e8f9c40, + 0x3e6cf400, 0x3e4a81c0, 0x3e282140, 0x3e059980, + 0x3de2b280, 0x3dbf4100, 0x3d9b3640, 0x3d768b00, + 0x3d513640, 0x3d2b3840, 0x3d049b80, 0x3cdd6b40, + 0x3cb5b400, 0x3c8d8f40, 0x3c652080, 0x3c3c8c40, + 0x3c13f480, 0x3beb7580, 0x3bc327c0, 0x3b9b2680, + 0x3b737000, 0x3b4bc580, 0x3b23d740, 0x3afb5640, + 0x3ad21c40, 0x3aa83780, 0x3a7dbc40, 0x3a52bf80, + 0x3a276600, 0x39fbe0c0, 0x39d06140, 0x39a50ec0, + 0x3979e300, 0x394ebf40, 0x392386c0, 0x38f82280, + 0x38cc89c0, 0x38a0b7c0, 0x3874a740, 0x38485840, + 0x381bd1c0, 0x37ef1b40, 0x37c23cc0, 0x37953dc0, + 0x376825c0, 0x373afc80, 0x370dc980, 0x36e09440, + 0x36b41dc0, 0x36862100, 0x3657e480, 0x36297240, + 0x35fad380, 0x35cc1200, 0x359d36c0, 0x356e4b40, + 0x353f5880, 0x35106780, 0x34e17780, 0x34b28240, + 0x34838040, 0x345466c0, 0x34251940, 0x33f57280, + 0x33c54bc0, 0x33949840, 0x33638380, 0x33324980, + 0x33012500, 0x32d04480, 0x329fc7c0, 0x326fcbc0, + 0x324068c0, 0x32116fc0, 0x31e27600, 0x31b30fc0, + 0x3182e300, 0x3151e240, 0x312029c0, 0x30edd080, + 0x30baf700, 0x3087cd00, 0x30548600, 0x30215680, + 0x2fee65c0, 0x2fbbca40, 0x2f899980, 0x2f57e6c0, + 0x2f26b540, 0x2ef5f980, 0x2ec5aa00, 0x2e95afc0, + 0x2e65c180, 0x2e357b40, 0x2e047840, 0x2dd27380, + 0x2d9f6c40, 0x2d6b7780, 0x2d36a6c0, 0x2d012940, + 0x2ccb5680, 0x2c958a00, 0x2c601b80, 0x2c2b3640, + 0x2bf6dfc0, 0x2bc31ec0, 0x2b8ff500, 0x2b5d5540, + 0x2b2b2a00, 0x2af95e80, 0x2ac7dd80, 0x2a968f80, + 0x2a655d40, 0x2a342f00, 0x2a02e8c0, 0x29d16700, + 0x299f8640, 0x296d2380, 0x293a2740, 0x29068400, + 0x28d22b40, 0x289d1540, 0x28675280, 0x28310180, + 0x27fa3f00, 0x27c32f80, 0x278c08c0, 0x275505c0, + 0x271e60c0, 0x26e84b00, 0x26b2e880, 0x267e5cc0, + 0x264ac940, 0x26183a40, 0x25e6aa80, 0x25b615c0, + 0x25866b80, 0x25576b40, 0x2528ba00, 0x24f9ffc0, + 0x24cadfc0, 0x249af540, 0x2469da80, 0x24372780, + 0x2402b800, 0x23ccbfc0, 0x23957cc0, 0x235d3140, + 0x23245200, 0x22eb8000, 0x22b35cc0, 0x227c7940, + 0x22471d40, 0x22136840, 0x21e18240, 0x21b15d80, + 0x21827dc0, 0x21544600, 0x21261b00, 0x20f78600, + 0x20c83e00, 0x20980000, 0x20668e00, 0x2033f300, + 0x20007400, 0x1fcc64e0, 0x1f97d120, 0x1f642320, + 0x1f2f49e0, 0x1efaa840, 0x1ec73580, 0x1e94d880, + 0x1e636120, 0x1e32a160, 0x1e025ba0, 0x1dd24300, + 0x1da20e60, 0x1d717940, 0x1d407560, 0x1d0f2040, + 0x1cdd95c0, 0x1cabf500, 0x1c7a6940, 0x1c492340, + 0x1c185680, 0x1be818c0, 0x1bb83f60, 0x1b888d20, + 0x1b58c640, 0x1b28c240, 0x1af871e0, 0x1ac7c960, + 0x1a96bf00, 0x1a656b60, 0x1a340360, 0x1a02bd20, + 0x19d1c6c0, 0x19a12f40, 0x1970f480, 0x19411640, + 0x19119000, 0x18e255a0, 0x18b358a0, 0x18848b20, + 0x1855e040, 0x18274e00, 0x17f8c9e0, 0x17ca4a80, + 0x179bce40, 0x176d5a60, 0x173ef400, 0x17109fe0, + 0x16e25f60, 0x16b43240, 0x16861880, 0x16581220, + 0x162a20c0, 0x15fc4620, 0x15ce8420, 0x15a0dca0, + 0x157351c0, 0x1545e580, 0x151899a0, 0x14eb6ec0, + 0x14be63a0, 0x14917a00, 0x14649ae0, 0x14377060, + 0x1409d0c0, 0x13dbbb20, 0x13ad58e0, 0x137f0160, + 0x1350cc80, 0x1322b8c0, 0x12f4ca60, 0x12c704e0, + 0x129968a0, 0x126bf5c0, 0x123eade0, 0x12119300, + 0x11e4a660, 0x11b7e860, 0x118b5940, 0x115ef8a0, + 0x1132c600, 0x1106c1a0, 0x10daecc0, 0x10af4900, + 0x1083d7a0, 0x10589c00, 0x102d9a00, 0x1002d1e0, + 0x0fd842c0, 0x0fadde80, 0x0f839a50, 0x0f597700, + 0x0f2f76e0, 0x0f05a170, 0x0edbf9c0, 0x0eb27f30, + 0x0e8930d0, 0x0e600d70, 0x0e371550, 0x0e0e4950, + 0x0de5ab50, 0x0dbd3d20, 0x0d94fe10, 0x0d6cecb0, + 0x0d450220, 0x0d1d38f0, 0x0cf59130, 0x0cce0c30, + 0x0ca6af10, 0x0c7f7b80, 0x0c587010, 0x0c318960, + 0x0c0ac200, 0x0be418d0, 0x0bbd8da0, 0x0b9724e0, + 0x0b70e6c0, 0x0b4ad970, 0x0b2502f0, 0x0aff6930, + 0x0ada1250, 0x0ab50430, 0x0a9044d0, 0x0a6bda30, + 0x0a3bedf0, 0x0a18be40, 0x09f5e530, 0x09d35cf0, + 0x09b11ff0, 0x098f2890, 0x096d7120, 0x094bf400, + 0x092aab80, 0x09099240, 0x08e8a620, 0x08c7e850, + 0x08a75990, 0x0886fae0, 0x0866ccf0, 0x0846d070, + 0x08270610, 0x08076e70, 0x07e80ac8, 0x07c8dc60, + 0x07a9e440, 0x078b2348, 0x076c99d0, 0x074e4818, + 0x07302e50, 0x07124d18, 0x06f4a530, 0x06d73778, + 0x06ba0488, 0x069d0c88, 0x06804f68, 0x0663cce0, + 0x06478528, 0x062b78a0, 0x060fa7e8, 0x05f413b8, + 0x05d8bc38, 0x05bda128, 0x05a2c258, 0x05881f60, + 0x056db888, 0x05538e60, 0x0539a170, 0x051ff218, + 0x05068040, 0x04ed4b90, 0x04d45398, 0x04bb9820, + 0x04a31988, 0x048ad860, 0x0472d528, 0x045b0ff0, + 0x04438860, 0x042c3de8, 0x04153040, 0x03fe5f4c, + 0x03e7cb98, 0x03d17580, 0x03bb5d64, 0x03a582e8, + 0x038fe588, 0x037a8494, 0x03655fcc, 0x03507768, + 0x033bcbb4, 0x03275d28, 0x03132bc0, 0x02ff370c, + 0x02eb7e94, 0x02d801e8, 0x02c4c11c, 0x02b1bcbc, + 0x029ef578, 0x028c6ba8, 0x027a1f20, 0x02680f54, + 0x02563bac, 0x0244a3c8, 0x023347a0, 0x02222730, + 0x0211429c, 0x02009938, 0x01f02974, 0x01dff1ae, + 0x01cff058, 0x01c024c8, 0x01b08ef4, 0x01a12eda, + 0x019204b0, 0x01831138, 0x01745588, 0x0165d2c2, + 0x01578a96, 0x01497ffc, 0x013bb670, 0x012e3160, + 0x0120f146, 0x0113f27c, 0x0107310c, 0x00faa909, + 0x00ee57a1, 0x00e23b09, 0x00d6515b, 0x00ca9977, + 0x00bf1509, 0x00b3c74d, 0x00a8b388, 0x009ddb3d, + 0x00933bf2, 0x0088d22c, 0x007e9a70, 0x0074935a, + 0x006abe70, 0x00611d5c, 0x0057b1f8, 0x004e7e73, + 0x0045859b, 0x003cca96, 0x00344f32, 0x002c1074, + 0x00240873, 0x001c31ba, 0x0014863f, 0x000cfe8b, + 0x00059307, 0xfffe3b9a, 0xfff6f718, 0xffefcd4d, + 0xffe8c6f4, 0xffe1ed10, 0xffdb4c57, 0xffd4f484, + 0xffcef5dc, 0xffc95d0c, 0xffc4284e, 0xffbf4e14, + 0xffbac5ae, 0xffb68360, 0xffb27548, 0xffae87be, + 0xffaaa733, 0xffa6c67e, 0xffa2e141, 0xff9ef40c, + 0xff9afc25, 0xff970058, 0xff930f7c, 0xff8f3857, + 0xff8b8900, 0xff880bfe, 0xff84c9ea, 0xff81cbbd, + 0xff7f17ad, 0xff7cadc6, 0xff7a8c4e, 0xff78b1cd, + 0xff7719f3, 0xff75bd06, 0xff7492a4, 0xff7392bf, + 0xff72b600, 0xff71f5c6, 0xff714b72, 0xff70b0ed, + 0xff702232, 0xff6f9c90, 0xff6f1cee, 0xff6ea21f, + 0xff6e2e9c, 0xff6dc617, 0xff6d6c09, 0xff6d2425, + 0xff6cf267, 0xff6cdaca, 0xff6ce155, 0xff6d0983, + 0xff6d56bb, 0xff6dcc4c, 0xff6e6cd0, 0xff6f3832, + 0xff702cc4, 0xff71492e, 0xff728ae2, 0xff73ed63, + 0xff756b7c, 0xff77001c, 0xff78a5d9, 0xff7a5693, + 0xff7c0c40, 0xff7dc141, 0xff7f74aa, 0xff81298b, + 0xff82e2de, 0xff84a3de, 0xff8670bd, 0xff884e42, + 0xff8a410c, 0xff8c4c7f, 0xff8e70fc, 0xff90ae18, + 0xff93037e, 0xff956f12, 0xff97ec86, 0xff9a7724, + 0xff9d0a9d, 0xff9fa3ea, 0xffa2417e, 0xffa4e1ac, + 0xffa78332, 0xffaa265a, 0xffaccc26, 0xffaf758e, + 0xffb223d4, 0xffb4d906, 0xffb79726, 0xffba604e, + 0xffbd349e, 0xffc011a8, 0xffc2f4d2, 0xffc5db82, + 0xffc8c45f, 0xffcbaed5, 0xffce9a6d, 0xffd186c6, + 0xffd473aa, 0xffd760e5, 0xffda4e55, 0xffdd3bd0, + 0xffe0292b, 0xffe31645, 0xffe602ff, 0xffe8eef7, + 0xffebd978, 0xffeec1bf, 0xfff1a72c, 0xfff488fe, + 0xfff76689, 0xfffa3f2c, 0xfffd1245, 0xffffdf33, + 0x000020ac, 0x0002e66f, 0x0005a937, 0x00086839, + 0x000b22b3, 0x000dd7da, 0x001086ec, 0x00132f3c, + 0x0015d001, 0x00186897, 0x001af849, 0x001d7eb6, + 0x001ffbbe, 0x00226f41, 0x0024d8e8, 0x00273874, + 0x00298d82, 0x002bd7aa, 0x002e16d4, 0x00304af6, + 0x00327406, 0x00349203, 0x0036a416, 0x0038a893, + 0x003a9da0, 0x003c8170, 0x003e53b8, 0x0040159a, + 0x0041c816, 0x00436c92, 0x0045042c, 0x00468ff2, + 0x00481106, 0x004987fe, 0x004af466, 0x004c5599, + 0x004daae4, 0x004ef28c, 0x005029c4, 0x00514d9a, + 0x00525b57, 0x005351f7, 0x00543190, 0x0054fa43, + 0x0055ac2f, 0x00564938, 0x0056d3f7, 0x00574f3c, + 0x0057bdd7, 0x00582260, 0x00587f28, 0x0058d6b1, + 0x0059293c, 0x0059741a, 0x0059b472, 0x0059e73c, + 0x005a0976, 0x005a1870, 0x005a116e, 0x0059f224, + 0x0059b964, 0x005966ce, 0x0058f9e2, 0x005872e8, + 0x0057d407, 0x00571f82, 0x005657b0, 0x00557ecd, + 0x00549731, 0x0053a34b, 0x0052a56a, 0x00519fc6, + 0x00509482, 0x004f85a4, 0x004e74ee, 0x004d6214, + 0x004c4bd3, 0x004b314c, 0x004a1110, 0x0048e8c8, + 0x0047b5f7, 0x00467626, 0x00452690, 0x0043c405, + 0x00424b7f, 0x0040ba04, 0x003f0e53, 0x003d488b, + 0x003b688c, 0x00396eb6, 0x00375dfb, 0x00353aaa, + 0x003308ac, 0x0030ccb1, 0x002e8cf1, 0x002c4fd5, + 0x002a1be8, 0x0027f486, 0x0025d90d, 0x0023c852, + 0x0021c13b, 0x001fbf23, 0x001dbafc, 0x001badc6, + 0x00199136, 0x00176150, 0x00151b86, 0x0012bcd1, + 0x001044d1, 0x000db8d0, 0x000b1f43, 0x00087e89, + 0x0005dbe2, 0x00033b1e, 0x00009fee, 0xfffe0d82, + 0xfffb83cf, 0xfff90047, 0xfff6805a, 0xfff4019a, + 0xfff18203, 0xffeeffb2, 0xffec78ba, 0xffe9ec4d, + 0xffe75b4e, 0xffe4c71f, 0xffe23138, 0xffdf9ae6, + 0xffdd0574, 0xffda723c, 0xffd7e24a, 0xffd55567, + 0xffd2cabe, 0xffd04161, 0xffcdb890, 0xffcb306a, + 0xffc8a95c, 0xffc62406, 0xffc3a140, 0xffc12188, + 0xffbea542, 0xffbc2cc2, 0xffb9b7d2, 0xffb745f2, + 0xffb4d6ac, 0xffb268fe, 0xffaffc72, 0xffad90e8, + 0xffab263e, 0xffa8bcb8, 0xffa6547e, 0xffa3ed7b, + 0xffa187ba, 0xff9f2351, 0xff9cc055, 0xff9a5ebc, + 0xff97fe84, 0xff959f84, 0xff934146, 0xff90e37d, + 0xff8e858a, 0xff8c26c0, 0xff89c69e, 0xff876483, + 0xff84ffe4, 0xff82982b, 0xff802cb6, 0xff7dbccf, + 0xff7b47b4, 0xff78ccd0, 0xff764b6c, 0xff73c2db, + 0xff713227, 0xff6e9864, 0xff6bf470, 0xff694553, + 0xff668a0d, 0xff63c1a6, 0xff60ec34, 0xff5e0e9e, + 0xff5b30d3, 0xff585b8c, 0xff5595c9, 0xff52e1da, + 0xff5040a0, 0xff4db31c, 0xff4b3a3b, 0xff48d67e, + 0xff468850, 0xff445011, 0xff422ded, 0xff4021f9, + 0xff3e2c56, 0xff3c4cf8, 0xff3a83df, 0xff38d0ec, + 0xff3733c9, 0xff35ac14, 0xff343963, 0xff32db09, + 0xff319066, 0xff305898, 0xff2f323d, 0xff2e1bb2, + 0xff2d1369, 0xff2c18f8, 0xff2b2d2a, 0xff2a50e1, + 0xff2984f4, 0xff28c978, 0xff281e01, 0xff278245, + 0xff26f5c3, 0xff26785a, 0xff2609bf, 0xff25a9c8, + 0xff255814, 0xff2513f6, 0xff24dcc4, 0xff24b1a6, + 0xff2492b1, 0xff248093, 0xff247c0b, 0xff2485c6, + 0xff249daf, 0xff24c359, 0xff24f639, 0xff253605, + 0xff258312, 0xff25ddd5, 0xff2646e7, 0xff26be25, + 0xff274264, 0xff27d1f6, 0xff286b19, 0xff290c13, + 0xff29b30d, 0xff2a5e38, 0xff2b0bbd, 0xff2bb9a2, + 0xff29a9d2, 0xff2a53dc, 0xff2b0a5a, 0xff2bcd43, + 0xff2c9c76, 0xff2d7808, 0xff2e5ffa, 0xff2f544c, + 0xff305528, 0xff316299, 0xff327ce0, 0xff33a432, + 0xff34d8ba, 0xff361a8e, 0xff3768f8, 0xff38c2f5, + 0xff3a2784, 0xff3b9623, 0xff3d0ef4, 0xff3e9277, + 0xff4020ed, 0xff41ba14, 0xff435ccc, 0xff4507fd, + 0xff46ba84, 0xff4873ac, 0xff4a32ea, 0xff4bf7bb, + 0xff4dc17f, 0xff4f8fa0, 0xff516167, 0xff53361d, + 0xff550d79, 0xff56e7ee, 0xff58c5ff, 0xff5aa84d, + 0xff5c8e41, 0xff5e75e2, 0xff605d4d, 0xff6242b6, + 0xff6424b8, 0xff66023d, 0xff67da44, 0xff69abd6, + 0xff6b7646, 0xff6d38e8, 0xff6ef348, 0xff70a4ce, + 0xff724d0f, 0xff73eb95, 0xff757fff, 0xff770a2d, + 0xff788a20, 0xff79fff6, 0xff7b6be7, 0xff7cce52, + 0xff7e27e4, 0xff7f78fc, 0xff80c38a, 0xff820e98, + 0xff836378, 0xff84caaa, 0xff864990, 0xff87dff4, + 0xff898c30, 0xff8b4cda, 0xff8d207a, 0xff8f05cc, + 0xff90fb9b, 0xff930098, 0xff95138e, 0xff97332d, + 0xff995e2a, 0xff9b934e, 0xff9dd18c, 0xffa017e3, + 0xffa26550, 0xffa4b8e7, 0xffa711a8, 0xffa96eae, + 0xffabcefc, 0xffae31cc, 0xffb09680, 0xffb2fc82, + 0xffb5635a, 0xffb7ca52, 0xffba30a8, 0xffbc95a8, + 0xffbef8a4, 0xffc158d0, 0xffc3b557, 0xffc60d6b, + 0xffc86041, 0xffcaacb7, 0xffccf1cb, 0xffcf2e5c, + 0xffd161e8, 0xffd38c8f, 0xffd5ae88, 0xffd7c808, + 0xffd9d925, 0xffdbe1c8, 0xffdde1f3, 0xffdfd964, + 0xffe1c79b, 0xffe3abcc, 0xffe5852a, 0xffe75341, + 0xffe9162f, 0xffeace55, 0xffec7c15, 0xffee1f63, + 0xffefb7e9, 0xfff1453d, 0xfff2c6fd, 0xfff43ca8, + 0xfff5a5d4, 0xfff701ea, 0xfff850b4, 0xfff99288, + 0xfffac853, 0xfffbf2d5, 0xfffd12e6, 0xfffe2991, + 0xffff37e4, 0x00003eea, 0x00013ec4, 0x00023646, + 0x0003244d, 0x00040797, 0x0004de8c, 0x0005a734, + 0x00065fab, 0x0007068f, 0x00079c82, 0x000822fa, + 0x00089b70, 0x000907a6, 0x00096a01, 0x0009c506, + 0x000a1b37, 0x000a6e18, 0x000abe1f, 0x000b0bac, + 0x000b5701, 0x000b9f3b, 0x000be2c2, 0x000c1fff, + 0x000c5599, 0x000c829a, 0x000ca661, 0x000cc058, + 0x000cd028, 0x000cd63d, 0x000cd317, 0x000cc739, + 0x000cb36d, 0x000c98c0, 0x000c7833, 0x000c52df, + 0x000c2984, 0x000bfcf9, 0x000bcdea, 0x000b9cf7, + 0x000b6a97, 0x000b3700, 0x000b029d, 0x000acd79, + 0x000a977e, 0x000a6076, 0x000a2838, 0x0009eea1, + 0x0009b37d, 0x000976c2, 0x0009384e, 0x0008f816, + 0x0008b612, 0x0008724a, 0x00082cd5, 0x0007e5e8, + 0x00079dce, 0x000754de, 0x00070b62, 0x0006c1c6, + 0x0006786a, 0x00062fba, 0x0005e801, 0x0005a1a0, + 0x00055ce1, 0x000519fb, 0x0004d8f8, 0x000499b8, + 0x00045c30, 0x00042040, 0x0003e5c8, 0x0003acb3, + 0x000374df, 0x00033e59, 0x00030934, 0x0002d57d, + 0x0002a348, 0x000272b6, 0x000243f2, 0x00021711, + 0x0001ec3e, 0x0001c37a, 0x00019cc3, 0x00017830, + 0x000155a0, 0x00013514, 0x0001168b, 0x0000f9e6, + 0x0000df23, 0x0000c62e, 0x0000aef2, 0x00009978, + 0x000085a1, 0x0000736d, 0x000062dc, 0x000053d8, + 0x0000466c, 0x00003a62, 0x00002fd1, 0x00002681, + 0x00001e73, 0x00001792, 0x000011c9, 0x00000cf6, + 0x0000091a, 0x000005ff, 0x000003b1, 0x00000203, + 0x000000d7, 0x0000002b, 0xffffffd5, 0xffffffc0, + 0xffffffd5, 0x00000000, 0x00000015, 0x00000000, + 0x00000000, 0x00000015, 0x00000000, 0xffffffd5, + 0xffffffca, 0xffffffd5, 0x0000002b, 0x000000cc, + 0x000001e3, 0x0000037b, 0x0000059f, 0x0000086e, + 0x00000bf4, 0x0000103b, 0x00001564, 0x00001b6e, + 0x0000226f, 0x00002a68, 0x00003377, 0x00003d93, + 0x000048c5, 0x00005525, 0x000062a6, 0x00007155, + 0x0000812f, 0x00009237, 0x0000a455, 0x0000b7ab, + 0x0000cc18, 0x0000e1bd, 0x0000f878, 0x0001106c, + 0x00012981, 0x000143c2, 0x00015f30, 0x00017bb6, + 0x00019948, 0x0001b7e6, 0x0001d771, 0x0001f7bc, + 0x000218b4, 0x00023a42, 0x00025c3b, 0x00027ea0, + 0x0002a150, 0x0002c440, 0x0002e771, 0x00030aed, + 0x00032eb4, 0x000352db, 0x00037759, 0x00039c4c, + 0x0003c1ac, 0x0003e74b, 0x00040d00, 0x0004329f, + 0x000457de, 0x00047c9c, 0x0004a083, 0x0004c35e, + 0x0004e502, 0x00050543, 0x000523ec, 0x000540e7, + 0x00055c2b, 0x000575c0, 0x00058da9, 0x0005a3e4, + 0x0005b886, 0x0005cbb1, 0x0005dd65, 0x0005edcb, + 0x0005fcfa, 0x00060afc, 0x00061808, 0x000623fc, + 0x00062ec3, 0x00063849, 0x0006404b, 0x000646ac, + 0x00064b13, 0x00064d37, 0x00064cd6, 0x0006497b, + 0x000642c5, 0x0006385e, 0x000629f0, 0x00061766, + 0x000600a0, 0x0005e57d, 0x0005c63e, 0x0005a322, + 0x00057c97, 0x00055306, 0x00052711, 0x0004f96f, + 0x0004caeb, 0x00049bfc, 0x00046c96, 0x00043cbb, + 0x00040c3f, 0x0003daab, 0x0003a734, 0x000370f9, + 0x0003372d, 0x0002f944, 0x0002b6d4, 0x00026f71, + 0x000222fb, 0x0001d212, 0x00017d84, 0x00012630, + 0x0000ccda, 0x00007200, 0x0000163b, 0xffffba15, + 0xffff5da3, 0xffff0091, 0xfffea293, 0xfffe4367, + 0xfffde2da, 0xfffd809f, 0xfffd1c81, 0xfffcb66a, + 0xfffc4e90, 0xfffbe53e, 0xfffb7aa0, 0xfffb0f0a, + 0xfffaa2c9, 0xfffa3612, 0xfff9c92f, 0xfff95c2d, + 0xfff8eef4, 0xfff8817c, 0xfff813c3, 0xfff7a5d4, + 0xfff737e5, 0xfff6ca17, 0xfff65c9e, 0xfff5efbc, + 0xfff58390, 0xfff51830, 0xfff4adbc, 0xfff44435, + 0xfff3db9a, 0xfff373d6, 0xfff30cfd, 0xfff2a71c, + 0xfff24248, 0xfff1de9f, 0xfff17c44, 0xfff11b56, + 0xfff0bbea, 0xfff05e17, 0xfff00206, 0xffefa7d9, + 0xffef4f99, 0xffeef95d, 0xffeea53a, 0xffee533a, + 0xffee035e, 0xffedb5b0, 0xffed6a3c, 0xffed20f5, + 0xffecd9fe, 0xffec9555, 0xffec5305, 0xffec1319, + 0xffebd591, 0xffeb9a83, 0xffeb61f9, 0xffeb2bfe, + 0xffeaf89c, 0xffeac7ea, 0xffea99d2, 0xffea6e7e, + 0xffea45ef, 0xffea203a, 0xffe9fda0, 0xffe9decc, + 0xffe9c3de, 0xffe9ac56, 0xffe99789, 0xffe9845e, + 0xffe97295, 0xffe96219, 0xffe952ea, 0xffe944f3, + 0xffe93833, 0xffe92c9f, 0xffe92238, 0xffe918fe, + 0xffe910fb, 0xffe90a3a, 0xffe904c6, 0xffe900a0, + 0xffe8fddb, 0xffe8fc83, 0xffe8fca4, 0xffe8fe3c, + 0xffe9016c, 0xffe9061e, 0xffe90c74, 0xffe9146c, + 0xffe91e11, 0xffe929a5, 0xffe93731, 0xffe946c0, + 0xffe95833, 0xffe96b7e, 0xffe98082, 0xffe9975e, + 0xffe9affd, 0xffe9ca5e, 0xffe9e68e, 0xffea0481, + 0xffea242b, 0xffea458e, 0xffea6894, 0xffea8d52, + 0xffeab3c8, 0xffeadc0c, 0xffeb05fe, 0xffeb31a7, + 0xffeb5ede, 0xffeb8da2, 0xffebbdf4, 0xffebefbd, + 0xffec231f, 0xffec5802, 0xffec8e5e, 0xffecc61c, + 0xffecff1c, 0xffed391e, 0xffed740c, 0xffedafb1, + 0xffedebe1, 0xffee287d, 0xffee654e, 0xffeea23f, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aactab.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aactab.h new file mode 100644 index 0000000000..7cd8128231 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aactab.h @@ -0,0 +1,186 @@ +/* + * AAC data declarations + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC data declarations + * @author Oded Shimon ( ods15 ods15 dyndns org ) + * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) + */ + +#ifndef AVCODEC_AACTAB_H +#define AVCODEC_AACTAB_H + +#include "libavutil/mem.h" +#include "aac.h" + +#include + +/* NOTE: + * Tables in this file are shared by the AAC decoders and encoder + */ + +extern float ff_aac_pow2sf_tab[428]; +extern float ff_aac_pow34sf_tab[428]; + +static inline void ff_aac_tableinit(void) +{ + int i; + + /* 2^(i/16) for 0 <= i <= 15 */ + static const float exp2_lut[] = { + 1.00000000000000000000, + 1.04427378242741384032, + 1.09050773266525765921, + 1.13878863475669165370, + 1.18920711500272106672, + 1.24185781207348404859, + 1.29683955465100966593, + 1.35425554693689272830, + 1.41421356237309504880, + 1.47682614593949931139, + 1.54221082540794082361, + 1.61049033194925430818, + 1.68179283050742908606, + 1.75625216037329948311, + 1.83400808640934246349, + 1.91520656139714729387, + }; + float t1 = 8.8817841970012523233890533447265625e-16; // 2^(-50) + float t2 = 3.63797880709171295166015625e-12; // 2^(-38) + int t1_inc_cur, t2_inc_cur; + int t1_inc_prev = 0; + int t2_inc_prev = 8; + + for (i = 0; i < 428; i++) { + t1_inc_cur = 4 * (i % 4); + t2_inc_cur = (8 + 3*i) % 16; + if (t1_inc_cur < t1_inc_prev) + t1 *= 2; + if (t2_inc_cur < t2_inc_prev) + t2 *= 2; + // A much more efficient and accurate way of doing: + // ff_aac_pow2sf_tab[i] = pow(2, (i - POW_SF2_ZERO) / 4.0); + // ff_aac_pow34sf_tab[i] = pow(ff_aac_pow2sf_tab[i], 3.0/4.0); + ff_aac_pow2sf_tab[i] = t1 * exp2_lut[t1_inc_cur]; + ff_aac_pow34sf_tab[i] = t2 * exp2_lut[t2_inc_cur]; + t1_inc_prev = t1_inc_cur; + t2_inc_prev = t2_inc_cur; + } +} + +/* @name ltp_coef + * Table of the LTP coefficients + */ +static const INTFLOAT ltp_coef[8] = { + Q30(0.570829), Q30(0.696616), Q30(0.813004), Q30(0.911304), + Q30(0.984900), Q30(1.067894), Q30(1.194601), Q30(1.369533), +}; + +/* @name tns_tmp2_map + * Tables of the tmp2[] arrays of LPC coefficients used for TNS. + * The suffix _M_N[] indicate the values of coef_compress and coef_res + * respectively. + * @{ + */ +static const INTFLOAT tns_tmp2_map_1_3[4] = { + Q31(0.00000000), Q31(-0.43388373), Q31(0.64278758), Q31(0.34202015), +}; + +static const INTFLOAT tns_tmp2_map_0_3[8] = { + Q31(0.00000000), Q31(-0.43388373), Q31(-0.78183150), Q31(-0.97492790), + Q31(0.98480773), Q31( 0.86602539), Q31( 0.64278758), Q31( 0.34202015), +}; + +static const INTFLOAT tns_tmp2_map_1_4[8] = { + Q31(0.00000000), Q31(-0.20791170), Q31(-0.40673664), Q31(-0.58778524), + Q31(0.67369562), Q31( 0.52643216), Q31( 0.36124167), Q31( 0.18374951), +}; + +static const INTFLOAT tns_tmp2_map_0_4[16] = { + Q31( 0.00000000), Q31(-0.20791170), Q31(-0.40673664), Q31(-0.58778524), + Q31(-0.74314481), Q31(-0.86602539), Q31(-0.95105654), Q31(-0.99452192), + Q31( 0.99573416), Q31( 0.96182561), Q31( 0.89516330), Q31( 0.79801720), + Q31( 0.67369562), Q31( 0.52643216), Q31( 0.36124167), Q31( 0.18374951), +}; + +static const INTFLOAT * const tns_tmp2_map[4] = { + tns_tmp2_map_0_3, + tns_tmp2_map_0_4, + tns_tmp2_map_1_3, + tns_tmp2_map_1_4 +}; +// @} + +/* @name window coefficients + * @{ + */ +DECLARE_ALIGNED(32, extern float, ff_aac_kbd_long_1024)[1024]; +DECLARE_ALIGNED(32, extern float, ff_aac_kbd_short_128)[128]; +DECLARE_ALIGNED(32, extern float, ff_aac_kbd_long_960)[960]; +DECLARE_ALIGNED(32, extern float, ff_aac_kbd_short_120)[120]; +DECLARE_ALIGNED(32, extern int, ff_aac_kbd_long_1024_fixed)[1024]; +DECLARE_ALIGNED(32, extern int, ff_aac_kbd_long_512_fixed)[512]; +DECLARE_ALIGNED(32, extern int, ff_aac_kbd_short_128_fixed)[128]; +DECLARE_ALIGNED(32, extern const float, ff_aac_eld_window_512)[1920]; +DECLARE_ALIGNED(32, extern const int, ff_aac_eld_window_512_fixed)[1920]; +DECLARE_ALIGNED(32, extern const float, ff_aac_eld_window_480)[1800]; +DECLARE_ALIGNED(32, extern const int, ff_aac_eld_window_480_fixed)[1800]; +// @} + +/* @name number of scalefactor window bands for long and short transform windows respectively + * @{ + */ +extern const uint8_t ff_aac_num_swb_1024[]; +extern const uint8_t ff_aac_num_swb_960 []; +extern const uint8_t ff_aac_num_swb_512 []; +extern const uint8_t ff_aac_num_swb_480 []; +extern const uint8_t ff_aac_num_swb_128 []; +extern const uint8_t ff_aac_num_swb_120 []; +// @} + +extern const uint8_t ff_aac_pred_sfb_max []; + +extern const uint32_t ff_aac_scalefactor_code[121]; +extern const uint8_t ff_aac_scalefactor_bits[121]; + +extern const uint16_t * const ff_aac_spectral_codes[11]; +extern const uint8_t * const ff_aac_spectral_bits [11]; +extern const uint16_t ff_aac_spectral_sizes[11]; + +extern const float *ff_aac_codebook_vectors[]; +extern const float *ff_aac_codebook_vector_vals[]; +extern const uint16_t *ff_aac_codebook_vector_idx[]; + +extern const uint16_t * const ff_swb_offset_1024[13]; +extern const uint16_t * const ff_swb_offset_960 [13]; +extern const uint16_t * const ff_swb_offset_512 [13]; +extern const uint16_t * const ff_swb_offset_480 [13]; +extern const uint16_t * const ff_swb_offset_128 [13]; +extern const uint16_t * const ff_swb_offset_120 [13]; + +extern const uint8_t ff_tns_max_bands_1024[13]; +extern const uint8_t ff_tns_max_bands_512 [13]; +extern const uint8_t ff_tns_max_bands_480 [13]; +extern const uint8_t ff_tns_max_bands_128 [13]; + +#endif /* AVCODEC_AACTAB_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/aacpsdsp_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/aacpsdsp_init_aarch64.c new file mode 100644 index 0000000000..5e7e19bba4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/aacpsdsp_init_aarch64.c @@ -0,0 +1,48 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/aacpsdsp.h" + +void ff_ps_add_squares_neon(float *dst, const float (*src)[2], int n); +void ff_ps_mul_pair_single_neon(float (*dst)[2], float (*src0)[2], + float *src1, int n); +void ff_ps_hybrid_analysis_neon(float (*out)[2], float (*in)[2], + const float (*filter)[8][2], + ptrdiff_t stride, int n); +void ff_ps_stereo_interpolate_neon(float (*l)[2], float (*r)[2], + float h[2][4], float h_step[2][4], + int len); +void ff_ps_stereo_interpolate_ipdopd_neon(float (*l)[2], float (*r)[2], + float h[2][4], float h_step[2][4], + int len); + +av_cold void ff_psdsp_init_aarch64(PSDSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + s->add_squares = ff_ps_add_squares_neon; + s->mul_pair_single = ff_ps_mul_pair_single_neon; + s->hybrid_analysis = ff_ps_hybrid_analysis_neon; + s->stereo_interpolate[0] = ff_ps_stereo_interpolate_neon; + s->stereo_interpolate[1] = ff_ps_stereo_interpolate_ipdopd_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/asm-offsets.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/asm-offsets.h new file mode 100644 index 0000000000..fc38eed298 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/asm-offsets.h @@ -0,0 +1,25 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AARCH64_ASM_OFFSETS_H +#define AVCODEC_AARCH64_ASM_OFFSETS_H + +/* FFTContext */ +#define IMDCT_HALF 0x48 + +#endif /* AVCODEC_AARCH64_ASM_OFFSETS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/cabac.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/cabac.h new file mode 100644 index 0000000000..6b9b77eb30 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/cabac.h @@ -0,0 +1,104 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AARCH64_CABAC_H +#define AVCODEC_AARCH64_CABAC_H + +#include "config.h" +#if HAVE_INLINE_ASM + +#include "libavutil/attributes.h" +#include "libavutil/internal.h" +#include "libavcodec/cabac.h" + +#define get_cabac_inline get_cabac_inline_aarch64 +static av_always_inline int get_cabac_inline_aarch64(CABACContext *c, + uint8_t *const state) +{ + int bit; + void *reg_a, *reg_b, *reg_c, *tmp; + + __asm__ volatile( + "ldrb %w[bit] , [%[state]] \n\t" + "add %[r_b] , %[tables] , %[lps_off] \n\t" + "mov %w[tmp] , %w[range] \n\t" + "and %w[range] , %w[range] , #0xC0 \n\t" + "lsl %w[r_c] , %w[range] , #1 \n\t" + "add %[r_b] , %[r_b] , %w[bit], UXTW \n\t" + "ldrb %w[range] , [%[r_b], %w[r_c], SXTW] \n\t" + "sub %w[r_c] , %w[tmp] , %w[range] \n\t" + "lsl %w[tmp] , %w[r_c] , #17 \n\t" + "cmp %w[tmp] , %w[low] \n\t" + "csel %w[tmp] , %w[tmp] , wzr , cc \n\t" + "csel %w[range] , %w[r_c] , %w[range], gt \n\t" + "cinv %w[bit] , %w[bit] , cc \n\t" + "sub %w[low] , %w[low] , %w[tmp] \n\t" + "add %[r_b] , %[tables] , %[norm_off] \n\t" + "add %[r_a] , %[tables] , %[mlps_off] \n\t" + "ldrb %w[tmp] , [%[r_b], %w[range], SXTW] \n\t" + "ldrb %w[r_a] , [%[r_a], %w[bit], SXTW] \n\t" + "lsl %w[low] , %w[low] , %w[tmp] \n\t" + "lsl %w[range] , %w[range] , %w[tmp] \n\t" + "uxth %w[r_c] , %w[low] \n\t" + "strb %w[r_a] , [%[state]] \n\t" + "cbnz %w[r_c] , 2f \n\t" + "ldr %[r_c] , [%[c], %[byte]] \n\t" + "ldr %[r_a] , [%[c], %[end]] \n\t" + "ldrh %w[tmp] , [%[r_c]] \n\t" + "cmp %[r_c] , %[r_a] \n\t" + "b.ge 1f \n\t" + "add %[r_a] , %[r_c] , #2 \n\t" + "str %[r_a] , [%[c], %[byte]] \n\t" + "1: \n\t" + "sub %w[r_c] , %w[low] , #1 \n\t" + "eor %w[r_c] , %w[r_c] , %w[low] \n\t" + "rev %w[tmp] , %w[tmp] \n\t" + "lsr %w[r_c] , %w[r_c] , #15 \n\t" + "lsr %w[tmp] , %w[tmp] , #15 \n\t" + "ldrb %w[r_c] , [%[r_b], %w[r_c], SXTW] \n\t" + "mov %w[r_b] , #0xFFFF \n\t" + "mov %w[r_a] , #7 \n\t" + "sub %w[tmp] , %w[tmp] , %w[r_b] \n\t" + "sub %w[r_c] , %w[r_a] , %w[r_c] \n\t" + "lsl %w[tmp] , %w[tmp] , %w[r_c] \n\t" + "add %w[low] , %w[low] , %w[tmp] \n\t" + "2: \n\t" + : [bit]"=&r"(bit), + [low]"+&r"(c->low), + [range]"+&r"(c->range), + [r_a]"=&r"(reg_a), + [r_b]"=&r"(reg_b), + [r_c]"=&r"(reg_c), + [tmp]"=&r"(tmp) + : [c]"r"(c), + [state]"r"(state), + [tables]"r"(ff_h264_cabac_tables), + [byte]"i"(offsetof(CABACContext, bytestream)), + [end]"i"(offsetof(CABACContext, bytestream_end)), + [norm_off]"I"(H264_NORM_SHIFT_OFFSET), + [lps_off]"I"(H264_LPS_RANGE_OFFSET), + [mlps_off]"I"(H264_MLPS_STATE_OFFSET + 128) + : "memory", "cc" + ); + + return bit & 1; +} + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVCODEC_AARCH64_CABAC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/fft_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/fft_init_aarch64.c new file mode 100644 index 0000000000..db285205ab --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/fft_init_aarch64.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2009 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/aarch64/cpu.h" + +#include "libavcodec/fft.h" + +void ff_fft_permute_neon(FFTContext *s, FFTComplex *z); +void ff_fft_calc_neon(FFTContext *s, FFTComplex *z); + +void ff_imdct_calc_neon(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_imdct_half_neon(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_mdct_calc_neon(FFTContext *s, FFTSample *output, const FFTSample *input); + +av_cold void ff_fft_init_aarch64(FFTContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + s->fft_permute = ff_fft_permute_neon; + s->fft_calc = ff_fft_calc_neon; +#if CONFIG_MDCT + s->imdct_calc = ff_imdct_calc_neon; + s->imdct_half = ff_imdct_half_neon; + s->mdct_calc = ff_mdct_calc_neon; + s->mdct_permutation = FF_MDCT_PERM_INTERLEAVE; +#endif + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/fmtconvert_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/fmtconvert_init.c new file mode 100644 index 0000000000..210e74b654 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/fmtconvert_init.c @@ -0,0 +1,43 @@ +/* + * ARM optimized Format Conversion Utils + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/fmtconvert.h" + +void ff_int32_to_float_fmul_array8_neon(FmtConvertContext *c, float *dst, + const int32_t *src, const float *mul, + int len); +void ff_int32_to_float_fmul_scalar_neon(float *dst, const int32_t *src, + float mul, int len); + +av_cold void ff_fmt_convert_init_aarch64(FmtConvertContext *c, + AVCodecContext *avctx) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_neon; + c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264chroma_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264chroma_init_aarch64.c new file mode 100644 index 0000000000..fa6e0eaf15 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264chroma_init_aarch64.c @@ -0,0 +1,59 @@ +/* + * ARM NEON optimised H.264 chroma functions + * Copyright (c) 2008 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/h264chroma.h" + +#include "config.h" + +void ff_put_h264_chroma_mc8_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_put_h264_chroma_mc4_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_put_h264_chroma_mc2_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); + +void ff_avg_h264_chroma_mc8_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_avg_h264_chroma_mc4_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_avg_h264_chroma_mc2_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); + +av_cold void ff_h264chroma_init_aarch64(H264ChromaContext *c, int bit_depth) +{ + const int high_bit_depth = bit_depth > 8; + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags) && !high_bit_depth) { + c->put_h264_chroma_pixels_tab[0] = ff_put_h264_chroma_mc8_neon; + c->put_h264_chroma_pixels_tab[1] = ff_put_h264_chroma_mc4_neon; + c->put_h264_chroma_pixels_tab[2] = ff_put_h264_chroma_mc2_neon; + + c->avg_h264_chroma_pixels_tab[0] = ff_avg_h264_chroma_mc8_neon; + c->avg_h264_chroma_pixels_tab[1] = ff_avg_h264_chroma_mc4_neon; + c->avg_h264_chroma_pixels_tab[2] = ff_avg_h264_chroma_mc2_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264dsp_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264dsp_init_aarch64.c new file mode 100644 index 0000000000..d5baccf235 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264dsp_init_aarch64.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2010 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/h264dsp.h" + +void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta, int8_t *tc0); +void ff_h264_h_loop_filter_luma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta, int8_t *tc0); +void ff_h264_v_loop_filter_luma_intra_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta); +void ff_h264_h_loop_filter_luma_intra_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta); +void ff_h264_v_loop_filter_chroma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta, int8_t *tc0); +void ff_h264_h_loop_filter_chroma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta, int8_t *tc0); +void ff_h264_h_loop_filter_chroma422_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta, int8_t *tc0); +void ff_h264_v_loop_filter_chroma_intra_neon(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_chroma_intra_neon(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_chroma422_intra_neon(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_chroma_mbaff_intra_neon(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); + +void ff_weight_h264_pixels_16_neon(uint8_t *dst, ptrdiff_t stride, int height, + int log2_den, int weight, int offset); +void ff_weight_h264_pixels_8_neon(uint8_t *dst, ptrdiff_t stride, int height, + int log2_den, int weight, int offset); +void ff_weight_h264_pixels_4_neon(uint8_t *dst, ptrdiff_t stride, int height, + int log2_den, int weight, int offset); + +void ff_biweight_h264_pixels_16_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int height, int log2_den, int weightd, + int weights, int offset); +void ff_biweight_h264_pixels_8_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int height, int log2_den, int weightd, + int weights, int offset); +void ff_biweight_h264_pixels_4_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int height, int log2_den, int weightd, + int weights, int offset); + +void ff_h264_idct_add_neon(uint8_t *dst, int16_t *block, int stride); +void ff_h264_idct_dc_add_neon(uint8_t *dst, int16_t *block, int stride); +void ff_h264_idct_add16_neon(uint8_t *dst, const int *block_offset, + int16_t *block, int stride, + const uint8_t nnzc[6*8]); +void ff_h264_idct_add16intra_neon(uint8_t *dst, const int *block_offset, + int16_t *block, int stride, + const uint8_t nnzc[6*8]); +void ff_h264_idct_add8_neon(uint8_t **dest, const int *block_offset, + int16_t *block, int stride, + const uint8_t nnzc[6*8]); + +void ff_h264_idct8_add_neon(uint8_t *dst, int16_t *block, int stride); +void ff_h264_idct8_dc_add_neon(uint8_t *dst, int16_t *block, int stride); +void ff_h264_idct8_add4_neon(uint8_t *dst, const int *block_offset, + int16_t *block, int stride, + const uint8_t nnzc[6*8]); + +av_cold void ff_h264dsp_init_aarch64(H264DSPContext *c, const int bit_depth, + const int chroma_format_idc) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags) && bit_depth == 8) { + c->h264_v_loop_filter_luma = ff_h264_v_loop_filter_luma_neon; + c->h264_h_loop_filter_luma = ff_h264_h_loop_filter_luma_neon; + c->h264_v_loop_filter_luma_intra= ff_h264_v_loop_filter_luma_intra_neon; + c->h264_h_loop_filter_luma_intra= ff_h264_h_loop_filter_luma_intra_neon; + + c->h264_v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon; + c->h264_v_loop_filter_chroma_intra = ff_h264_v_loop_filter_chroma_intra_neon; + + if (chroma_format_idc <= 1) { + c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon; + c->h264_h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma_intra_neon; + c->h264_h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_mbaff_intra_neon; + } else { + c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma422_neon; + c->h264_h_loop_filter_chroma_mbaff = ff_h264_h_loop_filter_chroma_neon; + c->h264_h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma422_intra_neon; + c->h264_h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_intra_neon; + } + + c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels_16_neon; + c->weight_h264_pixels_tab[1] = ff_weight_h264_pixels_8_neon; + c->weight_h264_pixels_tab[2] = ff_weight_h264_pixels_4_neon; + + c->biweight_h264_pixels_tab[0] = ff_biweight_h264_pixels_16_neon; + c->biweight_h264_pixels_tab[1] = ff_biweight_h264_pixels_8_neon; + c->biweight_h264_pixels_tab[2] = ff_biweight_h264_pixels_4_neon; + + c->h264_idct_add = ff_h264_idct_add_neon; + c->h264_idct_dc_add = ff_h264_idct_dc_add_neon; + c->h264_idct_add16 = ff_h264_idct_add16_neon; + c->h264_idct_add16intra = ff_h264_idct_add16intra_neon; + if (chroma_format_idc <= 1) + c->h264_idct_add8 = ff_h264_idct_add8_neon; + c->h264_idct8_add = ff_h264_idct8_add_neon; + c->h264_idct8_dc_add = ff_h264_idct8_dc_add_neon; + c->h264_idct8_add4 = ff_h264_idct8_add4_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264pred_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264pred_init.c new file mode 100644 index 0000000000..b144376f90 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264pred_init.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/h264pred.h" + +void ff_pred16x16_vert_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred16x16_hor_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred16x16_plane_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred16x16_dc_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred16x16_128_dc_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred16x16_left_dc_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred16x16_top_dc_neon(uint8_t *src, ptrdiff_t stride); + +void ff_pred8x8_vert_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred8x8_hor_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred8x8_plane_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred8x8_dc_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred8x8_128_dc_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred8x8_left_dc_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred8x8_top_dc_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred8x8_l0t_dc_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred8x8_0lt_dc_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred8x8_l00_dc_neon(uint8_t *src, ptrdiff_t stride); +void ff_pred8x8_0l0_dc_neon(uint8_t *src, ptrdiff_t stride); + +static av_cold void h264_pred_init_neon(H264PredContext *h, int codec_id, + const int bit_depth, + const int chroma_format_idc) +{ + const int high_depth = bit_depth > 8; + + if (high_depth) + return; + + if (chroma_format_idc <= 1) { + h->pred8x8[VERT_PRED8x8 ] = ff_pred8x8_vert_neon; + h->pred8x8[HOR_PRED8x8 ] = ff_pred8x8_hor_neon; + if (codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8) + h->pred8x8[PLANE_PRED8x8] = ff_pred8x8_plane_neon; + h->pred8x8[DC_128_PRED8x8 ] = ff_pred8x8_128_dc_neon; + if (codec_id != AV_CODEC_ID_RV40 && codec_id != AV_CODEC_ID_VP7 && + codec_id != AV_CODEC_ID_VP8) { + h->pred8x8[DC_PRED8x8 ] = ff_pred8x8_dc_neon; + h->pred8x8[LEFT_DC_PRED8x8] = ff_pred8x8_left_dc_neon; + h->pred8x8[TOP_DC_PRED8x8 ] = ff_pred8x8_top_dc_neon; + h->pred8x8[ALZHEIMER_DC_L0T_PRED8x8] = ff_pred8x8_l0t_dc_neon; + h->pred8x8[ALZHEIMER_DC_0LT_PRED8x8] = ff_pred8x8_0lt_dc_neon; + h->pred8x8[ALZHEIMER_DC_L00_PRED8x8] = ff_pred8x8_l00_dc_neon; + h->pred8x8[ALZHEIMER_DC_0L0_PRED8x8] = ff_pred8x8_0l0_dc_neon; + } + } + + h->pred16x16[DC_PRED8x8 ] = ff_pred16x16_dc_neon; + h->pred16x16[VERT_PRED8x8 ] = ff_pred16x16_vert_neon; + h->pred16x16[HOR_PRED8x8 ] = ff_pred16x16_hor_neon; + h->pred16x16[LEFT_DC_PRED8x8] = ff_pred16x16_left_dc_neon; + h->pred16x16[TOP_DC_PRED8x8 ] = ff_pred16x16_top_dc_neon; + h->pred16x16[DC_128_PRED8x8 ] = ff_pred16x16_128_dc_neon; + if (codec_id != AV_CODEC_ID_SVQ3 && codec_id != AV_CODEC_ID_RV40 && + codec_id != AV_CODEC_ID_VP7 && codec_id != AV_CODEC_ID_VP8) + h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_plane_neon; +} + +av_cold void ff_h264_pred_init_aarch64(H264PredContext *h, int codec_id, + int bit_depth, const int chroma_format_idc) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) + h264_pred_init_neon(h, codec_id, bit_depth, chroma_format_idc); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264qpel_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264qpel_init_aarch64.c new file mode 100644 index 0000000000..77f41d9a21 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/h264qpel_init_aarch64.c @@ -0,0 +1,172 @@ +/* + * ARM NEON optimised DSP functions + * Copyright (c) 2008 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/h264qpel.h" + +void ff_put_h264_qpel16_mc00_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc10_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc20_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc30_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc01_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc11_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc21_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc31_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc02_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc12_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc22_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc32_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc03_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc13_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc23_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel16_mc33_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); + +void ff_put_h264_qpel8_mc00_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc10_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc20_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc30_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc01_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc11_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc21_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc31_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc02_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc12_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc22_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc32_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc03_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc13_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc23_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_h264_qpel8_mc33_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); + +void ff_avg_h264_qpel16_mc00_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc10_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc20_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc30_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc01_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc11_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc21_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc31_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc02_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc12_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc22_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc32_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc03_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc13_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc23_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel16_mc33_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); + +void ff_avg_h264_qpel8_mc00_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc10_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc20_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc30_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc01_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc11_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc21_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc31_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc02_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc12_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc22_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc32_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc03_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc13_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc23_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_h264_qpel8_mc33_neon(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); + +av_cold void ff_h264qpel_init_aarch64(H264QpelContext *c, int bit_depth) +{ + const int high_bit_depth = bit_depth > 8; + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags) && !high_bit_depth) { + c->put_h264_qpel_pixels_tab[0][ 0] = ff_put_h264_qpel16_mc00_neon; + c->put_h264_qpel_pixels_tab[0][ 1] = ff_put_h264_qpel16_mc10_neon; + c->put_h264_qpel_pixels_tab[0][ 2] = ff_put_h264_qpel16_mc20_neon; + c->put_h264_qpel_pixels_tab[0][ 3] = ff_put_h264_qpel16_mc30_neon; + c->put_h264_qpel_pixels_tab[0][ 4] = ff_put_h264_qpel16_mc01_neon; + c->put_h264_qpel_pixels_tab[0][ 5] = ff_put_h264_qpel16_mc11_neon; + c->put_h264_qpel_pixels_tab[0][ 6] = ff_put_h264_qpel16_mc21_neon; + c->put_h264_qpel_pixels_tab[0][ 7] = ff_put_h264_qpel16_mc31_neon; + c->put_h264_qpel_pixels_tab[0][ 8] = ff_put_h264_qpel16_mc02_neon; + c->put_h264_qpel_pixels_tab[0][ 9] = ff_put_h264_qpel16_mc12_neon; + c->put_h264_qpel_pixels_tab[0][10] = ff_put_h264_qpel16_mc22_neon; + c->put_h264_qpel_pixels_tab[0][11] = ff_put_h264_qpel16_mc32_neon; + c->put_h264_qpel_pixels_tab[0][12] = ff_put_h264_qpel16_mc03_neon; + c->put_h264_qpel_pixels_tab[0][13] = ff_put_h264_qpel16_mc13_neon; + c->put_h264_qpel_pixels_tab[0][14] = ff_put_h264_qpel16_mc23_neon; + c->put_h264_qpel_pixels_tab[0][15] = ff_put_h264_qpel16_mc33_neon; + + c->put_h264_qpel_pixels_tab[1][ 0] = ff_put_h264_qpel8_mc00_neon; + c->put_h264_qpel_pixels_tab[1][ 1] = ff_put_h264_qpel8_mc10_neon; + c->put_h264_qpel_pixels_tab[1][ 2] = ff_put_h264_qpel8_mc20_neon; + c->put_h264_qpel_pixels_tab[1][ 3] = ff_put_h264_qpel8_mc30_neon; + c->put_h264_qpel_pixels_tab[1][ 4] = ff_put_h264_qpel8_mc01_neon; + c->put_h264_qpel_pixels_tab[1][ 5] = ff_put_h264_qpel8_mc11_neon; + c->put_h264_qpel_pixels_tab[1][ 6] = ff_put_h264_qpel8_mc21_neon; + c->put_h264_qpel_pixels_tab[1][ 7] = ff_put_h264_qpel8_mc31_neon; + c->put_h264_qpel_pixels_tab[1][ 8] = ff_put_h264_qpel8_mc02_neon; + c->put_h264_qpel_pixels_tab[1][ 9] = ff_put_h264_qpel8_mc12_neon; + c->put_h264_qpel_pixels_tab[1][10] = ff_put_h264_qpel8_mc22_neon; + c->put_h264_qpel_pixels_tab[1][11] = ff_put_h264_qpel8_mc32_neon; + c->put_h264_qpel_pixels_tab[1][12] = ff_put_h264_qpel8_mc03_neon; + c->put_h264_qpel_pixels_tab[1][13] = ff_put_h264_qpel8_mc13_neon; + c->put_h264_qpel_pixels_tab[1][14] = ff_put_h264_qpel8_mc23_neon; + c->put_h264_qpel_pixels_tab[1][15] = ff_put_h264_qpel8_mc33_neon; + + c->avg_h264_qpel_pixels_tab[0][ 0] = ff_avg_h264_qpel16_mc00_neon; + c->avg_h264_qpel_pixels_tab[0][ 1] = ff_avg_h264_qpel16_mc10_neon; + c->avg_h264_qpel_pixels_tab[0][ 2] = ff_avg_h264_qpel16_mc20_neon; + c->avg_h264_qpel_pixels_tab[0][ 3] = ff_avg_h264_qpel16_mc30_neon; + c->avg_h264_qpel_pixels_tab[0][ 4] = ff_avg_h264_qpel16_mc01_neon; + c->avg_h264_qpel_pixels_tab[0][ 5] = ff_avg_h264_qpel16_mc11_neon; + c->avg_h264_qpel_pixels_tab[0][ 6] = ff_avg_h264_qpel16_mc21_neon; + c->avg_h264_qpel_pixels_tab[0][ 7] = ff_avg_h264_qpel16_mc31_neon; + c->avg_h264_qpel_pixels_tab[0][ 8] = ff_avg_h264_qpel16_mc02_neon; + c->avg_h264_qpel_pixels_tab[0][ 9] = ff_avg_h264_qpel16_mc12_neon; + c->avg_h264_qpel_pixels_tab[0][10] = ff_avg_h264_qpel16_mc22_neon; + c->avg_h264_qpel_pixels_tab[0][11] = ff_avg_h264_qpel16_mc32_neon; + c->avg_h264_qpel_pixels_tab[0][12] = ff_avg_h264_qpel16_mc03_neon; + c->avg_h264_qpel_pixels_tab[0][13] = ff_avg_h264_qpel16_mc13_neon; + c->avg_h264_qpel_pixels_tab[0][14] = ff_avg_h264_qpel16_mc23_neon; + c->avg_h264_qpel_pixels_tab[0][15] = ff_avg_h264_qpel16_mc33_neon; + + c->avg_h264_qpel_pixels_tab[1][ 0] = ff_avg_h264_qpel8_mc00_neon; + c->avg_h264_qpel_pixels_tab[1][ 1] = ff_avg_h264_qpel8_mc10_neon; + c->avg_h264_qpel_pixels_tab[1][ 2] = ff_avg_h264_qpel8_mc20_neon; + c->avg_h264_qpel_pixels_tab[1][ 3] = ff_avg_h264_qpel8_mc30_neon; + c->avg_h264_qpel_pixels_tab[1][ 4] = ff_avg_h264_qpel8_mc01_neon; + c->avg_h264_qpel_pixels_tab[1][ 5] = ff_avg_h264_qpel8_mc11_neon; + c->avg_h264_qpel_pixels_tab[1][ 6] = ff_avg_h264_qpel8_mc21_neon; + c->avg_h264_qpel_pixels_tab[1][ 7] = ff_avg_h264_qpel8_mc31_neon; + c->avg_h264_qpel_pixels_tab[1][ 8] = ff_avg_h264_qpel8_mc02_neon; + c->avg_h264_qpel_pixels_tab[1][ 9] = ff_avg_h264_qpel8_mc12_neon; + c->avg_h264_qpel_pixels_tab[1][10] = ff_avg_h264_qpel8_mc22_neon; + c->avg_h264_qpel_pixels_tab[1][11] = ff_avg_h264_qpel8_mc32_neon; + c->avg_h264_qpel_pixels_tab[1][12] = ff_avg_h264_qpel8_mc03_neon; + c->avg_h264_qpel_pixels_tab[1][13] = ff_avg_h264_qpel8_mc13_neon; + c->avg_h264_qpel_pixels_tab[1][14] = ff_avg_h264_qpel8_mc23_neon; + c->avg_h264_qpel_pixels_tab[1][15] = ff_avg_h264_qpel8_mc33_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/hpeldsp_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/hpeldsp_init_aarch64.c new file mode 100644 index 0000000000..144ae2bcc4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/hpeldsp_init_aarch64.c @@ -0,0 +1,123 @@ +/* + * ARM NEON optimised DSP functions + * Copyright (c) 2008 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/hpeldsp.h" + +void ff_put_pixels16_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_x2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_y2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_xy2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_x2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_y2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_xy2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); + +void ff_put_pixels16_x2_no_rnd_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_y2_no_rnd_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_xy2_no_rnd_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_x2_no_rnd_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_y2_no_rnd_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_xy2_no_rnd_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); + +void ff_avg_pixels16_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_x2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_y2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_xy2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_x2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_y2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_xy2_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); + +void ff_avg_pixels16_x2_no_rnd_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_y2_no_rnd_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_xy2_no_rnd_neon(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); + +av_cold void ff_hpeldsp_init_aarch64(HpelDSPContext *c, int flags) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + c->put_pixels_tab[0][0] = ff_put_pixels16_neon; + c->put_pixels_tab[0][1] = ff_put_pixels16_x2_neon; + c->put_pixels_tab[0][2] = ff_put_pixels16_y2_neon; + c->put_pixels_tab[0][3] = ff_put_pixels16_xy2_neon; + c->put_pixels_tab[1][0] = ff_put_pixels8_neon; + c->put_pixels_tab[1][1] = ff_put_pixels8_x2_neon; + c->put_pixels_tab[1][2] = ff_put_pixels8_y2_neon; + c->put_pixels_tab[1][3] = ff_put_pixels8_xy2_neon; + + c->put_no_rnd_pixels_tab[0][0] = ff_put_pixels16_neon; + c->put_no_rnd_pixels_tab[0][1] = ff_put_pixels16_x2_no_rnd_neon; + c->put_no_rnd_pixels_tab[0][2] = ff_put_pixels16_y2_no_rnd_neon; + c->put_no_rnd_pixels_tab[0][3] = ff_put_pixels16_xy2_no_rnd_neon; + c->put_no_rnd_pixels_tab[1][0] = ff_put_pixels8_neon; + c->put_no_rnd_pixels_tab[1][1] = ff_put_pixels8_x2_no_rnd_neon; + c->put_no_rnd_pixels_tab[1][2] = ff_put_pixels8_y2_no_rnd_neon; + c->put_no_rnd_pixels_tab[1][3] = ff_put_pixels8_xy2_no_rnd_neon; + + c->avg_pixels_tab[0][0] = ff_avg_pixels16_neon; + c->avg_pixels_tab[0][1] = ff_avg_pixels16_x2_neon; + c->avg_pixels_tab[0][2] = ff_avg_pixels16_y2_neon; + c->avg_pixels_tab[0][3] = ff_avg_pixels16_xy2_neon; + c->avg_pixels_tab[1][0] = ff_avg_pixels8_neon; + c->avg_pixels_tab[1][1] = ff_avg_pixels8_x2_neon; + c->avg_pixels_tab[1][2] = ff_avg_pixels8_y2_neon; + c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_neon; + + c->avg_no_rnd_pixels_tab[0] = ff_avg_pixels16_neon; + c->avg_no_rnd_pixels_tab[1] = ff_avg_pixels16_x2_no_rnd_neon; + c->avg_no_rnd_pixels_tab[2] = ff_avg_pixels16_y2_no_rnd_neon; + c->avg_no_rnd_pixels_tab[3] = ff_avg_pixels16_xy2_no_rnd_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/idct.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/idct.h new file mode 100644 index 0000000000..5c49046148 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/idct.h @@ -0,0 +1,28 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AARCH64_IDCT_H +#define AVCODEC_AARCH64_IDCT_H + +#include + +void ff_simple_idct_neon(int16_t *data); +void ff_simple_idct_put_neon(uint8_t *dest, ptrdiff_t line_size, int16_t *data); +void ff_simple_idct_add_neon(uint8_t *dest, ptrdiff_t line_size, int16_t *data); + +#endif /* AVCODEC_AARCH64_IDCT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/idctdsp_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/idctdsp_init_aarch64.c new file mode 100644 index 0000000000..0406e60830 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/idctdsp_init_aarch64.c @@ -0,0 +1,41 @@ +/* + * ARM-NEON-optimized IDCT functions + * Copyright (c) 2008 Mans Rullgard + * Copyright (c) 2017 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/idctdsp.h" +#include "idct.h" + +av_cold void ff_idctdsp_init_aarch64(IDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth) +{ + if (!avctx->lowres && !high_bit_depth) { + if (avctx->idct_algo == FF_IDCT_AUTO || + avctx->idct_algo == FF_IDCT_SIMPLEAUTO || + avctx->idct_algo == FF_IDCT_SIMPLENEON) { + c->idct_put = ff_simple_idct_put_neon; + c->idct_add = ff_simple_idct_add_neon; + c->idct = ff_simple_idct_neon; + c->perm_type = FF_IDCT_PERM_PARTTRANS; + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/mpegaudiodsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/mpegaudiodsp_init.c new file mode 100644 index 0000000000..5d966af5f4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/mpegaudiodsp_init.c @@ -0,0 +1,40 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavutil/attributes.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/mpegaudiodsp.h" +#include "config.h" + +void ff_mpadsp_apply_window_fixed_neon(int32_t *synth_buf, int32_t *window, + int *dither, int16_t *samples, ptrdiff_t incr); +void ff_mpadsp_apply_window_float_neon(float *synth_buf, float *window, + int *dither, float *samples, ptrdiff_t incr); + +av_cold void ff_mpadsp_init_aarch64(MPADSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + s->apply_window_fixed = ff_mpadsp_apply_window_fixed_neon; + s->apply_window_float = ff_mpadsp_apply_window_float_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/opusdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/opusdsp_init.c new file mode 100644 index 0000000000..cc6a1b672d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/opusdsp_init.c @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/opusdsp.h" + +void ff_opus_postfilter_neon(float *data, int period, float *gains, int len); +float ff_opus_deemphasis_neon(float *out, float *in, float coeff, int len); + +av_cold void ff_opus_dsp_init_aarch64(OpusDSP *ctx) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + ctx->postfilter = ff_opus_postfilter_neon; + ctx->deemphasis = ff_opus_deemphasis_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/rv40dsp_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/rv40dsp_init_aarch64.c new file mode 100644 index 0000000000..142705db98 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/rv40dsp_init_aarch64.c @@ -0,0 +1,48 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/rv34dsp.h" + +#include "config.h" + +void ff_put_rv40_chroma_mc8_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_put_rv40_chroma_mc4_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); + +void ff_avg_rv40_chroma_mc8_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_avg_rv40_chroma_mc4_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); + +av_cold void ff_rv40dsp_init_aarch64(RV34DSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + c->put_chroma_pixels_tab[0] = ff_put_rv40_chroma_mc8_neon; + c->put_chroma_pixels_tab[1] = ff_put_rv40_chroma_mc4_neon; + c->avg_chroma_pixels_tab[0] = ff_avg_rv40_chroma_mc8_neon; + c->avg_chroma_pixels_tab[1] = ff_avg_rv40_chroma_mc4_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/sbrdsp_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/sbrdsp_init_aarch64.c new file mode 100644 index 0000000000..9c967990df --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/sbrdsp_init_aarch64.c @@ -0,0 +1,70 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/aarch64/cpu.h" +#include "libavutil/attributes.h" +#include "libavcodec/sbrdsp.h" + +void ff_sbr_sum64x5_neon(float *z); +float ff_sbr_sum_square_neon(float (*x)[2], int n); +void ff_sbr_neg_odd_64_neon(float *x); +void ff_sbr_qmf_pre_shuffle_neon(float *z); +void ff_sbr_qmf_post_shuffle_neon(float W[32][2], const float *z); +void ff_sbr_qmf_deint_neg_neon(float *v, const float *src); +void ff_sbr_qmf_deint_bfly_neon(float *v, const float *src0, const float *src1); +void ff_sbr_hf_g_filt_neon(float (*Y)[2], const float (*X_high)[40][2], + const float *g_filt, int m_max, intptr_t ixh); +void ff_sbr_hf_gen_neon(float (*X_high)[2], const float (*X_low)[2], + const float alpha0[2], const float alpha1[2], + float bw, int start, int end); +void ff_sbr_autocorrelate_neon(const float x[40][2], float phi[3][2][2]); +void ff_sbr_hf_apply_noise_0_neon(float Y[64][2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); +void ff_sbr_hf_apply_noise_1_neon(float Y[64][2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); +void ff_sbr_hf_apply_noise_2_neon(float Y[64][2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); +void ff_sbr_hf_apply_noise_3_neon(float Y[64][2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); + +av_cold void ff_sbrdsp_init_aarch64(SBRDSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + s->sum64x5 = ff_sbr_sum64x5_neon; + s->sum_square = ff_sbr_sum_square_neon; + s->neg_odd_64 = ff_sbr_neg_odd_64_neon; + s->qmf_pre_shuffle = ff_sbr_qmf_pre_shuffle_neon; + s->qmf_post_shuffle = ff_sbr_qmf_post_shuffle_neon; + s->qmf_deint_neg = ff_sbr_qmf_deint_neg_neon; + s->qmf_deint_bfly = ff_sbr_qmf_deint_bfly_neon; + s->hf_g_filt = ff_sbr_hf_g_filt_neon; + s->hf_gen = ff_sbr_hf_gen_neon; + s->autocorrelate = ff_sbr_autocorrelate_neon; + s->hf_apply_noise[0] = ff_sbr_hf_apply_noise_0_neon; + s->hf_apply_noise[1] = ff_sbr_hf_apply_noise_1_neon; + s->hf_apply_noise[2] = ff_sbr_hf_apply_noise_2_neon; + s->hf_apply_noise[3] = ff_sbr_hf_apply_noise_3_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/synth_filter_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/synth_filter_init.c new file mode 100644 index 0000000000..767b01112a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/synth_filter_init.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/aarch64/cpu.h" +#include "libavutil/attributes.h" +#include "libavutil/internal.h" +#include "libavcodec/fft.h" +#include "libavcodec/synth_filter.h" + +#include "asm-offsets.h" + +#if HAVE_NEON || HAVE_VFP +AV_CHECK_OFFSET(FFTContext, imdct_half, IMDCT_HALF); +#endif + +void ff_synth_filter_float_neon(FFTContext *imdct, + float *synth_buf_ptr, int *synth_buf_offset, + float synth_buf2[32], const float window[512], + float out[32], const float in[32], + float scale); + +av_cold void ff_synth_filter_init_aarch64(SynthFilterContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) + s->synth_filter_float = ff_synth_filter_float_neon; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vc1dsp_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vc1dsp_init_aarch64.c new file mode 100644 index 0000000000..13dfd74940 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vc1dsp_init_aarch64.c @@ -0,0 +1,47 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/vc1dsp.h" + +#include "config.h" + +void ff_put_vc1_chroma_mc8_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_avg_vc1_chroma_mc8_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_put_vc1_chroma_mc4_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); +void ff_avg_vc1_chroma_mc4_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + int h, int x, int y); + +av_cold void ff_vc1dsp_init_aarch64(VC1DSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + dsp->put_no_rnd_vc1_chroma_pixels_tab[0] = ff_put_vc1_chroma_mc8_neon; + dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = ff_avg_vc1_chroma_mc8_neon; + dsp->put_no_rnd_vc1_chroma_pixels_tab[1] = ff_put_vc1_chroma_mc4_neon; + dsp->avg_no_rnd_vc1_chroma_pixels_tab[1] = ff_avg_vc1_chroma_mc4_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/videodsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/videodsp_init.c new file mode 100644 index 0000000000..6f667a6d3e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/videodsp_init.c @@ -0,0 +1,32 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/videodsp.h" + +void ff_prefetch_aarch64(uint8_t *mem, ptrdiff_t stride, int h); + +av_cold void ff_videodsp_init_aarch64(VideoDSPContext *ctx, int bpc) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_armv8(cpu_flags)) + ctx->prefetch = ff_prefetch_aarch64; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vorbisdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vorbisdsp_init.c new file mode 100644 index 0000000000..c796f95e61 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vorbisdsp_init.c @@ -0,0 +1,34 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/vorbisdsp.h" + +void ff_vorbis_inverse_coupling_neon(float *mag, float *ang, + intptr_t blocksize); + +av_cold void ff_vorbisdsp_init_aarch64(VorbisDSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + c->vorbis_inverse_coupling = ff_vorbis_inverse_coupling_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp8dsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp8dsp.h new file mode 100644 index 0000000000..871fed7a95 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp8dsp.h @@ -0,0 +1,75 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AARCH64_VP8DSP_H +#define AVCODEC_AARCH64_VP8DSP_H + +#include "libavcodec/vp8dsp.h" + +#define VP8_LF_Y(hv, inner, opt) \ + void ff_vp8_##hv##_loop_filter16##inner##_##opt(uint8_t *dst, \ + ptrdiff_t stride, \ + int flim_E, int flim_I, \ + int hev_thresh) + +#define VP8_LF_UV(hv, inner, opt) \ + void ff_vp8_##hv##_loop_filter8uv##inner##_##opt(uint8_t *dstU, \ + uint8_t *dstV, \ + ptrdiff_t stride, \ + int flim_E, int flim_I, \ + int hev_thresh) + +#define VP8_LF_SIMPLE(hv, opt) \ + void ff_vp8_##hv##_loop_filter16_simple_##opt(uint8_t *dst, \ + ptrdiff_t stride, \ + int flim) + +#define VP8_LF_HV(inner, opt) \ + VP8_LF_Y(h, inner, opt); \ + VP8_LF_Y(v, inner, opt); \ + VP8_LF_UV(h, inner, opt); \ + VP8_LF_UV(v, inner, opt) + +#define VP8_LF(opt) \ + VP8_LF_HV(, opt); \ + VP8_LF_HV(_inner, opt); \ + VP8_LF_SIMPLE(h, opt); \ + VP8_LF_SIMPLE(v, opt) + +#define VP8_MC(n, opt) \ + void ff_put_vp8_##n##_##opt(uint8_t *dst, ptrdiff_t dststride, \ + uint8_t *src, ptrdiff_t srcstride, \ + int h, int x, int y) + +#define VP8_EPEL(w, opt) \ + VP8_MC(pixels ## w, opt); \ + VP8_MC(epel ## w ## _h4, opt); \ + VP8_MC(epel ## w ## _h6, opt); \ + VP8_MC(epel ## w ## _v4, opt); \ + VP8_MC(epel ## w ## _h4v4, opt); \ + VP8_MC(epel ## w ## _h6v4, opt); \ + VP8_MC(epel ## w ## _v6, opt); \ + VP8_MC(epel ## w ## _h4v6, opt); \ + VP8_MC(epel ## w ## _h6v6, opt) + +#define VP8_BILIN(w, opt) \ + VP8_MC(bilin ## w ## _h, opt); \ + VP8_MC(bilin ## w ## _v, opt); \ + VP8_MC(bilin ## w ## _hv, opt) + +#endif /* AVCODEC_AARCH64_VP8DSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp8dsp_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp8dsp_init_aarch64.c new file mode 100644 index 0000000000..fc7e831d17 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp8dsp_init_aarch64.c @@ -0,0 +1,124 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/vp8dsp.h" +#include "vp8dsp.h" + +void ff_vp8_luma_dc_wht_neon(int16_t block[4][4][16], int16_t dc[16]); + +void ff_vp8_idct_add_neon(uint8_t *dst, int16_t block[16], ptrdiff_t stride); +void ff_vp8_idct_dc_add_neon(uint8_t *dst, int16_t block[16], ptrdiff_t stride); +void ff_vp8_idct_dc_add4y_neon(uint8_t *dst, int16_t block[4][16], ptrdiff_t stride); +void ff_vp8_idct_dc_add4uv_neon(uint8_t *dst, int16_t block[4][16], ptrdiff_t stride); + +VP8_LF(neon); + +VP8_EPEL(16, neon); +VP8_EPEL(8, neon); +VP8_EPEL(4, neon); + +VP8_BILIN(16, neon); +VP8_BILIN(8, neon); +VP8_BILIN(4, neon); + +av_cold void ff_vp78dsp_init_aarch64(VP8DSPContext *dsp) +{ + if (!have_neon(av_get_cpu_flags())) + return; + dsp->put_vp8_epel_pixels_tab[0][0][0] = ff_put_vp8_pixels16_neon; + dsp->put_vp8_epel_pixels_tab[0][0][2] = ff_put_vp8_epel16_h6_neon; + dsp->put_vp8_epel_pixels_tab[0][2][0] = ff_put_vp8_epel16_v6_neon; + dsp->put_vp8_epel_pixels_tab[0][2][2] = ff_put_vp8_epel16_h6v6_neon; + + dsp->put_vp8_epel_pixels_tab[1][0][0] = ff_put_vp8_pixels8_neon; + dsp->put_vp8_epel_pixels_tab[1][0][1] = ff_put_vp8_epel8_h4_neon; + dsp->put_vp8_epel_pixels_tab[1][0][2] = ff_put_vp8_epel8_h6_neon; + dsp->put_vp8_epel_pixels_tab[1][1][0] = ff_put_vp8_epel8_v4_neon; + dsp->put_vp8_epel_pixels_tab[1][1][1] = ff_put_vp8_epel8_h4v4_neon; + dsp->put_vp8_epel_pixels_tab[1][1][2] = ff_put_vp8_epel8_h6v4_neon; + dsp->put_vp8_epel_pixels_tab[1][2][0] = ff_put_vp8_epel8_v6_neon; + dsp->put_vp8_epel_pixels_tab[1][2][1] = ff_put_vp8_epel8_h4v6_neon; + dsp->put_vp8_epel_pixels_tab[1][2][2] = ff_put_vp8_epel8_h6v6_neon; + + dsp->put_vp8_epel_pixels_tab[2][0][1] = ff_put_vp8_epel4_h4_neon; + dsp->put_vp8_epel_pixels_tab[2][0][2] = ff_put_vp8_epel4_h6_neon; + dsp->put_vp8_epel_pixels_tab[2][1][0] = ff_put_vp8_epel4_v4_neon; + dsp->put_vp8_epel_pixels_tab[2][1][1] = ff_put_vp8_epel4_h4v4_neon; + dsp->put_vp8_epel_pixels_tab[2][1][2] = ff_put_vp8_epel4_h6v4_neon; + dsp->put_vp8_epel_pixels_tab[2][2][0] = ff_put_vp8_epel4_v6_neon; + dsp->put_vp8_epel_pixels_tab[2][2][1] = ff_put_vp8_epel4_h4v6_neon; + dsp->put_vp8_epel_pixels_tab[2][2][2] = ff_put_vp8_epel4_h6v6_neon; + + dsp->put_vp8_bilinear_pixels_tab[0][0][0] = ff_put_vp8_pixels16_neon; + dsp->put_vp8_bilinear_pixels_tab[0][0][1] = ff_put_vp8_bilin16_h_neon; + dsp->put_vp8_bilinear_pixels_tab[0][0][2] = ff_put_vp8_bilin16_h_neon; + dsp->put_vp8_bilinear_pixels_tab[0][1][0] = ff_put_vp8_bilin16_v_neon; + dsp->put_vp8_bilinear_pixels_tab[0][1][1] = ff_put_vp8_bilin16_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[0][1][2] = ff_put_vp8_bilin16_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[0][2][0] = ff_put_vp8_bilin16_v_neon; + dsp->put_vp8_bilinear_pixels_tab[0][2][1] = ff_put_vp8_bilin16_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[0][2][2] = ff_put_vp8_bilin16_hv_neon; + + dsp->put_vp8_bilinear_pixels_tab[1][0][0] = ff_put_vp8_pixels8_neon; + dsp->put_vp8_bilinear_pixels_tab[1][0][1] = ff_put_vp8_bilin8_h_neon; + dsp->put_vp8_bilinear_pixels_tab[1][0][2] = ff_put_vp8_bilin8_h_neon; + dsp->put_vp8_bilinear_pixels_tab[1][1][0] = ff_put_vp8_bilin8_v_neon; + dsp->put_vp8_bilinear_pixels_tab[1][1][1] = ff_put_vp8_bilin8_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[1][1][2] = ff_put_vp8_bilin8_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[1][2][0] = ff_put_vp8_bilin8_v_neon; + dsp->put_vp8_bilinear_pixels_tab[1][2][1] = ff_put_vp8_bilin8_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[1][2][2] = ff_put_vp8_bilin8_hv_neon; + + dsp->put_vp8_bilinear_pixels_tab[2][0][1] = ff_put_vp8_bilin4_h_neon; + dsp->put_vp8_bilinear_pixels_tab[2][0][2] = ff_put_vp8_bilin4_h_neon; + dsp->put_vp8_bilinear_pixels_tab[2][1][0] = ff_put_vp8_bilin4_v_neon; + dsp->put_vp8_bilinear_pixels_tab[2][1][1] = ff_put_vp8_bilin4_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[2][1][2] = ff_put_vp8_bilin4_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[2][2][0] = ff_put_vp8_bilin4_v_neon; + dsp->put_vp8_bilinear_pixels_tab[2][2][1] = ff_put_vp8_bilin4_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[2][2][2] = ff_put_vp8_bilin4_hv_neon; +} + +av_cold void ff_vp8dsp_init_aarch64(VP8DSPContext *dsp) +{ + if (!have_neon(av_get_cpu_flags())) + return; + dsp->vp8_luma_dc_wht = ff_vp8_luma_dc_wht_neon; + + dsp->vp8_idct_add = ff_vp8_idct_add_neon; + dsp->vp8_idct_dc_add = ff_vp8_idct_dc_add_neon; + dsp->vp8_idct_dc_add4y = ff_vp8_idct_dc_add4y_neon; + dsp->vp8_idct_dc_add4uv = ff_vp8_idct_dc_add4uv_neon; + + dsp->vp8_v_loop_filter16y = ff_vp8_v_loop_filter16_neon; + dsp->vp8_h_loop_filter16y = ff_vp8_h_loop_filter16_neon; + dsp->vp8_v_loop_filter8uv = ff_vp8_v_loop_filter8uv_neon; + dsp->vp8_h_loop_filter8uv = ff_vp8_h_loop_filter8uv_neon; + + dsp->vp8_v_loop_filter16y_inner = ff_vp8_v_loop_filter16_inner_neon; + dsp->vp8_h_loop_filter16y_inner = ff_vp8_h_loop_filter16_inner_neon; + dsp->vp8_v_loop_filter8uv_inner = ff_vp8_v_loop_filter8uv_inner_neon; + dsp->vp8_h_loop_filter8uv_inner = ff_vp8_h_loop_filter8uv_inner_neon; + + dsp->vp8_v_loop_filter_simple = ff_vp8_v_loop_filter16_simple_neon; + dsp->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter16_simple_neon; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init.h new file mode 100644 index 0000000000..9df1752c62 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AARCH64_VP9DSP_INIT_H +#define AVCODEC_AARCH64_VP9DSP_INIT_H + +#include "libavcodec/vp9dsp.h" + +void ff_vp9dsp_init_10bpp_aarch64(VP9DSPContext *dsp); +void ff_vp9dsp_init_12bpp_aarch64(VP9DSPContext *dsp); + +#endif /* AVCODEC_AARCH64_VP9DSP_INIT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_10bpp_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_10bpp_aarch64.c new file mode 100644 index 0000000000..0fa0d7f8c2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_10bpp_aarch64.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define BPP 10 +#define INIT_FUNC ff_vp9dsp_init_10bpp_aarch64 +#include "vp9dsp_init_16bpp_aarch64_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_12bpp_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_12bpp_aarch64.c new file mode 100644 index 0000000000..dae2232403 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_12bpp_aarch64.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define BPP 12 +#define INIT_FUNC ff_vp9dsp_init_12bpp_aarch64 +#include "vp9dsp_init_16bpp_aarch64_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_16bpp_aarch64_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_16bpp_aarch64_template.c new file mode 100644 index 0000000000..8dcfdeaaf7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_16bpp_aarch64_template.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/internal.h" +#include "libavutil/aarch64/cpu.h" +#include "vp9dsp_init.h" + +#define declare_fpel(type, sz, suffix) \ +void ff_vp9_##type##sz##suffix##_neon(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, int mx, int my) + +#define decl_mc_func(op, filter, dir, sz, bpp) \ +void ff_vp9_##op##_##filter##sz##_##dir##_##bpp##_neon(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, int mx, int my) + +#define define_8tap_2d_fn(op, filter, sz, bpp) \ +static void op##_##filter##sz##_hv_##bpp##_neon(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, \ + ptrdiff_t src_stride, \ + int h, int mx, int my) \ +{ \ + LOCAL_ALIGNED_16(uint8_t, temp, [((1 + (sz < 64)) * sz + 8) * sz * 2]); \ + /* We only need h + 7 lines, but the horizontal filter assumes an \ + * even number of rows, so filter h + 8 lines here. */ \ + ff_vp9_put_##filter##sz##_h_##bpp##_neon(temp, 2 * sz, \ + src - 3 * src_stride, src_stride, \ + h + 8, mx, 0); \ + ff_vp9_##op##_##filter##sz##_v_##bpp##_neon(dst, dst_stride, \ + temp + 3 * 2 * sz, 2 * sz, \ + h, 0, my); \ +} + +#define decl_filter_funcs(op, dir, sz, bpp) \ + decl_mc_func(op, regular, dir, sz, bpp); \ + decl_mc_func(op, sharp, dir, sz, bpp); \ + decl_mc_func(op, smooth, dir, sz, bpp) + +#define decl_mc_funcs(sz, bpp) \ + decl_filter_funcs(put, h, sz, bpp); \ + decl_filter_funcs(avg, h, sz, bpp); \ + decl_filter_funcs(put, v, sz, bpp); \ + decl_filter_funcs(avg, v, sz, bpp); \ + decl_filter_funcs(put, hv, sz, bpp); \ + decl_filter_funcs(avg, hv, sz, bpp) + +#define ff_vp9_copy32_neon ff_vp9_copy32_aarch64 +#define ff_vp9_copy64_neon ff_vp9_copy64_aarch64 +#define ff_vp9_copy128_neon ff_vp9_copy128_aarch64 + +declare_fpel(copy, 128, ); +declare_fpel(copy, 64, ); +declare_fpel(copy, 32, ); +declare_fpel(copy, 16, ); +declare_fpel(copy, 8, ); +declare_fpel(avg, 64, _16); +declare_fpel(avg, 32, _16); +declare_fpel(avg, 16, _16); +declare_fpel(avg, 8, _16); +declare_fpel(avg, 4, _16); + +decl_mc_funcs(64, BPP); +decl_mc_funcs(32, BPP); +decl_mc_funcs(16, BPP); +decl_mc_funcs(8, BPP); +decl_mc_funcs(4, BPP); + +#define define_8tap_2d_funcs(sz, bpp) \ + define_8tap_2d_fn(put, regular, sz, bpp) \ + define_8tap_2d_fn(put, sharp, sz, bpp) \ + define_8tap_2d_fn(put, smooth, sz, bpp) \ + define_8tap_2d_fn(avg, regular, sz, bpp) \ + define_8tap_2d_fn(avg, sharp, sz, bpp) \ + define_8tap_2d_fn(avg, smooth, sz, bpp) + +define_8tap_2d_funcs(64, BPP) +define_8tap_2d_funcs(32, BPP) +define_8tap_2d_funcs(16, BPP) +define_8tap_2d_funcs(8, BPP) +define_8tap_2d_funcs(4, BPP) + +static av_cold void vp9dsp_mc_init_aarch64(VP9DSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + +#define init_fpel(idx1, idx2, sz, type, suffix) \ + dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][0][0] = \ + dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][0][0] = \ + dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][0][0] = \ + dsp->mc[idx1][FILTER_BILINEAR ][idx2][0][0] = ff_vp9_##type##sz##suffix + +#define init_copy(idx, sz, suffix) \ + init_fpel(idx, 0, sz, copy, suffix) + +#define init_avg(idx, sz, suffix) \ + init_fpel(idx, 1, sz, avg, suffix) + +#define init_copy_avg(idx, sz1, sz2) \ + init_copy(idx, sz2, _neon); \ + init_avg (idx, sz1, _16_neon) + + if (have_armv8(cpu_flags)) { + init_copy(0, 128, _aarch64); + init_copy(1, 64, _aarch64); + init_copy(2, 32, _aarch64); + } + + if (have_neon(cpu_flags)) { +#define init_mc_func(idx1, idx2, op, filter, fname, dir, mx, my, sz, pfx, bpp) \ + dsp->mc[idx1][filter][idx2][mx][my] = pfx##op##_##fname##sz##_##dir##_##bpp##_neon + +#define init_mc_funcs(idx, dir, mx, my, sz, pfx, bpp) \ + init_mc_func(idx, 0, put, FILTER_8TAP_REGULAR, regular, dir, mx, my, sz, pfx, bpp); \ + init_mc_func(idx, 0, put, FILTER_8TAP_SHARP, sharp, dir, mx, my, sz, pfx, bpp); \ + init_mc_func(idx, 0, put, FILTER_8TAP_SMOOTH, smooth, dir, mx, my, sz, pfx, bpp); \ + init_mc_func(idx, 1, avg, FILTER_8TAP_REGULAR, regular, dir, mx, my, sz, pfx, bpp); \ + init_mc_func(idx, 1, avg, FILTER_8TAP_SHARP, sharp, dir, mx, my, sz, pfx, bpp); \ + init_mc_func(idx, 1, avg, FILTER_8TAP_SMOOTH, smooth, dir, mx, my, sz, pfx, bpp) + +#define init_mc_funcs_dirs(idx, sz, bpp) \ + init_mc_funcs(idx, v, 0, 1, sz, ff_vp9_, bpp); \ + init_mc_funcs(idx, h, 1, 0, sz, ff_vp9_, bpp); \ + init_mc_funcs(idx, hv, 1, 1, sz, , bpp) + + + init_avg(0, 64, _16_neon); + init_avg(1, 32, _16_neon); + init_avg(2, 16, _16_neon); + init_copy_avg(3, 8, 16); + init_copy_avg(4, 4, 8); + + init_mc_funcs_dirs(0, 64, BPP); + init_mc_funcs_dirs(1, 32, BPP); + init_mc_funcs_dirs(2, 16, BPP); + init_mc_funcs_dirs(3, 8, BPP); + init_mc_funcs_dirs(4, 4, BPP); + } +} + +#define define_itxfm2(type_a, type_b, sz, bpp) \ +void ff_vp9_##type_a##_##type_b##_##sz##x##sz##_add_##bpp##_neon(uint8_t *_dst, \ + ptrdiff_t stride, \ + int16_t *_block, int eob) +#define define_itxfm(type_a, type_b, sz, bpp) define_itxfm2(type_a, type_b, sz, bpp) + +#define define_itxfm_funcs(sz, bpp) \ + define_itxfm(idct, idct, sz, bpp); \ + define_itxfm(iadst, idct, sz, bpp); \ + define_itxfm(idct, iadst, sz, bpp); \ + define_itxfm(iadst, iadst, sz, bpp) + +define_itxfm_funcs(4, BPP); +define_itxfm_funcs(8, BPP); +define_itxfm_funcs(16, BPP); +define_itxfm(idct, idct, 32, BPP); +define_itxfm(iwht, iwht, 4, BPP); + + +static av_cold void vp9dsp_itxfm_init_aarch64(VP9DSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { +#define init_itxfm2(tx, sz, bpp) \ + dsp->itxfm_add[tx][DCT_DCT] = ff_vp9_idct_idct_##sz##_add_##bpp##_neon; \ + dsp->itxfm_add[tx][DCT_ADST] = ff_vp9_iadst_idct_##sz##_add_##bpp##_neon; \ + dsp->itxfm_add[tx][ADST_DCT] = ff_vp9_idct_iadst_##sz##_add_##bpp##_neon; \ + dsp->itxfm_add[tx][ADST_ADST] = ff_vp9_iadst_iadst_##sz##_add_##bpp##_neon +#define init_itxfm(tx, sz, bpp) init_itxfm2(tx, sz, bpp) + +#define init_idct2(tx, nm, bpp) \ + dsp->itxfm_add[tx][DCT_DCT] = \ + dsp->itxfm_add[tx][ADST_DCT] = \ + dsp->itxfm_add[tx][DCT_ADST] = \ + dsp->itxfm_add[tx][ADST_ADST] = ff_vp9_##nm##_add_##bpp##_neon +#define init_idct(tx, nm, bpp) init_idct2(tx, nm, bpp) + + init_itxfm(TX_4X4, 4x4, BPP); + init_itxfm(TX_8X8, 8x8, BPP); + init_itxfm(TX_16X16, 16x16, BPP); + init_idct(TX_32X32, idct_idct_32x32, BPP); + init_idct(4, iwht_iwht_4x4, BPP); + } +} + +#define define_loop_filter(dir, wd, size, bpp) \ +void ff_vp9_loop_filter_##dir##_##wd##_##size##_##bpp##_neon(uint8_t *dst, ptrdiff_t stride, int E, int I, int H) + +#define define_loop_filters(wd, size, bpp) \ + define_loop_filter(h, wd, size, bpp); \ + define_loop_filter(v, wd, size, bpp) + +define_loop_filters(4, 8, BPP); +define_loop_filters(8, 8, BPP); +define_loop_filters(16, 8, BPP); + +define_loop_filters(16, 16, BPP); + +define_loop_filters(44, 16, BPP); +define_loop_filters(48, 16, BPP); +define_loop_filters(84, 16, BPP); +define_loop_filters(88, 16, BPP); + +static av_cold void vp9dsp_loopfilter_init_aarch64(VP9DSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { +#define init_lpf_func_8(idx1, idx2, dir, wd, bpp) \ + dsp->loop_filter_8[idx1][idx2] = ff_vp9_loop_filter_##dir##_##wd##_8_##bpp##_neon + +#define init_lpf_func_16(idx, dir, bpp) \ + dsp->loop_filter_16[idx] = ff_vp9_loop_filter_##dir##_16_16_##bpp##_neon + +#define init_lpf_func_mix2(idx1, idx2, idx3, dir, wd, bpp) \ + dsp->loop_filter_mix2[idx1][idx2][idx3] = ff_vp9_loop_filter_##dir##_##wd##_16_##bpp##_neon + +#define init_lpf_funcs_8_wd(idx, wd, bpp) \ + init_lpf_func_8(idx, 0, h, wd, bpp); \ + init_lpf_func_8(idx, 1, v, wd, bpp) + +#define init_lpf_funcs_16(bpp) \ + init_lpf_func_16(0, h, bpp); \ + init_lpf_func_16(1, v, bpp) + +#define init_lpf_funcs_mix2_wd(idx1, idx2, wd, bpp) \ + init_lpf_func_mix2(idx1, idx2, 0, h, wd, bpp); \ + init_lpf_func_mix2(idx1, idx2, 1, v, wd, bpp) + +#define init_lpf_funcs_8(bpp) \ + init_lpf_funcs_8_wd(0, 4, bpp); \ + init_lpf_funcs_8_wd(1, 8, bpp); \ + init_lpf_funcs_8_wd(2, 16, bpp) + +#define init_lpf_funcs_mix2(bpp) \ + init_lpf_funcs_mix2_wd(0, 0, 44, bpp); \ + init_lpf_funcs_mix2_wd(0, 1, 48, bpp); \ + init_lpf_funcs_mix2_wd(1, 0, 84, bpp); \ + init_lpf_funcs_mix2_wd(1, 1, 88, bpp) + + init_lpf_funcs_8(BPP); + init_lpf_funcs_16(BPP); + init_lpf_funcs_mix2(BPP); + } +} + +av_cold void INIT_FUNC(VP9DSPContext *dsp) +{ + vp9dsp_mc_init_aarch64(dsp); + vp9dsp_loopfilter_init_aarch64(dsp); + vp9dsp_itxfm_init_aarch64(dsp); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_aarch64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_aarch64.c new file mode 100644 index 0000000000..4c699759fe --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/vp9dsp_init_aarch64.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2016 Google Inc. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/internal.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/vp9dsp.h" +#include "vp9dsp_init.h" + +#define declare_fpel(type, sz) \ +void ff_vp9_##type##sz##_neon(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, int mx, int my) + +#define declare_copy_avg(sz) \ + declare_fpel(copy, sz); \ + declare_fpel(avg , sz) + +#define decl_mc_func(op, filter, dir, sz) \ +void ff_vp9_##op##_##filter##sz##_##dir##_neon(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, int mx, int my) + +#define define_8tap_2d_fn(op, filter, sz) \ +static void op##_##filter##sz##_hv_neon(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, int mx, int my) \ +{ \ + LOCAL_ALIGNED_16(uint8_t, temp, [((1 + (sz < 64)) * sz + 8) * sz]); \ + /* We only need h + 7 lines, but the horizontal filter assumes an \ + * even number of rows, so filter h + 8 lines here. */ \ + ff_vp9_put_##filter##sz##_h_neon(temp, sz, \ + src - 3 * src_stride, src_stride, \ + h + 8, mx, 0); \ + ff_vp9_##op##_##filter##sz##_v_neon(dst, dst_stride, \ + temp + 3 * sz, sz, \ + h, 0, my); \ +} + +#define decl_filter_funcs(op, dir, sz) \ + decl_mc_func(op, regular, dir, sz); \ + decl_mc_func(op, sharp, dir, sz); \ + decl_mc_func(op, smooth, dir, sz) + +#define decl_mc_funcs(sz) \ + decl_filter_funcs(put, h, sz); \ + decl_filter_funcs(avg, h, sz); \ + decl_filter_funcs(put, v, sz); \ + decl_filter_funcs(avg, v, sz); \ + decl_filter_funcs(put, hv, sz); \ + decl_filter_funcs(avg, hv, sz) + +#define ff_vp9_copy32_neon ff_vp9_copy32_aarch64 +#define ff_vp9_copy64_neon ff_vp9_copy64_aarch64 + +declare_copy_avg(64); +declare_copy_avg(32); +declare_copy_avg(16); +declare_copy_avg(8); +declare_copy_avg(4); + +decl_mc_funcs(64); +decl_mc_funcs(32); +decl_mc_funcs(16); +decl_mc_funcs(8); +decl_mc_funcs(4); + +#define define_8tap_2d_funcs(sz) \ + define_8tap_2d_fn(put, regular, sz) \ + define_8tap_2d_fn(put, sharp, sz) \ + define_8tap_2d_fn(put, smooth, sz) \ + define_8tap_2d_fn(avg, regular, sz) \ + define_8tap_2d_fn(avg, sharp, sz) \ + define_8tap_2d_fn(avg, smooth, sz) + +define_8tap_2d_funcs(64) +define_8tap_2d_funcs(32) +define_8tap_2d_funcs(16) +define_8tap_2d_funcs(8) +define_8tap_2d_funcs(4) + +static av_cold void vp9dsp_mc_init_aarch64(VP9DSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + +#define init_fpel(idx1, idx2, sz, type, suffix) \ + dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][0][0] = \ + dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][0][0] = \ + dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][0][0] = \ + dsp->mc[idx1][FILTER_BILINEAR ][idx2][0][0] = ff_vp9_##type##sz##suffix + +#define init_copy(idx, sz, suffix) \ + init_fpel(idx, 0, sz, copy, suffix) + +#define init_avg(idx, sz, suffix) \ + init_fpel(idx, 1, sz, avg, suffix) + +#define init_copy_avg(idx, sz) \ + init_copy(idx, sz, _neon); \ + init_avg (idx, sz, _neon) + + if (have_armv8(cpu_flags)) { + init_copy(0, 64, _aarch64); + init_copy(1, 32, _aarch64); + } + + if (have_neon(cpu_flags)) { +#define init_mc_func(idx1, idx2, op, filter, fname, dir, mx, my, sz, pfx) \ + dsp->mc[idx1][filter][idx2][mx][my] = pfx##op##_##fname##sz##_##dir##_neon + +#define init_mc_funcs(idx, dir, mx, my, sz, pfx) \ + init_mc_func(idx, 0, put, FILTER_8TAP_REGULAR, regular, dir, mx, my, sz, pfx); \ + init_mc_func(idx, 0, put, FILTER_8TAP_SHARP, sharp, dir, mx, my, sz, pfx); \ + init_mc_func(idx, 0, put, FILTER_8TAP_SMOOTH, smooth, dir, mx, my, sz, pfx); \ + init_mc_func(idx, 1, avg, FILTER_8TAP_REGULAR, regular, dir, mx, my, sz, pfx); \ + init_mc_func(idx, 1, avg, FILTER_8TAP_SHARP, sharp, dir, mx, my, sz, pfx); \ + init_mc_func(idx, 1, avg, FILTER_8TAP_SMOOTH, smooth, dir, mx, my, sz, pfx) + +#define init_mc_funcs_dirs(idx, sz) \ + init_mc_funcs(idx, h, 1, 0, sz, ff_vp9_); \ + init_mc_funcs(idx, v, 0, 1, sz, ff_vp9_); \ + init_mc_funcs(idx, hv, 1, 1, sz,) + + init_avg(0, 64, _neon); + init_avg(1, 32, _neon); + init_copy_avg(2, 16); + init_copy_avg(3, 8); + init_copy_avg(4, 4); + + init_mc_funcs_dirs(0, 64); + init_mc_funcs_dirs(1, 32); + init_mc_funcs_dirs(2, 16); + init_mc_funcs_dirs(3, 8); + init_mc_funcs_dirs(4, 4); + } +} + +#define define_itxfm(type_a, type_b, sz) \ +void ff_vp9_##type_a##_##type_b##_##sz##x##sz##_add_neon(uint8_t *_dst, \ + ptrdiff_t stride, \ + int16_t *_block, int eob) + +#define define_itxfm_funcs(sz) \ + define_itxfm(idct, idct, sz); \ + define_itxfm(iadst, idct, sz); \ + define_itxfm(idct, iadst, sz); \ + define_itxfm(iadst, iadst, sz) + +define_itxfm_funcs(4); +define_itxfm_funcs(8); +define_itxfm_funcs(16); +define_itxfm(idct, idct, 32); +define_itxfm(iwht, iwht, 4); + + +static av_cold void vp9dsp_itxfm_init_aarch64(VP9DSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { +#define init_itxfm(tx, sz) \ + dsp->itxfm_add[tx][DCT_DCT] = ff_vp9_idct_idct_##sz##_add_neon; \ + dsp->itxfm_add[tx][DCT_ADST] = ff_vp9_iadst_idct_##sz##_add_neon; \ + dsp->itxfm_add[tx][ADST_DCT] = ff_vp9_idct_iadst_##sz##_add_neon; \ + dsp->itxfm_add[tx][ADST_ADST] = ff_vp9_iadst_iadst_##sz##_add_neon + +#define init_idct(tx, nm) \ + dsp->itxfm_add[tx][DCT_DCT] = \ + dsp->itxfm_add[tx][ADST_DCT] = \ + dsp->itxfm_add[tx][DCT_ADST] = \ + dsp->itxfm_add[tx][ADST_ADST] = ff_vp9_##nm##_add_neon + + init_itxfm(TX_4X4, 4x4); + init_itxfm(TX_8X8, 8x8); + init_itxfm(TX_16X16, 16x16); + init_idct(TX_32X32, idct_idct_32x32); + init_idct(4, iwht_iwht_4x4); + } +} + +#define define_loop_filter(dir, wd, len) \ +void ff_vp9_loop_filter_##dir##_##wd##_##len##_neon(uint8_t *dst, ptrdiff_t stride, int E, int I, int H) + +#define define_loop_filters(wd, len) \ + define_loop_filter(h, wd, len); \ + define_loop_filter(v, wd, len) + +define_loop_filters(4, 8); +define_loop_filters(8, 8); +define_loop_filters(16, 8); + +define_loop_filters(16, 16); + +define_loop_filters(44, 16); +define_loop_filters(48, 16); +define_loop_filters(84, 16); +define_loop_filters(88, 16); + +static av_cold void vp9dsp_loopfilter_init_aarch64(VP9DSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + dsp->loop_filter_8[0][1] = ff_vp9_loop_filter_v_4_8_neon; + dsp->loop_filter_8[0][0] = ff_vp9_loop_filter_h_4_8_neon; + dsp->loop_filter_8[1][1] = ff_vp9_loop_filter_v_8_8_neon; + dsp->loop_filter_8[1][0] = ff_vp9_loop_filter_h_8_8_neon; + dsp->loop_filter_8[2][1] = ff_vp9_loop_filter_v_16_8_neon; + dsp->loop_filter_8[2][0] = ff_vp9_loop_filter_h_16_8_neon; + + dsp->loop_filter_16[0] = ff_vp9_loop_filter_h_16_16_neon; + dsp->loop_filter_16[1] = ff_vp9_loop_filter_v_16_16_neon; + + dsp->loop_filter_mix2[0][0][0] = ff_vp9_loop_filter_h_44_16_neon; + dsp->loop_filter_mix2[0][0][1] = ff_vp9_loop_filter_v_44_16_neon; + dsp->loop_filter_mix2[0][1][0] = ff_vp9_loop_filter_h_48_16_neon; + dsp->loop_filter_mix2[0][1][1] = ff_vp9_loop_filter_v_48_16_neon; + dsp->loop_filter_mix2[1][0][0] = ff_vp9_loop_filter_h_84_16_neon; + dsp->loop_filter_mix2[1][0][1] = ff_vp9_loop_filter_v_84_16_neon; + dsp->loop_filter_mix2[1][1][0] = ff_vp9_loop_filter_h_88_16_neon; + dsp->loop_filter_mix2[1][1][1] = ff_vp9_loop_filter_v_88_16_neon; + } +} + +av_cold void ff_vp9dsp_init_aarch64(VP9DSPContext *dsp, int bpp) +{ + if (bpp == 10) { + ff_vp9dsp_init_10bpp_aarch64(dsp); + return; + } else if (bpp == 12) { + ff_vp9dsp_init_12bpp_aarch64(dsp); + return; + } else if (bpp != 8) + return; + + vp9dsp_mc_init_aarch64(dsp); + vp9dsp_loopfilter_init_aarch64(dsp); + vp9dsp_itxfm_init_aarch64(dsp); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3.c new file mode 100644 index 0000000000..6d09288eee --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3.c @@ -0,0 +1,211 @@ +/* + * Common code between the AC-3 encoder and decoder + * Copyright (c) 2000 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Common code between the AC-3 encoder and decoder. + */ + +#include "libavutil/common.h" + +#include "avcodec.h" +#include "ac3.h" + +/** + * Starting frequency coefficient bin for each critical band. + */ +const uint8_t ff_ac3_band_start_tab[AC3_CRITICAL_BANDS+1] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, + 34, 37, 40, 43, 46, 49, 55, 61, 67, 73, + 79, 85, 97, 109, 121, 133, 157, 181, 205, 229, 253 +}; + +/** + * Map each frequency coefficient bin to the critical band that contains it. + */ +const uint8_t ff_ac3_bin_to_band_tab[253] = { + 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 28, 28, 29, 29, 29, 30, 30, 30, + 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, + 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, + 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, + 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49 +}; + +static inline int calc_lowcomp1(int a, int b0, int b1, int c) +{ + if ((b0 + 256) == b1) { + a = c; + } else if (b0 > b1) { + a = FFMAX(a - 64, 0); + } + return a; +} + +static inline int calc_lowcomp(int a, int b0, int b1, int bin) +{ + if (bin < 7) { + return calc_lowcomp1(a, b0, b1, 384); + } else if (bin < 20) { + return calc_lowcomp1(a, b0, b1, 320); + } else { + return FFMAX(a - 128, 0); + } +} + +void ff_ac3_bit_alloc_calc_psd(int8_t *exp, int start, int end, int16_t *psd, + int16_t *band_psd) +{ + int bin, band; + + /* exponent mapping to PSD */ + for (bin = start; bin < end; bin++) { + psd[bin]=(3072 - (exp[bin] << 7)); + } + + /* PSD integration */ + bin = start; + band = ff_ac3_bin_to_band_tab[start]; + do { + int v = psd[bin++]; + int band_end = FFMIN(ff_ac3_band_start_tab[band+1], end); + for (; bin < band_end; bin++) { + int max = FFMAX(v, psd[bin]); + /* logadd */ + int adr = FFMIN(max - ((v + psd[bin] + 1) >> 1), 255); + v = max + ff_ac3_log_add_tab[adr]; + } + band_psd[band++] = v; + } while (end > ff_ac3_band_start_tab[band]); +} + +int ff_ac3_bit_alloc_calc_mask(AC3BitAllocParameters *s, int16_t *band_psd, + int start, int end, int fast_gain, int is_lfe, + int dba_mode, int dba_nsegs, uint8_t *dba_offsets, + uint8_t *dba_lengths, uint8_t *dba_values, + int16_t *mask) +{ + int16_t excite[AC3_CRITICAL_BANDS]; /* excitation */ + int band; + int band_start, band_end, begin, end1; + int lowcomp, fastleak, slowleak; + + if (end <= 0) + return AVERROR_INVALIDDATA; + + /* excitation function */ + band_start = ff_ac3_bin_to_band_tab[start]; + band_end = ff_ac3_bin_to_band_tab[end-1] + 1; + + if (band_start == 0) { + lowcomp = 0; + lowcomp = calc_lowcomp1(lowcomp, band_psd[0], band_psd[1], 384); + excite[0] = band_psd[0] - fast_gain - lowcomp; + lowcomp = calc_lowcomp1(lowcomp, band_psd[1], band_psd[2], 384); + excite[1] = band_psd[1] - fast_gain - lowcomp; + begin = 7; + for (band = 2; band < 7; band++) { + if (!(is_lfe && band == 6)) + lowcomp = calc_lowcomp1(lowcomp, band_psd[band], band_psd[band+1], 384); + fastleak = band_psd[band] - fast_gain; + slowleak = band_psd[band] - s->slow_gain; + excite[band] = fastleak - lowcomp; + if (!(is_lfe && band == 6)) { + if (band_psd[band] <= band_psd[band+1]) { + begin = band + 1; + break; + } + } + } + + end1 = FFMIN(band_end, 22); + for (band = begin; band < end1; band++) { + if (!(is_lfe && band == 6)) + lowcomp = calc_lowcomp(lowcomp, band_psd[band], band_psd[band+1], band); + fastleak = FFMAX(fastleak - s->fast_decay, band_psd[band] - fast_gain); + slowleak = FFMAX(slowleak - s->slow_decay, band_psd[band] - s->slow_gain); + excite[band] = FFMAX(fastleak - lowcomp, slowleak); + } + begin = 22; + } else { + /* coupling channel */ + begin = band_start; + fastleak = (s->cpl_fast_leak << 8) + 768; + slowleak = (s->cpl_slow_leak << 8) + 768; + } + + for (band = begin; band < band_end; band++) { + fastleak = FFMAX(fastleak - s->fast_decay, band_psd[band] - fast_gain); + slowleak = FFMAX(slowleak - s->slow_decay, band_psd[band] - s->slow_gain); + excite[band] = FFMAX(fastleak, slowleak); + } + + /* compute masking curve */ + + for (band = band_start; band < band_end; band++) { + int tmp = s->db_per_bit - band_psd[band]; + if (tmp > 0) { + excite[band] += tmp >> 2; + } + mask[band] = FFMAX(ff_ac3_hearing_threshold_tab[band >> s->sr_shift][s->sr_code], excite[band]); + } + + /* delta bit allocation */ + + if (dba_mode == DBA_REUSE || dba_mode == DBA_NEW) { + int i, seg, delta; + if (dba_nsegs > 8) + return -1; + band = band_start; + for (seg = 0; seg < dba_nsegs; seg++) { + band += dba_offsets[seg]; + if (band >= AC3_CRITICAL_BANDS || dba_lengths[seg] > AC3_CRITICAL_BANDS-band) + return -1; + if (dba_values[seg] >= 4) { + delta = (dba_values[seg] - 3) * 128; + } else { + delta = (dba_values[seg] - 4) * 128; + } + for (i = 0; i < dba_lengths[seg]; i++) { + mask[band++] += delta; + } + } + } + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3.h new file mode 100644 index 0000000000..f8f6a81f45 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3.h @@ -0,0 +1,263 @@ +/* + * Common code between the AC-3 encoder and decoder + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Common code between the AC-3 encoder and decoder. + */ + +#ifndef AVCODEC_AC3_H +#define AVCODEC_AC3_H + +#define AC3_MAX_CODED_FRAME_SIZE 3840 /* in bytes */ +#define EAC3_MAX_CHANNELS 16 /**< maximum number of channels in EAC3 */ +#define AC3_MAX_CHANNELS 7 /**< maximum number of channels, including coupling channel */ +#define CPL_CH 0 /**< coupling channel index */ + +#define AC3_MAX_COEFS 256 +#define AC3_BLOCK_SIZE 256 +#define AC3_MAX_BLOCKS 6 +#define AC3_FRAME_SIZE (AC3_MAX_BLOCKS * 256) +#define AC3_WINDOW_SIZE (AC3_BLOCK_SIZE * 2) +#define AC3_CRITICAL_BANDS 50 +#define AC3_MAX_CPL_BANDS 18 + +#include "libavutil/opt.h" +#include "avcodec.h" +#include "ac3tab.h" + +/* exponent encoding strategy */ +#define EXP_REUSE 0 +#define EXP_NEW 1 + +#define EXP_D15 1 +#define EXP_D25 2 +#define EXP_D45 3 + +#ifndef USE_FIXED +#define USE_FIXED 0 +#endif + +#if USE_FIXED + +#define FFT_FLOAT 0 + +#define FIXR(a) ((int)((a) * 0 + 0.5)) +#define FIXR12(a) ((int)((a) * 4096 + 0.5)) +#define FIXR15(a) ((int)((a) * 32768 + 0.5)) +#define ROUND15(x) ((x) + 16384) >> 15 + +#define AC3_RENAME(x) x ## _fixed +#define AC3_NORM(norm) (1<<24)/(norm) +#define AC3_MUL(a,b) ((((int64_t) (a)) * (b))>>12) +#define AC3_RANGE(x) ((x)|(((x)&128)<<1)) +#define AC3_HEAVY_RANGE(x) ((x)<<1) +#define AC3_DYNAMIC_RANGE(x) (x) +#define AC3_SPX_BLEND(x) (x) +#define AC3_DYNAMIC_RANGE1 0 + +typedef int INTFLOAT; +typedef int16_t SHORTFLOAT; + +#else /* USE_FIXED */ + +#define FIXR(x) ((float)(x)) +#define FIXR12(x) ((float)(x)) +#define FIXR15(x) ((float)(x)) +#define ROUND15(x) (x) + +#define AC3_RENAME(x) x +#define AC3_NORM(norm) (1.0f/(norm)) +#define AC3_MUL(a,b) ((a) * (b)) +#define AC3_RANGE(x) (dynamic_range_tab[(x)]) +#define AC3_HEAVY_RANGE(x) (ff_ac3_heavy_dynamic_range_tab[(x)]) +#define AC3_DYNAMIC_RANGE(x) (powf(x, s->drc_scale)) +#define AC3_SPX_BLEND(x) (x)* (1.0f/32) +#define AC3_DYNAMIC_RANGE1 1.0f + +typedef float INTFLOAT; +typedef float SHORTFLOAT; + +#endif /* USE_FIXED */ + +#define AC3_LEVEL(x) ROUND15((x) * FIXR15(M_SQRT1_2)) + +/* pre-defined gain values */ +#define LEVEL_PLUS_3DB M_SQRT2 +#define LEVEL_PLUS_1POINT5DB 1.1892071150027209 +#define LEVEL_MINUS_1POINT5DB 0.8408964152537145 +#define LEVEL_MINUS_3DB M_SQRT1_2 +#define LEVEL_MINUS_4POINT5DB 0.5946035575013605 +#define LEVEL_MINUS_6DB 0.5000000000000000 +#define LEVEL_MINUS_9DB 0.3535533905932738 +#define LEVEL_ZERO 0.0000000000000000 +#define LEVEL_ONE 1.0000000000000000 + +/** Delta bit allocation strategy */ +typedef enum { + DBA_REUSE = 0, + DBA_NEW, + DBA_NONE, + DBA_RESERVED +} AC3DeltaStrategy; + +/** Channel mode (audio coding mode) */ +typedef enum { + AC3_CHMODE_DUALMONO = 0, + AC3_CHMODE_MONO, + AC3_CHMODE_STEREO, + AC3_CHMODE_3F, + AC3_CHMODE_2F1R, + AC3_CHMODE_3F1R, + AC3_CHMODE_2F2R, + AC3_CHMODE_3F2R +} AC3ChannelMode; + +/** Dolby Surround mode */ +typedef enum AC3DolbySurroundMode { + AC3_DSURMOD_NOTINDICATED = 0, + AC3_DSURMOD_OFF, + AC3_DSURMOD_ON, + AC3_DSURMOD_RESERVED +} AC3DolbySurroundMode; + +/** Dolby Surround EX mode */ +typedef enum AC3DolbySurroundEXMode { + AC3_DSUREXMOD_NOTINDICATED = 0, + AC3_DSUREXMOD_OFF, + AC3_DSUREXMOD_ON, + AC3_DSUREXMOD_PLIIZ +} AC3DolbySurroundEXMode; + +/** Dolby Headphone mode */ +typedef enum AC3DolbyHeadphoneMode { + AC3_DHEADPHONMOD_NOTINDICATED = 0, + AC3_DHEADPHONMOD_OFF, + AC3_DHEADPHONMOD_ON, + AC3_DHEADPHONMOD_RESERVED +} AC3DolbyHeadphoneMode; + +/** Preferred Stereo Downmix mode */ +typedef enum AC3PreferredStereoDownmixMode { + AC3_DMIXMOD_NOTINDICATED = 0, + AC3_DMIXMOD_LTRT, + AC3_DMIXMOD_LORO, + AC3_DMIXMOD_DPLII // reserved value in A/52, but used by encoders to indicate DPL2 +} AC3PreferredStereoDownmixMode; + +typedef struct AC3BitAllocParameters { + int sr_code; + int sr_shift; + int slow_gain, slow_decay, fast_decay, db_per_bit, floor; + int cpl_fast_leak, cpl_slow_leak; +} AC3BitAllocParameters; + +/** + * @struct AC3HeaderInfo + * Coded AC-3 header values up to the lfeon element, plus derived values. + */ +typedef struct AC3HeaderInfo { + /** @name Coded elements + * @{ + */ + uint16_t sync_word; + uint16_t crc1; + uint8_t sr_code; + uint8_t bitstream_id; + uint8_t bitstream_mode; + uint8_t channel_mode; + uint8_t lfe_on; + uint8_t frame_type; + int substreamid; ///< substream identification + int center_mix_level; ///< Center mix level index + int surround_mix_level; ///< Surround mix level index + uint16_t channel_map; + int num_blocks; ///< number of audio blocks + int dolby_surround_mode; + /** @} */ + + /** @name Derived values + * @{ + */ + uint8_t sr_shift; + uint16_t sample_rate; + uint32_t bit_rate; + uint8_t channels; + uint16_t frame_size; + uint64_t channel_layout; + /** @} */ +} AC3HeaderInfo; + +typedef enum { + EAC3_FRAME_TYPE_INDEPENDENT = 0, + EAC3_FRAME_TYPE_DEPENDENT, + EAC3_FRAME_TYPE_AC3_CONVERT, + EAC3_FRAME_TYPE_RESERVED +} EAC3FrameType; + +void ff_ac3_common_init(void); + +/** + * Calculate the log power-spectral density of the input signal. + * This gives a rough estimate of signal power in the frequency domain by using + * the spectral envelope (exponents). The psd is also separately grouped + * into critical bands for use in the calculating the masking curve. + * 128 units in psd = -6 dB. The dbknee parameter in AC3BitAllocParameters + * determines the reference level. + * + * @param[in] exp frequency coefficient exponents + * @param[in] start starting bin location + * @param[in] end ending bin location + * @param[out] psd signal power for each frequency bin + * @param[out] band_psd signal power for each critical band + */ +void ff_ac3_bit_alloc_calc_psd(int8_t *exp, int start, int end, int16_t *psd, + int16_t *band_psd); + +/** + * Calculate the masking curve. + * First, the excitation is calculated using parameters in s and the signal + * power in each critical band. The excitation is compared with a predefined + * hearing threshold table to produce the masking curve. If delta bit + * allocation information is provided, it is used for adjusting the masking + * curve, usually to give a closer match to a better psychoacoustic model. + * + * @param[in] s adjustable bit allocation parameters + * @param[in] band_psd signal power for each critical band + * @param[in] start starting bin location + * @param[in] end ending bin location + * @param[in] fast_gain fast gain (estimated signal-to-mask ratio) + * @param[in] is_lfe whether or not the channel being processed is the LFE + * @param[in] dba_mode delta bit allocation mode (none, reuse, or new) + * @param[in] dba_nsegs number of delta segments + * @param[in] dba_offsets location offsets for each segment + * @param[in] dba_lengths length of each segment + * @param[in] dba_values delta bit allocation for each segment + * @param[out] mask calculated masking curve + * @return returns 0 for success, non-zero for error + */ +int ff_ac3_bit_alloc_calc_mask(AC3BitAllocParameters *s, int16_t *band_psd, + int start, int end, int fast_gain, int is_lfe, + int dba_mode, int dba_nsegs, uint8_t *dba_offsets, + uint8_t *dba_lengths, uint8_t *dba_values, + int16_t *mask); + +#endif /* AVCODEC_AC3_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser.c new file mode 100644 index 0000000000..1e203ae6ac --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser.c @@ -0,0 +1,258 @@ +/* + * AC-3 parser + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/channel_layout.h" +#include "parser.h" +#include "ac3_parser.h" +#include "ac3_parser_internal.h" +#include "aac_ac3_parser.h" +#include "get_bits.h" + + +#define AC3_HEADER_SIZE 7 + +#if CONFIG_AC3_PARSER + +static const uint8_t eac3_blocks[4] = { + 1, 2, 3, 6 +}; + +/** + * Table for center mix levels + * reference: Section 5.4.2.4 cmixlev + */ +static const uint8_t center_levels[4] = { 4, 5, 6, 5 }; + +/** + * Table for surround mix levels + * reference: Section 5.4.2.5 surmixlev + */ +static const uint8_t surround_levels[4] = { 4, 6, 7, 6 }; + + +int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) +{ + int frame_size_code; + + memset(hdr, 0, sizeof(*hdr)); + + hdr->sync_word = get_bits(gbc, 16); + if(hdr->sync_word != 0x0B77) + return AAC_AC3_PARSE_ERROR_SYNC; + + /* read ahead to bsid to distinguish between AC-3 and E-AC-3 */ + hdr->bitstream_id = show_bits_long(gbc, 29) & 0x1F; + if(hdr->bitstream_id > 16) + return AAC_AC3_PARSE_ERROR_BSID; + + hdr->num_blocks = 6; + + /* set default mix levels */ + hdr->center_mix_level = 5; // -4.5dB + hdr->surround_mix_level = 6; // -6.0dB + + /* set default dolby surround mode */ + hdr->dolby_surround_mode = AC3_DSURMOD_NOTINDICATED; + + if(hdr->bitstream_id <= 10) { + /* Normal AC-3 */ + hdr->crc1 = get_bits(gbc, 16); + hdr->sr_code = get_bits(gbc, 2); + if(hdr->sr_code == 3) + return AAC_AC3_PARSE_ERROR_SAMPLE_RATE; + + frame_size_code = get_bits(gbc, 6); + if(frame_size_code > 37) + return AAC_AC3_PARSE_ERROR_FRAME_SIZE; + + skip_bits(gbc, 5); // skip bsid, already got it + + hdr->bitstream_mode = get_bits(gbc, 3); + hdr->channel_mode = get_bits(gbc, 3); + + if(hdr->channel_mode == AC3_CHMODE_STEREO) { + hdr->dolby_surround_mode = get_bits(gbc, 2); + } else { + if((hdr->channel_mode & 1) && hdr->channel_mode != AC3_CHMODE_MONO) + hdr-> center_mix_level = center_levels[get_bits(gbc, 2)]; + if(hdr->channel_mode & 4) + hdr->surround_mix_level = surround_levels[get_bits(gbc, 2)]; + } + hdr->lfe_on = get_bits1(gbc); + + hdr->sr_shift = FFMAX(hdr->bitstream_id, 8) - 8; + hdr->sample_rate = ff_ac3_sample_rate_tab[hdr->sr_code] >> hdr->sr_shift; + hdr->bit_rate = (ff_ac3_bitrate_tab[frame_size_code>>1] * 1000) >> hdr->sr_shift; + hdr->channels = ff_ac3_channels_tab[hdr->channel_mode] + hdr->lfe_on; + hdr->frame_size = ff_ac3_frame_size_tab[frame_size_code][hdr->sr_code] * 2; + hdr->frame_type = EAC3_FRAME_TYPE_AC3_CONVERT; //EAC3_FRAME_TYPE_INDEPENDENT; + hdr->substreamid = 0; + } else { + /* Enhanced AC-3 */ + hdr->crc1 = 0; + hdr->frame_type = get_bits(gbc, 2); + if(hdr->frame_type == EAC3_FRAME_TYPE_RESERVED) + return AAC_AC3_PARSE_ERROR_FRAME_TYPE; + + hdr->substreamid = get_bits(gbc, 3); + + hdr->frame_size = (get_bits(gbc, 11) + 1) << 1; + if(hdr->frame_size < AC3_HEADER_SIZE) + return AAC_AC3_PARSE_ERROR_FRAME_SIZE; + + hdr->sr_code = get_bits(gbc, 2); + if (hdr->sr_code == 3) { + int sr_code2 = get_bits(gbc, 2); + if(sr_code2 == 3) + return AAC_AC3_PARSE_ERROR_SAMPLE_RATE; + hdr->sample_rate = ff_ac3_sample_rate_tab[sr_code2] / 2; + hdr->sr_shift = 1; + } else { + hdr->num_blocks = eac3_blocks[get_bits(gbc, 2)]; + hdr->sample_rate = ff_ac3_sample_rate_tab[hdr->sr_code]; + hdr->sr_shift = 0; + } + + hdr->channel_mode = get_bits(gbc, 3); + hdr->lfe_on = get_bits1(gbc); + + hdr->bit_rate = 8LL * hdr->frame_size * hdr->sample_rate / + (hdr->num_blocks * 256); + hdr->channels = ff_ac3_channels_tab[hdr->channel_mode] + hdr->lfe_on; + } + hdr->channel_layout = avpriv_ac3_channel_layout_tab[hdr->channel_mode]; + if (hdr->lfe_on) + hdr->channel_layout |= AV_CH_LOW_FREQUENCY; + + return 0; +} + +// TODO: Better way to pass AC3HeaderInfo fields to mov muxer. +int avpriv_ac3_parse_header(AC3HeaderInfo **phdr, const uint8_t *buf, + size_t size) +{ + GetBitContext gb; + AC3HeaderInfo *hdr; + int err; + + if (!*phdr) + *phdr = av_mallocz(sizeof(AC3HeaderInfo)); + if (!*phdr) + return AVERROR(ENOMEM); + hdr = *phdr; + + err = init_get_bits8(&gb, buf, size); + if (err < 0) + return AVERROR_INVALIDDATA; + err = ff_ac3_parse_header(&gb, hdr); + if (err < 0) + return AVERROR_INVALIDDATA; + + return get_bits_count(&gb); +} + +int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size) +{ + GetBitContext gb; + AC3HeaderInfo hdr; + int err; + + init_get_bits8(&gb, buf, size); + err = ff_ac3_parse_header(&gb, &hdr); + if (err < 0) + return AVERROR_INVALIDDATA; + + *bitstream_id = hdr.bitstream_id; + *frame_size = hdr.frame_size; + + return 0; +} + +static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info, + int *need_next_header, int *new_frame_start) +{ + int err; + union { + uint64_t u64; + uint8_t u8[8 + AV_INPUT_BUFFER_PADDING_SIZE]; + } tmp = { av_be2ne64(state) }; + AC3HeaderInfo hdr; + GetBitContext gbc; + + init_get_bits(&gbc, tmp.u8+8-AC3_HEADER_SIZE, 54); + err = ff_ac3_parse_header(&gbc, &hdr); + + if(err < 0) + return 0; + + hdr_info->sample_rate = hdr.sample_rate; + hdr_info->bit_rate = hdr.bit_rate; + hdr_info->channels = hdr.channels; + hdr_info->channel_layout = hdr.channel_layout; + hdr_info->samples = hdr.num_blocks * 256; + hdr_info->service_type = hdr.bitstream_mode; + if (hdr.bitstream_mode == 0x7 && hdr.channels > 1) + hdr_info->service_type = AV_AUDIO_SERVICE_TYPE_KARAOKE; + if(hdr.bitstream_id>10) + hdr_info->codec_id = AV_CODEC_ID_EAC3; + else if (hdr_info->codec_id == AV_CODEC_ID_NONE) + hdr_info->codec_id = AV_CODEC_ID_AC3; + + *new_frame_start = (hdr.frame_type != EAC3_FRAME_TYPE_DEPENDENT); + *need_next_header = *new_frame_start || (hdr.frame_type != EAC3_FRAME_TYPE_AC3_CONVERT); + return hdr.frame_size; +} + +static av_cold int ac3_parse_init(AVCodecParserContext *s1) +{ + AACAC3ParseContext *s = s1->priv_data; + s->header_size = AC3_HEADER_SIZE; + s->sync = ac3_sync; + return 0; +} + + +AVCodecParser ff_ac3_parser = { + .codec_ids = { AV_CODEC_ID_AC3, AV_CODEC_ID_EAC3 }, + .priv_data_size = sizeof(AACAC3ParseContext), + .parser_init = ac3_parse_init, + .parser_parse = ff_aac_ac3_parse, + .parser_close = ff_parse_close, +}; + +#else + +int avpriv_ac3_parse_header(AC3HeaderInfo **phdr, const uint8_t *buf, + size_t size) +{ + return AVERROR(ENOSYS); +} + +int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size) +{ + return AVERROR(ENOSYS); +} +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser.h new file mode 100644 index 0000000000..ff8cc4cf09 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser.h @@ -0,0 +1,36 @@ +/* + * AC-3 parser prototypes + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AC3_PARSER_H +#define AVCODEC_AC3_PARSER_H + +#include +#include + +/** + * Extract the bitstream ID and the frame size from AC-3 data. + */ +int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size); + + +#endif /* AVCODEC_AC3_PARSER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser_internal.h new file mode 100644 index 0000000000..3648802a73 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3_parser_internal.h @@ -0,0 +1,42 @@ +/* + * AC-3 parser internal code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AC3_PARSER_INTERNAL_H +#define AVCODEC_AC3_PARSER_INTERNAL_H + +#include "ac3.h" +#include "get_bits.h" + +/** + * Parse AC-3 frame header. + * Parse the header up to the lfeon element, which is the first 52 or 54 bits + * depending on the audio coding mode. + * @param[in] gbc BitContext containing the first 54 bits of the frame. + * @param[out] hdr Pointer to struct where header info is written. + * @return Returns 0 on success, -1 if there is a sync word mismatch, + * -2 if the bsid (version) element is invalid, -3 if the fscod (sample rate) + * element is invalid, or -4 if the frmsizecod (bit rate) element is invalid. + */ +int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr); + +int avpriv_ac3_parse_header(AC3HeaderInfo **hdr, const uint8_t *buf, + size_t size); + +#endif /* AVCODEC_AC3_PARSER_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec.c new file mode 100644 index 0000000000..eaa327a3ee --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec.c @@ -0,0 +1,1843 @@ +/* + * AC-3 Audio Decoder + * This code was developed as part of Google Summer of Code 2006. + * E-AC-3 support was added as part of Google Summer of Code 2007. + * + * Copyright (c) 2006 Kartikey Mahendra BHATT (bhattkm at gmail dot com) + * Copyright (c) 2007-2008 Bartlomiej Wolowiec + * Copyright (c) 2007 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "libavutil/channel_layout.h" +#include "libavutil/crc.h" +#include "libavutil/downmix_info.h" +#include "libavutil/opt.h" +#include "bswapdsp.h" +#include "internal.h" +#include "aac_ac3_parser.h" +#include "ac3_parser_internal.h" +#include "ac3dec.h" +#include "ac3dec_data.h" +#include "kbdwin.h" + +/** + * table for ungrouping 3 values in 7 bits. + * used for exponents and bap=2 mantissas + */ +static uint8_t ungroup_3_in_7_bits_tab[128][3]; + +/** tables for ungrouping mantissas */ +static int b1_mantissas[32][3]; +static int b2_mantissas[128][3]; +static int b3_mantissas[8]; +static int b4_mantissas[128][2]; +static int b5_mantissas[16]; + +/** + * Quantization table: levels for symmetric. bits for asymmetric. + * reference: Table 7.18 Mapping of bap to Quantizer + */ +static const uint8_t quantization_tab[16] = { + 0, 3, 5, 7, 11, 15, + 5, 6, 7, 8, 9, 10, 11, 12, 14, 16 +}; + +#if (!USE_FIXED) +/** dynamic range table. converts codes to scale factors. */ +static float dynamic_range_tab[256]; +float ff_ac3_heavy_dynamic_range_tab[256]; +#endif + +/** Adjustments in dB gain */ +static const float gain_levels[9] = { + LEVEL_PLUS_3DB, + LEVEL_PLUS_1POINT5DB, + LEVEL_ONE, + LEVEL_MINUS_1POINT5DB, + LEVEL_MINUS_3DB, + LEVEL_MINUS_4POINT5DB, + LEVEL_MINUS_6DB, + LEVEL_ZERO, + LEVEL_MINUS_9DB +}; + +/** Adjustments in dB gain (LFE, +10 to -21 dB) */ +static const float gain_levels_lfe[32] = { + 3.162275, 2.818382, 2.511886, 2.238719, 1.995261, 1.778278, 1.584893, + 1.412536, 1.258924, 1.122018, 1.000000, 0.891251, 0.794328, 0.707946, + 0.630957, 0.562341, 0.501187, 0.446683, 0.398107, 0.354813, 0.316227, + 0.281838, 0.251188, 0.223872, 0.199526, 0.177828, 0.158489, 0.141253, + 0.125892, 0.112201, 0.100000, 0.089125 +}; + +/** + * Table for default stereo downmixing coefficients + * reference: Section 7.8.2 Downmixing Into Two Channels + */ +static const uint8_t ac3_default_coeffs[8][5][2] = { + { { 2, 7 }, { 7, 2 }, }, + { { 4, 4 }, }, + { { 2, 7 }, { 7, 2 }, }, + { { 2, 7 }, { 5, 5 }, { 7, 2 }, }, + { { 2, 7 }, { 7, 2 }, { 6, 6 }, }, + { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 8, 8 }, }, + { { 2, 7 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, + { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, +}; + +/** + * Symmetrical Dequantization + * reference: Section 7.3.3 Expansion of Mantissas for Symmetrical Quantization + * Tables 7.19 to 7.23 + */ +static inline int +symmetric_dequant(int code, int levels) +{ + return ((code - (levels >> 1)) * (1 << 24)) / levels; +} + +/* + * Initialize tables at runtime. + */ +static av_cold void ac3_tables_init(void) +{ + int i; + + /* generate table for ungrouping 3 values in 7 bits + reference: Section 7.1.3 Exponent Decoding */ + for (i = 0; i < 128; i++) { + ungroup_3_in_7_bits_tab[i][0] = i / 25; + ungroup_3_in_7_bits_tab[i][1] = (i % 25) / 5; + ungroup_3_in_7_bits_tab[i][2] = (i % 25) % 5; + } + + /* generate grouped mantissa tables + reference: Section 7.3.5 Ungrouping of Mantissas */ + for (i = 0; i < 32; i++) { + /* bap=1 mantissas */ + b1_mantissas[i][0] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][0], 3); + b1_mantissas[i][1] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][1], 3); + b1_mantissas[i][2] = symmetric_dequant(ff_ac3_ungroup_3_in_5_bits_tab[i][2], 3); + } + for (i = 0; i < 128; i++) { + /* bap=2 mantissas */ + b2_mantissas[i][0] = symmetric_dequant(ungroup_3_in_7_bits_tab[i][0], 5); + b2_mantissas[i][1] = symmetric_dequant(ungroup_3_in_7_bits_tab[i][1], 5); + b2_mantissas[i][2] = symmetric_dequant(ungroup_3_in_7_bits_tab[i][2], 5); + + /* bap=4 mantissas */ + b4_mantissas[i][0] = symmetric_dequant(i / 11, 11); + b4_mantissas[i][1] = symmetric_dequant(i % 11, 11); + } + /* generate ungrouped mantissa tables + reference: Tables 7.21 and 7.23 */ + for (i = 0; i < 7; i++) { + /* bap=3 mantissas */ + b3_mantissas[i] = symmetric_dequant(i, 7); + } + for (i = 0; i < 15; i++) { + /* bap=5 mantissas */ + b5_mantissas[i] = symmetric_dequant(i, 15); + } + +#if (!USE_FIXED) + /* generate dynamic range table + reference: Section 7.7.1 Dynamic Range Control */ + for (i = 0; i < 256; i++) { + int v = (i >> 5) - ((i >> 7) << 3) - 5; + dynamic_range_tab[i] = powf(2.0f, v) * ((i & 0x1F) | 0x20); + } + + /* generate compr dynamic range table + reference: Section 7.7.2 Heavy Compression */ + for (i = 0; i < 256; i++) { + int v = (i >> 4) - ((i >> 7) << 4) - 4; + ff_ac3_heavy_dynamic_range_tab[i] = powf(2.0f, v) * ((i & 0xF) | 0x10); + } +#endif +} + +/** + * AVCodec initialization + */ +static av_cold int ac3_decode_init(AVCodecContext *avctx) +{ + AC3DecodeContext *s = avctx->priv_data; + int i; + + s->avctx = avctx; + + ac3_tables_init(); + ff_mdct_init(&s->imdct_256, 8, 1, 1.0); + ff_mdct_init(&s->imdct_512, 9, 1, 1.0); + AC3_RENAME(ff_kbd_window_init)(s->window, 5.0, 256); + ff_bswapdsp_init(&s->bdsp); + +#if (USE_FIXED) + s->fdsp = avpriv_alloc_fixed_dsp(avctx->flags & AV_CODEC_FLAG_BITEXACT); +#else + s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); + ff_fmt_convert_init(&s->fmt_conv, avctx); +#endif + + ff_ac3dsp_init(&s->ac3dsp, avctx->flags & AV_CODEC_FLAG_BITEXACT); + av_lfg_init(&s->dith_state, 0); + + if (USE_FIXED) + avctx->sample_fmt = AV_SAMPLE_FMT_S16P; + else + avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; + + /* allow downmixing to stereo or mono */ + if (avctx->channels > 1 && + avctx->request_channel_layout == AV_CH_LAYOUT_MONO) + avctx->channels = 1; + else if (avctx->channels > 2 && + avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) + avctx->channels = 2; + s->downmixed = 1; + + for (i = 0; i < AC3_MAX_CHANNELS; i++) { + s->xcfptr[i] = s->transform_coeffs[i]; + s->dlyptr[i] = s->delay[i]; + } + + return 0; +} + +/** + * Parse the 'sync info' and 'bit stream info' from the AC-3 bitstream. + * GetBitContext within AC3DecodeContext must point to + * the start of the synchronized AC-3 bitstream. + */ +static int ac3_parse_header(AC3DecodeContext *s) +{ + GetBitContext *gbc = &s->gbc; + int i; + + /* read the rest of the bsi. read twice for dual mono mode. */ + i = !s->channel_mode; + do { + s->dialog_normalization[(!s->channel_mode)-i] = -get_bits(gbc, 5); + if (s->dialog_normalization[(!s->channel_mode)-i] == 0) { + s->dialog_normalization[(!s->channel_mode)-i] = -31; + } + if (s->target_level != 0) { + s->level_gain[(!s->channel_mode)-i] = powf(2.0f, + (float)(s->target_level - + s->dialog_normalization[(!s->channel_mode)-i])/6.0f); + } + if (s->compression_exists[(!s->channel_mode)-i] = get_bits1(gbc)) { + s->heavy_dynamic_range[(!s->channel_mode)-i] = + AC3_HEAVY_RANGE(get_bits(gbc, 8)); + } + if (get_bits1(gbc)) + skip_bits(gbc, 8); //skip language code + if (get_bits1(gbc)) + skip_bits(gbc, 7); //skip audio production information + } while (i--); + + skip_bits(gbc, 2); //skip copyright bit and original bitstream bit + + /* skip the timecodes or parse the Alternate Bit Stream Syntax */ + if (s->bitstream_id != 6) { + if (get_bits1(gbc)) + skip_bits(gbc, 14); //skip timecode1 + if (get_bits1(gbc)) + skip_bits(gbc, 14); //skip timecode2 + } else { + if (get_bits1(gbc)) { + s->preferred_downmix = get_bits(gbc, 2); + s->center_mix_level_ltrt = get_bits(gbc, 3); + s->surround_mix_level_ltrt = av_clip(get_bits(gbc, 3), 3, 7); + s->center_mix_level = get_bits(gbc, 3); + s->surround_mix_level = av_clip(get_bits(gbc, 3), 3, 7); + } + if (get_bits1(gbc)) { + s->dolby_surround_ex_mode = get_bits(gbc, 2); + s->dolby_headphone_mode = get_bits(gbc, 2); + skip_bits(gbc, 10); // skip adconvtyp (1), xbsi2 (8), encinfo (1) + } + } + + /* skip additional bitstream info */ + if (get_bits1(gbc)) { + i = get_bits(gbc, 6); + do { + skip_bits(gbc, 8); + } while (i--); + } + + return 0; +} + +/** + * Common function to parse AC-3 or E-AC-3 frame header + */ +static int parse_frame_header(AC3DecodeContext *s) +{ + AC3HeaderInfo hdr; + int err; + + err = ff_ac3_parse_header(&s->gbc, &hdr); + if (err) + return err; + + /* get decoding parameters from header info */ + s->bit_alloc_params.sr_code = hdr.sr_code; + s->bitstream_id = hdr.bitstream_id; + s->bitstream_mode = hdr.bitstream_mode; + s->channel_mode = hdr.channel_mode; + s->lfe_on = hdr.lfe_on; + s->bit_alloc_params.sr_shift = hdr.sr_shift; + s->sample_rate = hdr.sample_rate; + s->bit_rate = hdr.bit_rate; + s->channels = hdr.channels; + s->fbw_channels = s->channels - s->lfe_on; + s->lfe_ch = s->fbw_channels + 1; + s->frame_size = hdr.frame_size; + s->superframe_size += hdr.frame_size; + s->preferred_downmix = AC3_DMIXMOD_NOTINDICATED; + s->center_mix_level = hdr.center_mix_level; + s->center_mix_level_ltrt = 4; // -3.0dB + s->surround_mix_level = hdr.surround_mix_level; + s->surround_mix_level_ltrt = 4; // -3.0dB + s->lfe_mix_level_exists = 0; + s->num_blocks = hdr.num_blocks; + s->frame_type = hdr.frame_type; + s->substreamid = hdr.substreamid; + s->dolby_surround_mode = hdr.dolby_surround_mode; + s->dolby_surround_ex_mode = AC3_DSUREXMOD_NOTINDICATED; + s->dolby_headphone_mode = AC3_DHEADPHONMOD_NOTINDICATED; + + if (s->lfe_on) { + s->start_freq[s->lfe_ch] = 0; + s->end_freq[s->lfe_ch] = 7; + s->num_exp_groups[s->lfe_ch] = 2; + s->channel_in_cpl[s->lfe_ch] = 0; + } + + if (s->bitstream_id <= 10) { + s->eac3 = 0; + s->snr_offset_strategy = 2; + s->block_switch_syntax = 1; + s->dither_flag_syntax = 1; + s->bit_allocation_syntax = 1; + s->fast_gain_syntax = 0; + s->first_cpl_leak = 0; + s->dba_syntax = 1; + s->skip_syntax = 1; + memset(s->channel_uses_aht, 0, sizeof(s->channel_uses_aht)); + return ac3_parse_header(s); + } else if (CONFIG_EAC3_DECODER) { + s->eac3 = 1; + return ff_eac3_parse_header(s); + } else { + av_log(s->avctx, AV_LOG_ERROR, "E-AC-3 support not compiled in\n"); + return AVERROR(ENOSYS); + } +} + +/** + * Set stereo downmixing coefficients based on frame header info. + * reference: Section 7.8.2 Downmixing Into Two Channels + */ +static int set_downmix_coeffs(AC3DecodeContext *s) +{ + int i; + float cmix = gain_levels[s-> center_mix_level]; + float smix = gain_levels[s->surround_mix_level]; + float norm0, norm1; + float downmix_coeffs[2][AC3_MAX_CHANNELS]; + + if (!s->downmix_coeffs[0]) { + s->downmix_coeffs[0] = av_malloc_array(2 * AC3_MAX_CHANNELS, + sizeof(**s->downmix_coeffs)); + if (!s->downmix_coeffs[0]) + return AVERROR(ENOMEM); + s->downmix_coeffs[1] = s->downmix_coeffs[0] + AC3_MAX_CHANNELS; + } + + for (i = 0; i < s->fbw_channels; i++) { + downmix_coeffs[0][i] = gain_levels[ac3_default_coeffs[s->channel_mode][i][0]]; + downmix_coeffs[1][i] = gain_levels[ac3_default_coeffs[s->channel_mode][i][1]]; + } + if (s->channel_mode > 1 && s->channel_mode & 1) { + downmix_coeffs[0][1] = downmix_coeffs[1][1] = cmix; + } + if (s->channel_mode == AC3_CHMODE_2F1R || s->channel_mode == AC3_CHMODE_3F1R) { + int nf = s->channel_mode - 2; + downmix_coeffs[0][nf] = downmix_coeffs[1][nf] = smix * LEVEL_MINUS_3DB; + } + if (s->channel_mode == AC3_CHMODE_2F2R || s->channel_mode == AC3_CHMODE_3F2R) { + int nf = s->channel_mode - 4; + downmix_coeffs[0][nf] = downmix_coeffs[1][nf+1] = smix; + } + + /* renormalize */ + norm0 = norm1 = 0.0; + for (i = 0; i < s->fbw_channels; i++) { + norm0 += downmix_coeffs[0][i]; + norm1 += downmix_coeffs[1][i]; + } + norm0 = 1.0f / norm0; + norm1 = 1.0f / norm1; + for (i = 0; i < s->fbw_channels; i++) { + downmix_coeffs[0][i] *= norm0; + downmix_coeffs[1][i] *= norm1; + } + + if (s->output_mode == AC3_CHMODE_MONO) { + for (i = 0; i < s->fbw_channels; i++) + downmix_coeffs[0][i] = (downmix_coeffs[0][i] + + downmix_coeffs[1][i]) * LEVEL_MINUS_3DB; + } + for (i = 0; i < s->fbw_channels; i++) { + s->downmix_coeffs[0][i] = FIXR12(downmix_coeffs[0][i]); + s->downmix_coeffs[1][i] = FIXR12(downmix_coeffs[1][i]); + } + + return 0; +} + +/** + * Decode the grouped exponents according to exponent strategy. + * reference: Section 7.1.3 Exponent Decoding + */ +static int decode_exponents(AC3DecodeContext *s, + GetBitContext *gbc, int exp_strategy, int ngrps, + uint8_t absexp, int8_t *dexps) +{ + int i, j, grp, group_size; + int dexp[256]; + int expacc, prevexp; + + /* unpack groups */ + group_size = exp_strategy + (exp_strategy == EXP_D45); + for (grp = 0, i = 0; grp < ngrps; grp++) { + expacc = get_bits(gbc, 7); + if (expacc >= 125) { + av_log(s->avctx, AV_LOG_ERROR, "expacc %d is out-of-range\n", expacc); + return AVERROR_INVALIDDATA; + } + dexp[i++] = ungroup_3_in_7_bits_tab[expacc][0]; + dexp[i++] = ungroup_3_in_7_bits_tab[expacc][1]; + dexp[i++] = ungroup_3_in_7_bits_tab[expacc][2]; + } + + /* convert to absolute exps and expand groups */ + prevexp = absexp; + for (i = 0, j = 0; i < ngrps * 3; i++) { + prevexp += dexp[i] - 2; + if (prevexp > 24U) { + av_log(s->avctx, AV_LOG_ERROR, "exponent %d is out-of-range\n", prevexp); + return AVERROR_INVALIDDATA; + } + switch (group_size) { + case 4: dexps[j++] = prevexp; + dexps[j++] = prevexp; + case 2: dexps[j++] = prevexp; + case 1: dexps[j++] = prevexp; + } + } + return 0; +} + +/** + * Generate transform coefficients for each coupled channel in the coupling + * range using the coupling coefficients and coupling coordinates. + * reference: Section 7.4.3 Coupling Coordinate Format + */ +static void calc_transform_coeffs_cpl(AC3DecodeContext *s) +{ + int bin, band, ch; + + bin = s->start_freq[CPL_CH]; + for (band = 0; band < s->num_cpl_bands; band++) { + int band_start = bin; + int band_end = bin + s->cpl_band_sizes[band]; + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (s->channel_in_cpl[ch]) { + int cpl_coord = s->cpl_coords[ch][band] << 5; + for (bin = band_start; bin < band_end; bin++) { + s->fixed_coeffs[ch][bin] = + MULH(s->fixed_coeffs[CPL_CH][bin] * (1 << 4), cpl_coord); + } + if (ch == 2 && s->phase_flags[band]) { + for (bin = band_start; bin < band_end; bin++) + s->fixed_coeffs[2][bin] = -s->fixed_coeffs[2][bin]; + } + } + } + bin = band_end; + } +} + +/** + * Grouped mantissas for 3-level 5-level and 11-level quantization + */ +typedef struct mant_groups { + int b1_mant[2]; + int b2_mant[2]; + int b4_mant; + int b1; + int b2; + int b4; +} mant_groups; + +/** + * Decode the transform coefficients for a particular channel + * reference: Section 7.3 Quantization and Decoding of Mantissas + */ +static void ac3_decode_transform_coeffs_ch(AC3DecodeContext *s, int ch_index, mant_groups *m) +{ + int start_freq = s->start_freq[ch_index]; + int end_freq = s->end_freq[ch_index]; + uint8_t *baps = s->bap[ch_index]; + int8_t *exps = s->dexps[ch_index]; + int32_t *coeffs = s->fixed_coeffs[ch_index]; + int dither = (ch_index == CPL_CH) || s->dither_flag[ch_index]; + GetBitContext *gbc = &s->gbc; + int freq; + + for (freq = start_freq; freq < end_freq; freq++) { + int bap = baps[freq]; + int mantissa; + switch (bap) { + case 0: + /* random noise with approximate range of -0.707 to 0.707 */ + if (dither) + mantissa = (((av_lfg_get(&s->dith_state)>>8)*181)>>8) - 5931008; + else + mantissa = 0; + break; + case 1: + if (m->b1) { + m->b1--; + mantissa = m->b1_mant[m->b1]; + } else { + int bits = get_bits(gbc, 5); + mantissa = b1_mantissas[bits][0]; + m->b1_mant[1] = b1_mantissas[bits][1]; + m->b1_mant[0] = b1_mantissas[bits][2]; + m->b1 = 2; + } + break; + case 2: + if (m->b2) { + m->b2--; + mantissa = m->b2_mant[m->b2]; + } else { + int bits = get_bits(gbc, 7); + mantissa = b2_mantissas[bits][0]; + m->b2_mant[1] = b2_mantissas[bits][1]; + m->b2_mant[0] = b2_mantissas[bits][2]; + m->b2 = 2; + } + break; + case 3: + mantissa = b3_mantissas[get_bits(gbc, 3)]; + break; + case 4: + if (m->b4) { + m->b4 = 0; + mantissa = m->b4_mant; + } else { + int bits = get_bits(gbc, 7); + mantissa = b4_mantissas[bits][0]; + m->b4_mant = b4_mantissas[bits][1]; + m->b4 = 1; + } + break; + case 5: + mantissa = b5_mantissas[get_bits(gbc, 4)]; + break; + default: /* 6 to 15 */ + /* Shift mantissa and sign-extend it. */ + if (bap > 15) { + av_log(s->avctx, AV_LOG_ERROR, "bap %d is invalid in plain AC-3\n", bap); + bap = 15; + } + mantissa = (unsigned)get_sbits(gbc, quantization_tab[bap]) << (24 - quantization_tab[bap]); + break; + } + coeffs[freq] = mantissa >> exps[freq]; + } +} + +/** + * Remove random dithering from coupling range coefficients with zero-bit + * mantissas for coupled channels which do not use dithering. + * reference: Section 7.3.4 Dither for Zero Bit Mantissas (bap=0) + */ +static void remove_dithering(AC3DecodeContext *s) { + int ch, i; + + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (!s->dither_flag[ch] && s->channel_in_cpl[ch]) { + for (i = s->start_freq[CPL_CH]; i < s->end_freq[CPL_CH]; i++) { + if (!s->bap[CPL_CH][i]) + s->fixed_coeffs[ch][i] = 0; + } + } + } +} + +static inline void decode_transform_coeffs_ch(AC3DecodeContext *s, int blk, + int ch, mant_groups *m) +{ + if (!s->channel_uses_aht[ch]) { + ac3_decode_transform_coeffs_ch(s, ch, m); + } else { + /* if AHT is used, mantissas for all blocks are encoded in the first + block of the frame. */ + int bin; + if (CONFIG_EAC3_DECODER && !blk) + ff_eac3_decode_transform_coeffs_aht_ch(s, ch); + for (bin = s->start_freq[ch]; bin < s->end_freq[ch]; bin++) { + s->fixed_coeffs[ch][bin] = s->pre_mantissa[ch][bin][blk] >> s->dexps[ch][bin]; + } + } +} + +/** + * Decode the transform coefficients. + */ +static inline void decode_transform_coeffs(AC3DecodeContext *s, int blk) +{ + int ch, end; + int got_cplchan = 0; + mant_groups m; + + m.b1 = m.b2 = m.b4 = 0; + + for (ch = 1; ch <= s->channels; ch++) { + /* transform coefficients for full-bandwidth channel */ + decode_transform_coeffs_ch(s, blk, ch, &m); + /* transform coefficients for coupling channel come right after the + coefficients for the first coupled channel*/ + if (s->channel_in_cpl[ch]) { + if (!got_cplchan) { + decode_transform_coeffs_ch(s, blk, CPL_CH, &m); + calc_transform_coeffs_cpl(s); + got_cplchan = 1; + } + end = s->end_freq[CPL_CH]; + } else { + end = s->end_freq[ch]; + } + do + s->fixed_coeffs[ch][end] = 0; + while (++end < 256); + } + + /* zero the dithered coefficients for appropriate channels */ + remove_dithering(s); +} + +/** + * Stereo rematrixing. + * reference: Section 7.5.4 Rematrixing : Decoding Technique + */ +static void do_rematrixing(AC3DecodeContext *s) +{ + int bnd, i; + int end, bndend; + + end = FFMIN(s->end_freq[1], s->end_freq[2]); + + for (bnd = 0; bnd < s->num_rematrixing_bands; bnd++) { + if (s->rematrixing_flags[bnd]) { + bndend = FFMIN(end, ff_ac3_rematrix_band_tab[bnd + 1]); + for (i = ff_ac3_rematrix_band_tab[bnd]; i < bndend; i++) { + int tmp0 = s->fixed_coeffs[1][i]; + s->fixed_coeffs[1][i] += s->fixed_coeffs[2][i]; + s->fixed_coeffs[2][i] = tmp0 - s->fixed_coeffs[2][i]; + } + } + } +} + +/** + * Inverse MDCT Transform. + * Convert frequency domain coefficients to time-domain audio samples. + * reference: Section 7.9.4 Transformation Equations + */ +static inline void do_imdct(AC3DecodeContext *s, int channels, int offset) +{ + int ch; + + for (ch = 1; ch <= channels; ch++) { + if (s->block_switch[ch]) { + int i; + FFTSample *x = s->tmp_output + 128; + for (i = 0; i < 128; i++) + x[i] = s->transform_coeffs[ch][2 * i]; + s->imdct_256.imdct_half(&s->imdct_256, s->tmp_output, x); +#if USE_FIXED + s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1 + offset], + s->tmp_output, s->window, 128, 8); +#else + s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1 + offset], + s->tmp_output, s->window, 128); +#endif + for (i = 0; i < 128; i++) + x[i] = s->transform_coeffs[ch][2 * i + 1]; + s->imdct_256.imdct_half(&s->imdct_256, s->delay[ch - 1 + offset], x); + } else { + s->imdct_512.imdct_half(&s->imdct_512, s->tmp_output, s->transform_coeffs[ch]); +#if USE_FIXED + s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1 + offset], + s->tmp_output, s->window, 128, 8); +#else + s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1 + offset], + s->tmp_output, s->window, 128); +#endif + memcpy(s->delay[ch - 1 + offset], s->tmp_output + 128, 128 * sizeof(FFTSample)); + } + } +} + +/** + * Upmix delay samples from stereo to original channel layout. + */ +static void ac3_upmix_delay(AC3DecodeContext *s) +{ + int channel_data_size = sizeof(s->delay[0]); + switch (s->channel_mode) { + case AC3_CHMODE_DUALMONO: + case AC3_CHMODE_STEREO: + /* upmix mono to stereo */ + memcpy(s->delay[1], s->delay[0], channel_data_size); + break; + case AC3_CHMODE_2F2R: + memset(s->delay[3], 0, channel_data_size); + case AC3_CHMODE_2F1R: + memset(s->delay[2], 0, channel_data_size); + break; + case AC3_CHMODE_3F2R: + memset(s->delay[4], 0, channel_data_size); + case AC3_CHMODE_3F1R: + memset(s->delay[3], 0, channel_data_size); + case AC3_CHMODE_3F: + memcpy(s->delay[2], s->delay[1], channel_data_size); + memset(s->delay[1], 0, channel_data_size); + break; + } +} + +/** + * Decode band structure for coupling, spectral extension, or enhanced coupling. + * The band structure defines how many subbands are in each band. For each + * subband in the range, 1 means it is combined with the previous band, and 0 + * means that it starts a new band. + * + * @param[in] gbc bit reader context + * @param[in] blk block number + * @param[in] eac3 flag to indicate E-AC-3 + * @param[in] ecpl flag to indicate enhanced coupling + * @param[in] start_subband subband number for start of range + * @param[in] end_subband subband number for end of range + * @param[in] default_band_struct default band structure table + * @param[out] num_bands number of bands (optionally NULL) + * @param[out] band_sizes array containing the number of bins in each band (optionally NULL) + * @param[in,out] band_struct current band structure + */ +static void decode_band_structure(GetBitContext *gbc, int blk, int eac3, + int ecpl, int start_subband, int end_subband, + const uint8_t *default_band_struct, + int *num_bands, uint8_t *band_sizes, + uint8_t *band_struct, int band_struct_size) +{ + int subbnd, bnd, n_subbands, n_bands=0; + uint8_t bnd_sz[22]; + + n_subbands = end_subband - start_subband; + + if (!blk) + memcpy(band_struct, default_band_struct, band_struct_size); + + av_assert0(band_struct_size >= start_subband + n_subbands); + + band_struct += start_subband + 1; + + /* decode band structure from bitstream or use default */ + if (!eac3 || get_bits1(gbc)) { + for (subbnd = 0; subbnd < n_subbands - 1; subbnd++) { + band_struct[subbnd] = get_bits1(gbc); + } + } + + /* calculate number of bands and band sizes based on band structure. + note that the first 4 subbands in enhanced coupling span only 6 bins + instead of 12. */ + if (num_bands || band_sizes ) { + n_bands = n_subbands; + bnd_sz[0] = ecpl ? 6 : 12; + for (bnd = 0, subbnd = 1; subbnd < n_subbands; subbnd++) { + int subbnd_size = (ecpl && subbnd < 4) ? 6 : 12; + if (band_struct[subbnd - 1]) { + n_bands--; + bnd_sz[bnd] += subbnd_size; + } else { + bnd_sz[++bnd] = subbnd_size; + } + } + } + + /* set optional output params */ + if (num_bands) + *num_bands = n_bands; + if (band_sizes) + memcpy(band_sizes, bnd_sz, n_bands); +} + +static inline int spx_strategy(AC3DecodeContext *s, int blk) +{ + GetBitContext *bc = &s->gbc; + int fbw_channels = s->fbw_channels; + int dst_start_freq, dst_end_freq, src_start_freq, + start_subband, end_subband, ch; + + /* determine which channels use spx */ + if (s->channel_mode == AC3_CHMODE_MONO) { + s->channel_uses_spx[1] = 1; + } else { + for (ch = 1; ch <= fbw_channels; ch++) + s->channel_uses_spx[ch] = get_bits1(bc); + } + + /* get the frequency bins of the spx copy region and the spx start + and end subbands */ + dst_start_freq = get_bits(bc, 2); + start_subband = get_bits(bc, 3) + 2; + if (start_subband > 7) + start_subband += start_subband - 7; + end_subband = get_bits(bc, 3) + 5; +#if USE_FIXED + s->spx_dst_end_freq = end_freq_inv_tab[end_subband-5]; +#endif + if (end_subband > 7) + end_subband += end_subband - 7; + dst_start_freq = dst_start_freq * 12 + 25; + src_start_freq = start_subband * 12 + 25; + dst_end_freq = end_subband * 12 + 25; + + /* check validity of spx ranges */ + if (start_subband >= end_subband) { + av_log(s->avctx, AV_LOG_ERROR, "invalid spectral extension " + "range (%d >= %d)\n", start_subband, end_subband); + return AVERROR_INVALIDDATA; + } + if (dst_start_freq >= src_start_freq) { + av_log(s->avctx, AV_LOG_ERROR, "invalid spectral extension " + "copy start bin (%d >= %d)\n", dst_start_freq, src_start_freq); + return AVERROR_INVALIDDATA; + } + + s->spx_dst_start_freq = dst_start_freq; + s->spx_src_start_freq = src_start_freq; + if (!USE_FIXED) + s->spx_dst_end_freq = dst_end_freq; + + decode_band_structure(bc, blk, s->eac3, 0, + start_subband, end_subband, + ff_eac3_default_spx_band_struct, + &s->num_spx_bands, + s->spx_band_sizes, + s->spx_band_struct, sizeof(s->spx_band_struct)); + return 0; +} + +static inline void spx_coordinates(AC3DecodeContext *s) +{ + GetBitContext *bc = &s->gbc; + int fbw_channels = s->fbw_channels; + int ch, bnd; + + for (ch = 1; ch <= fbw_channels; ch++) { + if (s->channel_uses_spx[ch]) { + if (s->first_spx_coords[ch] || get_bits1(bc)) { + INTFLOAT spx_blend; + int bin, master_spx_coord; + + s->first_spx_coords[ch] = 0; + spx_blend = AC3_SPX_BLEND(get_bits(bc, 5)); + master_spx_coord = get_bits(bc, 2) * 3; + + bin = s->spx_src_start_freq; + for (bnd = 0; bnd < s->num_spx_bands; bnd++) { + int bandsize = s->spx_band_sizes[bnd]; + int spx_coord_exp, spx_coord_mant; + INTFLOAT nratio, sblend, nblend; +#if USE_FIXED + /* calculate blending factors */ + int64_t accu = ((bin << 23) + (bandsize << 22)) + * (int64_t)s->spx_dst_end_freq; + nratio = (int)(accu >> 32); + nratio -= spx_blend << 18; + + if (nratio < 0) { + nblend = 0; + sblend = 0x800000; + } else if (nratio > 0x7fffff) { + nblend = 14529495; // sqrt(3) in FP.23 + sblend = 0; + } else { + nblend = fixed_sqrt(nratio, 23); + accu = (int64_t)nblend * 1859775393; + nblend = (int)((accu + (1<<29)) >> 30); + sblend = fixed_sqrt(0x800000 - nratio, 23); + } +#else + float spx_coord; + + /* calculate blending factors */ + nratio = ((float)((bin + (bandsize >> 1))) / s->spx_dst_end_freq) - spx_blend; + nratio = av_clipf(nratio, 0.0f, 1.0f); + nblend = sqrtf(3.0f * nratio); // noise is scaled by sqrt(3) + // to give unity variance + sblend = sqrtf(1.0f - nratio); +#endif + bin += bandsize; + + /* decode spx coordinates */ + spx_coord_exp = get_bits(bc, 4); + spx_coord_mant = get_bits(bc, 2); + if (spx_coord_exp == 15) spx_coord_mant <<= 1; + else spx_coord_mant += 4; + spx_coord_mant <<= (25 - spx_coord_exp - master_spx_coord); + + /* multiply noise and signal blending factors by spx coordinate */ +#if USE_FIXED + accu = (int64_t)nblend * spx_coord_mant; + s->spx_noise_blend[ch][bnd] = (int)((accu + (1<<22)) >> 23); + accu = (int64_t)sblend * spx_coord_mant; + s->spx_signal_blend[ch][bnd] = (int)((accu + (1<<22)) >> 23); +#else + spx_coord = spx_coord_mant * (1.0f / (1 << 23)); + s->spx_noise_blend [ch][bnd] = nblend * spx_coord; + s->spx_signal_blend[ch][bnd] = sblend * spx_coord; +#endif + } + } + } else { + s->first_spx_coords[ch] = 1; + } + } +} + +static inline int coupling_strategy(AC3DecodeContext *s, int blk, + uint8_t *bit_alloc_stages) +{ + GetBitContext *bc = &s->gbc; + int fbw_channels = s->fbw_channels; + int channel_mode = s->channel_mode; + int ch; + + memset(bit_alloc_stages, 3, AC3_MAX_CHANNELS); + if (!s->eac3) + s->cpl_in_use[blk] = get_bits1(bc); + if (s->cpl_in_use[blk]) { + /* coupling in use */ + int cpl_start_subband, cpl_end_subband; + + if (channel_mode < AC3_CHMODE_STEREO) { + av_log(s->avctx, AV_LOG_ERROR, "coupling not allowed in mono or dual-mono\n"); + return AVERROR_INVALIDDATA; + } + + /* check for enhanced coupling */ + if (s->eac3 && get_bits1(bc)) { + /* TODO: parse enhanced coupling strategy info */ + avpriv_request_sample(s->avctx, "Enhanced coupling"); + return AVERROR_PATCHWELCOME; + } + + /* determine which channels are coupled */ + if (s->eac3 && s->channel_mode == AC3_CHMODE_STEREO) { + s->channel_in_cpl[1] = 1; + s->channel_in_cpl[2] = 1; + } else { + for (ch = 1; ch <= fbw_channels; ch++) + s->channel_in_cpl[ch] = get_bits1(bc); + } + + /* phase flags in use */ + if (channel_mode == AC3_CHMODE_STEREO) + s->phase_flags_in_use = get_bits1(bc); + + /* coupling frequency range */ + cpl_start_subband = get_bits(bc, 4); + cpl_end_subband = s->spx_in_use ? (s->spx_src_start_freq - 37) / 12 : + get_bits(bc, 4) + 3; + if (cpl_start_subband >= cpl_end_subband) { + av_log(s->avctx, AV_LOG_ERROR, "invalid coupling range (%d >= %d)\n", + cpl_start_subband, cpl_end_subband); + return AVERROR_INVALIDDATA; + } + s->start_freq[CPL_CH] = cpl_start_subband * 12 + 37; + s->end_freq[CPL_CH] = cpl_end_subband * 12 + 37; + + decode_band_structure(bc, blk, s->eac3, 0, cpl_start_subband, + cpl_end_subband, + ff_eac3_default_cpl_band_struct, + &s->num_cpl_bands, s->cpl_band_sizes, + s->cpl_band_struct, sizeof(s->cpl_band_struct)); + } else { + /* coupling not in use */ + for (ch = 1; ch <= fbw_channels; ch++) { + s->channel_in_cpl[ch] = 0; + s->first_cpl_coords[ch] = 1; + } + s->first_cpl_leak = s->eac3; + s->phase_flags_in_use = 0; + } + + return 0; +} + +static inline int coupling_coordinates(AC3DecodeContext *s, int blk) +{ + GetBitContext *bc = &s->gbc; + int fbw_channels = s->fbw_channels; + int ch, bnd; + int cpl_coords_exist = 0; + + for (ch = 1; ch <= fbw_channels; ch++) { + if (s->channel_in_cpl[ch]) { + if ((s->eac3 && s->first_cpl_coords[ch]) || get_bits1(bc)) { + int master_cpl_coord, cpl_coord_exp, cpl_coord_mant; + s->first_cpl_coords[ch] = 0; + cpl_coords_exist = 1; + master_cpl_coord = 3 * get_bits(bc, 2); + for (bnd = 0; bnd < s->num_cpl_bands; bnd++) { + cpl_coord_exp = get_bits(bc, 4); + cpl_coord_mant = get_bits(bc, 4); + if (cpl_coord_exp == 15) + s->cpl_coords[ch][bnd] = cpl_coord_mant << 22; + else + s->cpl_coords[ch][bnd] = (cpl_coord_mant + 16) << 21; + s->cpl_coords[ch][bnd] >>= (cpl_coord_exp + master_cpl_coord); + } + } else if (!blk) { + av_log(s->avctx, AV_LOG_ERROR, "new coupling coordinates must " + "be present in block 0\n"); + return AVERROR_INVALIDDATA; + } + } else { + /* channel not in coupling */ + s->first_cpl_coords[ch] = 1; + } + } + /* phase flags */ + if (s->channel_mode == AC3_CHMODE_STEREO && cpl_coords_exist) { + for (bnd = 0; bnd < s->num_cpl_bands; bnd++) { + s->phase_flags[bnd] = s->phase_flags_in_use ? get_bits1(bc) : 0; + } + } + + return 0; +} + +/** + * Decode a single audio block from the AC-3 bitstream. + */ +static int decode_audio_block(AC3DecodeContext *s, int blk, int offset) +{ + int fbw_channels = s->fbw_channels; + int channel_mode = s->channel_mode; + int i, bnd, seg, ch, ret; + int different_transforms; + int downmix_output; + int cpl_in_use; + GetBitContext *gbc = &s->gbc; + uint8_t bit_alloc_stages[AC3_MAX_CHANNELS] = { 0 }; + + /* block switch flags */ + different_transforms = 0; + if (s->block_switch_syntax) { + for (ch = 1; ch <= fbw_channels; ch++) { + s->block_switch[ch] = get_bits1(gbc); + if (ch > 1 && s->block_switch[ch] != s->block_switch[1]) + different_transforms = 1; + } + } + + /* dithering flags */ + if (s->dither_flag_syntax) { + for (ch = 1; ch <= fbw_channels; ch++) { + s->dither_flag[ch] = get_bits1(gbc); + } + } + + /* dynamic range */ + i = !s->channel_mode; + do { + if (get_bits1(gbc)) { + /* Allow asymmetric application of DRC when drc_scale > 1. + Amplification of quiet sounds is enhanced */ + int range_bits = get_bits(gbc, 8); + INTFLOAT range = AC3_RANGE(range_bits); + if (range_bits <= 127 || s->drc_scale <= 1.0) + s->dynamic_range[i] = AC3_DYNAMIC_RANGE(range); + else + s->dynamic_range[i] = range; + } else if (blk == 0) { + s->dynamic_range[i] = AC3_DYNAMIC_RANGE1; + } + } while (i--); + + /* spectral extension strategy */ + if (s->eac3 && (!blk || get_bits1(gbc))) { + s->spx_in_use = get_bits1(gbc); + if (s->spx_in_use) { + if ((ret = spx_strategy(s, blk)) < 0) + return ret; + } + } + if (!s->eac3 || !s->spx_in_use) { + s->spx_in_use = 0; + for (ch = 1; ch <= fbw_channels; ch++) { + s->channel_uses_spx[ch] = 0; + s->first_spx_coords[ch] = 1; + } + } + + /* spectral extension coordinates */ + if (s->spx_in_use) + spx_coordinates(s); + + /* coupling strategy */ + if (s->eac3 ? s->cpl_strategy_exists[blk] : get_bits1(gbc)) { + if ((ret = coupling_strategy(s, blk, bit_alloc_stages)) < 0) + return ret; + } else if (!s->eac3) { + if (!blk) { + av_log(s->avctx, AV_LOG_ERROR, "new coupling strategy must " + "be present in block 0\n"); + return AVERROR_INVALIDDATA; + } else { + s->cpl_in_use[blk] = s->cpl_in_use[blk-1]; + } + } + cpl_in_use = s->cpl_in_use[blk]; + + /* coupling coordinates */ + if (cpl_in_use) { + if ((ret = coupling_coordinates(s, blk)) < 0) + return ret; + } + + /* stereo rematrixing strategy and band structure */ + if (channel_mode == AC3_CHMODE_STEREO) { + if ((s->eac3 && !blk) || get_bits1(gbc)) { + s->num_rematrixing_bands = 4; + if (cpl_in_use && s->start_freq[CPL_CH] <= 61) { + s->num_rematrixing_bands -= 1 + (s->start_freq[CPL_CH] == 37); + } else if (s->spx_in_use && s->spx_src_start_freq <= 61) { + s->num_rematrixing_bands--; + } + for (bnd = 0; bnd < s->num_rematrixing_bands; bnd++) + s->rematrixing_flags[bnd] = get_bits1(gbc); + } else if (!blk) { + av_log(s->avctx, AV_LOG_WARNING, "Warning: " + "new rematrixing strategy not present in block 0\n"); + s->num_rematrixing_bands = 0; + } + } + + /* exponent strategies for each channel */ + for (ch = !cpl_in_use; ch <= s->channels; ch++) { + if (!s->eac3) + s->exp_strategy[blk][ch] = get_bits(gbc, 2 - (ch == s->lfe_ch)); + if (s->exp_strategy[blk][ch] != EXP_REUSE) + bit_alloc_stages[ch] = 3; + } + + /* channel bandwidth */ + for (ch = 1; ch <= fbw_channels; ch++) { + s->start_freq[ch] = 0; + if (s->exp_strategy[blk][ch] != EXP_REUSE) { + int group_size; + int prev = s->end_freq[ch]; + if (s->channel_in_cpl[ch]) + s->end_freq[ch] = s->start_freq[CPL_CH]; + else if (s->channel_uses_spx[ch]) + s->end_freq[ch] = s->spx_src_start_freq; + else { + int bandwidth_code = get_bits(gbc, 6); + if (bandwidth_code > 60) { + av_log(s->avctx, AV_LOG_ERROR, "bandwidth code = %d > 60\n", bandwidth_code); + return AVERROR_INVALIDDATA; + } + s->end_freq[ch] = bandwidth_code * 3 + 73; + } + group_size = 3 << (s->exp_strategy[blk][ch] - 1); + s->num_exp_groups[ch] = (s->end_freq[ch] + group_size-4) / group_size; + if (blk > 0 && s->end_freq[ch] != prev) + memset(bit_alloc_stages, 3, AC3_MAX_CHANNELS); + } + } + if (cpl_in_use && s->exp_strategy[blk][CPL_CH] != EXP_REUSE) { + s->num_exp_groups[CPL_CH] = (s->end_freq[CPL_CH] - s->start_freq[CPL_CH]) / + (3 << (s->exp_strategy[blk][CPL_CH] - 1)); + } + + /* decode exponents for each channel */ + for (ch = !cpl_in_use; ch <= s->channels; ch++) { + if (s->exp_strategy[blk][ch] != EXP_REUSE) { + s->dexps[ch][0] = get_bits(gbc, 4) << !ch; + if (decode_exponents(s, gbc, s->exp_strategy[blk][ch], + s->num_exp_groups[ch], s->dexps[ch][0], + &s->dexps[ch][s->start_freq[ch]+!!ch])) { + return AVERROR_INVALIDDATA; + } + if (ch != CPL_CH && ch != s->lfe_ch) + skip_bits(gbc, 2); /* skip gainrng */ + } + } + + /* bit allocation information */ + if (s->bit_allocation_syntax) { + if (get_bits1(gbc)) { + s->bit_alloc_params.slow_decay = ff_ac3_slow_decay_tab[get_bits(gbc, 2)] >> s->bit_alloc_params.sr_shift; + s->bit_alloc_params.fast_decay = ff_ac3_fast_decay_tab[get_bits(gbc, 2)] >> s->bit_alloc_params.sr_shift; + s->bit_alloc_params.slow_gain = ff_ac3_slow_gain_tab[get_bits(gbc, 2)]; + s->bit_alloc_params.db_per_bit = ff_ac3_db_per_bit_tab[get_bits(gbc, 2)]; + s->bit_alloc_params.floor = ff_ac3_floor_tab[get_bits(gbc, 3)]; + for (ch = !cpl_in_use; ch <= s->channels; ch++) + bit_alloc_stages[ch] = FFMAX(bit_alloc_stages[ch], 2); + } else if (!blk) { + av_log(s->avctx, AV_LOG_ERROR, "new bit allocation info must " + "be present in block 0\n"); + return AVERROR_INVALIDDATA; + } + } + + /* signal-to-noise ratio offsets and fast gains (signal-to-mask ratios) */ + if (!s->eac3 || !blk) { + if (s->snr_offset_strategy && get_bits1(gbc)) { + int snr = 0; + int csnr; + csnr = (get_bits(gbc, 6) - 15) << 4; + for (i = ch = !cpl_in_use; ch <= s->channels; ch++) { + /* snr offset */ + if (ch == i || s->snr_offset_strategy == 2) + snr = (csnr + get_bits(gbc, 4)) << 2; + /* run at least last bit allocation stage if snr offset changes */ + if (blk && s->snr_offset[ch] != snr) { + bit_alloc_stages[ch] = FFMAX(bit_alloc_stages[ch], 1); + } + s->snr_offset[ch] = snr; + + /* fast gain (normal AC-3 only) */ + if (!s->eac3) { + int prev = s->fast_gain[ch]; + s->fast_gain[ch] = ff_ac3_fast_gain_tab[get_bits(gbc, 3)]; + /* run last 2 bit allocation stages if fast gain changes */ + if (blk && prev != s->fast_gain[ch]) + bit_alloc_stages[ch] = FFMAX(bit_alloc_stages[ch], 2); + } + } + } else if (!s->eac3 && !blk) { + av_log(s->avctx, AV_LOG_ERROR, "new snr offsets must be present in block 0\n"); + return AVERROR_INVALIDDATA; + } + } + + /* fast gain (E-AC-3 only) */ + if (s->fast_gain_syntax && get_bits1(gbc)) { + for (ch = !cpl_in_use; ch <= s->channels; ch++) { + int prev = s->fast_gain[ch]; + s->fast_gain[ch] = ff_ac3_fast_gain_tab[get_bits(gbc, 3)]; + /* run last 2 bit allocation stages if fast gain changes */ + if (blk && prev != s->fast_gain[ch]) + bit_alloc_stages[ch] = FFMAX(bit_alloc_stages[ch], 2); + } + } else if (s->eac3 && !blk) { + for (ch = !cpl_in_use; ch <= s->channels; ch++) + s->fast_gain[ch] = ff_ac3_fast_gain_tab[4]; + } + + /* E-AC-3 to AC-3 converter SNR offset */ + if (s->frame_type == EAC3_FRAME_TYPE_INDEPENDENT && get_bits1(gbc)) { + skip_bits(gbc, 10); // skip converter snr offset + } + + /* coupling leak information */ + if (cpl_in_use) { + if (s->first_cpl_leak || get_bits1(gbc)) { + int fl = get_bits(gbc, 3); + int sl = get_bits(gbc, 3); + /* run last 2 bit allocation stages for coupling channel if + coupling leak changes */ + if (blk && (fl != s->bit_alloc_params.cpl_fast_leak || + sl != s->bit_alloc_params.cpl_slow_leak)) { + bit_alloc_stages[CPL_CH] = FFMAX(bit_alloc_stages[CPL_CH], 2); + } + s->bit_alloc_params.cpl_fast_leak = fl; + s->bit_alloc_params.cpl_slow_leak = sl; + } else if (!s->eac3 && !blk) { + av_log(s->avctx, AV_LOG_ERROR, "new coupling leak info must " + "be present in block 0\n"); + return AVERROR_INVALIDDATA; + } + s->first_cpl_leak = 0; + } + + /* delta bit allocation information */ + if (s->dba_syntax && get_bits1(gbc)) { + /* delta bit allocation exists (strategy) */ + for (ch = !cpl_in_use; ch <= fbw_channels; ch++) { + s->dba_mode[ch] = get_bits(gbc, 2); + if (s->dba_mode[ch] == DBA_RESERVED) { + av_log(s->avctx, AV_LOG_ERROR, "delta bit allocation strategy reserved\n"); + return AVERROR_INVALIDDATA; + } + bit_alloc_stages[ch] = FFMAX(bit_alloc_stages[ch], 2); + } + /* channel delta offset, len and bit allocation */ + for (ch = !cpl_in_use; ch <= fbw_channels; ch++) { + if (s->dba_mode[ch] == DBA_NEW) { + s->dba_nsegs[ch] = get_bits(gbc, 3) + 1; + for (seg = 0; seg < s->dba_nsegs[ch]; seg++) { + s->dba_offsets[ch][seg] = get_bits(gbc, 5); + s->dba_lengths[ch][seg] = get_bits(gbc, 4); + s->dba_values[ch][seg] = get_bits(gbc, 3); + } + /* run last 2 bit allocation stages if new dba values */ + bit_alloc_stages[ch] = FFMAX(bit_alloc_stages[ch], 2); + } + } + } else if (blk == 0) { + for (ch = 0; ch <= s->channels; ch++) { + s->dba_mode[ch] = DBA_NONE; + } + } + + /* Bit allocation */ + for (ch = !cpl_in_use; ch <= s->channels; ch++) { + if (bit_alloc_stages[ch] > 2) { + /* Exponent mapping into PSD and PSD integration */ + ff_ac3_bit_alloc_calc_psd(s->dexps[ch], + s->start_freq[ch], s->end_freq[ch], + s->psd[ch], s->band_psd[ch]); + } + if (bit_alloc_stages[ch] > 1) { + /* Compute excitation function, Compute masking curve, and + Apply delta bit allocation */ + if (ff_ac3_bit_alloc_calc_mask(&s->bit_alloc_params, s->band_psd[ch], + s->start_freq[ch], s->end_freq[ch], + s->fast_gain[ch], (ch == s->lfe_ch), + s->dba_mode[ch], s->dba_nsegs[ch], + s->dba_offsets[ch], s->dba_lengths[ch], + s->dba_values[ch], s->mask[ch])) { + av_log(s->avctx, AV_LOG_ERROR, "error in bit allocation\n"); + return AVERROR_INVALIDDATA; + } + } + if (bit_alloc_stages[ch] > 0) { + /* Compute bit allocation */ + const uint8_t *bap_tab = s->channel_uses_aht[ch] ? + ff_eac3_hebap_tab : ff_ac3_bap_tab; + s->ac3dsp.bit_alloc_calc_bap(s->mask[ch], s->psd[ch], + s->start_freq[ch], s->end_freq[ch], + s->snr_offset[ch], + s->bit_alloc_params.floor, + bap_tab, s->bap[ch]); + } + } + + /* unused dummy data */ + if (s->skip_syntax && get_bits1(gbc)) { + int skipl = get_bits(gbc, 9); + skip_bits_long(gbc, 8 * skipl); + } + + /* unpack the transform coefficients + this also uncouples channels if coupling is in use. */ + decode_transform_coeffs(s, blk); + + /* TODO: generate enhanced coupling coordinates and uncouple */ + + /* recover coefficients if rematrixing is in use */ + if (s->channel_mode == AC3_CHMODE_STEREO) + do_rematrixing(s); + + /* apply scaling to coefficients (headroom, dynrng) */ + for (ch = 1; ch <= s->channels; ch++) { + int audio_channel = 0; + INTFLOAT gain; + if (s->channel_mode == AC3_CHMODE_DUALMONO && ch <= 2) + audio_channel = 2-ch; + if (s->heavy_compression && s->compression_exists[audio_channel]) + gain = s->heavy_dynamic_range[audio_channel]; + else + gain = s->dynamic_range[audio_channel]; + +#if USE_FIXED + scale_coefs(s->transform_coeffs[ch], s->fixed_coeffs[ch], gain, 256); +#else + if (s->target_level != 0) + gain = gain * s->level_gain[audio_channel]; + gain *= 1.0 / 4194304.0f; + s->fmt_conv.int32_to_float_fmul_scalar(s->transform_coeffs[ch], + s->fixed_coeffs[ch], gain, 256); +#endif + } + + /* apply spectral extension to high frequency bins */ + if (CONFIG_EAC3_DECODER && s->spx_in_use) { + ff_eac3_apply_spectral_extension(s); + } + + /* downmix and MDCT. order depends on whether block switching is used for + any channel in this block. this is because coefficients for the long + and short transforms cannot be mixed. */ + downmix_output = s->channels != s->out_channels && + !((s->output_mode & AC3_OUTPUT_LFEON) && + s->fbw_channels == s->out_channels); + if (different_transforms) { + /* the delay samples have already been downmixed, so we upmix the delay + samples in order to reconstruct all channels before downmixing. */ + if (s->downmixed) { + s->downmixed = 0; + ac3_upmix_delay(s); + } + + do_imdct(s, s->channels, offset); + + if (downmix_output) { +#if USE_FIXED + ac3_downmix_c_fixed16(s->outptr, s->downmix_coeffs, + s->out_channels, s->fbw_channels, 256); +#else + ff_ac3dsp_downmix(&s->ac3dsp, s->outptr, s->downmix_coeffs, + s->out_channels, s->fbw_channels, 256); +#endif + } + } else { + if (downmix_output) { + AC3_RENAME(ff_ac3dsp_downmix)(&s->ac3dsp, s->xcfptr + 1, s->downmix_coeffs, + s->out_channels, s->fbw_channels, 256); + } + + if (downmix_output && !s->downmixed) { + s->downmixed = 1; + AC3_RENAME(ff_ac3dsp_downmix)(&s->ac3dsp, s->dlyptr, s->downmix_coeffs, + s->out_channels, s->fbw_channels, 128); + } + + do_imdct(s, s->out_channels, offset); + } + + return 0; +} + +/** + * Decode a single AC-3 frame. + */ +static int ac3_decode_frame(AVCodecContext * avctx, void *data, + int *got_frame_ptr, AVPacket *avpkt) +{ + AVFrame *frame = data; + const uint8_t *buf = avpkt->data; + int buf_size, full_buf_size = avpkt->size; + AC3DecodeContext *s = avctx->priv_data; + int blk, ch, err, offset, ret; + int i; + int skip = 0, got_independent_frame = 0; + const uint8_t *channel_map; + uint8_t extended_channel_map[EAC3_MAX_CHANNELS]; + const SHORTFLOAT *output[AC3_MAX_CHANNELS]; + enum AVMatrixEncoding matrix_encoding; + AVDownmixInfo *downmix_info; + + s->superframe_size = 0; + + buf_size = full_buf_size; + for (i = 1; i < buf_size; i += 2) { + if (buf[i] == 0x77 || buf[i] == 0x0B) { + if ((buf[i] ^ buf[i-1]) == (0x77 ^ 0x0B)) { + i--; + break; + } else if ((buf[i] ^ buf[i+1]) == (0x77 ^ 0x0B)) { + break; + } + } + } + if (i >= buf_size) + return AVERROR_INVALIDDATA; + if (i > 10) + return i; + buf += i; + buf_size -= i; + + /* copy input buffer to decoder context to avoid reading past the end + of the buffer, which can be caused by a damaged input stream. */ + if (buf_size >= 2 && AV_RB16(buf) == 0x770B) { + // seems to be byte-swapped AC-3 + int cnt = FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE) >> 1; + s->bdsp.bswap16_buf((uint16_t *) s->input_buffer, + (const uint16_t *) buf, cnt); + } else + memcpy(s->input_buffer, buf, FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE)); + + /* if consistent noise generation is enabled, seed the linear feedback generator + * with the contents of the AC-3 frame so that the noise is identical across + * decodes given the same AC-3 frame data, for use with non-linear edititing software. */ + if (s->consistent_noise_generation) + av_lfg_init_from_data(&s->dith_state, s->input_buffer, FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE)); + + buf = s->input_buffer; +dependent_frame: + /* initialize the GetBitContext with the start of valid AC-3 Frame */ + if ((ret = init_get_bits8(&s->gbc, buf, buf_size)) < 0) + return ret; + + /* parse the syncinfo */ + err = parse_frame_header(s); + + if (err) { + switch (err) { + case AAC_AC3_PARSE_ERROR_SYNC: + av_log(avctx, AV_LOG_ERROR, "frame sync error\n"); + return AVERROR_INVALIDDATA; + case AAC_AC3_PARSE_ERROR_BSID: + av_log(avctx, AV_LOG_ERROR, "invalid bitstream id\n"); + break; + case AAC_AC3_PARSE_ERROR_SAMPLE_RATE: + av_log(avctx, AV_LOG_ERROR, "invalid sample rate\n"); + break; + case AAC_AC3_PARSE_ERROR_FRAME_SIZE: + av_log(avctx, AV_LOG_ERROR, "invalid frame size\n"); + break; + case AAC_AC3_PARSE_ERROR_FRAME_TYPE: + /* skip frame if CRC is ok. otherwise use error concealment. */ + /* TODO: add support for substreams */ + if (s->substreamid) { + av_log(avctx, AV_LOG_DEBUG, + "unsupported substream %d: skipping frame\n", + s->substreamid); + *got_frame_ptr = 0; + return buf_size; + } else { + av_log(avctx, AV_LOG_ERROR, "invalid frame type\n"); + } + break; + case AAC_AC3_PARSE_ERROR_CRC: + case AAC_AC3_PARSE_ERROR_CHANNEL_CFG: + break; + default: // Normal AVERROR do not try to recover. + *got_frame_ptr = 0; + return err; + } + } else { + /* check that reported frame size fits in input buffer */ + if (s->frame_size > buf_size) { + av_log(avctx, AV_LOG_ERROR, "incomplete frame\n"); + err = AAC_AC3_PARSE_ERROR_FRAME_SIZE; + } else if (avctx->err_recognition & (AV_EF_CRCCHECK|AV_EF_CAREFUL)) { + /* check for crc mismatch */ + if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, &buf[2], + s->frame_size - 2)) { + av_log(avctx, AV_LOG_ERROR, "frame CRC mismatch\n"); + if (avctx->err_recognition & AV_EF_EXPLODE) + return AVERROR_INVALIDDATA; + err = AAC_AC3_PARSE_ERROR_CRC; + } + } + } + + if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT && !got_independent_frame) { + av_log(avctx, AV_LOG_WARNING, "Ignoring dependent frame without independent frame.\n"); + *got_frame_ptr = 0; + return FFMIN(full_buf_size, s->frame_size); + } + + /* channel config */ + if (!err || (s->channels && s->out_channels != s->channels)) { + s->out_channels = s->channels; + s->output_mode = s->channel_mode; + if (s->lfe_on) + s->output_mode |= AC3_OUTPUT_LFEON; + if (s->channels > 1 && + avctx->request_channel_layout == AV_CH_LAYOUT_MONO) { + s->out_channels = 1; + s->output_mode = AC3_CHMODE_MONO; + } else if (s->channels > 2 && + avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) { + s->out_channels = 2; + s->output_mode = AC3_CHMODE_STEREO; + } + + s->loro_center_mix_level = gain_levels[s-> center_mix_level]; + s->loro_surround_mix_level = gain_levels[s->surround_mix_level]; + s->ltrt_center_mix_level = LEVEL_MINUS_3DB; + s->ltrt_surround_mix_level = LEVEL_MINUS_3DB; + /* set downmixing coefficients if needed */ + if (s->channels != s->out_channels && !((s->output_mode & AC3_OUTPUT_LFEON) && + s->fbw_channels == s->out_channels)) { + if ((ret = set_downmix_coeffs(s)) < 0) { + av_log(avctx, AV_LOG_ERROR, "error setting downmix coeffs\n"); + return ret; + } + } + } else if (!s->channels) { + av_log(avctx, AV_LOG_ERROR, "unable to determine channel mode\n"); + return AVERROR_INVALIDDATA; + } + avctx->channels = s->out_channels; + avctx->channel_layout = avpriv_ac3_channel_layout_tab[s->output_mode & ~AC3_OUTPUT_LFEON]; + if (s->output_mode & AC3_OUTPUT_LFEON) + avctx->channel_layout |= AV_CH_LOW_FREQUENCY; + + /* set audio service type based on bitstream mode for AC-3 */ + avctx->audio_service_type = s->bitstream_mode; + if (s->bitstream_mode == 0x7 && s->channels > 1) + avctx->audio_service_type = AV_AUDIO_SERVICE_TYPE_KARAOKE; + + /* decode the audio blocks */ + channel_map = ff_ac3_dec_channel_map[s->output_mode & ~AC3_OUTPUT_LFEON][s->lfe_on]; + offset = s->frame_type == EAC3_FRAME_TYPE_DEPENDENT ? AC3_MAX_CHANNELS : 0; + for (ch = 0; ch < AC3_MAX_CHANNELS; ch++) { + output[ch] = s->output[ch + offset]; + s->outptr[ch] = s->output[ch + offset]; + } + for (ch = 0; ch < s->channels; ch++) { + if (ch < s->out_channels) + s->outptr[channel_map[ch]] = s->output_buffer[ch + offset]; + } + for (blk = 0; blk < s->num_blocks; blk++) { + if (!err && decode_audio_block(s, blk, offset)) { + av_log(avctx, AV_LOG_ERROR, "error decoding the audio block\n"); + err = 1; + } + if (err) + for (ch = 0; ch < s->out_channels; ch++) + memcpy(s->output_buffer[ch + offset] + AC3_BLOCK_SIZE*blk, output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT)); + for (ch = 0; ch < s->out_channels; ch++) + output[ch] = s->outptr[channel_map[ch]]; + for (ch = 0; ch < s->out_channels; ch++) { + if (!ch || channel_map[ch]) + s->outptr[channel_map[ch]] += AC3_BLOCK_SIZE; + } + } + + /* keep last block for error concealment in next frame */ + for (ch = 0; ch < s->out_channels; ch++) + memcpy(s->output[ch + offset], output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT)); + + /* check if there is dependent frame */ + if (buf_size > s->frame_size) { + AC3HeaderInfo hdr; + int err; + + if (buf_size - s->frame_size <= 16) { + skip = buf_size - s->frame_size; + goto skip; + } + + if ((ret = init_get_bits8(&s->gbc, buf + s->frame_size, buf_size - s->frame_size)) < 0) + return ret; + + err = ff_ac3_parse_header(&s->gbc, &hdr); + if (err) + return err; + + if (hdr.frame_type == EAC3_FRAME_TYPE_DEPENDENT) { + if (hdr.num_blocks != s->num_blocks || s->sample_rate != hdr.sample_rate) { + av_log(avctx, AV_LOG_WARNING, "Ignoring non-compatible dependent frame.\n"); + } else { + buf += s->frame_size; + buf_size -= s->frame_size; + s->prev_output_mode = s->output_mode; + s->prev_bit_rate = s->bit_rate; + got_independent_frame = 1; + goto dependent_frame; + } + } + } +skip: + + frame->decode_error_flags = err ? FF_DECODE_ERROR_INVALID_BITSTREAM : 0; + + /* if frame is ok, set audio parameters */ + if (!err) { + avctx->sample_rate = s->sample_rate; + avctx->bit_rate = s->bit_rate + s->prev_bit_rate; + } + + for (ch = 0; ch < EAC3_MAX_CHANNELS; ch++) + extended_channel_map[ch] = ch; + + if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) { + uint64_t ich_layout = avpriv_ac3_channel_layout_tab[s->prev_output_mode & ~AC3_OUTPUT_LFEON]; + int channel_map_size = ff_ac3_channels_tab[s->output_mode & ~AC3_OUTPUT_LFEON] + s->lfe_on; + uint64_t channel_layout; + int extend = 0; + + if (s->prev_output_mode & AC3_OUTPUT_LFEON) + ich_layout |= AV_CH_LOW_FREQUENCY; + + channel_layout = ich_layout; + for (ch = 0; ch < 16; ch++) { + if (s->channel_map & (1 << (EAC3_MAX_CHANNELS - ch - 1))) { + channel_layout |= ff_eac3_custom_channel_map_locations[ch][1]; + } + } + if (av_get_channel_layout_nb_channels(channel_layout) > EAC3_MAX_CHANNELS) { + av_log(avctx, AV_LOG_ERROR, "Too many channels (%d) coded\n", + av_get_channel_layout_nb_channels(channel_layout)); + return AVERROR_INVALIDDATA; + } + + avctx->channel_layout = channel_layout; + avctx->channels = av_get_channel_layout_nb_channels(channel_layout); + + for (ch = 0; ch < EAC3_MAX_CHANNELS; ch++) { + if (s->channel_map & (1 << (EAC3_MAX_CHANNELS - ch - 1))) { + if (ff_eac3_custom_channel_map_locations[ch][0]) { + int index = av_get_channel_layout_channel_index(channel_layout, + ff_eac3_custom_channel_map_locations[ch][1]); + if (index < 0) + return AVERROR_INVALIDDATA; + if (extend >= channel_map_size) + return AVERROR_INVALIDDATA; + + extended_channel_map[index] = offset + channel_map[extend++]; + } else { + int i; + + for (i = 0; i < 64; i++) { + if ((1ULL << i) & ff_eac3_custom_channel_map_locations[ch][1]) { + int index = av_get_channel_layout_channel_index(channel_layout, + 1ULL << i); + if (index < 0) + return AVERROR_INVALIDDATA; + if (extend >= channel_map_size) + return AVERROR_INVALIDDATA; + + extended_channel_map[index] = offset + channel_map[extend++]; + } + } + } + } + } + } + + /* get output buffer */ + frame->nb_samples = s->num_blocks * AC3_BLOCK_SIZE; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + for (ch = 0; ch < avctx->channels; ch++) { + int map = extended_channel_map[ch]; + av_assert0(ch>=AV_NUM_DATA_POINTERS || frame->extended_data[ch] == frame->data[ch]); + memcpy((SHORTFLOAT *)frame->extended_data[ch], + s->output_buffer[map], + s->num_blocks * AC3_BLOCK_SIZE * sizeof(SHORTFLOAT)); + } + + /* + * AVMatrixEncoding + * + * Check whether the input layout is compatible, and make sure we're not + * downmixing (else the matrix encoding is no longer applicable). + */ + matrix_encoding = AV_MATRIX_ENCODING_NONE; + if (s->channel_mode == AC3_CHMODE_STEREO && + s->channel_mode == (s->output_mode & ~AC3_OUTPUT_LFEON)) { + if (s->dolby_surround_mode == AC3_DSURMOD_ON) + matrix_encoding = AV_MATRIX_ENCODING_DOLBY; + else if (s->dolby_headphone_mode == AC3_DHEADPHONMOD_ON) + matrix_encoding = AV_MATRIX_ENCODING_DOLBYHEADPHONE; + } else if (s->channel_mode >= AC3_CHMODE_2F2R && + s->channel_mode == (s->output_mode & ~AC3_OUTPUT_LFEON)) { + switch (s->dolby_surround_ex_mode) { + case AC3_DSUREXMOD_ON: // EX or PLIIx + matrix_encoding = AV_MATRIX_ENCODING_DOLBYEX; + break; + case AC3_DSUREXMOD_PLIIZ: + matrix_encoding = AV_MATRIX_ENCODING_DPLIIZ; + break; + default: // not indicated or off + break; + } + } + if ((ret = ff_side_data_update_matrix_encoding(frame, matrix_encoding)) < 0) + return ret; + + /* AVDownmixInfo */ + if ((downmix_info = av_downmix_info_update_side_data(frame))) { + switch (s->preferred_downmix) { + case AC3_DMIXMOD_LTRT: + downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_LTRT; + break; + case AC3_DMIXMOD_LORO: + downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_LORO; + break; + case AC3_DMIXMOD_DPLII: + downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_DPLII; + break; + default: + downmix_info->preferred_downmix_type = AV_DOWNMIX_TYPE_UNKNOWN; + break; + } + downmix_info->center_mix_level = gain_levels[s-> center_mix_level]; + downmix_info->center_mix_level_ltrt = gain_levels[s-> center_mix_level_ltrt]; + downmix_info->surround_mix_level = gain_levels[s-> surround_mix_level]; + downmix_info->surround_mix_level_ltrt = gain_levels[s->surround_mix_level_ltrt]; + if (s->lfe_mix_level_exists) + downmix_info->lfe_mix_level = gain_levels_lfe[s->lfe_mix_level]; + else + downmix_info->lfe_mix_level = 0.0; // -inf dB + } else + return AVERROR(ENOMEM); + + *got_frame_ptr = 1; + + if (!s->superframe_size) + return FFMIN(full_buf_size, s->frame_size + skip); + + return FFMIN(full_buf_size, s->superframe_size + skip); +} + +/** + * Uninitialize the AC-3 decoder. + */ +static av_cold int ac3_decode_end(AVCodecContext *avctx) +{ + AC3DecodeContext *s = avctx->priv_data; + ff_mdct_end(&s->imdct_512); + ff_mdct_end(&s->imdct_256); + av_freep(&s->fdsp); + av_freep(&s->downmix_coeffs[0]); + + return 0; +} + +#define OFFSET(x) offsetof(AC3DecodeContext, x) +#define PAR (AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM) diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec.h new file mode 100644 index 0000000000..ce1434b55c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec.h @@ -0,0 +1,277 @@ +/* + * Common code between the AC-3 and E-AC-3 decoders + * Copyright (c) 2007 Bartlomiej Wolowiec + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Common code between the AC-3 and E-AC-3 decoders. + * + * Summary of MDCT Coefficient Grouping: + * The individual MDCT coefficient indices are often referred to in the + * (E-)AC-3 specification as frequency bins. These bins are grouped together + * into subbands of 12 coefficients each. The subbands are grouped together + * into bands as defined in the bitstream by the band structures, which + * determine the number of bands and the size of each band. The full spectrum + * of 256 frequency bins is divided into 1 DC bin + 21 subbands = 253 bins. + * This system of grouping coefficients is used for channel bandwidth, stereo + * rematrixing, channel coupling, enhanced coupling, and spectral extension. + * + * +-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-+ + * |1| |12| | [12|12|12|12] | | | | | | | | | | | | |3| + * +-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-+ + * ~~~ ~~~~ ~~~~~~~~~~~~~ ~~~ + * | | | | + * | | | 3 unused frequency bins--+ + * | | | + * | | +--1 band containing 4 subbands + * | | + * | +--1 subband of 12 frequency bins + * | + * +--DC frequency bin + */ + +#ifndef AVCODEC_AC3DEC_H +#define AVCODEC_AC3DEC_H + +#include "libavutil/float_dsp.h" +#include "libavutil/fixed_dsp.h" +#include "libavutil/lfg.h" +#include "ac3.h" +#include "ac3dsp.h" +#include "bswapdsp.h" +#include "get_bits.h" +#include "fft.h" +#include "fmtconvert.h" + +#define AC3_OUTPUT_LFEON 8 + +#define SPX_MAX_BANDS 17 + +/** Large enough for maximum possible frame size when the specification limit is ignored */ +#define AC3_FRAME_BUFFER_SIZE 32768 + +typedef struct AC3DecodeContext { + AVClass *class; ///< class for AVOptions + AVCodecContext *avctx; ///< parent context + GetBitContext gbc; ///< bitstream reader + +///@name Bit stream information +///@{ + int frame_type; ///< frame type (strmtyp) + int substreamid; ///< substream identification + int superframe_size; ///< current superframe size, in bytes + int frame_size; ///< current frame size, in bytes + int bit_rate; ///< stream bit rate, in bits-per-second + int sample_rate; ///< sample frequency, in Hz + int num_blocks; ///< number of audio blocks + int bitstream_id; ///< bitstream id (bsid) + int bitstream_mode; ///< bitstream mode (bsmod) + int channel_mode; ///< channel mode (acmod) + int lfe_on; ///< lfe channel in use + int dialog_normalization[2]; ///< dialog level in dBFS (dialnorm) + int compression_exists[2]; ///< compression field is valid for frame (compre) + int compression_gain[2]; ///< gain to apply for heavy compression (compr) + int channel_map; ///< custom channel map (chanmap) + int preferred_downmix; ///< Preferred 2-channel downmix mode (dmixmod) + int center_mix_level; ///< Center mix level index + int center_mix_level_ltrt; ///< Center mix level index for Lt/Rt (ltrtcmixlev) + int surround_mix_level; ///< Surround mix level index + int surround_mix_level_ltrt; ///< Surround mix level index for Lt/Rt (ltrtsurmixlev) + int lfe_mix_level_exists; ///< indicates if lfemixlevcod is specified (lfemixlevcode) + int lfe_mix_level; ///< LFE mix level index (lfemixlevcod) + int eac3; ///< indicates if current frame is E-AC-3 + int eac3_frame_dependent_found; ///< bitstream has E-AC-3 dependent frame(s) + int eac3_subsbtreamid_found; ///< bitstream has E-AC-3 additional substream(s) + int dolby_surround_mode; ///< dolby surround mode (dsurmod) + int dolby_surround_ex_mode; ///< dolby surround ex mode (dsurexmod) + int dolby_headphone_mode; ///< dolby headphone mode (dheadphonmod) +///@} + + int preferred_stereo_downmix; + float ltrt_center_mix_level; + float ltrt_surround_mix_level; + float loro_center_mix_level; + float loro_surround_mix_level; + int target_level; ///< target level in dBFS + float level_gain[2]; + +///@name Frame syntax parameters + int snr_offset_strategy; ///< SNR offset strategy (snroffststr) + int block_switch_syntax; ///< block switch syntax enabled (blkswe) + int dither_flag_syntax; ///< dither flag syntax enabled (dithflage) + int bit_allocation_syntax; ///< bit allocation model syntax enabled (bamode) + int fast_gain_syntax; ///< fast gain codes enabled (frmfgaincode) + int dba_syntax; ///< delta bit allocation syntax enabled (dbaflde) + int skip_syntax; ///< skip field syntax enabled (skipflde) + ///@} + +///@name Standard coupling + int cpl_in_use[AC3_MAX_BLOCKS]; ///< coupling in use (cplinu) + int cpl_strategy_exists[AC3_MAX_BLOCKS];///< coupling strategy exists (cplstre) + int channel_in_cpl[AC3_MAX_CHANNELS]; ///< channel in coupling (chincpl) + int phase_flags_in_use; ///< phase flags in use (phsflginu) + int phase_flags[AC3_MAX_CPL_BANDS]; ///< phase flags (phsflg) + int num_cpl_bands; ///< number of coupling bands (ncplbnd) + uint8_t cpl_band_struct[AC3_MAX_CPL_BANDS]; + uint8_t cpl_band_sizes[AC3_MAX_CPL_BANDS]; ///< number of coeffs in each coupling band + int firstchincpl; ///< first channel in coupling + int first_cpl_coords[AC3_MAX_CHANNELS]; ///< first coupling coordinates states (firstcplcos) + int cpl_coords[AC3_MAX_CHANNELS][AC3_MAX_CPL_BANDS]; ///< coupling coordinates (cplco) +///@} + +///@name Spectral extension +///@{ + int spx_in_use; ///< spectral extension in use (spxinu) + uint8_t channel_uses_spx[AC3_MAX_CHANNELS]; ///< channel uses spectral extension (chinspx) + int8_t spx_atten_code[AC3_MAX_CHANNELS]; ///< spx attenuation code (spxattencod) + int spx_src_start_freq; ///< spx start frequency bin + int spx_dst_end_freq; ///< spx end frequency bin + int spx_dst_start_freq; ///< spx starting frequency bin for copying (copystartmant) + ///< the copy region ends at the start of the spx region. + int num_spx_bands; ///< number of spx bands (nspxbnds) + uint8_t spx_band_struct[SPX_MAX_BANDS]; + uint8_t spx_band_sizes[SPX_MAX_BANDS]; ///< number of bins in each spx band + uint8_t first_spx_coords[AC3_MAX_CHANNELS]; ///< first spx coordinates states (firstspxcos) + INTFLOAT spx_noise_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS]; ///< spx noise blending factor (nblendfact) + INTFLOAT spx_signal_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS];///< spx signal blending factor (sblendfact) +///@} + +///@name Adaptive hybrid transform + int channel_uses_aht[AC3_MAX_CHANNELS]; ///< channel AHT in use (chahtinu) + int pre_mantissa[AC3_MAX_CHANNELS][AC3_MAX_COEFS][AC3_MAX_BLOCKS]; ///< pre-IDCT mantissas +///@} + +///@name Channel + int fbw_channels; ///< number of full-bandwidth channels + int channels; ///< number of total channels + int lfe_ch; ///< index of LFE channel + SHORTFLOAT *downmix_coeffs[2]; ///< stereo downmix coefficients + int downmixed; ///< indicates if coeffs are currently downmixed + int output_mode; ///< output channel configuration + int prev_output_mode; ///< output channel configuration for previous frame + int out_channels; ///< number of output channels + int prev_bit_rate; ///< stream bit rate, in bits-per-second for previous frame +///@} + +///@name Dynamic range + INTFLOAT dynamic_range[2]; ///< dynamic range + INTFLOAT drc_scale; ///< percentage of dynamic range compression to be applied + int heavy_compression; ///< apply heavy compression + INTFLOAT heavy_dynamic_range[2]; ///< heavy dynamic range compression +///@} + +///@name Bandwidth + int start_freq[AC3_MAX_CHANNELS]; ///< start frequency bin (strtmant) + int end_freq[AC3_MAX_CHANNELS]; ///< end frequency bin (endmant) +///@} + +///@name Consistent noise generation + int consistent_noise_generation; ///< seed noise generation with AC-3 frame on decode +///@} + +///@name Rematrixing + int num_rematrixing_bands; ///< number of rematrixing bands (nrematbnd) + int rematrixing_flags[4]; ///< rematrixing flags (rematflg) +///@} + +///@name Exponents + int num_exp_groups[AC3_MAX_CHANNELS]; ///< Number of exponent groups (nexpgrp) + int8_t dexps[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< decoded exponents + int exp_strategy[AC3_MAX_BLOCKS][AC3_MAX_CHANNELS]; ///< exponent strategies (expstr) +///@} + +///@name Bit allocation + AC3BitAllocParameters bit_alloc_params; ///< bit allocation parameters + int first_cpl_leak; ///< first coupling leak state (firstcplleak) + int snr_offset[AC3_MAX_CHANNELS]; ///< signal-to-noise ratio offsets (snroffst) + int fast_gain[AC3_MAX_CHANNELS]; ///< fast gain values/SMR's (fgain) + uint8_t bap[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< bit allocation pointers + int16_t psd[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< scaled exponents + int16_t band_psd[AC3_MAX_CHANNELS][AC3_CRITICAL_BANDS]; ///< interpolated exponents + int16_t mask[AC3_MAX_CHANNELS][AC3_CRITICAL_BANDS]; ///< masking curve values + int dba_mode[AC3_MAX_CHANNELS]; ///< delta bit allocation mode + int dba_nsegs[AC3_MAX_CHANNELS]; ///< number of delta segments + uint8_t dba_offsets[AC3_MAX_CHANNELS][8]; ///< delta segment offsets + uint8_t dba_lengths[AC3_MAX_CHANNELS][8]; ///< delta segment lengths + uint8_t dba_values[AC3_MAX_CHANNELS][8]; ///< delta values for each segment +///@} + +///@name Zero-mantissa dithering + int dither_flag[AC3_MAX_CHANNELS]; ///< dither flags (dithflg) + AVLFG dith_state; ///< for dither generation +///@} + +///@name IMDCT + int block_switch[AC3_MAX_CHANNELS]; ///< block switch flags (blksw) + FFTContext imdct_512; ///< for 512 sample IMDCT + FFTContext imdct_256; ///< for 256 sample IMDCT +///@} + +///@name Optimization + BswapDSPContext bdsp; +#if USE_FIXED + AVFixedDSPContext *fdsp; +#else + AVFloatDSPContext *fdsp; +#endif + AC3DSPContext ac3dsp; + FmtConvertContext fmt_conv; ///< optimized conversion functions +///@} + + SHORTFLOAT *outptr[AC3_MAX_CHANNELS]; + INTFLOAT *xcfptr[AC3_MAX_CHANNELS]; + INTFLOAT *dlyptr[AC3_MAX_CHANNELS]; + +///@name Aligned arrays + DECLARE_ALIGNED(16, int, fixed_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< fixed-point transform coefficients + DECLARE_ALIGNED(32, INTFLOAT, transform_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< transform coefficients + DECLARE_ALIGNED(32, INTFLOAT, delay)[EAC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< delay - added to the next block + DECLARE_ALIGNED(32, INTFLOAT, window)[AC3_BLOCK_SIZE]; ///< window coefficients + DECLARE_ALIGNED(32, INTFLOAT, tmp_output)[AC3_BLOCK_SIZE]; ///< temporary storage for output before windowing + DECLARE_ALIGNED(32, SHORTFLOAT, output)[EAC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< output after imdct transform and windowing + DECLARE_ALIGNED(32, uint8_t, input_buffer)[AC3_FRAME_BUFFER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; ///< temp buffer to prevent overread + DECLARE_ALIGNED(32, SHORTFLOAT, output_buffer)[EAC3_MAX_CHANNELS][AC3_BLOCK_SIZE * 6]; ///< final output buffer +///@} +} AC3DecodeContext; + +/** + * Parse the E-AC-3 frame header. + * This parses both the bit stream info and audio frame header. + */ +static int ff_eac3_parse_header(AC3DecodeContext *s); + +/** + * Decode mantissas in a single channel for the entire frame. + * This is used when AHT mode is enabled. + */ +static void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch); + +/** + * Apply spectral extension to each channel by copying lower frequency + * coefficients to higher frequency bins and applying side information to + * approximate the original high frequency signal. + */ +static void ff_eac3_apply_spectral_extension(AC3DecodeContext *s); + +#if (!USE_FIXED) +extern float ff_ac3_heavy_dynamic_range_tab[256]; +#endif + +#endif /* AVCODEC_AC3DEC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_data.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_data.c new file mode 100644 index 0000000000..d0a9b1ec40 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_data.c @@ -0,0 +1,60 @@ +/* + * AC-3 and E-AC-3 decoder tables + * Copyright (c) 2007 Bartlomiej Wolowiec + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Tables taken directly from the AC-3 spec. + */ + +#include "ac3dec_data.h" +#include "ac3.h" + +/** + * Table used to ungroup 3 values stored in 5 bits. + * Used by bap=1 mantissas and GAQ. + * ff_ac3_ungroup_3_in_5_bits_tab[i] = { i/9, (i%9)/3, (i%9)%3 } + */ +const uint8_t ff_ac3_ungroup_3_in_5_bits_tab[32][3] = { + { 0, 0, 0 }, { 0, 0, 1 }, { 0, 0, 2 }, { 0, 1, 0 }, + { 0, 1, 1 }, { 0, 1, 2 }, { 0, 2, 0 }, { 0, 2, 1 }, + { 0, 2, 2 }, { 1, 0, 0 }, { 1, 0, 1 }, { 1, 0, 2 }, + { 1, 1, 0 }, { 1, 1, 1 }, { 1, 1, 2 }, { 1, 2, 0 }, + { 1, 2, 1 }, { 1, 2, 2 }, { 2, 0, 0 }, { 2, 0, 1 }, + { 2, 0, 2 }, { 2, 1, 0 }, { 2, 1, 1 }, { 2, 1, 2 }, + { 2, 2, 0 }, { 2, 2, 1 }, { 2, 2, 2 }, { 3, 0, 0 }, + { 3, 0, 1 }, { 3, 0, 2 }, { 3, 1, 0 }, { 3, 1, 1 } +}; + +const uint8_t ff_eac3_hebap_tab[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, + 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, + 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, + 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, + 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, + 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, + 19, 19, 19, 19, +}; + +/** + * Table E2.15 Default Spectral Extension Banding Structure + */ +const uint8_t ff_eac3_default_spx_band_struct[17] = +{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_data.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_data.h new file mode 100644 index 0000000000..975b52ef2c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_data.h @@ -0,0 +1,32 @@ +/* + * AC-3 and E-AC-3 decoder tables + * Copyright (c) 2007 Bartlomiej Wolowiec + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AC3DEC_DATA_H +#define AVCODEC_AC3DEC_DATA_H + +#include + +extern const uint8_t ff_ac3_ungroup_3_in_5_bits_tab[32][3]; + +extern const uint8_t ff_eac3_hebap_tab[64]; +extern const uint8_t ff_eac3_default_spx_band_struct[17]; + +#endif /* AVCODEC_AC3DEC_DATA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_fixed.c new file mode 100644 index 0000000000..bd66175d50 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_fixed.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2012 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Stanislav Ocovaj (socovaj@mips.com) + * + * AC3 fixed-point decoder for MIPS platforms + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FFT_FLOAT 0 +#define USE_FIXED 1 +#define FFT_FIXED_32 1 +#include "ac3dec.h" + + +static const int end_freq_inv_tab[8] = +{ + 50529027, 44278013, 39403370, 32292987, 27356480, 23729101, 20951060, 18755316 +}; + +static void scale_coefs ( + int32_t *dst, + const int32_t *src, + int dynrng, + int len) +{ + int i, shift; + unsigned mul, round; + int temp, temp1, temp2, temp3, temp4, temp5, temp6, temp7; + + mul = (dynrng & 0x1f) + 0x20; + shift = 4 - (sign_extend(dynrng, 9) >> 5); + if (shift > 0 ) { + round = 1 << (shift-1); + for (i=0; i> shift; + temp3 = src[i+3] * mul; + temp2 = temp2 + round; + + dst[i+1] = temp1 >> shift; + temp4 = src[i + 4] * mul; + temp3 = temp3 + round; + dst[i+2] = temp2 >> shift; + + temp5 = src[i+5] * mul; + temp4 = temp4 + round; + dst[i+3] = temp3 >> shift; + temp6 = src[i+6] * mul; + + dst[i+4] = temp4 >> shift; + temp5 = temp5 + round; + temp7 = src[i+7] * mul; + temp6 = temp6 + round; + + dst[i+5] = temp5 >> shift; + temp7 = temp7 + round; + dst[i+6] = temp6 >> shift; + dst[i+7] = temp7 >> shift; + + } + } else { + shift = -shift; + for (i=0; i>12; + samples[1][i] = (v1+2048)>>12; + } + } else if (out_ch == 1) { + for (i = 0; i < len; i++) { + v0 = 0; + for (j = 0; j < in_ch; j++) + v0 += samples[j][i] * matrix[0][j]; + samples[0][i] = (v0+2048)>>12; + } + } +} + +#include "eac3dec.c" +#include "ac3dec.c" + +static const AVOption options[] = { + { "cons_noisegen", "enable consistent noise generation", OFFSET(consistent_noise_generation), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR }, + { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR }, + { "heavy_compr", "enable heavy dynamic range compression", OFFSET(heavy_compression), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR }, + { NULL}, +}; + +static const AVClass ac3_decoder_class = { + .class_name = "Fixed-Point AC-3 Decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_ac3_fixed_decoder = { + .name = "ac3_fixed", + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_AC3, + .priv_data_size = sizeof (AC3DecodeContext), + .init = ac3_decode_init, + .close = ac3_decode_end, + .decode = ac3_decode_frame, + .capabilities = AV_CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"), + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_NONE }, + .priv_class = &ac3_decoder_class, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_float.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_float.c new file mode 100644 index 0000000000..b85a4ce336 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dec_float.c @@ -0,0 +1,93 @@ +/* + * AC-3 Audio Decoder + * This code was developed as part of Google Summer of Code 2006. + * E-AC-3 support was added as part of Google Summer of Code 2007. + * + * Copyright (c) 2006 Kartikey Mahendra BHATT (bhattkm at gmail dot com) + * Copyright (c) 2007-2008 Bartlomiej Wolowiec + * Copyright (c) 2007 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * Upmix delay samples from stereo to original channel layout. + */ +#include "ac3dec.h" +#include "eac3dec.c" +#include "ac3dec.c" + +static const AVOption options[] = { + { "cons_noisegen", "enable consistent noise generation", OFFSET(consistent_noise_generation), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR }, + { "drc_scale", "percentage of dynamic range compression to apply", OFFSET(drc_scale), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 6.0, PAR }, + { "heavy_compr", "enable heavy dynamic range compression", OFFSET(heavy_compression), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, PAR }, + { "target_level", "target level in -dBFS (0 not applied)", OFFSET(target_level), AV_OPT_TYPE_INT, {.i64 = 0 }, -31, 0, PAR }, + +{"dmix_mode", "Preferred Stereo Downmix Mode", OFFSET(preferred_stereo_downmix), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 2, 0, "dmix_mode"}, +{"ltrt_cmixlev", "Lt/Rt Center Mix Level", OFFSET(ltrt_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, +{"ltrt_surmixlev", "Lt/Rt Surround Mix Level", OFFSET(ltrt_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, +{"loro_cmixlev", "Lo/Ro Center Mix Level", OFFSET(loro_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, +{"loro_surmixlev", "Lo/Ro Surround Mix Level", OFFSET(loro_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, 0}, + + { NULL}, +}; + +static const AVClass ac3_decoder_class = { + .class_name = "AC3 decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_ac3_decoder = { + .name = "ac3", + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_AC3, + .priv_data_size = sizeof (AC3DecodeContext), + .init = ac3_decode_init, + .close = ac3_decode_end, + .decode = ac3_decode_frame, + .capabilities = AV_CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"), + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_NONE }, + .priv_class = &ac3_decoder_class, +}; + +#if CONFIG_EAC3_DECODER +static const AVClass eac3_decoder_class = { + .class_name = "E-AC3 decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_eac3_decoder = { + .name = "eac3", + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_EAC3, + .priv_data_size = sizeof (AC3DecodeContext), + .init = ac3_decode_init, + .close = ac3_decode_end, + .decode = ac3_decode_frame, + .capabilities = AV_CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52B (AC-3, E-AC-3)"), + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_NONE }, + .priv_class = &eac3_decoder_class, +}; +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dsp.c new file mode 100644 index 0000000000..43438da131 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dsp.c @@ -0,0 +1,447 @@ +/* + * AC-3 DSP functions + * Copyright (c) 2011 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "ac3.h" +#include "ac3dsp.h" +#include "mathops.h" + +static void ac3_exponent_min_c(uint8_t *exp, int num_reuse_blocks, int nb_coefs) +{ + int blk, i; + + if (!num_reuse_blocks) + return; + + for (i = 0; i < nb_coefs; i++) { + uint8_t min_exp = *exp; + uint8_t *exp1 = exp + 256; + for (blk = 0; blk < num_reuse_blocks; blk++) { + uint8_t next_exp = *exp1; + if (next_exp < min_exp) + min_exp = next_exp; + exp1 += 256; + } + *exp++ = min_exp; + } +} + +static int ac3_max_msb_abs_int16_c(const int16_t *src, int len) +{ + int i, v = 0; + for (i = 0; i < len; i++) + v |= abs(src[i]); + return v; +} + +static void ac3_lshift_int16_c(int16_t *src, unsigned int len, + unsigned int shift) +{ + uint32_t *src32 = (uint32_t *)src; + const uint32_t mask = ~(((1 << shift) - 1) << 16); + int i; + len >>= 1; + for (i = 0; i < len; i += 8) { + src32[i ] = (src32[i ] << shift) & mask; + src32[i+1] = (src32[i+1] << shift) & mask; + src32[i+2] = (src32[i+2] << shift) & mask; + src32[i+3] = (src32[i+3] << shift) & mask; + src32[i+4] = (src32[i+4] << shift) & mask; + src32[i+5] = (src32[i+5] << shift) & mask; + src32[i+6] = (src32[i+6] << shift) & mask; + src32[i+7] = (src32[i+7] << shift) & mask; + } +} + +static void ac3_rshift_int32_c(int32_t *src, unsigned int len, + unsigned int shift) +{ + do { + *src++ >>= shift; + *src++ >>= shift; + *src++ >>= shift; + *src++ >>= shift; + *src++ >>= shift; + *src++ >>= shift; + *src++ >>= shift; + *src++ >>= shift; + len -= 8; + } while (len > 0); +} + +static void float_to_fixed24_c(int32_t *dst, const float *src, unsigned int len) +{ + const float scale = 1 << 24; + do { + *dst++ = lrintf(*src++ * scale); + *dst++ = lrintf(*src++ * scale); + *dst++ = lrintf(*src++ * scale); + *dst++ = lrintf(*src++ * scale); + *dst++ = lrintf(*src++ * scale); + *dst++ = lrintf(*src++ * scale); + *dst++ = lrintf(*src++ * scale); + *dst++ = lrintf(*src++ * scale); + len -= 8; + } while (len > 0); +} + +static void ac3_bit_alloc_calc_bap_c(int16_t *mask, int16_t *psd, + int start, int end, + int snr_offset, int floor, + const uint8_t *bap_tab, uint8_t *bap) +{ + int bin, band, band_end; + + /* special case, if snr offset is -960, set all bap's to zero */ + if (snr_offset == -960) { + memset(bap, 0, AC3_MAX_COEFS); + return; + } + + bin = start; + band = ff_ac3_bin_to_band_tab[start]; + do { + int m = (FFMAX(mask[band] - snr_offset - floor, 0) & 0x1FE0) + floor; + band_end = ff_ac3_band_start_tab[++band]; + band_end = FFMIN(band_end, end); + + for (; bin < band_end; bin++) { + int address = av_clip_uintp2((psd[bin] - m) >> 5, 6); + bap[bin] = bap_tab[address]; + } + } while (end > band_end); +} + +static void ac3_update_bap_counts_c(uint16_t mant_cnt[16], uint8_t *bap, + int len) +{ + while (len-- > 0) + mant_cnt[bap[len]]++; +} + +DECLARE_ALIGNED(16, const uint16_t, ff_ac3_bap_bits)[16] = { + 0, 0, 0, 3, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16 +}; + +static int ac3_compute_mantissa_size_c(uint16_t mant_cnt[6][16]) +{ + int blk, bap; + int bits = 0; + + for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) { + // bap=1 : 3 mantissas in 5 bits + bits += (mant_cnt[blk][1] / 3) * 5; + // bap=2 : 3 mantissas in 7 bits + // bap=4 : 2 mantissas in 7 bits + bits += ((mant_cnt[blk][2] / 3) + (mant_cnt[blk][4] >> 1)) * 7; + // bap=3 : 1 mantissa in 3 bits + bits += mant_cnt[blk][3] * 3; + // bap=5 to 15 : get bits per mantissa from table + for (bap = 5; bap < 16; bap++) + bits += mant_cnt[blk][bap] * ff_ac3_bap_bits[bap]; + } + return bits; +} + +static void ac3_extract_exponents_c(uint8_t *exp, int32_t *coef, int nb_coefs) +{ + int i; + + for (i = 0; i < nb_coefs; i++) { + int v = abs(coef[i]); + exp[i] = v ? 23 - av_log2(v) : 24; + } +} + +static void ac3_sum_square_butterfly_int32_c(int64_t sum[4], + const int32_t *coef0, + const int32_t *coef1, + int len) +{ + int i; + + sum[0] = sum[1] = sum[2] = sum[3] = 0; + + for (i = 0; i < len; i++) { + int lt = coef0[i]; + int rt = coef1[i]; + int md = lt + rt; + int sd = lt - rt; + MAC64(sum[0], lt, lt); + MAC64(sum[1], rt, rt); + MAC64(sum[2], md, md); + MAC64(sum[3], sd, sd); + } +} + +static void ac3_sum_square_butterfly_float_c(float sum[4], + const float *coef0, + const float *coef1, + int len) +{ + int i; + + sum[0] = sum[1] = sum[2] = sum[3] = 0; + + for (i = 0; i < len; i++) { + float lt = coef0[i]; + float rt = coef1[i]; + float md = lt + rt; + float sd = lt - rt; + sum[0] += lt * lt; + sum[1] += rt * rt; + sum[2] += md * md; + sum[3] += sd * sd; + } +} + +static void ac3_downmix_5_to_2_symmetric_c(float **samples, float **matrix, + int len) +{ + int i; + float v0, v1; + float front_mix = matrix[0][0]; + float center_mix = matrix[0][1]; + float surround_mix = matrix[0][3]; + + for (i = 0; i < len; i++) { + v0 = samples[0][i] * front_mix + + samples[1][i] * center_mix + + samples[3][i] * surround_mix; + + v1 = samples[1][i] * center_mix + + samples[2][i] * front_mix + + samples[4][i] * surround_mix; + + samples[0][i] = v0; + samples[1][i] = v1; + } +} + +static void ac3_downmix_5_to_1_symmetric_c(float **samples, float **matrix, + int len) +{ + int i; + float front_mix = matrix[0][0]; + float center_mix = matrix[0][1]; + float surround_mix = matrix[0][3]; + + for (i = 0; i < len; i++) { + samples[0][i] = samples[0][i] * front_mix + + samples[1][i] * center_mix + + samples[2][i] * front_mix + + samples[3][i] * surround_mix + + samples[4][i] * surround_mix; + } +} + +static void ac3_downmix_c(float **samples, float **matrix, + int out_ch, int in_ch, int len) +{ + int i, j; + float v0, v1; + + if (out_ch == 2) { + for (i = 0; i < len; i++) { + v0 = v1 = 0.0f; + for (j = 0; j < in_ch; j++) { + v0 += samples[j][i] * matrix[0][j]; + v1 += samples[j][i] * matrix[1][j]; + } + samples[0][i] = v0; + samples[1][i] = v1; + } + } else if (out_ch == 1) { + for (i = 0; i < len; i++) { + v0 = 0.0f; + for (j = 0; j < in_ch; j++) + v0 += samples[j][i] * matrix[0][j]; + samples[0][i] = v0; + } + } +} + +static void ac3_downmix_5_to_2_symmetric_c_fixed(int32_t **samples, int16_t **matrix, + int len) +{ + int i; + int64_t v0, v1; + int16_t front_mix = matrix[0][0]; + int16_t center_mix = matrix[0][1]; + int16_t surround_mix = matrix[0][3]; + + for (i = 0; i < len; i++) { + v0 = (int64_t)samples[0][i] * front_mix + + (int64_t)samples[1][i] * center_mix + + (int64_t)samples[3][i] * surround_mix; + + v1 = (int64_t)samples[1][i] * center_mix + + (int64_t)samples[2][i] * front_mix + + (int64_t)samples[4][i] * surround_mix; + + samples[0][i] = (v0+2048)>>12; + samples[1][i] = (v1+2048)>>12; + } +} + +static void ac3_downmix_5_to_1_symmetric_c_fixed(int32_t **samples, int16_t **matrix, + int len) +{ + int i; + int64_t v0; + int16_t front_mix = matrix[0][0]; + int16_t center_mix = matrix[0][1]; + int16_t surround_mix = matrix[0][3]; + + for (i = 0; i < len; i++) { + v0 = (int64_t)samples[0][i] * front_mix + + (int64_t)samples[1][i] * center_mix + + (int64_t)samples[2][i] * front_mix + + (int64_t)samples[3][i] * surround_mix + + (int64_t)samples[4][i] * surround_mix; + + samples[0][i] = (v0+2048)>>12; + } +} + +static void ac3_downmix_c_fixed(int32_t **samples, int16_t **matrix, + int out_ch, int in_ch, int len) +{ + int i, j; + int64_t v0, v1; + if (out_ch == 2) { + for (i = 0; i < len; i++) { + v0 = v1 = 0; + for (j = 0; j < in_ch; j++) { + v0 += (int64_t)samples[j][i] * matrix[0][j]; + v1 += (int64_t)samples[j][i] * matrix[1][j]; + } + samples[0][i] = (v0+2048)>>12; + samples[1][i] = (v1+2048)>>12; + } + } else if (out_ch == 1) { + for (i = 0; i < len; i++) { + v0 = 0; + for (j = 0; j < in_ch; j++) + v0 += (int64_t)samples[j][i] * matrix[0][j]; + samples[0][i] = (v0+2048)>>12; + } + } +} + +void ff_ac3dsp_downmix_fixed(AC3DSPContext *c, int32_t **samples, int16_t **matrix, + int out_ch, int in_ch, int len) +{ + if (c->in_channels != in_ch || c->out_channels != out_ch) { + c->in_channels = in_ch; + c->out_channels = out_ch; + c->downmix_fixed = NULL; + + if (in_ch == 5 && out_ch == 2 && + !(matrix[1][0] | matrix[0][2] | + matrix[1][3] | matrix[0][4] | + (matrix[0][1] ^ matrix[1][1]) | + (matrix[0][0] ^ matrix[1][2]))) { + c->downmix_fixed = ac3_downmix_5_to_2_symmetric_c_fixed; + } else if (in_ch == 5 && out_ch == 1 && + matrix[0][0] == matrix[0][2] && + matrix[0][3] == matrix[0][4]) { + c->downmix_fixed = ac3_downmix_5_to_1_symmetric_c_fixed; + } + } + + if (c->downmix_fixed) + c->downmix_fixed(samples, matrix, len); + else + ac3_downmix_c_fixed(samples, matrix, out_ch, in_ch, len); +} + +static void apply_window_int16_c(int16_t *output, const int16_t *input, + const int16_t *window, unsigned int len) +{ + int i; + int len2 = len >> 1; + + for (i = 0; i < len2; i++) { + int16_t w = window[i]; + output[i] = (MUL16(input[i], w) + (1 << 14)) >> 15; + output[len-i-1] = (MUL16(input[len-i-1], w) + (1 << 14)) >> 15; + } +} + +void ff_ac3dsp_downmix(AC3DSPContext *c, float **samples, float **matrix, + int out_ch, int in_ch, int len) +{ + if (c->in_channels != in_ch || c->out_channels != out_ch) { + int **matrix_cmp = (int **)matrix; + + c->in_channels = in_ch; + c->out_channels = out_ch; + c->downmix = NULL; + + if (in_ch == 5 && out_ch == 2 && + !(matrix_cmp[1][0] | matrix_cmp[0][2] | + matrix_cmp[1][3] | matrix_cmp[0][4] | + (matrix_cmp[0][1] ^ matrix_cmp[1][1]) | + (matrix_cmp[0][0] ^ matrix_cmp[1][2]))) { + c->downmix = ac3_downmix_5_to_2_symmetric_c; + } else if (in_ch == 5 && out_ch == 1 && + matrix_cmp[0][0] == matrix_cmp[0][2] && + matrix_cmp[0][3] == matrix_cmp[0][4]) { + c->downmix = ac3_downmix_5_to_1_symmetric_c; + } + + if (ARCH_X86) + ff_ac3dsp_set_downmix_x86(c); + } + + if (c->downmix) + c->downmix(samples, matrix, len); + else + ac3_downmix_c(samples, matrix, out_ch, in_ch, len); +} + +av_cold void ff_ac3dsp_init(AC3DSPContext *c, int bit_exact) +{ + c->ac3_exponent_min = ac3_exponent_min_c; + c->ac3_max_msb_abs_int16 = ac3_max_msb_abs_int16_c; + c->ac3_lshift_int16 = ac3_lshift_int16_c; + c->ac3_rshift_int32 = ac3_rshift_int32_c; + c->float_to_fixed24 = float_to_fixed24_c; + c->bit_alloc_calc_bap = ac3_bit_alloc_calc_bap_c; + c->update_bap_counts = ac3_update_bap_counts_c; + c->compute_mantissa_size = ac3_compute_mantissa_size_c; + c->extract_exponents = ac3_extract_exponents_c; + c->sum_square_butterfly_int32 = ac3_sum_square_butterfly_int32_c; + c->sum_square_butterfly_float = ac3_sum_square_butterfly_float_c; + c->in_channels = 0; + c->out_channels = 0; + c->downmix = NULL; + c->downmix_fixed = NULL; + c->apply_window_int16 = apply_window_int16_c; + + if (ARCH_ARM) + ff_ac3dsp_init_arm(c, bit_exact); + if (ARCH_X86) + ff_ac3dsp_init_x86(c, bit_exact); + if (ARCH_MIPS) + ff_ac3dsp_init_mips(c, bit_exact); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dsp.h new file mode 100644 index 0000000000..161de4cb86 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3dsp.h @@ -0,0 +1,167 @@ +/* + * AC-3 DSP functions + * Copyright (c) 2011 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AC3DSP_H +#define AVCODEC_AC3DSP_H + +#include + +/** + * Number of mantissa bits written for each bap value. + * bap values with fractional bits are set to 0 and are calculated separately. + */ +extern const uint16_t ff_ac3_bap_bits[16]; + +typedef struct AC3DSPContext { + /** + * Set each encoded exponent in a block to the minimum of itself and the + * exponents in the same frequency bin of up to 5 following blocks. + * @param exp pointer to the start of the current block of exponents. + * constraints: align 16 + * @param num_reuse_blocks number of blocks that will reuse exponents from the current block. + * constraints: range 0 to 5 + * @param nb_coefs number of frequency coefficients. + */ + void (*ac3_exponent_min)(uint8_t *exp, int num_reuse_blocks, int nb_coefs); + + /** + * Calculate the maximum MSB of the absolute value of each element in an + * array of int16_t. + * @param src input array + * constraints: align 16. values must be in range [-32767,32767] + * @param len number of values in the array + * constraints: multiple of 16 greater than 0 + * @return a value with the same MSB as max(abs(src[])) + */ + int (*ac3_max_msb_abs_int16)(const int16_t *src, int len); + + /** + * Left-shift each value in an array of int16_t by a specified amount. + * @param src input array + * constraints: align 16 + * @param len number of values in the array + * constraints: multiple of 32 greater than 0 + * @param shift left shift amount + * constraints: range [0,15] + */ + void (*ac3_lshift_int16)(int16_t *src, unsigned int len, unsigned int shift); + + /** + * Right-shift each value in an array of int32_t by a specified amount. + * @param src input array + * constraints: align 16 + * @param len number of values in the array + * constraints: multiple of 16 greater than 0 + * @param shift right shift amount + * constraints: range [0,31] + */ + void (*ac3_rshift_int32)(int32_t *src, unsigned int len, unsigned int shift); + + /** + * Convert an array of float in range [-1.0,1.0] to int32_t with range + * [-(1<<24),(1<<24)] + * + * @param dst destination array of int32_t. + * constraints: 16-byte aligned + * @param src source array of float. + * constraints: 16-byte aligned + * @param len number of elements to convert. + * constraints: multiple of 32 greater than zero + */ + void (*float_to_fixed24)(int32_t *dst, const float *src, unsigned int len); + + /** + * Calculate bit allocation pointers. + * The SNR is the difference between the masking curve and the signal. AC-3 + * uses this value for each frequency bin to allocate bits. The snroffset + * parameter is a global adjustment to the SNR for all bins. + * + * @param[in] mask masking curve + * @param[in] psd signal power for each frequency bin + * @param[in] start starting bin location + * @param[in] end ending bin location + * @param[in] snr_offset SNR adjustment + * @param[in] floor noise floor + * @param[in] bap_tab look-up table for bit allocation pointers + * @param[out] bap bit allocation pointers + */ + void (*bit_alloc_calc_bap)(int16_t *mask, int16_t *psd, int start, int end, + int snr_offset, int floor, + const uint8_t *bap_tab, uint8_t *bap); + + /** + * Update bap counts using the supplied array of bap. + * + * @param[out] mant_cnt bap counts for 1 block + * @param[in] bap array of bap, pointing to start coef bin + * @param[in] len number of elements to process + */ + void (*update_bap_counts)(uint16_t mant_cnt[16], uint8_t *bap, int len); + + /** + * Calculate the number of bits needed to encode a set of mantissas. + * + * @param[in] mant_cnt bap counts for all blocks + * @return mantissa bit count + */ + int (*compute_mantissa_size)(uint16_t mant_cnt[6][16]); + + void (*extract_exponents)(uint8_t *exp, int32_t *coef, int nb_coefs); + + void (*sum_square_butterfly_int32)(int64_t sum[4], const int32_t *coef0, + const int32_t *coef1, int len); + + void (*sum_square_butterfly_float)(float sum[4], const float *coef0, + const float *coef1, int len); + + int out_channels; + int in_channels; + void (*downmix)(float **samples, float **matrix, int len); + void (*downmix_fixed)(int32_t **samples, int16_t **matrix, int len); + + /** + * Apply symmetric window in 16-bit fixed-point. + * @param output destination array + * constraints: 16-byte aligned + * @param input source array + * constraints: 16-byte aligned + * @param window window array + * constraints: 16-byte aligned, at least len/2 elements + * @param len full window length + * constraints: multiple of ? greater than zero + */ + void (*apply_window_int16)(int16_t *output, const int16_t *input, + const int16_t *window, unsigned int len); +} AC3DSPContext; + +void ff_ac3dsp_init (AC3DSPContext *c, int bit_exact); +void ff_ac3dsp_init_arm(AC3DSPContext *c, int bit_exact); +void ff_ac3dsp_init_x86(AC3DSPContext *c, int bit_exact); +void ff_ac3dsp_init_mips(AC3DSPContext *c, int bit_exact); + +void ff_ac3dsp_downmix(AC3DSPContext *c, float **samples, float **matrix, + int out_ch, int in_ch, int len); +void ff_ac3dsp_downmix_fixed(AC3DSPContext *c, int32_t **samples, int16_t **matrix, + int out_ch, int in_ch, int len); + +void ff_ac3dsp_set_downmix_x86(AC3DSPContext *c); + +#endif /* AVCODEC_AC3DSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc.c new file mode 100644 index 0000000000..f1c95ce877 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc.c @@ -0,0 +1,2495 @@ +/* + * The simplest AC-3 encoder + * Copyright (c) 2000 Fabrice Bellard + * Copyright (c) 2006-2010 Justin Ruggles + * Copyright (c) 2006-2010 Prakash Punnoor + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * The simplest AC-3 encoder. + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" +#include "libavutil/crc.h" +#include "libavutil/internal.h" +#include "libavutil/opt.h" +#include "avcodec.h" +#include "internal.h" +#include "me_cmp.h" +#include "put_bits.h" +#include "audiodsp.h" +#include "ac3dsp.h" +#include "ac3.h" +#include "fft.h" +#include "ac3enc.h" +#include "eac3enc.h" + +typedef struct AC3Mant { + int16_t *qmant1_ptr, *qmant2_ptr, *qmant4_ptr; ///< mantissa pointers for bap=1,2,4 + int mant1_cnt, mant2_cnt, mant4_cnt; ///< mantissa counts for bap=1,2,4 +} AC3Mant; + +#define CMIXLEV_NUM_OPTIONS 3 +static const float cmixlev_options[CMIXLEV_NUM_OPTIONS] = { + LEVEL_MINUS_3DB, LEVEL_MINUS_4POINT5DB, LEVEL_MINUS_6DB +}; + +#define SURMIXLEV_NUM_OPTIONS 3 +static const float surmixlev_options[SURMIXLEV_NUM_OPTIONS] = { + LEVEL_MINUS_3DB, LEVEL_MINUS_6DB, LEVEL_ZERO +}; + +#define EXTMIXLEV_NUM_OPTIONS 8 +static const float extmixlev_options[EXTMIXLEV_NUM_OPTIONS] = { + LEVEL_PLUS_3DB, LEVEL_PLUS_1POINT5DB, LEVEL_ONE, LEVEL_MINUS_4POINT5DB, + LEVEL_MINUS_3DB, LEVEL_MINUS_4POINT5DB, LEVEL_MINUS_6DB, LEVEL_ZERO +}; + + +/** + * LUT for number of exponent groups. + * exponent_group_tab[coupling][exponent strategy-1][number of coefficients] + */ +static uint8_t exponent_group_tab[2][3][256]; + + +/** + * List of supported channel layouts. + */ +const uint64_t ff_ac3_channel_layouts[19] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_2_1, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_2_2, + AV_CH_LAYOUT_QUAD, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0, + AV_CH_LAYOUT_5POINT0_BACK, + (AV_CH_LAYOUT_MONO | AV_CH_LOW_FREQUENCY), + (AV_CH_LAYOUT_STEREO | AV_CH_LOW_FREQUENCY), + (AV_CH_LAYOUT_2_1 | AV_CH_LOW_FREQUENCY), + (AV_CH_LAYOUT_SURROUND | AV_CH_LOW_FREQUENCY), + (AV_CH_LAYOUT_2_2 | AV_CH_LOW_FREQUENCY), + (AV_CH_LAYOUT_QUAD | AV_CH_LOW_FREQUENCY), + (AV_CH_LAYOUT_4POINT0 | AV_CH_LOW_FREQUENCY), + AV_CH_LAYOUT_5POINT1, + AV_CH_LAYOUT_5POINT1_BACK, + 0 +}; + + +/** + * LUT to select the bandwidth code based on the bit rate, sample rate, and + * number of full-bandwidth channels. + * bandwidth_tab[fbw_channels-1][sample rate code][bit rate code] + */ +static const uint8_t ac3_bandwidth_tab[5][3][19] = { +// 32 40 48 56 64 80 96 112 128 160 192 224 256 320 384 448 512 576 640 + + { { 0, 0, 0, 12, 16, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 }, + { 0, 0, 0, 16, 20, 36, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56 }, + { 0, 0, 0, 32, 40, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 } }, + + { { 0, 0, 0, 0, 0, 0, 0, 20, 24, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48 }, + { 0, 0, 0, 0, 0, 0, 4, 24, 28, 36, 56, 56, 56, 56, 56, 56, 56, 56, 56 }, + { 0, 0, 0, 0, 0, 0, 20, 44, 52, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 } }, + + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 24, 32, 40, 48, 48, 48, 48, 48, 48 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 4, 20, 28, 36, 44, 56, 56, 56, 56, 56, 56 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 20, 40, 48, 60, 60, 60, 60, 60, 60, 60, 60 } }, + + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 24, 32, 48, 48, 48, 48, 48, 48 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 28, 36, 56, 56, 56, 56, 56, 56 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 48, 60, 60, 60, 60, 60, 60, 60 } }, + + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 20, 32, 40, 48, 48, 48, 48 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 24, 36, 44, 56, 56, 56, 56 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 44, 60, 60, 60, 60, 60, 60 } } +}; + + +/** + * LUT to select the coupling start band based on the bit rate, sample rate, and + * number of full-bandwidth channels. -1 = coupling off + * ac3_coupling_start_tab[channel_mode-2][sample rate code][bit rate code] + * + * TODO: more testing for optimal parameters. + * multi-channel tests at 44.1kHz and 32kHz. + */ +static const int8_t ac3_coupling_start_tab[6][3][19] = { +// 32 40 48 56 64 80 96 112 128 160 192 224 256 320 384 448 512 576 640 + + // 2/0 + { { 0, 0, 0, 0, 0, 0, 0, 1, 1, 7, 8, 11, 12, -1, -1, -1, -1, -1, -1 }, + { 0, 0, 0, 0, 0, 0, 1, 3, 5, 7, 10, 12, 13, -1, -1, -1, -1, -1, -1 }, + { 0, 0, 0, 0, 1, 2, 2, 9, 13, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }, + + // 3/0 + { { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 6, 9, 11, 12, 13, -1, -1, -1, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 6, 9, 11, 12, 13, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }, + + // 2/1 - untested + { { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 6, 9, 11, 12, 13, -1, -1, -1, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 6, 9, 11, 12, 13, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }, + + // 3/1 + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 10, 11, 11, 12, 12, 14, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 10, 11, 11, 12, 12, 14, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }, + + // 2/2 - untested + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 10, 11, 11, 12, 12, 14, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 10, 11, 11, 12, 12, 14, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }, + + // 3/2 + { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 8, 11, 12, 12, -1, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 8, 11, 12, 12, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }, +}; + + +/** + * Adjust the frame size to make the average bit rate match the target bit rate. + * This is only needed for 11025, 22050, and 44100 sample rates or any E-AC-3. + * + * @param s AC-3 encoder private context + */ +void ff_ac3_adjust_frame_size(AC3EncodeContext *s) +{ + while (s->bits_written >= s->bit_rate && s->samples_written >= s->sample_rate) { + s->bits_written -= s->bit_rate; + s->samples_written -= s->sample_rate; + } + s->frame_size = s->frame_size_min + + 2 * (s->bits_written * s->sample_rate < s->samples_written * s->bit_rate); + s->bits_written += s->frame_size * 8; + s->samples_written += AC3_BLOCK_SIZE * s->num_blocks; +} + + +/** + * Set the initial coupling strategy parameters prior to coupling analysis. + * + * @param s AC-3 encoder private context + */ +void ff_ac3_compute_coupling_strategy(AC3EncodeContext *s) +{ + int blk, ch; + int got_cpl_snr; + int num_cpl_blocks; + + /* set coupling use flags for each block/channel */ + /* TODO: turn coupling on/off and adjust start band based on bit usage */ + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + for (ch = 1; ch <= s->fbw_channels; ch++) + block->channel_in_cpl[ch] = s->cpl_on; + } + + /* enable coupling for each block if at least 2 channels have coupling + enabled for that block */ + got_cpl_snr = 0; + num_cpl_blocks = 0; + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + block->num_cpl_channels = 0; + for (ch = 1; ch <= s->fbw_channels; ch++) + block->num_cpl_channels += block->channel_in_cpl[ch]; + block->cpl_in_use = block->num_cpl_channels > 1; + num_cpl_blocks += block->cpl_in_use; + if (!block->cpl_in_use) { + block->num_cpl_channels = 0; + for (ch = 1; ch <= s->fbw_channels; ch++) + block->channel_in_cpl[ch] = 0; + } + + block->new_cpl_strategy = !blk; + if (blk) { + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (block->channel_in_cpl[ch] != s->blocks[blk-1].channel_in_cpl[ch]) { + block->new_cpl_strategy = 1; + break; + } + } + } + block->new_cpl_leak = block->new_cpl_strategy; + + if (!blk || (block->cpl_in_use && !got_cpl_snr)) { + block->new_snr_offsets = 1; + if (block->cpl_in_use) + got_cpl_snr = 1; + } else { + block->new_snr_offsets = 0; + } + } + if (!num_cpl_blocks) + s->cpl_on = 0; + + /* set bandwidth for each channel */ + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (block->channel_in_cpl[ch]) + block->end_freq[ch] = s->start_freq[CPL_CH]; + else + block->end_freq[ch] = s->bandwidth_code * 3 + 73; + } + } +} + + +/** + * Apply stereo rematrixing to coefficients based on rematrixing flags. + * + * @param s AC-3 encoder private context + */ +void ff_ac3_apply_rematrixing(AC3EncodeContext *s) +{ + int nb_coefs; + int blk, bnd, i; + int start, end; + uint8_t *flags = NULL; + + if (!s->rematrixing_enabled) + return; + + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + if (block->new_rematrixing_strategy) + flags = block->rematrixing_flags; + nb_coefs = FFMIN(block->end_freq[1], block->end_freq[2]); + for (bnd = 0; bnd < block->num_rematrixing_bands; bnd++) { + if (flags[bnd]) { + start = ff_ac3_rematrix_band_tab[bnd]; + end = FFMIN(nb_coefs, ff_ac3_rematrix_band_tab[bnd+1]); + for (i = start; i < end; i++) { + int32_t lt = block->fixed_coef[1][i]; + int32_t rt = block->fixed_coef[2][i]; + block->fixed_coef[1][i] = (lt + rt) >> 1; + block->fixed_coef[2][i] = (lt - rt) >> 1; + } + } + } + } +} + + +/* + * Initialize exponent tables. + */ +static av_cold void exponent_init(AC3EncodeContext *s) +{ + int expstr, i, grpsize; + + for (expstr = EXP_D15-1; expstr <= EXP_D45-1; expstr++) { + grpsize = 3 << expstr; + for (i = 12; i < 256; i++) { + exponent_group_tab[0][expstr][i] = (i + grpsize - 4) / grpsize; + exponent_group_tab[1][expstr][i] = (i ) / grpsize; + } + } + /* LFE */ + exponent_group_tab[0][0][7] = 2; + + if (CONFIG_EAC3_ENCODER && s->eac3) + ff_eac3_exponent_init(); +} + + +/* + * Extract exponents from the MDCT coefficients. + */ +static void extract_exponents(AC3EncodeContext *s) +{ + int ch = !s->cpl_on; + int chan_size = AC3_MAX_COEFS * s->num_blocks * (s->channels - ch + 1); + AC3Block *block = &s->blocks[0]; + + s->ac3dsp.extract_exponents(block->exp[ch], block->fixed_coef[ch], chan_size); +} + + +/** + * Exponent Difference Threshold. + * New exponents are sent if their SAD exceed this number. + */ +#define EXP_DIFF_THRESHOLD 500 + +/** + * Table used to select exponent strategy based on exponent reuse block interval. + */ +static const uint8_t exp_strategy_reuse_tab[4][6] = { + { EXP_D15, EXP_D15, EXP_D15, EXP_D15, EXP_D15, EXP_D15 }, + { EXP_D15, EXP_D15, EXP_D15, EXP_D15, EXP_D15, EXP_D15 }, + { EXP_D25, EXP_D25, EXP_D15, EXP_D15, EXP_D15, EXP_D15 }, + { EXP_D45, EXP_D25, EXP_D25, EXP_D15, EXP_D15, EXP_D15 } +}; + +/* + * Calculate exponent strategies for all channels. + * Array arrangement is reversed to simplify the per-channel calculation. + */ +static void compute_exp_strategy(AC3EncodeContext *s) +{ + int ch, blk, blk1; + + for (ch = !s->cpl_on; ch <= s->fbw_channels; ch++) { + uint8_t *exp_strategy = s->exp_strategy[ch]; + uint8_t *exp = s->blocks[0].exp[ch]; + int exp_diff; + + /* estimate if the exponent variation & decide if they should be + reused in the next frame */ + exp_strategy[0] = EXP_NEW; + exp += AC3_MAX_COEFS; + for (blk = 1; blk < s->num_blocks; blk++, exp += AC3_MAX_COEFS) { + if (ch == CPL_CH) { + if (!s->blocks[blk-1].cpl_in_use) { + exp_strategy[blk] = EXP_NEW; + continue; + } else if (!s->blocks[blk].cpl_in_use) { + exp_strategy[blk] = EXP_REUSE; + continue; + } + } else if (s->blocks[blk].channel_in_cpl[ch] != s->blocks[blk-1].channel_in_cpl[ch]) { + exp_strategy[blk] = EXP_NEW; + continue; + } + exp_diff = s->mecc.sad[0](NULL, exp, exp - AC3_MAX_COEFS, 16, 16); + exp_strategy[blk] = EXP_REUSE; + if (ch == CPL_CH && exp_diff > (EXP_DIFF_THRESHOLD * (s->blocks[blk].end_freq[ch] - s->start_freq[ch]) / AC3_MAX_COEFS)) + exp_strategy[blk] = EXP_NEW; + else if (ch > CPL_CH && exp_diff > EXP_DIFF_THRESHOLD) + exp_strategy[blk] = EXP_NEW; + } + + /* now select the encoding strategy type : if exponents are often + recoded, we use a coarse encoding */ + blk = 0; + while (blk < s->num_blocks) { + blk1 = blk + 1; + while (blk1 < s->num_blocks && exp_strategy[blk1] == EXP_REUSE) + blk1++; + exp_strategy[blk] = exp_strategy_reuse_tab[s->num_blks_code][blk1-blk-1]; + blk = blk1; + } + } + if (s->lfe_on) { + ch = s->lfe_channel; + s->exp_strategy[ch][0] = EXP_D15; + for (blk = 1; blk < s->num_blocks; blk++) + s->exp_strategy[ch][blk] = EXP_REUSE; + } + + /* for E-AC-3, determine frame exponent strategy */ + if (CONFIG_EAC3_ENCODER && s->eac3) + ff_eac3_get_frame_exp_strategy(s); +} + + +/** + * Update the exponents so that they are the ones the decoder will decode. + * + * @param[in,out] exp array of exponents for 1 block in 1 channel + * @param nb_exps number of exponents in active bandwidth + * @param exp_strategy exponent strategy for the block + * @param cpl indicates if the block is in the coupling channel + */ +static void encode_exponents_blk_ch(uint8_t *exp, int nb_exps, int exp_strategy, + int cpl) +{ + int nb_groups, i, k; + + nb_groups = exponent_group_tab[cpl][exp_strategy-1][nb_exps] * 3; + + /* for each group, compute the minimum exponent */ + switch(exp_strategy) { + case EXP_D25: + for (i = 1, k = 1-cpl; i <= nb_groups; i++) { + uint8_t exp_min = exp[k]; + if (exp[k+1] < exp_min) + exp_min = exp[k+1]; + exp[i-cpl] = exp_min; + k += 2; + } + break; + case EXP_D45: + for (i = 1, k = 1-cpl; i <= nb_groups; i++) { + uint8_t exp_min = exp[k]; + if (exp[k+1] < exp_min) + exp_min = exp[k+1]; + if (exp[k+2] < exp_min) + exp_min = exp[k+2]; + if (exp[k+3] < exp_min) + exp_min = exp[k+3]; + exp[i-cpl] = exp_min; + k += 4; + } + break; + } + + /* constraint for DC exponent */ + if (!cpl && exp[0] > 15) + exp[0] = 15; + + /* decrease the delta between each groups to within 2 so that they can be + differentially encoded */ + for (i = 1; i <= nb_groups; i++) + exp[i] = FFMIN(exp[i], exp[i-1] + 2); + i--; + while (--i >= 0) + exp[i] = FFMIN(exp[i], exp[i+1] + 2); + + if (cpl) + exp[-1] = exp[0] & ~1; + + /* now we have the exponent values the decoder will see */ + switch (exp_strategy) { + case EXP_D25: + for (i = nb_groups, k = (nb_groups * 2)-cpl; i > 0; i--) { + uint8_t exp1 = exp[i-cpl]; + exp[k--] = exp1; + exp[k--] = exp1; + } + break; + case EXP_D45: + for (i = nb_groups, k = (nb_groups * 4)-cpl; i > 0; i--) { + exp[k] = exp[k-1] = exp[k-2] = exp[k-3] = exp[i-cpl]; + k -= 4; + } + break; + } +} + + +/* + * Encode exponents from original extracted form to what the decoder will see. + * This copies and groups exponents based on exponent strategy and reduces + * deltas between adjacent exponent groups so that they can be differentially + * encoded. + */ +static void encode_exponents(AC3EncodeContext *s) +{ + int blk, blk1, ch, cpl; + uint8_t *exp, *exp_strategy; + int nb_coefs, num_reuse_blocks; + + for (ch = !s->cpl_on; ch <= s->channels; ch++) { + exp = s->blocks[0].exp[ch] + s->start_freq[ch]; + exp_strategy = s->exp_strategy[ch]; + + cpl = (ch == CPL_CH); + blk = 0; + while (blk < s->num_blocks) { + AC3Block *block = &s->blocks[blk]; + if (cpl && !block->cpl_in_use) { + exp += AC3_MAX_COEFS; + blk++; + continue; + } + nb_coefs = block->end_freq[ch] - s->start_freq[ch]; + blk1 = blk + 1; + + /* count the number of EXP_REUSE blocks after the current block + and set exponent reference block numbers */ + s->exp_ref_block[ch][blk] = blk; + while (blk1 < s->num_blocks && exp_strategy[blk1] == EXP_REUSE) { + s->exp_ref_block[ch][blk1] = blk; + blk1++; + } + num_reuse_blocks = blk1 - blk - 1; + + /* for the EXP_REUSE case we select the min of the exponents */ + s->ac3dsp.ac3_exponent_min(exp-s->start_freq[ch], num_reuse_blocks, + AC3_MAX_COEFS); + + encode_exponents_blk_ch(exp, nb_coefs, exp_strategy[blk], cpl); + + exp += AC3_MAX_COEFS * (num_reuse_blocks + 1); + blk = blk1; + } + } + + /* reference block numbers have been changed, so reset ref_bap_set */ + s->ref_bap_set = 0; +} + + +/* + * Count exponent bits based on bandwidth, coupling, and exponent strategies. + */ +static int count_exponent_bits(AC3EncodeContext *s) +{ + int blk, ch; + int nb_groups, bit_count; + + bit_count = 0; + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + for (ch = !block->cpl_in_use; ch <= s->channels; ch++) { + int exp_strategy = s->exp_strategy[ch][blk]; + int cpl = (ch == CPL_CH); + int nb_coefs = block->end_freq[ch] - s->start_freq[ch]; + + if (exp_strategy == EXP_REUSE) + continue; + + nb_groups = exponent_group_tab[cpl][exp_strategy-1][nb_coefs]; + bit_count += 4 + (nb_groups * 7); + } + } + + return bit_count; +} + + +/** + * Group exponents. + * 3 delta-encoded exponents are in each 7-bit group. The number of groups + * varies depending on exponent strategy and bandwidth. + * + * @param s AC-3 encoder private context + */ +void ff_ac3_group_exponents(AC3EncodeContext *s) +{ + int blk, ch, i, cpl; + int group_size, nb_groups; + uint8_t *p; + int delta0, delta1, delta2; + int exp0, exp1; + + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + for (ch = !block->cpl_in_use; ch <= s->channels; ch++) { + int exp_strategy = s->exp_strategy[ch][blk]; + if (exp_strategy == EXP_REUSE) + continue; + cpl = (ch == CPL_CH); + group_size = exp_strategy + (exp_strategy == EXP_D45); + nb_groups = exponent_group_tab[cpl][exp_strategy-1][block->end_freq[ch]-s->start_freq[ch]]; + p = block->exp[ch] + s->start_freq[ch] - cpl; + + /* DC exponent */ + exp1 = *p++; + block->grouped_exp[ch][0] = exp1; + + /* remaining exponents are delta encoded */ + for (i = 1; i <= nb_groups; i++) { + /* merge three delta in one code */ + exp0 = exp1; + exp1 = p[0]; + p += group_size; + delta0 = exp1 - exp0 + 2; + av_assert2(delta0 >= 0 && delta0 <= 4); + + exp0 = exp1; + exp1 = p[0]; + p += group_size; + delta1 = exp1 - exp0 + 2; + av_assert2(delta1 >= 0 && delta1 <= 4); + + exp0 = exp1; + exp1 = p[0]; + p += group_size; + delta2 = exp1 - exp0 + 2; + av_assert2(delta2 >= 0 && delta2 <= 4); + + block->grouped_exp[ch][i] = ((delta0 * 5 + delta1) * 5) + delta2; + } + } + } +} + + +/** + * Calculate final exponents from the supplied MDCT coefficients and exponent shift. + * Extract exponents from MDCT coefficients, calculate exponent strategies, + * and encode final exponents. + * + * @param s AC-3 encoder private context + */ +void ff_ac3_process_exponents(AC3EncodeContext *s) +{ + extract_exponents(s); + + compute_exp_strategy(s); + + encode_exponents(s); + + emms_c(); +} + + +/* + * Count frame bits that are based solely on fixed parameters. + * This only has to be run once when the encoder is initialized. + */ +static void count_frame_bits_fixed(AC3EncodeContext *s) +{ + static const uint8_t frame_bits_inc[8] = { 0, 0, 2, 2, 2, 4, 2, 4 }; + int blk; + int frame_bits; + + /* assumptions: + * no dynamic range codes + * bit allocation parameters do not change between blocks + * no delta bit allocation + * no skipped data + * no auxiliary data + * no E-AC-3 metadata + */ + + /* header */ + frame_bits = 16; /* sync info */ + if (s->eac3) { + /* bitstream info header */ + frame_bits += 35; + frame_bits += 1 + 1; + if (s->num_blocks != 0x6) + frame_bits++; + frame_bits++; + /* audio frame header */ + if (s->num_blocks == 6) + frame_bits += 2; + frame_bits += 10; + /* exponent strategy */ + if (s->use_frame_exp_strategy) + frame_bits += 5 * s->fbw_channels; + else + frame_bits += s->num_blocks * 2 * s->fbw_channels; + if (s->lfe_on) + frame_bits += s->num_blocks; + /* converter exponent strategy */ + if (s->num_blks_code != 0x3) + frame_bits++; + else + frame_bits += s->fbw_channels * 5; + /* snr offsets */ + frame_bits += 10; + /* block start info */ + if (s->num_blocks != 1) + frame_bits++; + } else { + frame_bits += 49; + frame_bits += frame_bits_inc[s->channel_mode]; + } + + /* audio blocks */ + for (blk = 0; blk < s->num_blocks; blk++) { + if (!s->eac3) { + /* block switch flags */ + frame_bits += s->fbw_channels; + + /* dither flags */ + frame_bits += s->fbw_channels; + } + + /* dynamic range */ + frame_bits++; + + /* spectral extension */ + if (s->eac3) + frame_bits++; + + if (!s->eac3) { + /* exponent strategy */ + frame_bits += 2 * s->fbw_channels; + if (s->lfe_on) + frame_bits++; + + /* bit allocation params */ + frame_bits++; + if (!blk) + frame_bits += 2 + 2 + 2 + 2 + 3; + } + + /* converter snr offset */ + if (s->eac3) + frame_bits++; + + if (!s->eac3) { + /* delta bit allocation */ + frame_bits++; + + /* skipped data */ + frame_bits++; + } + } + + /* auxiliary data */ + frame_bits++; + + /* CRC */ + frame_bits += 1 + 16; + + s->frame_bits_fixed = frame_bits; +} + + +/* + * Initialize bit allocation. + * Set default parameter codes and calculate parameter values. + */ +static av_cold void bit_alloc_init(AC3EncodeContext *s) +{ + int ch; + + /* init default parameters */ + s->slow_decay_code = 2; + s->fast_decay_code = 1; + s->slow_gain_code = 1; + s->db_per_bit_code = s->eac3 ? 2 : 3; + s->floor_code = 7; + for (ch = 0; ch <= s->channels; ch++) + s->fast_gain_code[ch] = 4; + + /* initial snr offset */ + s->coarse_snr_offset = 40; + + /* compute real values */ + /* currently none of these values change during encoding, so we can just + set them once at initialization */ + s->bit_alloc.slow_decay = ff_ac3_slow_decay_tab[s->slow_decay_code] >> s->bit_alloc.sr_shift; + s->bit_alloc.fast_decay = ff_ac3_fast_decay_tab[s->fast_decay_code] >> s->bit_alloc.sr_shift; + s->bit_alloc.slow_gain = ff_ac3_slow_gain_tab[s->slow_gain_code]; + s->bit_alloc.db_per_bit = ff_ac3_db_per_bit_tab[s->db_per_bit_code]; + s->bit_alloc.floor = ff_ac3_floor_tab[s->floor_code]; + s->bit_alloc.cpl_fast_leak = 0; + s->bit_alloc.cpl_slow_leak = 0; + + count_frame_bits_fixed(s); +} + + +/* + * Count the bits used to encode the frame, minus exponents and mantissas. + * Bits based on fixed parameters have already been counted, so now we just + * have to add the bits based on parameters that change during encoding. + */ +static void count_frame_bits(AC3EncodeContext *s) +{ + AC3EncOptions *opt = &s->options; + int blk, ch; + int frame_bits = 0; + + /* header */ + if (s->eac3) { + if (opt->eac3_mixing_metadata) { + if (s->channel_mode > AC3_CHMODE_STEREO) + frame_bits += 2; + if (s->has_center) + frame_bits += 6; + if (s->has_surround) + frame_bits += 6; + frame_bits += s->lfe_on; + frame_bits += 1 + 1 + 2; + if (s->channel_mode < AC3_CHMODE_STEREO) + frame_bits++; + frame_bits++; + } + if (opt->eac3_info_metadata) { + frame_bits += 3 + 1 + 1; + if (s->channel_mode == AC3_CHMODE_STEREO) + frame_bits += 2 + 2; + if (s->channel_mode >= AC3_CHMODE_2F2R) + frame_bits += 2; + frame_bits++; + if (opt->audio_production_info) + frame_bits += 5 + 2 + 1; + frame_bits++; + } + /* coupling */ + if (s->channel_mode > AC3_CHMODE_MONO) { + frame_bits++; + for (blk = 1; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + frame_bits++; + if (block->new_cpl_strategy) + frame_bits++; + } + } + /* coupling exponent strategy */ + if (s->cpl_on) { + if (s->use_frame_exp_strategy) { + frame_bits += 5 * s->cpl_on; + } else { + for (blk = 0; blk < s->num_blocks; blk++) + frame_bits += 2 * s->blocks[blk].cpl_in_use; + } + } + } else { + if (opt->audio_production_info) + frame_bits += 7; + if (s->bitstream_id == 6) { + if (opt->extended_bsi_1) + frame_bits += 14; + if (opt->extended_bsi_2) + frame_bits += 14; + } + } + + /* audio blocks */ + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + + /* coupling strategy */ + if (!s->eac3) + frame_bits++; + if (block->new_cpl_strategy) { + if (!s->eac3) + frame_bits++; + if (block->cpl_in_use) { + if (s->eac3) + frame_bits++; + if (!s->eac3 || s->channel_mode != AC3_CHMODE_STEREO) + frame_bits += s->fbw_channels; + if (s->channel_mode == AC3_CHMODE_STEREO) + frame_bits++; + frame_bits += 4 + 4; + if (s->eac3) + frame_bits++; + else + frame_bits += s->num_cpl_subbands - 1; + } + } + + /* coupling coordinates */ + if (block->cpl_in_use) { + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (block->channel_in_cpl[ch]) { + if (!s->eac3 || block->new_cpl_coords[ch] != 2) + frame_bits++; + if (block->new_cpl_coords[ch]) { + frame_bits += 2; + frame_bits += (4 + 4) * s->num_cpl_bands; + } + } + } + } + + /* stereo rematrixing */ + if (s->channel_mode == AC3_CHMODE_STEREO) { + if (!s->eac3 || blk > 0) + frame_bits++; + if (s->blocks[blk].new_rematrixing_strategy) + frame_bits += block->num_rematrixing_bands; + } + + /* bandwidth codes & gain range */ + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (s->exp_strategy[ch][blk] != EXP_REUSE) { + if (!block->channel_in_cpl[ch]) + frame_bits += 6; + frame_bits += 2; + } + } + + /* coupling exponent strategy */ + if (!s->eac3 && block->cpl_in_use) + frame_bits += 2; + + /* snr offsets and fast gain codes */ + if (!s->eac3) { + frame_bits++; + if (block->new_snr_offsets) + frame_bits += 6 + (s->channels + block->cpl_in_use) * (4 + 3); + } + + /* coupling leak info */ + if (block->cpl_in_use) { + if (!s->eac3 || block->new_cpl_leak != 2) + frame_bits++; + if (block->new_cpl_leak) + frame_bits += 3 + 3; + } + } + + s->frame_bits = s->frame_bits_fixed + frame_bits; +} + + +/* + * Calculate masking curve based on the final exponents. + * Also calculate the power spectral densities to use in future calculations. + */ +static void bit_alloc_masking(AC3EncodeContext *s) +{ + int blk, ch; + + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + for (ch = !block->cpl_in_use; ch <= s->channels; ch++) { + /* We only need psd and mask for calculating bap. + Since we currently do not calculate bap when exponent + strategy is EXP_REUSE we do not need to calculate psd or mask. */ + if (s->exp_strategy[ch][blk] != EXP_REUSE) { + ff_ac3_bit_alloc_calc_psd(block->exp[ch], s->start_freq[ch], + block->end_freq[ch], block->psd[ch], + block->band_psd[ch]); + ff_ac3_bit_alloc_calc_mask(&s->bit_alloc, block->band_psd[ch], + s->start_freq[ch], block->end_freq[ch], + ff_ac3_fast_gain_tab[s->fast_gain_code[ch]], + ch == s->lfe_channel, + DBA_NONE, 0, NULL, NULL, NULL, + block->mask[ch]); + } + } + } +} + + +/* + * Ensure that bap for each block and channel point to the current bap_buffer. + * They may have been switched during the bit allocation search. + */ +static void reset_block_bap(AC3EncodeContext *s) +{ + int blk, ch; + uint8_t *ref_bap; + + if (s->ref_bap[0][0] == s->bap_buffer && s->ref_bap_set) + return; + + ref_bap = s->bap_buffer; + for (ch = 0; ch <= s->channels; ch++) { + for (blk = 0; blk < s->num_blocks; blk++) + s->ref_bap[ch][blk] = ref_bap + AC3_MAX_COEFS * s->exp_ref_block[ch][blk]; + ref_bap += AC3_MAX_COEFS * s->num_blocks; + } + s->ref_bap_set = 1; +} + + +/** + * Initialize mantissa counts. + * These are set so that they are padded to the next whole group size when bits + * are counted in compute_mantissa_size. + * + * @param[in,out] mant_cnt running counts for each bap value for each block + */ +static void count_mantissa_bits_init(uint16_t mant_cnt[AC3_MAX_BLOCKS][16]) +{ + int blk; + + for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) { + memset(mant_cnt[blk], 0, sizeof(mant_cnt[blk])); + mant_cnt[blk][1] = mant_cnt[blk][2] = 2; + mant_cnt[blk][4] = 1; + } +} + + +/** + * Update mantissa bit counts for all blocks in 1 channel in a given bandwidth + * range. + * + * @param s AC-3 encoder private context + * @param ch channel index + * @param[in,out] mant_cnt running counts for each bap value for each block + * @param start starting coefficient bin + * @param end ending coefficient bin + */ +static void count_mantissa_bits_update_ch(AC3EncodeContext *s, int ch, + uint16_t mant_cnt[AC3_MAX_BLOCKS][16], + int start, int end) +{ + int blk; + + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + if (ch == CPL_CH && !block->cpl_in_use) + continue; + s->ac3dsp.update_bap_counts(mant_cnt[blk], + s->ref_bap[ch][blk] + start, + FFMIN(end, block->end_freq[ch]) - start); + } +} + + +/* + * Count the number of mantissa bits in the frame based on the bap values. + */ +static int count_mantissa_bits(AC3EncodeContext *s) +{ + int ch, max_end_freq; + LOCAL_ALIGNED_16(uint16_t, mant_cnt, [AC3_MAX_BLOCKS], [16]); + + count_mantissa_bits_init(mant_cnt); + + max_end_freq = s->bandwidth_code * 3 + 73; + for (ch = !s->cpl_enabled; ch <= s->channels; ch++) + count_mantissa_bits_update_ch(s, ch, mant_cnt, s->start_freq[ch], + max_end_freq); + + return s->ac3dsp.compute_mantissa_size(mant_cnt); +} + + +/** + * Run the bit allocation with a given SNR offset. + * This calculates the bit allocation pointers that will be used to determine + * the quantization of each mantissa. + * + * @param s AC-3 encoder private context + * @param snr_offset SNR offset, 0 to 1023 + * @return the number of bits needed for mantissas if the given SNR offset is + * is used. + */ +static int bit_alloc(AC3EncodeContext *s, int snr_offset) +{ + int blk, ch; + + snr_offset = (snr_offset - 240) << 2; + + reset_block_bap(s); + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + + for (ch = !block->cpl_in_use; ch <= s->channels; ch++) { + /* Currently the only bit allocation parameters which vary across + blocks within a frame are the exponent values. We can take + advantage of that by reusing the bit allocation pointers + whenever we reuse exponents. */ + if (s->exp_strategy[ch][blk] != EXP_REUSE) { + s->ac3dsp.bit_alloc_calc_bap(block->mask[ch], block->psd[ch], + s->start_freq[ch], block->end_freq[ch], + snr_offset, s->bit_alloc.floor, + ff_ac3_bap_tab, s->ref_bap[ch][blk]); + } + } + } + return count_mantissa_bits(s); +} + + +/* + * Constant bitrate bit allocation search. + * Find the largest SNR offset that will allow data to fit in the frame. + */ +static int cbr_bit_allocation(AC3EncodeContext *s) +{ + int ch; + int bits_left; + int snr_offset, snr_incr; + + bits_left = 8 * s->frame_size - (s->frame_bits + s->exponent_bits); + if (bits_left < 0) + return AVERROR(EINVAL); + + snr_offset = s->coarse_snr_offset << 4; + + /* if previous frame SNR offset was 1023, check if current frame can also + use SNR offset of 1023. if so, skip the search. */ + if ((snr_offset | s->fine_snr_offset[1]) == 1023) { + if (bit_alloc(s, 1023) <= bits_left) + return 0; + } + + while (snr_offset >= 0 && + bit_alloc(s, snr_offset) > bits_left) { + snr_offset -= 64; + } + if (snr_offset < 0) + return AVERROR(EINVAL); + + FFSWAP(uint8_t *, s->bap_buffer, s->bap1_buffer); + for (snr_incr = 64; snr_incr > 0; snr_incr >>= 2) { + while (snr_offset + snr_incr <= 1023 && + bit_alloc(s, snr_offset + snr_incr) <= bits_left) { + snr_offset += snr_incr; + FFSWAP(uint8_t *, s->bap_buffer, s->bap1_buffer); + } + } + FFSWAP(uint8_t *, s->bap_buffer, s->bap1_buffer); + reset_block_bap(s); + + s->coarse_snr_offset = snr_offset >> 4; + for (ch = !s->cpl_on; ch <= s->channels; ch++) + s->fine_snr_offset[ch] = snr_offset & 0xF; + + return 0; +} + + +/* + * Perform bit allocation search. + * Finds the SNR offset value that maximizes quality and fits in the specified + * frame size. Output is the SNR offset and a set of bit allocation pointers + * used to quantize the mantissas. + */ +int ff_ac3_compute_bit_allocation(AC3EncodeContext *s) +{ + count_frame_bits(s); + + s->exponent_bits = count_exponent_bits(s); + + bit_alloc_masking(s); + + return cbr_bit_allocation(s); +} + + +/** + * Symmetric quantization on 'levels' levels. + * + * @param c unquantized coefficient + * @param e exponent + * @param levels number of quantization levels + * @return quantized coefficient + */ +static inline int sym_quant(int c, int e, int levels) +{ + int v = (((levels * c) >> (24 - e)) + levels) >> 1; + av_assert2(v >= 0 && v < levels); + return v; +} + + +/** + * Asymmetric quantization on 2^qbits levels. + * + * @param c unquantized coefficient + * @param e exponent + * @param qbits number of quantization bits + * @return quantized coefficient + */ +static inline int asym_quant(int c, int e, int qbits) +{ + int m; + + c = (((c * (1<> (24 - qbits)) + 1) >> 1; + m = (1 << (qbits-1)); + if (c >= m) + c = m - 1; + av_assert2(c >= -m); + return c; +} + + +/** + * Quantize a set of mantissas for a single channel in a single block. + * + * @param s Mantissa count context + * @param fixed_coef unquantized fixed-point coefficients + * @param exp exponents + * @param bap bit allocation pointer indices + * @param[out] qmant quantized coefficients + * @param start_freq starting coefficient bin + * @param end_freq ending coefficient bin + */ +static void quantize_mantissas_blk_ch(AC3Mant *s, int32_t *fixed_coef, + uint8_t *exp, uint8_t *bap, + int16_t *qmant, int start_freq, + int end_freq) +{ + int i; + + for (i = start_freq; i < end_freq; i++) { + int c = fixed_coef[i]; + int e = exp[i]; + int v = bap[i]; + if (v) + switch (v) { + case 1: + v = sym_quant(c, e, 3); + switch (s->mant1_cnt) { + case 0: + s->qmant1_ptr = &qmant[i]; + v = 9 * v; + s->mant1_cnt = 1; + break; + case 1: + *s->qmant1_ptr += 3 * v; + s->mant1_cnt = 2; + v = 128; + break; + default: + *s->qmant1_ptr += v; + s->mant1_cnt = 0; + v = 128; + break; + } + break; + case 2: + v = sym_quant(c, e, 5); + switch (s->mant2_cnt) { + case 0: + s->qmant2_ptr = &qmant[i]; + v = 25 * v; + s->mant2_cnt = 1; + break; + case 1: + *s->qmant2_ptr += 5 * v; + s->mant2_cnt = 2; + v = 128; + break; + default: + *s->qmant2_ptr += v; + s->mant2_cnt = 0; + v = 128; + break; + } + break; + case 3: + v = sym_quant(c, e, 7); + break; + case 4: + v = sym_quant(c, e, 11); + switch (s->mant4_cnt) { + case 0: + s->qmant4_ptr = &qmant[i]; + v = 11 * v; + s->mant4_cnt = 1; + break; + default: + *s->qmant4_ptr += v; + s->mant4_cnt = 0; + v = 128; + break; + } + break; + case 5: + v = sym_quant(c, e, 15); + break; + case 14: + v = asym_quant(c, e, 14); + break; + case 15: + v = asym_quant(c, e, 16); + break; + default: + v = asym_quant(c, e, v - 1); + break; + } + qmant[i] = v; + } +} + + +/** + * Quantize mantissas using coefficients, exponents, and bit allocation pointers. + * + * @param s AC-3 encoder private context + */ +void ff_ac3_quantize_mantissas(AC3EncodeContext *s) +{ + int blk, ch, ch0=0, got_cpl; + + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + AC3Mant m = { 0 }; + + got_cpl = !block->cpl_in_use; + for (ch = 1; ch <= s->channels; ch++) { + if (!got_cpl && ch > 1 && block->channel_in_cpl[ch-1]) { + ch0 = ch - 1; + ch = CPL_CH; + got_cpl = 1; + } + quantize_mantissas_blk_ch(&m, block->fixed_coef[ch], + s->blocks[s->exp_ref_block[ch][blk]].exp[ch], + s->ref_bap[ch][blk], block->qmant[ch], + s->start_freq[ch], block->end_freq[ch]); + if (ch == CPL_CH) + ch = ch0; + } + } +} + + +/* + * Write the AC-3 frame header to the output bitstream. + */ +static void ac3_output_frame_header(AC3EncodeContext *s) +{ + AC3EncOptions *opt = &s->options; + + put_bits(&s->pb, 16, 0x0b77); /* frame header */ + put_bits(&s->pb, 16, 0); /* crc1: will be filled later */ + put_bits(&s->pb, 2, s->bit_alloc.sr_code); + put_bits(&s->pb, 6, s->frame_size_code + (s->frame_size - s->frame_size_min) / 2); + put_bits(&s->pb, 5, s->bitstream_id); + put_bits(&s->pb, 3, s->bitstream_mode); + put_bits(&s->pb, 3, s->channel_mode); + if ((s->channel_mode & 0x01) && s->channel_mode != AC3_CHMODE_MONO) + put_bits(&s->pb, 2, s->center_mix_level); + if (s->channel_mode & 0x04) + put_bits(&s->pb, 2, s->surround_mix_level); + if (s->channel_mode == AC3_CHMODE_STEREO) + put_bits(&s->pb, 2, opt->dolby_surround_mode); + put_bits(&s->pb, 1, s->lfe_on); /* LFE */ + put_bits(&s->pb, 5, -opt->dialogue_level); + put_bits(&s->pb, 1, 0); /* no compression control word */ + put_bits(&s->pb, 1, 0); /* no lang code */ + put_bits(&s->pb, 1, opt->audio_production_info); + if (opt->audio_production_info) { + put_bits(&s->pb, 5, opt->mixing_level - 80); + put_bits(&s->pb, 2, opt->room_type); + } + put_bits(&s->pb, 1, opt->copyright); + put_bits(&s->pb, 1, opt->original); + if (s->bitstream_id == 6) { + /* alternate bit stream syntax */ + put_bits(&s->pb, 1, opt->extended_bsi_1); + if (opt->extended_bsi_1) { + put_bits(&s->pb, 2, opt->preferred_stereo_downmix); + put_bits(&s->pb, 3, s->ltrt_center_mix_level); + put_bits(&s->pb, 3, s->ltrt_surround_mix_level); + put_bits(&s->pb, 3, s->loro_center_mix_level); + put_bits(&s->pb, 3, s->loro_surround_mix_level); + } + put_bits(&s->pb, 1, opt->extended_bsi_2); + if (opt->extended_bsi_2) { + put_bits(&s->pb, 2, opt->dolby_surround_ex_mode); + put_bits(&s->pb, 2, opt->dolby_headphone_mode); + put_bits(&s->pb, 1, opt->ad_converter_type); + put_bits(&s->pb, 9, 0); /* xbsi2 and encinfo : reserved */ + } + } else { + put_bits(&s->pb, 1, 0); /* no time code 1 */ + put_bits(&s->pb, 1, 0); /* no time code 2 */ + } + put_bits(&s->pb, 1, 0); /* no additional bit stream info */ +} + + +/* + * Write one audio block to the output bitstream. + */ +static void output_audio_block(AC3EncodeContext *s, int blk) +{ + int ch, i, baie, bnd, got_cpl, av_uninit(ch0); + AC3Block *block = &s->blocks[blk]; + + /* block switching */ + if (!s->eac3) { + for (ch = 0; ch < s->fbw_channels; ch++) + put_bits(&s->pb, 1, 0); + } + + /* dither flags */ + if (!s->eac3) { + for (ch = 0; ch < s->fbw_channels; ch++) + put_bits(&s->pb, 1, 1); + } + + /* dynamic range codes */ + put_bits(&s->pb, 1, 0); + + /* spectral extension */ + if (s->eac3) + put_bits(&s->pb, 1, 0); + + /* channel coupling */ + if (!s->eac3) + put_bits(&s->pb, 1, block->new_cpl_strategy); + if (block->new_cpl_strategy) { + if (!s->eac3) + put_bits(&s->pb, 1, block->cpl_in_use); + if (block->cpl_in_use) { + int start_sub, end_sub; + if (s->eac3) + put_bits(&s->pb, 1, 0); /* enhanced coupling */ + if (!s->eac3 || s->channel_mode != AC3_CHMODE_STEREO) { + for (ch = 1; ch <= s->fbw_channels; ch++) + put_bits(&s->pb, 1, block->channel_in_cpl[ch]); + } + if (s->channel_mode == AC3_CHMODE_STEREO) + put_bits(&s->pb, 1, 0); /* phase flags in use */ + start_sub = (s->start_freq[CPL_CH] - 37) / 12; + end_sub = (s->cpl_end_freq - 37) / 12; + put_bits(&s->pb, 4, start_sub); + put_bits(&s->pb, 4, end_sub - 3); + /* coupling band structure */ + if (s->eac3) { + put_bits(&s->pb, 1, 0); /* use default */ + } else { + for (bnd = start_sub+1; bnd < end_sub; bnd++) + put_bits(&s->pb, 1, ff_eac3_default_cpl_band_struct[bnd]); + } + } + } + + /* coupling coordinates */ + if (block->cpl_in_use) { + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (block->channel_in_cpl[ch]) { + if (!s->eac3 || block->new_cpl_coords[ch] != 2) + put_bits(&s->pb, 1, block->new_cpl_coords[ch]); + if (block->new_cpl_coords[ch]) { + put_bits(&s->pb, 2, block->cpl_master_exp[ch]); + for (bnd = 0; bnd < s->num_cpl_bands; bnd++) { + put_bits(&s->pb, 4, block->cpl_coord_exp [ch][bnd]); + put_bits(&s->pb, 4, block->cpl_coord_mant[ch][bnd]); + } + } + } + } + } + + /* stereo rematrixing */ + if (s->channel_mode == AC3_CHMODE_STEREO) { + if (!s->eac3 || blk > 0) + put_bits(&s->pb, 1, block->new_rematrixing_strategy); + if (block->new_rematrixing_strategy) { + /* rematrixing flags */ + for (bnd = 0; bnd < block->num_rematrixing_bands; bnd++) + put_bits(&s->pb, 1, block->rematrixing_flags[bnd]); + } + } + + /* exponent strategy */ + if (!s->eac3) { + for (ch = !block->cpl_in_use; ch <= s->fbw_channels; ch++) + put_bits(&s->pb, 2, s->exp_strategy[ch][blk]); + if (s->lfe_on) + put_bits(&s->pb, 1, s->exp_strategy[s->lfe_channel][blk]); + } + + /* bandwidth */ + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (s->exp_strategy[ch][blk] != EXP_REUSE && !block->channel_in_cpl[ch]) + put_bits(&s->pb, 6, s->bandwidth_code); + } + + /* exponents */ + for (ch = !block->cpl_in_use; ch <= s->channels; ch++) { + int nb_groups; + int cpl = (ch == CPL_CH); + + if (s->exp_strategy[ch][blk] == EXP_REUSE) + continue; + + /* DC exponent */ + put_bits(&s->pb, 4, block->grouped_exp[ch][0] >> cpl); + + /* exponent groups */ + nb_groups = exponent_group_tab[cpl][s->exp_strategy[ch][blk]-1][block->end_freq[ch]-s->start_freq[ch]]; + for (i = 1; i <= nb_groups; i++) + put_bits(&s->pb, 7, block->grouped_exp[ch][i]); + + /* gain range info */ + if (ch != s->lfe_channel && !cpl) + put_bits(&s->pb, 2, 0); + } + + /* bit allocation info */ + if (!s->eac3) { + baie = (blk == 0); + put_bits(&s->pb, 1, baie); + if (baie) { + put_bits(&s->pb, 2, s->slow_decay_code); + put_bits(&s->pb, 2, s->fast_decay_code); + put_bits(&s->pb, 2, s->slow_gain_code); + put_bits(&s->pb, 2, s->db_per_bit_code); + put_bits(&s->pb, 3, s->floor_code); + } + } + + /* snr offset */ + if (!s->eac3) { + put_bits(&s->pb, 1, block->new_snr_offsets); + if (block->new_snr_offsets) { + put_bits(&s->pb, 6, s->coarse_snr_offset); + for (ch = !block->cpl_in_use; ch <= s->channels; ch++) { + put_bits(&s->pb, 4, s->fine_snr_offset[ch]); + put_bits(&s->pb, 3, s->fast_gain_code[ch]); + } + } + } else { + put_bits(&s->pb, 1, 0); /* no converter snr offset */ + } + + /* coupling leak */ + if (block->cpl_in_use) { + if (!s->eac3 || block->new_cpl_leak != 2) + put_bits(&s->pb, 1, block->new_cpl_leak); + if (block->new_cpl_leak) { + put_bits(&s->pb, 3, s->bit_alloc.cpl_fast_leak); + put_bits(&s->pb, 3, s->bit_alloc.cpl_slow_leak); + } + } + + if (!s->eac3) { + put_bits(&s->pb, 1, 0); /* no delta bit allocation */ + put_bits(&s->pb, 1, 0); /* no data to skip */ + } + + /* mantissas */ + got_cpl = !block->cpl_in_use; + for (ch = 1; ch <= s->channels; ch++) { + int b, q; + + if (!got_cpl && ch > 1 && block->channel_in_cpl[ch-1]) { + ch0 = ch - 1; + ch = CPL_CH; + got_cpl = 1; + } + for (i = s->start_freq[ch]; i < block->end_freq[ch]; i++) { + q = block->qmant[ch][i]; + b = s->ref_bap[ch][blk][i]; + switch (b) { + case 0: break; + case 1: if (q != 128) put_bits (&s->pb, 5, q); break; + case 2: if (q != 128) put_bits (&s->pb, 7, q); break; + case 3: put_sbits(&s->pb, 3, q); break; + case 4: if (q != 128) put_bits (&s->pb, 7, q); break; + case 14: put_sbits(&s->pb, 14, q); break; + case 15: put_sbits(&s->pb, 16, q); break; + default: put_sbits(&s->pb, b-1, q); break; + } + } + if (ch == CPL_CH) + ch = ch0; + } +} + + +/** CRC-16 Polynomial */ +#define CRC16_POLY ((1 << 0) | (1 << 2) | (1 << 15) | (1 << 16)) + + +static unsigned int mul_poly(unsigned int a, unsigned int b, unsigned int poly) +{ + unsigned int c; + + c = 0; + while (a) { + if (a & 1) + c ^= b; + a = a >> 1; + b = b << 1; + if (b & (1 << 16)) + b ^= poly; + } + return c; +} + + +static unsigned int pow_poly(unsigned int a, unsigned int n, unsigned int poly) +{ + unsigned int r; + r = 1; + while (n) { + if (n & 1) + r = mul_poly(r, a, poly); + a = mul_poly(a, a, poly); + n >>= 1; + } + return r; +} + + +/* + * Fill the end of the frame with 0's and compute the two CRCs. + */ +static void output_frame_end(AC3EncodeContext *s) +{ + const AVCRC *crc_ctx = av_crc_get_table(AV_CRC_16_ANSI); + int frame_size_58, pad_bytes, crc1, crc2_partial, crc2, crc_inv; + uint8_t *frame; + + frame_size_58 = ((s->frame_size >> 2) + (s->frame_size >> 4)) << 1; + + /* pad the remainder of the frame with zeros */ + av_assert2(s->frame_size * 8 - put_bits_count(&s->pb) >= 18); + flush_put_bits(&s->pb); + frame = s->pb.buf; + pad_bytes = s->frame_size - (put_bits_ptr(&s->pb) - frame) - 2; + av_assert2(pad_bytes >= 0); + if (pad_bytes > 0) + memset(put_bits_ptr(&s->pb), 0, pad_bytes); + + if (s->eac3) { + /* compute crc2 */ + crc2_partial = av_crc(crc_ctx, 0, frame + 2, s->frame_size - 5); + } else { + /* compute crc1 */ + /* this is not so easy because it is at the beginning of the data... */ + crc1 = av_bswap16(av_crc(crc_ctx, 0, frame + 4, frame_size_58 - 4)); + crc_inv = s->crc_inv[s->frame_size > s->frame_size_min]; + crc1 = mul_poly(crc_inv, crc1, CRC16_POLY); + AV_WB16(frame + 2, crc1); + + /* compute crc2 */ + crc2_partial = av_crc(crc_ctx, 0, frame + frame_size_58, + s->frame_size - frame_size_58 - 3); + } + crc2 = av_crc(crc_ctx, crc2_partial, frame + s->frame_size - 3, 1); + /* ensure crc2 does not match sync word by flipping crcrsv bit if needed */ + if (crc2 == 0x770B) { + frame[s->frame_size - 3] ^= 0x1; + crc2 = av_crc(crc_ctx, crc2_partial, frame + s->frame_size - 3, 1); + } + crc2 = av_bswap16(crc2); + AV_WB16(frame + s->frame_size - 2, crc2); +} + + +/** + * Write the frame to the output bitstream. + * + * @param s AC-3 encoder private context + * @param frame output data buffer + */ +void ff_ac3_output_frame(AC3EncodeContext *s, unsigned char *frame) +{ + int blk; + + init_put_bits(&s->pb, frame, AC3_MAX_CODED_FRAME_SIZE); + + s->output_frame_header(s); + + for (blk = 0; blk < s->num_blocks; blk++) + output_audio_block(s, blk); + + output_frame_end(s); +} + + +static void dprint_options(AC3EncodeContext *s) +{ +#ifdef DEBUG + AVCodecContext *avctx = s->avctx; + AC3EncOptions *opt = &s->options; + char strbuf[32]; + + switch (s->bitstream_id) { + case 6: av_strlcpy(strbuf, "AC-3 (alt syntax)", 32); break; + case 8: av_strlcpy(strbuf, "AC-3 (standard)", 32); break; + case 9: av_strlcpy(strbuf, "AC-3 (dnet half-rate)", 32); break; + case 10: av_strlcpy(strbuf, "AC-3 (dnet quater-rate)", 32); break; + case 16: av_strlcpy(strbuf, "E-AC-3 (enhanced)", 32); break; + default: snprintf(strbuf, 32, "ERROR"); + } + ff_dlog(avctx, "bitstream_id: %s (%d)\n", strbuf, s->bitstream_id); + ff_dlog(avctx, "sample_fmt: %s\n", av_get_sample_fmt_name(avctx->sample_fmt)); + av_get_channel_layout_string(strbuf, 32, s->channels, avctx->channel_layout); + ff_dlog(avctx, "channel_layout: %s\n", strbuf); + ff_dlog(avctx, "sample_rate: %d\n", s->sample_rate); + ff_dlog(avctx, "bit_rate: %d\n", s->bit_rate); + ff_dlog(avctx, "blocks/frame: %d (code=%d)\n", s->num_blocks, s->num_blks_code); + if (s->cutoff) + ff_dlog(avctx, "cutoff: %d\n", s->cutoff); + + ff_dlog(avctx, "per_frame_metadata: %s\n", + opt->allow_per_frame_metadata?"on":"off"); + if (s->has_center) + ff_dlog(avctx, "center_mixlev: %0.3f (%d)\n", opt->center_mix_level, + s->center_mix_level); + else + ff_dlog(avctx, "center_mixlev: {not written}\n"); + if (s->has_surround) + ff_dlog(avctx, "surround_mixlev: %0.3f (%d)\n", opt->surround_mix_level, + s->surround_mix_level); + else + ff_dlog(avctx, "surround_mixlev: {not written}\n"); + if (opt->audio_production_info) { + ff_dlog(avctx, "mixing_level: %ddB\n", opt->mixing_level); + switch (opt->room_type) { + case AC3ENC_OPT_NOT_INDICATED: av_strlcpy(strbuf, "notindicated", 32); break; + case AC3ENC_OPT_LARGE_ROOM: av_strlcpy(strbuf, "large", 32); break; + case AC3ENC_OPT_SMALL_ROOM: av_strlcpy(strbuf, "small", 32); break; + default: snprintf(strbuf, 32, "ERROR (%d)", opt->room_type); + } + ff_dlog(avctx, "room_type: %s\n", strbuf); + } else { + ff_dlog(avctx, "mixing_level: {not written}\n"); + ff_dlog(avctx, "room_type: {not written}\n"); + } + ff_dlog(avctx, "copyright: %s\n", opt->copyright?"on":"off"); + ff_dlog(avctx, "dialnorm: %ddB\n", opt->dialogue_level); + if (s->channel_mode == AC3_CHMODE_STEREO) { + switch (opt->dolby_surround_mode) { + case AC3ENC_OPT_NOT_INDICATED: av_strlcpy(strbuf, "notindicated", 32); break; + case AC3ENC_OPT_MODE_ON: av_strlcpy(strbuf, "on", 32); break; + case AC3ENC_OPT_MODE_OFF: av_strlcpy(strbuf, "off", 32); break; + default: snprintf(strbuf, 32, "ERROR (%d)", opt->dolby_surround_mode); + } + ff_dlog(avctx, "dsur_mode: %s\n", strbuf); + } else { + ff_dlog(avctx, "dsur_mode: {not written}\n"); + } + ff_dlog(avctx, "original: %s\n", opt->original?"on":"off"); + + if (s->bitstream_id == 6) { + if (opt->extended_bsi_1) { + switch (opt->preferred_stereo_downmix) { + case AC3ENC_OPT_NOT_INDICATED: av_strlcpy(strbuf, "notindicated", 32); break; + case AC3ENC_OPT_DOWNMIX_LTRT: av_strlcpy(strbuf, "ltrt", 32); break; + case AC3ENC_OPT_DOWNMIX_LORO: av_strlcpy(strbuf, "loro", 32); break; + default: snprintf(strbuf, 32, "ERROR (%d)", opt->preferred_stereo_downmix); + } + ff_dlog(avctx, "dmix_mode: %s\n", strbuf); + ff_dlog(avctx, "ltrt_cmixlev: %0.3f (%d)\n", + opt->ltrt_center_mix_level, s->ltrt_center_mix_level); + ff_dlog(avctx, "ltrt_surmixlev: %0.3f (%d)\n", + opt->ltrt_surround_mix_level, s->ltrt_surround_mix_level); + ff_dlog(avctx, "loro_cmixlev: %0.3f (%d)\n", + opt->loro_center_mix_level, s->loro_center_mix_level); + ff_dlog(avctx, "loro_surmixlev: %0.3f (%d)\n", + opt->loro_surround_mix_level, s->loro_surround_mix_level); + } else { + ff_dlog(avctx, "extended bitstream info 1: {not written}\n"); + } + if (opt->extended_bsi_2) { + switch (opt->dolby_surround_ex_mode) { + case AC3ENC_OPT_NOT_INDICATED: av_strlcpy(strbuf, "notindicated", 32); break; + case AC3ENC_OPT_MODE_ON: av_strlcpy(strbuf, "on", 32); break; + case AC3ENC_OPT_MODE_OFF: av_strlcpy(strbuf, "off", 32); break; + default: snprintf(strbuf, 32, "ERROR (%d)", opt->dolby_surround_ex_mode); + } + ff_dlog(avctx, "dsurex_mode: %s\n", strbuf); + switch (opt->dolby_headphone_mode) { + case AC3ENC_OPT_NOT_INDICATED: av_strlcpy(strbuf, "notindicated", 32); break; + case AC3ENC_OPT_MODE_ON: av_strlcpy(strbuf, "on", 32); break; + case AC3ENC_OPT_MODE_OFF: av_strlcpy(strbuf, "off", 32); break; + default: snprintf(strbuf, 32, "ERROR (%d)", opt->dolby_headphone_mode); + } + ff_dlog(avctx, "dheadphone_mode: %s\n", strbuf); + + switch (opt->ad_converter_type) { + case AC3ENC_OPT_ADCONV_STANDARD: av_strlcpy(strbuf, "standard", 32); break; + case AC3ENC_OPT_ADCONV_HDCD: av_strlcpy(strbuf, "hdcd", 32); break; + default: snprintf(strbuf, 32, "ERROR (%d)", opt->ad_converter_type); + } + ff_dlog(avctx, "ad_conv_type: %s\n", strbuf); + } else { + ff_dlog(avctx, "extended bitstream info 2: {not written}\n"); + } + } +#endif +} + + +#define FLT_OPTION_THRESHOLD 0.01 + +static int validate_float_option(float v, const float *v_list, int v_list_size) +{ + int i; + + for (i = 0; i < v_list_size; i++) { + if (v < (v_list[i] + FLT_OPTION_THRESHOLD) && + v > (v_list[i] - FLT_OPTION_THRESHOLD)) + break; + } + if (i == v_list_size) + return AVERROR(EINVAL); + + return i; +} + + +static void validate_mix_level(void *log_ctx, const char *opt_name, + float *opt_param, const float *list, + int list_size, int default_value, int min_value, + int *ctx_param) +{ + int mixlev = validate_float_option(*opt_param, list, list_size); + if (mixlev < min_value) { + mixlev = default_value; + if (*opt_param >= 0.0) { + av_log(log_ctx, AV_LOG_WARNING, "requested %s is not valid. using " + "default value: %0.3f\n", opt_name, list[mixlev]); + } + } + *opt_param = list[mixlev]; + *ctx_param = mixlev; +} + + +/** + * Validate metadata options as set by AVOption system. + * These values can optionally be changed per-frame. + * + * @param s AC-3 encoder private context + */ +int ff_ac3_validate_metadata(AC3EncodeContext *s) +{ + AVCodecContext *avctx = s->avctx; + AC3EncOptions *opt = &s->options; + + opt->audio_production_info = 0; + opt->extended_bsi_1 = 0; + opt->extended_bsi_2 = 0; + opt->eac3_mixing_metadata = 0; + opt->eac3_info_metadata = 0; + + /* determine mixing metadata / xbsi1 use */ + if (s->channel_mode > AC3_CHMODE_STEREO && opt->preferred_stereo_downmix != AC3ENC_OPT_NONE) { + opt->extended_bsi_1 = 1; + opt->eac3_mixing_metadata = 1; + } + if (s->has_center && + (opt->ltrt_center_mix_level >= 0 || opt->loro_center_mix_level >= 0)) { + opt->extended_bsi_1 = 1; + opt->eac3_mixing_metadata = 1; + } + if (s->has_surround && + (opt->ltrt_surround_mix_level >= 0 || opt->loro_surround_mix_level >= 0)) { + opt->extended_bsi_1 = 1; + opt->eac3_mixing_metadata = 1; + } + + if (s->eac3) { + /* determine info metadata use */ + if (avctx->audio_service_type != AV_AUDIO_SERVICE_TYPE_MAIN) + opt->eac3_info_metadata = 1; + if (opt->copyright != AC3ENC_OPT_NONE || opt->original != AC3ENC_OPT_NONE) + opt->eac3_info_metadata = 1; + if (s->channel_mode == AC3_CHMODE_STEREO && + (opt->dolby_headphone_mode != AC3ENC_OPT_NONE || opt->dolby_surround_mode != AC3ENC_OPT_NONE)) + opt->eac3_info_metadata = 1; + if (s->channel_mode >= AC3_CHMODE_2F2R && opt->dolby_surround_ex_mode != AC3ENC_OPT_NONE) + opt->eac3_info_metadata = 1; + if (opt->mixing_level != AC3ENC_OPT_NONE || opt->room_type != AC3ENC_OPT_NONE || + opt->ad_converter_type != AC3ENC_OPT_NONE) { + opt->audio_production_info = 1; + opt->eac3_info_metadata = 1; + } + } else { + /* determine audio production info use */ + if (opt->mixing_level != AC3ENC_OPT_NONE || opt->room_type != AC3ENC_OPT_NONE) + opt->audio_production_info = 1; + + /* determine xbsi2 use */ + if (s->channel_mode >= AC3_CHMODE_2F2R && opt->dolby_surround_ex_mode != AC3ENC_OPT_NONE) + opt->extended_bsi_2 = 1; + if (s->channel_mode == AC3_CHMODE_STEREO && opt->dolby_headphone_mode != AC3ENC_OPT_NONE) + opt->extended_bsi_2 = 1; + if (opt->ad_converter_type != AC3ENC_OPT_NONE) + opt->extended_bsi_2 = 1; + } + + /* validate AC-3 mixing levels */ + if (!s->eac3) { + if (s->has_center) { + validate_mix_level(avctx, "center_mix_level", &opt->center_mix_level, + cmixlev_options, CMIXLEV_NUM_OPTIONS, 1, 0, + &s->center_mix_level); + } + if (s->has_surround) { + validate_mix_level(avctx, "surround_mix_level", &opt->surround_mix_level, + surmixlev_options, SURMIXLEV_NUM_OPTIONS, 1, 0, + &s->surround_mix_level); + } + } + + /* validate extended bsi 1 / mixing metadata */ + if (opt->extended_bsi_1 || opt->eac3_mixing_metadata) { + /* default preferred stereo downmix */ + if (opt->preferred_stereo_downmix == AC3ENC_OPT_NONE) + opt->preferred_stereo_downmix = AC3ENC_OPT_NOT_INDICATED; + if (!s->eac3 || s->has_center) { + /* validate Lt/Rt center mix level */ + validate_mix_level(avctx, "ltrt_center_mix_level", + &opt->ltrt_center_mix_level, extmixlev_options, + EXTMIXLEV_NUM_OPTIONS, 5, 0, + &s->ltrt_center_mix_level); + /* validate Lo/Ro center mix level */ + validate_mix_level(avctx, "loro_center_mix_level", + &opt->loro_center_mix_level, extmixlev_options, + EXTMIXLEV_NUM_OPTIONS, 5, 0, + &s->loro_center_mix_level); + } + if (!s->eac3 || s->has_surround) { + /* validate Lt/Rt surround mix level */ + validate_mix_level(avctx, "ltrt_surround_mix_level", + &opt->ltrt_surround_mix_level, extmixlev_options, + EXTMIXLEV_NUM_OPTIONS, 6, 3, + &s->ltrt_surround_mix_level); + /* validate Lo/Ro surround mix level */ + validate_mix_level(avctx, "loro_surround_mix_level", + &opt->loro_surround_mix_level, extmixlev_options, + EXTMIXLEV_NUM_OPTIONS, 6, 3, + &s->loro_surround_mix_level); + } + } + + /* validate audio service type / channels combination */ + if ((avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_KARAOKE && + avctx->channels == 1) || + ((avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_COMMENTARY || + avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_EMERGENCY || + avctx->audio_service_type == AV_AUDIO_SERVICE_TYPE_VOICE_OVER) + && avctx->channels > 1)) { + av_log(avctx, AV_LOG_ERROR, "invalid audio service type for the " + "specified number of channels\n"); + return AVERROR(EINVAL); + } + + /* validate extended bsi 2 / info metadata */ + if (opt->extended_bsi_2 || opt->eac3_info_metadata) { + /* default dolby headphone mode */ + if (opt->dolby_headphone_mode == AC3ENC_OPT_NONE) + opt->dolby_headphone_mode = AC3ENC_OPT_NOT_INDICATED; + /* default dolby surround ex mode */ + if (opt->dolby_surround_ex_mode == AC3ENC_OPT_NONE) + opt->dolby_surround_ex_mode = AC3ENC_OPT_NOT_INDICATED; + /* default A/D converter type */ + if (opt->ad_converter_type == AC3ENC_OPT_NONE) + opt->ad_converter_type = AC3ENC_OPT_ADCONV_STANDARD; + } + + /* copyright & original defaults */ + if (!s->eac3 || opt->eac3_info_metadata) { + /* default copyright */ + if (opt->copyright == AC3ENC_OPT_NONE) + opt->copyright = AC3ENC_OPT_OFF; + /* default original */ + if (opt->original == AC3ENC_OPT_NONE) + opt->original = AC3ENC_OPT_ON; + } + + /* dolby surround mode default */ + if (!s->eac3 || opt->eac3_info_metadata) { + if (opt->dolby_surround_mode == AC3ENC_OPT_NONE) + opt->dolby_surround_mode = AC3ENC_OPT_NOT_INDICATED; + } + + /* validate audio production info */ + if (opt->audio_production_info) { + if (opt->mixing_level == AC3ENC_OPT_NONE) { + av_log(avctx, AV_LOG_ERROR, "mixing_level must be set if " + "room_type is set\n"); + return AVERROR(EINVAL); + } + if (opt->mixing_level < 80) { + av_log(avctx, AV_LOG_ERROR, "invalid mixing level. must be between " + "80dB and 111dB\n"); + return AVERROR(EINVAL); + } + /* default room type */ + if (opt->room_type == AC3ENC_OPT_NONE) + opt->room_type = AC3ENC_OPT_NOT_INDICATED; + } + + /* set bitstream id for alternate bitstream syntax */ + if (!s->eac3 && (opt->extended_bsi_1 || opt->extended_bsi_2)) { + if (s->bitstream_id > 8 && s->bitstream_id < 11) { + static int warn_once = 1; + if (warn_once) { + av_log(avctx, AV_LOG_WARNING, "alternate bitstream syntax is " + "not compatible with reduced samplerates. writing of " + "extended bitstream information will be disabled.\n"); + warn_once = 0; + } + } else { + s->bitstream_id = 6; + } + } + + return 0; +} + + +/** + * Finalize encoding and free any memory allocated by the encoder. + * + * @param avctx Codec context + */ +av_cold int ff_ac3_encode_close(AVCodecContext *avctx) +{ + int blk, ch; + AC3EncodeContext *s = avctx->priv_data; + + av_freep(&s->windowed_samples); + if (s->planar_samples) + for (ch = 0; ch < s->channels; ch++) + av_freep(&s->planar_samples[ch]); + av_freep(&s->planar_samples); + av_freep(&s->bap_buffer); + av_freep(&s->bap1_buffer); + av_freep(&s->mdct_coef_buffer); + av_freep(&s->fixed_coef_buffer); + av_freep(&s->exp_buffer); + av_freep(&s->grouped_exp_buffer); + av_freep(&s->psd_buffer); + av_freep(&s->band_psd_buffer); + av_freep(&s->mask_buffer); + av_freep(&s->qmant_buffer); + av_freep(&s->cpl_coord_exp_buffer); + av_freep(&s->cpl_coord_mant_buffer); + av_freep(&s->fdsp); + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + av_freep(&block->mdct_coef); + av_freep(&block->fixed_coef); + av_freep(&block->exp); + av_freep(&block->grouped_exp); + av_freep(&block->psd); + av_freep(&block->band_psd); + av_freep(&block->mask); + av_freep(&block->qmant); + av_freep(&block->cpl_coord_exp); + av_freep(&block->cpl_coord_mant); + } + + s->mdct_end(s); + + return 0; +} + + +/* + * Set channel information during initialization. + */ +static av_cold int set_channel_info(AC3EncodeContext *s, int channels, + uint64_t *channel_layout) +{ + int ch_layout; + + if (channels < 1 || channels > AC3_MAX_CHANNELS) + return AVERROR(EINVAL); + if (*channel_layout > 0x7FF) + return AVERROR(EINVAL); + ch_layout = *channel_layout; + if (!ch_layout) + ch_layout = av_get_default_channel_layout(channels); + + s->lfe_on = !!(ch_layout & AV_CH_LOW_FREQUENCY); + s->channels = channels; + s->fbw_channels = channels - s->lfe_on; + s->lfe_channel = s->lfe_on ? s->fbw_channels + 1 : -1; + if (s->lfe_on) + ch_layout -= AV_CH_LOW_FREQUENCY; + + switch (ch_layout) { + case AV_CH_LAYOUT_MONO: s->channel_mode = AC3_CHMODE_MONO; break; + case AV_CH_LAYOUT_STEREO: s->channel_mode = AC3_CHMODE_STEREO; break; + case AV_CH_LAYOUT_SURROUND: s->channel_mode = AC3_CHMODE_3F; break; + case AV_CH_LAYOUT_2_1: s->channel_mode = AC3_CHMODE_2F1R; break; + case AV_CH_LAYOUT_4POINT0: s->channel_mode = AC3_CHMODE_3F1R; break; + case AV_CH_LAYOUT_QUAD: + case AV_CH_LAYOUT_2_2: s->channel_mode = AC3_CHMODE_2F2R; break; + case AV_CH_LAYOUT_5POINT0: + case AV_CH_LAYOUT_5POINT0_BACK: s->channel_mode = AC3_CHMODE_3F2R; break; + default: + return AVERROR(EINVAL); + } + s->has_center = (s->channel_mode & 0x01) && s->channel_mode != AC3_CHMODE_MONO; + s->has_surround = s->channel_mode & 0x04; + + s->channel_map = ff_ac3_enc_channel_map[s->channel_mode][s->lfe_on]; + *channel_layout = ch_layout; + if (s->lfe_on) + *channel_layout |= AV_CH_LOW_FREQUENCY; + + return 0; +} + + +static av_cold int validate_options(AC3EncodeContext *s) +{ + AVCodecContext *avctx = s->avctx; + int i, ret, max_sr; + + /* validate channel layout */ + if (!avctx->channel_layout) { + av_log(avctx, AV_LOG_WARNING, "No channel layout specified. The " + "encoder will guess the layout, but it " + "might be incorrect.\n"); + } + ret = set_channel_info(s, avctx->channels, &avctx->channel_layout); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "invalid channel layout\n"); + return ret; + } + + /* validate sample rate */ + /* note: max_sr could be changed from 2 to 5 for E-AC-3 once we find a + decoder that supports half sample rate so we can validate that + the generated files are correct. */ + max_sr = s->eac3 ? 2 : 8; + for (i = 0; i <= max_sr; i++) { + if ((ff_ac3_sample_rate_tab[i % 3] >> (i / 3)) == avctx->sample_rate) + break; + } + if (i > max_sr) { + av_log(avctx, AV_LOG_ERROR, "invalid sample rate\n"); + return AVERROR(EINVAL); + } + s->sample_rate = avctx->sample_rate; + s->bit_alloc.sr_shift = i / 3; + s->bit_alloc.sr_code = i % 3; + s->bitstream_id = s->eac3 ? 16 : 8 + s->bit_alloc.sr_shift; + + /* select a default bit rate if not set by the user */ + if (!avctx->bit_rate) { + switch (s->fbw_channels) { + case 1: avctx->bit_rate = 96000; break; + case 2: avctx->bit_rate = 192000; break; + case 3: avctx->bit_rate = 320000; break; + case 4: avctx->bit_rate = 384000; break; + case 5: avctx->bit_rate = 448000; break; + } + } + + /* validate bit rate */ + if (s->eac3) { + int max_br, min_br, wpf, min_br_code; + int num_blks_code, num_blocks, frame_samples; + long long min_br_dist; + + /* calculate min/max bitrate */ + /* TODO: More testing with 3 and 2 blocks. All E-AC-3 samples I've + found use either 6 blocks or 1 block, even though 2 or 3 blocks + would work as far as the bit rate is concerned. */ + for (num_blks_code = 3; num_blks_code >= 0; num_blks_code--) { + num_blocks = ((int[]){ 1, 2, 3, 6 })[num_blks_code]; + frame_samples = AC3_BLOCK_SIZE * num_blocks; + max_br = 2048 * s->sample_rate / frame_samples * 16; + min_br = ((s->sample_rate + (frame_samples-1)) / frame_samples) * 16; + if (avctx->bit_rate <= max_br) + break; + } + if (avctx->bit_rate < min_br || avctx->bit_rate > max_br) { + av_log(avctx, AV_LOG_ERROR, "invalid bit rate. must be %d to %d " + "for this sample rate\n", min_br, max_br); + return AVERROR(EINVAL); + } + s->num_blks_code = num_blks_code; + s->num_blocks = num_blocks; + + /* calculate words-per-frame for the selected bitrate */ + wpf = (avctx->bit_rate / 16) * frame_samples / s->sample_rate; + av_assert1(wpf > 0 && wpf <= 2048); + + /* find the closest AC-3 bitrate code to the selected bitrate. + this is needed for lookup tables for bandwidth and coupling + parameter selection */ + min_br_code = -1; + min_br_dist = INT64_MAX; + for (i = 0; i < 19; i++) { + long long br_dist = llabs(ff_ac3_bitrate_tab[i] * 1000 - avctx->bit_rate); + if (br_dist < min_br_dist) { + min_br_dist = br_dist; + min_br_code = i; + } + } + + /* make sure the minimum frame size is below the average frame size */ + s->frame_size_code = min_br_code << 1; + while (wpf > 1 && wpf * s->sample_rate / AC3_FRAME_SIZE * 16 > avctx->bit_rate) + wpf--; + s->frame_size_min = 2 * wpf; + } else { + int best_br = 0, best_code = 0; + long long best_diff = INT64_MAX; + for (i = 0; i < 19; i++) { + int br = (ff_ac3_bitrate_tab[i] >> s->bit_alloc.sr_shift) * 1000; + long long diff = llabs(br - avctx->bit_rate); + if (diff < best_diff) { + best_br = br; + best_code = i; + best_diff = diff; + } + if (!best_diff) + break; + } + avctx->bit_rate = best_br; + s->frame_size_code = best_code << 1; + s->frame_size_min = 2 * ff_ac3_frame_size_tab[s->frame_size_code][s->bit_alloc.sr_code]; + s->num_blks_code = 0x3; + s->num_blocks = 6; + } + s->bit_rate = avctx->bit_rate; + s->frame_size = s->frame_size_min; + + /* validate cutoff */ + if (avctx->cutoff < 0) { + av_log(avctx, AV_LOG_ERROR, "invalid cutoff frequency\n"); + return AVERROR(EINVAL); + } + s->cutoff = avctx->cutoff; + if (s->cutoff > (s->sample_rate >> 1)) + s->cutoff = s->sample_rate >> 1; + + ret = ff_ac3_validate_metadata(s); + if (ret) + return ret; + + s->rematrixing_enabled = s->options.stereo_rematrixing && + (s->channel_mode == AC3_CHMODE_STEREO); + + s->cpl_enabled = s->options.channel_coupling && + s->channel_mode >= AC3_CHMODE_STEREO; + + return 0; +} + + +/* + * Set bandwidth for all channels. + * The user can optionally supply a cutoff frequency. Otherwise an appropriate + * default value will be used. + */ +static av_cold void set_bandwidth(AC3EncodeContext *s) +{ + int blk, ch, av_uninit(cpl_start); + + if (s->cutoff) { + /* calculate bandwidth based on user-specified cutoff frequency */ + int fbw_coeffs; + fbw_coeffs = s->cutoff * 2 * AC3_MAX_COEFS / s->sample_rate; + s->bandwidth_code = av_clip((fbw_coeffs - 73) / 3, 0, 60); + } else { + /* use default bandwidth setting */ + s->bandwidth_code = ac3_bandwidth_tab[s->fbw_channels-1][s->bit_alloc.sr_code][s->frame_size_code/2]; + } + + /* set number of coefficients for each channel */ + for (ch = 1; ch <= s->fbw_channels; ch++) { + s->start_freq[ch] = 0; + for (blk = 0; blk < s->num_blocks; blk++) + s->blocks[blk].end_freq[ch] = s->bandwidth_code * 3 + 73; + } + /* LFE channel always has 7 coefs */ + if (s->lfe_on) { + s->start_freq[s->lfe_channel] = 0; + for (blk = 0; blk < s->num_blocks; blk++) + s->blocks[blk].end_freq[ch] = 7; + } + + /* initialize coupling strategy */ + if (s->cpl_enabled) { + if (s->options.cpl_start != AC3ENC_OPT_AUTO) { + cpl_start = s->options.cpl_start; + } else { + cpl_start = ac3_coupling_start_tab[s->channel_mode-2][s->bit_alloc.sr_code][s->frame_size_code/2]; + if (cpl_start < 0) { + if (s->options.channel_coupling == AC3ENC_OPT_AUTO) + s->cpl_enabled = 0; + else + cpl_start = 15; + } + } + } + if (s->cpl_enabled) { + int i, cpl_start_band, cpl_end_band; + uint8_t *cpl_band_sizes = s->cpl_band_sizes; + + cpl_end_band = s->bandwidth_code / 4 + 3; + cpl_start_band = av_clip(cpl_start, 0, FFMIN(cpl_end_band-1, 15)); + + s->num_cpl_subbands = cpl_end_band - cpl_start_band; + + s->num_cpl_bands = 1; + *cpl_band_sizes = 12; + for (i = cpl_start_band + 1; i < cpl_end_band; i++) { + if (ff_eac3_default_cpl_band_struct[i]) { + *cpl_band_sizes += 12; + } else { + s->num_cpl_bands++; + cpl_band_sizes++; + *cpl_band_sizes = 12; + } + } + + s->start_freq[CPL_CH] = cpl_start_band * 12 + 37; + s->cpl_end_freq = cpl_end_band * 12 + 37; + for (blk = 0; blk < s->num_blocks; blk++) + s->blocks[blk].end_freq[CPL_CH] = s->cpl_end_freq; + } +} + + +static av_cold int allocate_buffers(AC3EncodeContext *s) +{ + AVCodecContext *avctx = s->avctx; + int blk, ch; + int channels = s->channels + 1; /* includes coupling channel */ + int channel_blocks = channels * s->num_blocks; + int total_coefs = AC3_MAX_COEFS * channel_blocks; + + if (s->allocate_sample_buffers(s)) + goto alloc_fail; + + FF_ALLOC_ARRAY_OR_GOTO(avctx, s->bap_buffer, total_coefs, + sizeof(*s->bap_buffer), alloc_fail); + FF_ALLOC_ARRAY_OR_GOTO(avctx, s->bap1_buffer, total_coefs, + sizeof(*s->bap1_buffer), alloc_fail); + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->mdct_coef_buffer, total_coefs, + sizeof(*s->mdct_coef_buffer), alloc_fail); + FF_ALLOC_ARRAY_OR_GOTO(avctx, s->exp_buffer, total_coefs, + sizeof(*s->exp_buffer), alloc_fail); + FF_ALLOC_ARRAY_OR_GOTO(avctx, s->grouped_exp_buffer, channel_blocks, 128 * + sizeof(*s->grouped_exp_buffer), alloc_fail); + FF_ALLOC_ARRAY_OR_GOTO(avctx, s->psd_buffer, total_coefs, + sizeof(*s->psd_buffer), alloc_fail); + FF_ALLOC_ARRAY_OR_GOTO(avctx, s->band_psd_buffer, channel_blocks, 64 * + sizeof(*s->band_psd_buffer), alloc_fail); + FF_ALLOC_ARRAY_OR_GOTO(avctx, s->mask_buffer, channel_blocks, 64 * + sizeof(*s->mask_buffer), alloc_fail); + FF_ALLOC_ARRAY_OR_GOTO(avctx, s->qmant_buffer, total_coefs, + sizeof(*s->qmant_buffer), alloc_fail); + if (s->cpl_enabled) { + FF_ALLOC_ARRAY_OR_GOTO(avctx, s->cpl_coord_exp_buffer, channel_blocks, 16 * + sizeof(*s->cpl_coord_exp_buffer), alloc_fail); + FF_ALLOC_ARRAY_OR_GOTO(avctx, s->cpl_coord_mant_buffer, channel_blocks, 16 * + sizeof(*s->cpl_coord_mant_buffer), alloc_fail); + } + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->mdct_coef, channels, sizeof(*block->mdct_coef), + alloc_fail); + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->exp, channels, sizeof(*block->exp), + alloc_fail); + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->grouped_exp, channels, sizeof(*block->grouped_exp), + alloc_fail); + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->psd, channels, sizeof(*block->psd), + alloc_fail); + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->band_psd, channels, sizeof(*block->band_psd), + alloc_fail); + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->mask, channels, sizeof(*block->mask), + alloc_fail); + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->qmant, channels, sizeof(*block->qmant), + alloc_fail); + if (s->cpl_enabled) { + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->cpl_coord_exp, channels, sizeof(*block->cpl_coord_exp), + alloc_fail); + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->cpl_coord_mant, channels, sizeof(*block->cpl_coord_mant), + alloc_fail); + } + + for (ch = 0; ch < channels; ch++) { + /* arrangement: block, channel, coeff */ + block->grouped_exp[ch] = &s->grouped_exp_buffer[128 * (blk * channels + ch)]; + block->psd[ch] = &s->psd_buffer [AC3_MAX_COEFS * (blk * channels + ch)]; + block->band_psd[ch] = &s->band_psd_buffer [64 * (blk * channels + ch)]; + block->mask[ch] = &s->mask_buffer [64 * (blk * channels + ch)]; + block->qmant[ch] = &s->qmant_buffer [AC3_MAX_COEFS * (blk * channels + ch)]; + if (s->cpl_enabled) { + block->cpl_coord_exp[ch] = &s->cpl_coord_exp_buffer [16 * (blk * channels + ch)]; + block->cpl_coord_mant[ch] = &s->cpl_coord_mant_buffer[16 * (blk * channels + ch)]; + } + + /* arrangement: channel, block, coeff */ + block->exp[ch] = &s->exp_buffer [AC3_MAX_COEFS * (s->num_blocks * ch + blk)]; + block->mdct_coef[ch] = &s->mdct_coef_buffer [AC3_MAX_COEFS * (s->num_blocks * ch + blk)]; + } + } + + if (!s->fixed_point) { + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->fixed_coef_buffer, total_coefs, + sizeof(*s->fixed_coef_buffer), alloc_fail); + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->fixed_coef, channels, + sizeof(*block->fixed_coef), alloc_fail); + for (ch = 0; ch < channels; ch++) + block->fixed_coef[ch] = &s->fixed_coef_buffer[AC3_MAX_COEFS * (s->num_blocks * ch + blk)]; + } + } else { + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, block->fixed_coef, channels, + sizeof(*block->fixed_coef), alloc_fail); + for (ch = 0; ch < channels; ch++) + block->fixed_coef[ch] = (int32_t *)block->mdct_coef[ch]; + } + } + + return 0; +alloc_fail: + return AVERROR(ENOMEM); +} + + +av_cold int ff_ac3_encode_init(AVCodecContext *avctx) +{ + AC3EncodeContext *s = avctx->priv_data; + int ret, frame_size_58; + + s->avctx = avctx; + + s->eac3 = avctx->codec_id == AV_CODEC_ID_EAC3; + + ret = validate_options(s); + if (ret) + return ret; + + avctx->frame_size = AC3_BLOCK_SIZE * s->num_blocks; + avctx->initial_padding = AC3_BLOCK_SIZE; + + s->bitstream_mode = avctx->audio_service_type; + if (s->bitstream_mode == AV_AUDIO_SERVICE_TYPE_KARAOKE) + s->bitstream_mode = 0x7; + + s->bits_written = 0; + s->samples_written = 0; + + /* calculate crc_inv for both possible frame sizes */ + frame_size_58 = (( s->frame_size >> 2) + ( s->frame_size >> 4)) << 1; + s->crc_inv[0] = pow_poly((CRC16_POLY >> 1), (8 * frame_size_58) - 16, CRC16_POLY); + if (s->bit_alloc.sr_code == 1) { + frame_size_58 = (((s->frame_size+2) >> 2) + ((s->frame_size+2) >> 4)) << 1; + s->crc_inv[1] = pow_poly((CRC16_POLY >> 1), (8 * frame_size_58) - 16, CRC16_POLY); + } + + /* set function pointers */ + if (CONFIG_AC3_FIXED_ENCODER && s->fixed_point) { + s->mdct_end = ff_ac3_fixed_mdct_end; + s->mdct_init = ff_ac3_fixed_mdct_init; + s->allocate_sample_buffers = ff_ac3_fixed_allocate_sample_buffers; + } else if (CONFIG_AC3_ENCODER || CONFIG_EAC3_ENCODER) { + s->mdct_end = ff_ac3_float_mdct_end; + s->mdct_init = ff_ac3_float_mdct_init; + s->allocate_sample_buffers = ff_ac3_float_allocate_sample_buffers; + } + if (CONFIG_EAC3_ENCODER && s->eac3) + s->output_frame_header = ff_eac3_output_frame_header; + else + s->output_frame_header = ac3_output_frame_header; + + set_bandwidth(s); + + exponent_init(s); + + bit_alloc_init(s); + + ret = s->mdct_init(s); + if (ret) + goto init_fail; + + ret = allocate_buffers(s); + if (ret) + goto init_fail; + + ff_audiodsp_init(&s->adsp); + ff_me_cmp_init(&s->mecc, avctx); + ff_ac3dsp_init(&s->ac3dsp, avctx->flags & AV_CODEC_FLAG_BITEXACT); + + dprint_options(s); + + return 0; +init_fail: + ff_ac3_encode_close(avctx); + return ret; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc.h new file mode 100644 index 0000000000..a2442d0e55 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc.h @@ -0,0 +1,315 @@ +/* + * AC-3 encoder & E-AC-3 encoder common header + * Copyright (c) 2000 Fabrice Bellard + * Copyright (c) 2006-2010 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AC-3 encoder & E-AC-3 encoder common header + */ + +#ifndef AVCODEC_AC3ENC_H +#define AVCODEC_AC3ENC_H + +#include + +#include "libavutil/float_dsp.h" + +#include "ac3.h" +#include "ac3dsp.h" +#include "avcodec.h" +#include "fft.h" +#include "mathops.h" +#include "me_cmp.h" +#include "put_bits.h" +#include "audiodsp.h" + +#ifndef CONFIG_AC3ENC_FLOAT +#define CONFIG_AC3ENC_FLOAT 0 +#endif + +#define OFFSET(param) offsetof(AC3EncodeContext, options.param) +#define AC3ENC_PARAM (AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) + +#define AC3ENC_TYPE_AC3_FIXED 0 +#define AC3ENC_TYPE_AC3 1 +#define AC3ENC_TYPE_EAC3 2 + +#if CONFIG_AC3ENC_FLOAT +#define AC3_NAME(x) ff_ac3_float_ ## x +#define MAC_COEF(d,a,b) ((d)+=(a)*(b)) +#define COEF_MIN (-16777215.0/16777216.0) +#define COEF_MAX ( 16777215.0/16777216.0) +#define NEW_CPL_COORD_THRESHOLD 0.03 +typedef float SampleType; +typedef float CoefType; +typedef float CoefSumType; +#else +#define AC3_NAME(x) ff_ac3_fixed_ ## x +#define MAC_COEF(d,a,b) MAC64(d,a,b) +#define COEF_MIN -16777215 +#define COEF_MAX 16777215 +#define NEW_CPL_COORD_THRESHOLD 503317 +typedef int16_t SampleType; +typedef int32_t CoefType; +typedef int64_t CoefSumType; +#endif + +/* common option values */ +#define AC3ENC_OPT_NONE -1 +#define AC3ENC_OPT_AUTO -1 +#define AC3ENC_OPT_OFF 0 +#define AC3ENC_OPT_ON 1 +#define AC3ENC_OPT_NOT_INDICATED 0 +#define AC3ENC_OPT_MODE_ON 2 +#define AC3ENC_OPT_MODE_OFF 1 +#define AC3ENC_OPT_DSUREX_DPLIIZ 3 + +/* specific option values */ +#define AC3ENC_OPT_LARGE_ROOM 1 +#define AC3ENC_OPT_SMALL_ROOM 2 +#define AC3ENC_OPT_DOWNMIX_LTRT 1 +#define AC3ENC_OPT_DOWNMIX_LORO 2 +#define AC3ENC_OPT_DOWNMIX_DPLII 3 // reserved value in A/52, but used by encoders to indicate DPL2 +#define AC3ENC_OPT_ADCONV_STANDARD 0 +#define AC3ENC_OPT_ADCONV_HDCD 1 + + +/** + * Encoding Options used by AVOption. + */ +typedef struct AC3EncOptions { + /* AC-3 metadata options*/ + int dialogue_level; + int bitstream_mode; + float center_mix_level; + float surround_mix_level; + int dolby_surround_mode; + int audio_production_info; + int mixing_level; + int room_type; + int copyright; + int original; + int extended_bsi_1; + int preferred_stereo_downmix; + float ltrt_center_mix_level; + float ltrt_surround_mix_level; + float loro_center_mix_level; + float loro_surround_mix_level; + int extended_bsi_2; + int dolby_surround_ex_mode; + int dolby_headphone_mode; + int ad_converter_type; + int eac3_mixing_metadata; + int eac3_info_metadata; + + /* other encoding options */ + int allow_per_frame_metadata; + int stereo_rematrixing; + int channel_coupling; + int cpl_start; +} AC3EncOptions; + +/** + * Data for a single audio block. + */ +typedef struct AC3Block { + CoefType **mdct_coef; ///< MDCT coefficients + int32_t **fixed_coef; ///< fixed-point MDCT coefficients + uint8_t **exp; ///< original exponents + uint8_t **grouped_exp; ///< grouped exponents + int16_t **psd; ///< psd per frequency bin + int16_t **band_psd; ///< psd per critical band + int16_t **mask; ///< masking curve + uint16_t **qmant; ///< quantized mantissas + uint8_t **cpl_coord_exp; ///< coupling coord exponents (cplcoexp) + uint8_t **cpl_coord_mant; ///< coupling coord mantissas (cplcomant) + uint8_t coeff_shift[AC3_MAX_CHANNELS]; ///< fixed-point coefficient shift values + uint8_t new_rematrixing_strategy; ///< send new rematrixing flags in this block + int num_rematrixing_bands; ///< number of rematrixing bands + uint8_t rematrixing_flags[4]; ///< rematrixing flags + int new_cpl_strategy; ///< send new coupling strategy + int cpl_in_use; ///< coupling in use for this block (cplinu) + uint8_t channel_in_cpl[AC3_MAX_CHANNELS]; ///< channel in coupling (chincpl) + int num_cpl_channels; ///< number of channels in coupling + uint8_t new_cpl_coords[AC3_MAX_CHANNELS]; ///< send new coupling coordinates (cplcoe) + uint8_t cpl_master_exp[AC3_MAX_CHANNELS]; ///< coupling coord master exponents (mstrcplco) + int new_snr_offsets; ///< send new SNR offsets + int new_cpl_leak; ///< send new coupling leak info + int end_freq[AC3_MAX_CHANNELS]; ///< end frequency bin (endmant) +} AC3Block; + +/** + * AC-3 encoder private context. + */ +typedef struct AC3EncodeContext { + AVClass *av_class; ///< AVClass used for AVOption + AC3EncOptions options; ///< encoding options + AVCodecContext *avctx; ///< parent AVCodecContext + PutBitContext pb; ///< bitstream writer context + AudioDSPContext adsp; + AVFloatDSPContext *fdsp; + MECmpContext mecc; + AC3DSPContext ac3dsp; ///< AC-3 optimized functions + FFTContext mdct; ///< FFT context for MDCT calculation + const SampleType *mdct_window; ///< MDCT window function array + + AC3Block blocks[AC3_MAX_BLOCKS]; ///< per-block info + + int fixed_point; ///< indicates if fixed-point encoder is being used + int eac3; ///< indicates if this is E-AC-3 vs. AC-3 + int bitstream_id; ///< bitstream id (bsid) + int bitstream_mode; ///< bitstream mode (bsmod) + + int bit_rate; ///< target bit rate, in bits-per-second + int sample_rate; ///< sampling frequency, in Hz + + int num_blks_code; ///< number of blocks code (numblkscod) + int num_blocks; ///< number of blocks per frame + int frame_size_min; ///< minimum frame size in case rounding is necessary + int frame_size; ///< current frame size in bytes + int frame_size_code; ///< frame size code (frmsizecod) + uint16_t crc_inv[2]; + int64_t bits_written; ///< bit count (used to avg. bitrate) + int64_t samples_written; ///< sample count (used to avg. bitrate) + + int fbw_channels; ///< number of full-bandwidth channels (nfchans) + int channels; ///< total number of channels (nchans) + int lfe_on; ///< indicates if there is an LFE channel (lfeon) + int lfe_channel; ///< channel index of the LFE channel + int has_center; ///< indicates if there is a center channel + int has_surround; ///< indicates if there are one or more surround channels + int channel_mode; ///< channel mode (acmod) + const uint8_t *channel_map; ///< channel map used to reorder channels + + int center_mix_level; ///< center mix level code + int surround_mix_level; ///< surround mix level code + int ltrt_center_mix_level; ///< Lt/Rt center mix level code + int ltrt_surround_mix_level; ///< Lt/Rt surround mix level code + int loro_center_mix_level; ///< Lo/Ro center mix level code + int loro_surround_mix_level; ///< Lo/Ro surround mix level code + + int cutoff; ///< user-specified cutoff frequency, in Hz + int bandwidth_code; ///< bandwidth code (0 to 60) (chbwcod) + int start_freq[AC3_MAX_CHANNELS]; ///< start frequency bin (strtmant) + int cpl_end_freq; ///< coupling channel end frequency bin + + int cpl_on; ///< coupling turned on for this frame + int cpl_enabled; ///< coupling enabled for all frames + int num_cpl_subbands; ///< number of coupling subbands (ncplsubnd) + int num_cpl_bands; ///< number of coupling bands (ncplbnd) + uint8_t cpl_band_sizes[AC3_MAX_CPL_BANDS]; ///< number of coeffs in each coupling band + + int rematrixing_enabled; ///< stereo rematrixing enabled + + /* bitrate allocation control */ + int slow_gain_code; ///< slow gain code (sgaincod) + int slow_decay_code; ///< slow decay code (sdcycod) + int fast_decay_code; ///< fast decay code (fdcycod) + int db_per_bit_code; ///< dB/bit code (dbpbcod) + int floor_code; ///< floor code (floorcod) + AC3BitAllocParameters bit_alloc; ///< bit allocation parameters + int coarse_snr_offset; ///< coarse SNR offsets (csnroffst) + int fast_gain_code[AC3_MAX_CHANNELS]; ///< fast gain codes (signal-to-mask ratio) (fgaincod) + int fine_snr_offset[AC3_MAX_CHANNELS]; ///< fine SNR offsets (fsnroffst) + int frame_bits_fixed; ///< number of non-coefficient bits for fixed parameters + int frame_bits; ///< all frame bits except exponents and mantissas + int exponent_bits; ///< number of bits used for exponents + + SampleType *windowed_samples; + SampleType **planar_samples; + uint8_t *bap_buffer; + uint8_t *bap1_buffer; + CoefType *mdct_coef_buffer; + int32_t *fixed_coef_buffer; + uint8_t *exp_buffer; + uint8_t *grouped_exp_buffer; + int16_t *psd_buffer; + int16_t *band_psd_buffer; + int16_t *mask_buffer; + int16_t *qmant_buffer; + uint8_t *cpl_coord_exp_buffer; + uint8_t *cpl_coord_mant_buffer; + + uint8_t exp_strategy[AC3_MAX_CHANNELS][AC3_MAX_BLOCKS]; ///< exponent strategies + uint8_t frame_exp_strategy[AC3_MAX_CHANNELS]; ///< frame exp strategy index + int use_frame_exp_strategy; ///< indicates use of frame exp strategy + uint8_t exp_ref_block[AC3_MAX_CHANNELS][AC3_MAX_BLOCKS]; ///< reference blocks for EXP_REUSE + uint8_t *ref_bap [AC3_MAX_CHANNELS][AC3_MAX_BLOCKS]; ///< bit allocation pointers (bap) + int ref_bap_set; ///< indicates if ref_bap pointers have been set + + /* fixed vs. float function pointers */ + void (*mdct_end)(struct AC3EncodeContext *s); + int (*mdct_init)(struct AC3EncodeContext *s); + + /* fixed vs. float templated function pointers */ + int (*allocate_sample_buffers)(struct AC3EncodeContext *s); + + /* AC-3 vs. E-AC-3 function pointers */ + void (*output_frame_header)(struct AC3EncodeContext *s); +} AC3EncodeContext; + + +extern const uint64_t ff_ac3_channel_layouts[19]; + +int ff_ac3_encode_init(AVCodecContext *avctx); +int ff_ac3_float_encode_init(AVCodecContext *avctx); + +int ff_ac3_encode_close(AVCodecContext *avctx); + +int ff_ac3_validate_metadata(AC3EncodeContext *s); + +void ff_ac3_adjust_frame_size(AC3EncodeContext *s); + +void ff_ac3_compute_coupling_strategy(AC3EncodeContext *s); + +void ff_ac3_apply_rematrixing(AC3EncodeContext *s); + +void ff_ac3_process_exponents(AC3EncodeContext *s); + +int ff_ac3_compute_bit_allocation(AC3EncodeContext *s); + +void ff_ac3_group_exponents(AC3EncodeContext *s); + +void ff_ac3_quantize_mantissas(AC3EncodeContext *s); + +void ff_ac3_output_frame(AC3EncodeContext *s, unsigned char *frame); + + +/* prototypes for functions in ac3enc_fixed.c and ac3enc_float.c */ + +void ff_ac3_fixed_mdct_end(AC3EncodeContext *s); +void ff_ac3_float_mdct_end(AC3EncodeContext *s); + +int ff_ac3_fixed_mdct_init(AC3EncodeContext *s); +int ff_ac3_float_mdct_init(AC3EncodeContext *s); + + +/* prototypes for functions in ac3enc_template.c */ + +int ff_ac3_fixed_allocate_sample_buffers(AC3EncodeContext *s); +int ff_ac3_float_allocate_sample_buffers(AC3EncodeContext *s); + +int ff_ac3_fixed_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); +int ff_ac3_float_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + +#endif /* AVCODEC_AC3ENC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_fixed.c new file mode 100644 index 0000000000..b23fc64776 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_fixed.c @@ -0,0 +1,160 @@ +/* + * The simplest AC-3 encoder + * Copyright (c) 2000 Fabrice Bellard + * Copyright (c) 2006-2010 Justin Ruggles + * Copyright (c) 2006-2010 Prakash Punnoor + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * fixed-point AC-3 encoder. + */ + +#define FFT_FLOAT 0 +#undef CONFIG_AC3ENC_FLOAT +#include "internal.h" +#include "audiodsp.h" +#include "ac3enc.h" +#include "eac3enc.h" + +#define AC3ENC_TYPE AC3ENC_TYPE_AC3_FIXED +#include "ac3enc_opts_template.c" + +static const AVClass ac3enc_class = { + .class_name = "Fixed-Point AC-3 Encoder", + .item_name = av_default_item_name, + .option = ac3_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +/* + * Normalize the input samples to use the maximum available precision. + * This assumes signed 16-bit input samples. + */ +static int normalize_samples(AC3EncodeContext *s) +{ + int v = s->ac3dsp.ac3_max_msb_abs_int16(s->windowed_samples, AC3_WINDOW_SIZE); + v = 14 - av_log2(v); + if (v > 0) + s->ac3dsp.ac3_lshift_int16(s->windowed_samples, AC3_WINDOW_SIZE, v); + /* +6 to right-shift from 31-bit to 25-bit */ + return v + 6; +} + + +/* + * Scale MDCT coefficients to 25-bit signed fixed-point. + */ +static void scale_coefficients(AC3EncodeContext *s) +{ + int blk, ch; + + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + for (ch = 1; ch <= s->channels; ch++) { + s->ac3dsp.ac3_rshift_int32(block->mdct_coef[ch], AC3_MAX_COEFS, + block->coeff_shift[ch]); + } + } +} + +static void sum_square_butterfly(AC3EncodeContext *s, int64_t sum[4], + const int32_t *coef0, const int32_t *coef1, + int len) +{ + s->ac3dsp.sum_square_butterfly_int32(sum, coef0, coef1, len); +} + +/* + * Clip MDCT coefficients to allowable range. + */ +static void clip_coefficients(AudioDSPContext *adsp, int32_t *coef, + unsigned int len) +{ + adsp->vector_clip_int32(coef, coef, COEF_MIN, COEF_MAX, len); +} + + +/* + * Calculate a single coupling coordinate. + */ +static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl) +{ + if (energy_cpl <= COEF_MAX) { + return 1048576; + } else { + uint64_t coord = energy_ch / (energy_cpl >> 24); + uint32_t coord32 = FFMIN(coord, 1073741824); + coord32 = ff_sqrt(coord32) << 9; + return FFMIN(coord32, COEF_MAX); + } +} + + +#include "ac3enc_template.c" + + +/** + * Finalize MDCT and free allocated memory. + * + * @param s AC-3 encoder private context + */ +av_cold void ff_ac3_fixed_mdct_end(AC3EncodeContext *s) +{ + ff_mdct_end(&s->mdct); +} + + +/** + * Initialize MDCT tables. + * + * @param s AC-3 encoder private context + * @return 0 on success, negative error code on failure + */ +av_cold int ff_ac3_fixed_mdct_init(AC3EncodeContext *s) +{ + int ret = ff_mdct_init(&s->mdct, 9, 0, -1.0); + s->mdct_window = ff_ac3_window; + return ret; +} + + +static av_cold int ac3_fixed_encode_init(AVCodecContext *avctx) +{ + AC3EncodeContext *s = avctx->priv_data; + s->fixed_point = 1; + return ff_ac3_encode_init(avctx); +} + + +AVCodec ff_ac3_fixed_encoder = { + .name = "ac3_fixed", + .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_AC3, + .priv_data_size = sizeof(AC3EncodeContext), + .init = ac3_fixed_encode_init, + .encode2 = ff_ac3_fixed_encode_frame, + .close = ff_ac3_encode_close, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_NONE }, + .priv_class = &ac3enc_class, + .channel_layouts = ff_ac3_channel_layouts, + .defaults = ac3_defaults, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_float.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_float.c new file mode 100644 index 0000000000..d6e658b2b4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_float.c @@ -0,0 +1,155 @@ +/* + * The simplest AC-3 encoder + * Copyright (c) 2000 Fabrice Bellard + * Copyright (c) 2006-2010 Justin Ruggles + * Copyright (c) 2006-2010 Prakash Punnoor + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * floating-point AC-3 encoder. + */ + +#define CONFIG_AC3ENC_FLOAT 1 +#include "internal.h" +#include "audiodsp.h" +#include "ac3enc.h" +#include "eac3enc.h" +#include "kbdwin.h" + + +#define AC3ENC_TYPE AC3ENC_TYPE_AC3 +#include "ac3enc_opts_template.c" +static const AVClass ac3enc_class = { + .class_name = "AC-3 Encoder", + .item_name = av_default_item_name, + .option = ac3_options, + .version = LIBAVUTIL_VERSION_INT, +}; + + +/* + * Scale MDCT coefficients from float to 24-bit fixed-point. + */ +static void scale_coefficients(AC3EncodeContext *s) +{ + int chan_size = AC3_MAX_COEFS * s->num_blocks; + int cpl = s->cpl_on; + s->ac3dsp.float_to_fixed24(s->fixed_coef_buffer + (chan_size * !cpl), + s->mdct_coef_buffer + (chan_size * !cpl), + chan_size * (s->channels + cpl)); +} + + +/* + * Clip MDCT coefficients to allowable range. + */ +static void clip_coefficients(AudioDSPContext *adsp, float *coef, + unsigned int len) +{ + adsp->vector_clipf(coef, coef, len, COEF_MIN, COEF_MAX); +} + + +/* + * Calculate a single coupling coordinate. + */ +static CoefType calc_cpl_coord(CoefSumType energy_ch, CoefSumType energy_cpl) +{ + float coord = 0.125; + if (energy_cpl > 0) + coord *= sqrtf(energy_ch / energy_cpl); + return FFMIN(coord, COEF_MAX); +} + +static void sum_square_butterfly(AC3EncodeContext *s, float sum[4], + const float *coef0, const float *coef1, + int len) +{ + s->ac3dsp.sum_square_butterfly_float(sum, coef0, coef1, len); +} + + +#include "ac3enc_template.c" + + +/** + * Finalize MDCT and free allocated memory. + * + * @param s AC-3 encoder private context + */ +av_cold void ff_ac3_float_mdct_end(AC3EncodeContext *s) +{ + ff_mdct_end(&s->mdct); + av_freep(&s->mdct_window); +} + + +/** + * Initialize MDCT tables. + * + * @param s AC-3 encoder private context + * @return 0 on success, negative error code on failure + */ +av_cold int ff_ac3_float_mdct_init(AC3EncodeContext *s) +{ + float *window; + int i, n, n2; + + n = 1 << 9; + n2 = n >> 1; + + window = av_malloc_array(n, sizeof(*window)); + if (!window) { + av_log(s->avctx, AV_LOG_ERROR, "Cannot allocate memory.\n"); + return AVERROR(ENOMEM); + } + ff_kbd_window_init(window, 5.0, n2); + for (i = 0; i < n2; i++) + window[n-1-i] = window[i]; + s->mdct_window = window; + + return ff_mdct_init(&s->mdct, 9, 0, -2.0 / n); +} + + +av_cold int ff_ac3_float_encode_init(AVCodecContext *avctx) +{ + AC3EncodeContext *s = avctx->priv_data; + s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); + if (!s->fdsp) + return AVERROR(ENOMEM); + return ff_ac3_encode_init(avctx); +} + +AVCodec ff_ac3_encoder = { + .name = "ac3", + .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_AC3, + .priv_data_size = sizeof(AC3EncodeContext), + .init = ff_ac3_float_encode_init, + .encode2 = ff_ac3_float_encode_frame, + .close = ff_ac3_encode_close, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_NONE }, + .priv_class = &ac3enc_class, + .channel_layouts = ff_ac3_channel_layouts, + .defaults = ac3_defaults, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_opts_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_opts_template.c new file mode 100644 index 0000000000..57b65a7a9f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_opts_template.c @@ -0,0 +1,82 @@ +/* + * AC-3 encoder options + * Copyright (c) 2011 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "internal.h" +#include "ac3.h" + +static const AVOption ac3_options[] = { +/* Metadata Options */ +{"per_frame_metadata", "Allow Changing Metadata Per-Frame", OFFSET(allow_per_frame_metadata), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, AC3ENC_PARAM}, +#if AC3ENC_TYPE != AC3ENC_TYPE_EAC3 +/* AC-3 downmix levels */ +{"center_mixlev", "Center Mix Level", OFFSET(center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = LEVEL_MINUS_4POINT5DB }, 0.0, 1.0, AC3ENC_PARAM}, +{"surround_mixlev", "Surround Mix Level", OFFSET(surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = LEVEL_MINUS_6DB }, 0.0, 1.0, AC3ENC_PARAM}, +#endif +/* audio production information */ +{"mixing_level", "Mixing Level", OFFSET(mixing_level), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_NONE }, AC3ENC_OPT_NONE, 111, AC3ENC_PARAM}, +{"room_type", "Room Type", OFFSET(room_type), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_NONE }, AC3ENC_OPT_NONE, AC3ENC_OPT_SMALL_ROOM, AC3ENC_PARAM, "room_type"}, + {"notindicated", "Not Indicated (default)", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_NOT_INDICATED }, INT_MIN, INT_MAX, AC3ENC_PARAM, "room_type"}, + {"large", "Large Room", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_LARGE_ROOM }, INT_MIN, INT_MAX, AC3ENC_PARAM, "room_type"}, + {"small", "Small Room", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_SMALL_ROOM }, INT_MIN, INT_MAX, AC3ENC_PARAM, "room_type"}, +/* other metadata options */ +{"copyright", "Copyright Bit", OFFSET(copyright), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_NONE }, AC3ENC_OPT_NONE, 1, AC3ENC_PARAM}, +{"dialnorm", "Dialogue Level (dB)", OFFSET(dialogue_level), AV_OPT_TYPE_INT, {.i64 = -31 }, -31, -1, AC3ENC_PARAM}, +{"dsur_mode", "Dolby Surround Mode", OFFSET(dolby_surround_mode), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_NONE }, AC3ENC_OPT_NONE, AC3ENC_OPT_MODE_ON, AC3ENC_PARAM, "dsur_mode"}, + {"notindicated", "Not Indicated (default)", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_NOT_INDICATED }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dsur_mode"}, + {"on", "Dolby Surround Encoded", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_MODE_ON }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dsur_mode"}, + {"off", "Not Dolby Surround Encoded", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_MODE_OFF }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dsur_mode"}, +{"original", "Original Bit Stream", OFFSET(original), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_NONE }, AC3ENC_OPT_NONE, 1, AC3ENC_PARAM}, +/* extended bitstream information */ +{"dmix_mode", "Preferred Stereo Downmix Mode", OFFSET(preferred_stereo_downmix), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_NONE }, AC3ENC_OPT_NONE, AC3ENC_OPT_DOWNMIX_DPLII, AC3ENC_PARAM, "dmix_mode"}, + {"notindicated", "Not Indicated (default)", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_NOT_INDICATED }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dmix_mode"}, + {"ltrt", "Lt/Rt Downmix Preferred", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_DOWNMIX_LTRT }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dmix_mode"}, + {"loro", "Lo/Ro Downmix Preferred", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_DOWNMIX_LORO }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dmix_mode"}, + {"dplii", "Dolby Pro Logic II Downmix Preferred", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_DOWNMIX_DPLII }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dmix_mode"}, +{"ltrt_cmixlev", "Lt/Rt Center Mix Level", OFFSET(ltrt_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, AC3ENC_PARAM}, +{"ltrt_surmixlev", "Lt/Rt Surround Mix Level", OFFSET(ltrt_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, AC3ENC_PARAM}, +{"loro_cmixlev", "Lo/Ro Center Mix Level", OFFSET(loro_center_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, AC3ENC_PARAM}, +{"loro_surmixlev", "Lo/Ro Surround Mix Level", OFFSET(loro_surround_mix_level), AV_OPT_TYPE_FLOAT, {.dbl = -1.0 }, -1.0, 2.0, AC3ENC_PARAM}, +{"dsurex_mode", "Dolby Surround EX Mode", OFFSET(dolby_surround_ex_mode), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_NONE }, AC3ENC_OPT_NONE, AC3ENC_OPT_DSUREX_DPLIIZ, AC3ENC_PARAM, "dsurex_mode"}, + {"notindicated", "Not Indicated (default)", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_NOT_INDICATED }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dsurex_mode"}, + {"on", "Dolby Surround EX Encoded", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_MODE_ON }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dsurex_mode"}, + {"off", "Not Dolby Surround EX Encoded", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_MODE_OFF }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dsurex_mode"}, + {"dpliiz", "Dolby Pro Logic IIz-encoded", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_DSUREX_DPLIIZ }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dsurex_mode"}, +{"dheadphone_mode", "Dolby Headphone Mode", OFFSET(dolby_headphone_mode), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_NONE }, AC3ENC_OPT_NONE, AC3ENC_OPT_MODE_ON, AC3ENC_PARAM, "dheadphone_mode"}, + {"notindicated", "Not Indicated (default)", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_NOT_INDICATED }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dheadphone_mode"}, + {"on", "Dolby Headphone Encoded", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_MODE_ON }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dheadphone_mode"}, + {"off", "Not Dolby Headphone Encoded", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_MODE_OFF }, INT_MIN, INT_MAX, AC3ENC_PARAM, "dheadphone_mode"}, +{"ad_conv_type", "A/D Converter Type", OFFSET(ad_converter_type), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_NONE }, AC3ENC_OPT_NONE, AC3ENC_OPT_ADCONV_HDCD, AC3ENC_PARAM, "ad_conv_type"}, + {"standard", "Standard (default)", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_ADCONV_STANDARD }, INT_MIN, INT_MAX, AC3ENC_PARAM, "ad_conv_type"}, + {"hdcd", "HDCD", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_ADCONV_HDCD }, INT_MIN, INT_MAX, AC3ENC_PARAM, "ad_conv_type"}, +/* Other Encoding Options */ +{"stereo_rematrixing", "Stereo Rematrixing", OFFSET(stereo_rematrixing), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, AC3ENC_PARAM}, +{"channel_coupling", "Channel Coupling", OFFSET(channel_coupling), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_AUTO }, AC3ENC_OPT_AUTO, AC3ENC_OPT_ON, AC3ENC_PARAM, "channel_coupling"}, + {"auto", "Selected by the Encoder", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_AUTO }, INT_MIN, INT_MAX, AC3ENC_PARAM, "channel_coupling"}, +{"cpl_start_band", "Coupling Start Band", OFFSET(cpl_start), AV_OPT_TYPE_INT, {.i64 = AC3ENC_OPT_AUTO }, AC3ENC_OPT_AUTO, 15, AC3ENC_PARAM, "cpl_start_band"}, + {"auto", "Selected by the Encoder", 0, AV_OPT_TYPE_CONST, {.i64 = AC3ENC_OPT_AUTO }, INT_MIN, INT_MAX, AC3ENC_PARAM, "cpl_start_band"}, +{NULL} +}; + +static const AVCodecDefault ac3_defaults[] = { + { "b", "0" }, + { NULL } +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_template.c new file mode 100644 index 0000000000..be659872f7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3enc_template.c @@ -0,0 +1,436 @@ +/* + * AC-3 encoder float/fixed template + * Copyright (c) 2000 Fabrice Bellard + * Copyright (c) 2006-2011 Justin Ruggles + * Copyright (c) 2006-2010 Prakash Punnoor + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AC-3 encoder float/fixed template + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/internal.h" + +#include "audiodsp.h" +#include "internal.h" +#include "ac3enc.h" +#include "eac3enc.h" + + +int AC3_NAME(allocate_sample_buffers)(AC3EncodeContext *s) +{ + int ch; + + FF_ALLOC_OR_GOTO(s->avctx, s->windowed_samples, AC3_WINDOW_SIZE * + sizeof(*s->windowed_samples), alloc_fail); + FF_ALLOC_ARRAY_OR_GOTO(s->avctx, s->planar_samples, s->channels, sizeof(*s->planar_samples), + alloc_fail); + for (ch = 0; ch < s->channels; ch++) { + FF_ALLOCZ_OR_GOTO(s->avctx, s->planar_samples[ch], + (AC3_FRAME_SIZE+AC3_BLOCK_SIZE) * sizeof(**s->planar_samples), + alloc_fail); + } + + return 0; +alloc_fail: + return AVERROR(ENOMEM); +} + + +/* + * Copy input samples. + * Channels are reordered from FFmpeg's default order to AC-3 order. + */ +static void copy_input_samples(AC3EncodeContext *s, SampleType **samples) +{ + int ch; + + /* copy and remap input samples */ + for (ch = 0; ch < s->channels; ch++) { + /* copy last 256 samples of previous frame to the start of the current frame */ + memcpy(&s->planar_samples[ch][0], &s->planar_samples[ch][AC3_BLOCK_SIZE * s->num_blocks], + AC3_BLOCK_SIZE * sizeof(s->planar_samples[0][0])); + + /* copy new samples for current frame */ + memcpy(&s->planar_samples[ch][AC3_BLOCK_SIZE], + samples[s->channel_map[ch]], + AC3_BLOCK_SIZE * s->num_blocks * sizeof(s->planar_samples[0][0])); + } +} + + +/* + * Apply the MDCT to input samples to generate frequency coefficients. + * This applies the KBD window and normalizes the input to reduce precision + * loss due to fixed-point calculations. + */ +static void apply_mdct(AC3EncodeContext *s) +{ + int blk, ch; + + for (ch = 0; ch < s->channels; ch++) { + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + const SampleType *input_samples = &s->planar_samples[ch][blk * AC3_BLOCK_SIZE]; + +#if CONFIG_AC3ENC_FLOAT + s->fdsp->vector_fmul(s->windowed_samples, input_samples, + s->mdct_window, AC3_WINDOW_SIZE); +#else + s->ac3dsp.apply_window_int16(s->windowed_samples, input_samples, + s->mdct_window, AC3_WINDOW_SIZE); + + if (s->fixed_point) + block->coeff_shift[ch+1] = normalize_samples(s); +#endif + + s->mdct.mdct_calcw(&s->mdct, block->mdct_coef[ch+1], + s->windowed_samples); + } + } +} + + +/* + * Calculate coupling channel and coupling coordinates. + */ +static void apply_channel_coupling(AC3EncodeContext *s) +{ + LOCAL_ALIGNED_16(CoefType, cpl_coords, [AC3_MAX_BLOCKS], [AC3_MAX_CHANNELS][16]); +#if CONFIG_AC3ENC_FLOAT + LOCAL_ALIGNED_16(int32_t, fixed_cpl_coords, [AC3_MAX_BLOCKS], [AC3_MAX_CHANNELS][16]); +#else + int32_t (*fixed_cpl_coords)[AC3_MAX_CHANNELS][16] = cpl_coords; +#endif + int av_uninit(blk), ch, bnd, i, j; + CoefSumType energy[AC3_MAX_BLOCKS][AC3_MAX_CHANNELS][16] = {{{0}}}; + int cpl_start, num_cpl_coefs; + + memset(cpl_coords, 0, AC3_MAX_BLOCKS * sizeof(*cpl_coords)); +#if CONFIG_AC3ENC_FLOAT + memset(fixed_cpl_coords, 0, AC3_MAX_BLOCKS * sizeof(*cpl_coords)); +#endif + + /* align start to 16-byte boundary. align length to multiple of 32. + note: coupling start bin % 4 will always be 1 */ + cpl_start = s->start_freq[CPL_CH] - 1; + num_cpl_coefs = FFALIGN(s->num_cpl_subbands * 12 + 1, 32); + cpl_start = FFMIN(256, cpl_start + num_cpl_coefs) - num_cpl_coefs; + + /* calculate coupling channel from fbw channels */ + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + CoefType *cpl_coef = &block->mdct_coef[CPL_CH][cpl_start]; + if (!block->cpl_in_use) + continue; + memset(cpl_coef, 0, num_cpl_coefs * sizeof(*cpl_coef)); + for (ch = 1; ch <= s->fbw_channels; ch++) { + CoefType *ch_coef = &block->mdct_coef[ch][cpl_start]; + if (!block->channel_in_cpl[ch]) + continue; + for (i = 0; i < num_cpl_coefs; i++) + cpl_coef[i] += ch_coef[i]; + } + + /* coefficients must be clipped in order to be encoded */ + clip_coefficients(&s->adsp, cpl_coef, num_cpl_coefs); + } + + /* calculate energy in each band in coupling channel and each fbw channel */ + /* TODO: possibly use SIMD to speed up energy calculation */ + bnd = 0; + i = s->start_freq[CPL_CH]; + while (i < s->cpl_end_freq) { + int band_size = s->cpl_band_sizes[bnd]; + for (ch = CPL_CH; ch <= s->fbw_channels; ch++) { + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + if (!block->cpl_in_use || (ch > CPL_CH && !block->channel_in_cpl[ch])) + continue; + for (j = 0; j < band_size; j++) { + CoefType v = block->mdct_coef[ch][i+j]; + MAC_COEF(energy[blk][ch][bnd], v, v); + } + } + } + i += band_size; + bnd++; + } + + /* calculate coupling coordinates for all blocks for all channels */ + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + if (!block->cpl_in_use) + continue; + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (!block->channel_in_cpl[ch]) + continue; + for (bnd = 0; bnd < s->num_cpl_bands; bnd++) { + cpl_coords[blk][ch][bnd] = calc_cpl_coord(energy[blk][ch][bnd], + energy[blk][CPL_CH][bnd]); + } + } + } + + /* determine which blocks to send new coupling coordinates for */ + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + AC3Block *block0 = blk ? &s->blocks[blk-1] : NULL; + + memset(block->new_cpl_coords, 0, sizeof(block->new_cpl_coords)); + + if (block->cpl_in_use) { + /* send new coordinates if this is the first block, if previous + * block did not use coupling but this block does, the channels + * using coupling has changed from the previous block, or the + * coordinate difference from the last block for any channel is + * greater than a threshold value. */ + if (blk == 0 || !block0->cpl_in_use) { + for (ch = 1; ch <= s->fbw_channels; ch++) + block->new_cpl_coords[ch] = 1; + } else { + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (!block->channel_in_cpl[ch]) + continue; + if (!block0->channel_in_cpl[ch]) { + block->new_cpl_coords[ch] = 1; + } else { + CoefSumType coord_diff = 0; + for (bnd = 0; bnd < s->num_cpl_bands; bnd++) { + coord_diff += FFABS(cpl_coords[blk-1][ch][bnd] - + cpl_coords[blk ][ch][bnd]); + } + coord_diff /= s->num_cpl_bands; + if (coord_diff > NEW_CPL_COORD_THRESHOLD) + block->new_cpl_coords[ch] = 1; + } + } + } + } + } + + /* calculate final coupling coordinates, taking into account reusing of + coordinates in successive blocks */ + for (bnd = 0; bnd < s->num_cpl_bands; bnd++) { + blk = 0; + while (blk < s->num_blocks) { + int av_uninit(blk1); + AC3Block *block = &s->blocks[blk]; + + if (!block->cpl_in_use) { + blk++; + continue; + } + + for (ch = 1; ch <= s->fbw_channels; ch++) { + CoefSumType energy_ch, energy_cpl; + if (!block->channel_in_cpl[ch]) + continue; + energy_cpl = energy[blk][CPL_CH][bnd]; + energy_ch = energy[blk][ch][bnd]; + blk1 = blk+1; + while (blk1 < s->num_blocks && !s->blocks[blk1].new_cpl_coords[ch]) { + if (s->blocks[blk1].cpl_in_use) { + energy_cpl += energy[blk1][CPL_CH][bnd]; + energy_ch += energy[blk1][ch][bnd]; + } + blk1++; + } + cpl_coords[blk][ch][bnd] = calc_cpl_coord(energy_ch, energy_cpl); + } + blk = blk1; + } + } + + /* calculate exponents/mantissas for coupling coordinates */ + for (blk = 0; blk < s->num_blocks; blk++) { + AC3Block *block = &s->blocks[blk]; + if (!block->cpl_in_use) + continue; + +#if CONFIG_AC3ENC_FLOAT + s->ac3dsp.float_to_fixed24(fixed_cpl_coords[blk][1], + cpl_coords[blk][1], + s->fbw_channels * 16); +#endif + s->ac3dsp.extract_exponents(block->cpl_coord_exp[1], + fixed_cpl_coords[blk][1], + s->fbw_channels * 16); + + for (ch = 1; ch <= s->fbw_channels; ch++) { + int bnd, min_exp, max_exp, master_exp; + + if (!block->new_cpl_coords[ch]) + continue; + + /* determine master exponent */ + min_exp = max_exp = block->cpl_coord_exp[ch][0]; + for (bnd = 1; bnd < s->num_cpl_bands; bnd++) { + int exp = block->cpl_coord_exp[ch][bnd]; + min_exp = FFMIN(exp, min_exp); + max_exp = FFMAX(exp, max_exp); + } + master_exp = ((max_exp - 15) + 2) / 3; + master_exp = FFMAX(master_exp, 0); + while (min_exp < master_exp * 3) + master_exp--; + for (bnd = 0; bnd < s->num_cpl_bands; bnd++) { + block->cpl_coord_exp[ch][bnd] = av_clip(block->cpl_coord_exp[ch][bnd] - + master_exp * 3, 0, 15); + } + block->cpl_master_exp[ch] = master_exp; + + /* quantize mantissas */ + for (bnd = 0; bnd < s->num_cpl_bands; bnd++) { + int cpl_exp = block->cpl_coord_exp[ch][bnd]; + int cpl_mant = (fixed_cpl_coords[blk][ch][bnd] << (5 + cpl_exp + master_exp * 3)) >> 24; + if (cpl_exp == 15) + cpl_mant >>= 1; + else + cpl_mant -= 16; + + block->cpl_coord_mant[ch][bnd] = cpl_mant; + } + } + } + + if (CONFIG_EAC3_ENCODER && s->eac3) + ff_eac3_set_cpl_states(s); +} + + +/* + * Determine rematrixing flags for each block and band. + */ +static void compute_rematrixing_strategy(AC3EncodeContext *s) +{ + int nb_coefs; + int blk, bnd; + AC3Block *block, *block0 = NULL; + + if (s->channel_mode != AC3_CHMODE_STEREO) + return; + + for (blk = 0; blk < s->num_blocks; blk++) { + block = &s->blocks[blk]; + block->new_rematrixing_strategy = !blk; + + block->num_rematrixing_bands = 4; + if (block->cpl_in_use) { + block->num_rematrixing_bands -= (s->start_freq[CPL_CH] <= 61); + block->num_rematrixing_bands -= (s->start_freq[CPL_CH] == 37); + if (blk && block->num_rematrixing_bands != block0->num_rematrixing_bands) + block->new_rematrixing_strategy = 1; + } + nb_coefs = FFMIN(block->end_freq[1], block->end_freq[2]); + + if (!s->rematrixing_enabled) { + block0 = block; + continue; + } + + for (bnd = 0; bnd < block->num_rematrixing_bands; bnd++) { + /* calculate sum of squared coeffs for one band in one block */ + int start = ff_ac3_rematrix_band_tab[bnd]; + int end = FFMIN(nb_coefs, ff_ac3_rematrix_band_tab[bnd+1]); + CoefSumType sum[4]; + sum_square_butterfly(s, sum, block->mdct_coef[1] + start, + block->mdct_coef[2] + start, end - start); + + /* compare sums to determine if rematrixing will be used for this band */ + if (FFMIN(sum[2], sum[3]) < FFMIN(sum[0], sum[1])) + block->rematrixing_flags[bnd] = 1; + else + block->rematrixing_flags[bnd] = 0; + + /* determine if new rematrixing flags will be sent */ + if (blk && + block->rematrixing_flags[bnd] != block0->rematrixing_flags[bnd]) { + block->new_rematrixing_strategy = 1; + } + } + block0 = block; + } +} + + +int AC3_NAME(encode_frame)(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + AC3EncodeContext *s = avctx->priv_data; + int ret; + + if (s->options.allow_per_frame_metadata) { + ret = ff_ac3_validate_metadata(s); + if (ret) + return ret; + } + + if (s->bit_alloc.sr_code == 1 || s->eac3) + ff_ac3_adjust_frame_size(s); + + copy_input_samples(s, (SampleType **)frame->extended_data); + + apply_mdct(s); + + if (s->fixed_point) + scale_coefficients(s); + + clip_coefficients(&s->adsp, s->blocks[0].mdct_coef[1], + AC3_MAX_COEFS * s->num_blocks * s->channels); + + s->cpl_on = s->cpl_enabled; + ff_ac3_compute_coupling_strategy(s); + + if (s->cpl_on) + apply_channel_coupling(s); + + compute_rematrixing_strategy(s); + + if (!s->fixed_point) + scale_coefficients(s); + + ff_ac3_apply_rematrixing(s); + + ff_ac3_process_exponents(s); + + ret = ff_ac3_compute_bit_allocation(s); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "Bit allocation failed. Try increasing the bitrate.\n"); + return ret; + } + + ff_ac3_group_exponents(s); + + ff_ac3_quantize_mantissas(s); + + if ((ret = ff_alloc_packet2(avctx, avpkt, s->frame_size, 0)) < 0) + return ret; + ff_ac3_output_frame(s, avpkt->data); + + if (frame->pts != AV_NOPTS_VALUE) + avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->initial_padding); + + *got_packet_ptr = 1; + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3tab.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3tab.c new file mode 100644 index 0000000000..bd88f32d92 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3tab.c @@ -0,0 +1,334 @@ +/* + * AC-3 tables + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * tables taken directly from the AC-3 spec. + */ + +#include "libavutil/channel_layout.h" +#include "libavutil/mem.h" + +#include "avcodec.h" +#include "ac3tab.h" + +/** + * Possible frame sizes. + * from ATSC A/52 Table 5.18 Frame Size Code Table. + */ +const uint16_t ff_ac3_frame_size_tab[38][3] = { + { 64, 69, 96 }, + { 64, 70, 96 }, + { 80, 87, 120 }, + { 80, 88, 120 }, + { 96, 104, 144 }, + { 96, 105, 144 }, + { 112, 121, 168 }, + { 112, 122, 168 }, + { 128, 139, 192 }, + { 128, 140, 192 }, + { 160, 174, 240 }, + { 160, 175, 240 }, + { 192, 208, 288 }, + { 192, 209, 288 }, + { 224, 243, 336 }, + { 224, 244, 336 }, + { 256, 278, 384 }, + { 256, 279, 384 }, + { 320, 348, 480 }, + { 320, 349, 480 }, + { 384, 417, 576 }, + { 384, 418, 576 }, + { 448, 487, 672 }, + { 448, 488, 672 }, + { 512, 557, 768 }, + { 512, 558, 768 }, + { 640, 696, 960 }, + { 640, 697, 960 }, + { 768, 835, 1152 }, + { 768, 836, 1152 }, + { 896, 975, 1344 }, + { 896, 976, 1344 }, + { 1024, 1114, 1536 }, + { 1024, 1115, 1536 }, + { 1152, 1253, 1728 }, + { 1152, 1254, 1728 }, + { 1280, 1393, 1920 }, + { 1280, 1394, 1920 }, +}; + +/** + * Map audio coding mode (acmod) to number of full-bandwidth channels. + * from ATSC A/52 Table 5.8 Audio Coding Mode + */ +const uint8_t ff_ac3_channels_tab[8] = { + 2, 1, 2, 3, 3, 4, 4, 5 +}; + +/** + * Map audio coding mode (acmod) to channel layout mask. + */ +const uint16_t avpriv_ac3_channel_layout_tab[8] = { + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_2_1, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_2_2, + AV_CH_LAYOUT_5POINT0 +}; + +#define COMMON_CHANNEL_MAP \ + { { 0, 1, }, { 0, 1, 2, } },\ + { { 0, }, { 0, 1, } },\ + { { 0, 1, }, { 0, 1, 2, } },\ + { { 0, 2, 1, }, { 0, 2, 1, 3, } },\ + { { 0, 1, 2, }, { 0, 1, 3, 2, } },\ + { { 0, 2, 1, 3, }, { 0, 2, 1, 4, 3, } }, + +/** + * Table to remap channels from SMPTE order to AC-3 order. + * [channel_mode][lfe][ch] + */ +const uint8_t ff_ac3_enc_channel_map[8][2][6] = { + COMMON_CHANNEL_MAP + { { 0, 1, 2, 3, }, { 0, 1, 3, 4, 2, } }, + { { 0, 2, 1, 3, 4, }, { 0, 2, 1, 4, 5, 3 } }, +}; + +/** + * Table to remap channels from AC-3 order to SMPTE order. + * [channel_mode][lfe][ch] + */ +const uint8_t ff_ac3_dec_channel_map[8][2][6] = { + COMMON_CHANNEL_MAP + { { 0, 1, 2, 3, }, { 0, 1, 4, 2, 3, } }, + { { 0, 2, 1, 3, 4, }, { 0, 2, 1, 5, 3, 4 } }, +}; + +/* possible frequencies */ +const uint16_t ff_ac3_sample_rate_tab[3] = { 48000, 44100, 32000 }; + +/* possible bitrates */ +const uint16_t ff_ac3_bitrate_tab[19] = { + 32, 40, 48, 56, 64, 80, 96, 112, 128, + 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 +}; + +/** + * Table of bin locations for rematrixing bands + * reference: Section 7.5.2 Rematrixing : Frequency Band Definitions + */ +const uint8_t ff_ac3_rematrix_band_tab[5] = { 13, 25, 37, 61, 253 }; + +/** + * Table E2.16 Default Coupling Banding Structure + */ +const uint8_t ff_eac3_default_cpl_band_struct[18] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1 +}; + +/* AC-3 MDCT window */ + +/* MDCT window */ +DECLARE_ALIGNED(16, const int16_t, ff_ac3_window)[AC3_WINDOW_SIZE/2] = { + 4, 7, 12, 16, 21, 28, 34, 42, + 51, 61, 72, 84, 97, 111, 127, 145, + 164, 184, 207, 231, 257, 285, 315, 347, + 382, 419, 458, 500, 544, 591, 641, 694, + 750, 810, 872, 937, 1007, 1079, 1155, 1235, + 1318, 1406, 1497, 1593, 1692, 1796, 1903, 2016, + 2132, 2253, 2379, 2509, 2644, 2783, 2927, 3076, + 3230, 3389, 3552, 3721, 3894, 4072, 4255, 4444, + 4637, 4835, 5038, 5246, 5459, 5677, 5899, 6127, + 6359, 6596, 6837, 7083, 7334, 7589, 7848, 8112, + 8380, 8652, 8927, 9207, 9491, 9778,10069,10363, +10660,10960,11264,11570,11879,12190,12504,12820, +13138,13458,13780,14103,14427,14753,15079,15407, +15735,16063,16392,16720,17049,17377,17705,18032, +18358,18683,19007,19330,19651,19970,20287,20602, +20914,21225,21532,21837,22139,22438,22733,23025, +23314,23599,23880,24157,24430,24699,24964,25225, +25481,25732,25979,26221,26459,26691,26919,27142, +27359,27572,27780,27983,28180,28373,28560,28742, +28919,29091,29258,29420,29577,29729,29876,30018, +30155,30288,30415,30538,30657,30771,30880,30985, +31086,31182,31274,31363,31447,31528,31605,31678, +31747,31814,31877,31936,31993,32046,32097,32145, +32190,32232,32272,32310,32345,32378,32409,32438, +32465,32490,32513,32535,32556,32574,32592,32608, +32623,32636,32649,32661,32671,32681,32690,32698, +32705,32712,32718,32724,32729,32733,32737,32741, +32744,32747,32750,32752,32754,32756,32757,32759, +32760,32761,32762,32763,32764,32764,32765,32765, +32766,32766,32766,32766,32767,32767,32767,32767, +32767,32767,32767,32767,32767,32767,32767,32767, +32767,32767,32767,32767,32767,32767,32767,32767, +}; + +const uint8_t ff_ac3_log_add_tab[260]= { +0x40,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,0x37, +0x36,0x35,0x34,0x34,0x33,0x32,0x31,0x30,0x2f,0x2f, +0x2e,0x2d,0x2c,0x2c,0x2b,0x2a,0x29,0x29,0x28,0x27, +0x26,0x26,0x25,0x24,0x24,0x23,0x23,0x22,0x21,0x21, +0x20,0x20,0x1f,0x1e,0x1e,0x1d,0x1d,0x1c,0x1c,0x1b, +0x1b,0x1a,0x1a,0x19,0x19,0x18,0x18,0x17,0x17,0x16, +0x16,0x15,0x15,0x15,0x14,0x14,0x13,0x13,0x13,0x12, +0x12,0x12,0x11,0x11,0x11,0x10,0x10,0x10,0x0f,0x0f, +0x0f,0x0e,0x0e,0x0e,0x0d,0x0d,0x0d,0x0d,0x0c,0x0c, +0x0c,0x0c,0x0b,0x0b,0x0b,0x0b,0x0a,0x0a,0x0a,0x0a, +0x0a,0x09,0x09,0x09,0x09,0x09,0x08,0x08,0x08,0x08, +0x08,0x08,0x07,0x07,0x07,0x07,0x07,0x07,0x06,0x06, +0x06,0x06,0x06,0x06,0x06,0x06,0x05,0x05,0x05,0x05, +0x05,0x05,0x05,0x05,0x04,0x04,0x04,0x04,0x04,0x04, +0x04,0x04,0x04,0x04,0x04,0x03,0x03,0x03,0x03,0x03, +0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02, +0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, +0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x01,0x01, +0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +const uint16_t ff_ac3_hearing_threshold_tab[AC3_CRITICAL_BANDS][3]= { +{ 0x04d0,0x04f0,0x0580 }, +{ 0x04d0,0x04f0,0x0580 }, +{ 0x0440,0x0460,0x04b0 }, +{ 0x0400,0x0410,0x0450 }, +{ 0x03e0,0x03e0,0x0420 }, +{ 0x03c0,0x03d0,0x03f0 }, +{ 0x03b0,0x03c0,0x03e0 }, +{ 0x03b0,0x03b0,0x03d0 }, +{ 0x03a0,0x03b0,0x03c0 }, +{ 0x03a0,0x03a0,0x03b0 }, +{ 0x03a0,0x03a0,0x03b0 }, +{ 0x03a0,0x03a0,0x03b0 }, +{ 0x03a0,0x03a0,0x03a0 }, +{ 0x0390,0x03a0,0x03a0 }, +{ 0x0390,0x0390,0x03a0 }, +{ 0x0390,0x0390,0x03a0 }, +{ 0x0380,0x0390,0x03a0 }, +{ 0x0380,0x0380,0x03a0 }, +{ 0x0370,0x0380,0x03a0 }, +{ 0x0370,0x0380,0x03a0 }, +{ 0x0360,0x0370,0x0390 }, +{ 0x0360,0x0370,0x0390 }, +{ 0x0350,0x0360,0x0390 }, +{ 0x0350,0x0360,0x0390 }, +{ 0x0340,0x0350,0x0380 }, +{ 0x0340,0x0350,0x0380 }, +{ 0x0330,0x0340,0x0380 }, +{ 0x0320,0x0340,0x0370 }, +{ 0x0310,0x0320,0x0360 }, +{ 0x0300,0x0310,0x0350 }, +{ 0x02f0,0x0300,0x0340 }, +{ 0x02f0,0x02f0,0x0330 }, +{ 0x02f0,0x02f0,0x0320 }, +{ 0x02f0,0x02f0,0x0310 }, +{ 0x0300,0x02f0,0x0300 }, +{ 0x0310,0x0300,0x02f0 }, +{ 0x0340,0x0320,0x02f0 }, +{ 0x0390,0x0350,0x02f0 }, +{ 0x03e0,0x0390,0x0300 }, +{ 0x0420,0x03e0,0x0310 }, +{ 0x0460,0x0420,0x0330 }, +{ 0x0490,0x0450,0x0350 }, +{ 0x04a0,0x04a0,0x03c0 }, +{ 0x0460,0x0490,0x0410 }, +{ 0x0440,0x0460,0x0470 }, +{ 0x0440,0x0440,0x04a0 }, +{ 0x0520,0x0480,0x0460 }, +{ 0x0800,0x0630,0x0440 }, +{ 0x0840,0x0840,0x0450 }, +{ 0x0840,0x0840,0x04e0 }, +}; + +const uint8_t ff_ac3_bap_tab[64]= { + 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, + 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, + 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, + 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, + 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, + 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, + 15, 15, 15, 15, +}; + +const uint8_t ff_ac3_slow_decay_tab[4]={ + 0x0f, 0x11, 0x13, 0x15, +}; + +const uint8_t ff_ac3_fast_decay_tab[4]={ + 0x3f, 0x53, 0x67, 0x7b, +}; + +const uint16_t ff_ac3_slow_gain_tab[4]= { + 0x540, 0x4d8, 0x478, 0x410, +}; + +const uint16_t ff_ac3_db_per_bit_tab[4]= { + 0x000, 0x700, 0x900, 0xb00, +}; + +const int16_t ff_ac3_floor_tab[8]= { + 0x2f0, 0x2b0, 0x270, 0x230, 0x1f0, 0x170, 0x0f0, 0xf800, +}; + +const uint16_t ff_ac3_fast_gain_tab[8]= { + 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400, +}; + +/** + * Default channel map for a dependent substream defined by acmod + */ +const uint16_t ff_eac3_default_chmap[8] = { + AC3_CHMAP_L | AC3_CHMAP_R, // FIXME Ch1+Ch2 + AC3_CHMAP_C, + AC3_CHMAP_L | AC3_CHMAP_R, + AC3_CHMAP_L | AC3_CHMAP_C | AC3_CHMAP_R, + AC3_CHMAP_L | AC3_CHMAP_R | AC3_CHMAP_C_SUR, + AC3_CHMAP_L | AC3_CHMAP_C | AC3_CHMAP_R | AC3_CHMAP_C_SUR, + AC3_CHMAP_L | AC3_CHMAP_R | AC3_CHMAP_L_SUR | AC3_CHMAP_R_SUR, + AC3_CHMAP_L | AC3_CHMAP_C | AC3_CHMAP_R | AC3_CHMAP_L_SUR | AC3_CHMAP_R_SUR +}; +const uint64_t ff_eac3_custom_channel_map_locations[16][2] = { + { 1, AV_CH_FRONT_LEFT }, + { 1, AV_CH_FRONT_CENTER }, + { 1, AV_CH_FRONT_RIGHT }, + { 1, AV_CH_SIDE_LEFT }, + { 1, AV_CH_SIDE_RIGHT }, + { 0, AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER }, + { 0, AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT }, + { 0, AV_CH_BACK_CENTER }, + { 0, AV_CH_TOP_CENTER }, + { 0, AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT }, + { 0, AV_CH_WIDE_LEFT | AV_CH_WIDE_RIGHT }, + { 0, AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT}, + { 0, AV_CH_TOP_FRONT_CENTER }, + { 0, AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT }, + { 0, AV_CH_LOW_FREQUENCY_2 }, + { 1, AV_CH_LOW_FREQUENCY }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3tab.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3tab.h new file mode 100644 index 0000000000..aa71acbce1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ac3tab.h @@ -0,0 +1,71 @@ +/* + * AC-3 tables + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AC3TAB_H +#define AVCODEC_AC3TAB_H + +#include + +#include "libavutil/internal.h" +#include "ac3.h" +#include "internal.h" + +extern const uint16_t ff_ac3_frame_size_tab[38][3]; +extern const uint8_t ff_ac3_channels_tab[8]; +extern av_export_avcodec const uint16_t avpriv_ac3_channel_layout_tab[8]; +extern const uint8_t ff_ac3_enc_channel_map[8][2][6]; +extern const uint8_t ff_ac3_dec_channel_map[8][2][6]; +extern const uint16_t ff_ac3_sample_rate_tab[3]; +extern const uint16_t ff_ac3_bitrate_tab[19]; +extern const uint8_t ff_ac3_rematrix_band_tab[5]; +extern const uint8_t ff_eac3_default_cpl_band_struct[18]; +extern const int16_t ff_ac3_window[AC3_WINDOW_SIZE/2]; +extern const uint8_t ff_ac3_log_add_tab[260]; +extern const uint16_t ff_ac3_hearing_threshold_tab[AC3_CRITICAL_BANDS][3]; +extern const uint8_t ff_ac3_bap_tab[64]; +extern const uint8_t ff_ac3_slow_decay_tab[4]; +extern const uint8_t ff_ac3_fast_decay_tab[4]; +extern const uint16_t ff_ac3_slow_gain_tab[4]; +extern const uint16_t ff_ac3_db_per_bit_tab[4]; +extern const int16_t ff_ac3_floor_tab[8]; +extern const uint16_t ff_ac3_fast_gain_tab[8]; +extern const uint16_t ff_eac3_default_chmap[8]; +extern const uint8_t ff_ac3_band_start_tab[AC3_CRITICAL_BANDS+1]; +extern const uint8_t ff_ac3_bin_to_band_tab[253]; +extern const uint64_t ff_eac3_custom_channel_map_locations[16][2]; + + +/** Custom channel map locations bitmask + * Other channels described in documentation: + * Lc/Rc pair, Lrs/Rrs pair, Ts, Lsd/Rsd pair, + * Lw/Rw pair, Lvh/Rvh pair, Cvh, Reserved, LFE2 + */ +enum CustomChannelMapLocation{ + AC3_CHMAP_L= 1<<(15-0), + AC3_CHMAP_C= 1<<(15-1), + AC3_CHMAP_R= 1<<(15-2), + AC3_CHMAP_L_SUR= 1<<(15-3), + AC3_CHMAP_R_SUR = 1<<(15-4), + AC3_CHMAP_C_SUR= 1<<(15-7), + AC3_CHMAP_LFE = 1<<(15-15) +}; + +#endif /* AVCODEC_AC3TAB_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_header.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_header.c new file mode 100644 index 0000000000..0889820f8a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_header.c @@ -0,0 +1,71 @@ +/* + * Audio and Video frame extraction + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003 Michael Niedermayer + * Copyright (c) 2009 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "aac_ac3_parser.h" +#include "adts_header.h" +#include "adts_parser.h" +#include "get_bits.h" +#include "mpeg4audio.h" + +int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr) +{ + int size, rdb, ch, sr; + int aot, crc_abs; + + if (get_bits(gbc, 12) != 0xfff) + return AAC_AC3_PARSE_ERROR_SYNC; + + skip_bits1(gbc); /* id */ + skip_bits(gbc, 2); /* layer */ + crc_abs = get_bits1(gbc); /* protection_absent */ + aot = get_bits(gbc, 2); /* profile_objecttype */ + sr = get_bits(gbc, 4); /* sample_frequency_index */ + if (!avpriv_mpeg4audio_sample_rates[sr]) + return AAC_AC3_PARSE_ERROR_SAMPLE_RATE; + skip_bits1(gbc); /* private_bit */ + ch = get_bits(gbc, 3); /* channel_configuration */ + + skip_bits1(gbc); /* original/copy */ + skip_bits1(gbc); /* home */ + + /* adts_variable_header */ + skip_bits1(gbc); /* copyright_identification_bit */ + skip_bits1(gbc); /* copyright_identification_start */ + size = get_bits(gbc, 13); /* aac_frame_length */ + if (size < AV_AAC_ADTS_HEADER_SIZE) + return AAC_AC3_PARSE_ERROR_FRAME_SIZE; + + skip_bits(gbc, 11); /* adts_buffer_fullness */ + rdb = get_bits(gbc, 2); /* number_of_raw_data_blocks_in_frame */ + + hdr->object_type = aot + 1; + hdr->chan_config = ch; + hdr->crc_absent = crc_abs; + hdr->num_aac_frames = rdb + 1; + hdr->sampling_index = sr; + hdr->sample_rate = avpriv_mpeg4audio_sample_rates[sr]; + hdr->samples = (rdb + 1) * 1024; + hdr->bit_rate = size * 8 * hdr->sample_rate / hdr->samples; + + return size; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_header.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_header.h new file mode 100644 index 0000000000..f615f6a9f9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_header.h @@ -0,0 +1,50 @@ +/* + * AAC ADTS header decoding prototypes and structures + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_ADTS_HEADER_H +#define AVCODEC_ADTS_HEADER_H + +#include "get_bits.h" + +typedef struct AACADTSHeaderInfo { + uint32_t sample_rate; + uint32_t samples; + uint32_t bit_rate; + uint8_t crc_absent; + uint8_t object_type; + uint8_t sampling_index; + uint8_t chan_config; + uint8_t num_aac_frames; +} AACADTSHeaderInfo; + +/** + * Parse the ADTS frame header to the end of the variable header, which is + * the first 54 bits. + * @param[in] gbc BitContext containing the first 54 bits of the frame. + * @param[out] hdr Pointer to struct where header info is written. + * @return Returns 0 on success, -1 if there is a sync word mismatch, + * -2 if the version element is invalid, -3 if the sample rate + * element is invalid, or -4 if the bit rate element is invalid. + */ +int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr); + +#endif /* AVCODEC_ADTS_HEADER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_parser.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_parser.c new file mode 100644 index 0000000000..5c9f8ff6f2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_parser.c @@ -0,0 +1,44 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include + +#include "adts_header.h" +#include "adts_parser.h" + +int av_adts_header_parse(const uint8_t *buf, uint32_t *samples, uint8_t *frames) +{ +#if CONFIG_ADTS_HEADER + GetBitContext gb; + AACADTSHeaderInfo hdr; + int err = init_get_bits8(&gb, buf, AV_AAC_ADTS_HEADER_SIZE); + if (err < 0) + return err; + err = ff_adts_header_parse(&gb, &hdr); + if (err < 0) + return err; + *samples = hdr.samples; + *frames = hdr.num_aac_frames; + return 0; +#else + return AVERROR(ENOSYS); +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_parser.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_parser.h new file mode 100644 index 0000000000..f85becd131 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/adts_parser.h @@ -0,0 +1,37 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_ADTS_PARSER_H +#define AVCODEC_ADTS_PARSER_H + +#include +#include + +#define AV_AAC_ADTS_HEADER_SIZE 7 + +/** + * Extract the number of samples and frames from AAC data. + * @param[in] buf pointer to AAC data buffer + * @param[out] samples Pointer to where number of samples is written + * @param[out] frames Pointer to where number of frames is written + * @return Returns 0 on success, error code on failure. + */ +int av_adts_header_parse(const uint8_t *buf, uint32_t *samples, + uint8_t *frames); + +#endif /* AVCODEC_ADTS_PARSER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/allcodecs.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/allcodecs.c new file mode 100644 index 0000000000..d2f9a39ce5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/allcodecs.c @@ -0,0 +1,921 @@ +/* + * Provide registration of all codecs, parsers and bitstream filters for libavcodec. + * Copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Provide registration of all codecs, parsers and bitstream filters for libavcodec. + */ + +#include "config.h" +#include "libavutil/thread.h" +#include "avcodec.h" +#include "version.h" + +extern AVCodec ff_a64multi_encoder; +extern AVCodec ff_a64multi5_encoder; +extern AVCodec ff_aasc_decoder; +extern AVCodec ff_aic_decoder; +extern AVCodec ff_alias_pix_encoder; +extern AVCodec ff_alias_pix_decoder; +extern AVCodec ff_agm_decoder; +extern AVCodec ff_amv_encoder; +extern AVCodec ff_amv_decoder; +extern AVCodec ff_anm_decoder; +extern AVCodec ff_ansi_decoder; +extern AVCodec ff_apng_encoder; +extern AVCodec ff_apng_decoder; +extern AVCodec ff_arbc_decoder; +extern AVCodec ff_asv1_encoder; +extern AVCodec ff_asv1_decoder; +extern AVCodec ff_asv2_encoder; +extern AVCodec ff_asv2_decoder; +extern AVCodec ff_aura_decoder; +extern AVCodec ff_aura2_decoder; +extern AVCodec ff_avrp_encoder; +extern AVCodec ff_avrp_decoder; +extern AVCodec ff_avrn_decoder; +extern AVCodec ff_avs_decoder; +extern AVCodec ff_avui_encoder; +extern AVCodec ff_avui_decoder; +extern AVCodec ff_ayuv_encoder; +extern AVCodec ff_ayuv_decoder; +extern AVCodec ff_bethsoftvid_decoder; +extern AVCodec ff_bfi_decoder; +extern AVCodec ff_bink_decoder; +extern AVCodec ff_bitpacked_decoder; +extern AVCodec ff_bmp_encoder; +extern AVCodec ff_bmp_decoder; +extern AVCodec ff_bmv_video_decoder; +extern AVCodec ff_brender_pix_decoder; +extern AVCodec ff_c93_decoder; +extern AVCodec ff_cavs_decoder; +extern AVCodec ff_cdgraphics_decoder; +extern AVCodec ff_cdxl_decoder; +extern AVCodec ff_cfhd_decoder; +extern AVCodec ff_cinepak_encoder; +extern AVCodec ff_cinepak_decoder; +extern AVCodec ff_clearvideo_decoder; +extern AVCodec ff_cljr_encoder; +extern AVCodec ff_cljr_decoder; +extern AVCodec ff_cllc_decoder; +extern AVCodec ff_comfortnoise_encoder; +extern AVCodec ff_comfortnoise_decoder; +extern AVCodec ff_cpia_decoder; +extern AVCodec ff_cscd_decoder; +extern AVCodec ff_cyuv_decoder; +extern AVCodec ff_dds_decoder; +extern AVCodec ff_dfa_decoder; +extern AVCodec ff_dirac_decoder; +extern AVCodec ff_dnxhd_encoder; +extern AVCodec ff_dnxhd_decoder; +extern AVCodec ff_dpx_encoder; +extern AVCodec ff_dpx_decoder; +extern AVCodec ff_dsicinvideo_decoder; +extern AVCodec ff_dvaudio_decoder; +extern AVCodec ff_dvvideo_encoder; +extern AVCodec ff_dvvideo_decoder; +extern AVCodec ff_dxa_decoder; +extern AVCodec ff_dxtory_decoder; +extern AVCodec ff_dxv_decoder; +extern AVCodec ff_eacmv_decoder; +extern AVCodec ff_eamad_decoder; +extern AVCodec ff_eatgq_decoder; +extern AVCodec ff_eatgv_decoder; +extern AVCodec ff_eatqi_decoder; +extern AVCodec ff_eightbps_decoder; +extern AVCodec ff_eightsvx_exp_decoder; +extern AVCodec ff_eightsvx_fib_decoder; +extern AVCodec ff_escape124_decoder; +extern AVCodec ff_escape130_decoder; +extern AVCodec ff_exr_decoder; +extern AVCodec ff_ffv1_encoder; +extern AVCodec ff_ffv1_decoder; +extern AVCodec ff_ffvhuff_encoder; +extern AVCodec ff_ffvhuff_decoder; +extern AVCodec ff_fic_decoder; +extern AVCodec ff_fits_encoder; +extern AVCodec ff_fits_decoder; +extern AVCodec ff_flashsv_encoder; +extern AVCodec ff_flashsv_decoder; +extern AVCodec ff_flashsv2_encoder; +extern AVCodec ff_flashsv2_decoder; +extern AVCodec ff_flic_decoder; +extern AVCodec ff_flv_encoder; +extern AVCodec ff_flv_decoder; +extern AVCodec ff_fmvc_decoder; +extern AVCodec ff_fourxm_decoder; +extern AVCodec ff_fraps_decoder; +extern AVCodec ff_frwu_decoder; +extern AVCodec ff_g2m_decoder; +extern AVCodec ff_gdv_decoder; +extern AVCodec ff_gif_encoder; +extern AVCodec ff_gif_decoder; +extern AVCodec ff_h261_encoder; +extern AVCodec ff_h261_decoder; +extern AVCodec ff_h263_encoder; +extern AVCodec ff_h263_decoder; +extern AVCodec ff_h263i_decoder; +extern AVCodec ff_h263p_encoder; +extern AVCodec ff_h263p_decoder; +extern AVCodec ff_h263_v4l2m2m_decoder; +extern AVCodec ff_h264_decoder; +extern AVCodec ff_h264_crystalhd_decoder; +extern AVCodec ff_h264_v4l2m2m_decoder; +extern AVCodec ff_h264_mediacodec_decoder; +extern AVCodec ff_h264_mmal_decoder; +extern AVCodec ff_h264_qsv_decoder; +extern AVCodec ff_h264_rkmpp_decoder; +extern AVCodec ff_hap_encoder; +extern AVCodec ff_hap_decoder; +extern AVCodec ff_hevc_decoder; +extern AVCodec ff_hevc_qsv_decoder; +extern AVCodec ff_hevc_rkmpp_decoder; +extern AVCodec ff_hevc_v4l2m2m_decoder; +extern AVCodec ff_hnm4_video_decoder; +extern AVCodec ff_hq_hqa_decoder; +extern AVCodec ff_hqx_decoder; +extern AVCodec ff_huffyuv_encoder; +extern AVCodec ff_huffyuv_decoder; +extern AVCodec ff_hymt_decoder; +extern AVCodec ff_idcin_decoder; +extern AVCodec ff_iff_ilbm_decoder; +extern AVCodec ff_imm4_decoder; +extern AVCodec ff_indeo2_decoder; +extern AVCodec ff_indeo3_decoder; +extern AVCodec ff_indeo4_decoder; +extern AVCodec ff_indeo5_decoder; +extern AVCodec ff_interplay_video_decoder; +extern AVCodec ff_jpeg2000_encoder; +extern AVCodec ff_jpeg2000_decoder; +extern AVCodec ff_jpegls_encoder; +extern AVCodec ff_jpegls_decoder; +extern AVCodec ff_jv_decoder; +extern AVCodec ff_kgv1_decoder; +extern AVCodec ff_kmvc_decoder; +extern AVCodec ff_lagarith_decoder; +extern AVCodec ff_ljpeg_encoder; +extern AVCodec ff_loco_decoder; +extern AVCodec ff_lscr_decoder; +extern AVCodec ff_m101_decoder; +extern AVCodec ff_magicyuv_encoder; +extern AVCodec ff_magicyuv_decoder; +extern AVCodec ff_mdec_decoder; +extern AVCodec ff_mimic_decoder; +extern AVCodec ff_mjpeg_encoder; +extern AVCodec ff_mjpeg_decoder; +extern AVCodec ff_mjpegb_decoder; +extern AVCodec ff_mmvideo_decoder; +extern AVCodec ff_motionpixels_decoder; +extern AVCodec ff_mpeg1video_encoder; +extern AVCodec ff_mpeg1video_decoder; +extern AVCodec ff_mpeg2video_encoder; +extern AVCodec ff_mpeg2video_decoder; +extern AVCodec ff_mpeg4_encoder; +extern AVCodec ff_mpeg4_decoder; +extern AVCodec ff_mpeg4_crystalhd_decoder; +extern AVCodec ff_mpeg4_v4l2m2m_decoder; +extern AVCodec ff_mpeg4_mmal_decoder; +extern AVCodec ff_mpegvideo_decoder; +extern AVCodec ff_mpeg1_v4l2m2m_decoder; +extern AVCodec ff_mpeg2_mmal_decoder; +extern AVCodec ff_mpeg2_crystalhd_decoder; +extern AVCodec ff_mpeg2_v4l2m2m_decoder; +extern AVCodec ff_mpeg2_qsv_decoder; +extern AVCodec ff_mpeg2_mediacodec_decoder; +extern AVCodec ff_msa1_decoder; +extern AVCodec ff_mscc_decoder; +extern AVCodec ff_msmpeg4v1_decoder; +extern AVCodec ff_msmpeg4v2_encoder; +extern AVCodec ff_msmpeg4v2_decoder; +extern AVCodec ff_msmpeg4v3_encoder; +extern AVCodec ff_msmpeg4v3_decoder; +extern AVCodec ff_msmpeg4_crystalhd_decoder; +extern AVCodec ff_msrle_decoder; +extern AVCodec ff_mss1_decoder; +extern AVCodec ff_mss2_decoder; +extern AVCodec ff_msvideo1_encoder; +extern AVCodec ff_msvideo1_decoder; +extern AVCodec ff_mszh_decoder; +extern AVCodec ff_mts2_decoder; +extern AVCodec ff_mvc1_decoder; +extern AVCodec ff_mvc2_decoder; +extern AVCodec ff_mwsc_decoder; +extern AVCodec ff_mxpeg_decoder; +extern AVCodec ff_nuv_decoder; +extern AVCodec ff_paf_video_decoder; +extern AVCodec ff_pam_encoder; +extern AVCodec ff_pam_decoder; +extern AVCodec ff_pbm_encoder; +extern AVCodec ff_pbm_decoder; +extern AVCodec ff_pcx_encoder; +extern AVCodec ff_pcx_decoder; +extern AVCodec ff_pgm_encoder; +extern AVCodec ff_pgm_decoder; +extern AVCodec ff_pgmyuv_encoder; +extern AVCodec ff_pgmyuv_decoder; +extern AVCodec ff_pictor_decoder; +extern AVCodec ff_pixlet_decoder; +extern AVCodec ff_png_encoder; +extern AVCodec ff_png_decoder; +extern AVCodec ff_ppm_encoder; +extern AVCodec ff_ppm_decoder; +extern AVCodec ff_prores_encoder; +extern AVCodec ff_prores_decoder; +extern AVCodec ff_prores_aw_encoder; +extern AVCodec ff_prores_ks_encoder; +extern AVCodec ff_prosumer_decoder; +extern AVCodec ff_psd_decoder; +extern AVCodec ff_ptx_decoder; +extern AVCodec ff_qdraw_decoder; +extern AVCodec ff_qpeg_decoder; +extern AVCodec ff_qtrle_encoder; +extern AVCodec ff_qtrle_decoder; +extern AVCodec ff_r10k_encoder; +extern AVCodec ff_r10k_decoder; +extern AVCodec ff_r210_encoder; +extern AVCodec ff_r210_decoder; +extern AVCodec ff_rasc_decoder; +extern AVCodec ff_rawvideo_encoder; +extern AVCodec ff_rawvideo_decoder; +extern AVCodec ff_rl2_decoder; +extern AVCodec ff_roq_encoder; +extern AVCodec ff_roq_decoder; +extern AVCodec ff_rpza_decoder; +extern AVCodec ff_rscc_decoder; +extern AVCodec ff_rv10_encoder; +extern AVCodec ff_rv10_decoder; +extern AVCodec ff_rv20_encoder; +extern AVCodec ff_rv20_decoder; +extern AVCodec ff_rv30_decoder; +extern AVCodec ff_rv40_decoder; +extern AVCodec ff_s302m_encoder; +extern AVCodec ff_s302m_decoder; +extern AVCodec ff_sanm_decoder; +extern AVCodec ff_scpr_decoder; +extern AVCodec ff_screenpresso_decoder; +extern AVCodec ff_sdx2_dpcm_decoder; +extern AVCodec ff_sgi_encoder; +extern AVCodec ff_sgi_decoder; +extern AVCodec ff_sgirle_decoder; +extern AVCodec ff_sheervideo_decoder; +extern AVCodec ff_smacker_decoder; +extern AVCodec ff_smc_decoder; +extern AVCodec ff_smvjpeg_decoder; +extern AVCodec ff_snow_encoder; +extern AVCodec ff_snow_decoder; +extern AVCodec ff_sp5x_decoder; +extern AVCodec ff_speedhq_decoder; +extern AVCodec ff_srgc_decoder; +extern AVCodec ff_sunrast_encoder; +extern AVCodec ff_sunrast_decoder; +extern AVCodec ff_svq1_encoder; +extern AVCodec ff_svq1_decoder; +extern AVCodec ff_svq3_decoder; +extern AVCodec ff_targa_encoder; +extern AVCodec ff_targa_decoder; +extern AVCodec ff_targa_y216_decoder; +extern AVCodec ff_tdsc_decoder; +extern AVCodec ff_theora_decoder; +extern AVCodec ff_thp_decoder; +extern AVCodec ff_tiertexseqvideo_decoder; +extern AVCodec ff_tiff_encoder; +extern AVCodec ff_tiff_decoder; +extern AVCodec ff_tmv_decoder; +extern AVCodec ff_truemotion1_decoder; +extern AVCodec ff_truemotion2_decoder; +extern AVCodec ff_truemotion2rt_decoder; +extern AVCodec ff_tscc_decoder; +extern AVCodec ff_tscc2_decoder; +extern AVCodec ff_txd_decoder; +extern AVCodec ff_ulti_decoder; +extern AVCodec ff_utvideo_encoder; +extern AVCodec ff_utvideo_decoder; +extern AVCodec ff_v210_encoder; +extern AVCodec ff_v210_decoder; +extern AVCodec ff_v210x_decoder; +extern AVCodec ff_v308_encoder; +extern AVCodec ff_v308_decoder; +extern AVCodec ff_v408_encoder; +extern AVCodec ff_v408_decoder; +extern AVCodec ff_v410_encoder; +extern AVCodec ff_v410_decoder; +extern AVCodec ff_vb_decoder; +extern AVCodec ff_vble_decoder; +extern AVCodec ff_vc1_decoder; +extern AVCodec ff_vc1_crystalhd_decoder; +extern AVCodec ff_vc1image_decoder; +extern AVCodec ff_vc1_mmal_decoder; +extern AVCodec ff_vc1_qsv_decoder; +extern AVCodec ff_vc1_v4l2m2m_decoder; +extern AVCodec ff_vc2_encoder; +extern AVCodec ff_vcr1_decoder; +extern AVCodec ff_vmdvideo_decoder; +extern AVCodec ff_vmnc_decoder; +extern AVCodec ff_vp3_decoder; +extern AVCodec ff_vp4_decoder; +extern AVCodec ff_vp5_decoder; +extern AVCodec ff_vp6_decoder; +extern AVCodec ff_vp6a_decoder; +extern AVCodec ff_vp6f_decoder; +extern AVCodec ff_vp7_decoder; +extern AVCodec ff_vp8_decoder; +extern AVCodec ff_vp8_rkmpp_decoder; +extern AVCodec ff_vp8_v4l2m2m_decoder; +extern AVCodec ff_vp9_decoder; +extern AVCodec ff_vp9_rkmpp_decoder; +extern AVCodec ff_vp9_v4l2m2m_decoder; +extern AVCodec ff_vqa_decoder; +extern AVCodec ff_webp_decoder; +extern AVCodec ff_wcmv_decoder; +extern AVCodec ff_wrapped_avframe_encoder; +extern AVCodec ff_wrapped_avframe_decoder; +extern AVCodec ff_wmv1_encoder; +extern AVCodec ff_wmv1_decoder; +extern AVCodec ff_wmv2_encoder; +extern AVCodec ff_wmv2_decoder; +extern AVCodec ff_wmv3_decoder; +extern AVCodec ff_wmv3_crystalhd_decoder; +extern AVCodec ff_wmv3image_decoder; +extern AVCodec ff_wnv1_decoder; +extern AVCodec ff_xan_wc3_decoder; +extern AVCodec ff_xan_wc4_decoder; +extern AVCodec ff_xbm_encoder; +extern AVCodec ff_xbm_decoder; +extern AVCodec ff_xface_encoder; +extern AVCodec ff_xface_decoder; +extern AVCodec ff_xl_decoder; +extern AVCodec ff_xpm_decoder; +extern AVCodec ff_xwd_encoder; +extern AVCodec ff_xwd_decoder; +extern AVCodec ff_y41p_encoder; +extern AVCodec ff_y41p_decoder; +extern AVCodec ff_ylc_decoder; +extern AVCodec ff_yop_decoder; +extern AVCodec ff_yuv4_encoder; +extern AVCodec ff_yuv4_decoder; +extern AVCodec ff_zero12v_decoder; +extern AVCodec ff_zerocodec_decoder; +extern AVCodec ff_zlib_encoder; +extern AVCodec ff_zlib_decoder; +extern AVCodec ff_zmbv_encoder; +extern AVCodec ff_zmbv_decoder; + +/* audio codecs */ +extern AVCodec ff_aac_encoder; +extern AVCodec ff_aac_decoder; +extern AVCodec ff_aac_fixed_decoder; +extern AVCodec ff_aac_latm_decoder; +extern AVCodec ff_ac3_encoder; +extern AVCodec ff_ac3_decoder; +extern AVCodec ff_ac3_fixed_encoder; +extern AVCodec ff_ac3_fixed_decoder; +extern AVCodec ff_alac_encoder; +extern AVCodec ff_alac_decoder; +extern AVCodec ff_als_decoder; +extern AVCodec ff_amrnb_decoder; +extern AVCodec ff_amrwb_decoder; +extern AVCodec ff_ape_decoder; +extern AVCodec ff_aptx_encoder; +extern AVCodec ff_aptx_decoder; +extern AVCodec ff_aptx_hd_encoder; +extern AVCodec ff_aptx_hd_decoder; +extern AVCodec ff_atrac1_decoder; +extern AVCodec ff_atrac3_decoder; +extern AVCodec ff_atrac3al_decoder; +extern AVCodec ff_atrac3p_decoder; +extern AVCodec ff_atrac3pal_decoder; +extern AVCodec ff_atrac9_decoder; +extern AVCodec ff_binkaudio_dct_decoder; +extern AVCodec ff_binkaudio_rdft_decoder; +extern AVCodec ff_bmv_audio_decoder; +extern AVCodec ff_cook_decoder; +extern AVCodec ff_dca_encoder; +extern AVCodec ff_dca_decoder; +extern AVCodec ff_dolby_e_decoder; +extern AVCodec ff_dsd_lsbf_decoder; +extern AVCodec ff_dsd_msbf_decoder; +extern AVCodec ff_dsd_lsbf_planar_decoder; +extern AVCodec ff_dsd_msbf_planar_decoder; +extern AVCodec ff_dsicinaudio_decoder; +extern AVCodec ff_dss_sp_decoder; +extern AVCodec ff_dst_decoder; +extern AVCodec ff_eac3_encoder; +extern AVCodec ff_eac3_decoder; +extern AVCodec ff_evrc_decoder; +extern AVCodec ff_ffwavesynth_decoder; +extern AVCodec ff_flac_encoder; +extern AVCodec ff_flac_decoder; +extern AVCodec ff_g723_1_encoder; +extern AVCodec ff_g723_1_decoder; +extern AVCodec ff_g729_decoder; +extern AVCodec ff_gsm_decoder; +extern AVCodec ff_gsm_ms_decoder; +extern AVCodec ff_hcom_decoder; +extern AVCodec ff_iac_decoder; +extern AVCodec ff_ilbc_decoder; +extern AVCodec ff_imc_decoder; +extern AVCodec ff_interplay_acm_decoder; +extern AVCodec ff_mace3_decoder; +extern AVCodec ff_mace6_decoder; +extern AVCodec ff_metasound_decoder; +extern AVCodec ff_mlp_encoder; +extern AVCodec ff_mlp_decoder; +extern AVCodec ff_mp1_decoder; +extern AVCodec ff_mp1float_decoder; +extern AVCodec ff_mp2_encoder; +extern AVCodec ff_mp2_decoder; +extern AVCodec ff_mp2float_decoder; +extern AVCodec ff_mp2fixed_encoder; +extern AVCodec ff_mp3float_decoder; +extern AVCodec ff_mp3_decoder; +extern AVCodec ff_mp3adufloat_decoder; +extern AVCodec ff_mp3adu_decoder; +extern AVCodec ff_mp3on4float_decoder; +extern AVCodec ff_mp3on4_decoder; +extern AVCodec ff_mpc7_decoder; +extern AVCodec ff_mpc8_decoder; +extern AVCodec ff_nellymoser_encoder; +extern AVCodec ff_nellymoser_decoder; +extern AVCodec ff_on2avc_decoder; +extern AVCodec ff_opus_encoder; +extern AVCodec ff_opus_decoder; +extern AVCodec ff_paf_audio_decoder; +extern AVCodec ff_qcelp_decoder; +extern AVCodec ff_qdm2_decoder; +extern AVCodec ff_qdmc_decoder; +extern AVCodec ff_ra_144_encoder; +extern AVCodec ff_ra_144_decoder; +extern AVCodec ff_ra_288_decoder; +extern AVCodec ff_ralf_decoder; +extern AVCodec ff_sbc_encoder; +extern AVCodec ff_sbc_decoder; +extern AVCodec ff_shorten_decoder; +extern AVCodec ff_sipr_decoder; +extern AVCodec ff_smackaud_decoder; +extern AVCodec ff_sonic_encoder; +extern AVCodec ff_sonic_decoder; +extern AVCodec ff_sonic_ls_encoder; +extern AVCodec ff_tak_decoder; +extern AVCodec ff_truehd_encoder; +extern AVCodec ff_truehd_decoder; +extern AVCodec ff_truespeech_decoder; +extern AVCodec ff_tta_encoder; +extern AVCodec ff_tta_decoder; +extern AVCodec ff_twinvq_decoder; +extern AVCodec ff_vmdaudio_decoder; +extern AVCodec ff_vorbis_encoder; +extern AVCodec ff_vorbis_decoder; +extern AVCodec ff_wavpack_encoder; +extern AVCodec ff_wavpack_decoder; +extern AVCodec ff_wmalossless_decoder; +extern AVCodec ff_wmapro_decoder; +extern AVCodec ff_wmav1_encoder; +extern AVCodec ff_wmav1_decoder; +extern AVCodec ff_wmav2_encoder; +extern AVCodec ff_wmav2_decoder; +extern AVCodec ff_wmavoice_decoder; +extern AVCodec ff_ws_snd1_decoder; +extern AVCodec ff_xma1_decoder; +extern AVCodec ff_xma2_decoder; + +/* PCM codecs */ +extern AVCodec ff_pcm_alaw_encoder; +extern AVCodec ff_pcm_alaw_decoder; +extern AVCodec ff_pcm_bluray_decoder; +extern AVCodec ff_pcm_dvd_encoder; +extern AVCodec ff_pcm_dvd_decoder; +extern AVCodec ff_pcm_f16le_decoder; +extern AVCodec ff_pcm_f24le_decoder; +extern AVCodec ff_pcm_f32be_encoder; +extern AVCodec ff_pcm_f32be_decoder; +extern AVCodec ff_pcm_f32le_encoder; +extern AVCodec ff_pcm_f32le_decoder; +extern AVCodec ff_pcm_f64be_encoder; +extern AVCodec ff_pcm_f64be_decoder; +extern AVCodec ff_pcm_f64le_encoder; +extern AVCodec ff_pcm_f64le_decoder; +extern AVCodec ff_pcm_lxf_decoder; +extern AVCodec ff_pcm_mulaw_encoder; +extern AVCodec ff_pcm_mulaw_decoder; +extern AVCodec ff_pcm_s8_encoder; +extern AVCodec ff_pcm_s8_decoder; +extern AVCodec ff_pcm_s8_planar_encoder; +extern AVCodec ff_pcm_s8_planar_decoder; +extern AVCodec ff_pcm_s16be_encoder; +extern AVCodec ff_pcm_s16be_decoder; +extern AVCodec ff_pcm_s16be_planar_encoder; +extern AVCodec ff_pcm_s16be_planar_decoder; +extern AVCodec ff_pcm_s16le_encoder; +extern AVCodec ff_pcm_s16le_decoder; +extern AVCodec ff_pcm_s16le_planar_encoder; +extern AVCodec ff_pcm_s16le_planar_decoder; +extern AVCodec ff_pcm_s24be_encoder; +extern AVCodec ff_pcm_s24be_decoder; +extern AVCodec ff_pcm_s24daud_encoder; +extern AVCodec ff_pcm_s24daud_decoder; +extern AVCodec ff_pcm_s24le_encoder; +extern AVCodec ff_pcm_s24le_decoder; +extern AVCodec ff_pcm_s24le_planar_encoder; +extern AVCodec ff_pcm_s24le_planar_decoder; +extern AVCodec ff_pcm_s32be_encoder; +extern AVCodec ff_pcm_s32be_decoder; +extern AVCodec ff_pcm_s32le_encoder; +extern AVCodec ff_pcm_s32le_decoder; +extern AVCodec ff_pcm_s32le_planar_encoder; +extern AVCodec ff_pcm_s32le_planar_decoder; +extern AVCodec ff_pcm_s64be_encoder; +extern AVCodec ff_pcm_s64be_decoder; +extern AVCodec ff_pcm_s64le_encoder; +extern AVCodec ff_pcm_s64le_decoder; +extern AVCodec ff_pcm_u8_encoder; +extern AVCodec ff_pcm_u8_decoder; +extern AVCodec ff_pcm_u16be_encoder; +extern AVCodec ff_pcm_u16be_decoder; +extern AVCodec ff_pcm_u16le_encoder; +extern AVCodec ff_pcm_u16le_decoder; +extern AVCodec ff_pcm_u24be_encoder; +extern AVCodec ff_pcm_u24be_decoder; +extern AVCodec ff_pcm_u24le_encoder; +extern AVCodec ff_pcm_u24le_decoder; +extern AVCodec ff_pcm_u32be_encoder; +extern AVCodec ff_pcm_u32be_decoder; +extern AVCodec ff_pcm_u32le_encoder; +extern AVCodec ff_pcm_u32le_decoder; +extern AVCodec ff_pcm_vidc_encoder; +extern AVCodec ff_pcm_vidc_decoder; +extern AVCodec ff_pcm_zork_decoder; + +/* DPCM codecs */ +extern AVCodec ff_gremlin_dpcm_decoder; +extern AVCodec ff_interplay_dpcm_decoder; +extern AVCodec ff_roq_dpcm_encoder; +extern AVCodec ff_roq_dpcm_decoder; +extern AVCodec ff_sol_dpcm_decoder; +extern AVCodec ff_xan_dpcm_decoder; + +/* ADPCM codecs */ +extern AVCodec ff_adpcm_4xm_decoder; +extern AVCodec ff_adpcm_adx_encoder; +extern AVCodec ff_adpcm_adx_decoder; +extern AVCodec ff_adpcm_afc_decoder; +extern AVCodec ff_adpcm_agm_decoder; +extern AVCodec ff_adpcm_aica_decoder; +extern AVCodec ff_adpcm_ct_decoder; +extern AVCodec ff_adpcm_dtk_decoder; +extern AVCodec ff_adpcm_ea_decoder; +extern AVCodec ff_adpcm_ea_maxis_xa_decoder; +extern AVCodec ff_adpcm_ea_r1_decoder; +extern AVCodec ff_adpcm_ea_r2_decoder; +extern AVCodec ff_adpcm_ea_r3_decoder; +extern AVCodec ff_adpcm_ea_xas_decoder; +extern AVCodec ff_adpcm_g722_encoder; +extern AVCodec ff_adpcm_g722_decoder; +extern AVCodec ff_adpcm_g726_encoder; +extern AVCodec ff_adpcm_g726_decoder; +extern AVCodec ff_adpcm_g726le_encoder; +extern AVCodec ff_adpcm_g726le_decoder; +extern AVCodec ff_adpcm_ima_amv_decoder; +extern AVCodec ff_adpcm_ima_apc_decoder; +extern AVCodec ff_adpcm_ima_dat4_decoder; +extern AVCodec ff_adpcm_ima_dk3_decoder; +extern AVCodec ff_adpcm_ima_dk4_decoder; +extern AVCodec ff_adpcm_ima_ea_eacs_decoder; +extern AVCodec ff_adpcm_ima_ea_sead_decoder; +extern AVCodec ff_adpcm_ima_iss_decoder; +extern AVCodec ff_adpcm_ima_oki_decoder; +extern AVCodec ff_adpcm_ima_qt_encoder; +extern AVCodec ff_adpcm_ima_qt_decoder; +extern AVCodec ff_adpcm_ima_rad_decoder; +extern AVCodec ff_adpcm_ima_smjpeg_decoder; +extern AVCodec ff_adpcm_ima_wav_encoder; +extern AVCodec ff_adpcm_ima_wav_decoder; +extern AVCodec ff_adpcm_ima_ws_decoder; +extern AVCodec ff_adpcm_ms_encoder; +extern AVCodec ff_adpcm_ms_decoder; +extern AVCodec ff_adpcm_mtaf_decoder; +extern AVCodec ff_adpcm_psx_decoder; +extern AVCodec ff_adpcm_sbpro_2_decoder; +extern AVCodec ff_adpcm_sbpro_3_decoder; +extern AVCodec ff_adpcm_sbpro_4_decoder; +extern AVCodec ff_adpcm_swf_encoder; +extern AVCodec ff_adpcm_swf_decoder; +extern AVCodec ff_adpcm_thp_decoder; +extern AVCodec ff_adpcm_thp_le_decoder; +extern AVCodec ff_adpcm_vima_decoder; +extern AVCodec ff_adpcm_xa_decoder; +extern AVCodec ff_adpcm_yamaha_encoder; +extern AVCodec ff_adpcm_yamaha_decoder; + +/* subtitles */ +extern AVCodec ff_ssa_encoder; +extern AVCodec ff_ssa_decoder; +extern AVCodec ff_ass_encoder; +extern AVCodec ff_ass_decoder; +extern AVCodec ff_ccaption_decoder; +extern AVCodec ff_dvbsub_encoder; +extern AVCodec ff_dvbsub_decoder; +extern AVCodec ff_dvdsub_encoder; +extern AVCodec ff_dvdsub_decoder; +extern AVCodec ff_jacosub_decoder; +extern AVCodec ff_microdvd_decoder; +extern AVCodec ff_movtext_encoder; +extern AVCodec ff_movtext_decoder; +extern AVCodec ff_mpl2_decoder; +extern AVCodec ff_pgssub_decoder; +extern AVCodec ff_pjs_decoder; +extern AVCodec ff_realtext_decoder; +extern AVCodec ff_sami_decoder; +extern AVCodec ff_srt_encoder; +extern AVCodec ff_srt_decoder; +extern AVCodec ff_stl_decoder; +extern AVCodec ff_subrip_encoder; +extern AVCodec ff_subrip_decoder; +extern AVCodec ff_subviewer_decoder; +extern AVCodec ff_subviewer1_decoder; +extern AVCodec ff_text_encoder; +extern AVCodec ff_text_decoder; +extern AVCodec ff_vplayer_decoder; +extern AVCodec ff_webvtt_encoder; +extern AVCodec ff_webvtt_decoder; +extern AVCodec ff_xsub_encoder; +extern AVCodec ff_xsub_decoder; + +/* external libraries */ +extern AVCodec ff_aac_at_encoder; +extern AVCodec ff_aac_at_decoder; +extern AVCodec ff_ac3_at_decoder; +extern AVCodec ff_adpcm_ima_qt_at_decoder; +extern AVCodec ff_alac_at_encoder; +extern AVCodec ff_alac_at_decoder; +extern AVCodec ff_amr_nb_at_decoder; +extern AVCodec ff_eac3_at_decoder; +extern AVCodec ff_gsm_ms_at_decoder; +extern AVCodec ff_ilbc_at_encoder; +extern AVCodec ff_ilbc_at_decoder; +extern AVCodec ff_mp1_at_decoder; +extern AVCodec ff_mp2_at_decoder; +extern AVCodec ff_mp3_at_decoder; +extern AVCodec ff_pcm_alaw_at_encoder; +extern AVCodec ff_pcm_alaw_at_decoder; +extern AVCodec ff_pcm_mulaw_at_encoder; +extern AVCodec ff_pcm_mulaw_at_decoder; +extern AVCodec ff_qdmc_at_decoder; +extern AVCodec ff_qdm2_at_decoder; +extern AVCodec ff_libaom_av1_decoder; +extern AVCodec ff_libaom_av1_encoder; +extern AVCodec ff_libaribb24_decoder; +extern AVCodec ff_libcelt_decoder; +extern AVCodec ff_libcodec2_encoder; +extern AVCodec ff_libcodec2_decoder; +extern AVCodec ff_libdav1d_decoder; +extern AVCodec ff_libdavs2_decoder; +extern AVCodec ff_libfdk_aac_encoder; +extern AVCodec ff_libfdk_aac_decoder; +extern AVCodec ff_libgsm_encoder; +extern AVCodec ff_libgsm_decoder; +extern AVCodec ff_libgsm_ms_encoder; +extern AVCodec ff_libgsm_ms_decoder; +extern AVCodec ff_libilbc_encoder; +extern AVCodec ff_libilbc_decoder; +extern AVCodec ff_libmp3lame_encoder; +extern AVCodec ff_libopencore_amrnb_encoder; +extern AVCodec ff_libopencore_amrnb_decoder; +extern AVCodec ff_libopencore_amrwb_decoder; +extern AVCodec ff_libopenjpeg_encoder; +extern AVCodec ff_libopenjpeg_decoder; +extern AVCodec ff_libopus_encoder; +extern AVCodec ff_libopus_decoder; +extern AVCodec ff_librsvg_decoder; +extern AVCodec ff_libshine_encoder; +extern AVCodec ff_libspeex_encoder; +extern AVCodec ff_libspeex_decoder; +extern AVCodec ff_libtheora_encoder; +extern AVCodec ff_libtwolame_encoder; +extern AVCodec ff_libvo_amrwbenc_encoder; +extern AVCodec ff_libvorbis_encoder; +extern AVCodec ff_libvorbis_decoder; +extern AVCodec ff_libvpx_vp8_encoder; +extern AVCodec ff_libvpx_vp8_decoder; +extern AVCodec ff_libvpx_vp9_encoder; +extern AVCodec ff_libvpx_vp9_decoder; +extern AVCodec ff_libwavpack_encoder; +/* preferred over libwebp */ +extern AVCodec ff_libwebp_anim_encoder; +extern AVCodec ff_libwebp_encoder; +extern AVCodec ff_libx262_encoder; +extern AVCodec ff_libx264_encoder; +extern AVCodec ff_libx264rgb_encoder; +extern AVCodec ff_libx265_encoder; +extern AVCodec ff_libxavs_encoder; +extern AVCodec ff_libxavs2_encoder; +extern AVCodec ff_libxvid_encoder; +extern AVCodec ff_libzvbi_teletext_decoder; + +/* text */ +extern AVCodec ff_bintext_decoder; +extern AVCodec ff_xbin_decoder; +extern AVCodec ff_idf_decoder; + +/* external libraries, that shouldn't be used by default if one of the + * above is available */ +extern AVCodec ff_h263_v4l2m2m_encoder; +extern AVCodec ff_libopenh264_encoder; +extern AVCodec ff_libopenh264_decoder; +extern AVCodec ff_h264_amf_encoder; +extern AVCodec ff_h264_cuvid_decoder; +extern AVCodec ff_h264_nvenc_encoder; +extern AVCodec ff_h264_omx_encoder; +extern AVCodec ff_h264_qsv_encoder; +extern AVCodec ff_h264_v4l2m2m_encoder; +extern AVCodec ff_h264_vaapi_encoder; +extern AVCodec ff_h264_videotoolbox_encoder; +#if FF_API_NVENC_OLD_NAME +extern AVCodec ff_nvenc_encoder; +extern AVCodec ff_nvenc_h264_encoder; +extern AVCodec ff_nvenc_hevc_encoder; +#endif +extern AVCodec ff_hevc_amf_encoder; +extern AVCodec ff_hevc_cuvid_decoder; +extern AVCodec ff_hevc_mediacodec_decoder; +extern AVCodec ff_hevc_nvenc_encoder; +extern AVCodec ff_hevc_qsv_encoder; +extern AVCodec ff_hevc_v4l2m2m_encoder; +extern AVCodec ff_hevc_vaapi_encoder; +extern AVCodec ff_hevc_videotoolbox_encoder; +extern AVCodec ff_libkvazaar_encoder; +extern AVCodec ff_mjpeg_cuvid_decoder; +extern AVCodec ff_mjpeg_qsv_encoder; +extern AVCodec ff_mjpeg_vaapi_encoder; +extern AVCodec ff_mpeg1_cuvid_decoder; +extern AVCodec ff_mpeg2_cuvid_decoder; +extern AVCodec ff_mpeg2_qsv_encoder; +extern AVCodec ff_mpeg2_vaapi_encoder; +extern AVCodec ff_mpeg4_cuvid_decoder; +extern AVCodec ff_mpeg4_mediacodec_decoder; +extern AVCodec ff_mpeg4_v4l2m2m_encoder; +extern AVCodec ff_vc1_cuvid_decoder; +extern AVCodec ff_vp8_cuvid_decoder; +extern AVCodec ff_vp8_mediacodec_decoder; +extern AVCodec ff_vp8_qsv_decoder; +extern AVCodec ff_vp8_v4l2m2m_encoder; +extern AVCodec ff_vp8_vaapi_encoder; +extern AVCodec ff_vp9_cuvid_decoder; +extern AVCodec ff_vp9_mediacodec_decoder; +extern AVCodec ff_vp9_vaapi_encoder; + +// The iterate API is not usable with ossfuzz due to the excessive size of binaries created +#if CONFIG_OSSFUZZ +AVCodec * codec_list[] = { + NULL, + NULL +}; +#else +#include "libavcodec/codec_list.c" +#endif + +static AVOnce av_codec_static_init = AV_ONCE_INIT; +static void av_codec_init_static(void) +{ + for (int i = 0; codec_list[i]; i++) { + if (codec_list[i]->init_static_data) + codec_list[i]->init_static_data((AVCodec*)codec_list[i]); + } +} + +const AVCodec *av_codec_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVCodec *c = codec_list[i]; + + ff_thread_once(&av_codec_static_init, av_codec_init_static); + + if (c) + *opaque = (void*)(i + 1); + + return c; +} + +#if FF_API_NEXT +FF_DISABLE_DEPRECATION_WARNINGS +static AVOnce av_codec_next_init = AV_ONCE_INIT; + +static void av_codec_init_next(void) +{ + AVCodec *prev = NULL, *p; + void *i = 0; + while ((p = (AVCodec*)av_codec_iterate(&i))) { + if (prev) + prev->next = p; + prev = p; + } +} + + + +av_cold void avcodec_register(AVCodec *codec) +{ + ff_thread_once(&av_codec_next_init, av_codec_init_next); +} + +AVCodec *av_codec_next(const AVCodec *c) +{ + ff_thread_once(&av_codec_next_init, av_codec_init_next); + + if (c) + return c->next; + else + return (AVCodec*)codec_list[0]; +} + +void avcodec_register_all(void) +{ + ff_thread_once(&av_codec_next_init, av_codec_init_next); +} +FF_ENABLE_DEPRECATION_WARNINGS +#endif + +static enum AVCodecID remap_deprecated_codec_id(enum AVCodecID id) +{ + switch(id){ + //This is for future deprecatec codec ids, its empty since + //last major bump but will fill up again over time, please don't remove it + default : return id; + } +} + +static AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *)) +{ + const AVCodec *p, *experimental = NULL; + void *i = 0; + + id = remap_deprecated_codec_id(id); + + while ((p = av_codec_iterate(&i))) { + if (!x(p)) + continue; + if (p->id == id) { + if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) { + experimental = p; + } else + return (AVCodec*)p; + } + } + + return (AVCodec*)experimental; +} + +AVCodec *avcodec_find_encoder(enum AVCodecID id) +{ + return find_codec(id, av_codec_is_encoder); +} + +AVCodec *avcodec_find_decoder(enum AVCodecID id) +{ + return find_codec(id, av_codec_is_decoder); +} + +static AVCodec *find_codec_by_name(const char *name, int (*x)(const AVCodec *)) +{ + void *i = 0; + const AVCodec *p; + + if (!name) + return NULL; + + while ((p = av_codec_iterate(&i))) { + if (!x(p)) + continue; + if (strcmp(name, p->name) == 0) + return (AVCodec*)p; + } + + return NULL; +} + +AVCodec *avcodec_find_encoder_by_name(const char *name) +{ + return find_codec_by_name(name, av_codec_is_encoder); +} + +AVCodec *avcodec_find_decoder_by_name(const char *name) +{ + return find_codec_by_name(name, av_codec_is_decoder); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/audio_frame_queue.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/audio_frame_queue.c new file mode 100644 index 0000000000..f2ccd69281 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/audio_frame_queue.c @@ -0,0 +1,113 @@ +/* + * Audio Frame Queue + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/common.h" +#include "audio_frame_queue.h" +#include "internal.h" +#include "libavutil/avassert.h" + +av_cold void ff_af_queue_init(AVCodecContext *avctx, AudioFrameQueue *afq) +{ + afq->avctx = avctx; + afq->remaining_delay = avctx->initial_padding; + afq->remaining_samples = avctx->initial_padding; + afq->frame_count = 0; +} + +void ff_af_queue_close(AudioFrameQueue *afq) +{ + if(afq->frame_count) + av_log(afq->avctx, AV_LOG_WARNING, "%d frames left in the queue on closing\n", afq->frame_count); + av_freep(&afq->frames); + memset(afq, 0, sizeof(*afq)); +} + +int ff_af_queue_add(AudioFrameQueue *afq, const AVFrame *f) +{ + AudioFrame *new = av_fast_realloc(afq->frames, &afq->frame_alloc, sizeof(*afq->frames)*(afq->frame_count+1)); + if(!new) + return AVERROR(ENOMEM); + afq->frames = new; + new += afq->frame_count; + + /* get frame parameters */ + new->duration = f->nb_samples; + new->duration += afq->remaining_delay; + if (f->pts != AV_NOPTS_VALUE) { + new->pts = av_rescale_q(f->pts, + afq->avctx->time_base, + (AVRational){ 1, afq->avctx->sample_rate }); + new->pts -= afq->remaining_delay; + if(afq->frame_count && new[-1].pts >= new->pts) + av_log(afq->avctx, AV_LOG_WARNING, "Queue input is backward in time\n"); + } else { + new->pts = AV_NOPTS_VALUE; + } + afq->remaining_delay = 0; + + /* add frame sample count */ + afq->remaining_samples += f->nb_samples; + + afq->frame_count++; + + return 0; +} + +void ff_af_queue_remove(AudioFrameQueue *afq, int nb_samples, int64_t *pts, + int64_t *duration) +{ + int64_t out_pts = AV_NOPTS_VALUE; + int removed_samples = 0; + int i; + + if (afq->frame_count || afq->frame_alloc) { + if (afq->frames->pts != AV_NOPTS_VALUE) + out_pts = afq->frames->pts; + } + if(!afq->frame_count) + av_log(afq->avctx, AV_LOG_WARNING, "Trying to remove %d samples, but the queue is empty\n", nb_samples); + if (pts) + *pts = ff_samples_to_time_base(afq->avctx, out_pts); + + for(i=0; nb_samples && iframe_count; i++){ + int n= FFMIN(afq->frames[i].duration, nb_samples); + afq->frames[i].duration -= n; + nb_samples -= n; + removed_samples += n; + if(afq->frames[i].pts != AV_NOPTS_VALUE) + afq->frames[i].pts += n; + } + afq->remaining_samples -= removed_samples; + i -= i && afq->frames[i-1].duration; + memmove(afq->frames, afq->frames + i, sizeof(*afq->frames) * (afq->frame_count - i)); + afq->frame_count -= i; + + if(nb_samples){ + av_assert0(!afq->frame_count); + av_assert0(afq->remaining_samples == afq->remaining_delay); + if(afq->frames && afq->frames[0].pts != AV_NOPTS_VALUE) + afq->frames[0].pts += nb_samples; + av_log(afq->avctx, AV_LOG_DEBUG, "Trying to remove %d more samples than there are in the queue\n", nb_samples); + } + if (duration) + *duration = ff_samples_to_time_base(afq->avctx, removed_samples); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/audio_frame_queue.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/audio_frame_queue.h new file mode 100644 index 0000000000..d8076eae54 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/audio_frame_queue.h @@ -0,0 +1,83 @@ +/* + * Audio Frame Queue + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AUDIO_FRAME_QUEUE_H +#define AVCODEC_AUDIO_FRAME_QUEUE_H + +#include "avcodec.h" + +typedef struct AudioFrame { + int64_t pts; + int duration; +} AudioFrame; + +typedef struct AudioFrameQueue { + AVCodecContext *avctx; + int remaining_delay; + int remaining_samples; + AudioFrame *frames; + unsigned frame_count; + unsigned frame_alloc; +} AudioFrameQueue; + +/** + * Initialize AudioFrameQueue. + * + * @param avctx context to use for time_base and av_log + * @param afq queue context + */ +void ff_af_queue_init(AVCodecContext *avctx, AudioFrameQueue *afq); + +/** + * Close AudioFrameQueue. + * + * Frees memory if needed. + * + * @param afq queue context + */ +void ff_af_queue_close(AudioFrameQueue *afq); + +/** + * Add a frame to the queue. + * + * @param afq queue context + * @param f frame to add to the queue + */ +int ff_af_queue_add(AudioFrameQueue *afq, const AVFrame *f); + +/** + * Remove frame(s) from the queue. + * + * Retrieves the pts of the next available frame, or a generated pts based on + * the last frame duration if there are no frames left in the queue. The number + * of requested samples should be the full number of samples represented by the + * packet that will be output by the encoder. If fewer samples are available + * in the queue, a smaller value will be used for the output duration. + * + * @param afq queue context + * @param nb_samples number of samples to remove from the queue + * @param[out] pts output packet pts + * @param[out] duration output packet duration + */ +void ff_af_queue_remove(AudioFrameQueue *afq, int nb_samples, int64_t *pts, + int64_t *duration); + +#endif /* AVCODEC_AUDIO_FRAME_QUEUE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avcodec.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avcodec.h new file mode 100644 index 0000000000..d234271c5b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avcodec.h @@ -0,0 +1,6228 @@ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVCODEC_H +#define AVCODEC_AVCODEC_H + +/** + * @file + * @ingroup libavc + * Libavcodec external API header + */ + +#include +#include "libavutil/samplefmt.h" +#include "libavutil/attributes.h" +#include "libavutil/avutil.h" +#include "libavutil/buffer.h" +#include "libavutil/cpu.h" +#include "libavutil/channel_layout.h" +#include "libavutil/dict.h" +#include "libavutil/frame.h" +#include "libavutil/hwcontext.h" +#include "libavutil/log.h" +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" + +#include "version.h" + +/** + * @defgroup libavc libavcodec + * Encoding/Decoding Library + * + * @{ + * + * @defgroup lavc_decoding Decoding + * @{ + * @} + * + * @defgroup lavc_encoding Encoding + * @{ + * @} + * + * @defgroup lavc_codec Codecs + * @{ + * @defgroup lavc_codec_native Native Codecs + * @{ + * @} + * @defgroup lavc_codec_wrappers External library wrappers + * @{ + * @} + * @defgroup lavc_codec_hwaccel Hardware Accelerators bridge + * @{ + * @} + * @} + * @defgroup lavc_internal Internal + * @{ + * @} + * @} + */ + +/** + * @ingroup libavc + * @defgroup lavc_encdec send/receive encoding and decoding API overview + * @{ + * + * The avcodec_send_packet()/avcodec_receive_frame()/avcodec_send_frame()/ + * avcodec_receive_packet() functions provide an encode/decode API, which + * decouples input and output. + * + * The API is very similar for encoding/decoding and audio/video, and works as + * follows: + * - Set up and open the AVCodecContext as usual. + * - Send valid input: + * - For decoding, call avcodec_send_packet() to give the decoder raw + * compressed data in an AVPacket. + * - For encoding, call avcodec_send_frame() to give the encoder an AVFrame + * containing uncompressed audio or video. + * In both cases, it is recommended that AVPackets and AVFrames are + * refcounted, or libavcodec might have to copy the input data. (libavformat + * always returns refcounted AVPackets, and av_frame_get_buffer() allocates + * refcounted AVFrames.) + * - Receive output in a loop. Periodically call one of the avcodec_receive_*() + * functions and process their output: + * - For decoding, call avcodec_receive_frame(). On success, it will return + * an AVFrame containing uncompressed audio or video data. + * - For encoding, call avcodec_receive_packet(). On success, it will return + * an AVPacket with a compressed frame. + * Repeat this call until it returns AVERROR(EAGAIN) or an error. The + * AVERROR(EAGAIN) return value means that new input data is required to + * return new output. In this case, continue with sending input. For each + * input frame/packet, the codec will typically return 1 output frame/packet, + * but it can also be 0 or more than 1. + * + * At the beginning of decoding or encoding, the codec might accept multiple + * input frames/packets without returning a frame, until its internal buffers + * are filled. This situation is handled transparently if you follow the steps + * outlined above. + * + * In theory, sending input can result in EAGAIN - this should happen only if + * not all output was received. You can use this to structure alternative decode + * or encode loops other than the one suggested above. For example, you could + * try sending new input on each iteration, and try to receive output if that + * returns EAGAIN. + * + * End of stream situations. These require "flushing" (aka draining) the codec, + * as the codec might buffer multiple frames or packets internally for + * performance or out of necessity (consider B-frames). + * This is handled as follows: + * - Instead of valid input, send NULL to the avcodec_send_packet() (decoding) + * or avcodec_send_frame() (encoding) functions. This will enter draining + * mode. + * - Call avcodec_receive_frame() (decoding) or avcodec_receive_packet() + * (encoding) in a loop until AVERROR_EOF is returned. The functions will + * not return AVERROR(EAGAIN), unless you forgot to enter draining mode. + * - Before decoding can be resumed again, the codec has to be reset with + * avcodec_flush_buffers(). + * + * Using the API as outlined above is highly recommended. But it is also + * possible to call functions outside of this rigid schema. For example, you can + * call avcodec_send_packet() repeatedly without calling + * avcodec_receive_frame(). In this case, avcodec_send_packet() will succeed + * until the codec's internal buffer has been filled up (which is typically of + * size 1 per output frame, after initial input), and then reject input with + * AVERROR(EAGAIN). Once it starts rejecting input, you have no choice but to + * read at least some output. + * + * Not all codecs will follow a rigid and predictable dataflow; the only + * guarantee is that an AVERROR(EAGAIN) return value on a send/receive call on + * one end implies that a receive/send call on the other end will succeed, or + * at least will not fail with AVERROR(EAGAIN). In general, no codec will + * permit unlimited buffering of input or output. + * + * This API replaces the following legacy functions: + * - avcodec_decode_video2() and avcodec_decode_audio4(): + * Use avcodec_send_packet() to feed input to the decoder, then use + * avcodec_receive_frame() to receive decoded frames after each packet. + * Unlike with the old video decoding API, multiple frames might result from + * a packet. For audio, splitting the input packet into frames by partially + * decoding packets becomes transparent to the API user. You never need to + * feed an AVPacket to the API twice (unless it is rejected with AVERROR(EAGAIN) - then + * no data was read from the packet). + * Additionally, sending a flush/draining packet is required only once. + * - avcodec_encode_video2()/avcodec_encode_audio2(): + * Use avcodec_send_frame() to feed input to the encoder, then use + * avcodec_receive_packet() to receive encoded packets. + * Providing user-allocated buffers for avcodec_receive_packet() is not + * possible. + * - The new API does not handle subtitles yet. + * + * Mixing new and old function calls on the same AVCodecContext is not allowed, + * and will result in undefined behavior. + * + * Some codecs might require using the new API; using the old API will return + * an error when calling it. All codecs support the new API. + * + * A codec is not allowed to return AVERROR(EAGAIN) for both sending and receiving. This + * would be an invalid state, which could put the codec user into an endless + * loop. The API has no concept of time either: it cannot happen that trying to + * do avcodec_send_packet() results in AVERROR(EAGAIN), but a repeated call 1 second + * later accepts the packet (with no other receive/flush API calls involved). + * The API is a strict state machine, and the passage of time is not supposed + * to influence it. Some timing-dependent behavior might still be deemed + * acceptable in certain cases. But it must never result in both send/receive + * returning EAGAIN at the same time at any point. It must also absolutely be + * avoided that the current state is "unstable" and can "flip-flop" between + * the send/receive APIs allowing progress. For example, it's not allowed that + * the codec randomly decides that it actually wants to consume a packet now + * instead of returning a frame, after it just returned AVERROR(EAGAIN) on an + * avcodec_send_packet() call. + * @} + */ + +/** + * @defgroup lavc_core Core functions/structures. + * @ingroup libavc + * + * Basic definitions, functions for querying libavcodec capabilities, + * allocating core structures, etc. + * @{ + */ + + +/** + * Identify the syntax and semantics of the bitstream. + * The principle is roughly: + * Two decoders with the same ID can decode the same streams. + * Two encoders with the same ID can encode compatible streams. + * There may be slight deviations from the principle due to implementation + * details. + * + * If you add a codec ID to this list, add it so that + * 1. no value of an existing codec ID changes (that would break ABI), + * 2. it is as close as possible to similar codecs + * + * After adding new codec IDs, do not forget to add an entry to the codec + * descriptor list and bump libavcodec minor version. + */ +enum AVCodecID { + AV_CODEC_ID_NONE, + + /* video codecs */ + AV_CODEC_ID_MPEG1VIDEO, + AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding + AV_CODEC_ID_H261, + AV_CODEC_ID_H263, + AV_CODEC_ID_RV10, + AV_CODEC_ID_RV20, + AV_CODEC_ID_MJPEG, + AV_CODEC_ID_MJPEGB, + AV_CODEC_ID_LJPEG, + AV_CODEC_ID_SP5X, + AV_CODEC_ID_JPEGLS, + AV_CODEC_ID_MPEG4, + AV_CODEC_ID_RAWVIDEO, + AV_CODEC_ID_MSMPEG4V1, + AV_CODEC_ID_MSMPEG4V2, + AV_CODEC_ID_MSMPEG4V3, + AV_CODEC_ID_WMV1, + AV_CODEC_ID_WMV2, + AV_CODEC_ID_H263P, + AV_CODEC_ID_H263I, + AV_CODEC_ID_FLV1, + AV_CODEC_ID_SVQ1, + AV_CODEC_ID_SVQ3, + AV_CODEC_ID_DVVIDEO, + AV_CODEC_ID_HUFFYUV, + AV_CODEC_ID_CYUV, + AV_CODEC_ID_H264, + AV_CODEC_ID_INDEO3, + AV_CODEC_ID_VP3, + AV_CODEC_ID_THEORA, + AV_CODEC_ID_ASV1, + AV_CODEC_ID_ASV2, + AV_CODEC_ID_FFV1, + AV_CODEC_ID_4XM, + AV_CODEC_ID_VCR1, + AV_CODEC_ID_CLJR, + AV_CODEC_ID_MDEC, + AV_CODEC_ID_ROQ, + AV_CODEC_ID_INTERPLAY_VIDEO, + AV_CODEC_ID_XAN_WC3, + AV_CODEC_ID_XAN_WC4, + AV_CODEC_ID_RPZA, + AV_CODEC_ID_CINEPAK, + AV_CODEC_ID_WS_VQA, + AV_CODEC_ID_MSRLE, + AV_CODEC_ID_MSVIDEO1, + AV_CODEC_ID_IDCIN, + AV_CODEC_ID_8BPS, + AV_CODEC_ID_SMC, + AV_CODEC_ID_FLIC, + AV_CODEC_ID_TRUEMOTION1, + AV_CODEC_ID_VMDVIDEO, + AV_CODEC_ID_MSZH, + AV_CODEC_ID_ZLIB, + AV_CODEC_ID_QTRLE, + AV_CODEC_ID_TSCC, + AV_CODEC_ID_ULTI, + AV_CODEC_ID_QDRAW, + AV_CODEC_ID_VIXL, + AV_CODEC_ID_QPEG, + AV_CODEC_ID_PNG, + AV_CODEC_ID_PPM, + AV_CODEC_ID_PBM, + AV_CODEC_ID_PGM, + AV_CODEC_ID_PGMYUV, + AV_CODEC_ID_PAM, + AV_CODEC_ID_FFVHUFF, + AV_CODEC_ID_RV30, + AV_CODEC_ID_RV40, + AV_CODEC_ID_VC1, + AV_CODEC_ID_WMV3, + AV_CODEC_ID_LOCO, + AV_CODEC_ID_WNV1, + AV_CODEC_ID_AASC, + AV_CODEC_ID_INDEO2, + AV_CODEC_ID_FRAPS, + AV_CODEC_ID_TRUEMOTION2, + AV_CODEC_ID_BMP, + AV_CODEC_ID_CSCD, + AV_CODEC_ID_MMVIDEO, + AV_CODEC_ID_ZMBV, + AV_CODEC_ID_AVS, + AV_CODEC_ID_SMACKVIDEO, + AV_CODEC_ID_NUV, + AV_CODEC_ID_KMVC, + AV_CODEC_ID_FLASHSV, + AV_CODEC_ID_CAVS, + AV_CODEC_ID_JPEG2000, + AV_CODEC_ID_VMNC, + AV_CODEC_ID_VP5, + AV_CODEC_ID_VP6, + AV_CODEC_ID_VP6F, + AV_CODEC_ID_TARGA, + AV_CODEC_ID_DSICINVIDEO, + AV_CODEC_ID_TIERTEXSEQVIDEO, + AV_CODEC_ID_TIFF, + AV_CODEC_ID_GIF, + AV_CODEC_ID_DXA, + AV_CODEC_ID_DNXHD, + AV_CODEC_ID_THP, + AV_CODEC_ID_SGI, + AV_CODEC_ID_C93, + AV_CODEC_ID_BETHSOFTVID, + AV_CODEC_ID_PTX, + AV_CODEC_ID_TXD, + AV_CODEC_ID_VP6A, + AV_CODEC_ID_AMV, + AV_CODEC_ID_VB, + AV_CODEC_ID_PCX, + AV_CODEC_ID_SUNRAST, + AV_CODEC_ID_INDEO4, + AV_CODEC_ID_INDEO5, + AV_CODEC_ID_MIMIC, + AV_CODEC_ID_RL2, + AV_CODEC_ID_ESCAPE124, + AV_CODEC_ID_DIRAC, + AV_CODEC_ID_BFI, + AV_CODEC_ID_CMV, + AV_CODEC_ID_MOTIONPIXELS, + AV_CODEC_ID_TGV, + AV_CODEC_ID_TGQ, + AV_CODEC_ID_TQI, + AV_CODEC_ID_AURA, + AV_CODEC_ID_AURA2, + AV_CODEC_ID_V210X, + AV_CODEC_ID_TMV, + AV_CODEC_ID_V210, + AV_CODEC_ID_DPX, + AV_CODEC_ID_MAD, + AV_CODEC_ID_FRWU, + AV_CODEC_ID_FLASHSV2, + AV_CODEC_ID_CDGRAPHICS, + AV_CODEC_ID_R210, + AV_CODEC_ID_ANM, + AV_CODEC_ID_BINKVIDEO, + AV_CODEC_ID_IFF_ILBM, +#define AV_CODEC_ID_IFF_BYTERUN1 AV_CODEC_ID_IFF_ILBM + AV_CODEC_ID_KGV1, + AV_CODEC_ID_YOP, + AV_CODEC_ID_VP8, + AV_CODEC_ID_PICTOR, + AV_CODEC_ID_ANSI, + AV_CODEC_ID_A64_MULTI, + AV_CODEC_ID_A64_MULTI5, + AV_CODEC_ID_R10K, + AV_CODEC_ID_MXPEG, + AV_CODEC_ID_LAGARITH, + AV_CODEC_ID_PRORES, + AV_CODEC_ID_JV, + AV_CODEC_ID_DFA, + AV_CODEC_ID_WMV3IMAGE, + AV_CODEC_ID_VC1IMAGE, + AV_CODEC_ID_UTVIDEO, + AV_CODEC_ID_BMV_VIDEO, + AV_CODEC_ID_VBLE, + AV_CODEC_ID_DXTORY, + AV_CODEC_ID_V410, + AV_CODEC_ID_XWD, + AV_CODEC_ID_CDXL, + AV_CODEC_ID_XBM, + AV_CODEC_ID_ZEROCODEC, + AV_CODEC_ID_MSS1, + AV_CODEC_ID_MSA1, + AV_CODEC_ID_TSCC2, + AV_CODEC_ID_MTS2, + AV_CODEC_ID_CLLC, + AV_CODEC_ID_MSS2, + AV_CODEC_ID_VP9, + AV_CODEC_ID_AIC, + AV_CODEC_ID_ESCAPE130, + AV_CODEC_ID_G2M, + AV_CODEC_ID_WEBP, + AV_CODEC_ID_HNM4_VIDEO, + AV_CODEC_ID_HEVC, +#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC + AV_CODEC_ID_FIC, + AV_CODEC_ID_ALIAS_PIX, + AV_CODEC_ID_BRENDER_PIX, + AV_CODEC_ID_PAF_VIDEO, + AV_CODEC_ID_EXR, + AV_CODEC_ID_VP7, + AV_CODEC_ID_SANM, + AV_CODEC_ID_SGIRLE, + AV_CODEC_ID_MVC1, + AV_CODEC_ID_MVC2, + AV_CODEC_ID_HQX, + AV_CODEC_ID_TDSC, + AV_CODEC_ID_HQ_HQA, + AV_CODEC_ID_HAP, + AV_CODEC_ID_DDS, + AV_CODEC_ID_DXV, + AV_CODEC_ID_SCREENPRESSO, + AV_CODEC_ID_RSCC, + AV_CODEC_ID_AVS2, + + AV_CODEC_ID_Y41P = 0x8000, + AV_CODEC_ID_AVRP, + AV_CODEC_ID_012V, + AV_CODEC_ID_AVUI, + AV_CODEC_ID_AYUV, + AV_CODEC_ID_TARGA_Y216, + AV_CODEC_ID_V308, + AV_CODEC_ID_V408, + AV_CODEC_ID_YUV4, + AV_CODEC_ID_AVRN, + AV_CODEC_ID_CPIA, + AV_CODEC_ID_XFACE, + AV_CODEC_ID_SNOW, + AV_CODEC_ID_SMVJPEG, + AV_CODEC_ID_APNG, + AV_CODEC_ID_DAALA, + AV_CODEC_ID_CFHD, + AV_CODEC_ID_TRUEMOTION2RT, + AV_CODEC_ID_M101, + AV_CODEC_ID_MAGICYUV, + AV_CODEC_ID_SHEERVIDEO, + AV_CODEC_ID_YLC, + AV_CODEC_ID_PSD, + AV_CODEC_ID_PIXLET, + AV_CODEC_ID_SPEEDHQ, + AV_CODEC_ID_FMVC, + AV_CODEC_ID_SCPR, + AV_CODEC_ID_CLEARVIDEO, + AV_CODEC_ID_XPM, + AV_CODEC_ID_AV1, + AV_CODEC_ID_BITPACKED, + AV_CODEC_ID_MSCC, + AV_CODEC_ID_SRGC, + AV_CODEC_ID_SVG, + AV_CODEC_ID_GDV, + AV_CODEC_ID_FITS, + AV_CODEC_ID_IMM4, + AV_CODEC_ID_PROSUMER, + AV_CODEC_ID_MWSC, + AV_CODEC_ID_WCMV, + AV_CODEC_ID_RASC, + AV_CODEC_ID_HYMT, + AV_CODEC_ID_ARBC, + AV_CODEC_ID_AGM, + AV_CODEC_ID_LSCR, + AV_CODEC_ID_VP4, + + /* various PCM "codecs" */ + AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs + AV_CODEC_ID_PCM_S16LE = 0x10000, + AV_CODEC_ID_PCM_S16BE, + AV_CODEC_ID_PCM_U16LE, + AV_CODEC_ID_PCM_U16BE, + AV_CODEC_ID_PCM_S8, + AV_CODEC_ID_PCM_U8, + AV_CODEC_ID_PCM_MULAW, + AV_CODEC_ID_PCM_ALAW, + AV_CODEC_ID_PCM_S32LE, + AV_CODEC_ID_PCM_S32BE, + AV_CODEC_ID_PCM_U32LE, + AV_CODEC_ID_PCM_U32BE, + AV_CODEC_ID_PCM_S24LE, + AV_CODEC_ID_PCM_S24BE, + AV_CODEC_ID_PCM_U24LE, + AV_CODEC_ID_PCM_U24BE, + AV_CODEC_ID_PCM_S24DAUD, + AV_CODEC_ID_PCM_ZORK, + AV_CODEC_ID_PCM_S16LE_PLANAR, + AV_CODEC_ID_PCM_DVD, + AV_CODEC_ID_PCM_F32BE, + AV_CODEC_ID_PCM_F32LE, + AV_CODEC_ID_PCM_F64BE, + AV_CODEC_ID_PCM_F64LE, + AV_CODEC_ID_PCM_BLURAY, + AV_CODEC_ID_PCM_LXF, + AV_CODEC_ID_S302M, + AV_CODEC_ID_PCM_S8_PLANAR, + AV_CODEC_ID_PCM_S24LE_PLANAR, + AV_CODEC_ID_PCM_S32LE_PLANAR, + AV_CODEC_ID_PCM_S16BE_PLANAR, + + AV_CODEC_ID_PCM_S64LE = 0x10800, + AV_CODEC_ID_PCM_S64BE, + AV_CODEC_ID_PCM_F16LE, + AV_CODEC_ID_PCM_F24LE, + AV_CODEC_ID_PCM_VIDC, + + /* various ADPCM codecs */ + AV_CODEC_ID_ADPCM_IMA_QT = 0x11000, + AV_CODEC_ID_ADPCM_IMA_WAV, + AV_CODEC_ID_ADPCM_IMA_DK3, + AV_CODEC_ID_ADPCM_IMA_DK4, + AV_CODEC_ID_ADPCM_IMA_WS, + AV_CODEC_ID_ADPCM_IMA_SMJPEG, + AV_CODEC_ID_ADPCM_MS, + AV_CODEC_ID_ADPCM_4XM, + AV_CODEC_ID_ADPCM_XA, + AV_CODEC_ID_ADPCM_ADX, + AV_CODEC_ID_ADPCM_EA, + AV_CODEC_ID_ADPCM_G726, + AV_CODEC_ID_ADPCM_CT, + AV_CODEC_ID_ADPCM_SWF, + AV_CODEC_ID_ADPCM_YAMAHA, + AV_CODEC_ID_ADPCM_SBPRO_4, + AV_CODEC_ID_ADPCM_SBPRO_3, + AV_CODEC_ID_ADPCM_SBPRO_2, + AV_CODEC_ID_ADPCM_THP, + AV_CODEC_ID_ADPCM_IMA_AMV, + AV_CODEC_ID_ADPCM_EA_R1, + AV_CODEC_ID_ADPCM_EA_R3, + AV_CODEC_ID_ADPCM_EA_R2, + AV_CODEC_ID_ADPCM_IMA_EA_SEAD, + AV_CODEC_ID_ADPCM_IMA_EA_EACS, + AV_CODEC_ID_ADPCM_EA_XAS, + AV_CODEC_ID_ADPCM_EA_MAXIS_XA, + AV_CODEC_ID_ADPCM_IMA_ISS, + AV_CODEC_ID_ADPCM_G722, + AV_CODEC_ID_ADPCM_IMA_APC, + AV_CODEC_ID_ADPCM_VIMA, + + AV_CODEC_ID_ADPCM_AFC = 0x11800, + AV_CODEC_ID_ADPCM_IMA_OKI, + AV_CODEC_ID_ADPCM_DTK, + AV_CODEC_ID_ADPCM_IMA_RAD, + AV_CODEC_ID_ADPCM_G726LE, + AV_CODEC_ID_ADPCM_THP_LE, + AV_CODEC_ID_ADPCM_PSX, + AV_CODEC_ID_ADPCM_AICA, + AV_CODEC_ID_ADPCM_IMA_DAT4, + AV_CODEC_ID_ADPCM_MTAF, + AV_CODEC_ID_ADPCM_AGM, + + /* AMR */ + AV_CODEC_ID_AMR_NB = 0x12000, + AV_CODEC_ID_AMR_WB, + + /* RealAudio codecs*/ + AV_CODEC_ID_RA_144 = 0x13000, + AV_CODEC_ID_RA_288, + + /* various DPCM codecs */ + AV_CODEC_ID_ROQ_DPCM = 0x14000, + AV_CODEC_ID_INTERPLAY_DPCM, + AV_CODEC_ID_XAN_DPCM, + AV_CODEC_ID_SOL_DPCM, + + AV_CODEC_ID_SDX2_DPCM = 0x14800, + AV_CODEC_ID_GREMLIN_DPCM, + + /* audio codecs */ + AV_CODEC_ID_MP2 = 0x15000, + AV_CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 + AV_CODEC_ID_AAC, + AV_CODEC_ID_AC3, + AV_CODEC_ID_DTS, + AV_CODEC_ID_VORBIS, + AV_CODEC_ID_DVAUDIO, + AV_CODEC_ID_WMAV1, + AV_CODEC_ID_WMAV2, + AV_CODEC_ID_MACE3, + AV_CODEC_ID_MACE6, + AV_CODEC_ID_VMDAUDIO, + AV_CODEC_ID_FLAC, + AV_CODEC_ID_MP3ADU, + AV_CODEC_ID_MP3ON4, + AV_CODEC_ID_SHORTEN, + AV_CODEC_ID_ALAC, + AV_CODEC_ID_WESTWOOD_SND1, + AV_CODEC_ID_GSM, ///< as in Berlin toast format + AV_CODEC_ID_QDM2, + AV_CODEC_ID_COOK, + AV_CODEC_ID_TRUESPEECH, + AV_CODEC_ID_TTA, + AV_CODEC_ID_SMACKAUDIO, + AV_CODEC_ID_QCELP, + AV_CODEC_ID_WAVPACK, + AV_CODEC_ID_DSICINAUDIO, + AV_CODEC_ID_IMC, + AV_CODEC_ID_MUSEPACK7, + AV_CODEC_ID_MLP, + AV_CODEC_ID_GSM_MS, /* as found in WAV */ + AV_CODEC_ID_ATRAC3, + AV_CODEC_ID_APE, + AV_CODEC_ID_NELLYMOSER, + AV_CODEC_ID_MUSEPACK8, + AV_CODEC_ID_SPEEX, + AV_CODEC_ID_WMAVOICE, + AV_CODEC_ID_WMAPRO, + AV_CODEC_ID_WMALOSSLESS, + AV_CODEC_ID_ATRAC3P, + AV_CODEC_ID_EAC3, + AV_CODEC_ID_SIPR, + AV_CODEC_ID_MP1, + AV_CODEC_ID_TWINVQ, + AV_CODEC_ID_TRUEHD, + AV_CODEC_ID_MP4ALS, + AV_CODEC_ID_ATRAC1, + AV_CODEC_ID_BINKAUDIO_RDFT, + AV_CODEC_ID_BINKAUDIO_DCT, + AV_CODEC_ID_AAC_LATM, + AV_CODEC_ID_QDMC, + AV_CODEC_ID_CELT, + AV_CODEC_ID_G723_1, + AV_CODEC_ID_G729, + AV_CODEC_ID_8SVX_EXP, + AV_CODEC_ID_8SVX_FIB, + AV_CODEC_ID_BMV_AUDIO, + AV_CODEC_ID_RALF, + AV_CODEC_ID_IAC, + AV_CODEC_ID_ILBC, + AV_CODEC_ID_OPUS, + AV_CODEC_ID_COMFORT_NOISE, + AV_CODEC_ID_TAK, + AV_CODEC_ID_METASOUND, + AV_CODEC_ID_PAF_AUDIO, + AV_CODEC_ID_ON2AVC, + AV_CODEC_ID_DSS_SP, + AV_CODEC_ID_CODEC2, + + AV_CODEC_ID_FFWAVESYNTH = 0x15800, + AV_CODEC_ID_SONIC, + AV_CODEC_ID_SONIC_LS, + AV_CODEC_ID_EVRC, + AV_CODEC_ID_SMV, + AV_CODEC_ID_DSD_LSBF, + AV_CODEC_ID_DSD_MSBF, + AV_CODEC_ID_DSD_LSBF_PLANAR, + AV_CODEC_ID_DSD_MSBF_PLANAR, + AV_CODEC_ID_4GV, + AV_CODEC_ID_INTERPLAY_ACM, + AV_CODEC_ID_XMA1, + AV_CODEC_ID_XMA2, + AV_CODEC_ID_DST, + AV_CODEC_ID_ATRAC3AL, + AV_CODEC_ID_ATRAC3PAL, + AV_CODEC_ID_DOLBY_E, + AV_CODEC_ID_APTX, + AV_CODEC_ID_APTX_HD, + AV_CODEC_ID_SBC, + AV_CODEC_ID_ATRAC9, + AV_CODEC_ID_HCOM, + + /* subtitle codecs */ + AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. + AV_CODEC_ID_DVD_SUBTITLE = 0x17000, + AV_CODEC_ID_DVB_SUBTITLE, + AV_CODEC_ID_TEXT, ///< raw UTF-8 text + AV_CODEC_ID_XSUB, + AV_CODEC_ID_SSA, + AV_CODEC_ID_MOV_TEXT, + AV_CODEC_ID_HDMV_PGS_SUBTITLE, + AV_CODEC_ID_DVB_TELETEXT, + AV_CODEC_ID_SRT, + + AV_CODEC_ID_MICRODVD = 0x17800, + AV_CODEC_ID_EIA_608, + AV_CODEC_ID_JACOSUB, + AV_CODEC_ID_SAMI, + AV_CODEC_ID_REALTEXT, + AV_CODEC_ID_STL, + AV_CODEC_ID_SUBVIEWER1, + AV_CODEC_ID_SUBVIEWER, + AV_CODEC_ID_SUBRIP, + AV_CODEC_ID_WEBVTT, + AV_CODEC_ID_MPL2, + AV_CODEC_ID_VPLAYER, + AV_CODEC_ID_PJS, + AV_CODEC_ID_ASS, + AV_CODEC_ID_HDMV_TEXT_SUBTITLE, + AV_CODEC_ID_TTML, + AV_CODEC_ID_ARIB_CAPTION, + + /* other specific kind of codecs (generally used for attachments) */ + AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. + AV_CODEC_ID_TTF = 0x18000, + + AV_CODEC_ID_SCTE_35, ///< Contain timestamp estimated through PCR of program stream. + AV_CODEC_ID_BINTEXT = 0x18800, + AV_CODEC_ID_XBIN, + AV_CODEC_ID_IDF, + AV_CODEC_ID_OTF, + AV_CODEC_ID_SMPTE_KLV, + AV_CODEC_ID_DVD_NAV, + AV_CODEC_ID_TIMED_ID3, + AV_CODEC_ID_BIN_DATA, + + + AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it + + AV_CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS + * stream (only used by libavformat) */ + AV_CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems + * stream (only used by libavformat) */ + AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information. + AV_CODEC_ID_WRAPPED_AVFRAME = 0x21001, ///< Passthrough codec, AVFrames wrapped in AVPacket +}; + +/** + * This struct describes the properties of a single codec described by an + * AVCodecID. + * @see avcodec_descriptor_get() + */ +typedef struct AVCodecDescriptor { + enum AVCodecID id; + enum AVMediaType type; + /** + * Name of the codec described by this descriptor. It is non-empty and + * unique for each codec descriptor. It should contain alphanumeric + * characters and '_' only. + */ + const char *name; + /** + * A more descriptive name for this codec. May be NULL. + */ + const char *long_name; + /** + * Codec properties, a combination of AV_CODEC_PROP_* flags. + */ + int props; + /** + * MIME type(s) associated with the codec. + * May be NULL; if not, a NULL-terminated array of MIME types. + * The first item is always non-NULL and is the preferred MIME type. + */ + const char *const *mime_types; + /** + * If non-NULL, an array of profiles recognized for this codec. + * Terminated with FF_PROFILE_UNKNOWN. + */ + const struct AVProfile *profiles; +} AVCodecDescriptor; + +/** + * Codec uses only intra compression. + * Video and audio codecs only. + */ +#define AV_CODEC_PROP_INTRA_ONLY (1 << 0) +/** + * Codec supports lossy compression. Audio and video codecs only. + * @note a codec may support both lossy and lossless + * compression modes + */ +#define AV_CODEC_PROP_LOSSY (1 << 1) +/** + * Codec supports lossless compression. Audio and video codecs only. + */ +#define AV_CODEC_PROP_LOSSLESS (1 << 2) +/** + * Codec supports frame reordering. That is, the coded order (the order in which + * the encoded packets are output by the encoders / stored / input to the + * decoders) may be different from the presentation order of the corresponding + * frames. + * + * For codecs that do not have this property set, PTS and DTS should always be + * equal. + */ +#define AV_CODEC_PROP_REORDER (1 << 3) +/** + * Subtitle codec is bitmap based + * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field. + */ +#define AV_CODEC_PROP_BITMAP_SUB (1 << 16) +/** + * Subtitle codec is text based. + * Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field. + */ +#define AV_CODEC_PROP_TEXT_SUB (1 << 17) + +/** + * @ingroup lavc_decoding + * Required number of additionally allocated bytes at the end of the input bitstream for decoding. + * This is mainly needed because some optimized bitstream readers read + * 32 or 64 bit at once and could read over the end.
      + * Note: If the first 23 bits of the additional bytes are not 0, then damaged + * MPEG bitstreams could cause overread and segfault. + */ +#define AV_INPUT_BUFFER_PADDING_SIZE 64 + +/** + * @ingroup lavc_encoding + * minimum encoding buffer size + * Used to avoid some checks during header writing. + */ +#define AV_INPUT_BUFFER_MIN_SIZE 16384 + +/** + * @ingroup lavc_decoding + */ +enum AVDiscard{ + /* We leave some space between them for extensions (drop some + * keyframes for intra-only or drop just some bidir frames). */ + AVDISCARD_NONE =-16, ///< discard nothing + AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi + AVDISCARD_NONREF = 8, ///< discard all non reference + AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames + AVDISCARD_NONINTRA= 24, ///< discard all non intra frames + AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes + AVDISCARD_ALL = 48, ///< discard all +}; + +enum AVAudioServiceType { + AV_AUDIO_SERVICE_TYPE_MAIN = 0, + AV_AUDIO_SERVICE_TYPE_EFFECTS = 1, + AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED = 2, + AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED = 3, + AV_AUDIO_SERVICE_TYPE_DIALOGUE = 4, + AV_AUDIO_SERVICE_TYPE_COMMENTARY = 5, + AV_AUDIO_SERVICE_TYPE_EMERGENCY = 6, + AV_AUDIO_SERVICE_TYPE_VOICE_OVER = 7, + AV_AUDIO_SERVICE_TYPE_KARAOKE = 8, + AV_AUDIO_SERVICE_TYPE_NB , ///< Not part of ABI +}; + +/** + * @ingroup lavc_encoding + */ +typedef struct RcOverride{ + int start_frame; + int end_frame; + int qscale; // If this is 0 then quality_factor will be used instead. + float quality_factor; +} RcOverride; + +/* encoding support + These flags can be passed in AVCodecContext.flags before initialization. + Note: Not everything is supported yet. +*/ + +/** + * Allow decoders to produce frames with data planes that are not aligned + * to CPU requirements (e.g. due to cropping). + */ +#define AV_CODEC_FLAG_UNALIGNED (1 << 0) +/** + * Use fixed qscale. + */ +#define AV_CODEC_FLAG_QSCALE (1 << 1) +/** + * 4 MV per MB allowed / advanced prediction for H.263. + */ +#define AV_CODEC_FLAG_4MV (1 << 2) +/** + * Output even those frames that might be corrupted. + */ +#define AV_CODEC_FLAG_OUTPUT_CORRUPT (1 << 3) +/** + * Use qpel MC. + */ +#define AV_CODEC_FLAG_QPEL (1 << 4) +/** + * Don't output frames whose parameters differ from first + * decoded frame in stream. + */ +#define AV_CODEC_FLAG_DROPCHANGED (1 << 5) +/** + * Use internal 2pass ratecontrol in first pass mode. + */ +#define AV_CODEC_FLAG_PASS1 (1 << 9) +/** + * Use internal 2pass ratecontrol in second pass mode. + */ +#define AV_CODEC_FLAG_PASS2 (1 << 10) +/** + * loop filter. + */ +#define AV_CODEC_FLAG_LOOP_FILTER (1 << 11) +/** + * Only decode/encode grayscale. + */ +#define AV_CODEC_FLAG_GRAY (1 << 13) +/** + * error[?] variables will be set during encoding. + */ +#define AV_CODEC_FLAG_PSNR (1 << 15) +/** + * Input bitstream might be truncated at a random location + * instead of only at frame boundaries. + */ +#define AV_CODEC_FLAG_TRUNCATED (1 << 16) +/** + * Use interlaced DCT. + */ +#define AV_CODEC_FLAG_INTERLACED_DCT (1 << 18) +/** + * Force low delay. + */ +#define AV_CODEC_FLAG_LOW_DELAY (1 << 19) +/** + * Place global headers in extradata instead of every keyframe. + */ +#define AV_CODEC_FLAG_GLOBAL_HEADER (1 << 22) +/** + * Use only bitexact stuff (except (I)DCT). + */ +#define AV_CODEC_FLAG_BITEXACT (1 << 23) +/* Fx : Flag for H.263+ extra options */ +/** + * H.263 advanced intra coding / MPEG-4 AC prediction + */ +#define AV_CODEC_FLAG_AC_PRED (1 << 24) +/** + * interlaced motion estimation + */ +#define AV_CODEC_FLAG_INTERLACED_ME (1 << 29) +#define AV_CODEC_FLAG_CLOSED_GOP (1U << 31) + +/** + * Allow non spec compliant speedup tricks. + */ +#define AV_CODEC_FLAG2_FAST (1 << 0) +/** + * Skip bitstream encoding. + */ +#define AV_CODEC_FLAG2_NO_OUTPUT (1 << 2) +/** + * Place global headers at every keyframe instead of in extradata. + */ +#define AV_CODEC_FLAG2_LOCAL_HEADER (1 << 3) + +/** + * timecode is in drop frame format. DEPRECATED!!!! + */ +#define AV_CODEC_FLAG2_DROP_FRAME_TIMECODE (1 << 13) + +/** + * Input bitstream might be truncated at a packet boundaries + * instead of only at frame boundaries. + */ +#define AV_CODEC_FLAG2_CHUNKS (1 << 15) +/** + * Discard cropping information from SPS. + */ +#define AV_CODEC_FLAG2_IGNORE_CROP (1 << 16) + +/** + * Show all frames before the first keyframe + */ +#define AV_CODEC_FLAG2_SHOW_ALL (1 << 22) +/** + * Export motion vectors through frame side data + */ +#define AV_CODEC_FLAG2_EXPORT_MVS (1 << 28) +/** + * Do not skip samples and export skip information as frame side data + */ +#define AV_CODEC_FLAG2_SKIP_MANUAL (1 << 29) +/** + * Do not reset ASS ReadOrder field on flush (subtitles decoding) + */ +#define AV_CODEC_FLAG2_RO_FLUSH_NOOP (1 << 30) + +/* Unsupported options : + * Syntax Arithmetic coding (SAC) + * Reference Picture Selection + * Independent Segment Decoding */ +/* /Fx */ +/* codec capabilities */ + +/** + * Decoder can use draw_horiz_band callback. + */ +#define AV_CODEC_CAP_DRAW_HORIZ_BAND (1 << 0) +/** + * Codec uses get_buffer() for allocating buffers and supports custom allocators. + * If not set, it might not use get_buffer() at all or use operations that + * assume the buffer was allocated by avcodec_default_get_buffer. + */ +#define AV_CODEC_CAP_DR1 (1 << 1) +#define AV_CODEC_CAP_TRUNCATED (1 << 3) +/** + * Encoder or decoder requires flushing with NULL input at the end in order to + * give the complete and correct output. + * + * NOTE: If this flag is not set, the codec is guaranteed to never be fed with + * with NULL data. The user can still send NULL data to the public encode + * or decode function, but libavcodec will not pass it along to the codec + * unless this flag is set. + * + * Decoders: + * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to get the delayed data until the decoder no longer + * returns frames. + * + * Encoders: + * The encoder needs to be fed with NULL data at the end of encoding until the + * encoder no longer returns data. + * + * NOTE: For encoders implementing the AVCodec.encode2() function, setting this + * flag also means that the encoder must set the pts and duration for + * each output packet. If this flag is not set, the pts and duration will + * be determined by libavcodec from the input frame. + */ +#define AV_CODEC_CAP_DELAY (1 << 5) +/** + * Codec can be fed a final frame with a smaller size. + * This can be used to prevent truncation of the last audio samples. + */ +#define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6) + +/** + * Codec can output multiple frames per AVPacket + * Normally demuxers return one frame at a time, demuxers which do not do + * are connected to a parser to split what they return into proper frames. + * This flag is reserved to the very rare category of codecs which have a + * bitstream that cannot be split into frames without timeconsuming + * operations like full decoding. Demuxers carrying such bitstreams thus + * may return multiple frames in a packet. This has many disadvantages like + * prohibiting stream copy in many cases thus it should only be considered + * as a last resort. + */ +#define AV_CODEC_CAP_SUBFRAMES (1 << 8) +/** + * Codec is experimental and is thus avoided in favor of non experimental + * encoders + */ +#define AV_CODEC_CAP_EXPERIMENTAL (1 << 9) +/** + * Codec should fill in channel configuration and samplerate instead of container + */ +#define AV_CODEC_CAP_CHANNEL_CONF (1 << 10) +/** + * Codec supports frame-level multithreading. + */ +#define AV_CODEC_CAP_FRAME_THREADS (1 << 12) +/** + * Codec supports slice-based (or partition-based) multithreading. + */ +#define AV_CODEC_CAP_SLICE_THREADS (1 << 13) +/** + * Codec supports changed parameters at any point. + */ +#define AV_CODEC_CAP_PARAM_CHANGE (1 << 14) +/** + * Codec supports avctx->thread_count == 0 (auto). + */ +#define AV_CODEC_CAP_AUTO_THREADS (1 << 15) +/** + * Audio encoder supports receiving a different number of samples in each call. + */ +#define AV_CODEC_CAP_VARIABLE_FRAME_SIZE (1 << 16) +/** + * Decoder is not a preferred choice for probing. + * This indicates that the decoder is not a good choice for probing. + * It could for example be an expensive to spin up hardware decoder, + * or it could simply not provide a lot of useful information about + * the stream. + * A decoder marked with this flag should only be used as last resort + * choice for probing. + */ +#define AV_CODEC_CAP_AVOID_PROBING (1 << 17) +/** + * Codec is intra only. + */ +#define AV_CODEC_CAP_INTRA_ONLY 0x40000000 +/** + * Codec is lossless. + */ +#define AV_CODEC_CAP_LOSSLESS 0x80000000 + +/** + * Codec is backed by a hardware implementation. Typically used to + * identify a non-hwaccel hardware decoder. For information about hwaccels, use + * avcodec_get_hw_config() instead. + */ +#define AV_CODEC_CAP_HARDWARE (1 << 18) + +/** + * Codec is potentially backed by a hardware implementation, but not + * necessarily. This is used instead of AV_CODEC_CAP_HARDWARE, if the + * implementation provides some sort of internal fallback. + */ +#define AV_CODEC_CAP_HYBRID (1 << 19) + +/** + * This codec takes the reordered_opaque field from input AVFrames + * and returns it in the corresponding field in AVCodecContext after + * encoding. + */ +#define AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE (1 << 20) + +/** + * Pan Scan area. + * This specifies the area which should be displayed. + * Note there may be multiple such areas for one frame. + */ +typedef struct AVPanScan { + /** + * id + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int id; + + /** + * width and height in 1/16 pel + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int width; + int height; + + /** + * position of the top left corner in 1/16 pel for up to 3 fields/frames + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int16_t position[3][2]; +} AVPanScan; + +/** + * This structure describes the bitrate properties of an encoded bitstream. It + * roughly corresponds to a subset the VBV parameters for MPEG-2 or HRD + * parameters for H.264/HEVC. + */ +typedef struct AVCPBProperties { + /** + * Maximum bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ +#if FF_API_UNSANITIZED_BITRATES + int max_bitrate; +#else + int64_t max_bitrate; +#endif + /** + * Minimum bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ +#if FF_API_UNSANITIZED_BITRATES + int min_bitrate; +#else + int64_t min_bitrate; +#endif + /** + * Average bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ +#if FF_API_UNSANITIZED_BITRATES + int avg_bitrate; +#else + int64_t avg_bitrate; +#endif + + /** + * The size of the buffer to which the ratecontrol is applied, in bits. + * Zero if unknown or unspecified. + */ + int buffer_size; + + /** + * The delay between the time the packet this structure is associated with + * is received and the time when it should be decoded, in periods of a 27MHz + * clock. + * + * UINT64_MAX when unknown or unspecified. + */ + uint64_t vbv_delay; +} AVCPBProperties; + +/** + * The decoder will keep a reference to the frame and may reuse it later. + */ +#define AV_GET_BUFFER_FLAG_REF (1 << 0) + +/** + * @defgroup lavc_packet AVPacket + * + * Types and functions for working with AVPacket. + * @{ + */ +enum AVPacketSideDataType { + /** + * An AV_PKT_DATA_PALETTE side data packet contains exactly AVPALETTE_SIZE + * bytes worth of palette. This side data signals that a new palette is + * present. + */ + AV_PKT_DATA_PALETTE, + + /** + * The AV_PKT_DATA_NEW_EXTRADATA is used to notify the codec or the format + * that the extradata buffer was changed and the receiving side should + * act upon it appropriately. The new extradata is embedded in the side + * data buffer and should be immediately used for processing the current + * frame or packet. + */ + AV_PKT_DATA_NEW_EXTRADATA, + + /** + * An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows: + * @code + * u32le param_flags + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) + * s32le channel_count + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) + * u64le channel_layout + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) + * s32le sample_rate + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) + * s32le width + * s32le height + * @endcode + */ + AV_PKT_DATA_PARAM_CHANGE, + + /** + * An AV_PKT_DATA_H263_MB_INFO side data packet contains a number of + * structures with info about macroblocks relevant to splitting the + * packet into smaller packets on macroblock edges (e.g. as for RFC 2190). + * That is, it does not necessarily contain info about all macroblocks, + * as long as the distance between macroblocks in the info is smaller + * than the target payload size. + * Each MB info structure is 12 bytes, and is laid out as follows: + * @code + * u32le bit offset from the start of the packet + * u8 current quantizer at the start of the macroblock + * u8 GOB number + * u16le macroblock address within the GOB + * u8 horizontal MV predictor + * u8 vertical MV predictor + * u8 horizontal MV predictor for block number 3 + * u8 vertical MV predictor for block number 3 + * @endcode + */ + AV_PKT_DATA_H263_MB_INFO, + + /** + * This side data should be associated with an audio stream and contains + * ReplayGain information in form of the AVReplayGain struct. + */ + AV_PKT_DATA_REPLAYGAIN, + + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the decoded video frames for + * correct presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_PKT_DATA_DISPLAYMATRIX, + + /** + * This side data should be associated with a video stream and contains + * Stereoscopic 3D information in form of the AVStereo3D struct. + */ + AV_PKT_DATA_STEREO3D, + + /** + * This side data should be associated with an audio stream and corresponds + * to enum AVAudioServiceType. + */ + AV_PKT_DATA_AUDIO_SERVICE_TYPE, + + /** + * This side data contains quality related information from the encoder. + * @code + * u32le quality factor of the compressed frame. Allowed range is between 1 (good) and FF_LAMBDA_MAX (bad). + * u8 picture type + * u8 error count + * u16 reserved + * u64le[error count] sum of squared differences between encoder in and output + * @endcode + */ + AV_PKT_DATA_QUALITY_STATS, + + /** + * This side data contains an integer value representing the stream index + * of a "fallback" track. A fallback track indicates an alternate + * track to use when the current track can not be decoded for some reason. + * e.g. no decoder available for codec. + */ + AV_PKT_DATA_FALLBACK_TRACK, + + /** + * This side data corresponds to the AVCPBProperties struct. + */ + AV_PKT_DATA_CPB_PROPERTIES, + + /** + * Recommmends skipping the specified number of samples + * @code + * u32le number of samples to skip from start of this packet + * u32le number of samples to skip from end of this packet + * u8 reason for start skip + * u8 reason for end skip (0=padding silence, 1=convergence) + * @endcode + */ + AV_PKT_DATA_SKIP_SAMPLES, + + /** + * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that + * the packet may contain "dual mono" audio specific to Japanese DTV + * and if it is true, recommends only the selected channel to be used. + * @code + * u8 selected channels (0=mail/left, 1=sub/right, 2=both) + * @endcode + */ + AV_PKT_DATA_JP_DUALMONO, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. + */ + AV_PKT_DATA_STRINGS_METADATA, + + /** + * Subtitle event position + * @code + * u32le x1 + * u32le y1 + * u32le x2 + * u32le y2 + * @endcode + */ + AV_PKT_DATA_SUBTITLE_POSITION, + + /** + * Data found in BlockAdditional element of matroska container. There is + * no end marker for the data, so it is required to rely on the side data + * size to recognize the end. 8 byte id (as found in BlockAddId) followed + * by data. + */ + AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, + + /** + * The optional first identifier line of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_IDENTIFIER, + + /** + * The optional settings (rendering instructions) that immediately + * follow the timestamp specifier of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_SETTINGS, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. This + * side data includes updated metadata which appeared in the stream. + */ + AV_PKT_DATA_METADATA_UPDATE, + + /** + * MPEGTS stream ID as uint8_t, this is required to pass the stream ID + * information from the demuxer to the corresponding muxer. + */ + AV_PKT_DATA_MPEGTS_STREAM_ID, + + /** + * Mastering display metadata (based on SMPTE-2086:2014). This metadata + * should be associated with a video stream and contains data in the form + * of the AVMasteringDisplayMetadata struct. + */ + AV_PKT_DATA_MASTERING_DISPLAY_METADATA, + + /** + * This side data should be associated with a video stream and corresponds + * to the AVSphericalMapping structure. + */ + AV_PKT_DATA_SPHERICAL, + + /** + * Content light level (based on CTA-861.3). This metadata should be + * associated with a video stream and contains data in the form of the + * AVContentLightMetadata struct. + */ + AV_PKT_DATA_CONTENT_LIGHT_LEVEL, + + /** + * ATSC A53 Part 4 Closed Captions. This metadata should be associated with + * a video stream. A53 CC bitstream is stored as uint8_t in AVPacketSideData.data. + * The number of bytes of CC data is AVPacketSideData.size. + */ + AV_PKT_DATA_A53_CC, + + /** + * This side data is encryption initialization data. + * The format is not part of ABI, use av_encryption_init_info_* methods to + * access. + */ + AV_PKT_DATA_ENCRYPTION_INIT_INFO, + + /** + * This side data contains encryption info for how to decrypt the packet. + * The format is not part of ABI, use av_encryption_info_* methods to access. + */ + AV_PKT_DATA_ENCRYPTION_INFO, + + /** + * Active Format Description data consisting of a single byte as specified + * in ETSI TS 101 154 using AVActiveFormatDescription enum. + */ + AV_PKT_DATA_AFD, + + /** + * The number of side data types. + * This is not part of the public API/ABI in the sense that it may + * change when new side data types are added. + * This must stay the last enum value. + * If its value becomes huge, some code using it + * needs to be updated as it assumes it to be smaller than other limits. + */ + AV_PKT_DATA_NB +}; + +#define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATED + +typedef struct AVPacketSideData { + uint8_t *data; + int size; + enum AVPacketSideDataType type; +} AVPacketSideData; + +/** + * This structure stores compressed data. It is typically exported by demuxers + * and then passed as input to decoders, or received as output from encoders and + * then passed to muxers. + * + * For video, it should typically contain one compressed frame. For audio it may + * contain several compressed frames. Encoders are allowed to output empty + * packets, with no compressed data, containing only side data + * (e.g. to update some stream parameters at the end of encoding). + * + * AVPacket is one of the few structs in FFmpeg, whose size is a part of public + * ABI. Thus it may be allocated on stack and no new fields can be added to it + * without libavcodec and libavformat major bump. + * + * The semantics of data ownership depends on the buf field. + * If it is set, the packet data is dynamically allocated and is + * valid indefinitely until a call to av_packet_unref() reduces the + * reference count to 0. + * + * If the buf field is not set av_packet_ref() would make a copy instead + * of increasing the reference count. + * + * The side data is always allocated with av_malloc(), copied by + * av_packet_ref() and freed by av_packet_unref(). + * + * @see av_packet_ref + * @see av_packet_unref + */ +typedef struct AVPacket { + /** + * A reference to the reference-counted buffer where the packet data is + * stored. + * May be NULL, then the packet data is not reference-counted. + */ + AVBufferRef *buf; + /** + * Presentation timestamp in AVStream->time_base units; the time at which + * the decompressed packet will be presented to the user. + * Can be AV_NOPTS_VALUE if it is not stored in the file. + * pts MUST be larger or equal to dts as presentation cannot happen before + * decompression, unless one wants to view hex dumps. Some formats misuse + * the terms dts and pts/cts to mean something different. Such timestamps + * must be converted to true pts/dts before they are stored in AVPacket. + */ + int64_t pts; + /** + * Decompression timestamp in AVStream->time_base units; the time at which + * the packet is decompressed. + * Can be AV_NOPTS_VALUE if it is not stored in the file. + */ + int64_t dts; + uint8_t *data; + int size; + int stream_index; + /** + * A combination of AV_PKT_FLAG values + */ + int flags; + /** + * Additional packet data that can be provided by the container. + * Packet can contain several types of side information. + */ + AVPacketSideData *side_data; + int side_data_elems; + + /** + * Duration of this packet in AVStream->time_base units, 0 if unknown. + * Equals next_pts - this_pts in presentation order. + */ + int64_t duration; + + int64_t pos; ///< byte position in stream, -1 if unknown + +#if FF_API_CONVERGENCE_DURATION + /** + * @deprecated Same as the duration field, but as int64_t. This was required + * for Matroska subtitles, whose duration values could overflow when the + * duration field was still an int. + */ + attribute_deprecated + int64_t convergence_duration; +#endif +} AVPacket; +#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe +#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted +/** + * Flag is used to discard packets which are required to maintain valid + * decoder state but are not required for output and should be dropped + * after decoding. + **/ +#define AV_PKT_FLAG_DISCARD 0x0004 +/** + * The packet comes from a trusted source. + * + * Otherwise-unsafe constructs such as arbitrary pointers to data + * outside the packet may be followed. + */ +#define AV_PKT_FLAG_TRUSTED 0x0008 +/** + * Flag is used to indicate packets that contain frames that can + * be discarded by the decoder. I.e. Non-reference frames. + */ +#define AV_PKT_FLAG_DISPOSABLE 0x0010 + + +enum AVSideDataParamChangeFlags { + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001, + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT = 0x0002, + AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE = 0x0004, + AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS = 0x0008, +}; +/** + * @} + */ + +struct AVCodecInternal; + +enum AVFieldOrder { + AV_FIELD_UNKNOWN, + AV_FIELD_PROGRESSIVE, + AV_FIELD_TT, //< Top coded_first, top displayed first + AV_FIELD_BB, //< Bottom coded first, bottom displayed first + AV_FIELD_TB, //< Top coded first, bottom displayed first + AV_FIELD_BT, //< Bottom coded first, top displayed first +}; + +/** + * main external API structure. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * You can use AVOptions (av_opt* / av_set/get*()) to access these fields from user + * applications. + * The name string for AVOptions options matches the associated command line + * parameter name and can be found in libavcodec/options_table.h + * The AVOption/command line parameter names differ in some cases from the C + * structure field names for historic reasons or brevity. + * sizeof(AVCodecContext) must not be used outside libav*. + */ +typedef struct AVCodecContext { + /** + * information on struct for av_log + * - set by avcodec_alloc_context3 + */ + const AVClass *av_class; + int log_level_offset; + + enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */ + const struct AVCodec *codec; + enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ + + /** + * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * This is used to work around some encoder bugs. + * A demuxer should set this to what is stored in the field used to identify the codec. + * If there are multiple such fields in a container then the demuxer should choose the one + * which maximizes the information about the used codec. + * If the codec tag field in a container is larger than 32 bits then the demuxer should + * remap the longer ID to 32 bits with a table or other structure. Alternatively a new + * extra_codec_tag + size could be added but for this a clear advantage must be demonstrated + * first. + * - encoding: Set by user, if not then the default based on codec_id will be used. + * - decoding: Set by user, will be converted to uppercase by libavcodec during init. + */ + unsigned int codec_tag; + + void *priv_data; + + /** + * Private context used for internal data. + * + * Unlike priv_data, this is not codec-specific. It is used in general + * libavcodec functions. + */ + struct AVCodecInternal *internal; + + /** + * Private data of the user, can be used to carry app specific stuff. + * - encoding: Set by user. + * - decoding: Set by user. + */ + void *opaque; + + /** + * the average bitrate + * - encoding: Set by user; unused for constant quantizer encoding. + * - decoding: Set by user, may be overwritten by libavcodec + * if this info is available in the stream + */ + int64_t bit_rate; + + /** + * number of bits the bitstream is allowed to diverge from the reference. + * the reference can be CBR (for CBR pass1) or VBR (for pass2) + * - encoding: Set by user; unused for constant quantizer encoding. + * - decoding: unused + */ + int bit_rate_tolerance; + + /** + * Global quality for codecs which cannot change it per frame. + * This should be proportional to MPEG-1/2/4 qscale. + * - encoding: Set by user. + * - decoding: unused + */ + int global_quality; + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int compression_level; +#define FF_COMPRESSION_DEFAULT -1 + + /** + * AV_CODEC_FLAG_*. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags; + + /** + * AV_CODEC_FLAG2_* + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags2; + + /** + * some codecs need / can use extradata like Huffman tables. + * MJPEG: Huffman tables + * rv10: additional flags + * MPEG-4: global headers (they can be in the bitstream or here) + * The allocated memory should be AV_INPUT_BUFFER_PADDING_SIZE bytes larger + * than extradata_size to avoid problems if it is read with the bitstream reader. + * The bytewise contents of extradata must not depend on the architecture or CPU endianness. + * Must be allocated with the av_malloc() family of functions. + * - encoding: Set/allocated/freed by libavcodec. + * - decoding: Set/allocated/freed by user. + */ + uint8_t *extradata; + int extradata_size; + + /** + * This is the fundamental unit of time (in seconds) in terms + * of which frame timestamps are represented. For fixed-fps content, + * timebase should be 1/framerate and timestamp increments should be + * identically 1. + * This often, but not always is the inverse of the frame rate or field rate + * for video. 1/time_base is not the average frame rate if the frame rate is not + * constant. + * + * Like containers, elementary streams also can store timestamps, 1/time_base + * is the unit in which these timestamps are specified. + * As example of such codec time base see ISO/IEC 14496-2:2001(E) + * vop_time_increment_resolution and fixed_vop_rate + * (fixed_vop_rate == 0 implies that it is different from the framerate) + * + * - encoding: MUST be set by user. + * - decoding: the use of this field for decoding is deprecated. + * Use framerate instead. + */ + AVRational time_base; + + /** + * For some codecs, the time base is closer to the field rate than the frame rate. + * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration + * if no telecine is used ... + * + * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. + */ + int ticks_per_frame; + + /** + * Codec delay. + * + * Encoding: Number of frames delay there will be from the encoder input to + * the decoder output. (we assume the decoder matches the spec) + * Decoding: Number of frames delay in addition to what a standard decoder + * as specified in the spec would produce. + * + * Video: + * Number of frames the decoded output will be delayed relative to the + * encoded input. + * + * Audio: + * For encoding, this field is unused (see initial_padding). + * + * For decoding, this is the number of samples the decoder needs to + * output before the decoder's output is valid. When seeking, you should + * start decoding this many samples prior to your desired seek point. + * + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int delay; + + + /* video only */ + /** + * picture width / height. + * + * @note Those fields may not match the values of the last + * AVFrame output by avcodec_decode_video2 due frame + * reordering. + * + * - encoding: MUST be set by user. + * - decoding: May be set by the user before opening the decoder if known e.g. + * from the container. Some decoders will require the dimensions + * to be set by the caller. During decoding, the decoder may + * overwrite those values as required while parsing the data. + */ + int width, height; + + /** + * Bitstream width / height, may be different from width/height e.g. when + * the decoded frame is cropped before being output or lowres is enabled. + * + * @note Those field may not match the value of the last + * AVFrame output by avcodec_receive_frame() due frame + * reordering. + * + * - encoding: unused + * - decoding: May be set by the user before opening the decoder if known + * e.g. from the container. During decoding, the decoder may + * overwrite those values as required while parsing the data. + */ + int coded_width, coded_height; + + /** + * the number of pictures in a group of pictures, or 0 for intra_only + * - encoding: Set by user. + * - decoding: unused + */ + int gop_size; + + /** + * Pixel format, see AV_PIX_FMT_xxx. + * May be set by the demuxer if known from headers. + * May be overridden by the decoder if it knows better. + * + * @note This field may not match the value of the last + * AVFrame output by avcodec_receive_frame() due frame + * reordering. + * + * - encoding: Set by user. + * - decoding: Set by user if known, overridden by libavcodec while + * parsing the data. + */ + enum AVPixelFormat pix_fmt; + + /** + * If non NULL, 'draw_horiz_band' is called by the libavcodec + * decoder to draw a horizontal band. It improves cache usage. Not + * all codecs can do that. You must check the codec capabilities + * beforehand. + * When multithreading is used, it may be called from multiple threads + * at the same time; threads might draw different parts of the same AVFrame, + * or multiple AVFrames, and there is no guarantee that slices will be drawn + * in order. + * The function is also used by hardware acceleration APIs. + * It is called at least once during frame decoding to pass + * the data needed for hardware render. + * In that mode instead of pixel data, AVFrame points to + * a structure specific to the acceleration API. The application + * reads the structure and can change some fields to indicate progress + * or mark state. + * - encoding: unused + * - decoding: Set by user. + * @param height the height of the slice + * @param y the y position of the slice + * @param type 1->top field, 2->bottom field, 3->frame + * @param offset offset into the AVFrame.data from which the slice should be read + */ + void (*draw_horiz_band)(struct AVCodecContext *s, + const AVFrame *src, int offset[AV_NUM_DATA_POINTERS], + int y, int type, int height); + + /** + * callback to negotiate the pixelFormat + * @param fmt is the list of formats which are supported by the codec, + * it is terminated by -1 as 0 is a valid format, the formats are ordered by quality. + * The first is always the native one. + * @note The callback may be called again immediately if initialization for + * the selected (hardware-accelerated) pixel format failed. + * @warning Behavior is undefined if the callback returns a value not + * in the fmt list of formats. + * @return the chosen format + * - encoding: unused + * - decoding: Set by user, if not set the native format will be chosen. + */ + enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt); + + /** + * maximum number of B-frames between non-B-frames + * Note: The output will be delayed by max_b_frames+1 relative to the input. + * - encoding: Set by user. + * - decoding: unused + */ + int max_b_frames; + + /** + * qscale factor between IP and B-frames + * If > 0 then the last P-frame quantizer will be used (q= lastp_q*factor+offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused + */ + float b_quant_factor; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int b_frame_strategy; +#endif + + /** + * qscale offset between IP and B-frames + * - encoding: Set by user. + * - decoding: unused + */ + float b_quant_offset; + + /** + * Size of the frame reordering buffer in the decoder. + * For MPEG-2 it is 1 IPB or 0 low delay IP. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int has_b_frames; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int mpeg_quant; +#endif + + /** + * qscale factor between P- and I-frames + * If > 0 then the last P-frame quantizer will be used (q = lastp_q * factor + offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused + */ + float i_quant_factor; + + /** + * qscale offset between P and I-frames + * - encoding: Set by user. + * - decoding: unused + */ + float i_quant_offset; + + /** + * luminance masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float lumi_masking; + + /** + * temporary complexity masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float temporal_cplx_masking; + + /** + * spatial complexity masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float spatial_cplx_masking; + + /** + * p block masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float p_masking; + + /** + * darkness masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float dark_masking; + + /** + * slice count + * - encoding: Set by libavcodec. + * - decoding: Set by user (or 0). + */ + int slice_count; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int prediction_method; +#define FF_PRED_LEFT 0 +#define FF_PRED_PLANE 1 +#define FF_PRED_MEDIAN 2 +#endif + + /** + * slice offsets in the frame in bytes + * - encoding: Set/allocated by libavcodec. + * - decoding: Set/allocated by user (or NULL). + */ + int *slice_offset; + + /** + * sample aspect ratio (0 if unknown) + * That is the width of a pixel divided by the height of the pixel. + * Numerator and denominator must be relatively prime and smaller than 256 for some video standards. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVRational sample_aspect_ratio; + + /** + * motion estimation comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_cmp; + /** + * subpixel motion estimation comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_sub_cmp; + /** + * macroblock comparison function (not supported yet) + * - encoding: Set by user. + * - decoding: unused + */ + int mb_cmp; + /** + * interlaced DCT comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int ildct_cmp; +#define FF_CMP_SAD 0 +#define FF_CMP_SSE 1 +#define FF_CMP_SATD 2 +#define FF_CMP_DCT 3 +#define FF_CMP_PSNR 4 +#define FF_CMP_BIT 5 +#define FF_CMP_RD 6 +#define FF_CMP_ZERO 7 +#define FF_CMP_VSAD 8 +#define FF_CMP_VSSE 9 +#define FF_CMP_NSSE 10 +#define FF_CMP_W53 11 +#define FF_CMP_W97 12 +#define FF_CMP_DCTMAX 13 +#define FF_CMP_DCT264 14 +#define FF_CMP_MEDIAN_SAD 15 +#define FF_CMP_CHROMA 256 + + /** + * ME diamond size & shape + * - encoding: Set by user. + * - decoding: unused + */ + int dia_size; + + /** + * amount of previous MV predictors (2a+1 x 2a+1 square) + * - encoding: Set by user. + * - decoding: unused + */ + int last_predictor_count; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int pre_me; +#endif + + /** + * motion estimation prepass comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_pre_cmp; + + /** + * ME prepass diamond size & shape + * - encoding: Set by user. + * - decoding: unused + */ + int pre_dia_size; + + /** + * subpel ME quality + * - encoding: Set by user. + * - decoding: unused + */ + int me_subpel_quality; + + /** + * maximum motion estimation search range in subpel units + * If 0 then no limit. + * + * - encoding: Set by user. + * - decoding: unused + */ + int me_range; + + /** + * slice flags + * - encoding: unused + * - decoding: Set by user. + */ + int slice_flags; +#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display +#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG-2 field pics) +#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) + + /** + * macroblock decision mode + * - encoding: Set by user. + * - decoding: unused + */ + int mb_decision; +#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp +#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits +#define FF_MB_DECISION_RD 2 ///< rate distortion + + /** + * custom intra quantization matrix + * Must be allocated with the av_malloc() family of functions, and will be freed in + * avcodec_free_context(). + * - encoding: Set/allocated by user, freed by libavcodec. Can be NULL. + * - decoding: Set/allocated/freed by libavcodec. + */ + uint16_t *intra_matrix; + + /** + * custom inter quantization matrix + * Must be allocated with the av_malloc() family of functions, and will be freed in + * avcodec_free_context(). + * - encoding: Set/allocated by user, freed by libavcodec. Can be NULL. + * - decoding: Set/allocated/freed by libavcodec. + */ + uint16_t *inter_matrix; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int scenechange_threshold; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int noise_reduction; +#endif + + /** + * precision of the intra DC coefficient - 8 + * - encoding: Set by user. + * - decoding: Set by libavcodec + */ + int intra_dc_precision; + + /** + * Number of macroblock rows at the top which are skipped. + * - encoding: unused + * - decoding: Set by user. + */ + int skip_top; + + /** + * Number of macroblock rows at the bottom which are skipped. + * - encoding: unused + * - decoding: Set by user. + */ + int skip_bottom; + + /** + * minimum MB Lagrange multiplier + * - encoding: Set by user. + * - decoding: unused + */ + int mb_lmin; + + /** + * maximum MB Lagrange multiplier + * - encoding: Set by user. + * - decoding: unused + */ + int mb_lmax; + +#if FF_API_PRIVATE_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int me_penalty_compensation; +#endif + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int bidir_refine; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int brd_scale; +#endif + + /** + * minimum GOP size + * - encoding: Set by user. + * - decoding: unused + */ + int keyint_min; + + /** + * number of reference frames + * - encoding: Set by user. + * - decoding: Set by lavc. + */ + int refs; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int chromaoffset; +#endif + + /** + * Note: Value depends upon the compare function used for fullpel ME. + * - encoding: Set by user. + * - decoding: unused + */ + int mv0_threshold; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int b_sensitivity; +#endif + + /** + * Chromaticity coordinates of the source primaries. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorPrimaries color_primaries; + + /** + * Color Transfer Characteristic. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + /** + * MPEG vs JPEG YUV range. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + /** + * This defines the location of chroma samples. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVChromaLocation chroma_sample_location; + + /** + * Number of slices. + * Indicates number of picture subdivisions. Used for parallelized + * decoding. + * - encoding: Set by user + * - decoding: unused + */ + int slices; + + /** Field order + * - encoding: set by libavcodec + * - decoding: Set by user. + */ + enum AVFieldOrder field_order; + + /* audio only */ + int sample_rate; ///< samples per second + int channels; ///< number of audio channels + + /** + * audio sample format + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + enum AVSampleFormat sample_fmt; ///< sample format + + /* The following data should not be initialized. */ + /** + * Number of samples per channel in an audio frame. + * + * - encoding: set by libavcodec in avcodec_open2(). Each submitted frame + * except the last must contain exactly frame_size samples per channel. + * May be 0 when the codec has AV_CODEC_CAP_VARIABLE_FRAME_SIZE set, then the + * frame size is not restricted. + * - decoding: may be set by some decoders to indicate constant frame size + */ + int frame_size; + + /** + * Frame counter, set by libavcodec. + * + * - decoding: total number of frames returned from the decoder so far. + * - encoding: total number of frames passed to the encoder so far. + * + * @note the counter is not incremented if encoding/decoding resulted in + * an error. + */ + int frame_number; + + /** + * number of bytes per packet if constant and known or 0 + * Used by some WAV based audio codecs. + */ + int block_align; + + /** + * Audio cutoff bandwidth (0 means "automatic") + * - encoding: Set by user. + * - decoding: unused + */ + int cutoff; + + /** + * Audio channel layout. + * - encoding: set by user. + * - decoding: set by user, may be overwritten by libavcodec. + */ + uint64_t channel_layout; + + /** + * Request decoder to use this channel layout if it can (0 for default) + * - encoding: unused + * - decoding: Set by user. + */ + uint64_t request_channel_layout; + + /** + * Type of service that the audio stream conveys. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + enum AVAudioServiceType audio_service_type; + + /** + * desired sample format + * - encoding: Not used. + * - decoding: Set by user. + * Decoder will decode to this format if it can. + */ + enum AVSampleFormat request_sample_fmt; + + /** + * This callback is called at the beginning of each frame to get data + * buffer(s) for it. There may be one contiguous buffer for all the data or + * there may be a buffer per each data plane or anything in between. What + * this means is, you may set however many entries in buf[] you feel necessary. + * Each buffer must be reference-counted using the AVBuffer API (see description + * of buf[] below). + * + * The following fields will be set in the frame before this callback is + * called: + * - format + * - width, height (video only) + * - sample_rate, channel_layout, nb_samples (audio only) + * Their values may differ from the corresponding values in + * AVCodecContext. This callback must use the frame values, not the codec + * context values, to calculate the required buffer size. + * + * This callback must fill the following fields in the frame: + * - data[] + * - linesize[] + * - extended_data: + * * if the data is planar audio with more than 8 channels, then this + * callback must allocate and fill extended_data to contain all pointers + * to all data planes. data[] must hold as many pointers as it can. + * extended_data must be allocated with av_malloc() and will be freed in + * av_frame_unref(). + * * otherwise extended_data must point to data + * - buf[] must contain one or more pointers to AVBufferRef structures. Each of + * the frame's data and extended_data pointers must be contained in these. That + * is, one AVBufferRef for each allocated chunk of memory, not necessarily one + * AVBufferRef per data[] entry. See: av_buffer_create(), av_buffer_alloc(), + * and av_buffer_ref(). + * - extended_buf and nb_extended_buf must be allocated with av_malloc() by + * this callback and filled with the extra buffers if there are more + * buffers than buf[] can hold. extended_buf will be freed in + * av_frame_unref(). + * + * If AV_CODEC_CAP_DR1 is not set then get_buffer2() must call + * avcodec_default_get_buffer2() instead of providing buffers allocated by + * some other means. + * + * Each data plane must be aligned to the maximum required by the target + * CPU. + * + * @see avcodec_default_get_buffer2() + * + * Video: + * + * If AV_GET_BUFFER_FLAG_REF is set in flags then the frame may be reused + * (read and/or written to if it is writable) later by libavcodec. + * + * avcodec_align_dimensions2() should be used to find the required width and + * height, as they normally need to be rounded up to the next multiple of 16. + * + * Some decoders do not support linesizes changing between frames. + * + * If frame multithreading is used and thread_safe_callbacks is set, + * this callback may be called from a different thread, but not from more + * than one at once. Does not need to be reentrant. + * + * @see avcodec_align_dimensions2() + * + * Audio: + * + * Decoders request a buffer of a particular size by setting + * AVFrame.nb_samples prior to calling get_buffer2(). The decoder may, + * however, utilize only part of the buffer by setting AVFrame.nb_samples + * to a smaller value in the output frame. + * + * As a convenience, av_samples_get_buffer_size() and + * av_samples_fill_arrays() in libavutil may be used by custom get_buffer2() + * functions to find the required data size and to fill data pointers and + * linesize. In AVFrame.linesize, only linesize[0] may be set for audio + * since all planes must be the same size. + * + * @see av_samples_get_buffer_size(), av_samples_fill_arrays() + * + * - encoding: unused + * - decoding: Set by libavcodec, user can override. + */ + int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags); + + /** + * If non-zero, the decoded audio and video frames returned from + * avcodec_decode_video2() and avcodec_decode_audio4() are reference-counted + * and are valid indefinitely. The caller must free them with + * av_frame_unref() when they are not needed anymore. + * Otherwise, the decoded frames must not be freed by the caller and are + * only valid until the next decode call. + * + * This is always automatically enabled if avcodec_receive_frame() is used. + * + * - encoding: unused + * - decoding: set by the caller before avcodec_open2(). + */ + attribute_deprecated + int refcounted_frames; + + /* - encoding parameters */ + float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0) + float qblur; ///< amount of qscale smoothing over time (0.0-1.0) + + /** + * minimum quantizer + * - encoding: Set by user. + * - decoding: unused + */ + int qmin; + + /** + * maximum quantizer + * - encoding: Set by user. + * - decoding: unused + */ + int qmax; + + /** + * maximum quantizer difference between frames + * - encoding: Set by user. + * - decoding: unused + */ + int max_qdiff; + + /** + * decoder bitstream buffer size + * - encoding: Set by user. + * - decoding: unused + */ + int rc_buffer_size; + + /** + * ratecontrol override, see RcOverride + * - encoding: Allocated/set/freed by user. + * - decoding: unused + */ + int rc_override_count; + RcOverride *rc_override; + + /** + * maximum bitrate + * - encoding: Set by user. + * - decoding: Set by user, may be overwritten by libavcodec. + */ + int64_t rc_max_rate; + + /** + * minimum bitrate + * - encoding: Set by user. + * - decoding: unused + */ + int64_t rc_min_rate; + + /** + * Ratecontrol attempt to use, at maximum, of what can be used without an underflow. + * - encoding: Set by user. + * - decoding: unused. + */ + float rc_max_available_vbv_use; + + /** + * Ratecontrol attempt to use, at least, times the amount needed to prevent a vbv overflow. + * - encoding: Set by user. + * - decoding: unused. + */ + float rc_min_vbv_overflow_use; + + /** + * Number of bits which should be loaded into the rc buffer before decoding starts. + * - encoding: Set by user. + * - decoding: unused + */ + int rc_initial_buffer_occupancy; + +#if FF_API_CODER_TYPE +#define FF_CODER_TYPE_VLC 0 +#define FF_CODER_TYPE_AC 1 +#define FF_CODER_TYPE_RAW 2 +#define FF_CODER_TYPE_RLE 3 + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int coder_type; +#endif /* FF_API_CODER_TYPE */ + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int context_model; +#endif + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int frame_skip_threshold; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int frame_skip_factor; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int frame_skip_exp; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int frame_skip_cmp; +#endif /* FF_API_PRIVATE_OPT */ + + /** + * trellis RD quantization + * - encoding: Set by user. + * - decoding: unused + */ + int trellis; + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int min_prediction_order; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int max_prediction_order; + + /** @deprecated use encoder private options instead */ + attribute_deprecated + int64_t timecode_frame_start; +#endif + +#if FF_API_RTP_CALLBACK + /** + * @deprecated unused + */ + /* The RTP callback: This function is called */ + /* every time the encoder has a packet to send. */ + /* It depends on the encoder if the data starts */ + /* with a Start Code (it should). H.263 does. */ + /* mb_nb contains the number of macroblocks */ + /* encoded in the RTP payload. */ + attribute_deprecated + void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb); +#endif + +#if FF_API_PRIVATE_OPT + /** @deprecated use encoder private options instead */ + attribute_deprecated + int rtp_payload_size; /* The size of the RTP payload: the coder will */ + /* do its best to deliver a chunk with size */ + /* below rtp_payload_size, the chunk will start */ + /* with a start code on some codecs like H.263. */ + /* This doesn't take account of any particular */ + /* headers inside the transmitted RTP payload. */ +#endif + +#if FF_API_STAT_BITS + /* statistics, used for 2-pass encoding */ + attribute_deprecated + int mv_bits; + attribute_deprecated + int header_bits; + attribute_deprecated + int i_tex_bits; + attribute_deprecated + int p_tex_bits; + attribute_deprecated + int i_count; + attribute_deprecated + int p_count; + attribute_deprecated + int skip_count; + attribute_deprecated + int misc_bits; + + /** @deprecated this field is unused */ + attribute_deprecated + int frame_bits; +#endif + + /** + * pass1 encoding statistics output buffer + * - encoding: Set by libavcodec. + * - decoding: unused + */ + char *stats_out; + + /** + * pass2 encoding statistics input buffer + * Concatenated stuff from stats_out of pass1 should be placed here. + * - encoding: Allocated/set/freed by user. + * - decoding: unused + */ + char *stats_in; + + /** + * Work around bugs in encoders which sometimes cannot be detected automatically. + * - encoding: Set by user + * - decoding: Set by user + */ + int workaround_bugs; +#define FF_BUG_AUTODETECT 1 ///< autodetection +#define FF_BUG_XVID_ILACE 4 +#define FF_BUG_UMP4 8 +#define FF_BUG_NO_PADDING 16 +#define FF_BUG_AMV 32 +#define FF_BUG_QPEL_CHROMA 64 +#define FF_BUG_STD_QPEL 128 +#define FF_BUG_QPEL_CHROMA2 256 +#define FF_BUG_DIRECT_BLOCKSIZE 512 +#define FF_BUG_EDGE 1024 +#define FF_BUG_HPEL_CHROMA 2048 +#define FF_BUG_DC_CLIP 4096 +#define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders. +#define FF_BUG_TRUNCATED 16384 +#define FF_BUG_IEDGE 32768 + + /** + * strictly follow the standard (MPEG-4, ...). + * - encoding: Set by user. + * - decoding: Set by user. + * Setting this to STRICT or higher means the encoder and decoder will + * generally do stupid things, whereas setting it to unofficial or lower + * will mean the encoder might produce output that is not supported by all + * spec-compliant decoders. Decoders don't differentiate between normal, + * unofficial and experimental (that is, they always try to decode things + * when they can) unless they are explicitly asked to behave stupidly + * (=strictly conform to the specs) + */ + int strict_std_compliance; +#define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to an older more strict version of the spec or reference software. +#define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences. +#define FF_COMPLIANCE_NORMAL 0 +#define FF_COMPLIANCE_UNOFFICIAL -1 ///< Allow unofficial extensions +#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things. + + /** + * error concealment flags + * - encoding: unused + * - decoding: Set by user. + */ + int error_concealment; +#define FF_EC_GUESS_MVS 1 +#define FF_EC_DEBLOCK 2 +#define FF_EC_FAVOR_INTER 256 + + /** + * debug + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug; +#define FF_DEBUG_PICT_INFO 1 +#define FF_DEBUG_RC 2 +#define FF_DEBUG_BITSTREAM 4 +#define FF_DEBUG_MB_TYPE 8 +#define FF_DEBUG_QP 16 +#if FF_API_DEBUG_MV +/** + * @deprecated this option does nothing + */ +#define FF_DEBUG_MV 32 +#endif +#define FF_DEBUG_DCT_COEFF 0x00000040 +#define FF_DEBUG_SKIP 0x00000080 +#define FF_DEBUG_STARTCODE 0x00000100 +#define FF_DEBUG_ER 0x00000400 +#define FF_DEBUG_MMCO 0x00000800 +#define FF_DEBUG_BUGS 0x00001000 +#if FF_API_DEBUG_MV +#define FF_DEBUG_VIS_QP 0x00002000 +#define FF_DEBUG_VIS_MB_TYPE 0x00004000 +#endif +#define FF_DEBUG_BUFFERS 0x00008000 +#define FF_DEBUG_THREADS 0x00010000 +#define FF_DEBUG_GREEN_MD 0x00800000 +#define FF_DEBUG_NOMC 0x01000000 + +#if FF_API_DEBUG_MV + /** + * debug + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 // visualize forward predicted MVs of P-frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 // visualize forward predicted MVs of B-frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 // visualize backward predicted MVs of B-frames +#endif + + /** + * Error recognition; may misdetect some more or less valid parts as errors. + * - encoding: unused + * - decoding: Set by user. + */ + int err_recognition; + +/** + * Verify checksums embedded in the bitstream (could be of either encoded or + * decoded data, depending on the codec) and print an error message on mismatch. + * If AV_EF_EXPLODE is also set, a mismatching checksum will result in the + * decoder returning an error. + */ +#define AV_EF_CRCCHECK (1<<0) +#define AV_EF_BITSTREAM (1<<1) ///< detect bitstream specification deviations +#define AV_EF_BUFFER (1<<2) ///< detect improper bitstream length +#define AV_EF_EXPLODE (1<<3) ///< abort decoding on minor error detection + +#define AV_EF_IGNORE_ERR (1<<15) ///< ignore errors and continue +#define AV_EF_CAREFUL (1<<16) ///< consider things that violate the spec, are fast to calculate and have not been seen in the wild as errors +#define AV_EF_COMPLIANT (1<<17) ///< consider all spec non compliances as errors +#define AV_EF_AGGRESSIVE (1<<18) ///< consider things that a sane encoder should not do as an error + + + /** + * opaque 64-bit number (generally a PTS) that will be reordered and + * output in AVFrame.reordered_opaque + * - encoding: Set by libavcodec to the reordered_opaque of the input + * frame corresponding to the last returned packet. Only + * supported by encoders with the + * AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE capability. + * - decoding: Set by user. + */ + int64_t reordered_opaque; + + /** + * Hardware accelerator in use + * - encoding: unused. + * - decoding: Set by libavcodec + */ + const struct AVHWAccel *hwaccel; + + /** + * Hardware accelerator context. + * For some hardware accelerators, a global context needs to be + * provided by the user. In that case, this holds display-dependent + * data FFmpeg cannot instantiate itself. Please refer to the + * FFmpeg HW accelerator documentation to know how to fill this + * is. e.g. for VA API, this is a struct vaapi_context. + * - encoding: unused + * - decoding: Set by user + */ + void *hwaccel_context; + + /** + * error + * - encoding: Set by libavcodec if flags & AV_CODEC_FLAG_PSNR. + * - decoding: unused + */ + uint64_t error[AV_NUM_DATA_POINTERS]; + + /** + * DCT algorithm, see FF_DCT_* below + * - encoding: Set by user. + * - decoding: unused + */ + int dct_algo; +#define FF_DCT_AUTO 0 +#define FF_DCT_FASTINT 1 +#define FF_DCT_INT 2 +#define FF_DCT_MMX 3 +#define FF_DCT_ALTIVEC 5 +#define FF_DCT_FAAN 6 + + /** + * IDCT algorithm, see FF_IDCT_* below. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int idct_algo; +#define FF_IDCT_AUTO 0 +#define FF_IDCT_INT 1 +#define FF_IDCT_SIMPLE 2 +#define FF_IDCT_SIMPLEMMX 3 +#define FF_IDCT_ARM 7 +#define FF_IDCT_ALTIVEC 8 +#define FF_IDCT_SIMPLEARM 10 +#define FF_IDCT_XVID 14 +#define FF_IDCT_SIMPLEARMV5TE 16 +#define FF_IDCT_SIMPLEARMV6 17 +#define FF_IDCT_FAAN 20 +#define FF_IDCT_SIMPLENEON 22 +#define FF_IDCT_NONE 24 /* Used by XvMC to extract IDCT coefficients with FF_IDCT_PERM_NONE */ +#define FF_IDCT_SIMPLEAUTO 128 + + /** + * bits per sample/pixel from the demuxer (needed for huffyuv). + * - encoding: Set by libavcodec. + * - decoding: Set by user. + */ + int bits_per_coded_sample; + + /** + * Bits per sample/pixel of internal libavcodec pixel/sample format. + * - encoding: set by user. + * - decoding: set by libavcodec. + */ + int bits_per_raw_sample; + +#if FF_API_LOWRES + /** + * low resolution decoding, 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: Set by user. + */ + int lowres; +#endif + +#if FF_API_CODED_FRAME + /** + * the picture in the bitstream + * - encoding: Set by libavcodec. + * - decoding: unused + * + * @deprecated use the quality factor packet side data instead + */ + attribute_deprecated AVFrame *coded_frame; +#endif + + /** + * thread count + * is used to decide how many independent tasks should be passed to execute() + * - encoding: Set by user. + * - decoding: Set by user. + */ + int thread_count; + + /** + * Which multithreading methods to use. + * Use of FF_THREAD_FRAME will increase decoding delay by one frame per thread, + * so clients which cannot provide future frames should not use it. + * + * - encoding: Set by user, otherwise the default is used. + * - decoding: Set by user, otherwise the default is used. + */ + int thread_type; +#define FF_THREAD_FRAME 1 ///< Decode more than one frame at once +#define FF_THREAD_SLICE 2 ///< Decode more than one part of a single frame at once + + /** + * Which multithreading methods are in use by the codec. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int active_thread_type; + + /** + * Set by the client if its custom get_buffer() callback can be called + * synchronously from another thread, which allows faster multithreaded decoding. + * draw_horiz_band() will be called from other threads regardless of this setting. + * Ignored if the default get_buffer() is used. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int thread_safe_callbacks; + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * @param count the number of things to execute + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size); + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * Also see avcodec_thread_init and e.g. the --enable-pthread configure option. + * @param c context passed also to func + * @param count the number of things to execute + * @param arg2 argument passed unchanged to func + * @param ret return values of executed functions, must have space for "count" values. May be NULL. + * @param func function that will be called count times, with jobnr from 0 to count-1. + * threadnr will be in the range 0 to c->thread_count-1 < MAX_THREADS and so that no + * two instances of func executing at the same time will have the same threadnr. + * @return always 0 currently, but code should handle a future improvement where when any call to func + * returns < 0 no further calls to func may be done and < 0 is returned. + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count); + + /** + * noise vs. sse weight for the nsse comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int nsse_weight; + + /** + * profile + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int profile; +#define FF_PROFILE_UNKNOWN -99 +#define FF_PROFILE_RESERVED -100 + +#define FF_PROFILE_AAC_MAIN 0 +#define FF_PROFILE_AAC_LOW 1 +#define FF_PROFILE_AAC_SSR 2 +#define FF_PROFILE_AAC_LTP 3 +#define FF_PROFILE_AAC_HE 4 +#define FF_PROFILE_AAC_HE_V2 28 +#define FF_PROFILE_AAC_LD 22 +#define FF_PROFILE_AAC_ELD 38 +#define FF_PROFILE_MPEG2_AAC_LOW 128 +#define FF_PROFILE_MPEG2_AAC_HE 131 + +#define FF_PROFILE_DNXHD 0 +#define FF_PROFILE_DNXHR_LB 1 +#define FF_PROFILE_DNXHR_SQ 2 +#define FF_PROFILE_DNXHR_HQ 3 +#define FF_PROFILE_DNXHR_HQX 4 +#define FF_PROFILE_DNXHR_444 5 + +#define FF_PROFILE_DTS 20 +#define FF_PROFILE_DTS_ES 30 +#define FF_PROFILE_DTS_96_24 40 +#define FF_PROFILE_DTS_HD_HRA 50 +#define FF_PROFILE_DTS_HD_MA 60 +#define FF_PROFILE_DTS_EXPRESS 70 + +#define FF_PROFILE_MPEG2_422 0 +#define FF_PROFILE_MPEG2_HIGH 1 +#define FF_PROFILE_MPEG2_SS 2 +#define FF_PROFILE_MPEG2_SNR_SCALABLE 3 +#define FF_PROFILE_MPEG2_MAIN 4 +#define FF_PROFILE_MPEG2_SIMPLE 5 + +#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag +#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag + +#define FF_PROFILE_H264_BASELINE 66 +#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) +#define FF_PROFILE_H264_MAIN 77 +#define FF_PROFILE_H264_EXTENDED 88 +#define FF_PROFILE_H264_HIGH 100 +#define FF_PROFILE_H264_HIGH_10 110 +#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_MULTIVIEW_HIGH 118 +#define FF_PROFILE_H264_HIGH_422 122 +#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_STEREO_HIGH 128 +#define FF_PROFILE_H264_HIGH_444 144 +#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244 +#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_CAVLC_444 44 + +#define FF_PROFILE_VC1_SIMPLE 0 +#define FF_PROFILE_VC1_MAIN 1 +#define FF_PROFILE_VC1_COMPLEX 2 +#define FF_PROFILE_VC1_ADVANCED 3 + +#define FF_PROFILE_MPEG4_SIMPLE 0 +#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1 +#define FF_PROFILE_MPEG4_CORE 2 +#define FF_PROFILE_MPEG4_MAIN 3 +#define FF_PROFILE_MPEG4_N_BIT 4 +#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5 +#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 +#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 +#define FF_PROFILE_MPEG4_HYBRID 8 +#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 +#define FF_PROFILE_MPEG4_CORE_SCALABLE 10 +#define FF_PROFILE_MPEG4_ADVANCED_CODING 11 +#define FF_PROFILE_MPEG4_ADVANCED_CORE 12 +#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 +#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14 +#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15 + +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 1 +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 2 +#define FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 32768 +#define FF_PROFILE_JPEG2000_DCINEMA_2K 3 +#define FF_PROFILE_JPEG2000_DCINEMA_4K 4 + +#define FF_PROFILE_VP9_0 0 +#define FF_PROFILE_VP9_1 1 +#define FF_PROFILE_VP9_2 2 +#define FF_PROFILE_VP9_3 3 + +#define FF_PROFILE_HEVC_MAIN 1 +#define FF_PROFILE_HEVC_MAIN_10 2 +#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3 +#define FF_PROFILE_HEVC_REXT 4 + +#define FF_PROFILE_AV1_MAIN 0 +#define FF_PROFILE_AV1_HIGH 1 +#define FF_PROFILE_AV1_PROFESSIONAL 2 + +#define FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT 0xc0 +#define FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT 0xc1 +#define FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT 0xc2 +#define FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS 0xc3 +#define FF_PROFILE_MJPEG_JPEG_LS 0xf7 + +#define FF_PROFILE_SBC_MSBC 1 + +#define FF_PROFILE_PRORES_PROXY 0 +#define FF_PROFILE_PRORES_LT 1 +#define FF_PROFILE_PRORES_STANDARD 2 +#define FF_PROFILE_PRORES_HQ 3 +#define FF_PROFILE_PRORES_4444 4 +#define FF_PROFILE_PRORES_XQ 5 + +#define FF_PROFILE_ARIB_PROFILE_A 0 +#define FF_PROFILE_ARIB_PROFILE_C 1 + + /** + * level + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int level; +#define FF_LEVEL_UNKNOWN -99 + + /** + * Skip loop filtering for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_loop_filter; + + /** + * Skip IDCT/dequantization for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_idct; + + /** + * Skip decoding for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_frame; + + /** + * Header containing style information for text subtitles. + * For SUBTITLE_ASS subtitle type, it should contain the whole ASS + * [Script Info] and [V4+ Styles] section, plus the [Events] line and + * the Format line following. It shouldn't include any Dialogue line. + * - encoding: Set/allocated/freed by user (before avcodec_open2()) + * - decoding: Set/allocated/freed by libavcodec (by avcodec_open2()) + */ + uint8_t *subtitle_header; + int subtitle_header_size; + +#if FF_API_VBV_DELAY + /** + * VBV delay coded in the last frame (in periods of a 27 MHz clock). + * Used for compliant TS muxing. + * - encoding: Set by libavcodec. + * - decoding: unused. + * @deprecated this value is now exported as a part of + * AV_PKT_DATA_CPB_PROPERTIES packet side data + */ + attribute_deprecated + uint64_t vbv_delay; +#endif + +#if FF_API_SIDEDATA_ONLY_PKT + /** + * Encoding only and set by default. Allow encoders to output packets + * that do not contain any encoded data, only side data. + * + * Some encoders need to output such packets, e.g. to update some stream + * parameters at the end of encoding. + * + * @deprecated this field disables the default behaviour and + * it is kept only for compatibility. + */ + attribute_deprecated + int side_data_only_packets; +#endif + + /** + * Audio only. The number of "priming" samples (padding) inserted by the + * encoder at the beginning of the audio. I.e. this number of leading + * decoded samples must be discarded by the caller to get the original audio + * without leading padding. + * + * - decoding: unused + * - encoding: Set by libavcodec. The timestamps on the output packets are + * adjusted by the encoder so that they always refer to the + * first sample of the data actually contained in the packet, + * including any added padding. E.g. if the timebase is + * 1/samplerate and the timestamp of the first input sample is + * 0, the timestamp of the first output packet will be + * -initial_padding. + */ + int initial_padding; + + /** + * - decoding: For codecs that store a framerate value in the compressed + * bitstream, the decoder may export it here. { 0, 1} when + * unknown. + * - encoding: May be used to signal the framerate of CFR content to an + * encoder. + */ + AVRational framerate; + + /** + * Nominal unaccelerated pixel format, see AV_PIX_FMT_xxx. + * - encoding: unused. + * - decoding: Set by libavcodec before calling get_format() + */ + enum AVPixelFormat sw_pix_fmt; + + /** + * Timebase in which pkt_dts/pts and AVPacket.dts/pts are. + * - encoding unused. + * - decoding set by user. + */ + AVRational pkt_timebase; + + /** + * AVCodecDescriptor + * - encoding: unused. + * - decoding: set by libavcodec. + */ + const AVCodecDescriptor *codec_descriptor; + +#if !FF_API_LOWRES + /** + * low resolution decoding, 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: Set by user. + */ + int lowres; +#endif + + /** + * Current statistics for PTS correction. + * - decoding: maintained and used by libavcodec, not intended to be used by user apps + * - encoding: unused + */ + int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far + int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far + int64_t pts_correction_last_pts; /// PTS of the last frame + int64_t pts_correction_last_dts; /// DTS of the last frame + + /** + * Character encoding of the input subtitles file. + * - decoding: set by user + * - encoding: unused + */ + char *sub_charenc; + + /** + * Subtitles character encoding mode. Formats or codecs might be adjusting + * this setting (if they are doing the conversion themselves for instance). + * - decoding: set by libavcodec + * - encoding: unused + */ + int sub_charenc_mode; +#define FF_SUB_CHARENC_MODE_DO_NOTHING -1 ///< do nothing (demuxer outputs a stream supposed to be already in UTF-8, or the codec is bitmap for instance) +#define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself +#define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv +#define FF_SUB_CHARENC_MODE_IGNORE 2 ///< neither convert the subtitles, nor check them for valid UTF-8 + + /** + * Skip processing alpha if supported by codec. + * Note that if the format uses pre-multiplied alpha (common with VP6, + * and recommended due to better video quality/compression) + * the image will look as if alpha-blended onto a black background. + * However for formats that do not use pre-multiplied alpha + * there might be serious artefacts (though e.g. libswscale currently + * assumes pre-multiplied alpha anyway). + * + * - decoding: set by user + * - encoding: unused + */ + int skip_alpha; + + /** + * Number of samples to skip after a discontinuity + * - decoding: unused + * - encoding: set by libavcodec + */ + int seek_preroll; + +#if !FF_API_DEBUG_MV + /** + * debug motion vectors + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames +#endif + + /** + * custom intra quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: unused. + */ + uint16_t *chroma_intra_matrix; + + /** + * dump format separator. + * can be ", " or "\n " or anything else + * - encoding: Set by user. + * - decoding: Set by user. + */ + uint8_t *dump_separator; + + /** + * ',' separated list of allowed decoders. + * If NULL then all are allowed + * - encoding: unused + * - decoding: set by user + */ + char *codec_whitelist; + + /** + * Properties of the stream that gets decoded + * - encoding: unused + * - decoding: set by libavcodec + */ + unsigned properties; +#define FF_CODEC_PROPERTY_LOSSLESS 0x00000001 +#define FF_CODEC_PROPERTY_CLOSED_CAPTIONS 0x00000002 + + /** + * Additional data associated with the entire coded stream. + * + * - decoding: unused + * - encoding: may be set by libavcodec after avcodec_open2(). + */ + AVPacketSideData *coded_side_data; + int nb_coded_side_data; + + /** + * A reference to the AVHWFramesContext describing the input (for encoding) + * or output (decoding) frames. The reference is set by the caller and + * afterwards owned (and freed) by libavcodec - it should never be read by + * the caller after being set. + * + * - decoding: This field should be set by the caller from the get_format() + * callback. The previous reference (if any) will always be + * unreffed by libavcodec before the get_format() call. + * + * If the default get_buffer2() is used with a hwaccel pixel + * format, then this AVHWFramesContext will be used for + * allocating the frame buffers. + * + * - encoding: For hardware encoders configured to use a hwaccel pixel + * format, this field should be set by the caller to a reference + * to the AVHWFramesContext describing input frames. + * AVHWFramesContext.format must be equal to + * AVCodecContext.pix_fmt. + * + * This field should be set before avcodec_open2() is called. + */ + AVBufferRef *hw_frames_ctx; + + /** + * Control the form of AVSubtitle.rects[N]->ass + * - decoding: set by user + * - encoding: unused + */ + int sub_text_format; +#define FF_SUB_TEXT_FMT_ASS 0 +#if FF_API_ASS_TIMING +#define FF_SUB_TEXT_FMT_ASS_WITH_TIMINGS 1 +#endif + + /** + * Audio only. The amount of padding (in samples) appended by the encoder to + * the end of the audio. I.e. this number of decoded samples must be + * discarded by the caller from the end of the stream to get the original + * audio without any trailing padding. + * + * - decoding: unused + * - encoding: unused + */ + int trailing_padding; + + /** + * The number of pixels per image to maximally accept. + * + * - decoding: set by user + * - encoding: set by user + */ + int64_t max_pixels; + + /** + * A reference to the AVHWDeviceContext describing the device which will + * be used by a hardware encoder/decoder. The reference is set by the + * caller and afterwards owned (and freed) by libavcodec. + * + * This should be used if either the codec device does not require + * hardware frames or any that are used are to be allocated internally by + * libavcodec. If the user wishes to supply any of the frames used as + * encoder input or decoder output then hw_frames_ctx should be used + * instead. When hw_frames_ctx is set in get_format() for a decoder, this + * field will be ignored while decoding the associated stream segment, but + * may again be used on a following one after another get_format() call. + * + * For both encoders and decoders this field should be set before + * avcodec_open2() is called and must not be written to thereafter. + * + * Note that some decoders may require this field to be set initially in + * order to support hw_frames_ctx at all - in that case, all frames + * contexts used must be created on the same device. + */ + AVBufferRef *hw_device_ctx; + + /** + * Bit set of AV_HWACCEL_FLAG_* flags, which affect hardware accelerated + * decoding (if active). + * - encoding: unused + * - decoding: Set by user (either before avcodec_open2(), or in the + * AVCodecContext.get_format callback) + */ + int hwaccel_flags; + + /** + * Video decoding only. Certain video codecs support cropping, meaning that + * only a sub-rectangle of the decoded frame is intended for display. This + * option controls how cropping is handled by libavcodec. + * + * When set to 1 (the default), libavcodec will apply cropping internally. + * I.e. it will modify the output frame width/height fields and offset the + * data pointers (only by as much as possible while preserving alignment, or + * by the full amount if the AV_CODEC_FLAG_UNALIGNED flag is set) so that + * the frames output by the decoder refer only to the cropped area. The + * crop_* fields of the output frames will be zero. + * + * When set to 0, the width/height fields of the output frames will be set + * to the coded dimensions and the crop_* fields will describe the cropping + * rectangle. Applying the cropping is left to the caller. + * + * @warning When hardware acceleration with opaque output frames is used, + * libavcodec is unable to apply cropping from the top/left border. + * + * @note when this option is set to zero, the width/height fields of the + * AVCodecContext and output AVFrames have different meanings. The codec + * context fields store display dimensions (with the coded dimensions in + * coded_width/height), while the frame fields store the coded dimensions + * (with the display dimensions being determined by the crop_* fields). + */ + int apply_cropping; + + /* + * Video decoding only. Sets the number of extra hardware frames which + * the decoder will allocate for use by the caller. This must be set + * before avcodec_open2() is called. + * + * Some hardware decoders require all frames that they will use for + * output to be defined in advance before decoding starts. For such + * decoders, the hardware frame pool must therefore be of a fixed size. + * The extra frames set here are on top of any number that the decoder + * needs internally in order to operate normally (for example, frames + * used as reference pictures). + */ + int extra_hw_frames; + + /** + * The percentage of damaged samples to discard a frame. + * + * - decoding: set by user + * - encoding: unused + */ + int discard_damaged_percentage; +} AVCodecContext; + +#if FF_API_CODEC_GET_SET +/** + * Accessors for some AVCodecContext fields. These used to be provided for ABI + * compatibility, and do not need to be used anymore. + */ +attribute_deprecated +AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx); +attribute_deprecated +void av_codec_set_pkt_timebase (AVCodecContext *avctx, AVRational val); + +attribute_deprecated +const AVCodecDescriptor *av_codec_get_codec_descriptor(const AVCodecContext *avctx); +attribute_deprecated +void av_codec_set_codec_descriptor(AVCodecContext *avctx, const AVCodecDescriptor *desc); + +attribute_deprecated +unsigned av_codec_get_codec_properties(const AVCodecContext *avctx); + +#if FF_API_LOWRES +attribute_deprecated +int av_codec_get_lowres(const AVCodecContext *avctx); +attribute_deprecated +void av_codec_set_lowres(AVCodecContext *avctx, int val); +#endif + +attribute_deprecated +int av_codec_get_seek_preroll(const AVCodecContext *avctx); +attribute_deprecated +void av_codec_set_seek_preroll(AVCodecContext *avctx, int val); + +attribute_deprecated +uint16_t *av_codec_get_chroma_intra_matrix(const AVCodecContext *avctx); +attribute_deprecated +void av_codec_set_chroma_intra_matrix(AVCodecContext *avctx, uint16_t *val); +#endif + +/** + * AVProfile. + */ +typedef struct AVProfile { + int profile; + const char *name; ///< short name for the profile +} AVProfile; + +enum { + /** + * The codec supports this format via the hw_device_ctx interface. + * + * When selecting this format, AVCodecContext.hw_device_ctx should + * have been set to a device of the specified type before calling + * avcodec_open2(). + */ + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX = 0x01, + /** + * The codec supports this format via the hw_frames_ctx interface. + * + * When selecting this format for a decoder, + * AVCodecContext.hw_frames_ctx should be set to a suitable frames + * context inside the get_format() callback. The frames context + * must have been created on a device of the specified type. + */ + AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX = 0x02, + /** + * The codec supports this format by some internal method. + * + * This format can be selected without any additional configuration - + * no device or frames context is required. + */ + AV_CODEC_HW_CONFIG_METHOD_INTERNAL = 0x04, + /** + * The codec supports this format by some ad-hoc method. + * + * Additional settings and/or function calls are required. See the + * codec-specific documentation for details. (Methods requiring + * this sort of configuration are deprecated and others should be + * used in preference.) + */ + AV_CODEC_HW_CONFIG_METHOD_AD_HOC = 0x08, +}; + +typedef struct AVCodecHWConfig { + /** + * A hardware pixel format which the codec can use. + */ + enum AVPixelFormat pix_fmt; + /** + * Bit set of AV_CODEC_HW_CONFIG_METHOD_* flags, describing the possible + * setup methods which can be used with this configuration. + */ + int methods; + /** + * The device type associated with the configuration. + * + * Must be set for AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX and + * AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, otherwise unused. + */ + enum AVHWDeviceType device_type; +} AVCodecHWConfig; + +typedef struct AVCodecDefault AVCodecDefault; + +struct AVSubtitle; + +/** + * AVCodec. + */ +typedef struct AVCodec { + /** + * Name of the codec implementation. + * The name is globally unique among encoders and among decoders (but an + * encoder and a decoder can share the same name). + * This is the primary way to find a codec from the user perspective. + */ + const char *name; + /** + * Descriptive name for the codec, meant to be more human readable than name. + * You should use the NULL_IF_CONFIG_SMALL() macro to define it. + */ + const char *long_name; + enum AVMediaType type; + enum AVCodecID id; + /** + * Codec capabilities. + * see AV_CODEC_CAP_* + */ + int capabilities; + const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0} + const enum AVPixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1 + const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0 + const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1 + const uint64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0 + uint8_t max_lowres; ///< maximum value for lowres supported by the decoder + const AVClass *priv_class; ///< AVClass for the private context + const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN} + + /** + * Group name of the codec implementation. + * This is a short symbolic name of the wrapper backing this codec. A + * wrapper uses some kind of external implementation for the codec, such + * as an external library, or a codec implementation provided by the OS or + * the hardware. + * If this field is NULL, this is a builtin, libavcodec native codec. + * If non-NULL, this will be the suffix in AVCodec.name in most cases + * (usually AVCodec.name will be of the form "_"). + */ + const char *wrapper_name; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + int priv_data_size; + struct AVCodec *next; + /** + * @name Frame-level threading support functions + * @{ + */ + /** + * If defined, called on thread contexts when they are created. + * If the codec allocates writable tables in init(), re-allocate them here. + * priv_data will be set to a copy of the original. + */ + int (*init_thread_copy)(AVCodecContext *); + /** + * Copy necessary context variables from a previous thread context to the current one. + * If not defined, the next thread will start automatically; otherwise, the codec + * must call ff_thread_finish_setup(). + * + * dst and src will (rarely) point to the same context, in which case memcpy should be skipped. + */ + int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src); + /** @} */ + + /** + * Private codec-specific defaults. + */ + const AVCodecDefault *defaults; + + /** + * Initialize codec static data, called from avcodec_register(). + * + * This is not intended for time consuming operations as it is + * run for every codec regardless of that codec being used. + */ + void (*init_static_data)(struct AVCodec *codec); + + int (*init)(AVCodecContext *); + int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size, + const struct AVSubtitle *sub); + /** + * Encode data to an AVPacket. + * + * @param avctx codec context + * @param avpkt output AVPacket (may contain a user-provided buffer) + * @param[in] frame AVFrame containing the raw data to be encoded + * @param[out] got_packet_ptr encoder sets to 0 or 1 to indicate that a + * non-empty packet was returned in avpkt. + * @return 0 on success, negative error code on failure + */ + int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, + int *got_packet_ptr); + int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); + int (*close)(AVCodecContext *); + /** + * Encode API with decoupled packet/frame dataflow. The API is the + * same as the avcodec_ prefixed APIs (avcodec_send_frame() etc.), except + * that: + * - never called if the codec is closed or the wrong type, + * - if AV_CODEC_CAP_DELAY is not set, drain frames are never sent, + * - only one drain frame is ever passed down, + */ + int (*send_frame)(AVCodecContext *avctx, const AVFrame *frame); + int (*receive_packet)(AVCodecContext *avctx, AVPacket *avpkt); + + /** + * Decode API with decoupled packet/frame dataflow. This function is called + * to get one output frame. It should call ff_decode_get_packet() to obtain + * input data. + */ + int (*receive_frame)(AVCodecContext *avctx, AVFrame *frame); + /** + * Flush buffers. + * Will be called when seeking + */ + void (*flush)(AVCodecContext *); + /** + * Internal codec capabilities. + * See FF_CODEC_CAP_* in internal.h + */ + int caps_internal; + + /** + * Decoding only, a comma-separated list of bitstream filters to apply to + * packets before decoding. + */ + const char *bsfs; + + /** + * Array of pointers to hardware configurations supported by the codec, + * or NULL if no hardware supported. The array is terminated by a NULL + * pointer. + * + * The user can only access this field via avcodec_get_hw_config(). + */ + const struct AVCodecHWConfigInternal **hw_configs; +} AVCodec; + +#if FF_API_CODEC_GET_SET +attribute_deprecated +int av_codec_get_max_lowres(const AVCodec *codec); +#endif + +struct MpegEncContext; + +/** + * Retrieve supported hardware configurations for a codec. + * + * Values of index from zero to some maximum return the indexed configuration + * descriptor; all other values return NULL. If the codec does not support + * any hardware configurations then it will always return NULL. + */ +const AVCodecHWConfig *avcodec_get_hw_config(const AVCodec *codec, int index); + +/** + * @defgroup lavc_hwaccel AVHWAccel + * + * @note Nothing in this structure should be accessed by the user. At some + * point in future it will not be externally visible at all. + * + * @{ + */ +typedef struct AVHWAccel { + /** + * Name of the hardware accelerated codec. + * The name is globally unique among encoders and among decoders (but an + * encoder and a decoder can share the same name). + */ + const char *name; + + /** + * Type of codec implemented by the hardware accelerator. + * + * See AVMEDIA_TYPE_xxx + */ + enum AVMediaType type; + + /** + * Codec implemented by the hardware accelerator. + * + * See AV_CODEC_ID_xxx + */ + enum AVCodecID id; + + /** + * Supported pixel format. + * + * Only hardware accelerated formats are supported here. + */ + enum AVPixelFormat pix_fmt; + + /** + * Hardware accelerated codec capabilities. + * see AV_HWACCEL_CODEC_CAP_* + */ + int capabilities; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + + /** + * Allocate a custom buffer + */ + int (*alloc_frame)(AVCodecContext *avctx, AVFrame *frame); + + /** + * Called at the beginning of each frame or field picture. + * + * Meaningful frame information (codec specific) is guaranteed to + * be parsed at this point. This function is mandatory. + * + * Note that buf can be NULL along with buf_size set to 0. + * Otherwise, this means the whole frame is available at this point. + * + * @param avctx the codec context + * @param buf the frame data buffer base + * @param buf_size the size of the frame in bytes + * @return zero if successful, a negative value otherwise + */ + int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); + + /** + * Callback for parameter data (SPS/PPS/VPS etc). + * + * Useful for hardware decoders which keep persistent state about the + * video parameters, and need to receive any changes to update that state. + * + * @param avctx the codec context + * @param type the nal unit type + * @param buf the nal unit data buffer + * @param buf_size the size of the nal unit in bytes + * @return zero if successful, a negative value otherwise + */ + int (*decode_params)(AVCodecContext *avctx, int type, const uint8_t *buf, uint32_t buf_size); + + /** + * Callback for each slice. + * + * Meaningful slice information (codec specific) is guaranteed to + * be parsed at this point. This function is mandatory. + * The only exception is XvMC, that works on MB level. + * + * @param avctx the codec context + * @param buf the slice data buffer base + * @param buf_size the size of the slice in bytes + * @return zero if successful, a negative value otherwise + */ + int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); + + /** + * Called at the end of each frame or field picture. + * + * The whole picture is parsed at this point and can now be sent + * to the hardware accelerator. This function is mandatory. + * + * @param avctx the codec context + * @return zero if successful, a negative value otherwise + */ + int (*end_frame)(AVCodecContext *avctx); + + /** + * Size of per-frame hardware accelerator private data. + * + * Private data is allocated with av_mallocz() before + * AVCodecContext.get_buffer() and deallocated after + * AVCodecContext.release_buffer(). + */ + int frame_priv_data_size; + + /** + * Called for every Macroblock in a slice. + * + * XvMC uses it to replace the ff_mpv_reconstruct_mb(). + * Instead of decoding to raw picture, MB parameters are + * stored in an array provided by the video driver. + * + * @param s the mpeg context + */ + void (*decode_mb)(struct MpegEncContext *s); + + /** + * Initialize the hwaccel private data. + * + * This will be called from ff_get_format(), after hwaccel and + * hwaccel_context are set and the hwaccel private data in AVCodecInternal + * is allocated. + */ + int (*init)(AVCodecContext *avctx); + + /** + * Uninitialize the hwaccel private data. + * + * This will be called from get_format() or avcodec_close(), after hwaccel + * and hwaccel_context are already uninitialized. + */ + int (*uninit)(AVCodecContext *avctx); + + /** + * Size of the private data to allocate in + * AVCodecInternal.hwaccel_priv_data. + */ + int priv_data_size; + + /** + * Internal hwaccel capabilities. + */ + int caps_internal; + + /** + * Fill the given hw_frames context with current codec parameters. Called + * from get_format. Refer to avcodec_get_hw_frames_parameters() for + * details. + * + * This CAN be called before AVHWAccel.init is called, and you must assume + * that avctx->hwaccel_priv_data is invalid. + */ + int (*frame_params)(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx); +} AVHWAccel; + +/** + * HWAccel is experimental and is thus avoided in favor of non experimental + * codecs + */ +#define AV_HWACCEL_CODEC_CAP_EXPERIMENTAL 0x0200 + +/** + * Hardware acceleration should be used for decoding even if the codec level + * used is unknown or higher than the maximum supported level reported by the + * hardware driver. + * + * It's generally a good idea to pass this flag unless you have a specific + * reason not to, as hardware tends to under-report supported levels. + */ +#define AV_HWACCEL_FLAG_IGNORE_LEVEL (1 << 0) + +/** + * Hardware acceleration can output YUV pixel formats with a different chroma + * sampling than 4:2:0 and/or other than 8 bits per component. + */ +#define AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH (1 << 1) + +/** + * Hardware acceleration should still be attempted for decoding when the + * codec profile does not match the reported capabilities of the hardware. + * + * For example, this can be used to try to decode baseline profile H.264 + * streams in hardware - it will often succeed, because many streams marked + * as baseline profile actually conform to constrained baseline profile. + * + * @warning If the stream is actually not supported then the behaviour is + * undefined, and may include returning entirely incorrect output + * while indicating success. + */ +#define AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH (1 << 2) + +/** + * @} + */ + +#if FF_API_AVPICTURE +/** + * @defgroup lavc_picture AVPicture + * + * Functions for working with AVPicture + * @{ + */ + +/** + * Picture data structure. + * + * Up to four components can be stored into it, the last component is + * alpha. + * @deprecated use AVFrame or imgutils functions instead + */ +typedef struct AVPicture { + attribute_deprecated + uint8_t *data[AV_NUM_DATA_POINTERS]; ///< pointers to the image data planes + attribute_deprecated + int linesize[AV_NUM_DATA_POINTERS]; ///< number of bytes per line +} AVPicture; + +/** + * @} + */ +#endif + +enum AVSubtitleType { + SUBTITLE_NONE, + + SUBTITLE_BITMAP, ///< A bitmap, pict will be set + + /** + * Plain text, the text field must be set by the decoder and is + * authoritative. ass and pict fields may contain approximations. + */ + SUBTITLE_TEXT, + + /** + * Formatted text, the ass field must be set by the decoder and is + * authoritative. pict and text fields may contain approximations. + */ + SUBTITLE_ASS, +}; + +#define AV_SUBTITLE_FLAG_FORCED 0x00000001 + +typedef struct AVSubtitleRect { + int x; ///< top left corner of pict, undefined when pict is not set + int y; ///< top left corner of pict, undefined when pict is not set + int w; ///< width of pict, undefined when pict is not set + int h; ///< height of pict, undefined when pict is not set + int nb_colors; ///< number of colors in pict, undefined when pict is not set + +#if FF_API_AVPICTURE + /** + * @deprecated unused + */ + attribute_deprecated + AVPicture pict; +#endif + /** + * data+linesize for the bitmap of this subtitle. + * Can be set for text/ass as well once they are rendered. + */ + uint8_t *data[4]; + int linesize[4]; + + enum AVSubtitleType type; + + char *text; ///< 0 terminated plain UTF-8 text + + /** + * 0 terminated ASS/SSA compatible event line. + * The presentation of this is unaffected by the other values in this + * struct. + */ + char *ass; + + int flags; +} AVSubtitleRect; + +typedef struct AVSubtitle { + uint16_t format; /* 0 = graphics */ + uint32_t start_display_time; /* relative to packet pts, in ms */ + uint32_t end_display_time; /* relative to packet pts, in ms */ + unsigned num_rects; + AVSubtitleRect **rects; + int64_t pts; ///< Same as packet pts, in AV_TIME_BASE +} AVSubtitle; + +/** + * This struct describes the properties of an encoded stream. + * + * sizeof(AVCodecParameters) is not a part of the public ABI, this struct must + * be allocated with avcodec_parameters_alloc() and freed with + * avcodec_parameters_free(). + */ +typedef struct AVCodecParameters { + /** + * General type of the encoded data. + */ + enum AVMediaType codec_type; + /** + * Specific type of the encoded data (the codec used). + */ + enum AVCodecID codec_id; + /** + * Additional information about the codec (corresponds to the AVI FOURCC). + */ + uint32_t codec_tag; + + /** + * Extra binary data needed for initializing the decoder, codec-dependent. + * + * Must be allocated with av_malloc() and will be freed by + * avcodec_parameters_free(). The allocated size of extradata must be at + * least extradata_size + AV_INPUT_BUFFER_PADDING_SIZE, with the padding + * bytes zeroed. + */ + uint8_t *extradata; + /** + * Size of the extradata content in bytes. + */ + int extradata_size; + + /** + * - video: the pixel format, the value corresponds to enum AVPixelFormat. + * - audio: the sample format, the value corresponds to enum AVSampleFormat. + */ + int format; + + /** + * The average bitrate of the encoded data (in bits per second). + */ + int64_t bit_rate; + + /** + * The number of bits per sample in the codedwords. + * + * This is basically the bitrate per sample. It is mandatory for a bunch of + * formats to actually decode them. It's the number of bits for one sample in + * the actual coded bitstream. + * + * This could be for example 4 for ADPCM + * For PCM formats this matches bits_per_raw_sample + * Can be 0 + */ + int bits_per_coded_sample; + + /** + * This is the number of valid bits in each output sample. If the + * sample format has more bits, the least significant bits are additional + * padding bits, which are always 0. Use right shifts to reduce the sample + * to its actual size. For example, audio formats with 24 bit samples will + * have bits_per_raw_sample set to 24, and format set to AV_SAMPLE_FMT_S32. + * To get the original sample use "(int32_t)sample >> 8"." + * + * For ADPCM this might be 12 or 16 or similar + * Can be 0 + */ + int bits_per_raw_sample; + + /** + * Codec-specific bitstream restrictions that the stream conforms to. + */ + int profile; + int level; + + /** + * Video only. The dimensions of the video frame in pixels. + */ + int width; + int height; + + /** + * Video only. The aspect ratio (width / height) which a single pixel + * should have when displayed. + * + * When the aspect ratio is unknown / undefined, the numerator should be + * set to 0 (the denominator may have any value). + */ + AVRational sample_aspect_ratio; + + /** + * Video only. The order of the fields in interlaced video. + */ + enum AVFieldOrder field_order; + + /** + * Video only. Additional colorspace characteristics. + */ + enum AVColorRange color_range; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace color_space; + enum AVChromaLocation chroma_location; + + /** + * Video only. Number of delayed frames. + */ + int video_delay; + + /** + * Audio only. The channel layout bitmask. May be 0 if the channel layout is + * unknown or unspecified, otherwise the number of bits set must be equal to + * the channels field. + */ + uint64_t channel_layout; + /** + * Audio only. The number of audio channels. + */ + int channels; + /** + * Audio only. The number of audio samples per second. + */ + int sample_rate; + /** + * Audio only. The number of bytes per coded audio frame, required by some + * formats. + * + * Corresponds to nBlockAlign in WAVEFORMATEX. + */ + int block_align; + /** + * Audio only. Audio frame size, if known. Required by some formats to be static. + */ + int frame_size; + + /** + * Audio only. The amount of padding (in samples) inserted by the encoder at + * the beginning of the audio. I.e. this number of leading decoded samples + * must be discarded by the caller to get the original audio without leading + * padding. + */ + int initial_padding; + /** + * Audio only. The amount of padding (in samples) appended by the encoder to + * the end of the audio. I.e. this number of decoded samples must be + * discarded by the caller from the end of the stream to get the original + * audio without any trailing padding. + */ + int trailing_padding; + /** + * Audio only. Number of samples to skip after a discontinuity. + */ + int seek_preroll; +} AVCodecParameters; + +/** + * Iterate over all registered codecs. + * + * @param opaque a pointer where libavcodec will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered codec or NULL when the iteration is + * finished + */ +const AVCodec *av_codec_iterate(void **opaque); + +#if FF_API_NEXT +/** + * If c is NULL, returns the first registered codec, + * if c is non-NULL, returns the next registered codec after c, + * or NULL if c is the last one. + */ +attribute_deprecated +AVCodec *av_codec_next(const AVCodec *c); +#endif + +/** + * Return the LIBAVCODEC_VERSION_INT constant. + */ +unsigned avcodec_version(void); + +/** + * Return the libavcodec build-time configuration. + */ +const char *avcodec_configuration(void); + +/** + * Return the libavcodec license. + */ +const char *avcodec_license(void); + +#if FF_API_NEXT +/** + * Register the codec codec and initialize libavcodec. + * + * @warning either this function or avcodec_register_all() must be called + * before any other libavcodec functions. + * + * @see avcodec_register_all() + */ +attribute_deprecated +void avcodec_register(AVCodec *codec); + +/** + * Register all the codecs, parsers and bitstream filters which were enabled at + * configuration time. If you do not call this function you can select exactly + * which formats you want to support, by using the individual registration + * functions. + * + * @see avcodec_register + * @see av_register_codec_parser + * @see av_register_bitstream_filter + */ +attribute_deprecated +void avcodec_register_all(void); +#endif + +/** + * Allocate an AVCodecContext and set its fields to default values. The + * resulting struct should be freed with avcodec_free_context(). + * + * @param codec if non-NULL, allocate private data and initialize defaults + * for the given codec. It is illegal to then call avcodec_open2() + * with a different codec. + * If NULL, then the codec-specific defaults won't be initialized, + * which may result in suboptimal default settings (this is + * important mainly for encoders, e.g. libx264). + * + * @return An AVCodecContext filled with default values or NULL on failure. + */ +AVCodecContext *avcodec_alloc_context3(const AVCodec *codec); + +/** + * Free the codec context and everything associated with it and write NULL to + * the provided pointer. + */ +void avcodec_free_context(AVCodecContext **avctx); + +#if FF_API_GET_CONTEXT_DEFAULTS +/** + * @deprecated This function should not be used, as closing and opening a codec + * context multiple time is not supported. A new codec context should be + * allocated for each new use. + */ +int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec); +#endif + +/** + * Get the AVClass for AVCodecContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_class(void); + +#if FF_API_COPY_CONTEXT +/** + * Get the AVClass for AVFrame. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_frame_class(void); + +/** + * Get the AVClass for AVSubtitleRect. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_subtitle_rect_class(void); + +/** + * Copy the settings of the source AVCodecContext into the destination + * AVCodecContext. The resulting destination codec context will be + * unopened, i.e. you are required to call avcodec_open2() before you + * can use this AVCodecContext to decode/encode video/audio data. + * + * @param dest target codec context, should be initialized with + * avcodec_alloc_context3(NULL), but otherwise uninitialized + * @param src source codec context + * @return AVERROR() on error (e.g. memory allocation error), 0 on success + * + * @deprecated The semantics of this function are ill-defined and it should not + * be used. If you need to transfer the stream parameters from one codec context + * to another, use an intermediate AVCodecParameters instance and the + * avcodec_parameters_from_context() / avcodec_parameters_to_context() + * functions. + */ +attribute_deprecated +int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src); +#endif + +/** + * Allocate a new AVCodecParameters and set its fields to default values + * (unknown/invalid/0). The returned struct must be freed with + * avcodec_parameters_free(). + */ +AVCodecParameters *avcodec_parameters_alloc(void); + +/** + * Free an AVCodecParameters instance and everything associated with it and + * write NULL to the supplied pointer. + */ +void avcodec_parameters_free(AVCodecParameters **par); + +/** + * Copy the contents of src to dst. Any allocated fields in dst are freed and + * replaced with newly allocated duplicates of the corresponding fields in src. + * + * @return >= 0 on success, a negative AVERROR code on failure. + */ +int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src); + +/** + * Fill the parameters struct based on the values from the supplied codec + * context. Any allocated fields in par are freed and replaced with duplicates + * of the corresponding fields in codec. + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int avcodec_parameters_from_context(AVCodecParameters *par, + const AVCodecContext *codec); + +/** + * Fill the codec context based on the values from the supplied codec + * parameters. Any allocated fields in codec that have a corresponding field in + * par are freed and replaced with duplicates of the corresponding field in par. + * Fields in codec that do not have a counterpart in par are not touched. + * + * @return >= 0 on success, a negative AVERROR code on failure. + */ +int avcodec_parameters_to_context(AVCodecContext *codec, + const AVCodecParameters *par); + +/** + * Initialize the AVCodecContext to use the given AVCodec. Prior to using this + * function the context has to be allocated with avcodec_alloc_context3(). + * + * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), + * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for + * retrieving a codec. + * + * @warning This function is not thread safe! + * + * @note Always call this function before using decoding routines (such as + * @ref avcodec_receive_frame()). + * + * @code + * avcodec_register_all(); + * av_dict_set(&opts, "b", "2.5M", 0); + * codec = avcodec_find_decoder(AV_CODEC_ID_H264); + * if (!codec) + * exit(1); + * + * context = avcodec_alloc_context3(codec); + * + * if (avcodec_open2(context, codec, opts) < 0) + * exit(1); + * @endcode + * + * @param avctx The context to initialize. + * @param codec The codec to open this context for. If a non-NULL codec has been + * previously passed to avcodec_alloc_context3() or + * for this context, then this parameter MUST be either NULL or + * equal to the previously passed codec. + * @param options A dictionary filled with AVCodecContext and codec-private options. + * On return this object will be filled with options that were not found. + * + * @return zero on success, a negative value on error + * @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(), + * av_dict_set(), av_opt_find(). + */ +int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); + +/** + * Close a given AVCodecContext and free all the data associated with it + * (but not the AVCodecContext itself). + * + * Calling this function on an AVCodecContext that hasn't been opened will free + * the codec-specific data allocated in avcodec_alloc_context3() with a non-NULL + * codec. Subsequent calls will do nothing. + * + * @note Do not use this function. Use avcodec_free_context() to destroy a + * codec context (either open or closed). Opening and closing a codec context + * multiple times is not supported anymore -- use multiple codec contexts + * instead. + */ +int avcodec_close(AVCodecContext *avctx); + +/** + * Free all allocated data in the given subtitle struct. + * + * @param sub AVSubtitle to free. + */ +void avsubtitle_free(AVSubtitle *sub); + +/** + * @} + */ + +/** + * @addtogroup lavc_packet + * @{ + */ + +/** + * Allocate an AVPacket and set its fields to default values. The resulting + * struct must be freed using av_packet_free(). + * + * @return An AVPacket filled with default values or NULL on failure. + * + * @note this only allocates the AVPacket itself, not the data buffers. Those + * must be allocated through other means such as av_new_packet. + * + * @see av_new_packet + */ +AVPacket *av_packet_alloc(void); + +/** + * Create a new packet that references the same data as src. + * + * This is a shortcut for av_packet_alloc()+av_packet_ref(). + * + * @return newly created AVPacket on success, NULL on error. + * + * @see av_packet_alloc + * @see av_packet_ref + */ +AVPacket *av_packet_clone(const AVPacket *src); + +/** + * Free the packet, if the packet is reference counted, it will be + * unreferenced first. + * + * @param pkt packet to be freed. The pointer will be set to NULL. + * @note passing NULL is a no-op. + */ +void av_packet_free(AVPacket **pkt); + +/** + * Initialize optional fields of a packet with default values. + * + * Note, this does not touch the data and size members, which have to be + * initialized separately. + * + * @param pkt packet + */ +void av_init_packet(AVPacket *pkt); + +/** + * Allocate the payload of a packet and initialize its fields with + * default values. + * + * @param pkt packet + * @param size wanted payload size + * @return 0 if OK, AVERROR_xxx otherwise + */ +int av_new_packet(AVPacket *pkt, int size); + +/** + * Reduce packet size, correctly zeroing padding + * + * @param pkt packet + * @param size new size + */ +void av_shrink_packet(AVPacket *pkt, int size); + +/** + * Increase packet size, correctly zeroing padding + * + * @param pkt packet + * @param grow_by number of bytes by which to increase the size of the packet + */ +int av_grow_packet(AVPacket *pkt, int grow_by); + +/** + * Initialize a reference-counted packet from av_malloc()ed data. + * + * @param pkt packet to be initialized. This function will set the data, size, + * and buf fields, all others are left untouched. + * @param data Data allocated by av_malloc() to be used as packet data. If this + * function returns successfully, the data is owned by the underlying AVBuffer. + * The caller may not access the data through other means. + * @param size size of data in bytes, without the padding. I.e. the full buffer + * size is assumed to be size + AV_INPUT_BUFFER_PADDING_SIZE. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size); + +#if FF_API_AVPACKET_OLD_API +/** + * @warning This is a hack - the packet memory allocation stuff is broken. The + * packet is allocated if it was not really allocated. + * + * @deprecated Use av_packet_ref or av_packet_make_refcounted + */ +attribute_deprecated +int av_dup_packet(AVPacket *pkt); +/** + * Copy packet, including contents + * + * @return 0 on success, negative AVERROR on fail + * + * @deprecated Use av_packet_ref + */ +attribute_deprecated +int av_copy_packet(AVPacket *dst, const AVPacket *src); + +/** + * Copy packet side data + * + * @return 0 on success, negative AVERROR on fail + * + * @deprecated Use av_packet_copy_props + */ +attribute_deprecated +int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src); + +/** + * Free a packet. + * + * @deprecated Use av_packet_unref + * + * @param pkt packet to free + */ +attribute_deprecated +void av_free_packet(AVPacket *pkt); +#endif +/** + * Allocate new information of a packet. + * + * @param pkt packet + * @param type side information type + * @param size side information size + * @return pointer to fresh allocated data or NULL otherwise + */ +uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size); + +/** + * Wrap an existing array as a packet side data. + * + * @param pkt packet + * @param type side information type + * @param data the side data array. It must be allocated with the av_malloc() + * family of functions. The ownership of the data is transferred to + * pkt. + * @param size side information size + * @return a non-negative number on success, a negative AVERROR code on + * failure. On failure, the packet is unchanged and the data remains + * owned by the caller. + */ +int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + uint8_t *data, size_t size); + +/** + * Shrink the already allocated side data buffer + * + * @param pkt packet + * @param type side information type + * @param size new side information size + * @return 0 on success, < 0 on failure + */ +int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size); + +/** + * Get side information from packet. + * + * @param pkt packet + * @param type desired side information type + * @param size pointer for side information size to store (optional) + * @return pointer to data if present or NULL otherwise + */ +uint8_t* av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type, + int *size); + +#if FF_API_MERGE_SD_API +attribute_deprecated +int av_packet_merge_side_data(AVPacket *pkt); + +attribute_deprecated +int av_packet_split_side_data(AVPacket *pkt); +#endif + +const char *av_packet_side_data_name(enum AVPacketSideDataType type); + +/** + * Pack a dictionary for use in side_data. + * + * @param dict The dictionary to pack. + * @param size pointer to store the size of the returned data + * @return pointer to data if successful, NULL otherwise + */ +uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size); +/** + * Unpack a dictionary from side_data. + * + * @param data data from side_data + * @param size size of the data + * @param dict the metadata storage dictionary + * @return 0 on success, < 0 on failure + */ +int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict); + + +/** + * Convenience function to free all the side data stored. + * All the other fields stay untouched. + * + * @param pkt packet + */ +void av_packet_free_side_data(AVPacket *pkt); + +/** + * Setup a new reference to the data described by a given packet + * + * If src is reference-counted, setup dst as a new reference to the + * buffer in src. Otherwise allocate a new buffer in dst and copy the + * data from src into it. + * + * All the other fields are copied from src. + * + * @see av_packet_unref + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_packet_ref(AVPacket *dst, const AVPacket *src); + +/** + * Wipe the packet. + * + * Unreference the buffer referenced by the packet and reset the + * remaining packet fields to their default values. + * + * @param pkt The packet to be unreferenced. + */ +void av_packet_unref(AVPacket *pkt); + +/** + * Move every field in src to dst and reset src. + * + * @see av_packet_unref + * + * @param src Source packet, will be reset + * @param dst Destination packet + */ +void av_packet_move_ref(AVPacket *dst, AVPacket *src); + +/** + * Copy only "properties" fields from src to dst. + * + * Properties for the purpose of this function are all the fields + * beside those related to the packet data (buf, data, size) + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success AVERROR on failure. + */ +int av_packet_copy_props(AVPacket *dst, const AVPacket *src); + +/** + * Ensure the data described by a given packet is reference counted. + * + * @note This function does not ensure that the reference will be writable. + * Use av_packet_make_writable instead for that purpose. + * + * @see av_packet_ref + * @see av_packet_make_writable + * + * @param pkt packet whose data should be made reference counted. + * + * @return 0 on success, a negative AVERROR on error. On failure, the + * packet is unchanged. + */ +int av_packet_make_refcounted(AVPacket *pkt); + +/** + * Create a writable reference for the data described by a given packet, + * avoiding data copy if possible. + * + * @param pkt Packet whose data should be made writable. + * + * @return 0 on success, a negative AVERROR on failure. On failure, the + * packet is unchanged. + */ +int av_packet_make_writable(AVPacket *pkt); + +/** + * Convert valid timing fields (timestamps / durations) in a packet from one + * timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be + * ignored. + * + * @param pkt packet on which the conversion will be performed + * @param tb_src source timebase, in which the timing fields in pkt are + * expressed + * @param tb_dst destination timebase, to which the timing fields will be + * converted + */ +void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst); + +/** + * @} + */ + +/** + * @addtogroup lavc_decoding + * @{ + */ + +/** + * Find a registered decoder with a matching codec ID. + * + * @param id AVCodecID of the requested decoder + * @return A decoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_decoder(enum AVCodecID id); + +/** + * Find a registered decoder with the specified name. + * + * @param name name of the requested decoder + * @return A decoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_decoder_by_name(const char *name); + +/** + * The default callback for AVCodecContext.get_buffer2(). It is made public so + * it can be called by custom get_buffer2() implementations for decoders without + * AV_CODEC_CAP_DR1 set. + */ +int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags); + +/** + * Modify width and height values so that they will result in a memory + * buffer that is acceptable for the codec if you do not use any horizontal + * padding. + * + * May only be used if a codec with AV_CODEC_CAP_DR1 has been opened. + */ +void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height); + +/** + * Modify width and height values so that they will result in a memory + * buffer that is acceptable for the codec if you also ensure that all + * line sizes are a multiple of the respective linesize_align[i]. + * + * May only be used if a codec with AV_CODEC_CAP_DR1 has been opened. + */ +void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, + int linesize_align[AV_NUM_DATA_POINTERS]); + +/** + * Converts AVChromaLocation to swscale x/y chroma position. + * + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position + */ +int avcodec_enum_to_chroma_pos(int *xpos, int *ypos, enum AVChromaLocation pos); + +/** + * Converts swscale x/y chroma position to AVChromaLocation. + * + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position + */ +enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos); + +/** + * Decode the audio frame of size avpkt->size from avpkt->data into frame. + * + * Some decoders may support multiple frames in a single AVPacket. Such + * decoders would then just decode the first frame and the return value would be + * less than the packet size. In this case, avcodec_decode_audio4 has to be + * called again with an AVPacket containing the remaining data in order to + * decode the second frame, etc... Even if no frames are returned, the packet + * needs to be fed to the decoder with remaining data until it is completely + * consumed or an error occurs. + * + * Some decoders (those marked with AV_CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning samples. It is safe to flush even those decoders that are not + * marked with AV_CODEC_CAP_DELAY, then no samples will be returned. + * + * @warning The input buffer, avpkt->data must be AV_INPUT_BUFFER_PADDING_SIZE + * larger than the actual read bytes because some optimized bitstream + * readers read 32 or 64 bits at once and could read over the end. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx the codec context + * @param[out] frame The AVFrame in which to store decoded audio samples. + * The decoder will allocate a buffer for the decoded frame by + * calling the AVCodecContext.get_buffer2() callback. + * When AVCodecContext.refcounted_frames is set to 1, the frame is + * reference counted and the returned reference belongs to the + * caller. The caller must release the frame using av_frame_unref() + * when the frame is no longer needed. The caller may safely write + * to the frame if av_frame_is_writable() returns 1. + * When AVCodecContext.refcounted_frames is set to 0, the returned + * reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. + * @param[out] got_frame_ptr Zero if no frame could be decoded, otherwise it is + * non-zero. Note that this field being set to zero + * does not mean that an error has occurred. For + * decoders with AV_CODEC_CAP_DELAY set, no given decode + * call is guaranteed to produce a frame. + * @param[in] avpkt The input AVPacket containing the input buffer. + * At least avpkt->data and avpkt->size should be set. Some + * decoders might also require additional fields to be set. + * @return A negative error code is returned if an error occurred during + * decoding, otherwise the number of bytes consumed from the input + * AVPacket is returned. + * +* @deprecated Use avcodec_send_packet() and avcodec_receive_frame(). + */ +attribute_deprecated +int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, const AVPacket *avpkt); + +/** + * Decode the video frame of size avpkt->size from avpkt->data into picture. + * Some decoders may support multiple frames in a single AVPacket, such + * decoders would then just decode the first frame. + * + * @warning The input buffer must be AV_INPUT_BUFFER_PADDING_SIZE larger than + * the actual read bytes because some optimized bitstream readers read 32 or 64 + * bits at once and could read over the end. + * + * @warning The end of the input buffer buf should be set to 0 to ensure that + * no overreading happens for damaged MPEG streams. + * + * @note Codecs which have the AV_CODEC_CAP_DELAY capability set have a delay + * between input and output, these need to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to return the remaining frames. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx the codec context + * @param[out] picture The AVFrame in which the decoded video frame will be stored. + * Use av_frame_alloc() to get an AVFrame. The codec will + * allocate memory for the actual bitmap by calling the + * AVCodecContext.get_buffer2() callback. + * When AVCodecContext.refcounted_frames is set to 1, the frame is + * reference counted and the returned reference belongs to the + * caller. The caller must release the frame using av_frame_unref() + * when the frame is no longer needed. The caller may safely write + * to the frame if av_frame_is_writable() returns 1. + * When AVCodecContext.refcounted_frames is set to 0, the returned + * reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. + * + * @param[in] avpkt The input AVPacket containing the input buffer. + * You can create such packet with av_init_packet() and by then setting + * data and size, some decoders might in addition need other fields like + * flags&AV_PKT_FLAG_KEY. All decoders are designed to use the least + * fields possible. + * @param[in,out] got_picture_ptr Zero if no frame could be decompressed, otherwise, it is nonzero. + * @return On error a negative value is returned, otherwise the number of bytes + * used or zero if no frame could be decompressed. + * + * @deprecated Use avcodec_send_packet() and avcodec_receive_frame(). + */ +attribute_deprecated +int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, + int *got_picture_ptr, + const AVPacket *avpkt); + +/** + * Decode a subtitle message. + * Return a negative value on error, otherwise return the number of bytes used. + * If no subtitle could be decompressed, got_sub_ptr is zero. + * Otherwise, the subtitle is stored in *sub. + * Note that AV_CODEC_CAP_DR1 is not available for subtitle codecs. This is for + * simplicity, because the performance difference is expect to be negligible + * and reusing a get_buffer written for video codecs would probably perform badly + * due to a potentially very different allocation pattern. + * + * Some decoders (those marked with AV_CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning subtitles. It is safe to flush even those decoders that are not + * marked with AV_CODEC_CAP_DELAY, then no subtitles will be returned. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx the codec context + * @param[out] sub The Preallocated AVSubtitle in which the decoded subtitle will be stored, + * must be freed with avsubtitle_free if *got_sub_ptr is set. + * @param[in,out] got_sub_ptr Zero if no subtitle could be decompressed, otherwise, it is nonzero. + * @param[in] avpkt The input AVPacket containing the input buffer. + */ +int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, + int *got_sub_ptr, + AVPacket *avpkt); + +/** + * Supply raw packet data as input to a decoder. + * + * Internally, this call will copy relevant AVCodecContext fields, which can + * influence decoding per-packet, and apply them when the packet is actually + * decoded. (For example AVCodecContext.skip_frame, which might direct the + * decoder to drop the frame contained by the packet sent with this function.) + * + * @warning The input buffer, avpkt->data must be AV_INPUT_BUFFER_PADDING_SIZE + * larger than the actual read bytes because some optimized bitstream + * readers read 32 or 64 bits at once and could read over the end. + * + * @warning Do not mix this API with the legacy API (like avcodec_decode_video2()) + * on the same AVCodecContext. It will return unexpected results now + * or in future libavcodec versions. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx codec context + * @param[in] avpkt The input AVPacket. Usually, this will be a single video + * frame, or several complete audio frames. + * Ownership of the packet remains with the caller, and the + * decoder will not write to the packet. The decoder may create + * a reference to the packet data (or copy it if the packet is + * not reference-counted). + * Unlike with older APIs, the packet is always fully consumed, + * and if it contains multiple frames (e.g. some audio codecs), + * will require you to call avcodec_receive_frame() multiple + * times afterwards before you can send a new packet. + * It can be NULL (or an AVPacket with data set to NULL and + * size set to 0); in this case, it is considered a flush + * packet, which signals the end of the stream. Sending the + * first flush packet will return success. Subsequent ones are + * unnecessary and will return AVERROR_EOF. If the decoder + * still has frames buffered, it will return them after sending + * a flush packet. + * + * @return 0 on success, otherwise negative error code: + * AVERROR(EAGAIN): input is not accepted in the current state - user + * must read output with avcodec_receive_frame() (once + * all output is read, the packet should be resent, and + * the call will not fail with EAGAIN). + * AVERROR_EOF: the decoder has been flushed, and no new packets can + * be sent to it (also returned if more than 1 flush + * packet is sent) + * AVERROR(EINVAL): codec not opened, it is an encoder, or requires flush + * AVERROR(ENOMEM): failed to add packet to internal queue, or similar + * other errors: legitimate decoding errors + */ +int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt); + +/** + * Return decoded output data from a decoder. + * + * @param avctx codec context + * @param frame This will be set to a reference-counted video or audio + * frame (depending on the decoder type) allocated by the + * decoder. Note that the function will always call + * av_frame_unref(frame) before doing anything else. + * + * @return + * 0: success, a frame was returned + * AVERROR(EAGAIN): output is not available in this state - user must try + * to send new input + * AVERROR_EOF: the decoder has been fully flushed, and there will be + * no more output frames + * AVERROR(EINVAL): codec not opened, or it is an encoder + * AVERROR_INPUT_CHANGED: current decoded frame has changed parameters + * with respect to first decoded frame. Applicable + * when flag AV_CODEC_FLAG_DROPCHANGED is set. + * other negative values: legitimate decoding errors + */ +int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame); + +/** + * Supply a raw video or audio frame to the encoder. Use avcodec_receive_packet() + * to retrieve buffered output packets. + * + * @param avctx codec context + * @param[in] frame AVFrame containing the raw audio or video frame to be encoded. + * Ownership of the frame remains with the caller, and the + * encoder will not write to the frame. The encoder may create + * a reference to the frame data (or copy it if the frame is + * not reference-counted). + * It can be NULL, in which case it is considered a flush + * packet. This signals the end of the stream. If the encoder + * still has packets buffered, it will return them after this + * call. Once flushing mode has been entered, additional flush + * packets are ignored, and sending frames will return + * AVERROR_EOF. + * + * For audio: + * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame + * can have any number of samples. + * If it is not set, frame->nb_samples must be equal to + * avctx->frame_size for all frames except the last. + * The final frame may be smaller than avctx->frame_size. + * @return 0 on success, otherwise negative error code: + * AVERROR(EAGAIN): input is not accepted in the current state - user + * must read output with avcodec_receive_packet() (once + * all output is read, the packet should be resent, and + * the call will not fail with EAGAIN). + * AVERROR_EOF: the encoder has been flushed, and no new frames can + * be sent to it + * AVERROR(EINVAL): codec not opened, refcounted_frames not set, it is a + * decoder, or requires flush + * AVERROR(ENOMEM): failed to add packet to internal queue, or similar + * other errors: legitimate decoding errors + */ +int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame); + +/** + * Read encoded data from the encoder. + * + * @param avctx codec context + * @param avpkt This will be set to a reference-counted packet allocated by the + * encoder. Note that the function will always call + * av_frame_unref(frame) before doing anything else. + * @return 0 on success, otherwise negative error code: + * AVERROR(EAGAIN): output is not available in the current state - user + * must try to send input + * AVERROR_EOF: the encoder has been fully flushed, and there will be + * no more output packets + * AVERROR(EINVAL): codec not opened, or it is an encoder + * other errors: legitimate decoding errors + */ +int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt); + +/** + * Create and return a AVHWFramesContext with values adequate for hardware + * decoding. This is meant to get called from the get_format callback, and is + * a helper for preparing a AVHWFramesContext for AVCodecContext.hw_frames_ctx. + * This API is for decoding with certain hardware acceleration modes/APIs only. + * + * The returned AVHWFramesContext is not initialized. The caller must do this + * with av_hwframe_ctx_init(). + * + * Calling this function is not a requirement, but makes it simpler to avoid + * codec or hardware API specific details when manually allocating frames. + * + * Alternatively to this, an API user can set AVCodecContext.hw_device_ctx, + * which sets up AVCodecContext.hw_frames_ctx fully automatically, and makes + * it unnecessary to call this function or having to care about + * AVHWFramesContext initialization at all. + * + * There are a number of requirements for calling this function: + * + * - It must be called from get_format with the same avctx parameter that was + * passed to get_format. Calling it outside of get_format is not allowed, and + * can trigger undefined behavior. + * - The function is not always supported (see description of return values). + * Even if this function returns successfully, hwaccel initialization could + * fail later. (The degree to which implementations check whether the stream + * is actually supported varies. Some do this check only after the user's + * get_format callback returns.) + * - The hw_pix_fmt must be one of the choices suggested by get_format. If the + * user decides to use a AVHWFramesContext prepared with this API function, + * the user must return the same hw_pix_fmt from get_format. + * - The device_ref passed to this function must support the given hw_pix_fmt. + * - After calling this API function, it is the user's responsibility to + * initialize the AVHWFramesContext (returned by the out_frames_ref parameter), + * and to set AVCodecContext.hw_frames_ctx to it. If done, this must be done + * before returning from get_format (this is implied by the normal + * AVCodecContext.hw_frames_ctx API rules). + * - The AVHWFramesContext parameters may change every time time get_format is + * called. Also, AVCodecContext.hw_frames_ctx is reset before get_format. So + * you are inherently required to go through this process again on every + * get_format call. + * - It is perfectly possible to call this function without actually using + * the resulting AVHWFramesContext. One use-case might be trying to reuse a + * previously initialized AVHWFramesContext, and calling this API function + * only to test whether the required frame parameters have changed. + * - Fields that use dynamically allocated values of any kind must not be set + * by the user unless setting them is explicitly allowed by the documentation. + * If the user sets AVHWFramesContext.free and AVHWFramesContext.user_opaque, + * the new free callback must call the potentially set previous free callback. + * This API call may set any dynamically allocated fields, including the free + * callback. + * + * The function will set at least the following fields on AVHWFramesContext + * (potentially more, depending on hwaccel API): + * + * - All fields set by av_hwframe_ctx_alloc(). + * - Set the format field to hw_pix_fmt. + * - Set the sw_format field to the most suited and most versatile format. (An + * implication is that this will prefer generic formats over opaque formats + * with arbitrary restrictions, if possible.) + * - Set the width/height fields to the coded frame size, rounded up to the + * API-specific minimum alignment. + * - Only _if_ the hwaccel requires a pre-allocated pool: set the initial_pool_size + * field to the number of maximum reference surfaces possible with the codec, + * plus 1 surface for the user to work (meaning the user can safely reference + * at most 1 decoded surface at a time), plus additional buffering introduced + * by frame threading. If the hwaccel does not require pre-allocation, the + * field is left to 0, and the decoder will allocate new surfaces on demand + * during decoding. + * - Possibly AVHWFramesContext.hwctx fields, depending on the underlying + * hardware API. + * + * Essentially, out_frames_ref returns the same as av_hwframe_ctx_alloc(), but + * with basic frame parameters set. + * + * The function is stateless, and does not change the AVCodecContext or the + * device_ref AVHWDeviceContext. + * + * @param avctx The context which is currently calling get_format, and which + * implicitly contains all state needed for filling the returned + * AVHWFramesContext properly. + * @param device_ref A reference to the AVHWDeviceContext describing the device + * which will be used by the hardware decoder. + * @param hw_pix_fmt The hwaccel format you are going to return from get_format. + * @param out_frames_ref On success, set to a reference to an _uninitialized_ + * AVHWFramesContext, created from the given device_ref. + * Fields will be set to values required for decoding. + * Not changed if an error is returned. + * @return zero on success, a negative value on error. The following error codes + * have special semantics: + * AVERROR(ENOENT): the decoder does not support this functionality. Setup + * is always manual, or it is a decoder which does not + * support setting AVCodecContext.hw_frames_ctx at all, + * or it is a software format. + * AVERROR(EINVAL): it is known that hardware decoding is not supported for + * this configuration, or the device_ref is not supported + * for the hwaccel referenced by hw_pix_fmt. + */ +int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, + AVBufferRef *device_ref, + enum AVPixelFormat hw_pix_fmt, + AVBufferRef **out_frames_ref); + + + +/** + * @defgroup lavc_parsing Frame parsing + * @{ + */ + +enum AVPictureStructure { + AV_PICTURE_STRUCTURE_UNKNOWN, //< unknown + AV_PICTURE_STRUCTURE_TOP_FIELD, //< coded as top field + AV_PICTURE_STRUCTURE_BOTTOM_FIELD, //< coded as bottom field + AV_PICTURE_STRUCTURE_FRAME, //< coded as frame +}; + +typedef struct AVCodecParserContext { + void *priv_data; + struct AVCodecParser *parser; + int64_t frame_offset; /* offset of the current frame */ + int64_t cur_offset; /* current offset + (incremented by each av_parser_parse()) */ + int64_t next_frame_offset; /* offset of the next frame */ + /* video info */ + int pict_type; /* XXX: Put it back in AVCodecContext. */ + /** + * This field is used for proper frame duration computation in lavf. + * It signals, how much longer the frame duration of the current frame + * is compared to normal frame duration. + * + * frame_duration = (1 + repeat_pict) * time_base + * + * It is used by codecs like H.264 to display telecined material. + */ + int repeat_pict; /* XXX: Put it back in AVCodecContext. */ + int64_t pts; /* pts of the current frame */ + int64_t dts; /* dts of the current frame */ + + /* private data */ + int64_t last_pts; + int64_t last_dts; + int fetch_timestamp; + +#define AV_PARSER_PTS_NB 4 + int cur_frame_start_index; + int64_t cur_frame_offset[AV_PARSER_PTS_NB]; + int64_t cur_frame_pts[AV_PARSER_PTS_NB]; + int64_t cur_frame_dts[AV_PARSER_PTS_NB]; + + int flags; +#define PARSER_FLAG_COMPLETE_FRAMES 0x0001 +#define PARSER_FLAG_ONCE 0x0002 +/// Set if the parser has a valid file offset +#define PARSER_FLAG_FETCHED_OFFSET 0x0004 +#define PARSER_FLAG_USE_CODEC_TS 0x1000 + + int64_t offset; ///< byte offset from starting packet start + int64_t cur_frame_end[AV_PARSER_PTS_NB]; + + /** + * Set by parser to 1 for key frames and 0 for non-key frames. + * It is initialized to -1, so if the parser doesn't set this flag, + * old-style fallback using AV_PICTURE_TYPE_I picture type as key frames + * will be used. + */ + int key_frame; + +#if FF_API_CONVERGENCE_DURATION + /** + * @deprecated unused + */ + attribute_deprecated + int64_t convergence_duration; +#endif + + // Timestamp generation support: + /** + * Synchronization point for start of timestamp generation. + * + * Set to >0 for sync point, 0 for no sync point and <0 for undefined + * (default). + * + * For example, this corresponds to presence of H.264 buffering period + * SEI message. + */ + int dts_sync_point; + + /** + * Offset of the current timestamp against last timestamp sync point in + * units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain a valid timestamp offset. + * + * Note that the timestamp of sync point has usually a nonzero + * dts_ref_dts_delta, which refers to the previous sync point. Offset of + * the next frame after timestamp sync point will be usually 1. + * + * For example, this corresponds to H.264 cpb_removal_delay. + */ + int dts_ref_dts_delta; + + /** + * Presentation delay of current frame in units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain valid non-negative timestamp delta (presentation time of a frame + * must not lie in the past). + * + * This delay represents the difference between decoding and presentation + * time of the frame. + * + * For example, this corresponds to H.264 dpb_output_delay. + */ + int pts_dts_delta; + + /** + * Position of the packet in file. + * + * Analogous to cur_frame_pts/dts + */ + int64_t cur_frame_pos[AV_PARSER_PTS_NB]; + + /** + * Byte position of currently parsed frame in stream. + */ + int64_t pos; + + /** + * Previous frame byte position. + */ + int64_t last_pos; + + /** + * Duration of the current frame. + * For audio, this is in units of 1 / AVCodecContext.sample_rate. + * For all other types, this is in units of AVCodecContext.time_base. + */ + int duration; + + enum AVFieldOrder field_order; + + /** + * Indicate whether a picture is coded as a frame, top field or bottom field. + * + * For example, H.264 field_pic_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_FRAME. An H.264 picture with field_pic_flag + * equal to 1 and bottom_field_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_TOP_FIELD. + */ + enum AVPictureStructure picture_structure; + + /** + * Picture number incremented in presentation or output order. + * This field may be reinitialized at the first picture of a new sequence. + * + * For example, this corresponds to H.264 PicOrderCnt. + */ + int output_picture_number; + + /** + * Dimensions of the decoded video intended for presentation. + */ + int width; + int height; + + /** + * Dimensions of the coded video. + */ + int coded_width; + int coded_height; + + /** + * The format of the coded data, corresponds to enum AVPixelFormat for video + * and for enum AVSampleFormat for audio. + * + * Note that a decoder can have considerable freedom in how exactly it + * decodes the data, so the format reported here might be different from the + * one returned by a decoder. + */ + int format; +} AVCodecParserContext; + +typedef struct AVCodecParser { + int codec_ids[5]; /* several codec IDs are permitted */ + int priv_data_size; + int (*parser_init)(AVCodecParserContext *s); + /* This callback never returns an error, a negative value means that + * the frame start was in a previous packet. */ + int (*parser_parse)(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size); + void (*parser_close)(AVCodecParserContext *s); + int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); + struct AVCodecParser *next; +} AVCodecParser; + +/** + * Iterate over all registered codec parsers. + * + * @param opaque a pointer where libavcodec will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered codec parser or NULL when the iteration is + * finished + */ +const AVCodecParser *av_parser_iterate(void **opaque); + +attribute_deprecated +AVCodecParser *av_parser_next(const AVCodecParser *c); + +attribute_deprecated +void av_register_codec_parser(AVCodecParser *parser); +AVCodecParserContext *av_parser_init(int codec_id); + +/** + * Parse a packet. + * + * @param s parser context. + * @param avctx codec context. + * @param poutbuf set to pointer to parsed buffer or NULL if not yet finished. + * @param poutbuf_size set to size of parsed buffer or zero if not yet finished. + * @param buf input buffer. + * @param buf_size buffer size in bytes without the padding. I.e. the full buffer + size is assumed to be buf_size + AV_INPUT_BUFFER_PADDING_SIZE. + To signal EOF, this should be 0 (so that the last frame + can be output). + * @param pts input presentation timestamp. + * @param dts input decoding timestamp. + * @param pos input byte position in stream. + * @return the number of bytes of the input bitstream used. + * + * Example: + * @code + * while(in_len){ + * len = av_parser_parse2(myparser, AVCodecContext, &data, &size, + * in_data, in_len, + * pts, dts, pos); + * in_data += len; + * in_len -= len; + * + * if(size) + * decode_frame(data, size); + * } + * @endcode + */ +int av_parser_parse2(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, + int64_t pts, int64_t dts, + int64_t pos); + +/** + * @return 0 if the output buffer is a subset of the input, 1 if it is allocated and must be freed + * @deprecated use AVBitStreamFilter + */ +int av_parser_change(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); +void av_parser_close(AVCodecParserContext *s); + +/** + * @} + * @} + */ + +/** + * @addtogroup lavc_encoding + * @{ + */ + +/** + * Find a registered encoder with a matching codec ID. + * + * @param id AVCodecID of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder(enum AVCodecID id); + +/** + * Find a registered encoder with the specified name. + * + * @param name name of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder_by_name(const char *name); + +/** + * Encode a frame of audio. + * + * Takes input samples from frame and writes the next output packet, if + * available, to avpkt. The output packet does not necessarily contain data for + * the most recent frame, as encoders can delay, split, and combine input frames + * internally as needed. + * + * @param avctx codec context + * @param avpkt output AVPacket. + * The user can supply an output buffer by setting + * avpkt->data and avpkt->size prior to calling the + * function, but if the size of the user-provided data is not + * large enough, encoding will fail. If avpkt->data and + * avpkt->size are set, avpkt->destruct must also be set. All + * other AVPacket fields will be reset by the encoder using + * av_init_packet(). If avpkt->data is NULL, the encoder will + * allocate it. The encoder will set avpkt->size to the size + * of the output packet. + * + * If this function fails or produces no output, avpkt will be + * freed using av_packet_unref(). + * @param[in] frame AVFrame containing the raw audio data to be encoded. + * May be NULL when flushing an encoder that has the + * AV_CODEC_CAP_DELAY capability set. + * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame + * can have any number of samples. + * If it is not set, frame->nb_samples must be equal to + * avctx->frame_size for all frames except the last. + * The final frame may be smaller than avctx->frame_size. + * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the + * output packet is non-empty, and to 0 if it is + * empty. If the function returns an error, the + * packet can be assumed to be invalid, and the + * value of got_packet_ptr is undefined and should + * not be used. + * @return 0 on success, negative error code on failure + * + * @deprecated use avcodec_send_frame()/avcodec_receive_packet() instead + */ +attribute_deprecated +int avcodec_encode_audio2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + +/** + * Encode a frame of video. + * + * Takes input raw video data from frame and writes the next output packet, if + * available, to avpkt. The output packet does not necessarily contain data for + * the most recent frame, as encoders can delay and reorder input frames + * internally as needed. + * + * @param avctx codec context + * @param avpkt output AVPacket. + * The user can supply an output buffer by setting + * avpkt->data and avpkt->size prior to calling the + * function, but if the size of the user-provided data is not + * large enough, encoding will fail. All other AVPacket fields + * will be reset by the encoder using av_init_packet(). If + * avpkt->data is NULL, the encoder will allocate it. + * The encoder will set avpkt->size to the size of the + * output packet. The returned data (if any) belongs to the + * caller, he is responsible for freeing it. + * + * If this function fails or produces no output, avpkt will be + * freed using av_packet_unref(). + * @param[in] frame AVFrame containing the raw video data to be encoded. + * May be NULL when flushing an encoder that has the + * AV_CODEC_CAP_DELAY capability set. + * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the + * output packet is non-empty, and to 0 if it is + * empty. If the function returns an error, the + * packet can be assumed to be invalid, and the + * value of got_packet_ptr is undefined and should + * not be used. + * @return 0 on success, negative error code on failure + * + * @deprecated use avcodec_send_frame()/avcodec_receive_packet() instead + */ +attribute_deprecated +int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + +int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVSubtitle *sub); + + +/** + * @} + */ + +#if FF_API_AVPICTURE +/** + * @addtogroup lavc_picture + * @{ + */ + +/** + * @deprecated unused + */ +attribute_deprecated +int avpicture_alloc(AVPicture *picture, enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated unused + */ +attribute_deprecated +void avpicture_free(AVPicture *picture); + +/** + * @deprecated use av_image_fill_arrays() instead. + */ +attribute_deprecated +int avpicture_fill(AVPicture *picture, const uint8_t *ptr, + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated use av_image_copy_to_buffer() instead. + */ +attribute_deprecated +int avpicture_layout(const AVPicture *src, enum AVPixelFormat pix_fmt, + int width, int height, + unsigned char *dest, int dest_size); + +/** + * @deprecated use av_image_get_buffer_size() instead. + */ +attribute_deprecated +int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated av_image_copy() instead. + */ +attribute_deprecated +void av_picture_copy(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated unused + */ +attribute_deprecated +int av_picture_crop(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int top_band, int left_band); + +/** + * @deprecated unused + */ +attribute_deprecated +int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, enum AVPixelFormat pix_fmt, + int padtop, int padbottom, int padleft, int padright, int *color); + +/** + * @} + */ +#endif + +/** + * @defgroup lavc_misc Utility functions + * @ingroup libavc + * + * Miscellaneous utility functions related to both encoding and decoding + * (or neither). + * @{ + */ + +/** + * @defgroup lavc_misc_pixfmt Pixel formats + * + * Functions for working with pixel formats. + * @{ + */ + +#if FF_API_GETCHROMA +/** + * @deprecated Use av_pix_fmt_get_chroma_sub_sample + */ + +attribute_deprecated +void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift); +#endif + +/** + * Return a value representing the fourCC code associated to the + * pixel format pix_fmt, or 0 if no associated fourCC code can be + * found. + */ +unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat pix_fmt); + +/** + * @deprecated see av_get_pix_fmt_loss() + */ +int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Find the best pixel format to convert to given a certain source pixel + * format. When converting from one pixel format to another, information loss + * may occur. For example, when converting from RGB24 to GRAY, the color + * information will be lost. Similarly, other losses occur when converting from + * some formats to other formats. avcodec_find_best_pix_fmt_of_2() searches which of + * the given pixel formats should be used to suffer the least amount of loss. + * The pixel formats from which it chooses one, are determined by the + * pix_fmt_list parameter. + * + * + * @param[in] pix_fmt_list AV_PIX_FMT_NONE terminated array of pixel formats to choose from + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur. + * @return The best pixel format to convert to or -1 if none was found. + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr); + +/** + * @deprecated see av_find_best_pix_fmt_of_2() + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +attribute_deprecated +enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum AVPixelFormat * fmt); + +/** + * @} + */ + +#if FF_API_TAG_STRING +/** + * Put a string representing the codec tag codec_tag in buf. + * + * @param buf buffer to place codec tag in + * @param buf_size size in bytes of buf + * @param codec_tag codec tag to assign + * @return the length of the string that would have been generated if + * enough space had been available, excluding the trailing null + * + * @deprecated see av_fourcc_make_string() and av_fourcc2str(). + */ +attribute_deprecated +size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_tag); +#endif + +void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); + +/** + * Return a name for the specified profile, if available. + * + * @param codec the codec that is searched for the given profile + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + */ +const char *av_get_profile_name(const AVCodec *codec, int profile); + +/** + * Return a name for the specified profile, if available. + * + * @param codec_id the ID of the codec to which the requested profile belongs + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + * + * @note unlike av_get_profile_name(), which searches a list of profiles + * supported by a specific decoder or encoder implementation, this + * function searches the list of profiles from the AVCodecDescriptor + */ +const char *avcodec_profile_name(enum AVCodecID codec_id, int profile); + +int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size); +int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count); +//FIXME func typedef + +/** + * Fill AVFrame audio data and linesize pointers. + * + * The buffer buf must be a preallocated buffer with a size big enough + * to contain the specified samples amount. The filled AVFrame data + * pointers will point to this buffer. + * + * AVFrame extended_data channel pointers are allocated if necessary for + * planar audio. + * + * @param frame the AVFrame + * frame->nb_samples must be set prior to calling the + * function. This function fills in frame->data, + * frame->extended_data, frame->linesize[0]. + * @param nb_channels channel count + * @param sample_fmt sample format + * @param buf buffer to use for frame data + * @param buf_size size of buffer + * @param align plane size sample alignment (0 = default) + * @return >=0 on success, negative error code on failure + * @todo return the size in bytes required to store the samples in + * case of success, at the next libavutil bump + */ +int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels, + enum AVSampleFormat sample_fmt, const uint8_t *buf, + int buf_size, int align); + +/** + * Reset the internal decoder state / flush internal buffers. Should be called + * e.g. when seeking or when switching to a different stream. + * + * @note when refcounted frames are not used (i.e. avctx->refcounted_frames is 0), + * this invalidates the frames previously returned from the decoder. When + * refcounted frames are used, the decoder just releases any references it might + * keep internally, but the caller's reference remains valid. + */ +void avcodec_flush_buffers(AVCodecContext *avctx); + +/** + * Return codec bits per sample. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return the PCM codec associated with a sample format. + * @param be endianness, 0 for little, 1 for big, + * -1 (or anything else) for native + * @return AV_CODEC_ID_PCM_* or AV_CODEC_ID_NONE + */ +enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be); + +/** + * Return codec bits per sample. + * Only return non-zero if the bits per sample is exactly correct, not an + * approximation. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_exact_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return audio frame duration. + * + * @param avctx codec context + * @param frame_bytes size of the frame, or 0 if unknown + * @return frame duration, in samples, if known. 0 if not able to + * determine. + */ +int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes); + +/** + * This function is the same as av_get_audio_frame_duration(), except it works + * with AVCodecParameters instead of an AVCodecContext. + */ +int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes); + +#if FF_API_OLD_BSF +typedef struct AVBitStreamFilterContext { + void *priv_data; + const struct AVBitStreamFilter *filter; + AVCodecParserContext *parser; + struct AVBitStreamFilterContext *next; + /** + * Internal default arguments, used if NULL is passed to av_bitstream_filter_filter(). + * Not for access by library users. + */ + char *args; +} AVBitStreamFilterContext; +#endif + +typedef struct AVBSFInternal AVBSFInternal; + +/** + * The bitstream filter state. + * + * This struct must be allocated with av_bsf_alloc() and freed with + * av_bsf_free(). + * + * The fields in the struct will only be changed (by the caller or by the + * filter) as described in their documentation, and are to be considered + * immutable otherwise. + */ +typedef struct AVBSFContext { + /** + * A class for logging and AVOptions + */ + const AVClass *av_class; + + /** + * The bitstream filter this context is an instance of. + */ + const struct AVBitStreamFilter *filter; + + /** + * Opaque libavcodec internal data. Must not be touched by the caller in any + * way. + */ + AVBSFInternal *internal; + + /** + * Opaque filter-specific private data. If filter->priv_class is non-NULL, + * this is an AVOptions-enabled struct. + */ + void *priv_data; + + /** + * Parameters of the input stream. This field is allocated in + * av_bsf_alloc(), it needs to be filled by the caller before + * av_bsf_init(). + */ + AVCodecParameters *par_in; + + /** + * Parameters of the output stream. This field is allocated in + * av_bsf_alloc(), it is set by the filter in av_bsf_init(). + */ + AVCodecParameters *par_out; + + /** + * The timebase used for the timestamps of the input packets. Set by the + * caller before av_bsf_init(). + */ + AVRational time_base_in; + + /** + * The timebase used for the timestamps of the output packets. Set by the + * filter in av_bsf_init(). + */ + AVRational time_base_out; +} AVBSFContext; + +typedef struct AVBitStreamFilter { + const char *name; + + /** + * A list of codec ids supported by the filter, terminated by + * AV_CODEC_ID_NONE. + * May be NULL, in that case the bitstream filter works with any codec id. + */ + const enum AVCodecID *codec_ids; + + /** + * A class for the private data, used to declare bitstream filter private + * AVOptions. This field is NULL for bitstream filters that do not declare + * any options. + * + * If this field is non-NULL, the first member of the filter private data + * must be a pointer to AVClass, which will be set by libavcodec generic + * code to this class. + */ + const AVClass *priv_class; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + + int priv_data_size; + int (*init)(AVBSFContext *ctx); + int (*filter)(AVBSFContext *ctx, AVPacket *pkt); + void (*close)(AVBSFContext *ctx); + void (*flush)(AVBSFContext *ctx); +} AVBitStreamFilter; + +#if FF_API_OLD_BSF +/** + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use the new bitstream filtering API (using AVBSFContext). + */ +attribute_deprecated +void av_register_bitstream_filter(AVBitStreamFilter *bsf); +/** + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use av_bsf_get_by_name(), av_bsf_alloc(), and av_bsf_init() + * from the new bitstream filtering API (using AVBSFContext). + */ +attribute_deprecated +AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); +/** + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use av_bsf_send_packet() and av_bsf_receive_packet() from the + * new bitstream filtering API (using AVBSFContext). + */ +attribute_deprecated +int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const char *args, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); +/** + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use av_bsf_free() from the new bitstream filtering API (using + * AVBSFContext). + */ +attribute_deprecated +void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); +/** + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use av_bsf_iterate() from the new bitstream filtering API (using + * AVBSFContext). + */ +attribute_deprecated +const AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); +#endif + +/** + * @return a bitstream filter with the specified name or NULL if no such + * bitstream filter exists. + */ +const AVBitStreamFilter *av_bsf_get_by_name(const char *name); + +/** + * Iterate over all registered bitstream filters. + * + * @param opaque a pointer where libavcodec will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered bitstream filter or NULL when the iteration is + * finished + */ +const AVBitStreamFilter *av_bsf_iterate(void **opaque); +#if FF_API_NEXT +attribute_deprecated +const AVBitStreamFilter *av_bsf_next(void **opaque); +#endif + +/** + * Allocate a context for a given bitstream filter. The caller must fill in the + * context parameters as described in the documentation and then call + * av_bsf_init() before sending any data to the filter. + * + * @param filter the filter for which to allocate an instance. + * @param ctx a pointer into which the pointer to the newly-allocated context + * will be written. It must be freed with av_bsf_free() after the + * filtering is done. + * + * @return 0 on success, a negative AVERROR code on failure + */ +int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **ctx); + +/** + * Prepare the filter for use, after all the parameters and options have been + * set. + */ +int av_bsf_init(AVBSFContext *ctx); + +/** + * Submit a packet for filtering. + * + * After sending each packet, the filter must be completely drained by calling + * av_bsf_receive_packet() repeatedly until it returns AVERROR(EAGAIN) or + * AVERROR_EOF. + * + * @param pkt the packet to filter. The bitstream filter will take ownership of + * the packet and reset the contents of pkt. pkt is not touched if an error occurs. + * This parameter may be NULL, which signals the end of the stream (i.e. no more + * packets will be sent). That will cause the filter to output any packets it + * may have buffered internally. + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt); + +/** + * Retrieve a filtered packet. + * + * @param[out] pkt this struct will be filled with the contents of the filtered + * packet. It is owned by the caller and must be freed using + * av_packet_unref() when it is no longer needed. + * This parameter should be "clean" (i.e. freshly allocated + * with av_packet_alloc() or unreffed with av_packet_unref()) + * when this function is called. If this function returns + * successfully, the contents of pkt will be completely + * overwritten by the returned data. On failure, pkt is not + * touched. + * + * @return 0 on success. AVERROR(EAGAIN) if more packets need to be sent to the + * filter (using av_bsf_send_packet()) to get more output. AVERROR_EOF if there + * will be no further output from the filter. Another negative AVERROR value if + * an error occurs. + * + * @note one input packet may result in several output packets, so after sending + * a packet with av_bsf_send_packet(), this function needs to be called + * repeatedly until it stops returning 0. It is also possible for a filter to + * output fewer packets than were sent to it, so this function may return + * AVERROR(EAGAIN) immediately after a successful av_bsf_send_packet() call. + */ +int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt); + +/** + * Reset the internal bitstream filter state / flush internal buffers. + */ +void av_bsf_flush(AVBSFContext *ctx); + +/** + * Free a bitstream filter context and everything associated with it; write NULL + * into the supplied pointer. + */ +void av_bsf_free(AVBSFContext **ctx); + +/** + * Get the AVClass for AVBSFContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *av_bsf_get_class(void); + +/** + * Structure for chain/list of bitstream filters. + * Empty list can be allocated by av_bsf_list_alloc(). + */ +typedef struct AVBSFList AVBSFList; + +/** + * Allocate empty list of bitstream filters. + * The list must be later freed by av_bsf_list_free() + * or finalized by av_bsf_list_finalize(). + * + * @return Pointer to @ref AVBSFList on success, NULL in case of failure + */ +AVBSFList *av_bsf_list_alloc(void); + +/** + * Free list of bitstream filters. + * + * @param lst Pointer to pointer returned by av_bsf_list_alloc() + */ +void av_bsf_list_free(AVBSFList **lst); + +/** + * Append bitstream filter to the list of bitstream filters. + * + * @param lst List to append to + * @param bsf Filter context to be appended + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf); + +/** + * Construct new bitstream filter context given it's name and options + * and append it to the list of bitstream filters. + * + * @param lst List to append to + * @param bsf_name Name of the bitstream filter + * @param options Options for the bitstream filter, can be set to NULL + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_append2(AVBSFList *lst, const char * bsf_name, AVDictionary **options); +/** + * Finalize list of bitstream filters. + * + * This function will transform @ref AVBSFList to single @ref AVBSFContext, + * so the whole chain of bitstream filters can be treated as single filter + * freshly allocated by av_bsf_alloc(). + * If the call is successful, @ref AVBSFList structure is freed and lst + * will be set to NULL. In case of failure, caller is responsible for + * freeing the structure by av_bsf_list_free() + * + * @param lst Filter list structure to be transformed + * @param[out] bsf Pointer to be set to newly created @ref AVBSFContext structure + * representing the chain of bitstream filters + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf); + +/** + * Parse string describing list of bitstream filters and create single + * @ref AVBSFContext describing the whole chain of bitstream filters. + * Resulting @ref AVBSFContext can be treated as any other @ref AVBSFContext freshly + * allocated by av_bsf_alloc(). + * + * @param str String describing chain of bitstream filters in format + * `bsf1[=opt1=val1:opt2=val2][,bsf2]` + * @param[out] bsf Pointer to be set to newly created @ref AVBSFContext structure + * representing the chain of bitstream filters + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf); + +/** + * Get null/pass-through bitstream filter. + * + * @param[out] bsf Pointer to be set to new instance of pass-through bitstream filter + * + * @return + */ +int av_bsf_get_null_filter(AVBSFContext **bsf); + +/* memory */ + +/** + * Same behaviour av_fast_malloc but the buffer has additional + * AV_INPUT_BUFFER_PADDING_SIZE at the end which will always be 0. + * + * In addition the whole buffer will initially and after resizes + * be 0-initialized so that no uninitialized data will ever appear. + */ +void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Same behaviour av_fast_padded_malloc except that buffer will always + * be 0-initialized after call. + */ +void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); + +/** + * Encode extradata length to a buffer. Used by xiph codecs. + * + * @param s buffer to write to; must be at least (v/255+1) bytes long + * @param v size of extradata in bytes + * @return number of bytes written to the buffer. + */ +unsigned int av_xiphlacing(unsigned char *s, unsigned int v); + +#if FF_API_USER_VISIBLE_AVHWACCEL +/** + * Register the hardware accelerator hwaccel. + * + * @deprecated This function doesn't do anything. + */ +attribute_deprecated +void av_register_hwaccel(AVHWAccel *hwaccel); + +/** + * If hwaccel is NULL, returns the first registered hardware accelerator, + * if hwaccel is non-NULL, returns the next registered hardware accelerator + * after hwaccel, or NULL if hwaccel is the last one. + * + * @deprecated AVHWaccel structures contain no user-serviceable parts, so + * this function should not be used. + */ +attribute_deprecated +AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel); +#endif + +#if FF_API_LOCKMGR +/** + * Lock operation used by lockmgr + * + * @deprecated Deprecated together with av_lockmgr_register(). + */ +enum AVLockOp { + AV_LOCK_CREATE, ///< Create a mutex + AV_LOCK_OBTAIN, ///< Lock the mutex + AV_LOCK_RELEASE, ///< Unlock the mutex + AV_LOCK_DESTROY, ///< Free mutex resources +}; + +/** + * Register a user provided lock manager supporting the operations + * specified by AVLockOp. The "mutex" argument to the function points + * to a (void *) where the lockmgr should store/get a pointer to a user + * allocated mutex. It is NULL upon AV_LOCK_CREATE and equal to the + * value left by the last call for all other ops. If the lock manager is + * unable to perform the op then it should leave the mutex in the same + * state as when it was called and return a non-zero value. However, + * when called with AV_LOCK_DESTROY the mutex will always be assumed to + * have been successfully destroyed. If av_lockmgr_register succeeds + * it will return a non-negative value, if it fails it will return a + * negative value and destroy all mutex and unregister all callbacks. + * av_lockmgr_register is not thread-safe, it must be called from a + * single thread before any calls which make use of locking are used. + * + * @param cb User defined callback. av_lockmgr_register invokes calls + * to this callback and the previously registered callback. + * The callback will be used to create more than one mutex + * each of which must be backed by its own underlying locking + * mechanism (i.e. do not use a single static object to + * implement your lock manager). If cb is set to NULL the + * lockmgr will be unregistered. + * + * @deprecated This function does nothing, and always returns 0. Be sure to + * build with thread support to get basic thread safety. + */ +attribute_deprecated +int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)); +#endif + +/** + * Get the type of the given codec. + */ +enum AVMediaType avcodec_get_type(enum AVCodecID codec_id); + +/** + * Get the name of a codec. + * @return a static string identifying the codec; never NULL + */ +const char *avcodec_get_name(enum AVCodecID id); + +/** + * @return a positive value if s is open (i.e. avcodec_open2() was called on it + * with no corresponding avcodec_close()), 0 otherwise. + */ +int avcodec_is_open(AVCodecContext *s); + +/** + * @return a non-zero number if codec is an encoder, zero otherwise + */ +int av_codec_is_encoder(const AVCodec *codec); + +/** + * @return a non-zero number if codec is a decoder, zero otherwise + */ +int av_codec_is_decoder(const AVCodec *codec); + +/** + * @return descriptor for given codec ID or NULL if no descriptor exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id); + +/** + * Iterate over all codec descriptors known to libavcodec. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev); + +/** + * @return codec descriptor with the given name or NULL if no such descriptor + * exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name); + +/** + * Allocate a CPB properties structure and initialize its fields to default + * values. + * + * @param size if non-NULL, the size of the allocated struct will be written + * here. This is useful for embedding it in side data. + * + * @return the newly allocated struct or NULL on failure + */ +AVCPBProperties *av_cpb_properties_alloc(size_t *size); + +/** + * @} + */ + +#endif /* AVCODEC_AVCODEC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avdct.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avdct.c new file mode 100644 index 0000000000..47e5f7134e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avdct.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2014 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "idctdsp.h" +#include "fdctdsp.h" +#include "pixblockdsp.h" +#include "avdct.h" + +#define OFFSET(x) offsetof(AVDCT,x) +#define DEFAULT 0 //should be NAN but it does not work as it is not a constant in glibc as required by ANSI/ISO C +//these names are too long to be readable +#define V AV_OPT_FLAG_VIDEO_PARAM +#define A AV_OPT_FLAG_AUDIO_PARAM +#define E AV_OPT_FLAG_ENCODING_PARAM +#define D AV_OPT_FLAG_DECODING_PARAM + +static const AVOption avdct_options[] = { +{"dct", "DCT algorithm", OFFSET(dct_algo), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, V|E, "dct"}, +{"auto", "autoselect a good one", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_AUTO }, INT_MIN, INT_MAX, V|E, "dct"}, +{"fastint", "fast integer (experimental / for debugging)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_FASTINT }, INT_MIN, INT_MAX, V|E, "dct"}, +{"int", "accurate integer", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_INT }, INT_MIN, INT_MAX, V|E, "dct"}, +{"mmx", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_MMX }, INT_MIN, INT_MAX, V|E, "dct"}, +{"altivec", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_ALTIVEC }, INT_MIN, INT_MAX, V|E, "dct"}, +{"faan", "floating point AAN DCT (experimental / for debugging)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_FAAN }, INT_MIN, INT_MAX, V|E, "dct"}, + +{"idct", "select IDCT implementation", OFFSET(idct_algo), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, V|E|D, "idct"}, +{"auto", "autoselect a good one", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_AUTO }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"int", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_INT }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simple", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLE }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simplemmx", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEMMX }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"arm", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_ARM }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"altivec", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_ALTIVEC }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simplearm", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARM }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simplearmv5te", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARMV5TE }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simplearmv6", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARMV6 }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simpleneon", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLENEON }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"xvid", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"xvidmmx", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"faani", "floating point AAN IDCT (experimental / for debugging)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_FAAN }, INT_MIN, INT_MAX, V|D|E, "idct"}, +{"simpleauto", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEAUTO }, INT_MIN, INT_MAX, V|E|D, "idct"}, + +{"bits_per_sample", "", OFFSET(bits_per_sample), AV_OPT_TYPE_INT, {.i64 = 8 }, 0, 14, 0,}, +{NULL}, +}; + +static const AVClass avdct_class = { + .class_name = "AVDCT", + .option = avdct_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVClass *avcodec_dct_get_class(void) +{ + return &avdct_class; +} + +AVDCT *avcodec_dct_alloc(void) +{ + AVDCT *dsp = av_mallocz(sizeof(AVDCT)); + + if (!dsp) + return NULL; + + dsp->av_class = &avdct_class; + av_opt_set_defaults(dsp); + + return dsp; +} + +int avcodec_dct_init(AVDCT *dsp) +{ + AVCodecContext *avctx = avcodec_alloc_context3(NULL); + + if (!avctx) + return AVERROR(ENOMEM); + + avctx->idct_algo = dsp->idct_algo; + avctx->dct_algo = dsp->dct_algo; + avctx->bits_per_raw_sample = dsp->bits_per_sample; + +#define COPY(src, name) memcpy(&dsp->name, &src.name, sizeof(dsp->name)) + +#if CONFIG_IDCTDSP + { + IDCTDSPContext idsp; + ff_idctdsp_init(&idsp, avctx); + COPY(idsp, idct); + COPY(idsp, idct_permutation); + } +#endif + +#if CONFIG_FDCTDSP + { + FDCTDSPContext fdsp; + ff_fdctdsp_init(&fdsp, avctx); + COPY(fdsp, fdct); + } +#endif + +#if CONFIG_PIXBLOCKDSP + { + PixblockDSPContext pdsp; + ff_pixblockdsp_init(&pdsp, avctx); + COPY(pdsp, get_pixels); + } +#endif + + avcodec_free_context(&avctx); + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avdct.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avdct.h new file mode 100644 index 0000000000..272422e44c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avdct.h @@ -0,0 +1,84 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVDCT_H +#define AVCODEC_AVDCT_H + +#include "libavutil/opt.h" + +/** + * AVDCT context. + * @note function pointers can be NULL if the specific features have been + * disabled at build time. + */ +typedef struct AVDCT { + const AVClass *av_class; + + void (*idct)(int16_t *block /* align 16 */); + + /** + * IDCT input permutation. + * Several optimized IDCTs need a permutated input (relative to the + * normal order of the reference IDCT). + * This permutation must be performed before the idct_put/add. + * Note, normally this can be merged with the zigzag/alternate scan
      + * An example to avoid confusion: + * - (->decode coeffs -> zigzag reorder -> dequant -> reference IDCT -> ...) + * - (x -> reference DCT -> reference IDCT -> x) + * - (x -> reference DCT -> simple_mmx_perm = idct_permutation + * -> simple_idct_mmx -> x) + * - (-> decode coeffs -> zigzag reorder -> simple_mmx_perm -> dequant + * -> simple_idct_mmx -> ...) + */ + uint8_t idct_permutation[64]; + + void (*fdct)(int16_t *block /* align 16 */); + + + /** + * DCT algorithm. + * must use AVOptions to set this field. + */ + int dct_algo; + + /** + * IDCT algorithm. + * must use AVOptions to set this field. + */ + int idct_algo; + + void (*get_pixels)(int16_t *block /* align 16 */, + const uint8_t *pixels /* align 8 */, + ptrdiff_t line_size); + + int bits_per_sample; +} AVDCT; + +/** + * Allocates a AVDCT context. + * This needs to be initialized with avcodec_dct_init() after optionally + * configuring it with AVOptions. + * + * To free it use av_free() + */ +AVDCT *avcodec_dct_alloc(void); +int avcodec_dct_init(AVDCT *); + +const AVClass *avcodec_dct_get_class(void); + +#endif /* AVCODEC_AVDCT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avfft.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avfft.c new file mode 100644 index 0000000000..2200f37708 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avfft.c @@ -0,0 +1,145 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/mem.h" +#include "avfft.h" +#include "fft.h" +#include "rdft.h" +#include "dct.h" + +/* FFT */ + +FFTContext *av_fft_init(int nbits, int inverse) +{ + FFTContext *s = av_mallocz(sizeof(*s)); + + if (s && ff_fft_init(s, nbits, inverse)) + av_freep(&s); + + return s; +} + +void av_fft_permute(FFTContext *s, FFTComplex *z) +{ + s->fft_permute(s, z); +} + +void av_fft_calc(FFTContext *s, FFTComplex *z) +{ + s->fft_calc(s, z); +} + +av_cold void av_fft_end(FFTContext *s) +{ + if (s) { + ff_fft_end(s); + av_free(s); + } +} + +#if CONFIG_MDCT + +FFTContext *av_mdct_init(int nbits, int inverse, double scale) +{ + FFTContext *s = av_malloc(sizeof(*s)); + + if (s && ff_mdct_init(s, nbits, inverse, scale)) + av_freep(&s); + + return s; +} + +void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + s->imdct_calc(s, output, input); +} + +void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + s->imdct_half(s, output, input); +} + +void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + s->mdct_calc(s, output, input); +} + +av_cold void av_mdct_end(FFTContext *s) +{ + if (s) { + ff_mdct_end(s); + av_free(s); + } +} + +#endif /* CONFIG_MDCT */ + +#if CONFIG_RDFT + +RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans) +{ + RDFTContext *s = av_malloc(sizeof(*s)); + + if (s && ff_rdft_init(s, nbits, trans)) + av_freep(&s); + + return s; +} + +void av_rdft_calc(RDFTContext *s, FFTSample *data) +{ + s->rdft_calc(s, data); +} + +av_cold void av_rdft_end(RDFTContext *s) +{ + if (s) { + ff_rdft_end(s); + av_free(s); + } +} + +#endif /* CONFIG_RDFT */ + +#if CONFIG_DCT + +DCTContext *av_dct_init(int nbits, enum DCTTransformType inverse) +{ + DCTContext *s = av_malloc(sizeof(*s)); + + if (s && ff_dct_init(s, nbits, inverse)) + av_freep(&s); + + return s; +} + +void av_dct_calc(DCTContext *s, FFTSample *data) +{ + s->dct_calc(s, data); +} + +av_cold void av_dct_end(DCTContext *s) +{ + if (s) { + ff_dct_end(s); + av_free(s); + } +} + +#endif /* CONFIG_DCT */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avfft.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avfft.h new file mode 100644 index 0000000000..0c0f9b8d8d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avfft.h @@ -0,0 +1,118 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVFFT_H +#define AVCODEC_AVFFT_H + +/** + * @file + * @ingroup lavc_fft + * FFT functions + */ + +/** + * @defgroup lavc_fft FFT functions + * @ingroup lavc_misc + * + * @{ + */ + +typedef float FFTSample; + +typedef struct FFTComplex { + FFTSample re, im; +} FFTComplex; + +typedef struct FFTContext FFTContext; + +/** + * Set up a complex FFT. + * @param nbits log2 of the length of the input array + * @param inverse if 0 perform the forward transform, if 1 perform the inverse + */ +FFTContext *av_fft_init(int nbits, int inverse); + +/** + * Do the permutation needed BEFORE calling ff_fft_calc(). + */ +void av_fft_permute(FFTContext *s, FFTComplex *z); + +/** + * Do a complex FFT with the parameters defined in av_fft_init(). The + * input data must be permuted before. No 1.0/sqrt(n) normalization is done. + */ +void av_fft_calc(FFTContext *s, FFTComplex *z); + +void av_fft_end(FFTContext *s); + +FFTContext *av_mdct_init(int nbits, int inverse, double scale); +void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_end(FFTContext *s); + +/* Real Discrete Fourier Transform */ + +enum RDFTransformType { + DFT_R2C, + IDFT_C2R, + IDFT_R2C, + DFT_C2R, +}; + +typedef struct RDFTContext RDFTContext; + +/** + * Set up a real FFT. + * @param nbits log2 of the length of the input array + * @param trans the type of transform + */ +RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans); +void av_rdft_calc(RDFTContext *s, FFTSample *data); +void av_rdft_end(RDFTContext *s); + +/* Discrete Cosine Transform */ + +typedef struct DCTContext DCTContext; + +enum DCTTransformType { + DCT_II = 0, + DCT_III, + DCT_I, + DST_I, +}; + +/** + * Set up DCT. + * + * @param nbits size of the input array: + * (1 << nbits) for DCT-II, DCT-III and DST-I + * (1 << nbits) + 1 for DCT-I + * @param type the type of transform + * + * @note the first element of the input of DST-I is ignored + */ +DCTContext *av_dct_init(int nbits, enum DCTTransformType type); +void av_dct_calc(DCTContext *s, FFTSample *data); +void av_dct_end (DCTContext *s); + +/** + * @} + */ + +#endif /* AVCODEC_AVFFT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avpacket.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avpacket.c new file mode 100644 index 0000000000..2b20067211 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/avpacket.c @@ -0,0 +1,743 @@ +/* + * AVPacket functions for libavcodec + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/internal.h" +#include "libavutil/mathematics.h" +#include "libavutil/mem.h" +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" + +void av_init_packet(AVPacket *pkt) +{ + pkt->pts = AV_NOPTS_VALUE; + pkt->dts = AV_NOPTS_VALUE; + pkt->pos = -1; + pkt->duration = 0; +#if FF_API_CONVERGENCE_DURATION +FF_DISABLE_DEPRECATION_WARNINGS + pkt->convergence_duration = 0; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + pkt->flags = 0; + pkt->stream_index = 0; + pkt->buf = NULL; + pkt->side_data = NULL; + pkt->side_data_elems = 0; +} + +AVPacket *av_packet_alloc(void) +{ + AVPacket *pkt = av_mallocz(sizeof(AVPacket)); + if (!pkt) + return pkt; + + av_packet_unref(pkt); + + return pkt; +} + +void av_packet_free(AVPacket **pkt) +{ + if (!pkt || !*pkt) + return; + + av_packet_unref(*pkt); + av_freep(pkt); +} + +static int packet_alloc(AVBufferRef **buf, int size) +{ + int ret; + if (size < 0 || size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) + return AVERROR(EINVAL); + + ret = av_buffer_realloc(buf, size + AV_INPUT_BUFFER_PADDING_SIZE); + if (ret < 0) + return ret; + + memset((*buf)->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + return 0; +} + +int av_new_packet(AVPacket *pkt, int size) +{ + AVBufferRef *buf = NULL; + int ret = packet_alloc(&buf, size); + if (ret < 0) + return ret; + + av_init_packet(pkt); + pkt->buf = buf; + pkt->data = buf->data; + pkt->size = size; + + return 0; +} + +void av_shrink_packet(AVPacket *pkt, int size) +{ + if (pkt->size <= size) + return; + pkt->size = size; + memset(pkt->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); +} + +int av_grow_packet(AVPacket *pkt, int grow_by) +{ + int new_size; + av_assert0((unsigned)pkt->size <= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE); + if ((unsigned)grow_by > + INT_MAX - (pkt->size + AV_INPUT_BUFFER_PADDING_SIZE)) + return AVERROR(ENOMEM); + + new_size = pkt->size + grow_by + AV_INPUT_BUFFER_PADDING_SIZE; + if (pkt->buf) { + size_t data_offset; + uint8_t *old_data = pkt->data; + if (pkt->data == NULL) { + data_offset = 0; + pkt->data = pkt->buf->data; + } else { + data_offset = pkt->data - pkt->buf->data; + if (data_offset > INT_MAX - new_size) + return AVERROR(ENOMEM); + } + + if (new_size + data_offset > pkt->buf->size) { + int ret = av_buffer_realloc(&pkt->buf, new_size + data_offset); + if (ret < 0) { + pkt->data = old_data; + return ret; + } + pkt->data = pkt->buf->data + data_offset; + } + } else { + pkt->buf = av_buffer_alloc(new_size); + if (!pkt->buf) + return AVERROR(ENOMEM); + if (pkt->size > 0) + memcpy(pkt->buf->data, pkt->data, pkt->size); + pkt->data = pkt->buf->data; + } + pkt->size += grow_by; + memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + return 0; +} + +int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size) +{ + if (size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) + return AVERROR(EINVAL); + + pkt->buf = av_buffer_create(data, size + AV_INPUT_BUFFER_PADDING_SIZE, + av_buffer_default_free, NULL, 0); + if (!pkt->buf) + return AVERROR(ENOMEM); + + pkt->data = data; + pkt->size = size; + + return 0; +} + +#if FF_API_AVPACKET_OLD_API +FF_DISABLE_DEPRECATION_WARNINGS +#define ALLOC_MALLOC(data, size) data = av_malloc(size) +#define ALLOC_BUF(data, size) \ +do { \ + av_buffer_realloc(&pkt->buf, size); \ + data = pkt->buf ? pkt->buf->data : NULL; \ +} while (0) + +#define DUP_DATA(dst, src, size, padding, ALLOC) \ + do { \ + void *data; \ + if (padding) { \ + if ((unsigned)(size) > \ + (unsigned)(size) + AV_INPUT_BUFFER_PADDING_SIZE) \ + goto failed_alloc; \ + ALLOC(data, size + AV_INPUT_BUFFER_PADDING_SIZE); \ + } else { \ + ALLOC(data, size); \ + } \ + if (!data) \ + goto failed_alloc; \ + memcpy(data, src, size); \ + if (padding) \ + memset((uint8_t *)data + size, 0, \ + AV_INPUT_BUFFER_PADDING_SIZE); \ + dst = data; \ + } while (0) + +/* Makes duplicates of data, side_data, but does not copy any other fields */ +static int copy_packet_data(AVPacket *pkt, const AVPacket *src, int dup) +{ + pkt->data = NULL; + pkt->side_data = NULL; + pkt->side_data_elems = 0; + if (pkt->buf) { + AVBufferRef *ref = av_buffer_ref(src->buf); + if (!ref) + return AVERROR(ENOMEM); + pkt->buf = ref; + pkt->data = ref->data; + } else { + DUP_DATA(pkt->data, src->data, pkt->size, 1, ALLOC_BUF); + } + if (src->side_data_elems && dup) { + pkt->side_data = src->side_data; + pkt->side_data_elems = src->side_data_elems; + } + if (src->side_data_elems && !dup) { + return av_copy_packet_side_data(pkt, src); + } + return 0; + +failed_alloc: + av_packet_unref(pkt); + return AVERROR(ENOMEM); +} + +int av_copy_packet_side_data(AVPacket *pkt, const AVPacket *src) +{ + if (src->side_data_elems) { + int i; + DUP_DATA(pkt->side_data, src->side_data, + src->side_data_elems * sizeof(*src->side_data), 0, ALLOC_MALLOC); + if (src != pkt) { + memset(pkt->side_data, 0, + src->side_data_elems * sizeof(*src->side_data)); + } + for (i = 0; i < src->side_data_elems; i++) { + DUP_DATA(pkt->side_data[i].data, src->side_data[i].data, + src->side_data[i].size, 1, ALLOC_MALLOC); + pkt->side_data[i].size = src->side_data[i].size; + pkt->side_data[i].type = src->side_data[i].type; + } + } + pkt->side_data_elems = src->side_data_elems; + return 0; + +failed_alloc: + av_packet_unref(pkt); + return AVERROR(ENOMEM); +} + +int av_dup_packet(AVPacket *pkt) +{ + AVPacket tmp_pkt; + + if (!pkt->buf && pkt->data) { + tmp_pkt = *pkt; + return copy_packet_data(pkt, &tmp_pkt, 1); + } + return 0; +} + +int av_copy_packet(AVPacket *dst, const AVPacket *src) +{ + *dst = *src; + return copy_packet_data(dst, src, 0); +} +FF_ENABLE_DEPRECATION_WARNINGS +#endif + +void av_packet_free_side_data(AVPacket *pkt) +{ + int i; + for (i = 0; i < pkt->side_data_elems; i++) + av_freep(&pkt->side_data[i].data); + av_freep(&pkt->side_data); + pkt->side_data_elems = 0; +} + +#if FF_API_AVPACKET_OLD_API +FF_DISABLE_DEPRECATION_WARNINGS +void av_free_packet(AVPacket *pkt) +{ + if (pkt) { + if (pkt->buf) + av_buffer_unref(&pkt->buf); + pkt->data = NULL; + pkt->size = 0; + + av_packet_free_side_data(pkt); + } +} +FF_ENABLE_DEPRECATION_WARNINGS +#endif + +int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + uint8_t *data, size_t size) +{ + AVPacketSideData *tmp; + int i, elems = pkt->side_data_elems; + + for (i = 0; i < elems; i++) { + AVPacketSideData *sd = &pkt->side_data[i]; + + if (sd->type == type) { + av_free(sd->data); + sd->data = data; + sd->size = size; + return 0; + } + } + + if ((unsigned)elems + 1 > AV_PKT_DATA_NB) + return AVERROR(ERANGE); + + tmp = av_realloc(pkt->side_data, (elems + 1) * sizeof(*tmp)); + if (!tmp) + return AVERROR(ENOMEM); + + pkt->side_data = tmp; + pkt->side_data[elems].data = data; + pkt->side_data[elems].size = size; + pkt->side_data[elems].type = type; + pkt->side_data_elems++; + + return 0; +} + + +uint8_t *av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size) +{ + int ret; + uint8_t *data; + + if ((unsigned)size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) + return NULL; + data = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!data) + return NULL; + + ret = av_packet_add_side_data(pkt, type, data, size); + if (ret < 0) { + av_freep(&data); + return NULL; + } + + return data; +} + +uint8_t *av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type, + int *size) +{ + int i; + + for (i = 0; i < pkt->side_data_elems; i++) { + if (pkt->side_data[i].type == type) { + if (size) + *size = pkt->side_data[i].size; + return pkt->side_data[i].data; + } + } + if (size) + *size = 0; + return NULL; +} + +const char *av_packet_side_data_name(enum AVPacketSideDataType type) +{ + switch(type) { + case AV_PKT_DATA_PALETTE: return "Palette"; + case AV_PKT_DATA_NEW_EXTRADATA: return "New Extradata"; + case AV_PKT_DATA_PARAM_CHANGE: return "Param Change"; + case AV_PKT_DATA_H263_MB_INFO: return "H263 MB Info"; + case AV_PKT_DATA_REPLAYGAIN: return "Replay Gain"; + case AV_PKT_DATA_DISPLAYMATRIX: return "Display Matrix"; + case AV_PKT_DATA_STEREO3D: return "Stereo 3D"; + case AV_PKT_DATA_AUDIO_SERVICE_TYPE: return "Audio Service Type"; + case AV_PKT_DATA_QUALITY_STATS: return "Quality stats"; + case AV_PKT_DATA_FALLBACK_TRACK: return "Fallback track"; + case AV_PKT_DATA_CPB_PROPERTIES: return "CPB properties"; + case AV_PKT_DATA_SKIP_SAMPLES: return "Skip Samples"; + case AV_PKT_DATA_JP_DUALMONO: return "JP Dual Mono"; + case AV_PKT_DATA_STRINGS_METADATA: return "Strings Metadata"; + case AV_PKT_DATA_SUBTITLE_POSITION: return "Subtitle Position"; + case AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL: return "Matroska BlockAdditional"; + case AV_PKT_DATA_WEBVTT_IDENTIFIER: return "WebVTT ID"; + case AV_PKT_DATA_WEBVTT_SETTINGS: return "WebVTT Settings"; + case AV_PKT_DATA_METADATA_UPDATE: return "Metadata Update"; + case AV_PKT_DATA_MPEGTS_STREAM_ID: return "MPEGTS Stream ID"; + case AV_PKT_DATA_MASTERING_DISPLAY_METADATA: return "Mastering display metadata"; + case AV_PKT_DATA_CONTENT_LIGHT_LEVEL: return "Content light level metadata"; + case AV_PKT_DATA_SPHERICAL: return "Spherical Mapping"; + case AV_PKT_DATA_A53_CC: return "A53 Closed Captions"; + case AV_PKT_DATA_ENCRYPTION_INIT_INFO: return "Encryption initialization data"; + case AV_PKT_DATA_ENCRYPTION_INFO: return "Encryption info"; + case AV_PKT_DATA_AFD: return "Active Format Description data"; + } + return NULL; +} + +#if FF_API_MERGE_SD_API + +#define FF_MERGE_MARKER 0x8c4d9d108e25e9feULL + +int av_packet_merge_side_data(AVPacket *pkt){ + if(pkt->side_data_elems){ + AVBufferRef *buf; + int i; + uint8_t *p; + uint64_t size= pkt->size + 8LL + AV_INPUT_BUFFER_PADDING_SIZE; + AVPacket old= *pkt; + for (i=0; i INT_MAX) + return AVERROR(EINVAL); + buf = av_buffer_alloc(size); + if (!buf) + return AVERROR(ENOMEM); + pkt->buf = buf; + pkt->data = p = buf->data; + pkt->size = size - AV_INPUT_BUFFER_PADDING_SIZE; + bytestream_put_buffer(&p, old.data, old.size); + for (i=old.side_data_elems-1; i>=0; i--) { + bytestream_put_buffer(&p, old.side_data[i].data, old.side_data[i].size); + bytestream_put_be32(&p, old.side_data[i].size); + *p++ = old.side_data[i].type | ((i==old.side_data_elems-1)*128); + } + bytestream_put_be64(&p, FF_MERGE_MARKER); + av_assert0(p-pkt->data == pkt->size); + memset(p, 0, AV_INPUT_BUFFER_PADDING_SIZE); + av_packet_unref(&old); + pkt->side_data_elems = 0; + pkt->side_data = NULL; + return 1; + } + return 0; +} + +int av_packet_split_side_data(AVPacket *pkt){ + if (!pkt->side_data_elems && pkt->size >12 && AV_RB64(pkt->data + pkt->size - 8) == FF_MERGE_MARKER){ + int i; + unsigned int size; + uint8_t *p; + + p = pkt->data + pkt->size - 8 - 5; + for (i=1; ; i++){ + size = AV_RB32(p); + if (size>INT_MAX - 5 || p - pkt->data < size) + return 0; + if (p[4]&128) + break; + if (p - pkt->data < size + 5) + return 0; + p-= size+5; + } + + if (i > AV_PKT_DATA_NB) + return AVERROR(ERANGE); + + pkt->side_data = av_malloc_array(i, sizeof(*pkt->side_data)); + if (!pkt->side_data) + return AVERROR(ENOMEM); + + p= pkt->data + pkt->size - 8 - 5; + for (i=0; ; i++){ + size= AV_RB32(p); + av_assert0(size<=INT_MAX - 5 && p - pkt->data >= size); + pkt->side_data[i].data = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); + pkt->side_data[i].size = size; + pkt->side_data[i].type = p[4]&127; + if (!pkt->side_data[i].data) + return AVERROR(ENOMEM); + memcpy(pkt->side_data[i].data, p-size, size); + pkt->size -= size + 5; + if(p[4]&128) + break; + p-= size+5; + } + pkt->size -= 8; + pkt->side_data_elems = i+1; + return 1; + } + return 0; +} +#endif + +uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size) +{ + AVDictionaryEntry *t = NULL; + uint8_t *data = NULL; + *size = 0; + + if (!dict) + return NULL; + + while ((t = av_dict_get(dict, "", t, AV_DICT_IGNORE_SUFFIX))) { + const size_t keylen = strlen(t->key); + const size_t valuelen = strlen(t->value); + const size_t new_size = *size + keylen + 1 + valuelen + 1; + uint8_t *const new_data = av_realloc(data, new_size); + + if (!new_data) + goto fail; + data = new_data; + if (new_size > INT_MAX) + goto fail; + + memcpy(data + *size, t->key, keylen + 1); + memcpy(data + *size + keylen + 1, t->value, valuelen + 1); + + *size = new_size; + } + + return data; + +fail: + av_freep(&data); + *size = 0; + return NULL; +} + +int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict) +{ + const uint8_t *end; + int ret = 0; + + if (!dict || !data || !size) + return ret; + end = data + size; + if (size && end[-1]) + return AVERROR_INVALIDDATA; + while (data < end) { + const uint8_t *key = data; + const uint8_t *val = data + strlen(key) + 1; + + if (val >= end || !*key) + return AVERROR_INVALIDDATA; + + ret = av_dict_set(dict, key, val, 0); + if (ret < 0) + break; + data = val + strlen(val) + 1; + } + + return ret; +} + +int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size) +{ + int i; + + for (i = 0; i < pkt->side_data_elems; i++) { + if (pkt->side_data[i].type == type) { + if (size > pkt->side_data[i].size) + return AVERROR(ENOMEM); + pkt->side_data[i].size = size; + return 0; + } + } + return AVERROR(ENOENT); +} + +int av_packet_copy_props(AVPacket *dst, const AVPacket *src) +{ + int i; + + dst->pts = src->pts; + dst->dts = src->dts; + dst->pos = src->pos; + dst->duration = src->duration; +#if FF_API_CONVERGENCE_DURATION +FF_DISABLE_DEPRECATION_WARNINGS + dst->convergence_duration = src->convergence_duration; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + dst->flags = src->flags; + dst->stream_index = src->stream_index; + + dst->side_data = NULL; + dst->side_data_elems = 0; + for (i = 0; i < src->side_data_elems; i++) { + enum AVPacketSideDataType type = src->side_data[i].type; + int size = src->side_data[i].size; + uint8_t *src_data = src->side_data[i].data; + uint8_t *dst_data = av_packet_new_side_data(dst, type, size); + + if (!dst_data) { + av_packet_free_side_data(dst); + return AVERROR(ENOMEM); + } + memcpy(dst_data, src_data, size); + } + + return 0; +} + +void av_packet_unref(AVPacket *pkt) +{ + av_packet_free_side_data(pkt); + av_buffer_unref(&pkt->buf); + av_init_packet(pkt); + pkt->data = NULL; + pkt->size = 0; +} + +int av_packet_ref(AVPacket *dst, const AVPacket *src) +{ + int ret; + + ret = av_packet_copy_props(dst, src); + if (ret < 0) + return ret; + + if (!src->buf) { + ret = packet_alloc(&dst->buf, src->size); + if (ret < 0) + goto fail; + av_assert1(!src->size || src->data); + if (src->size) + memcpy(dst->buf->data, src->data, src->size); + + dst->data = dst->buf->data; + } else { + dst->buf = av_buffer_ref(src->buf); + if (!dst->buf) { + ret = AVERROR(ENOMEM); + goto fail; + } + dst->data = src->data; + } + + dst->size = src->size; + + return 0; +fail: + av_packet_free_side_data(dst); + return ret; +} + +AVPacket *av_packet_clone(const AVPacket *src) +{ + AVPacket *ret = av_packet_alloc(); + + if (!ret) + return ret; + + if (av_packet_ref(ret, src)) + av_packet_free(&ret); + + return ret; +} + +void av_packet_move_ref(AVPacket *dst, AVPacket *src) +{ + *dst = *src; + av_init_packet(src); + src->data = NULL; + src->size = 0; +} + +int av_packet_make_refcounted(AVPacket *pkt) +{ + int ret; + + if (pkt->buf) + return 0; + + ret = packet_alloc(&pkt->buf, pkt->size); + if (ret < 0) + return ret; + av_assert1(!pkt->size || pkt->data); + if (pkt->size) + memcpy(pkt->buf->data, pkt->data, pkt->size); + + pkt->data = pkt->buf->data; + + return 0; +} + +int av_packet_make_writable(AVPacket *pkt) +{ + AVBufferRef *buf = NULL; + int ret; + + if (pkt->buf && av_buffer_is_writable(pkt->buf)) + return 0; + + ret = packet_alloc(&buf, pkt->size); + if (ret < 0) + return ret; + av_assert1(!pkt->size || pkt->data); + if (pkt->size) + memcpy(buf->data, pkt->data, pkt->size); + + av_buffer_unref(&pkt->buf); + pkt->buf = buf; + pkt->data = buf->data; + + return 0; +} + +void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb) +{ + if (pkt->pts != AV_NOPTS_VALUE) + pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb); + if (pkt->dts != AV_NOPTS_VALUE) + pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb); + if (pkt->duration > 0) + pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb); +#if FF_API_CONVERGENCE_DURATION +FF_DISABLE_DEPRECATION_WARNINGS + if (pkt->convergence_duration > 0) + pkt->convergence_duration = av_rescale_q(pkt->convergence_duration, src_tb, dst_tb); +FF_ENABLE_DEPRECATION_WARNINGS +#endif +} + +int ff_side_data_set_encoder_stats(AVPacket *pkt, int quality, int64_t *error, int error_count, int pict_type) +{ + uint8_t *side_data; + int side_data_size; + int i; + + side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, &side_data_size); + if (!side_data) { + side_data_size = 4+4+8*error_count; + side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, + side_data_size); + } + + if (!side_data || side_data_size < 4+4+8*error_count) + return AVERROR(ENOMEM); + + AV_WL32(side_data , quality ); + side_data[4] = pict_type; + side_data[5] = error_count; + for (i = 0; idata, picture->linesize, + ptr, pix_fmt, width, height, 1); +} + +int avpicture_layout(const AVPicture* src, enum AVPixelFormat pix_fmt, int width, int height, + unsigned char *dest, int dest_size) +{ + return av_image_copy_to_buffer(dest, dest_size, + (const uint8_t * const*)src->data, src->linesize, + pix_fmt, width, height, 1); +} + +int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height) +{ + return av_image_get_buffer_size(pix_fmt, width, height, 1); +} + +int avpicture_alloc(AVPicture *picture, + enum AVPixelFormat pix_fmt, int width, int height) +{ + int ret = av_image_alloc(picture->data, picture->linesize, + width, height, pix_fmt, 1); + if (ret < 0) { + memset(picture, 0, sizeof(AVPicture)); + return ret; + } + + return 0; +} + +void avpicture_free(AVPicture *picture) +{ + av_freep(&picture->data[0]); +} + +void av_picture_copy(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int width, int height) +{ + av_image_copy(dst->data, dst->linesize, (const uint8_t **)src->data, + src->linesize, pix_fmt, width, height); +} +FF_ENABLE_DEPRECATION_WARNINGS +#endif /* FF_API_AVPICTURE */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream.c new file mode 100644 index 0000000000..be8a0f634d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream.c @@ -0,0 +1,362 @@ +/* + * Common bit i/o utils + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * Copyright (c) 2010 Loren Merritt + * + * alternative bitstream reader & writer by Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * bitstream api. + */ + +#include "libavutil/avassert.h" +#include "libavutil/qsort.h" +#include "avcodec.h" +#include "internal.h" +#include "mathops.h" +#include "put_bits.h" +#include "vlc.h" + +const uint8_t ff_log2_run[41]={ + 0, 0, 0, 0, 1, 1, 1, 1, + 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, + 8, 9,10,11,12,13,14,15, +16,17,18,19,20,21,22,23, +24, +}; + +void avpriv_align_put_bits(PutBitContext *s) +{ + put_bits(s, s->bit_left & 7, 0); +} + +void avpriv_put_string(PutBitContext *pb, const char *string, + int terminate_string) +{ + while (*string) { + put_bits(pb, 8, *string); + string++; + } + if (terminate_string) + put_bits(pb, 8, 0); +} + +void avpriv_copy_bits(PutBitContext *pb, const uint8_t *src, int length) +{ + int words = length >> 4; + int bits = length & 15; + int i; + + if (length == 0) + return; + + av_assert0(length <= put_bits_left(pb)); + + if (CONFIG_SMALL || words < 16 || put_bits_count(pb) & 7) { + for (i = 0; i < words; i++) + put_bits(pb, 16, AV_RB16(src + 2 * i)); + } else { + for (i = 0; put_bits_count(pb) & 31; i++) + put_bits(pb, 8, src[i]); + flush_put_bits(pb); + memcpy(put_bits_ptr(pb), src + i, 2 * words - i); + skip_put_bytes(pb, 2 * words - i); + } + + put_bits(pb, bits, AV_RB16(src + 2 * words) >> (16 - bits)); +} + +/* VLC decoding */ + +#define GET_DATA(v, table, i, wrap, size) \ +{ \ + const uint8_t *ptr = (const uint8_t *)table + i * wrap; \ + switch(size) { \ + case 1: \ + v = *(const uint8_t *)ptr; \ + break; \ + case 2: \ + v = *(const uint16_t *)ptr; \ + break; \ + case 4: \ + v = *(const uint32_t *)ptr; \ + break; \ + default: \ + av_assert1(0); \ + } \ +} + + +static int alloc_table(VLC *vlc, int size, int use_static) +{ + int index = vlc->table_size; + + vlc->table_size += size; + if (vlc->table_size > vlc->table_allocated) { + if (use_static) + abort(); // cannot do anything, init_vlc() is used with too little memory + vlc->table_allocated += (1 << vlc->bits); + vlc->table = av_realloc_f(vlc->table, vlc->table_allocated, sizeof(VLC_TYPE) * 2); + if (!vlc->table) { + vlc->table_allocated = 0; + vlc->table_size = 0; + return AVERROR(ENOMEM); + } + memset(vlc->table + vlc->table_allocated - (1 << vlc->bits), 0, sizeof(VLC_TYPE) * 2 << vlc->bits); + } + return index; +} + +typedef struct VLCcode { + uint8_t bits; + uint16_t symbol; + /** codeword, with the first bit-to-be-read in the msb + * (even if intended for a little-endian bitstream reader) */ + uint32_t code; +} VLCcode; + +static int compare_vlcspec(const void *a, const void *b) +{ + const VLCcode *sa = a, *sb = b; + return (sa->code >> 1) - (sb->code >> 1); +} +/** + * Build VLC decoding tables suitable for use with get_vlc(). + * + * @param vlc the context to be initialized + * + * @param table_nb_bits max length of vlc codes to store directly in this table + * (Longer codes are delegated to subtables.) + * + * @param nb_codes number of elements in codes[] + * + * @param codes descriptions of the vlc codes + * These must be ordered such that codes going into the same subtable are contiguous. + * Sorting by VLCcode.code is sufficient, though not necessary. + */ +static int build_table(VLC *vlc, int table_nb_bits, int nb_codes, + VLCcode *codes, int flags) +{ + int table_size, table_index, index, code_prefix, symbol, subtable_bits; + int i, j, k, n, nb, inc; + uint32_t code; + volatile VLC_TYPE (* volatile table)[2]; // the double volatile is needed to prevent an internal compiler error in gcc 4.2 + + table_size = 1 << table_nb_bits; + if (table_nb_bits > 30) + return AVERROR(EINVAL); + table_index = alloc_table(vlc, table_size, flags & INIT_VLC_USE_NEW_STATIC); + ff_dlog(NULL, "new table index=%d size=%d\n", table_index, table_size); + if (table_index < 0) + return table_index; + table = (volatile VLC_TYPE (*)[2])&vlc->table[table_index]; + + /* first pass: map codes and compute auxiliary table sizes */ + for (i = 0; i < nb_codes; i++) { + n = codes[i].bits; + code = codes[i].code; + symbol = codes[i].symbol; + ff_dlog(NULL, "i=%d n=%d code=0x%"PRIx32"\n", i, n, code); + if (n <= table_nb_bits) { + /* no need to add another table */ + j = code >> (32 - table_nb_bits); + nb = 1 << (table_nb_bits - n); + inc = 1; + if (flags & INIT_VLC_LE) { + j = bitswap_32(code); + inc = 1 << n; + } + for (k = 0; k < nb; k++) { + int bits = table[j][1]; + int oldsym = table[j][0]; + ff_dlog(NULL, "%4x: code=%d n=%d\n", j, i, n); + if ((bits || oldsym) && (bits != n || oldsym != symbol)) { + av_log(NULL, AV_LOG_ERROR, "incorrect codes\n"); + return AVERROR_INVALIDDATA; + } + table[j][1] = n; //bits + table[j][0] = symbol; + j += inc; + } + } else { + /* fill auxiliary table recursively */ + n -= table_nb_bits; + code_prefix = code >> (32 - table_nb_bits); + subtable_bits = n; + codes[i].bits = n; + codes[i].code = code << table_nb_bits; + for (k = i+1; k < nb_codes; k++) { + n = codes[k].bits - table_nb_bits; + if (n <= 0) + break; + code = codes[k].code; + if (code >> (32 - table_nb_bits) != code_prefix) + break; + codes[k].bits = n; + codes[k].code = code << table_nb_bits; + subtable_bits = FFMAX(subtable_bits, n); + } + subtable_bits = FFMIN(subtable_bits, table_nb_bits); + j = (flags & INIT_VLC_LE) ? bitswap_32(code_prefix) >> (32 - table_nb_bits) : code_prefix; + table[j][1] = -subtable_bits; + ff_dlog(NULL, "%4x: n=%d (subtable)\n", + j, codes[i].bits + table_nb_bits); + index = build_table(vlc, subtable_bits, k-i, codes+i, flags); + if (index < 0) + return index; + /* note: realloc has been done, so reload tables */ + table = (volatile VLC_TYPE (*)[2])&vlc->table[table_index]; + table[j][0] = index; //code + if (table[j][0] != index) { + avpriv_request_sample(NULL, "strange codes"); + return AVERROR_PATCHWELCOME; + } + i = k-1; + } + } + + for (i = 0; i < table_size; i++) { + if (table[i][1] == 0) //bits + table[i][0] = -1; //codes + } + + return table_index; +} + + +/* Build VLC decoding tables suitable for use with get_vlc(). + + 'nb_bits' sets the decoding table size (2^nb_bits) entries. The + bigger it is, the faster is the decoding. But it should not be too + big to save memory and L1 cache. '9' is a good compromise. + + 'nb_codes' : number of vlcs codes + + 'bits' : table which gives the size (in bits) of each vlc code. + + 'codes' : table which gives the bit pattern of of each vlc code. + + 'symbols' : table which gives the values to be returned from get_vlc(). + + 'xxx_wrap' : give the number of bytes between each entry of the + 'bits' or 'codes' tables. + + 'xxx_size' : gives the number of bytes of each entry of the 'bits' + or 'codes' tables. Currently 1,2 and 4 are supported. + + 'wrap' and 'size' make it possible to use any memory configuration and types + (byte/word/long) to store the 'bits', 'codes', and 'symbols' tables. + + 'use_static' should be set to 1 for tables, which should be freed + with av_free_static(), 0 if ff_free_vlc() will be used. +*/ +int ff_init_vlc_sparse(VLC *vlc_arg, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags) +{ + VLCcode *buf; + int i, j, ret; + VLCcode localbuf[1500]; // the maximum currently needed is 1296 by rv34 + VLC localvlc, *vlc; + + vlc = vlc_arg; + vlc->bits = nb_bits; + if (flags & INIT_VLC_USE_NEW_STATIC) { + av_assert0(nb_codes + 1 <= FF_ARRAY_ELEMS(localbuf)); + buf = localbuf; + localvlc = *vlc_arg; + vlc = &localvlc; + vlc->table_size = 0; + } else { + vlc->table = NULL; + vlc->table_allocated = 0; + vlc->table_size = 0; + + buf = av_malloc_array((nb_codes + 1), sizeof(VLCcode)); + if (!buf) + return AVERROR(ENOMEM); + } + + + av_assert0(symbols_size <= 2 || !symbols); + j = 0; +#define COPY(condition)\ + for (i = 0; i < nb_codes; i++) { \ + GET_DATA(buf[j].bits, bits, i, bits_wrap, bits_size); \ + if (!(condition)) \ + continue; \ + if (buf[j].bits > 3*nb_bits || buf[j].bits>32) { \ + av_log(NULL, AV_LOG_ERROR, "Too long VLC (%d) in init_vlc\n", buf[j].bits);\ + if (!(flags & INIT_VLC_USE_NEW_STATIC)) \ + av_free(buf); \ + return AVERROR(EINVAL); \ + } \ + GET_DATA(buf[j].code, codes, i, codes_wrap, codes_size); \ + if (buf[j].code >= (1LL< nb_bits); + // qsort is the slowest part of init_vlc, and could probably be improved or avoided + AV_QSORT(buf, j, struct VLCcode, compare_vlcspec); + COPY(buf[j].bits && buf[j].bits <= nb_bits); + nb_codes = j; + + ret = build_table(vlc, nb_bits, nb_codes, buf, flags); + + if (flags & INIT_VLC_USE_NEW_STATIC) { + if(vlc->table_size != vlc->table_allocated) + av_log(NULL, AV_LOG_ERROR, "needed %d had %d\n", vlc->table_size, vlc->table_allocated); + + av_assert0(ret >= 0); + *vlc_arg = *vlc; + } else { + av_free(buf); + if (ret < 0) { + av_freep(&vlc->table); + return ret; + } + } + return 0; +} + + +void ff_free_vlc(VLC *vlc) +{ + av_freep(&vlc->table); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream_filter.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream_filter.c new file mode 100644 index 0000000000..ca11ed371e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream_filter.c @@ -0,0 +1,185 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "avcodec.h" +#include "libavutil/internal.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" + +#if FF_API_OLD_BSF +FF_DISABLE_DEPRECATION_WARNINGS + +const AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f) +{ + const AVBitStreamFilter *filter = NULL; + void *opaque = NULL; + + while (filter != f) + filter = av_bsf_iterate(&opaque); + + return av_bsf_iterate(&opaque); +} + +void av_register_bitstream_filter(AVBitStreamFilter *bsf) +{ +} + +typedef struct BSFCompatContext { + AVBSFContext *ctx; + int extradata_updated; +} BSFCompatContext; + +AVBitStreamFilterContext *av_bitstream_filter_init(const char *name) +{ + AVBitStreamFilterContext *ctx = NULL; + BSFCompatContext *priv = NULL; + const AVBitStreamFilter *bsf; + + bsf = av_bsf_get_by_name(name); + if (!bsf) + return NULL; + + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return NULL; + + priv = av_mallocz(sizeof(*priv)); + if (!priv) + goto fail; + + + ctx->filter = bsf; + ctx->priv_data = priv; + + return ctx; + +fail: + if (priv) + av_bsf_free(&priv->ctx); + av_freep(&priv); + av_freep(&ctx); + return NULL; +} + +void av_bitstream_filter_close(AVBitStreamFilterContext *bsfc) +{ + BSFCompatContext *priv; + + if (!bsfc) + return; + + priv = bsfc->priv_data; + + av_bsf_free(&priv->ctx); + av_freep(&bsfc->priv_data); + av_free(bsfc); +} + +int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const char *args, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe) +{ + BSFCompatContext *priv = bsfc->priv_data; + AVPacket pkt = { 0 }; + int ret; + + if (!priv->ctx) { + ret = av_bsf_alloc(bsfc->filter, &priv->ctx); + if (ret < 0) + return ret; + + ret = avcodec_parameters_from_context(priv->ctx->par_in, avctx); + if (ret < 0) + return ret; + + priv->ctx->time_base_in = avctx->time_base; + + if (bsfc->args && bsfc->filter->priv_class) { + const AVOption *opt = av_opt_next(priv->ctx->priv_data, NULL); + const char * shorthand[2] = {NULL}; + + if (opt) + shorthand[0] = opt->name; + + ret = av_opt_set_from_string(priv->ctx->priv_data, bsfc->args, shorthand, "=", ":"); + if (ret < 0) + return ret; + } + + ret = av_bsf_init(priv->ctx); + if (ret < 0) + return ret; + } + + pkt.data = (uint8_t *)buf; + pkt.size = buf_size; + + ret = av_bsf_send_packet(priv->ctx, &pkt); + if (ret < 0) + return ret; + + *poutbuf = NULL; + *poutbuf_size = 0; + + ret = av_bsf_receive_packet(priv->ctx, &pkt); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + return 0; + else if (ret < 0) + return ret; + + *poutbuf = av_malloc(pkt.size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!*poutbuf) { + av_packet_unref(&pkt); + return AVERROR(ENOMEM); + } + + *poutbuf_size = pkt.size; + memcpy(*poutbuf, pkt.data, pkt.size); + + av_packet_unref(&pkt); + + /* drain all the remaining packets we cannot return */ + while (ret >= 0) { + ret = av_bsf_receive_packet(priv->ctx, &pkt); + av_packet_unref(&pkt); + } + + if (!priv->extradata_updated) { + /* update extradata in avctx from the output codec parameters */ + if (priv->ctx->par_out->extradata_size && (!args || !strstr(args, "private_spspps_buf"))) { + av_freep(&avctx->extradata); + avctx->extradata_size = 0; + avctx->extradata = av_mallocz(priv->ctx->par_out->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) + return AVERROR(ENOMEM); + memcpy(avctx->extradata, priv->ctx->par_out->extradata, priv->ctx->par_out->extradata_size); + avctx->extradata_size = priv->ctx->par_out->extradata_size; + } + + priv->extradata_updated = 1; + } + + return 1; +} +FF_ENABLE_DEPRECATION_WARNINGS +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream_filters.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream_filters.c new file mode 100644 index 0000000000..463003966a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bitstream_filters.c @@ -0,0 +1,114 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/common.h" +#include "libavutil/log.h" + +#include "avcodec.h" +#include "bsf.h" + +extern const AVBitStreamFilter ff_aac_adtstoasc_bsf; +extern const AVBitStreamFilter ff_av1_frame_split_bsf; +extern const AVBitStreamFilter ff_av1_metadata_bsf; +extern const AVBitStreamFilter ff_chomp_bsf; +extern const AVBitStreamFilter ff_dump_extradata_bsf; +extern const AVBitStreamFilter ff_dca_core_bsf; +extern const AVBitStreamFilter ff_eac3_core_bsf; +extern const AVBitStreamFilter ff_extract_extradata_bsf; +extern const AVBitStreamFilter ff_filter_units_bsf; +extern const AVBitStreamFilter ff_h264_metadata_bsf; +extern const AVBitStreamFilter ff_h264_mp4toannexb_bsf; +extern const AVBitStreamFilter ff_h264_redundant_pps_bsf; +extern const AVBitStreamFilter ff_hapqa_extract_bsf; +extern const AVBitStreamFilter ff_hevc_metadata_bsf; +extern const AVBitStreamFilter ff_hevc_mp4toannexb_bsf; +extern const AVBitStreamFilter ff_imx_dump_header_bsf; +extern const AVBitStreamFilter ff_mjpeg2jpeg_bsf; +extern const AVBitStreamFilter ff_mjpega_dump_header_bsf; +extern const AVBitStreamFilter ff_mp3_header_decompress_bsf; +extern const AVBitStreamFilter ff_mpeg2_metadata_bsf; +extern const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf; +extern const AVBitStreamFilter ff_mov2textsub_bsf; +extern const AVBitStreamFilter ff_noise_bsf; +extern const AVBitStreamFilter ff_null_bsf; +extern const AVBitStreamFilter ff_prores_metadata_bsf; +extern const AVBitStreamFilter ff_remove_extradata_bsf; +extern const AVBitStreamFilter ff_text2movsub_bsf; +extern const AVBitStreamFilter ff_trace_headers_bsf; +extern const AVBitStreamFilter ff_truehd_core_bsf; +extern const AVBitStreamFilter ff_vp9_metadata_bsf; +extern const AVBitStreamFilter ff_vp9_raw_reorder_bsf; +extern const AVBitStreamFilter ff_vp9_superframe_bsf; +extern const AVBitStreamFilter ff_vp9_superframe_split_bsf; + +#include "libavcodec/bsf_list.c" + +const AVBitStreamFilter *av_bsf_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVBitStreamFilter *f = bitstream_filters[i]; + + if (f) + *opaque = (void*)(i + 1); + + return f; +} + +#if FF_API_NEXT +const AVBitStreamFilter *av_bsf_next(void **opaque) { + return av_bsf_iterate(opaque); +} +#endif + +const AVBitStreamFilter *av_bsf_get_by_name(const char *name) +{ + const AVBitStreamFilter *f = NULL; + void *i = 0; + + if (!name) + return NULL; + + while ((f = av_bsf_iterate(&i))) { + if (!strcmp(f->name, name)) + return f; + } + + return NULL; +} + +const AVClass *ff_bsf_child_class_next(const AVClass *prev) +{ + const AVBitStreamFilter *f = NULL; + void *i = 0; + + /* find the filter that corresponds to prev */ + while (prev && (f = av_bsf_iterate(&i))) { + if (f->priv_class == prev) { + break; + } + } + + /* find next filter with priv options */ + while ((f = av_bsf_iterate(&i))) { + if (f->priv_class) + return f->priv_class; + } + return NULL; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/blockdsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/blockdsp.c new file mode 100644 index 0000000000..c7efe7e77b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/blockdsp.c @@ -0,0 +1,78 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "avcodec.h" +#include "blockdsp.h" +#include "version.h" + +static void clear_block_c(int16_t *block) +{ + memset(block, 0, sizeof(int16_t) * 64); +} + +static void clear_blocks_c(int16_t *blocks) +{ + memset(blocks, 0, sizeof(int16_t) * 6 * 64); +} + +static void fill_block16_c(uint8_t *block, uint8_t value, ptrdiff_t line_size, + int h) +{ + int i; + + for (i = 0; i < h; i++) { + memset(block, value, 16); + block += line_size; + } +} + +static void fill_block8_c(uint8_t *block, uint8_t value, ptrdiff_t line_size, + int h) +{ + int i; + + for (i = 0; i < h; i++) { + memset(block, value, 8); + block += line_size; + } +} + +av_cold void ff_blockdsp_init(BlockDSPContext *c, AVCodecContext *avctx) +{ + c->clear_block = clear_block_c; + c->clear_blocks = clear_blocks_c; + + c->fill_block_tab[0] = fill_block16_c; + c->fill_block_tab[1] = fill_block8_c; + + if (ARCH_ALPHA) + ff_blockdsp_init_alpha(c); + if (ARCH_ARM) + ff_blockdsp_init_arm(c); + if (ARCH_PPC) + ff_blockdsp_init_ppc(c); + if (ARCH_X86) + ff_blockdsp_init_x86(c, avctx); + if (ARCH_MIPS) + ff_blockdsp_init_mips(c); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/blockdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/blockdsp.h new file mode 100644 index 0000000000..26fc2ea13b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/blockdsp.h @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_BLOCKDSP_H +#define AVCODEC_BLOCKDSP_H + +#include +#include + +#include "avcodec.h" +#include "version.h" + +/* add and put pixel (decoding) + * Block sizes for op_pixels_func are 8x4,8x8 16x8 16x16. + * h for op_pixels_func is limited to { width / 2, width }, + * but never larger than 16 and never smaller than 4. */ +typedef void (*op_fill_func)(uint8_t *block /* align width (8 or 16) */, + uint8_t value, ptrdiff_t line_size, int h); + +typedef struct BlockDSPContext { + void (*clear_block)(int16_t *block /* align 32 */); + void (*clear_blocks)(int16_t *blocks /* align 32 */); + + op_fill_func fill_block_tab[2]; +} BlockDSPContext; + +void ff_blockdsp_init(BlockDSPContext *c, AVCodecContext *avctx); + +void ff_blockdsp_init_alpha(BlockDSPContext *c); +void ff_blockdsp_init_arm(BlockDSPContext *c); +void ff_blockdsp_init_ppc(BlockDSPContext *c); +void ff_blockdsp_init_x86(BlockDSPContext *c, AVCodecContext *avctx); +void ff_blockdsp_init_mips(BlockDSPContext *c); + +#endif /* AVCODEC_BLOCKDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf.c new file mode 100644 index 0000000000..5081307603 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf.c @@ -0,0 +1,567 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/log.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/avstring.h" +#include "libavutil/bprint.h" + +#include "avcodec.h" +#include "bsf.h" + +struct AVBSFInternal { + AVPacket *buffer_pkt; + int eof; +}; + +void av_bsf_free(AVBSFContext **pctx) +{ + AVBSFContext *ctx; + + if (!pctx || !*pctx) + return; + ctx = *pctx; + + if (ctx->filter->close) + ctx->filter->close(ctx); + if (ctx->filter->priv_class && ctx->priv_data) + av_opt_free(ctx->priv_data); + + av_opt_free(ctx); + + av_packet_free(&ctx->internal->buffer_pkt); + av_freep(&ctx->internal); + av_freep(&ctx->priv_data); + + avcodec_parameters_free(&ctx->par_in); + avcodec_parameters_free(&ctx->par_out); + + av_freep(pctx); +} + +static void *bsf_child_next(void *obj, void *prev) +{ + AVBSFContext *ctx = obj; + if (!prev && ctx->filter->priv_class) + return ctx->priv_data; + return NULL; +} + +static const AVClass bsf_class = { + .class_name = "AVBSFContext", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .child_next = bsf_child_next, + .child_class_next = ff_bsf_child_class_next, +}; + +const AVClass *av_bsf_get_class(void) +{ + return &bsf_class; +} + +int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **pctx) +{ + AVBSFContext *ctx; + int ret; + + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return AVERROR(ENOMEM); + + ctx->av_class = &bsf_class; + ctx->filter = filter; + + ctx->par_in = avcodec_parameters_alloc(); + ctx->par_out = avcodec_parameters_alloc(); + if (!ctx->par_in || !ctx->par_out) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ctx->internal = av_mallocz(sizeof(*ctx->internal)); + if (!ctx->internal) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ctx->internal->buffer_pkt = av_packet_alloc(); + if (!ctx->internal->buffer_pkt) { + ret = AVERROR(ENOMEM); + goto fail; + } + + av_opt_set_defaults(ctx); + + /* allocate priv data and init private options */ + if (filter->priv_data_size) { + ctx->priv_data = av_mallocz(filter->priv_data_size); + if (!ctx->priv_data) { + ret = AVERROR(ENOMEM); + goto fail; + } + if (filter->priv_class) { + *(const AVClass **)ctx->priv_data = filter->priv_class; + av_opt_set_defaults(ctx->priv_data); + } + } + + *pctx = ctx; + return 0; +fail: + av_bsf_free(&ctx); + return ret; +} + +int av_bsf_init(AVBSFContext *ctx) +{ + int ret, i; + + /* check that the codec is supported */ + if (ctx->filter->codec_ids) { + for (i = 0; ctx->filter->codec_ids[i] != AV_CODEC_ID_NONE; i++) + if (ctx->par_in->codec_id == ctx->filter->codec_ids[i]) + break; + if (ctx->filter->codec_ids[i] == AV_CODEC_ID_NONE) { + const AVCodecDescriptor *desc = avcodec_descriptor_get(ctx->par_in->codec_id); + av_log(ctx, AV_LOG_ERROR, "Codec '%s' (%d) is not supported by the " + "bitstream filter '%s'. Supported codecs are: ", + desc ? desc->name : "unknown", ctx->par_in->codec_id, ctx->filter->name); + for (i = 0; ctx->filter->codec_ids[i] != AV_CODEC_ID_NONE; i++) { + desc = avcodec_descriptor_get(ctx->filter->codec_ids[i]); + av_log(ctx, AV_LOG_ERROR, "%s (%d) ", + desc ? desc->name : "unknown", ctx->filter->codec_ids[i]); + } + av_log(ctx, AV_LOG_ERROR, "\n"); + return AVERROR(EINVAL); + } + } + + /* initialize output parameters to be the same as input + * init below might overwrite that */ + ret = avcodec_parameters_copy(ctx->par_out, ctx->par_in); + if (ret < 0) + return ret; + + ctx->time_base_out = ctx->time_base_in; + + if (ctx->filter->init) { + ret = ctx->filter->init(ctx); + if (ret < 0) + return ret; + } + + return 0; +} + +void av_bsf_flush(AVBSFContext *ctx) +{ + ctx->internal->eof = 0; + + av_packet_unref(ctx->internal->buffer_pkt); + + if (ctx->filter->flush) + ctx->filter->flush(ctx); +} + +int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt) +{ + int ret; + + if (!pkt || (!pkt->data && !pkt->side_data_elems)) { + ctx->internal->eof = 1; + return 0; + } + + if (ctx->internal->eof) { + av_log(ctx, AV_LOG_ERROR, "A non-NULL packet sent after an EOF.\n"); + return AVERROR(EINVAL); + } + + if (ctx->internal->buffer_pkt->data || + ctx->internal->buffer_pkt->side_data_elems) + return AVERROR(EAGAIN); + + ret = av_packet_make_refcounted(pkt); + if (ret < 0) + return ret; + av_packet_move_ref(ctx->internal->buffer_pkt, pkt); + + return 0; +} + +int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt) +{ + return ctx->filter->filter(ctx, pkt); +} + +int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt) +{ + AVBSFInternal *in = ctx->internal; + AVPacket *tmp_pkt; + + if (in->eof) + return AVERROR_EOF; + + if (!ctx->internal->buffer_pkt->data && + !ctx->internal->buffer_pkt->side_data_elems) + return AVERROR(EAGAIN); + + tmp_pkt = av_packet_alloc(); + if (!tmp_pkt) + return AVERROR(ENOMEM); + + *pkt = ctx->internal->buffer_pkt; + ctx->internal->buffer_pkt = tmp_pkt; + + return 0; +} + +int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt) +{ + AVBSFInternal *in = ctx->internal; + + if (in->eof) + return AVERROR_EOF; + + if (!ctx->internal->buffer_pkt->data && + !ctx->internal->buffer_pkt->side_data_elems) + return AVERROR(EAGAIN); + + av_packet_move_ref(pkt, ctx->internal->buffer_pkt); + + return 0; +} + +typedef struct BSFListContext { + const AVClass *class; + + AVBSFContext **bsfs; + int nb_bsfs; + + unsigned idx; // index of currently processed BSF + unsigned flushed_idx; // index of BSF being flushed + + char * item_name; +} BSFListContext; + + +static int bsf_list_init(AVBSFContext *bsf) +{ + BSFListContext *lst = bsf->priv_data; + int ret, i; + const AVCodecParameters *cod_par = bsf->par_in; + AVRational tb = bsf->time_base_in; + + for (i = 0; i < lst->nb_bsfs; ++i) { + ret = avcodec_parameters_copy(lst->bsfs[i]->par_in, cod_par); + if (ret < 0) + goto fail; + + lst->bsfs[i]->time_base_in = tb; + + ret = av_bsf_init(lst->bsfs[i]); + if (ret < 0) + goto fail; + + cod_par = lst->bsfs[i]->par_out; + tb = lst->bsfs[i]->time_base_out; + } + + bsf->time_base_out = tb; + ret = avcodec_parameters_copy(bsf->par_out, cod_par); + +fail: + return ret; +} + +static int bsf_list_filter(AVBSFContext *bsf, AVPacket *out) +{ + BSFListContext *lst = bsf->priv_data; + int ret; + + if (!lst->nb_bsfs) + return ff_bsf_get_packet_ref(bsf, out); + + while (1) { + if (lst->idx > lst->flushed_idx) { + ret = av_bsf_receive_packet(lst->bsfs[lst->idx-1], out); + if (ret == AVERROR(EAGAIN)) { + /* no more packets from idx-1, try with previous */ + ret = 0; + lst->idx--; + continue; + } else if (ret == AVERROR_EOF) { + /* filter idx-1 is done, continue with idx...nb_bsfs */ + lst->flushed_idx = lst->idx; + continue; + }else if (ret < 0) { + /* filtering error */ + break; + } + } else { + ret = ff_bsf_get_packet_ref(bsf, out); + if (ret == AVERROR_EOF) { + lst->idx = lst->flushed_idx; + } else if (ret < 0) + break; + } + + if (lst->idx < lst->nb_bsfs) { + AVPacket *pkt; + if (ret == AVERROR_EOF && lst->idx == lst->flushed_idx) { + /* ff_bsf_get_packet_ref returned EOF and idx is first + * filter of yet not flushed filter chain */ + pkt = NULL; + } else { + pkt = out; + } + ret = av_bsf_send_packet(lst->bsfs[lst->idx], pkt); + if (ret < 0) + break; + lst->idx++; + } else { + /* The end of filter chain, break to return result */ + break; + } + } + + if (ret < 0) + av_packet_unref(out); + + return ret; +} + +static void bsf_list_flush(AVBSFContext *bsf) +{ + BSFListContext *lst = bsf->priv_data; + + for (int i = 0; i < lst->nb_bsfs; i++) + av_bsf_flush(lst->bsfs[i]); + lst->idx = lst->flushed_idx = 0; +} + +static void bsf_list_close(AVBSFContext *bsf) +{ + BSFListContext *lst = bsf->priv_data; + int i; + + for (i = 0; i < lst->nb_bsfs; ++i) + av_bsf_free(&lst->bsfs[i]); + av_freep(&lst->bsfs); + av_freep(&lst->item_name); +} + +static const char *bsf_list_item_name(void *ctx) +{ + static const char *null_filter_name = "null"; + AVBSFContext *bsf_ctx = ctx; + BSFListContext *lst = bsf_ctx->priv_data; + + if (!lst->nb_bsfs) + return null_filter_name; + + if (!lst->item_name) { + int i; + AVBPrint bp; + av_bprint_init(&bp, 16, 128); + + av_bprintf(&bp, "bsf_list("); + for (i = 0; i < lst->nb_bsfs; i++) + av_bprintf(&bp, i ? ",%s" : "%s", lst->bsfs[i]->filter->name); + av_bprintf(&bp, ")"); + + av_bprint_finalize(&bp, &lst->item_name); + } + + return lst->item_name; +} + +static const AVClass bsf_list_class = { + .class_name = "bsf_list", + .item_name = bsf_list_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVBitStreamFilter ff_list_bsf = { + .name = "bsf_list", + .priv_data_size = sizeof(BSFListContext), + .priv_class = &bsf_list_class, + .init = bsf_list_init, + .filter = bsf_list_filter, + .flush = bsf_list_flush, + .close = bsf_list_close, +}; + +struct AVBSFList { + AVBSFContext **bsfs; + int nb_bsfs; +}; + +AVBSFList *av_bsf_list_alloc(void) +{ + return av_mallocz(sizeof(AVBSFList)); +} + +void av_bsf_list_free(AVBSFList **lst) +{ + int i; + + if (!*lst) + return; + + for (i = 0; i < (*lst)->nb_bsfs; ++i) + av_bsf_free(&(*lst)->bsfs[i]); + av_free((*lst)->bsfs); + av_freep(lst); +} + +int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf) +{ + return av_dynarray_add_nofree(&lst->bsfs, &lst->nb_bsfs, bsf); +} + +int av_bsf_list_append2(AVBSFList *lst, const char *bsf_name, AVDictionary ** options) +{ + int ret; + const AVBitStreamFilter *filter; + AVBSFContext *bsf; + + filter = av_bsf_get_by_name(bsf_name); + if (!filter) + return AVERROR_BSF_NOT_FOUND; + + ret = av_bsf_alloc(filter, &bsf); + if (ret < 0) + return ret; + + if (options) { + ret = av_opt_set_dict2(bsf, options, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) + goto end; + } + + ret = av_bsf_list_append(lst, bsf); + +end: + if (ret < 0) + av_bsf_free(&bsf); + + return ret; +} + +int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf) +{ + int ret = 0; + BSFListContext *ctx; + + if ((*lst)->nb_bsfs == 1) { + *bsf = (*lst)->bsfs[0]; + av_freep(&(*lst)->bsfs); + (*lst)->nb_bsfs = 0; + goto end; + } + + ret = av_bsf_alloc(&ff_list_bsf, bsf); + if (ret < 0) + return ret; + + ctx = (*bsf)->priv_data; + + ctx->bsfs = (*lst)->bsfs; + ctx->nb_bsfs = (*lst)->nb_bsfs; + +end: + av_freep(lst); + return ret; +} + +static int bsf_parse_single(const char *str, AVBSFList *bsf_lst) +{ + char *bsf_name, *bsf_options_str, *buf; + AVDictionary *bsf_options = NULL; + int ret = 0; + + if (!(buf = av_strdup(str))) + return AVERROR(ENOMEM); + + bsf_name = av_strtok(buf, "=", &bsf_options_str); + if (!bsf_name) { + ret = AVERROR(EINVAL); + goto end; + } + + if (bsf_options_str) { + ret = av_dict_parse_string(&bsf_options, bsf_options_str, "=", ":", 0); + if (ret < 0) + goto end; + } + + ret = av_bsf_list_append2(bsf_lst, bsf_name, &bsf_options); + + av_dict_free(&bsf_options); +end: + av_free(buf); + return ret; +} + +int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf_lst) +{ + AVBSFList *lst; + char *bsf_str, *buf, *dup, *saveptr; + int ret; + + if (!str) + return av_bsf_get_null_filter(bsf_lst); + + lst = av_bsf_list_alloc(); + if (!lst) + return AVERROR(ENOMEM); + + if (!(dup = buf = av_strdup(str))) { + ret = AVERROR(ENOMEM); + goto end; + } + + while (1) { + bsf_str = av_strtok(buf, ",", &saveptr); + if (!bsf_str) + break; + + ret = bsf_parse_single(bsf_str, lst); + if (ret < 0) + goto end; + + buf = NULL; + } + + ret = av_bsf_list_finalize(&lst, bsf_lst); +end: + if (ret < 0) + av_bsf_list_free(&lst); + av_free(dup); + return ret; +} + +int av_bsf_get_null_filter(AVBSFContext **bsf) +{ + return av_bsf_alloc(&ff_list_bsf, bsf); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf.h new file mode 100644 index 0000000000..af035eee44 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf.h @@ -0,0 +1,44 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_BSF_H +#define AVCODEC_BSF_H + +#include "avcodec.h" + +/** + * Called by the bitstream filters to get the next packet for filtering. + * The filter is responsible for either freeing the packet or passing it to the + * caller. + */ +int ff_bsf_get_packet(AVBSFContext *ctx, AVPacket **pkt); + +/** + * Called by bitstream filters to get packet for filtering. + * The reference to packet is moved to provided packet structure. + * + * @param ctx pointer to AVBSFContext of filter + * @param pkt pointer to packet to move reference to + * + * @return 0>= on success, negative AVERROR in case of failure + */ +int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt); + +const AVClass *ff_bsf_child_class_next(const AVClass *prev); + +#endif /* AVCODEC_BSF_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf_list.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf_list.c new file mode 100644 index 0000000000..d31ece942a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bsf_list.c @@ -0,0 +1,3 @@ +static const AVBitStreamFilter * const bitstream_filters[] = { + &ff_null_bsf, + NULL }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bytestream.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bytestream.h new file mode 100644 index 0000000000..7be7fc22fc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/bytestream.h @@ -0,0 +1,376 @@ +/* + * Bytestream functions + * copyright (c) 2006 Baptiste Coudurier + * Copyright (c) 2012 Aneesh Dogra (lionaneesh) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_BYTESTREAM_H +#define AVCODEC_BYTESTREAM_H + +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" + +typedef struct GetByteContext { + const uint8_t *buffer, *buffer_end, *buffer_start; +} GetByteContext; + +typedef struct PutByteContext { + uint8_t *buffer, *buffer_end, *buffer_start; + int eof; +} PutByteContext; + +#define DEF(type, name, bytes, read, write) \ +static av_always_inline type bytestream_get_ ## name(const uint8_t **b) \ +{ \ + (*b) += bytes; \ + return read(*b - bytes); \ +} \ +static av_always_inline void bytestream_put_ ## name(uint8_t **b, \ + const type value) \ +{ \ + write(*b, value); \ + (*b) += bytes; \ +} \ +static av_always_inline void bytestream2_put_ ## name ## u(PutByteContext *p, \ + const type value) \ +{ \ + bytestream_put_ ## name(&p->buffer, value); \ +} \ +static av_always_inline void bytestream2_put_ ## name(PutByteContext *p, \ + const type value) \ +{ \ + if (!p->eof && (p->buffer_end - p->buffer >= bytes)) { \ + write(p->buffer, value); \ + p->buffer += bytes; \ + } else \ + p->eof = 1; \ +} \ +static av_always_inline type bytestream2_get_ ## name ## u(GetByteContext *g) \ +{ \ + return bytestream_get_ ## name(&g->buffer); \ +} \ +static av_always_inline type bytestream2_get_ ## name(GetByteContext *g) \ +{ \ + if (g->buffer_end - g->buffer < bytes) { \ + g->buffer = g->buffer_end; \ + return 0; \ + } \ + return bytestream2_get_ ## name ## u(g); \ +} \ +static av_always_inline type bytestream2_peek_ ## name(GetByteContext *g) \ +{ \ + if (g->buffer_end - g->buffer < bytes) \ + return 0; \ + return read(g->buffer); \ +} + +DEF(uint64_t, le64, 8, AV_RL64, AV_WL64) +DEF(unsigned int, le32, 4, AV_RL32, AV_WL32) +DEF(unsigned int, le24, 3, AV_RL24, AV_WL24) +DEF(unsigned int, le16, 2, AV_RL16, AV_WL16) +DEF(uint64_t, be64, 8, AV_RB64, AV_WB64) +DEF(unsigned int, be32, 4, AV_RB32, AV_WB32) +DEF(unsigned int, be24, 3, AV_RB24, AV_WB24) +DEF(unsigned int, be16, 2, AV_RB16, AV_WB16) +DEF(unsigned int, byte, 1, AV_RB8 , AV_WB8) + +#if AV_HAVE_BIGENDIAN +# define bytestream2_get_ne16 bytestream2_get_be16 +# define bytestream2_get_ne24 bytestream2_get_be24 +# define bytestream2_get_ne32 bytestream2_get_be32 +# define bytestream2_get_ne64 bytestream2_get_be64 +# define bytestream2_get_ne16u bytestream2_get_be16u +# define bytestream2_get_ne24u bytestream2_get_be24u +# define bytestream2_get_ne32u bytestream2_get_be32u +# define bytestream2_get_ne64u bytestream2_get_be64u +# define bytestream2_put_ne16 bytestream2_put_be16 +# define bytestream2_put_ne24 bytestream2_put_be24 +# define bytestream2_put_ne32 bytestream2_put_be32 +# define bytestream2_put_ne64 bytestream2_put_be64 +# define bytestream2_peek_ne16 bytestream2_peek_be16 +# define bytestream2_peek_ne24 bytestream2_peek_be24 +# define bytestream2_peek_ne32 bytestream2_peek_be32 +# define bytestream2_peek_ne64 bytestream2_peek_be64 +#else +# define bytestream2_get_ne16 bytestream2_get_le16 +# define bytestream2_get_ne24 bytestream2_get_le24 +# define bytestream2_get_ne32 bytestream2_get_le32 +# define bytestream2_get_ne64 bytestream2_get_le64 +# define bytestream2_get_ne16u bytestream2_get_le16u +# define bytestream2_get_ne24u bytestream2_get_le24u +# define bytestream2_get_ne32u bytestream2_get_le32u +# define bytestream2_get_ne64u bytestream2_get_le64u +# define bytestream2_put_ne16 bytestream2_put_le16 +# define bytestream2_put_ne24 bytestream2_put_le24 +# define bytestream2_put_ne32 bytestream2_put_le32 +# define bytestream2_put_ne64 bytestream2_put_le64 +# define bytestream2_peek_ne16 bytestream2_peek_le16 +# define bytestream2_peek_ne24 bytestream2_peek_le24 +# define bytestream2_peek_ne32 bytestream2_peek_le32 +# define bytestream2_peek_ne64 bytestream2_peek_le64 +#endif + +static av_always_inline void bytestream2_init(GetByteContext *g, + const uint8_t *buf, + int buf_size) +{ + av_assert0(buf_size >= 0); + g->buffer = buf; + g->buffer_start = buf; + g->buffer_end = buf + buf_size; +} + +static av_always_inline void bytestream2_init_writer(PutByteContext *p, + uint8_t *buf, + int buf_size) +{ + av_assert0(buf_size >= 0); + p->buffer = buf; + p->buffer_start = buf; + p->buffer_end = buf + buf_size; + p->eof = 0; +} + +static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g) +{ + return g->buffer_end - g->buffer; +} + +static av_always_inline unsigned int bytestream2_get_bytes_left_p(PutByteContext *p) +{ + return p->buffer_end - p->buffer; +} + +static av_always_inline void bytestream2_skip(GetByteContext *g, + unsigned int size) +{ + g->buffer += FFMIN(g->buffer_end - g->buffer, size); +} + +static av_always_inline void bytestream2_skipu(GetByteContext *g, + unsigned int size) +{ + g->buffer += size; +} + +static av_always_inline void bytestream2_skip_p(PutByteContext *p, + unsigned int size) +{ + int size2; + if (p->eof) + return; + size2 = FFMIN(p->buffer_end - p->buffer, size); + if (size2 != size) + p->eof = 1; + p->buffer += size2; +} + +static av_always_inline int bytestream2_tell(GetByteContext *g) +{ + return (int)(g->buffer - g->buffer_start); +} + +static av_always_inline int bytestream2_tell_p(PutByteContext *p) +{ + return (int)(p->buffer - p->buffer_start); +} + +static av_always_inline int bytestream2_size(GetByteContext *g) +{ + return (int)(g->buffer_end - g->buffer_start); +} + +static av_always_inline int bytestream2_size_p(PutByteContext *p) +{ + return (int)(p->buffer_end - p->buffer_start); +} + +static av_always_inline int bytestream2_seek(GetByteContext *g, + int offset, + int whence) +{ + switch (whence) { + case SEEK_CUR: + offset = av_clip(offset, -(g->buffer - g->buffer_start), + g->buffer_end - g->buffer); + g->buffer += offset; + break; + case SEEK_END: + offset = av_clip(offset, -(g->buffer_end - g->buffer_start), 0); + g->buffer = g->buffer_end + offset; + break; + case SEEK_SET: + offset = av_clip(offset, 0, g->buffer_end - g->buffer_start); + g->buffer = g->buffer_start + offset; + break; + default: + return AVERROR(EINVAL); + } + return bytestream2_tell(g); +} + +static av_always_inline int bytestream2_seek_p(PutByteContext *p, + int offset, + int whence) +{ + p->eof = 0; + switch (whence) { + case SEEK_CUR: + if (p->buffer_end - p->buffer < offset) + p->eof = 1; + offset = av_clip(offset, -(p->buffer - p->buffer_start), + p->buffer_end - p->buffer); + p->buffer += offset; + break; + case SEEK_END: + if (offset > 0) + p->eof = 1; + offset = av_clip(offset, -(p->buffer_end - p->buffer_start), 0); + p->buffer = p->buffer_end + offset; + break; + case SEEK_SET: + if (p->buffer_end - p->buffer_start < offset) + p->eof = 1; + offset = av_clip(offset, 0, p->buffer_end - p->buffer_start); + p->buffer = p->buffer_start + offset; + break; + default: + return AVERROR(EINVAL); + } + return bytestream2_tell_p(p); +} + +static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, + uint8_t *dst, + unsigned int size) +{ + int size2 = FFMIN(g->buffer_end - g->buffer, size); + memcpy(dst, g->buffer, size2); + g->buffer += size2; + return size2; +} + +static av_always_inline unsigned int bytestream2_get_bufferu(GetByteContext *g, + uint8_t *dst, + unsigned int size) +{ + memcpy(dst, g->buffer, size); + g->buffer += size; + return size; +} + +static av_always_inline unsigned int bytestream2_put_buffer(PutByteContext *p, + const uint8_t *src, + unsigned int size) +{ + int size2; + if (p->eof) + return 0; + size2 = FFMIN(p->buffer_end - p->buffer, size); + if (size2 != size) + p->eof = 1; + memcpy(p->buffer, src, size2); + p->buffer += size2; + return size2; +} + +static av_always_inline unsigned int bytestream2_put_bufferu(PutByteContext *p, + const uint8_t *src, + unsigned int size) +{ + memcpy(p->buffer, src, size); + p->buffer += size; + return size; +} + +static av_always_inline void bytestream2_set_buffer(PutByteContext *p, + const uint8_t c, + unsigned int size) +{ + int size2; + if (p->eof) + return; + size2 = FFMIN(p->buffer_end - p->buffer, size); + if (size2 != size) + p->eof = 1; + memset(p->buffer, c, size2); + p->buffer += size2; +} + +static av_always_inline void bytestream2_set_bufferu(PutByteContext *p, + const uint8_t c, + unsigned int size) +{ + memset(p->buffer, c, size); + p->buffer += size; +} + +static av_always_inline unsigned int bytestream2_get_eof(PutByteContext *p) +{ + return p->eof; +} + +static av_always_inline unsigned int bytestream2_copy_bufferu(PutByteContext *p, + GetByteContext *g, + unsigned int size) +{ + memcpy(p->buffer, g->buffer, size); + p->buffer += size; + g->buffer += size; + return size; +} + +static av_always_inline unsigned int bytestream2_copy_buffer(PutByteContext *p, + GetByteContext *g, + unsigned int size) +{ + int size2; + + if (p->eof) + return 0; + size = FFMIN(g->buffer_end - g->buffer, size); + size2 = FFMIN(p->buffer_end - p->buffer, size); + if (size2 != size) + p->eof = 1; + + return bytestream2_copy_bufferu(p, g, size2); +} + +static av_always_inline unsigned int bytestream_get_buffer(const uint8_t **b, + uint8_t *dst, + unsigned int size) +{ + memcpy(dst, *b, size); + (*b) += size; + return size; +} + +static av_always_inline void bytestream_put_buffer(uint8_t **b, + const uint8_t *src, + unsigned int size) +{ + memcpy(*b, src, size); + (*b) += size; +} + +#endif /* AVCODEC_BYTESTREAM_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data.c new file mode 100644 index 0000000000..d2e36cd6dd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "cbrt_data.h" + +#include "libavutil/libm.h" + +#if CONFIG_HARDCODED_TABLES +#include "libavcodec/cbrt_tables.h" +#else +#include "cbrt_tablegen.h" +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data.h new file mode 100644 index 0000000000..89117f85b3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBRT_DATA_H +#define AVCODEC_CBRT_DATA_H + +#include + +#include "config.h" + +#if CONFIG_HARDCODED_TABLES +#define ff_cbrt_tableinit_fixed() +#define ff_cbrt_tableinit() +extern const uint32_t ff_cbrt_tab[1 << 13]; +extern const uint32_t ff_cbrt_tab_fixed[1 << 13]; +#else +void ff_cbrt_tableinit(void); +void ff_cbrt_tableinit_fixed(void); +extern uint32_t ff_cbrt_tab[1 << 13]; +extern uint32_t ff_cbrt_tab_fixed[1 << 13]; +#endif + +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data_fixed.c new file mode 100644 index 0000000000..d661b25a67 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_data_fixed.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "cbrt_data.h" + +#if CONFIG_HARDCODED_TABLES +#include "libavcodec/cbrt_fixed_tables.h" +#else +#define USE_FIXED 1 +#include "cbrt_tablegen.h" +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_tablegen.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_tablegen.c new file mode 100644 index 0000000000..8c2235e987 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_tablegen.c @@ -0,0 +1,24 @@ +/* + * Generate a header file for hardcoded AAC cube-root table + * + * Copyright (c) 2010 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 0 +#include "cbrt_tablegen_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_tablegen.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_tablegen.h new file mode 100644 index 0000000000..9af18d8ab5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/cbrt_tablegen.h @@ -0,0 +1,73 @@ +/* + * Header file for hardcoded AAC cube-root table + * + * Copyright (c) 2010 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBRT_TABLEGEN_H +#define AVCODEC_CBRT_TABLEGEN_H + +#include +#include +#include "libavutil/attributes.h" +#include "libavutil/intfloat.h" +#include "libavcodec/aac_defines.h" + +#if USE_FIXED +#define CBRT(x) lrint((x) * 8192) +#else +#define CBRT(x) av_float2int((float)(x)) +#endif + +uint32_t AAC_RENAME(ff_cbrt_tab)[1 << 13]; + +av_cold void AAC_RENAME(ff_cbrt_tableinit)(void) +{ + static double cbrt_tab_dbl[1 << 13]; + if (!AAC_RENAME(ff_cbrt_tab)[(1<<13) - 1]) { + int i, j, k; + double cbrt_val; + + for (i = 1; i < 1<<13; i++) + cbrt_tab_dbl[i] = 1; + + /* have to take care of non-squarefree numbers */ + for (i = 2; i < 90; i++) { + if (cbrt_tab_dbl[i] == 1) { + cbrt_val = i * cbrt(i); + for (k = i; k < 1<<13; k *= i) + for (j = k; j < 1<<13; j += k) + cbrt_tab_dbl[j] *= cbrt_val; + } + } + + for (i = 91; i <= 8191; i+= 2) { + if (cbrt_tab_dbl[i] == 1) { + cbrt_val = i * cbrt(i); + for (j = i; j < 1<<13; j += i) + cbrt_tab_dbl[j] *= cbrt_val; + } + } + + for (i = 0; i < 1<<13; i++) + AAC_RENAME(ff_cbrt_tab)[i] = CBRT(cbrt_tab_dbl[i]); + } +} + +#endif /* AVCODEC_CBRT_TABLEGEN_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/codec_desc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/codec_desc.c new file mode 100644 index 0000000000..4d033c20ff --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/codec_desc.c @@ -0,0 +1,3286 @@ +/* + * This file is part of FFmpeg. + * + * This table was generated from the long and short names of AVCodecs + * please see the respective codec sources for authorship + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/internal.h" +#include "avcodec.h" +#include "profiles.h" +#include "version.h" + +#define MT(...) (const char *const[]){ __VA_ARGS__, NULL } + +static const AVCodecDescriptor codec_descriptors[] = { + /* video codecs */ + { + .id = AV_CODEC_ID_MPEG1VIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mpeg1video", + .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_MPEG2VIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mpeg2video", + .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 video"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + .profiles = NULL_IF_CONFIG_SMALL(ff_mpeg2_video_profiles), + }, + { + .id = AV_CODEC_ID_H261, + .type = AVMEDIA_TYPE_VIDEO, + .name = "h261", + .long_name = NULL_IF_CONFIG_SMALL("H.261"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_H263, + .type = AVMEDIA_TYPE_VIDEO, + .name = "h263", + .long_name = NULL_IF_CONFIG_SMALL("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_RV10, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rv10", + .long_name = NULL_IF_CONFIG_SMALL("RealVideo 1.0"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_RV20, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rv20", + .long_name = NULL_IF_CONFIG_SMALL("RealVideo 2.0"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_MJPEG, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mjpeg", + .long_name = NULL_IF_CONFIG_SMALL("Motion JPEG"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .mime_types= MT("image/jpeg"), + .profiles = NULL_IF_CONFIG_SMALL(ff_mjpeg_profiles), + }, + { + .id = AV_CODEC_ID_MJPEGB, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mjpegb", + .long_name = NULL_IF_CONFIG_SMALL("Apple MJPEG-B"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_LJPEG, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ljpeg", + .long_name = NULL_IF_CONFIG_SMALL("Lossless JPEG"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_SP5X, + .type = AVMEDIA_TYPE_VIDEO, + .name = "sp5x", + .long_name = NULL_IF_CONFIG_SMALL("Sunplus JPEG (SP5X)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_JPEGLS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "jpegls", + .long_name = NULL_IF_CONFIG_SMALL("JPEG-LS"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | + AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MPEG4, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mpeg4", + .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + .profiles = NULL_IF_CONFIG_SMALL(ff_mpeg4_video_profiles), + }, + { + .id = AV_CODEC_ID_RAWVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rawvideo", + .long_name = NULL_IF_CONFIG_SMALL("raw video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MSMPEG4V1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "msmpeg4v1", + .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2 Microsoft variant version 1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MSMPEG4V2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "msmpeg4v2", + .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2 Microsoft variant version 2"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MSMPEG4V3, + .type = AVMEDIA_TYPE_VIDEO, + .name = "msmpeg4v3", + .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2 Microsoft variant version 3"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WMV1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wmv1", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 7"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WMV2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wmv2", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 8"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_H263P, + .type = AVMEDIA_TYPE_VIDEO, + .name = "h263p", + .long_name = NULL_IF_CONFIG_SMALL("H.263+ / H.263-1998 / H.263 version 2"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_H263I, + .type = AVMEDIA_TYPE_VIDEO, + .name = "h263i", + .long_name = NULL_IF_CONFIG_SMALL("Intel H.263"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_FLV1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "flv1", + .long_name = NULL_IF_CONFIG_SMALL("FLV / Sorenson Spark / Sorenson H.263 (Flash Video)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SVQ1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "svq1", + .long_name = NULL_IF_CONFIG_SMALL("Sorenson Vector Quantizer 1 / Sorenson Video 1 / SVQ1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SVQ3, + .type = AVMEDIA_TYPE_VIDEO, + .name = "svq3", + .long_name = NULL_IF_CONFIG_SMALL("Sorenson Vector Quantizer 3 / Sorenson Video 3 / SVQ3"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_DVVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dvvideo", + .long_name = NULL_IF_CONFIG_SMALL("DV (Digital Video)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_HUFFYUV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "huffyuv", + .long_name = NULL_IF_CONFIG_SMALL("HuffYUV"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_CYUV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cyuv", + .long_name = NULL_IF_CONFIG_SMALL("Creative YUV (CYUV)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_H264, + .type = AVMEDIA_TYPE_VIDEO, + .name = "h264", + .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS | AV_CODEC_PROP_REORDER, + .profiles = NULL_IF_CONFIG_SMALL(ff_h264_profiles), + }, + { + .id = AV_CODEC_ID_INDEO3, + .type = AVMEDIA_TYPE_VIDEO, + .name = "indeo3", + .long_name = NULL_IF_CONFIG_SMALL("Intel Indeo 3"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VP3, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp3", + .long_name = NULL_IF_CONFIG_SMALL("On2 VP3"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_THEORA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "theora", + .long_name = NULL_IF_CONFIG_SMALL("Theora"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ASV1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "asv1", + .long_name = NULL_IF_CONFIG_SMALL("ASUS V1"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ASV2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "asv2", + .long_name = NULL_IF_CONFIG_SMALL("ASUS V2"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_FFV1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ffv1", + .long_name = NULL_IF_CONFIG_SMALL("FFmpeg video codec #1"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_4XM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "4xm", + .long_name = NULL_IF_CONFIG_SMALL("4X Movie"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VCR1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vcr1", + .long_name = NULL_IF_CONFIG_SMALL("ATI VCR1"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_CLJR, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cljr", + .long_name = NULL_IF_CONFIG_SMALL("Cirrus Logic AccuPak"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MDEC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mdec", + .long_name = NULL_IF_CONFIG_SMALL("Sony PlayStation MDEC (Motion DECoder)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ROQ, + .type = AVMEDIA_TYPE_VIDEO, + .name = "roq", + .long_name = NULL_IF_CONFIG_SMALL("id RoQ video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_INTERPLAY_VIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "interplayvideo", + .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_XAN_WC3, + .type = AVMEDIA_TYPE_VIDEO, + .name = "xan_wc3", + .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_XAN_WC4, + .type = AVMEDIA_TYPE_VIDEO, + .name = "xan_wc4", + .long_name = NULL_IF_CONFIG_SMALL("Wing Commander IV / Xxan"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_RPZA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rpza", + .long_name = NULL_IF_CONFIG_SMALL("QuickTime video (RPZA)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_CINEPAK, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cinepak", + .long_name = NULL_IF_CONFIG_SMALL("Cinepak"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WS_VQA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ws_vqa", + .long_name = NULL_IF_CONFIG_SMALL("Westwood Studios VQA (Vector Quantized Animation) video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MSRLE, + .type = AVMEDIA_TYPE_VIDEO, + .name = "msrle", + .long_name = NULL_IF_CONFIG_SMALL("Microsoft RLE"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MSVIDEO1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "msvideo1", + .long_name = NULL_IF_CONFIG_SMALL("Microsoft Video 1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_IDCIN, + .type = AVMEDIA_TYPE_VIDEO, + .name = "idcin", + .long_name = NULL_IF_CONFIG_SMALL("id Quake II CIN video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_8BPS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "8bps", + .long_name = NULL_IF_CONFIG_SMALL("QuickTime 8BPS video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_SMC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "smc", + .long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_FLIC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "flic", + .long_name = NULL_IF_CONFIG_SMALL("Autodesk Animator Flic video"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_TRUEMOTION1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "truemotion1", + .long_name = NULL_IF_CONFIG_SMALL("Duck TrueMotion 1.0"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VMDVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vmdvideo", + .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MSZH, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mszh", + .long_name = NULL_IF_CONFIG_SMALL("LCL (LossLess Codec Library) MSZH"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ZLIB, + .type = AVMEDIA_TYPE_VIDEO, + .name = "zlib", + .long_name = NULL_IF_CONFIG_SMALL("LCL (LossLess Codec Library) ZLIB"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_QTRLE, + .type = AVMEDIA_TYPE_VIDEO, + .name = "qtrle", + .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_TSCC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tscc", + .long_name = NULL_IF_CONFIG_SMALL("TechSmith Screen Capture Codec"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ULTI, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ulti", + .long_name = NULL_IF_CONFIG_SMALL("IBM UltiMotion"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_QDRAW, + .type = AVMEDIA_TYPE_VIDEO, + .name = "qdraw", + .long_name = NULL_IF_CONFIG_SMALL("Apple QuickDraw"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_VIXL, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vixl", + .long_name = NULL_IF_CONFIG_SMALL("Miro VideoXL"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_QPEG, + .type = AVMEDIA_TYPE_VIDEO, + .name = "qpeg", + .long_name = NULL_IF_CONFIG_SMALL("Q-team QPEG"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PNG, + .type = AVMEDIA_TYPE_VIDEO, + .name = "png", + .long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"), + .props = AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/png"), + }, + { + .id = AV_CODEC_ID_PPM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ppm", + .long_name = NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PBM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pbm", + .long_name = NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PGM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pgm", + .long_name = NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PGMYUV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pgmyuv", + .long_name = NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PAM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pam", + .long_name = NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-portable-pixmap"), + }, + { + .id = AV_CODEC_ID_FFVHUFF, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ffvhuff", + .long_name = NULL_IF_CONFIG_SMALL("Huffyuv FFmpeg variant"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_RV30, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rv30", + .long_name = NULL_IF_CONFIG_SMALL("RealVideo 3.0"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_RV40, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rv40", + .long_name = NULL_IF_CONFIG_SMALL("RealVideo 4.0"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_VC1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vc1", + .long_name = NULL_IF_CONFIG_SMALL("SMPTE VC-1"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + .profiles = NULL_IF_CONFIG_SMALL(ff_vc1_profiles), + }, + { + .id = AV_CODEC_ID_WMV3, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wmv3", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + .profiles = NULL_IF_CONFIG_SMALL(ff_vc1_profiles), + }, + { + .id = AV_CODEC_ID_LOCO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "loco", + .long_name = NULL_IF_CONFIG_SMALL("LOCO"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_WNV1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wnv1", + .long_name = NULL_IF_CONFIG_SMALL("Winnov WNV1"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_AASC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "aasc", + .long_name = NULL_IF_CONFIG_SMALL("Autodesk RLE"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_INDEO2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "indeo2", + .long_name = NULL_IF_CONFIG_SMALL("Intel Indeo 2"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_FRAPS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "fraps", + .long_name = NULL_IF_CONFIG_SMALL("Fraps"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_TRUEMOTION2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "truemotion2", + .long_name = NULL_IF_CONFIG_SMALL("Duck TrueMotion 2.0"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_BMP, + .type = AVMEDIA_TYPE_VIDEO, + .name = "bmp", + .long_name = NULL_IF_CONFIG_SMALL("BMP (Windows and OS/2 bitmap)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-ms-bmp"), + }, + { + .id = AV_CODEC_ID_CSCD, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cscd", + .long_name = NULL_IF_CONFIG_SMALL("CamStudio"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MMVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mmvideo", + .long_name = NULL_IF_CONFIG_SMALL("American Laser Games MM Video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ZMBV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "zmbv", + .long_name = NULL_IF_CONFIG_SMALL("Zip Motion Blocks Video"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_AVS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "avs", + .long_name = NULL_IF_CONFIG_SMALL("AVS (Audio Video Standard) video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SMACKVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "smackvideo", + .long_name = NULL_IF_CONFIG_SMALL("Smacker video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_NUV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "nuv", + .long_name = NULL_IF_CONFIG_SMALL("NuppelVideo/RTJPEG"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_KMVC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "kmvc", + .long_name = NULL_IF_CONFIG_SMALL("Karl Morton's video codec"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_FLASHSV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "flashsv", + .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video v1"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_CAVS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cavs", + .long_name = NULL_IF_CONFIG_SMALL("Chinese AVS (Audio Video Standard) (AVS1-P2, JiZhun profile)"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_JPEG2000, + .type = AVMEDIA_TYPE_VIDEO, + .name = "jpeg2000", + .long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | + AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/jp2"), + .profiles = NULL_IF_CONFIG_SMALL(ff_jpeg2000_profiles), + }, + { + .id = AV_CODEC_ID_VMNC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vmnc", + .long_name = NULL_IF_CONFIG_SMALL("VMware Screen Codec / VMware Video"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_VP5, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp5", + .long_name = NULL_IF_CONFIG_SMALL("On2 VP5"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VP6, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp6", + .long_name = NULL_IF_CONFIG_SMALL("On2 VP6"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VP6F, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp6f", + .long_name = NULL_IF_CONFIG_SMALL("On2 VP6 (Flash version)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TARGA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "targa", + .long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-targa", "image/x-tga"), + }, + { + .id = AV_CODEC_ID_DSICINVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dsicinvideo", + .long_name = NULL_IF_CONFIG_SMALL("Delphine Software International CIN video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TIERTEXSEQVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tiertexseqvideo", + .long_name = NULL_IF_CONFIG_SMALL("Tiertex Limited SEQ video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TIFF, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tiff", + .long_name = NULL_IF_CONFIG_SMALL("TIFF image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/tiff"), + }, + { + .id = AV_CODEC_ID_GIF, + .type = AVMEDIA_TYPE_VIDEO, + .name = "gif", + .long_name = NULL_IF_CONFIG_SMALL("CompuServe GIF (Graphics Interchange Format)"), + .props = AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/gif"), + }, + { + .id = AV_CODEC_ID_DXA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dxa", + .long_name = NULL_IF_CONFIG_SMALL("Feeble Files/ScummVM DXA"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_DNXHD, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dnxhd", + .long_name = NULL_IF_CONFIG_SMALL("VC3/DNxHD"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_dnxhd_profiles), + }, + { + .id = AV_CODEC_ID_THP, + .type = AVMEDIA_TYPE_VIDEO, + .name = "thp", + .long_name = NULL_IF_CONFIG_SMALL("Nintendo Gamecube THP video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SGI, + .type = AVMEDIA_TYPE_VIDEO, + .name = "sgi", + .long_name = NULL_IF_CONFIG_SMALL("SGI image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_C93, + .type = AVMEDIA_TYPE_VIDEO, + .name = "c93", + .long_name = NULL_IF_CONFIG_SMALL("Interplay C93"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_BETHSOFTVID, + .type = AVMEDIA_TYPE_VIDEO, + .name = "bethsoftvid", + .long_name = NULL_IF_CONFIG_SMALL("Bethesda VID video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PTX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ptx", + .long_name = NULL_IF_CONFIG_SMALL("V.Flash PTX image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TXD, + .type = AVMEDIA_TYPE_VIDEO, + .name = "txd", + .long_name = NULL_IF_CONFIG_SMALL("Renderware TXD (TeXture Dictionary) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VP6A, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp6a", + .long_name = NULL_IF_CONFIG_SMALL("On2 VP6 (Flash version, with alpha channel)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_AMV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "amv", + .long_name = NULL_IF_CONFIG_SMALL("AMV Video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VB, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vb", + .long_name = NULL_IF_CONFIG_SMALL("Beam Software VB"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PCX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pcx", + .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-pcx"), + }, + { + .id = AV_CODEC_ID_SUNRAST, + .type = AVMEDIA_TYPE_VIDEO, + .name = "sunrast", + .long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_INDEO4, + .type = AVMEDIA_TYPE_VIDEO, + .name = "indeo4", + .long_name = NULL_IF_CONFIG_SMALL("Intel Indeo Video Interactive 4"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_INDEO5, + .type = AVMEDIA_TYPE_VIDEO, + .name = "indeo5", + .long_name = NULL_IF_CONFIG_SMALL("Intel Indeo Video Interactive 5"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MIMIC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mimic", + .long_name = NULL_IF_CONFIG_SMALL("Mimic"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_RL2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rl2", + .long_name = NULL_IF_CONFIG_SMALL("RL2 video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ESCAPE124, + .type = AVMEDIA_TYPE_VIDEO, + .name = "escape124", + .long_name = NULL_IF_CONFIG_SMALL("Escape 124"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DIRAC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dirac", + .long_name = NULL_IF_CONFIG_SMALL("Dirac"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS | AV_CODEC_PROP_REORDER, + }, + { + .id = AV_CODEC_ID_BFI, + .type = AVMEDIA_TYPE_VIDEO, + .name = "bfi", + .long_name = NULL_IF_CONFIG_SMALL("Brute Force & Ignorance"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_CMV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cmv", + .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts CMV video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MOTIONPIXELS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "motionpixels", + .long_name = NULL_IF_CONFIG_SMALL("Motion Pixels video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TGV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tgv", + .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TGV video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TGQ, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tgq", + .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TGQ video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TQI, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tqi", + .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TQI video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_AURA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "aura", + .long_name = NULL_IF_CONFIG_SMALL("Auravision AURA"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_AURA2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "aura2", + .long_name = NULL_IF_CONFIG_SMALL("Auravision Aura 2"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_V210X, + .type = AVMEDIA_TYPE_VIDEO, + .name = "v210x", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_TMV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tmv", + .long_name = NULL_IF_CONFIG_SMALL("8088flex TMV"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_V210, + .type = AVMEDIA_TYPE_VIDEO, + .name = "v210", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_DPX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dpx", + .long_name = NULL_IF_CONFIG_SMALL("DPX (Digital Picture Exchange) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MAD, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mad", + .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts Madcow Video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_FRWU, + .type = AVMEDIA_TYPE_VIDEO, + .name = "frwu", + .long_name = NULL_IF_CONFIG_SMALL("Forward Uncompressed"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_FLASHSV2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "flashsv2", + .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video v2"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_CDGRAPHICS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cdgraphics", + .long_name = NULL_IF_CONFIG_SMALL("CD Graphics video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_R210, + .type = AVMEDIA_TYPE_VIDEO, + .name = "r210", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed RGB 10-bit"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ANM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "anm", + .long_name = NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_BINKVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "binkvideo", + .long_name = NULL_IF_CONFIG_SMALL("Bink video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_IFF_ILBM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "iff_ilbm", + .long_name = NULL_IF_CONFIG_SMALL("IFF ACBM/ANIM/DEEP/ILBM/PBM/RGB8/RGBN"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_KGV1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "kgv1", + .long_name = NULL_IF_CONFIG_SMALL("Kega Game Video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_YOP, + .type = AVMEDIA_TYPE_VIDEO, + .name = "yop", + .long_name = NULL_IF_CONFIG_SMALL("Psygnosis YOP Video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VP8, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp8", + .long_name = NULL_IF_CONFIG_SMALL("On2 VP8"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PICTOR, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pictor", + .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ANSI, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ansi", + .long_name = NULL_IF_CONFIG_SMALL("ASCII/ANSI art"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_A64_MULTI, + .type = AVMEDIA_TYPE_VIDEO, + .name = "a64_multi", + .long_name = NULL_IF_CONFIG_SMALL("Multicolor charset for Commodore 64"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_A64_MULTI5, + .type = AVMEDIA_TYPE_VIDEO, + .name = "a64_multi5", + .long_name = NULL_IF_CONFIG_SMALL("Multicolor charset for Commodore 64, extended with 5th color (colram)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_R10K, + .type = AVMEDIA_TYPE_VIDEO, + .name = "r10k", + .long_name = NULL_IF_CONFIG_SMALL("AJA Kona 10-bit RGB Codec"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MXPEG, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mxpeg", + .long_name = NULL_IF_CONFIG_SMALL("Mobotix MxPEG video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_LAGARITH, + .type = AVMEDIA_TYPE_VIDEO, + .name = "lagarith", + .long_name = NULL_IF_CONFIG_SMALL("Lagarith lossless"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PRORES, + .type = AVMEDIA_TYPE_VIDEO, + .name = "prores", + .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), + }, + { + .id = AV_CODEC_ID_JV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "jv", + .long_name = NULL_IF_CONFIG_SMALL("Bitmap Brothers JV video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DFA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dfa", + .long_name = NULL_IF_CONFIG_SMALL("Chronomaster DFA"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WMV3IMAGE, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wmv3image", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 Image"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VC1IMAGE, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vc1image", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 Image v2"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_UTVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "utvideo", + .long_name = NULL_IF_CONFIG_SMALL("Ut Video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_BMV_VIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "bmv_video", + .long_name = NULL_IF_CONFIG_SMALL("Discworld II BMV video"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_VBLE, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vble", + .long_name = NULL_IF_CONFIG_SMALL("VBLE Lossless Codec"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_DXTORY, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dxtory", + .long_name = NULL_IF_CONFIG_SMALL("Dxtory"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_V410, + .type = AVMEDIA_TYPE_VIDEO, + .name = "v410", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:4:4 10-bit"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_XWD, + .type = AVMEDIA_TYPE_VIDEO, + .name = "xwd", + .long_name = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-xwindowdump"), + }, + { + .id = AV_CODEC_ID_CDXL, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cdxl", + .long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_XBM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "xbm", + .long_name = NULL_IF_CONFIG_SMALL("XBM (X BitMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-xbitmap"), + }, + { + .id = AV_CODEC_ID_ZEROCODEC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "zerocodec", + .long_name = NULL_IF_CONFIG_SMALL("ZeroCodec Lossless Video"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MSS1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mss1", + .long_name = NULL_IF_CONFIG_SMALL("MS Screen 1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MSA1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "msa1", + .long_name = NULL_IF_CONFIG_SMALL("MS ATC Screen"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TSCC2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tscc2", + .long_name = NULL_IF_CONFIG_SMALL("TechSmith Screen Codec 2"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MTS2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mts2", + .long_name = NULL_IF_CONFIG_SMALL("MS Expression Encoder Screen"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_CLLC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cllc", + .long_name = NULL_IF_CONFIG_SMALL("Canopus Lossless Codec"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MSS2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mss2", + .long_name = NULL_IF_CONFIG_SMALL("MS Windows Media Video V9 Screen"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VP9, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp9", + .long_name = NULL_IF_CONFIG_SMALL("Google VP9"), + .props = AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles), + }, + { + .id = AV_CODEC_ID_AIC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "aic", + .long_name = NULL_IF_CONFIG_SMALL("Apple Intermediate Codec"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ESCAPE130, + .type = AVMEDIA_TYPE_VIDEO, + .name = "escape130", + .long_name = NULL_IF_CONFIG_SMALL("Escape 130"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_G2M, + .type = AVMEDIA_TYPE_VIDEO, + .name = "g2m", + .long_name = NULL_IF_CONFIG_SMALL("Go2Meeting"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WEBP, + .type = AVMEDIA_TYPE_VIDEO, + .name = "webp", + .long_name = NULL_IF_CONFIG_SMALL("WebP"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | + AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/webp"), + }, + { + .id = AV_CODEC_ID_HNM4_VIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "hnm4video", + .long_name = NULL_IF_CONFIG_SMALL("HNM 4 video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_HEVC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "hevc", + .long_name = NULL_IF_CONFIG_SMALL("H.265 / HEVC (High Efficiency Video Coding)"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, + .profiles = NULL_IF_CONFIG_SMALL(ff_hevc_profiles), + }, + { + .id = AV_CODEC_ID_FIC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "fic", + .long_name = NULL_IF_CONFIG_SMALL("Mirillis FIC"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ALIAS_PIX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "alias_pix", + .long_name = NULL_IF_CONFIG_SMALL("Alias/Wavefront PIX image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_BRENDER_PIX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "brender_pix", + .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PAF_VIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "paf_video", + .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_EXR, + .type = AVMEDIA_TYPE_VIDEO, + .name = "exr", + .long_name = NULL_IF_CONFIG_SMALL("OpenEXR image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | + AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_VP7, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp7", + .long_name = NULL_IF_CONFIG_SMALL("On2 VP7"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SANM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "sanm", + .long_name = NULL_IF_CONFIG_SMALL("LucasArts SANM/SMUSH video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SGIRLE, + .type = AVMEDIA_TYPE_VIDEO, + .name = "sgirle", + .long_name = NULL_IF_CONFIG_SMALL("SGI RLE 8-bit"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MVC1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mvc1", + .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MVC2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mvc2", + .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_HQX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "hqx", + .long_name = NULL_IF_CONFIG_SMALL("Canopus HQX"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TDSC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tdsc", + .long_name = NULL_IF_CONFIG_SMALL("TDSC"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_HQ_HQA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "hq_hqa", + .long_name = NULL_IF_CONFIG_SMALL("Canopus HQ/HQA"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_HAP, + .type = AVMEDIA_TYPE_VIDEO, + .name = "hap", + .long_name = NULL_IF_CONFIG_SMALL("Vidvox Hap"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DDS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dds", + .long_name = NULL_IF_CONFIG_SMALL("DirectDraw Surface image decoder"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | + AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_DXV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dxv", + .long_name = NULL_IF_CONFIG_SMALL("Resolume DXV"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SCREENPRESSO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "screenpresso", + .long_name = NULL_IF_CONFIG_SMALL("Screenpresso"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_RSCC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rscc", + .long_name = NULL_IF_CONFIG_SMALL("innoHeim/Rsupport Screen Capture Codec"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_AVS2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "avs2", + .long_name = NULL_IF_CONFIG_SMALL("AVS2-P2/IEEE1857.4"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_Y41P, + .type = AVMEDIA_TYPE_VIDEO, + .name = "y41p", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_AVRP, + .type = AVMEDIA_TYPE_VIDEO, + .name = "avrp", + .long_name = NULL_IF_CONFIG_SMALL("Avid 1:1 10-bit RGB Packer"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_012V, + .type = AVMEDIA_TYPE_VIDEO, + .name = "012v", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_AVUI, + .type = AVMEDIA_TYPE_VIDEO, + .name = "avui", + .long_name = NULL_IF_CONFIG_SMALL("Avid Meridien Uncompressed"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_AYUV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ayuv", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed MS 4:4:4:4"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_TARGA_Y216, + .type = AVMEDIA_TYPE_VIDEO, + .name = "targa_y216", + .long_name = NULL_IF_CONFIG_SMALL("Pinnacle TARGA CineWave YUV16"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_V308, + .type = AVMEDIA_TYPE_VIDEO, + .name = "v308", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:4:4"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_V408, + .type = AVMEDIA_TYPE_VIDEO, + .name = "v408", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_YUV4, + .type = AVMEDIA_TYPE_VIDEO, + .name = "yuv4", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:2:0"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_AVRN, + .type = AVMEDIA_TYPE_VIDEO, + .name = "avrn", + .long_name = NULL_IF_CONFIG_SMALL("Avid AVI Codec"), + }, + { + .id = AV_CODEC_ID_CPIA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cpia", + .long_name = NULL_IF_CONFIG_SMALL("CPiA video format"), + }, + { + .id = AV_CODEC_ID_XFACE, + .type = AVMEDIA_TYPE_VIDEO, + .name = "xface", + .long_name = NULL_IF_CONFIG_SMALL("X-face image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SNOW, + .type = AVMEDIA_TYPE_VIDEO, + .name = "snow", + .long_name = NULL_IF_CONFIG_SMALL("Snow"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_SMVJPEG, + .type = AVMEDIA_TYPE_VIDEO, + .name = "smvjpeg", + .long_name = NULL_IF_CONFIG_SMALL("Sigmatel Motion Video"), + }, + { + .id = AV_CODEC_ID_APNG, + .type = AVMEDIA_TYPE_VIDEO, + .name = "apng", + .long_name = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"), + .props = AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/png"), + }, + { + .id = AV_CODEC_ID_DAALA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "daala", + .long_name = NULL_IF_CONFIG_SMALL("Daala"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_CFHD, + .type = AVMEDIA_TYPE_VIDEO, + .name = "cfhd", + .long_name = NULL_IF_CONFIG_SMALL("Cineform HD"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TRUEMOTION2RT, + .type = AVMEDIA_TYPE_VIDEO, + .name = "truemotion2rt", + .long_name = NULL_IF_CONFIG_SMALL("Duck TrueMotion 2.0 Real Time"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_M101, + .type = AVMEDIA_TYPE_VIDEO, + .name = "m101", + .long_name = NULL_IF_CONFIG_SMALL("Matrox Uncompressed SD"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MAGICYUV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "magicyuv", + .long_name = NULL_IF_CONFIG_SMALL("MagicYUV video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_SHEERVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "sheervideo", + .long_name = NULL_IF_CONFIG_SMALL("BitJazz SheerVideo"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_YLC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ylc", + .long_name = NULL_IF_CONFIG_SMALL("YUY2 Lossless Codec"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PSD, + .type = AVMEDIA_TYPE_VIDEO, + .name = "psd", + .long_name = NULL_IF_CONFIG_SMALL("Photoshop PSD file"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PIXLET, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pixlet", + .long_name = NULL_IF_CONFIG_SMALL("Apple Pixlet"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SPEEDHQ, + .type = AVMEDIA_TYPE_VIDEO, + .name = "speedhq", + .long_name = NULL_IF_CONFIG_SMALL("NewTek SpeedHQ"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_FMVC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "fmvc", + .long_name = NULL_IF_CONFIG_SMALL("FM Screen Capture Codec"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_SCPR, + .type = AVMEDIA_TYPE_VIDEO, + .name = "scpr", + .long_name = NULL_IF_CONFIG_SMALL("ScreenPressor"), + .props = AV_CODEC_PROP_LOSSLESS | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_CLEARVIDEO, + .type = AVMEDIA_TYPE_VIDEO, + .name = "clearvideo", + .long_name = NULL_IF_CONFIG_SMALL("Iterated Systems ClearVideo"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_XPM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "xpm", + .long_name = NULL_IF_CONFIG_SMALL("XPM (X PixMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-xpixmap"), + }, + { + .id = AV_CODEC_ID_AV1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "av1", + .long_name = NULL_IF_CONFIG_SMALL("Alliance for Open Media AV1"), + .props = AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_av1_profiles), + }, + { + .id = AV_CODEC_ID_BITPACKED, + .type = AVMEDIA_TYPE_VIDEO, + .name = "bitpacked", + .long_name = NULL_IF_CONFIG_SMALL("Bitpacked"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MSCC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mscc", + .long_name = NULL_IF_CONFIG_SMALL("Mandsoft Screen Capture Codec"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_SRGC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "srgc", + .long_name = NULL_IF_CONFIG_SMALL("Screen Recorder Gold Codec"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_SVG, + .type = AVMEDIA_TYPE_VIDEO, + .name = "svg", + .long_name = NULL_IF_CONFIG_SMALL("Scalable Vector Graphics"), + .props = AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/svg+xml"), + }, + { + .id = AV_CODEC_ID_GDV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "gdv", + .long_name = NULL_IF_CONFIG_SMALL("Gremlin Digital Video"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_FITS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "fits", + .long_name = NULL_IF_CONFIG_SMALL("FITS (Flexible Image Transport System)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_IMM4, + .type = AVMEDIA_TYPE_VIDEO, + .name = "imm4", + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM4"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PROSUMER, + .type = AVMEDIA_TYPE_VIDEO, + .name = "prosumer", + .long_name = NULL_IF_CONFIG_SMALL("Brooktree ProSumer Video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MWSC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mwsc", + .long_name = NULL_IF_CONFIG_SMALL("MatchWare Screen Capture Codec"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_WCMV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wcmv", + .long_name = NULL_IF_CONFIG_SMALL("WinCAM Motion Video"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_RASC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rasc", + .long_name = NULL_IF_CONFIG_SMALL("RemotelyAnywhere Screen Capture"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_HYMT, + .type = AVMEDIA_TYPE_VIDEO, + .name = "hymt", + .long_name = NULL_IF_CONFIG_SMALL("HuffYUV MT"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ARBC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "arbc", + .long_name = NULL_IF_CONFIG_SMALL("Gryphon's Anim Compressor"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_AGM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "agm", + .long_name = NULL_IF_CONFIG_SMALL("Amuse Graphics Movie"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_LSCR, + .type = AVMEDIA_TYPE_VIDEO, + .name = "lscr", + .long_name = NULL_IF_CONFIG_SMALL("LEAD Screen Capture"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VP4, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp4", + .long_name = NULL_IF_CONFIG_SMALL("On2 VP4"), + .props = AV_CODEC_PROP_LOSSY, + }, + + /* various PCM "codecs" */ + { + .id = AV_CODEC_ID_PCM_S16LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s16le", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16-bit little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S16BE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s16be", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16-bit big-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_U16LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_u16le", + .long_name = NULL_IF_CONFIG_SMALL("PCM unsigned 16-bit little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_U16BE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_u16be", + .long_name = NULL_IF_CONFIG_SMALL("PCM unsigned 16-bit big-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S8, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s8", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 8-bit"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_U8, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_u8", + .long_name = NULL_IF_CONFIG_SMALL("PCM unsigned 8-bit"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_MULAW, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_mulaw", + .long_name = NULL_IF_CONFIG_SMALL("PCM mu-law / G.711 mu-law"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PCM_ALAW, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_alaw", + .long_name = NULL_IF_CONFIG_SMALL("PCM A-law / G.711 A-law"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PCM_S32LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s32le", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 32-bit little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S32BE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s32be", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 32-bit big-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_U32LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_u32le", + .long_name = NULL_IF_CONFIG_SMALL("PCM unsigned 32-bit little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_U32BE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_u32be", + .long_name = NULL_IF_CONFIG_SMALL("PCM unsigned 32-bit big-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S24LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s24le", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 24-bit little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S24BE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s24be", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 24-bit big-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_U24LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_u24le", + .long_name = NULL_IF_CONFIG_SMALL("PCM unsigned 24-bit little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_U24BE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_u24be", + .long_name = NULL_IF_CONFIG_SMALL("PCM unsigned 24-bit big-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S24DAUD, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s24daud", + .long_name = NULL_IF_CONFIG_SMALL("PCM D-Cinema audio signed 24-bit"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_ZORK, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_zork", + .long_name = NULL_IF_CONFIG_SMALL("PCM Zork"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PCM_S16LE_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s16le_planar", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16-bit little-endian planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_DVD, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_dvd", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 20|24-bit big-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_F32BE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_f32be", + .long_name = NULL_IF_CONFIG_SMALL("PCM 32-bit floating point big-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_F32LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_f32le", + .long_name = NULL_IF_CONFIG_SMALL("PCM 32-bit floating point little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_F64BE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_f64be", + .long_name = NULL_IF_CONFIG_SMALL("PCM 64-bit floating point big-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_F64LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_f64le", + .long_name = NULL_IF_CONFIG_SMALL("PCM 64-bit floating point little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_BLURAY, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_bluray", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16|20|24-bit big-endian for Blu-ray media"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_LXF, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_lxf", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 20-bit little-endian planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_S302M, + .type = AVMEDIA_TYPE_AUDIO, + .name = "s302m", + .long_name = NULL_IF_CONFIG_SMALL("SMPTE 302M"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S8_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s8_planar", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 8-bit planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S24LE_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s24le_planar", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 24-bit little-endian planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S32LE_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s32le_planar", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 32-bit little-endian planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S16BE_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s16be_planar", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16-bit big-endian planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S64LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s64le", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 64-bit little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S64BE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s64be", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 64-bit big-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_F16LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_f16le", + .long_name = NULL_IF_CONFIG_SMALL("PCM 16.8 floating point little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_F24LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_f24le", + .long_name = NULL_IF_CONFIG_SMALL("PCM 24.0 floating point little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_VIDC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_vidc", + .long_name = NULL_IF_CONFIG_SMALL("PCM Archimedes VIDC"), + .props = AV_CODEC_PROP_LOSSY, + }, + + /* various ADPCM codecs */ + { + .id = AV_CODEC_ID_ADPCM_IMA_QT, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_qt", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA QuickTime"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_WAV, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_wav", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA WAV"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_DK3, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_dk3", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Duck DK3"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_DK4, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_dk4", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Duck DK4"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_WS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_ws", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Westwood"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_SMJPEG, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_smjpeg", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Loki SDL MJPEG"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_MS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ms", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Microsoft"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_4XM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_4xm", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM 4X Movie"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_XA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_xa", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM CDROM XA"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_ADX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_adx", + .long_name = NULL_IF_CONFIG_SMALL("SEGA CRI ADX ADPCM"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_EA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ea", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Electronic Arts"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_G726, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_g726", + .long_name = NULL_IF_CONFIG_SMALL("G.726 ADPCM"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_CT, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ct", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Creative Technology"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_SWF, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_swf", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Shockwave Flash"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_YAMAHA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_yamaha", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Yamaha"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_SBPRO_4, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_sbpro_4", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Sound Blaster Pro 4-bit"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_SBPRO_3, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_sbpro_3", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Sound Blaster Pro 2.6-bit"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_SBPRO_2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_sbpro_2", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Sound Blaster Pro 2-bit"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_THP, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_thp", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo THP"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_AMV, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_amv", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA AMV"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_EA_R1, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ea_r1", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Electronic Arts R1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_EA_R3, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ea_r3", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Electronic Arts R3"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_EA_R2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ea_r2", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Electronic Arts R2"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_EA_SEAD, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_ea_sead", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Electronic Arts SEAD"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_EA_EACS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_ea_eacs", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Electronic Arts EACS"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_EA_XAS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ea_xas", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Electronic Arts XAS"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_EA_MAXIS_XA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ea_maxis_xa", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Electronic Arts Maxis CDROM XA"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_ISS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_iss", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Funcom ISS"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_G722, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_g722", + .long_name = NULL_IF_CONFIG_SMALL("G.722 ADPCM"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_APC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_apc", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA CRYO APC"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_VIMA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_vima", + .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_AFC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_afc", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo Gamecube AFC"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_OKI, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_oki", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Dialogic OKI"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_DTK, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_dtk", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo Gamecube DTK"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_RAD, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_rad", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Radical"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_G726LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_g726le", + .long_name = NULL_IF_CONFIG_SMALL("G.726 ADPCM little-endian"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_THP_LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_thp_le", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo THP (Little-Endian)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_PSX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_psx", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Playstation"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_AICA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_aica", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Yamaha AICA"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_IMA_DAT4, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_dat4", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Eurocom DAT4"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_MTAF, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_mtaf", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM MTAF"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ADPCM_AGM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_agm", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM AmuseGraphics Movie AGM"), + .props = AV_CODEC_PROP_LOSSY, + }, + + /* AMR */ + { + .id = AV_CODEC_ID_AMR_NB, + .type = AVMEDIA_TYPE_AUDIO, + .name = "amr_nb", + .long_name = NULL_IF_CONFIG_SMALL("AMR-NB (Adaptive Multi-Rate NarrowBand)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_AMR_WB, + .type = AVMEDIA_TYPE_AUDIO, + .name = "amr_wb", + .long_name = NULL_IF_CONFIG_SMALL("AMR-WB (Adaptive Multi-Rate WideBand)"), + .props = AV_CODEC_PROP_LOSSY, + }, + + /* RealAudio codecs*/ + { + .id = AV_CODEC_ID_RA_144, + .type = AVMEDIA_TYPE_AUDIO, + .name = "ra_144", + .long_name = NULL_IF_CONFIG_SMALL("RealAudio 1.0 (14.4K)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_RA_288, + .type = AVMEDIA_TYPE_AUDIO, + .name = "ra_288", + .long_name = NULL_IF_CONFIG_SMALL("RealAudio 2.0 (28.8K)"), + .props = AV_CODEC_PROP_LOSSY, + }, + + /* various DPCM codecs */ + { + .id = AV_CODEC_ID_ROQ_DPCM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "roq_dpcm", + .long_name = NULL_IF_CONFIG_SMALL("DPCM id RoQ"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_INTERPLAY_DPCM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "interplay_dpcm", + .long_name = NULL_IF_CONFIG_SMALL("DPCM Interplay"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_XAN_DPCM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "xan_dpcm", + .long_name = NULL_IF_CONFIG_SMALL("DPCM Xan"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SOL_DPCM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "sol_dpcm", + .long_name = NULL_IF_CONFIG_SMALL("DPCM Sol"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SDX2_DPCM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "sdx2_dpcm", + .long_name = NULL_IF_CONFIG_SMALL("DPCM Squareroot-Delta-Exact"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_GREMLIN_DPCM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "gremlin_dpcm", + .long_name = NULL_IF_CONFIG_SMALL("DPCM Gremlin"), + .props = AV_CODEC_PROP_LOSSY, + }, + + /* audio codecs */ + { + .id = AV_CODEC_ID_MP2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "mp2", + .long_name = NULL_IF_CONFIG_SMALL("MP2 (MPEG audio layer 2)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MP3, + .type = AVMEDIA_TYPE_AUDIO, + .name = "mp3", + .long_name = NULL_IF_CONFIG_SMALL("MP3 (MPEG audio layer 3)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_AAC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "aac", + .long_name = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"), + .props = AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), + }, + { + .id = AV_CODEC_ID_AC3, + .type = AVMEDIA_TYPE_AUDIO, + .name = "ac3", + .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DTS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dts", + .long_name = NULL_IF_CONFIG_SMALL("DCA (DTS Coherent Acoustics)"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, + .profiles = NULL_IF_CONFIG_SMALL(ff_dca_profiles), + }, + { + .id = AV_CODEC_ID_VORBIS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "vorbis", + .long_name = NULL_IF_CONFIG_SMALL("Vorbis"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DVAUDIO, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dvaudio", + .long_name = NULL_IF_CONFIG_SMALL("DV audio"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WMAV1, + .type = AVMEDIA_TYPE_AUDIO, + .name = "wmav1", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WMAV2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "wmav2", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 2"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MACE3, + .type = AVMEDIA_TYPE_AUDIO, + .name = "mace3", + .long_name = NULL_IF_CONFIG_SMALL("MACE (Macintosh Audio Compression/Expansion) 3:1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MACE6, + .type = AVMEDIA_TYPE_AUDIO, + .name = "mace6", + .long_name = NULL_IF_CONFIG_SMALL("MACE (Macintosh Audio Compression/Expansion) 6:1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VMDAUDIO, + .type = AVMEDIA_TYPE_AUDIO, + .name = "vmdaudio", + .long_name = NULL_IF_CONFIG_SMALL("Sierra VMD audio"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_FLAC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "flac", + .long_name = NULL_IF_CONFIG_SMALL("FLAC (Free Lossless Audio Codec)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MP3ADU, + .type = AVMEDIA_TYPE_AUDIO, + .name = "mp3adu", + .long_name = NULL_IF_CONFIG_SMALL("ADU (Application Data Unit) MP3 (MPEG audio layer 3)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MP3ON4, + .type = AVMEDIA_TYPE_AUDIO, + .name = "mp3on4", + .long_name = NULL_IF_CONFIG_SMALL("MP3onMP4"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SHORTEN, + .type = AVMEDIA_TYPE_AUDIO, + .name = "shorten", + .long_name = NULL_IF_CONFIG_SMALL("Shorten"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ALAC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "alac", + .long_name = NULL_IF_CONFIG_SMALL("ALAC (Apple Lossless Audio Codec)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_WESTWOOD_SND1, + .type = AVMEDIA_TYPE_AUDIO, + .name = "westwood_snd1", + .long_name = NULL_IF_CONFIG_SMALL("Westwood Audio (SND1)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_GSM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "gsm", + .long_name = NULL_IF_CONFIG_SMALL("GSM"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_QDM2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "qdm2", + .long_name = NULL_IF_CONFIG_SMALL("QDesign Music Codec 2"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_COOK, + .type = AVMEDIA_TYPE_AUDIO, + .name = "cook", + .long_name = NULL_IF_CONFIG_SMALL("Cook / Cooker / Gecko (RealAudio G2)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TRUESPEECH, + .type = AVMEDIA_TYPE_AUDIO, + .name = "truespeech", + .long_name = NULL_IF_CONFIG_SMALL("DSP Group TrueSpeech"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TTA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "tta", + .long_name = NULL_IF_CONFIG_SMALL("TTA (True Audio)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_SMACKAUDIO, + .type = AVMEDIA_TYPE_AUDIO, + .name = "smackaudio", + .long_name = NULL_IF_CONFIG_SMALL("Smacker audio"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_QCELP, + .type = AVMEDIA_TYPE_AUDIO, + .name = "qcelp", + .long_name = NULL_IF_CONFIG_SMALL("QCELP / PureVoice"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WAVPACK, + .type = AVMEDIA_TYPE_AUDIO, + .name = "wavpack", + .long_name = NULL_IF_CONFIG_SMALL("WavPack"), + .props = AV_CODEC_PROP_INTRA_ONLY | + AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_DSICINAUDIO, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dsicinaudio", + .long_name = NULL_IF_CONFIG_SMALL("Delphine Software International CIN audio"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_IMC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "imc", + .long_name = NULL_IF_CONFIG_SMALL("IMC (Intel Music Coder)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MUSEPACK7, + .type = AVMEDIA_TYPE_AUDIO, + .name = "musepack7", + .long_name = NULL_IF_CONFIG_SMALL("Musepack SV7"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MLP, + .type = AVMEDIA_TYPE_AUDIO, + .name = "mlp", + .long_name = NULL_IF_CONFIG_SMALL("MLP (Meridian Lossless Packing)"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_GSM_MS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "gsm_ms", + .long_name = NULL_IF_CONFIG_SMALL("GSM Microsoft variant"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ATRAC3, + .type = AVMEDIA_TYPE_AUDIO, + .name = "atrac3", + .long_name = NULL_IF_CONFIG_SMALL("ATRAC3 (Adaptive TRansform Acoustic Coding 3)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_APE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "ape", + .long_name = NULL_IF_CONFIG_SMALL("Monkey's Audio"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_NELLYMOSER, + .type = AVMEDIA_TYPE_AUDIO, + .name = "nellymoser", + .long_name = NULL_IF_CONFIG_SMALL("Nellymoser Asao"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MUSEPACK8, + .type = AVMEDIA_TYPE_AUDIO, + .name = "musepack8", + .long_name = NULL_IF_CONFIG_SMALL("Musepack SV8"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SPEEX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "speex", + .long_name = NULL_IF_CONFIG_SMALL("Speex"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WMAVOICE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "wmavoice", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio Voice"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WMAPRO, + .type = AVMEDIA_TYPE_AUDIO, + .name = "wmapro", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio 9 Professional"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_WMALOSSLESS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "wmalossless", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Audio Lossless"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ATRAC3P, + .type = AVMEDIA_TYPE_AUDIO, + .name = "atrac3p", + .long_name = NULL_IF_CONFIG_SMALL("ATRAC3+ (Adaptive TRansform Acoustic Coding 3+)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_EAC3, + .type = AVMEDIA_TYPE_AUDIO, + .name = "eac3", + .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52B (AC-3, E-AC-3)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SIPR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "sipr", + .long_name = NULL_IF_CONFIG_SMALL("RealAudio SIPR / ACELP.NET"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MP1, + .type = AVMEDIA_TYPE_AUDIO, + .name = "mp1", + .long_name = NULL_IF_CONFIG_SMALL("MP1 (MPEG audio layer 1)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TWINVQ, + .type = AVMEDIA_TYPE_AUDIO, + .name = "twinvq", + .long_name = NULL_IF_CONFIG_SMALL("VQF TwinVQ"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TRUEHD, + .type = AVMEDIA_TYPE_AUDIO, + .name = "truehd", + .long_name = NULL_IF_CONFIG_SMALL("TrueHD"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_MP4ALS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "mp4als", + .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 Audio Lossless Coding (ALS)"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ATRAC1, + .type = AVMEDIA_TYPE_AUDIO, + .name = "atrac1", + .long_name = NULL_IF_CONFIG_SMALL("ATRAC1 (Adaptive TRansform Acoustic Coding)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_BINKAUDIO_RDFT, + .type = AVMEDIA_TYPE_AUDIO, + .name = "binkaudio_rdft", + .long_name = NULL_IF_CONFIG_SMALL("Bink Audio (RDFT)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_BINKAUDIO_DCT, + .type = AVMEDIA_TYPE_AUDIO, + .name = "binkaudio_dct", + .long_name = NULL_IF_CONFIG_SMALL("Bink Audio (DCT)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_AAC_LATM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "aac_latm", + .long_name = NULL_IF_CONFIG_SMALL("AAC LATM (Advanced Audio Coding LATM syntax)"), + .props = AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), + }, + { + .id = AV_CODEC_ID_QDMC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "qdmc", + .long_name = NULL_IF_CONFIG_SMALL("QDesign Music"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_CELT, + .type = AVMEDIA_TYPE_AUDIO, + .name = "celt", + .long_name = NULL_IF_CONFIG_SMALL("Constrained Energy Lapped Transform (CELT)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_G723_1, + .type = AVMEDIA_TYPE_AUDIO, + .name = "g723_1", + .long_name = NULL_IF_CONFIG_SMALL("G.723.1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_G729, + .type = AVMEDIA_TYPE_AUDIO, + .name = "g729", + .long_name = NULL_IF_CONFIG_SMALL("G.729"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_8SVX_EXP, + .type = AVMEDIA_TYPE_AUDIO, + .name = "8svx_exp", + .long_name = NULL_IF_CONFIG_SMALL("8SVX exponential"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_8SVX_FIB, + .type = AVMEDIA_TYPE_AUDIO, + .name = "8svx_fib", + .long_name = NULL_IF_CONFIG_SMALL("8SVX fibonacci"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_BMV_AUDIO, + .type = AVMEDIA_TYPE_AUDIO, + .name = "bmv_audio", + .long_name = NULL_IF_CONFIG_SMALL("Discworld II BMV audio"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_RALF, + .type = AVMEDIA_TYPE_AUDIO, + .name = "ralf", + .long_name = NULL_IF_CONFIG_SMALL("RealAudio Lossless"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_IAC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "iac", + .long_name = NULL_IF_CONFIG_SMALL("IAC (Indeo Audio Coder)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ILBC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "ilbc", + .long_name = NULL_IF_CONFIG_SMALL("iLBC (Internet Low Bitrate Codec)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_OPUS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "opus", + .long_name = NULL_IF_CONFIG_SMALL("Opus (Opus Interactive Audio Codec)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_COMFORT_NOISE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "comfortnoise", + .long_name = NULL_IF_CONFIG_SMALL("RFC 3389 Comfort Noise"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TAK, + .type = AVMEDIA_TYPE_AUDIO, + .name = "tak", + .long_name = NULL_IF_CONFIG_SMALL("TAK (Tom's lossless Audio Kompressor)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_METASOUND, + .type = AVMEDIA_TYPE_AUDIO, + .name = "metasound", + .long_name = NULL_IF_CONFIG_SMALL("Voxware MetaSound"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PAF_AUDIO, + .type = AVMEDIA_TYPE_AUDIO, + .name = "paf_audio", + .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Audio"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ON2AVC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "avc", + .long_name = NULL_IF_CONFIG_SMALL("On2 Audio for Video Codec"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DSS_SP, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dss_sp", + .long_name = NULL_IF_CONFIG_SMALL("Digital Speech Standard - Standard Play mode (DSS SP)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_CODEC2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "codec2", + .long_name = NULL_IF_CONFIG_SMALL("codec2 (very low bitrate speech codec)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_FFWAVESYNTH, + .type = AVMEDIA_TYPE_AUDIO, + .name = "wavesynth", + .long_name = NULL_IF_CONFIG_SMALL("Wave synthesis pseudo-codec"), + }, + { + .id = AV_CODEC_ID_SONIC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "sonic", + .long_name = NULL_IF_CONFIG_SMALL("Sonic"), + }, + { + .id = AV_CODEC_ID_SONIC_LS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "sonicls", + .long_name = NULL_IF_CONFIG_SMALL("Sonic lossless"), + }, + { + .id = AV_CODEC_ID_EVRC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "evrc", + .long_name = NULL_IF_CONFIG_SMALL("EVRC (Enhanced Variable Rate Codec)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SMV, + .type = AVMEDIA_TYPE_AUDIO, + .name = "smv", + .long_name = NULL_IF_CONFIG_SMALL("SMV (Selectable Mode Vocoder)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DSD_LSBF, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dsd_lsbf", + .long_name = NULL_IF_CONFIG_SMALL("DSD (Direct Stream Digital), least significant bit first"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DSD_MSBF, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dsd_msbf", + .long_name = NULL_IF_CONFIG_SMALL("DSD (Direct Stream Digital), most significant bit first"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DSD_LSBF_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dsd_lsbf_planar", + .long_name = NULL_IF_CONFIG_SMALL("DSD (Direct Stream Digital), least significant bit first, planar"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DSD_MSBF_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dsd_msbf_planar", + .long_name = NULL_IF_CONFIG_SMALL("DSD (Direct Stream Digital), most significant bit first, planar"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_4GV, + .type = AVMEDIA_TYPE_AUDIO, + .name = "4gv", + .long_name = NULL_IF_CONFIG_SMALL("4GV (Fourth Generation Vocoder)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_INTERPLAY_ACM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "interplayacm", + .long_name = NULL_IF_CONFIG_SMALL("Interplay ACM"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_XMA1, + .type = AVMEDIA_TYPE_AUDIO, + .name = "xma1", + .long_name = NULL_IF_CONFIG_SMALL("Xbox Media Audio 1"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_XMA2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "xma2", + .long_name = NULL_IF_CONFIG_SMALL("Xbox Media Audio 2"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_DST, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dst", + .long_name = NULL_IF_CONFIG_SMALL("DST (Direct Stream Transfer)"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ATRAC3AL, + .type = AVMEDIA_TYPE_AUDIO, + .name = "atrac3al", + .long_name = NULL_IF_CONFIG_SMALL("ATRAC3 AL (Adaptive TRansform Acoustic Coding 3 Advanced Lossless)"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ATRAC3PAL, + .type = AVMEDIA_TYPE_AUDIO, + .name = "atrac3pal", + .long_name = NULL_IF_CONFIG_SMALL("ATRAC3+ AL (Adaptive TRansform Acoustic Coding 3+ Advanced Lossless)"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_DOLBY_E, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dolby_e", + .long_name = NULL_IF_CONFIG_SMALL("Dolby E"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_APTX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "aptx", + .long_name = NULL_IF_CONFIG_SMALL("aptX (Audio Processing Technology for Bluetooth)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_APTX_HD, + .type = AVMEDIA_TYPE_AUDIO, + .name = "aptx_hd", + .long_name = NULL_IF_CONFIG_SMALL("aptX HD (Audio Processing Technology for Bluetooth)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SBC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "sbc", + .long_name = NULL_IF_CONFIG_SMALL("SBC (low-complexity subband codec)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_ATRAC9, + .type = AVMEDIA_TYPE_AUDIO, + .name = "atrac9", + .long_name = NULL_IF_CONFIG_SMALL("ATRAC9 (Adaptive TRansform Acoustic Coding 9)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_HCOM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "hcom", + .long_name = NULL_IF_CONFIG_SMALL("HCOM Audio"), + .props = AV_CODEC_PROP_LOSSY, + }, + + /* subtitle codecs */ + { + .id = AV_CODEC_ID_DVD_SUBTITLE, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "dvd_subtitle", + .long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"), + .props = AV_CODEC_PROP_BITMAP_SUB, + }, + { + .id = AV_CODEC_ID_DVB_SUBTITLE, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "dvb_subtitle", + .long_name = NULL_IF_CONFIG_SMALL("DVB subtitles"), + .props = AV_CODEC_PROP_BITMAP_SUB, + }, + { + .id = AV_CODEC_ID_TEXT, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "text", + .long_name = NULL_IF_CONFIG_SMALL("raw UTF-8 text"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_XSUB, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "xsub", + .long_name = NULL_IF_CONFIG_SMALL("XSUB"), + .props = AV_CODEC_PROP_BITMAP_SUB, + }, + { + .id = AV_CODEC_ID_SSA, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "ssa", + .long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_MOV_TEXT, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "mov_text", + .long_name = NULL_IF_CONFIG_SMALL("MOV text"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_HDMV_PGS_SUBTITLE, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "hdmv_pgs_subtitle", + .long_name = NULL_IF_CONFIG_SMALL("HDMV Presentation Graphic Stream subtitles"), + .props = AV_CODEC_PROP_BITMAP_SUB, + }, + { + .id = AV_CODEC_ID_DVB_TELETEXT, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "dvb_teletext", + .long_name = NULL_IF_CONFIG_SMALL("DVB teletext"), + }, + { + .id = AV_CODEC_ID_SRT, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "srt", + .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_MICRODVD, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "microdvd", + .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_EIA_608, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "eia_608", + .long_name = NULL_IF_CONFIG_SMALL("EIA-608 closed captions"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_JACOSUB, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "jacosub", + .long_name = NULL_IF_CONFIG_SMALL("JACOsub subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_SAMI, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "sami", + .long_name = NULL_IF_CONFIG_SMALL("SAMI subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_REALTEXT, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "realtext", + .long_name = NULL_IF_CONFIG_SMALL("RealText subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_STL, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "stl", + .long_name = NULL_IF_CONFIG_SMALL("Spruce subtitle format"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_SUBVIEWER1, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "subviewer1", + .long_name = NULL_IF_CONFIG_SMALL("SubViewer v1 subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_SUBVIEWER, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "subviewer", + .long_name = NULL_IF_CONFIG_SMALL("SubViewer subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_SUBRIP, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "subrip", + .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_WEBVTT, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "webvtt", + .long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_MPL2, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "mpl2", + .long_name = NULL_IF_CONFIG_SMALL("MPL2 subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_VPLAYER, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "vplayer", + .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_PJS, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "pjs", + .long_name = NULL_IF_CONFIG_SMALL("PJS (Phoenix Japanimation Society) subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_ASS, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "ass", + .long_name = NULL_IF_CONFIG_SMALL("ASS (Advanced SSA) subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_HDMV_TEXT_SUBTITLE, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "hdmv_text_subtitle", + .long_name = NULL_IF_CONFIG_SMALL("HDMV Text subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_TTML, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "ttml", + .long_name = NULL_IF_CONFIG_SMALL("Timed Text Markup Language"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_ARIB_CAPTION, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "arib_caption", + .long_name = NULL_IF_CONFIG_SMALL("ARIB STD-B24 caption"), + .props = AV_CODEC_PROP_TEXT_SUB, + .profiles = NULL_IF_CONFIG_SMALL(ff_arib_caption_profiles), + }, + + /* other kind of codecs and pseudo-codecs */ + { + .id = AV_CODEC_ID_TTF, + .type = AVMEDIA_TYPE_DATA, + .name = "ttf", + .long_name = NULL_IF_CONFIG_SMALL("TrueType font"), + .mime_types= MT("application/x-truetype-font", "application/x-font"), + }, + { + .id = AV_CODEC_ID_SCTE_35, + .type = AVMEDIA_TYPE_DATA, + .name = "scte_35", + .long_name = NULL_IF_CONFIG_SMALL("SCTE 35 Message Queue"), + }, + { + .id = AV_CODEC_ID_BINTEXT, + .type = AVMEDIA_TYPE_VIDEO, + .name = "bintext", + .long_name = NULL_IF_CONFIG_SMALL("Binary text"), + .props = AV_CODEC_PROP_INTRA_ONLY, + }, + { + .id = AV_CODEC_ID_XBIN, + .type = AVMEDIA_TYPE_VIDEO, + .name = "xbin", + .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text"), + .props = AV_CODEC_PROP_INTRA_ONLY, + }, + { + .id = AV_CODEC_ID_IDF, + .type = AVMEDIA_TYPE_VIDEO, + .name = "idf", + .long_name = NULL_IF_CONFIG_SMALL("iCEDraw text"), + .props = AV_CODEC_PROP_INTRA_ONLY, + }, + { + .id = AV_CODEC_ID_OTF, + .type = AVMEDIA_TYPE_DATA, + .name = "otf", + .long_name = NULL_IF_CONFIG_SMALL("OpenType font"), + .mime_types= MT("application/vnd.ms-opentype"), + }, + { + .id = AV_CODEC_ID_SMPTE_KLV, + .type = AVMEDIA_TYPE_DATA, + .name = "klv", + .long_name = NULL_IF_CONFIG_SMALL("SMPTE 336M Key-Length-Value (KLV) metadata"), + }, + { + .id = AV_CODEC_ID_DVD_NAV, + .type = AVMEDIA_TYPE_DATA, + .name = "dvd_nav_packet", + .long_name = NULL_IF_CONFIG_SMALL("DVD Nav packet"), + }, + { + .id = AV_CODEC_ID_TIMED_ID3, + .type = AVMEDIA_TYPE_DATA, + .name = "timed_id3", + .long_name = NULL_IF_CONFIG_SMALL("timed ID3 metadata"), + }, + { + .id = AV_CODEC_ID_BIN_DATA, + .type = AVMEDIA_TYPE_DATA, + .name = "bin_data", + .long_name = NULL_IF_CONFIG_SMALL("binary data"), + .mime_types= MT("application/octet-stream"), + }, + { + .id = AV_CODEC_ID_WRAPPED_AVFRAME, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wrapped_avframe", + .long_name = NULL_IF_CONFIG_SMALL("AVFrame to AVPacket passthrough"), + .props = AV_CODEC_PROP_LOSSLESS, + }, +}; + +static int descriptor_compare(const void *key, const void *member) +{ + enum AVCodecID id = *(const enum AVCodecID *) key; + const AVCodecDescriptor *desc = member; + + return id - desc->id; +} + +const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id) +{ + return bsearch(&id, codec_descriptors, FF_ARRAY_ELEMS(codec_descriptors), + sizeof(codec_descriptors[0]), descriptor_compare); +} + +const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev) +{ + if (!prev) + return &codec_descriptors[0]; + if (prev - codec_descriptors < FF_ARRAY_ELEMS(codec_descriptors) - 1) + return prev + 1; + return NULL; +} + +const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name) +{ + const AVCodecDescriptor *desc = NULL; + + while ((desc = avcodec_descriptor_next(desc))) + if (!strcmp(desc->name, name)) + return desc; + return NULL; +} + +enum AVMediaType avcodec_get_type(enum AVCodecID codec_id) +{ + const AVCodecDescriptor *desc = avcodec_descriptor_get(codec_id); + return desc ? desc->type : AVMEDIA_TYPE_UNKNOWN; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/codec_list.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/codec_list.c new file mode 100644 index 0000000000..7a4fa626f8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/codec_list.c @@ -0,0 +1,9 @@ +static const AVCodec * const codec_list[] = { + &ff_aac_encoder, + &ff_opus_encoder, + &ff_libopus_encoder, + &ff_aac_decoder, + &ff_aac_fixed_decoder, + &ff_aac_latm_decoder, + &ff_libopus_decoder, + NULL }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/d3d11va.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/d3d11va.c new file mode 100644 index 0000000000..9967f322c9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/d3d11va.c @@ -0,0 +1,48 @@ +/* + * Direct3D11 HW acceleration + * + * copyright (c) 2015 Steve Lhomme + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" + +#if CONFIG_D3D11VA +#include "libavutil/error.h" +#include "libavutil/mem.h" + +#include "d3d11va.h" + +AVD3D11VAContext *av_d3d11va_alloc_context(void) +{ + AVD3D11VAContext* res = av_mallocz(sizeof(AVD3D11VAContext)); + if (!res) + return NULL; + res->context_mutex = INVALID_HANDLE_VALUE; + return res; +} +#else +struct AVD3D11VAContext *av_d3d11va_alloc_context(void); + +struct AVD3D11VAContext *av_d3d11va_alloc_context(void) +{ + return NULL; +} +#endif /* CONFIG_D3D11VA */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/d3d11va.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/d3d11va.h new file mode 100644 index 0000000000..6816b6c1e6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/d3d11va.h @@ -0,0 +1,112 @@ +/* + * Direct3D11 HW acceleration + * + * copyright (c) 2009 Laurent Aimar + * copyright (c) 2015 Steve Lhomme + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_D3D11VA_H +#define AVCODEC_D3D11VA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_d3d11va + * Public libavcodec D3D11VA header. + */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif + +#include +#include + +/** + * @defgroup lavc_codec_hwaccel_d3d11va Direct3D11 + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG 1 ///< Work around for Direct3D11 and old UVD/UVD+ ATI video cards +#define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 ///< Work around for Direct3D11 and old Intel GPUs with ClearVideo interface + +/** + * This structure is used to provides the necessary configurations and data + * to the Direct3D11 FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + * + * Use av_d3d11va_alloc_context() exclusively to allocate an AVD3D11VAContext. + */ +typedef struct AVD3D11VAContext { + /** + * D3D11 decoder object + */ + ID3D11VideoDecoder *decoder; + + /** + * D3D11 VideoContext + */ + ID3D11VideoContext *video_context; + + /** + * D3D11 configuration used to create the decoder + */ + D3D11_VIDEO_DECODER_CONFIG *cfg; + + /** + * The number of surface in the surface array + */ + unsigned surface_count; + + /** + * The array of Direct3D surfaces used to create the decoder + */ + ID3D11VideoDecoderOutputView **surface; + + /** + * A bit field configuring the workarounds needed for using the decoder + */ + uint64_t workaround; + + /** + * Private to the FFmpeg AVHWAccel implementation + */ + unsigned report_id; + + /** + * Mutex to access video_context + */ + HANDLE context_mutex; +} AVD3D11VAContext; + +/** + * Allocate an AVD3D11VAContext. + * + * @return Newly-allocated AVD3D11VAContext or NULL on failure. + */ +AVD3D11VAContext *av_d3d11va_alloc_context(void); + +/** + * @} + */ + +#endif /* AVCODEC_D3D11VA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dct.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dct.h new file mode 100644 index 0000000000..0a03e256d1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dct.h @@ -0,0 +1,69 @@ +/* + * (I)DCT Transforms + * Copyright (c) 2009 Peter Ross + * Copyright (c) 2010 Alex Converse + * Copyright (c) 2010 Vitor Sessak + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined(AVCODEC_DCT_H) && (!defined(FFT_FLOAT) || FFT_FLOAT) +#define AVCODEC_DCT_H + +#include +#include + +#include "rdft.h" + +struct DCTContext { + int nbits; + int inverse; + RDFTContext rdft; + const float *costab; + FFTSample *csc2; + void (*dct_calc)(struct DCTContext *s, FFTSample *data); + void (*dct32)(FFTSample *out, const FFTSample *in); +}; + +/** + * Set up DCT. + * @param nbits size of the input array: + * (1 << nbits) for DCT-II, DCT-III and DST-I + * (1 << nbits) + 1 for DCT-I + * + * @note the first element of the input of DST-I is ignored + */ +int ff_dct_init(DCTContext *s, int nbits, enum DCTTransformType type); +void ff_dct_end (DCTContext *s); + +void ff_dct_init_x86(DCTContext *s); + +void ff_fdct_ifast(int16_t *data); +void ff_fdct_ifast248(int16_t *data); +void ff_jpeg_fdct_islow_8(int16_t *data); +void ff_jpeg_fdct_islow_10(int16_t *data); +void ff_fdct248_islow_8(int16_t *data); +void ff_fdct248_islow_10(int16_t *data); + +void ff_j_rev_dct(int16_t *data); +void ff_j_rev_dct4(int16_t *data); +void ff_j_rev_dct2(int16_t *data); +void ff_j_rev_dct1(int16_t *data); +void ff_jref_idct_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_jref_idct_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block); + +#endif /* AVCODEC_DCT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/decode.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/decode.c new file mode 100644 index 0000000000..6c31166ec2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/decode.c @@ -0,0 +1,2062 @@ +/* + * generic decoding-related code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "config.h" + +#if CONFIG_ICONV +# include +#endif + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/bprint.h" +#include "libavutil/common.h" +#include "libavutil/frame.h" +#include "libavutil/hwcontext.h" +#include "libavutil/imgutils.h" +#include "libavutil/internal.h" +#include "libavutil/intmath.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "decode.h" +#include "hwaccel.h" +#include "internal.h" +#include "thread.h" + +static int apply_param_change(AVCodecContext *avctx, const AVPacket *avpkt) +{ + int size = 0, ret; + const uint8_t *data; + uint32_t flags; + int64_t val; + + data = av_packet_get_side_data(avpkt, AV_PKT_DATA_PARAM_CHANGE, &size); + if (!data) + return 0; + + if (!(avctx->codec->capabilities & AV_CODEC_CAP_PARAM_CHANGE)) { + av_log(avctx, AV_LOG_ERROR, "This decoder does not support parameter " + "changes, but PARAM_CHANGE side data was sent to it.\n"); + ret = AVERROR(EINVAL); + goto fail2; + } + + if (size < 4) + goto fail; + + flags = bytestream_get_le32(&data); + size -= 4; + + if (flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) { + if (size < 4) + goto fail; + val = bytestream_get_le32(&data); + if (val <= 0 || val > INT_MAX) { + av_log(avctx, AV_LOG_ERROR, "Invalid channel count"); + ret = AVERROR_INVALIDDATA; + goto fail2; + } + avctx->channels = val; + size -= 4; + } + if (flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) { + if (size < 8) + goto fail; + avctx->channel_layout = bytestream_get_le64(&data); + size -= 8; + } + if (flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) { + if (size < 4) + goto fail; + val = bytestream_get_le32(&data); + if (val <= 0 || val > INT_MAX) { + av_log(avctx, AV_LOG_ERROR, "Invalid sample rate"); + ret = AVERROR_INVALIDDATA; + goto fail2; + } + avctx->sample_rate = val; + size -= 4; + } + if (flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) { + if (size < 8) + goto fail; + avctx->width = bytestream_get_le32(&data); + avctx->height = bytestream_get_le32(&data); + size -= 8; + ret = ff_set_dimensions(avctx, avctx->width, avctx->height); + if (ret < 0) + goto fail2; + } + + return 0; +fail: + av_log(avctx, AV_LOG_ERROR, "PARAM_CHANGE side data too small.\n"); + ret = AVERROR_INVALIDDATA; +fail2: + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n"); + if (avctx->err_recognition & AV_EF_EXPLODE) + return ret; + } + return 0; +} + +static int extract_packet_props(AVCodecInternal *avci, const AVPacket *pkt) +{ + int ret = 0; + + av_packet_unref(avci->last_pkt_props); + if (pkt) { + ret = av_packet_copy_props(avci->last_pkt_props, pkt); + if (!ret) + avci->last_pkt_props->size = pkt->size; // HACK: Needed for ff_decode_frame_props(). + } + return ret; +} + +static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame) +{ + int ret; + + /* move the original frame to our backup */ + av_frame_unref(avci->to_free); + av_frame_move_ref(avci->to_free, frame); + + /* now copy everything except the AVBufferRefs back + * note that we make a COPY of the side data, so calling av_frame_free() on + * the caller's frame will work properly */ + ret = av_frame_copy_props(frame, avci->to_free); + if (ret < 0) + return ret; + + memcpy(frame->data, avci->to_free->data, sizeof(frame->data)); + memcpy(frame->linesize, avci->to_free->linesize, sizeof(frame->linesize)); + if (avci->to_free->extended_data != avci->to_free->data) { + int planes = avci->to_free->channels; + int size = planes * sizeof(*frame->extended_data); + + if (!size) { + av_frame_unref(frame); + return AVERROR_BUG; + } + + frame->extended_data = av_malloc(size); + if (!frame->extended_data) { + av_frame_unref(frame); + return AVERROR(ENOMEM); + } + memcpy(frame->extended_data, avci->to_free->extended_data, + size); + } else + frame->extended_data = frame->data; + + frame->format = avci->to_free->format; + frame->width = avci->to_free->width; + frame->height = avci->to_free->height; + frame->channel_layout = avci->to_free->channel_layout; + frame->nb_samples = avci->to_free->nb_samples; + frame->channels = avci->to_free->channels; + + return 0; +} + +int ff_decode_bsfs_init(AVCodecContext *avctx) +{ + AVCodecInternal *avci = avctx->internal; + DecodeFilterContext *s = &avci->filter; + const char *bsfs_str; + int ret; + + if (s->nb_bsfs) + return 0; + + bsfs_str = avctx->codec->bsfs ? avctx->codec->bsfs : "null"; + while (bsfs_str && *bsfs_str) { + AVBSFContext **tmp; + const AVBitStreamFilter *filter; + char *bsf, *bsf_options_str, *bsf_name; + + bsf = av_get_token(&bsfs_str, ","); + if (!bsf) { + ret = AVERROR(ENOMEM); + goto fail; + } + bsf_name = av_strtok(bsf, "=", &bsf_options_str); + if (!bsf_name) { + av_freep(&bsf); + ret = AVERROR(ENOMEM); + goto fail; + } + + filter = av_bsf_get_by_name(bsf_name); + if (!filter) { + av_log(avctx, AV_LOG_ERROR, "A non-existing bitstream filter %s " + "requested by a decoder. This is a bug, please report it.\n", + bsf_name); + av_freep(&bsf); + ret = AVERROR_BUG; + goto fail; + } + + tmp = av_realloc_array(s->bsfs, s->nb_bsfs + 1, sizeof(*s->bsfs)); + if (!tmp) { + av_freep(&bsf); + ret = AVERROR(ENOMEM); + goto fail; + } + s->bsfs = tmp; + s->nb_bsfs++; + + ret = av_bsf_alloc(filter, &s->bsfs[s->nb_bsfs - 1]); + if (ret < 0) { + av_freep(&bsf); + goto fail; + } + + if (s->nb_bsfs == 1) { + /* We do not currently have an API for passing the input timebase into decoders, + * but no filters used here should actually need it. + * So we make up some plausible-looking number (the MPEG 90kHz timebase) */ + s->bsfs[s->nb_bsfs - 1]->time_base_in = (AVRational){ 1, 90000 }; + ret = avcodec_parameters_from_context(s->bsfs[s->nb_bsfs - 1]->par_in, + avctx); + } else { + s->bsfs[s->nb_bsfs - 1]->time_base_in = s->bsfs[s->nb_bsfs - 2]->time_base_out; + ret = avcodec_parameters_copy(s->bsfs[s->nb_bsfs - 1]->par_in, + s->bsfs[s->nb_bsfs - 2]->par_out); + } + if (ret < 0) { + av_freep(&bsf); + goto fail; + } + + if (bsf_options_str && filter->priv_class) { + const AVOption *opt = av_opt_next(s->bsfs[s->nb_bsfs - 1]->priv_data, NULL); + const char * shorthand[2] = {NULL}; + + if (opt) + shorthand[0] = opt->name; + + ret = av_opt_set_from_string(s->bsfs[s->nb_bsfs - 1]->priv_data, bsf_options_str, shorthand, "=", ":"); + if (ret < 0) { + if (ret != AVERROR(ENOMEM)) { + av_log(avctx, AV_LOG_ERROR, "Invalid options for bitstream filter %s " + "requested by the decoder. This is a bug, please report it.\n", + bsf_name); + ret = AVERROR_BUG; + } + av_freep(&bsf); + goto fail; + } + } + av_freep(&bsf); + + ret = av_bsf_init(s->bsfs[s->nb_bsfs - 1]); + if (ret < 0) + goto fail; + + if (*bsfs_str) + bsfs_str++; + } + + return 0; +fail: + ff_decode_bsfs_uninit(avctx); + return ret; +} + +/* try to get one output packet from the filter chain */ +static int bsfs_poll(AVCodecContext *avctx, AVPacket *pkt) +{ + DecodeFilterContext *s = &avctx->internal->filter; + int idx, ret; + + /* start with the last filter in the chain */ + idx = s->nb_bsfs - 1; + while (idx >= 0) { + /* request a packet from the currently selected filter */ + ret = av_bsf_receive_packet(s->bsfs[idx], pkt); + if (ret == AVERROR(EAGAIN)) { + /* no packets available, try the next filter up the chain */ + ret = 0; + idx--; + continue; + } else if (ret < 0 && ret != AVERROR_EOF) { + return ret; + } + + /* got a packet or EOF -- pass it to the caller or to the next filter + * down the chain */ + if (idx == s->nb_bsfs - 1) { + return ret; + } else { + idx++; + ret = av_bsf_send_packet(s->bsfs[idx], ret < 0 ? NULL : pkt); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "Error pre-processing a packet before decoding\n"); + av_packet_unref(pkt); + return ret; + } + } + } + + return AVERROR(EAGAIN); +} + +int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt) +{ + AVCodecInternal *avci = avctx->internal; + int ret; + + if (avci->draining) + return AVERROR_EOF; + + ret = bsfs_poll(avctx, pkt); + if (ret == AVERROR_EOF) + avci->draining = 1; + if (ret < 0) + return ret; + + ret = extract_packet_props(avctx->internal, pkt); + if (ret < 0) + goto finish; + + ret = apply_param_change(avctx, pkt); + if (ret < 0) + goto finish; + + if (avctx->codec->receive_frame) + avci->compat_decode_consumed += pkt->size; + + return 0; +finish: + av_packet_unref(pkt); + return ret; +} + +/** + * Attempt to guess proper monotonic timestamps for decoded video frames + * which might have incorrect times. Input timestamps may wrap around, in + * which case the output will as well. + * + * @param pts the pts field of the decoded AVPacket, as passed through + * AVFrame.pts + * @param dts the dts field of the decoded AVPacket + * @return one of the input values, may be AV_NOPTS_VALUE + */ +static int64_t guess_correct_pts(AVCodecContext *ctx, + int64_t reordered_pts, int64_t dts) +{ + int64_t pts = AV_NOPTS_VALUE; + + if (dts != AV_NOPTS_VALUE) { + ctx->pts_correction_num_faulty_dts += dts <= ctx->pts_correction_last_dts; + ctx->pts_correction_last_dts = dts; + } else if (reordered_pts != AV_NOPTS_VALUE) + ctx->pts_correction_last_dts = reordered_pts; + + if (reordered_pts != AV_NOPTS_VALUE) { + ctx->pts_correction_num_faulty_pts += reordered_pts <= ctx->pts_correction_last_pts; + ctx->pts_correction_last_pts = reordered_pts; + } else if(dts != AV_NOPTS_VALUE) + ctx->pts_correction_last_pts = dts; + + if ((ctx->pts_correction_num_faulty_pts<=ctx->pts_correction_num_faulty_dts || dts == AV_NOPTS_VALUE) + && reordered_pts != AV_NOPTS_VALUE) + pts = reordered_pts; + else + pts = dts; + + return pts; +} + +/* + * The core of the receive_frame_wrapper for the decoders implementing + * the simple API. Certain decoders might consume partial packets without + * returning any output, so this function needs to be called in a loop until it + * returns EAGAIN. + **/ +static int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame) +{ + AVCodecInternal *avci = avctx->internal; + DecodeSimpleContext *ds = &avci->ds; + AVPacket *pkt = ds->in_pkt; + // copy to ensure we do not change pkt + int got_frame, actual_got_frame; + int ret; + + if (!pkt->data && !avci->draining) { + av_packet_unref(pkt); + ret = ff_decode_get_packet(avctx, pkt); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + } + + // Some codecs (at least wma lossless) will crash when feeding drain packets + // after EOF was signaled. + if (avci->draining_done) + return AVERROR_EOF; + + if (!pkt->data && + !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY || + avctx->active_thread_type & FF_THREAD_FRAME)) + return AVERROR_EOF; + + got_frame = 0; + + if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) { + ret = ff_thread_decode_frame(avctx, frame, &got_frame, pkt); + } else { + ret = avctx->codec->decode(avctx, frame, &got_frame, pkt); + + if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS)) + frame->pkt_dts = pkt->dts; + if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) { + if(!avctx->has_b_frames) + frame->pkt_pos = pkt->pos; + //FIXME these should be under if(!avctx->has_b_frames) + /* get_buffer is supposed to set frame parameters */ + if (!(avctx->codec->capabilities & AV_CODEC_CAP_DR1)) { + if (!frame->sample_aspect_ratio.num) frame->sample_aspect_ratio = avctx->sample_aspect_ratio; + if (!frame->width) frame->width = avctx->width; + if (!frame->height) frame->height = avctx->height; + if (frame->format == AV_PIX_FMT_NONE) frame->format = avctx->pix_fmt; + } + } + } + emms_c(); + actual_got_frame = got_frame; + + if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) { + if (frame->flags & AV_FRAME_FLAG_DISCARD) + got_frame = 0; + if (got_frame) + frame->best_effort_timestamp = guess_correct_pts(avctx, + frame->pts, + frame->pkt_dts); + } else if (avctx->codec->type == AVMEDIA_TYPE_AUDIO) { + uint8_t *side; + int side_size; + uint32_t discard_padding = 0; + uint8_t skip_reason = 0; + uint8_t discard_reason = 0; + + if (ret >= 0 && got_frame) { + frame->best_effort_timestamp = guess_correct_pts(avctx, + frame->pts, + frame->pkt_dts); + if (frame->format == AV_SAMPLE_FMT_NONE) + frame->format = avctx->sample_fmt; + if (!frame->channel_layout) + frame->channel_layout = avctx->channel_layout; + if (!frame->channels) + frame->channels = avctx->channels; + if (!frame->sample_rate) + frame->sample_rate = avctx->sample_rate; + } + + side= av_packet_get_side_data(avci->last_pkt_props, AV_PKT_DATA_SKIP_SAMPLES, &side_size); + if(side && side_size>=10) { + avctx->internal->skip_samples = AV_RL32(side) * avctx->internal->skip_samples_multiplier; + discard_padding = AV_RL32(side + 4); + av_log(avctx, AV_LOG_DEBUG, "skip %d / discard %d samples due to side data\n", + avctx->internal->skip_samples, (int)discard_padding); + skip_reason = AV_RL8(side + 8); + discard_reason = AV_RL8(side + 9); + } + + if ((frame->flags & AV_FRAME_FLAG_DISCARD) && got_frame && + !(avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) { + avctx->internal->skip_samples = FFMAX(0, avctx->internal->skip_samples - frame->nb_samples); + got_frame = 0; + } + + if (avctx->internal->skip_samples > 0 && got_frame && + !(avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) { + if(frame->nb_samples <= avctx->internal->skip_samples){ + got_frame = 0; + avctx->internal->skip_samples -= frame->nb_samples; + av_log(avctx, AV_LOG_DEBUG, "skip whole frame, skip left: %d\n", + avctx->internal->skip_samples); + } else { + av_samples_copy(frame->extended_data, frame->extended_data, 0, avctx->internal->skip_samples, + frame->nb_samples - avctx->internal->skip_samples, avctx->channels, frame->format); + if(avctx->pkt_timebase.num && avctx->sample_rate) { + int64_t diff_ts = av_rescale_q(avctx->internal->skip_samples, + (AVRational){1, avctx->sample_rate}, + avctx->pkt_timebase); + if(frame->pts!=AV_NOPTS_VALUE) + frame->pts += diff_ts; +#if FF_API_PKT_PTS +FF_DISABLE_DEPRECATION_WARNINGS + if(frame->pkt_pts!=AV_NOPTS_VALUE) + frame->pkt_pts += diff_ts; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + if(frame->pkt_dts!=AV_NOPTS_VALUE) + frame->pkt_dts += diff_ts; + if (frame->pkt_duration >= diff_ts) + frame->pkt_duration -= diff_ts; + } else { + av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for skipped samples.\n"); + } + av_log(avctx, AV_LOG_DEBUG, "skip %d/%d samples\n", + avctx->internal->skip_samples, frame->nb_samples); + frame->nb_samples -= avctx->internal->skip_samples; + avctx->internal->skip_samples = 0; + } + } + + if (discard_padding > 0 && discard_padding <= frame->nb_samples && got_frame && + !(avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL)) { + if (discard_padding == frame->nb_samples) { + got_frame = 0; + } else { + if(avctx->pkt_timebase.num && avctx->sample_rate) { + int64_t diff_ts = av_rescale_q(frame->nb_samples - discard_padding, + (AVRational){1, avctx->sample_rate}, + avctx->pkt_timebase); + frame->pkt_duration = diff_ts; + } else { + av_log(avctx, AV_LOG_WARNING, "Could not update timestamps for discarded samples.\n"); + } + av_log(avctx, AV_LOG_DEBUG, "discard %d/%d samples\n", + (int)discard_padding, frame->nb_samples); + frame->nb_samples -= discard_padding; + } + } + + if ((avctx->flags2 & AV_CODEC_FLAG2_SKIP_MANUAL) && got_frame) { + AVFrameSideData *fside = av_frame_new_side_data(frame, AV_FRAME_DATA_SKIP_SAMPLES, 10); + if (fside) { + AV_WL32(fside->data, avctx->internal->skip_samples); + AV_WL32(fside->data + 4, discard_padding); + AV_WL8(fside->data + 8, skip_reason); + AV_WL8(fside->data + 9, discard_reason); + avctx->internal->skip_samples = 0; + } + } + } + + if (avctx->codec->type == AVMEDIA_TYPE_AUDIO && + !avci->showed_multi_packet_warning && + ret >= 0 && ret != pkt->size && !(avctx->codec->capabilities & AV_CODEC_CAP_SUBFRAMES)) { + av_log(avctx, AV_LOG_WARNING, "Multiple frames in a packet.\n"); + avci->showed_multi_packet_warning = 1; + } + + if (!got_frame) + av_frame_unref(frame); + + if (ret >= 0 && avctx->codec->type == AVMEDIA_TYPE_VIDEO && !(avctx->flags & AV_CODEC_FLAG_TRUNCATED)) + ret = pkt->size; + +#if FF_API_AVCTX_TIMEBASE + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1})); +#endif + + /* do not stop draining when actual_got_frame != 0 or ret < 0 */ + /* got_frame == 0 but actual_got_frame != 0 when frame is discarded */ + if (avctx->internal->draining && !actual_got_frame) { + if (ret < 0) { + /* prevent infinite loop if a decoder wrongly always return error on draining */ + /* reasonable nb_errors_max = maximum b frames + thread count */ + int nb_errors_max = 20 + (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME ? + avctx->thread_count : 1); + + if (avci->nb_draining_errors++ >= nb_errors_max) { + av_log(avctx, AV_LOG_ERROR, "Too many errors when draining, this is a bug. " + "Stop draining and force EOF.\n"); + avci->draining_done = 1; + ret = AVERROR_BUG; + } + } else { + avci->draining_done = 1; + } + } + + avci->compat_decode_consumed += ret; + + if (ret >= pkt->size || ret < 0) { + av_packet_unref(pkt); + } else { + int consumed = ret; + + pkt->data += consumed; + pkt->size -= consumed; + avci->last_pkt_props->size -= consumed; // See extract_packet_props() comment. + pkt->pts = AV_NOPTS_VALUE; + pkt->dts = AV_NOPTS_VALUE; + avci->last_pkt_props->pts = AV_NOPTS_VALUE; + avci->last_pkt_props->dts = AV_NOPTS_VALUE; + } + + if (got_frame) + av_assert0(frame->buf[0]); + + return ret < 0 ? ret : 0; +} + +static int decode_simple_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + int ret; + + while (!frame->buf[0]) { + ret = decode_simple_internal(avctx, frame); + if (ret < 0) + return ret; + } + + return 0; +} + +static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) +{ + AVCodecInternal *avci = avctx->internal; + int ret; + + av_assert0(!frame->buf[0]); + + if (avctx->codec->receive_frame) + ret = avctx->codec->receive_frame(avctx, frame); + else + ret = decode_simple_receive_frame(avctx, frame); + + if (ret == AVERROR_EOF) + avci->draining_done = 1; + + if (!ret) { + /* the only case where decode data is not set should be decoders + * that do not call ff_get_buffer() */ + av_assert0((frame->private_ref && frame->private_ref->size == sizeof(FrameDecodeData)) || + !(avctx->codec->capabilities & AV_CODEC_CAP_DR1)); + + if (frame->private_ref) { + FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + + if (fdd->post_process) { + ret = fdd->post_process(avctx, frame); + if (ret < 0) { + av_frame_unref(frame); + return ret; + } + } + } + } + + /* free the per-frame decode data */ + av_buffer_unref(&frame->private_ref); + + return ret; +} + +int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt) +{ + AVCodecInternal *avci = avctx->internal; + int ret; + + if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec)) + return AVERROR(EINVAL); + + if (avctx->internal->draining) + return AVERROR_EOF; + + if (avpkt && !avpkt->size && avpkt->data) + return AVERROR(EINVAL); + + av_packet_unref(avci->buffer_pkt); + if (avpkt && (avpkt->data || avpkt->side_data_elems)) { + ret = av_packet_ref(avci->buffer_pkt, avpkt); + if (ret < 0) + return ret; + } + + ret = av_bsf_send_packet(avci->filter.bsfs[0], avci->buffer_pkt); + if (ret < 0) { + av_packet_unref(avci->buffer_pkt); + return ret; + } + + if (!avci->buffer_frame->buf[0]) { + ret = decode_receive_frame_internal(avctx, avci->buffer_frame); + if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) + return ret; + } + + return 0; +} + +static int apply_cropping(AVCodecContext *avctx, AVFrame *frame) +{ + /* make sure we are noisy about decoders returning invalid cropping data */ + if (frame->crop_left >= INT_MAX - frame->crop_right || + frame->crop_top >= INT_MAX - frame->crop_bottom || + (frame->crop_left + frame->crop_right) >= frame->width || + (frame->crop_top + frame->crop_bottom) >= frame->height) { + av_log(avctx, AV_LOG_WARNING, + "Invalid cropping information set by a decoder: " + "%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER"/%"SIZE_SPECIFIER" " + "(frame size %dx%d). This is a bug, please report it\n", + frame->crop_left, frame->crop_right, frame->crop_top, frame->crop_bottom, + frame->width, frame->height); + frame->crop_left = 0; + frame->crop_right = 0; + frame->crop_top = 0; + frame->crop_bottom = 0; + return 0; + } + + if (!avctx->apply_cropping) + return 0; + + return av_frame_apply_cropping(frame, avctx->flags & AV_CODEC_FLAG_UNALIGNED ? + AV_FRAME_CROP_UNALIGNED : 0); +} + +int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + AVCodecInternal *avci = avctx->internal; + int ret, changed; + + av_frame_unref(frame); + + if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec)) + return AVERROR(EINVAL); + + if (avci->buffer_frame->buf[0]) { + av_frame_move_ref(frame, avci->buffer_frame); + } else { + ret = decode_receive_frame_internal(avctx, frame); + if (ret < 0) + return ret; + } + + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + ret = apply_cropping(avctx, frame); + if (ret < 0) { + av_frame_unref(frame); + return ret; + } + } + + avctx->frame_number++; + + if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) { + + if (avctx->frame_number == 1) { + avci->initial_format = frame->format; + switch(avctx->codec_type) { + case AVMEDIA_TYPE_VIDEO: + avci->initial_width = frame->width; + avci->initial_height = frame->height; + break; + case AVMEDIA_TYPE_AUDIO: + avci->initial_sample_rate = frame->sample_rate ? frame->sample_rate : + avctx->sample_rate; + avci->initial_channels = frame->channels; + avci->initial_channel_layout = frame->channel_layout; + break; + } + } + + if (avctx->frame_number > 1) { + changed = avci->initial_format != frame->format; + + switch(avctx->codec_type) { + case AVMEDIA_TYPE_VIDEO: + changed |= avci->initial_width != frame->width || + avci->initial_height != frame->height; + break; + case AVMEDIA_TYPE_AUDIO: + changed |= avci->initial_sample_rate != frame->sample_rate || + avci->initial_sample_rate != avctx->sample_rate || + avci->initial_channels != frame->channels || + avci->initial_channel_layout != frame->channel_layout; + break; + } + + if (changed) { + avci->changed_frames_dropped++; + av_log(avctx, AV_LOG_INFO, "dropped changed frame #%d pts %"PRId64 + " drop count: %d \n", + avctx->frame_number, frame->pts, + avci->changed_frames_dropped); + av_frame_unref(frame); + return AVERROR_INPUT_CHANGED; + } + } + } + return 0; +} + +static int compat_decode(AVCodecContext *avctx, AVFrame *frame, + int *got_frame, const AVPacket *pkt) +{ + AVCodecInternal *avci = avctx->internal; + int ret = 0; + + av_assert0(avci->compat_decode_consumed == 0); + + if (avci->draining_done && pkt && pkt->size != 0) { + av_log(avctx, AV_LOG_WARNING, "Got unexpected packet after EOF\n"); + avcodec_flush_buffers(avctx); + } + + *got_frame = 0; + avci->compat_decode = 1; + + if (avci->compat_decode_partial_size > 0 && + avci->compat_decode_partial_size != pkt->size) { + av_log(avctx, AV_LOG_ERROR, + "Got unexpected packet size after a partial decode\n"); + ret = AVERROR(EINVAL); + goto finish; + } + + if (!avci->compat_decode_partial_size) { + ret = avcodec_send_packet(avctx, pkt); + if (ret == AVERROR_EOF) + ret = 0; + else if (ret == AVERROR(EAGAIN)) { + /* we fully drain all the output in each decode call, so this should not + * ever happen */ + ret = AVERROR_BUG; + goto finish; + } else if (ret < 0) + goto finish; + } + + while (ret >= 0) { + ret = avcodec_receive_frame(avctx, frame); + if (ret < 0) { + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + ret = 0; + goto finish; + } + + if (frame != avci->compat_decode_frame) { + if (!avctx->refcounted_frames) { + ret = unrefcount_frame(avci, frame); + if (ret < 0) + goto finish; + } + + *got_frame = 1; + frame = avci->compat_decode_frame; + } else { + if (!avci->compat_decode_warned) { + av_log(avctx, AV_LOG_WARNING, "The deprecated avcodec_decode_* " + "API cannot return all the frames for this decoder. " + "Some frames will be dropped. Update your code to the " + "new decoding API to fix this.\n"); + avci->compat_decode_warned = 1; + } + } + + if (avci->draining || (!avctx->codec->bsfs && avci->compat_decode_consumed < pkt->size)) + break; + } + +finish: + if (ret == 0) { + /* if there are any bsfs then assume full packet is always consumed */ + if (avctx->codec->bsfs) + ret = pkt->size; + else + ret = FFMIN(avci->compat_decode_consumed, pkt->size); + } + avci->compat_decode_consumed = 0; + avci->compat_decode_partial_size = (ret >= 0) ? pkt->size - ret : 0; + + return ret; +} + +int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, + int *got_picture_ptr, + const AVPacket *avpkt) +{ + return compat_decode(avctx, picture, got_picture_ptr, avpkt); +} + +int attribute_align_arg avcodec_decode_audio4(AVCodecContext *avctx, + AVFrame *frame, + int *got_frame_ptr, + const AVPacket *avpkt) +{ + return compat_decode(avctx, frame, got_frame_ptr, avpkt); +} + +static void get_subtitle_defaults(AVSubtitle *sub) +{ + memset(sub, 0, sizeof(*sub)); + sub->pts = AV_NOPTS_VALUE; +} + +#define UTF8_MAX_BYTES 4 /* 5 and 6 bytes sequences should not be used */ +static int recode_subtitle(AVCodecContext *avctx, + AVPacket *outpkt, const AVPacket *inpkt) +{ +#if CONFIG_ICONV + iconv_t cd = (iconv_t)-1; + int ret = 0; + char *inb, *outb; + size_t inl, outl; + AVPacket tmp; +#endif + + if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_PRE_DECODER || inpkt->size == 0) + return 0; + +#if CONFIG_ICONV + cd = iconv_open("UTF-8", avctx->sub_charenc); + av_assert0(cd != (iconv_t)-1); + + inb = inpkt->data; + inl = inpkt->size; + + if (inl >= INT_MAX / UTF8_MAX_BYTES - AV_INPUT_BUFFER_PADDING_SIZE) { + av_log(avctx, AV_LOG_ERROR, "Subtitles packet is too big for recoding\n"); + ret = AVERROR(ENOMEM); + goto end; + } + + ret = av_new_packet(&tmp, inl * UTF8_MAX_BYTES); + if (ret < 0) + goto end; + outpkt->buf = tmp.buf; + outpkt->data = tmp.data; + outpkt->size = tmp.size; + outb = outpkt->data; + outl = outpkt->size; + + if (iconv(cd, &inb, &inl, &outb, &outl) == (size_t)-1 || + iconv(cd, NULL, NULL, &outb, &outl) == (size_t)-1 || + outl >= outpkt->size || inl != 0) { + ret = FFMIN(AVERROR(errno), -1); + av_log(avctx, AV_LOG_ERROR, "Unable to recode subtitle event \"%s\" " + "from %s to UTF-8\n", inpkt->data, avctx->sub_charenc); + av_packet_unref(&tmp); + goto end; + } + outpkt->size -= outl; + memset(outpkt->data + outpkt->size, 0, outl); + +end: + if (cd != (iconv_t)-1) + iconv_close(cd); + return ret; +#else + av_log(avctx, AV_LOG_ERROR, "requesting subtitles recoding without iconv"); + return AVERROR(EINVAL); +#endif +} + +static int utf8_check(const uint8_t *str) +{ + const uint8_t *byte; + uint32_t codepoint, min; + + while (*str) { + byte = str; + GET_UTF8(codepoint, *(byte++), return 0;); + min = byte - str == 1 ? 0 : byte - str == 2 ? 0x80 : + 1 << (5 * (byte - str) - 4); + if (codepoint < min || codepoint >= 0x110000 || + codepoint == 0xFFFE /* BOM */ || + codepoint >= 0xD800 && codepoint <= 0xDFFF /* surrogates */) + return 0; + str = byte; + } + return 1; +} + +#if FF_API_ASS_TIMING +static void insert_ts(AVBPrint *buf, int ts) +{ + if (ts == -1) { + av_bprintf(buf, "9:59:59.99,"); + } else { + int h, m, s; + + h = ts/360000; ts -= 360000*h; + m = ts/ 6000; ts -= 6000*m; + s = ts/ 100; ts -= 100*s; + av_bprintf(buf, "%d:%02d:%02d.%02d,", h, m, s, ts); + } +} + +static int convert_sub_to_old_ass_form(AVSubtitle *sub, const AVPacket *pkt, AVRational tb) +{ + int i; + AVBPrint buf; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + for (i = 0; i < sub->num_rects; i++) { + char *final_dialog; + const char *dialog; + AVSubtitleRect *rect = sub->rects[i]; + int ts_start, ts_duration = -1; + long int layer; + + if (rect->type != SUBTITLE_ASS || !strncmp(rect->ass, "Dialogue: ", 10)) + continue; + + av_bprint_clear(&buf); + + /* skip ReadOrder */ + dialog = strchr(rect->ass, ','); + if (!dialog) + continue; + dialog++; + + /* extract Layer or Marked */ + layer = strtol(dialog, (char**)&dialog, 10); + if (*dialog != ',') + continue; + dialog++; + + /* rescale timing to ASS time base (ms) */ + ts_start = av_rescale_q(pkt->pts, tb, av_make_q(1, 100)); + if (pkt->duration != -1) + ts_duration = av_rescale_q(pkt->duration, tb, av_make_q(1, 100)); + sub->end_display_time = FFMAX(sub->end_display_time, 10 * ts_duration); + + /* construct ASS (standalone file form with timestamps) string */ + av_bprintf(&buf, "Dialogue: %ld,", layer); + insert_ts(&buf, ts_start); + insert_ts(&buf, ts_duration == -1 ? -1 : ts_start + ts_duration); + av_bprintf(&buf, "%s\r\n", dialog); + + final_dialog = av_strdup(buf.str); + if (!av_bprint_is_complete(&buf) || !final_dialog) { + av_freep(&final_dialog); + av_bprint_finalize(&buf, NULL); + return AVERROR(ENOMEM); + } + av_freep(&rect->ass); + rect->ass = final_dialog; + } + + av_bprint_finalize(&buf, NULL); + return 0; +} +#endif + +int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, + int *got_sub_ptr, + AVPacket *avpkt) +{ + int i, ret = 0; + + if (!avpkt->data && avpkt->size) { + av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n"); + return AVERROR(EINVAL); + } + if (!avctx->codec) + return AVERROR(EINVAL); + if (avctx->codec->type != AVMEDIA_TYPE_SUBTITLE) { + av_log(avctx, AV_LOG_ERROR, "Invalid media type for subtitles\n"); + return AVERROR(EINVAL); + } + + *got_sub_ptr = 0; + get_subtitle_defaults(sub); + + if ((avctx->codec->capabilities & AV_CODEC_CAP_DELAY) || avpkt->size) { + AVPacket pkt_recoded = *avpkt; + + ret = recode_subtitle(avctx, &pkt_recoded, avpkt); + if (ret < 0) { + *got_sub_ptr = 0; + } else { + ret = extract_packet_props(avctx->internal, &pkt_recoded); + if (ret < 0) + return ret; + + if (avctx->pkt_timebase.num && avpkt->pts != AV_NOPTS_VALUE) + sub->pts = av_rescale_q(avpkt->pts, + avctx->pkt_timebase, AV_TIME_BASE_Q); + ret = avctx->codec->decode(avctx, sub, got_sub_ptr, &pkt_recoded); + av_assert1((ret >= 0) >= !!*got_sub_ptr && + !!*got_sub_ptr >= !!sub->num_rects); + +#if FF_API_ASS_TIMING + if (avctx->sub_text_format == FF_SUB_TEXT_FMT_ASS_WITH_TIMINGS + && *got_sub_ptr && sub->num_rects) { + const AVRational tb = avctx->pkt_timebase.num ? avctx->pkt_timebase + : avctx->time_base; + int err = convert_sub_to_old_ass_form(sub, avpkt, tb); + if (err < 0) + ret = err; + } +#endif + + if (sub->num_rects && !sub->end_display_time && avpkt->duration && + avctx->pkt_timebase.num) { + AVRational ms = { 1, 1000 }; + sub->end_display_time = av_rescale_q(avpkt->duration, + avctx->pkt_timebase, ms); + } + + if (avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB) + sub->format = 0; + else if (avctx->codec_descriptor->props & AV_CODEC_PROP_TEXT_SUB) + sub->format = 1; + + for (i = 0; i < sub->num_rects; i++) { + if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_IGNORE && + sub->rects[i]->ass && !utf8_check(sub->rects[i]->ass)) { + av_log(avctx, AV_LOG_ERROR, + "Invalid UTF-8 in decoded subtitles text; " + "maybe missing -sub_charenc option\n"); + avsubtitle_free(sub); + ret = AVERROR_INVALIDDATA; + break; + } + } + + if (avpkt->data != pkt_recoded.data) { // did we recode? + /* prevent from destroying side data from original packet */ + pkt_recoded.side_data = NULL; + pkt_recoded.side_data_elems = 0; + + av_packet_unref(&pkt_recoded); + } + } + + if (*got_sub_ptr) + avctx->frame_number++; + } + + return ret; +} + +enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *avctx, + const enum AVPixelFormat *fmt) +{ + const AVPixFmtDescriptor *desc; + const AVCodecHWConfig *config; + int i, n; + + // If a device was supplied when the codec was opened, assume that the + // user wants to use it. + if (avctx->hw_device_ctx && avctx->codec->hw_configs) { + AVHWDeviceContext *device_ctx = + (AVHWDeviceContext*)avctx->hw_device_ctx->data; + for (i = 0;; i++) { + config = &avctx->codec->hw_configs[i]->public; + if (!config) + break; + if (!(config->methods & + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) + continue; + if (device_ctx->type != config->device_type) + continue; + for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++) { + if (config->pix_fmt == fmt[n]) + return fmt[n]; + } + } + } + // No device or other setup, so we have to choose from things which + // don't any other external information. + + // If the last element of the list is a software format, choose it + // (this should be best software format if any exist). + for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++); + desc = av_pix_fmt_desc_get(fmt[n - 1]); + if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) + return fmt[n - 1]; + + // Finally, traverse the list in order and choose the first entry + // with no external dependencies (if there is no hardware configuration + // information available then this just picks the first entry). + for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++) { + for (i = 0;; i++) { + config = avcodec_get_hw_config(avctx->codec, i); + if (!config) + break; + if (config->pix_fmt == fmt[n]) + break; + } + if (!config) { + // No specific config available, so the decoder must be able + // to handle this format without any additional setup. + return fmt[n]; + } + if (config->methods & AV_CODEC_HW_CONFIG_METHOD_INTERNAL) { + // Usable with only internal setup. + return fmt[n]; + } + } + + // Nothing is usable, give up. + return AV_PIX_FMT_NONE; +} + +int ff_decode_get_hw_frames_ctx(AVCodecContext *avctx, + enum AVHWDeviceType dev_type) +{ + AVHWDeviceContext *device_ctx; + AVHWFramesContext *frames_ctx; + int ret; + + if (!avctx->hwaccel) + return AVERROR(ENOSYS); + + if (avctx->hw_frames_ctx) + return 0; + if (!avctx->hw_device_ctx) { + av_log(avctx, AV_LOG_ERROR, "A hardware frames or device context is " + "required for hardware accelerated decoding.\n"); + return AVERROR(EINVAL); + } + + device_ctx = (AVHWDeviceContext *)avctx->hw_device_ctx->data; + if (device_ctx->type != dev_type) { + av_log(avctx, AV_LOG_ERROR, "Device type %s expected for hardware " + "decoding, but got %s.\n", av_hwdevice_get_type_name(dev_type), + av_hwdevice_get_type_name(device_ctx->type)); + return AVERROR(EINVAL); + } + + ret = avcodec_get_hw_frames_parameters(avctx, + avctx->hw_device_ctx, + avctx->hwaccel->pix_fmt, + &avctx->hw_frames_ctx); + if (ret < 0) + return ret; + + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + + + if (frames_ctx->initial_pool_size) { + // We guarantee 4 base work surfaces. The function above guarantees 1 + // (the absolute minimum), so add the missing count. + frames_ctx->initial_pool_size += 3; + } + + ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); + if (ret < 0) { + av_buffer_unref(&avctx->hw_frames_ctx); + return ret; + } + + return 0; +} + +int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, + AVBufferRef *device_ref, + enum AVPixelFormat hw_pix_fmt, + AVBufferRef **out_frames_ref) +{ + AVBufferRef *frames_ref = NULL; + const AVCodecHWConfigInternal *hw_config; + const AVHWAccel *hwa; + int i, ret; + + for (i = 0;; i++) { + hw_config = avctx->codec->hw_configs[i]; + if (!hw_config) + return AVERROR(ENOENT); + if (hw_config->public.pix_fmt == hw_pix_fmt) + break; + } + + hwa = hw_config->hwaccel; + if (!hwa || !hwa->frame_params) + return AVERROR(ENOENT); + + frames_ref = av_hwframe_ctx_alloc(device_ref); + if (!frames_ref) + return AVERROR(ENOMEM); + + ret = hwa->frame_params(avctx, frames_ref); + if (ret >= 0) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)frames_ref->data; + + if (frames_ctx->initial_pool_size) { + // If the user has requested that extra output surfaces be + // available then add them here. + if (avctx->extra_hw_frames > 0) + frames_ctx->initial_pool_size += avctx->extra_hw_frames; + + // If frame threading is enabled then an extra surface per thread + // is also required. + if (avctx->active_thread_type & FF_THREAD_FRAME) + frames_ctx->initial_pool_size += avctx->thread_count; + } + + *out_frames_ref = frames_ref; + } else { + av_buffer_unref(&frames_ref); + } + return ret; +} + +static int hwaccel_init(AVCodecContext *avctx, + const AVCodecHWConfigInternal *hw_config) +{ + const AVHWAccel *hwaccel; + int err; + + hwaccel = hw_config->hwaccel; + if (hwaccel->capabilities & AV_HWACCEL_CODEC_CAP_EXPERIMENTAL && + avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + av_log(avctx, AV_LOG_WARNING, "Ignoring experimental hwaccel: %s\n", + hwaccel->name); + return AVERROR_PATCHWELCOME; + } + + if (hwaccel->priv_data_size) { + avctx->internal->hwaccel_priv_data = + av_mallocz(hwaccel->priv_data_size); + if (!avctx->internal->hwaccel_priv_data) + return AVERROR(ENOMEM); + } + + avctx->hwaccel = hwaccel; + if (hwaccel->init) { + err = hwaccel->init(avctx); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed setup for format %s: " + "hwaccel initialisation returned error.\n", + av_get_pix_fmt_name(hw_config->public.pix_fmt)); + av_freep(&avctx->internal->hwaccel_priv_data); + avctx->hwaccel = NULL; + return err; + } + } + + return 0; +} + +static void hwaccel_uninit(AVCodecContext *avctx) +{ + if (avctx->hwaccel && avctx->hwaccel->uninit) + avctx->hwaccel->uninit(avctx); + + av_freep(&avctx->internal->hwaccel_priv_data); + + avctx->hwaccel = NULL; + + av_buffer_unref(&avctx->hw_frames_ctx); +} + +int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) +{ + const AVPixFmtDescriptor *desc; + enum AVPixelFormat *choices; + enum AVPixelFormat ret, user_choice; + const AVCodecHWConfigInternal *hw_config; + const AVCodecHWConfig *config; + int i, n, err; + + // Find end of list. + for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++); + // Must contain at least one entry. + av_assert0(n >= 1); + // If a software format is available, it must be the last entry. + desc = av_pix_fmt_desc_get(fmt[n - 1]); + if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) { + // No software format is available. + } else { + avctx->sw_pix_fmt = fmt[n - 1]; + } + + choices = av_malloc_array(n + 1, sizeof(*choices)); + if (!choices) + return AV_PIX_FMT_NONE; + + memcpy(choices, fmt, (n + 1) * sizeof(*choices)); + + for (;;) { + // Remove the previous hwaccel, if there was one. + hwaccel_uninit(avctx); + + user_choice = avctx->get_format(avctx, choices); + if (user_choice == AV_PIX_FMT_NONE) { + // Explicitly chose nothing, give up. + ret = AV_PIX_FMT_NONE; + break; + } + + desc = av_pix_fmt_desc_get(user_choice); + if (!desc) { + av_log(avctx, AV_LOG_ERROR, "Invalid format returned by " + "get_format() callback.\n"); + ret = AV_PIX_FMT_NONE; + break; + } + av_log(avctx, AV_LOG_DEBUG, "Format %s chosen by get_format().\n", + desc->name); + + for (i = 0; i < n; i++) { + if (choices[i] == user_choice) + break; + } + if (i == n) { + av_log(avctx, AV_LOG_ERROR, "Invalid return from get_format(): " + "%s not in possible list.\n", desc->name); + ret = AV_PIX_FMT_NONE; + break; + } + + if (avctx->codec->hw_configs) { + for (i = 0;; i++) { + hw_config = avctx->codec->hw_configs[i]; + if (!hw_config) + break; + if (hw_config->public.pix_fmt == user_choice) + break; + } + } else { + hw_config = NULL; + } + + if (!hw_config) { + // No config available, so no extra setup required. + ret = user_choice; + break; + } + config = &hw_config->public; + + if (config->methods & + AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX && + avctx->hw_frames_ctx) { + const AVHWFramesContext *frames_ctx = + (AVHWFramesContext*)avctx->hw_frames_ctx->data; + if (frames_ctx->format != user_choice) { + av_log(avctx, AV_LOG_ERROR, "Invalid setup for format %s: " + "does not match the format of the provided frames " + "context.\n", desc->name); + goto try_again; + } + } else if (config->methods & + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && + avctx->hw_device_ctx) { + const AVHWDeviceContext *device_ctx = + (AVHWDeviceContext*)avctx->hw_device_ctx->data; + if (device_ctx->type != config->device_type) { + av_log(avctx, AV_LOG_ERROR, "Invalid setup for format %s: " + "does not match the type of the provided device " + "context.\n", desc->name); + goto try_again; + } + } else if (config->methods & + AV_CODEC_HW_CONFIG_METHOD_INTERNAL) { + // Internal-only setup, no additional configuration. + } else if (config->methods & + AV_CODEC_HW_CONFIG_METHOD_AD_HOC) { + // Some ad-hoc configuration we can't see and can't check. + } else { + av_log(avctx, AV_LOG_ERROR, "Invalid setup for format %s: " + "missing configuration.\n", desc->name); + goto try_again; + } + if (hw_config->hwaccel) { + av_log(avctx, AV_LOG_DEBUG, "Format %s requires hwaccel " + "initialisation.\n", desc->name); + err = hwaccel_init(avctx, hw_config); + if (err < 0) + goto try_again; + } + ret = user_choice; + break; + + try_again: + av_log(avctx, AV_LOG_DEBUG, "Format %s not usable, retrying " + "get_format() without it.\n", desc->name); + for (i = 0; i < n; i++) { + if (choices[i] == user_choice) + break; + } + for (; i + 1 < n; i++) + choices[i] = choices[i + 1]; + --n; + } + + av_freep(&choices); + return ret; +} + +static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame) +{ + FramePool *pool = avctx->internal->pool; + int i, ret; + + switch (avctx->codec_type) { + case AVMEDIA_TYPE_VIDEO: { + uint8_t *data[4]; + int linesize[4]; + int size[4] = { 0 }; + int w = frame->width; + int h = frame->height; + int tmpsize, unaligned; + + if (pool->format == frame->format && + pool->width == frame->width && pool->height == frame->height) + return 0; + + avcodec_align_dimensions2(avctx, &w, &h, pool->stride_align); + + do { + // NOTE: do not align linesizes individually, this breaks e.g. assumptions + // that linesize[0] == 2*linesize[1] in the MPEG-encoder for 4:2:2 + ret = av_image_fill_linesizes(linesize, avctx->pix_fmt, w); + if (ret < 0) + return ret; + // increase alignment of w for next try (rhs gives the lowest bit set in w) + w += w & ~(w - 1); + + unaligned = 0; + for (i = 0; i < 4; i++) + unaligned |= linesize[i] % pool->stride_align[i]; + } while (unaligned); + + tmpsize = av_image_fill_pointers(data, avctx->pix_fmt, h, + NULL, linesize); + if (tmpsize < 0) + return tmpsize; + + for (i = 0; i < 3 && data[i + 1]; i++) + size[i] = data[i + 1] - data[i]; + size[i] = tmpsize - (data[i] - data[0]); + + for (i = 0; i < 4; i++) { + av_buffer_pool_uninit(&pool->pools[i]); + pool->linesize[i] = linesize[i]; + if (size[i]) { + pool->pools[i] = av_buffer_pool_init(size[i] + 16 + STRIDE_ALIGN - 1, + CONFIG_MEMORY_POISONING ? + NULL : + av_buffer_allocz); + if (!pool->pools[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + } + pool->format = frame->format; + pool->width = frame->width; + pool->height = frame->height; + + break; + } + case AVMEDIA_TYPE_AUDIO: { + int ch = frame->channels; //av_get_channel_layout_nb_channels(frame->channel_layout); + int planar = av_sample_fmt_is_planar(frame->format); + int planes = planar ? ch : 1; + + if (pool->format == frame->format && pool->planes == planes && + pool->channels == ch && frame->nb_samples == pool->samples) + return 0; + + av_buffer_pool_uninit(&pool->pools[0]); + ret = av_samples_get_buffer_size(&pool->linesize[0], ch, + frame->nb_samples, frame->format, 0); + if (ret < 0) + goto fail; + + pool->pools[0] = av_buffer_pool_init(pool->linesize[0], NULL); + if (!pool->pools[0]) { + ret = AVERROR(ENOMEM); + goto fail; + } + + pool->format = frame->format; + pool->planes = planes; + pool->channels = ch; + pool->samples = frame->nb_samples; + break; + } + default: av_assert0(0); + } + return 0; +fail: + for (i = 0; i < 4; i++) + av_buffer_pool_uninit(&pool->pools[i]); + pool->format = -1; + pool->planes = pool->channels = pool->samples = 0; + pool->width = pool->height = 0; + return ret; +} + +static int audio_get_buffer(AVCodecContext *avctx, AVFrame *frame) +{ + FramePool *pool = avctx->internal->pool; + int planes = pool->planes; + int i; + + frame->linesize[0] = pool->linesize[0]; + + if (planes > AV_NUM_DATA_POINTERS) { + frame->extended_data = av_mallocz_array(planes, sizeof(*frame->extended_data)); + frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS; + frame->extended_buf = av_mallocz_array(frame->nb_extended_buf, + sizeof(*frame->extended_buf)); + if (!frame->extended_data || !frame->extended_buf) { + av_freep(&frame->extended_data); + av_freep(&frame->extended_buf); + return AVERROR(ENOMEM); + } + } else { + frame->extended_data = frame->data; + av_assert0(frame->nb_extended_buf == 0); + } + + for (i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) { + frame->buf[i] = av_buffer_pool_get(pool->pools[0]); + if (!frame->buf[i]) + goto fail; + frame->extended_data[i] = frame->data[i] = frame->buf[i]->data; + } + for (i = 0; i < frame->nb_extended_buf; i++) { + frame->extended_buf[i] = av_buffer_pool_get(pool->pools[0]); + if (!frame->extended_buf[i]) + goto fail; + frame->extended_data[i + AV_NUM_DATA_POINTERS] = frame->extended_buf[i]->data; + } + + if (avctx->debug & FF_DEBUG_BUFFERS) + av_log(avctx, AV_LOG_DEBUG, "default_get_buffer called on frame %p", frame); + + return 0; +fail: + av_frame_unref(frame); + return AVERROR(ENOMEM); +} + +static int video_get_buffer(AVCodecContext *s, AVFrame *pic) +{ + FramePool *pool = s->internal->pool; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pic->format); + int i; + + if (pic->data[0] || pic->data[1] || pic->data[2] || pic->data[3]) { + av_log(s, AV_LOG_ERROR, "pic->data[*]!=NULL in avcodec_default_get_buffer\n"); + return -1; + } + + if (!desc) { + av_log(s, AV_LOG_ERROR, + "Unable to get pixel format descriptor for format %s\n", + av_get_pix_fmt_name(pic->format)); + return AVERROR(EINVAL); + } + + memset(pic->data, 0, sizeof(pic->data)); + pic->extended_data = pic->data; + + for (i = 0; i < 4 && pool->pools[i]; i++) { + pic->linesize[i] = pool->linesize[i]; + + pic->buf[i] = av_buffer_pool_get(pool->pools[i]); + if (!pic->buf[i]) + goto fail; + + pic->data[i] = pic->buf[i]->data; + } + for (; i < AV_NUM_DATA_POINTERS; i++) { + pic->data[i] = NULL; + pic->linesize[i] = 0; + } + if (desc->flags & AV_PIX_FMT_FLAG_PAL || + ((desc->flags & FF_PSEUDOPAL) && pic->data[1])) + avpriv_set_systematic_pal2((uint32_t *)pic->data[1], pic->format); + + if (s->debug & FF_DEBUG_BUFFERS) + av_log(s, AV_LOG_DEBUG, "default_get_buffer called on pic %p\n", pic); + + return 0; +fail: + av_frame_unref(pic); + return AVERROR(ENOMEM); +} + +int avcodec_default_get_buffer2(AVCodecContext *avctx, AVFrame *frame, int flags) +{ + int ret; + + if (avctx->hw_frames_ctx) { + ret = av_hwframe_get_buffer(avctx->hw_frames_ctx, frame, 0); + frame->width = avctx->coded_width; + frame->height = avctx->coded_height; + return ret; + } + + if ((ret = update_frame_pool(avctx, frame)) < 0) + return ret; + + switch (avctx->codec_type) { + case AVMEDIA_TYPE_VIDEO: + return video_get_buffer(avctx, frame); + case AVMEDIA_TYPE_AUDIO: + return audio_get_buffer(avctx, frame); + default: + return -1; + } +} + +static int add_metadata_from_side_data(const AVPacket *avpkt, AVFrame *frame) +{ + int size; + const uint8_t *side_metadata; + + AVDictionary **frame_md = &frame->metadata; + + side_metadata = av_packet_get_side_data(avpkt, + AV_PKT_DATA_STRINGS_METADATA, &size); + return av_packet_unpack_dictionary(side_metadata, size, frame_md); +} + +int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame) +{ + const AVPacket *pkt = avctx->internal->last_pkt_props; + int i; + static const struct { + enum AVPacketSideDataType packet; + enum AVFrameSideDataType frame; + } sd[] = { + { AV_PKT_DATA_REPLAYGAIN , AV_FRAME_DATA_REPLAYGAIN }, + { AV_PKT_DATA_DISPLAYMATRIX, AV_FRAME_DATA_DISPLAYMATRIX }, + { AV_PKT_DATA_SPHERICAL, AV_FRAME_DATA_SPHERICAL }, + { AV_PKT_DATA_STEREO3D, AV_FRAME_DATA_STEREO3D }, + { AV_PKT_DATA_AUDIO_SERVICE_TYPE, AV_FRAME_DATA_AUDIO_SERVICE_TYPE }, + { AV_PKT_DATA_MASTERING_DISPLAY_METADATA, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA }, + { AV_PKT_DATA_CONTENT_LIGHT_LEVEL, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL }, + { AV_PKT_DATA_A53_CC, AV_FRAME_DATA_A53_CC }, + }; + + if (pkt) { + frame->pts = pkt->pts; +#if FF_API_PKT_PTS +FF_DISABLE_DEPRECATION_WARNINGS + frame->pkt_pts = pkt->pts; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + frame->pkt_pos = pkt->pos; + frame->pkt_duration = pkt->duration; + frame->pkt_size = pkt->size; + + for (i = 0; i < FF_ARRAY_ELEMS(sd); i++) { + int size; + uint8_t *packet_sd = av_packet_get_side_data(pkt, sd[i].packet, &size); + if (packet_sd) { + AVFrameSideData *frame_sd = av_frame_new_side_data(frame, + sd[i].frame, + size); + if (!frame_sd) + return AVERROR(ENOMEM); + + memcpy(frame_sd->data, packet_sd, size); + } + } + add_metadata_from_side_data(pkt, frame); + + if (pkt->flags & AV_PKT_FLAG_DISCARD) { + frame->flags |= AV_FRAME_FLAG_DISCARD; + } else { + frame->flags = (frame->flags & ~AV_FRAME_FLAG_DISCARD); + } + } + frame->reordered_opaque = avctx->reordered_opaque; + + if (frame->color_primaries == AVCOL_PRI_UNSPECIFIED) + frame->color_primaries = avctx->color_primaries; + if (frame->color_trc == AVCOL_TRC_UNSPECIFIED) + frame->color_trc = avctx->color_trc; + if (frame->colorspace == AVCOL_SPC_UNSPECIFIED) + frame->colorspace = avctx->colorspace; + if (frame->color_range == AVCOL_RANGE_UNSPECIFIED) + frame->color_range = avctx->color_range; + if (frame->chroma_location == AVCHROMA_LOC_UNSPECIFIED) + frame->chroma_location = avctx->chroma_sample_location; + + switch (avctx->codec->type) { + case AVMEDIA_TYPE_VIDEO: + frame->format = avctx->pix_fmt; + if (!frame->sample_aspect_ratio.num) + frame->sample_aspect_ratio = avctx->sample_aspect_ratio; + + if (frame->width && frame->height && + av_image_check_sar(frame->width, frame->height, + frame->sample_aspect_ratio) < 0) { + av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n", + frame->sample_aspect_ratio.num, + frame->sample_aspect_ratio.den); + frame->sample_aspect_ratio = (AVRational){ 0, 1 }; + } + + break; + case AVMEDIA_TYPE_AUDIO: + if (!frame->sample_rate) + frame->sample_rate = avctx->sample_rate; + if (frame->format < 0) + frame->format = avctx->sample_fmt; + if (!frame->channel_layout) { + if (avctx->channel_layout) { + if (av_get_channel_layout_nb_channels(avctx->channel_layout) != + avctx->channels) { + av_log(avctx, AV_LOG_ERROR, "Inconsistent channel " + "configuration.\n"); + return AVERROR(EINVAL); + } + + frame->channel_layout = avctx->channel_layout; + } else { + if (avctx->channels > FF_SANE_NB_CHANNELS) { + av_log(avctx, AV_LOG_ERROR, "Too many channels: %d.\n", + avctx->channels); + return AVERROR(ENOSYS); + } + } + } + frame->channels = avctx->channels; + break; + } + return 0; +} + +static void validate_avframe_allocation(AVCodecContext *avctx, AVFrame *frame) +{ + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + int i; + int num_planes = av_pix_fmt_count_planes(frame->format); + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int flags = desc ? desc->flags : 0; + if (num_planes == 1 && (flags & AV_PIX_FMT_FLAG_PAL)) + num_planes = 2; + if ((flags & FF_PSEUDOPAL) && frame->data[1]) + num_planes = 2; + for (i = 0; i < num_planes; i++) { + av_assert0(frame->data[i]); + } + // For formats without data like hwaccel allow unused pointers to be non-NULL. + for (i = num_planes; num_planes > 0 && i < FF_ARRAY_ELEMS(frame->data); i++) { + if (frame->data[i]) + av_log(avctx, AV_LOG_ERROR, "Buffer returned by get_buffer2() did not zero unused plane pointers\n"); + frame->data[i] = NULL; + } + } +} + +static void decode_data_free(void *opaque, uint8_t *data) +{ + FrameDecodeData *fdd = (FrameDecodeData*)data; + + if (fdd->post_process_opaque_free) + fdd->post_process_opaque_free(fdd->post_process_opaque); + + if (fdd->hwaccel_priv_free) + fdd->hwaccel_priv_free(fdd->hwaccel_priv); + + av_freep(&fdd); +} + +int ff_attach_decode_data(AVFrame *frame) +{ + AVBufferRef *fdd_buf; + FrameDecodeData *fdd; + + av_assert1(!frame->private_ref); + av_buffer_unref(&frame->private_ref); + + fdd = av_mallocz(sizeof(*fdd)); + if (!fdd) + return AVERROR(ENOMEM); + + fdd_buf = av_buffer_create((uint8_t*)fdd, sizeof(*fdd), decode_data_free, + NULL, AV_BUFFER_FLAG_READONLY); + if (!fdd_buf) { + av_freep(&fdd); + return AVERROR(ENOMEM); + } + + frame->private_ref = fdd_buf; + + return 0; +} + +static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) +{ + const AVHWAccel *hwaccel = avctx->hwaccel; + int override_dimensions = 1; + int ret; + + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + if ((ret = av_image_check_size2(FFALIGN(avctx->width, STRIDE_ALIGN), avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx)) < 0 || avctx->pix_fmt<0) { + av_log(avctx, AV_LOG_ERROR, "video_get_buffer: image parameters invalid\n"); + return AVERROR(EINVAL); + } + + if (frame->width <= 0 || frame->height <= 0) { + frame->width = FFMAX(avctx->width, AV_CEIL_RSHIFT(avctx->coded_width, avctx->lowres)); + frame->height = FFMAX(avctx->height, AV_CEIL_RSHIFT(avctx->coded_height, avctx->lowres)); + override_dimensions = 0; + } + + if (frame->data[0] || frame->data[1] || frame->data[2] || frame->data[3]) { + av_log(avctx, AV_LOG_ERROR, "pic->data[*]!=NULL in get_buffer_internal\n"); + return AVERROR(EINVAL); + } + } + ret = ff_decode_frame_props(avctx, frame); + if (ret < 0) + return ret; + + if (hwaccel) { + if (hwaccel->alloc_frame) { + ret = hwaccel->alloc_frame(avctx, frame); + goto end; + } + } else + avctx->sw_pix_fmt = avctx->pix_fmt; + + ret = avctx->get_buffer2(avctx, frame, flags); + if (ret < 0) + goto end; + + validate_avframe_allocation(avctx, frame); + + ret = ff_attach_decode_data(frame); + if (ret < 0) + goto end; + +end: + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions && + !(avctx->codec->caps_internal & FF_CODEC_CAP_EXPORTS_CROPPING)) { + frame->width = avctx->width; + frame->height = avctx->height; + } + + if (ret < 0) + av_frame_unref(frame); + + return ret; +} + +int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) +{ + int ret = get_buffer_internal(avctx, frame, flags); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + frame->width = frame->height = 0; + } + return ret; +} + +static int reget_buffer_internal(AVCodecContext *avctx, AVFrame *frame) +{ + AVFrame *tmp; + int ret; + + av_assert0(avctx->codec_type == AVMEDIA_TYPE_VIDEO); + + if (frame->data[0] && (frame->width != avctx->width || frame->height != avctx->height || frame->format != avctx->pix_fmt)) { + av_log(avctx, AV_LOG_WARNING, "Picture changed from size:%dx%d fmt:%s to size:%dx%d fmt:%s in reget buffer()\n", + frame->width, frame->height, av_get_pix_fmt_name(frame->format), avctx->width, avctx->height, av_get_pix_fmt_name(avctx->pix_fmt)); + av_frame_unref(frame); + } + + if (!frame->data[0]) + return ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF); + + if (av_frame_is_writable(frame)) + return ff_decode_frame_props(avctx, frame); + + tmp = av_frame_alloc(); + if (!tmp) + return AVERROR(ENOMEM); + + av_frame_move_ref(tmp, frame); + + ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF); + if (ret < 0) { + av_frame_free(&tmp); + return ret; + } + + av_frame_copy(frame, tmp); + av_frame_free(&tmp); + + return 0; +} + +int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame) +{ + int ret = reget_buffer_internal(avctx, frame); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); + return ret; +} + +static void bsfs_flush(AVCodecContext *avctx) +{ + DecodeFilterContext *s = &avctx->internal->filter; + + for (int i = 0; i < s->nb_bsfs; i++) + av_bsf_flush(s->bsfs[i]); +} + +void avcodec_flush_buffers(AVCodecContext *avctx) +{ + avctx->internal->draining = 0; + avctx->internal->draining_done = 0; + avctx->internal->nb_draining_errors = 0; + av_frame_unref(avctx->internal->buffer_frame); + av_frame_unref(avctx->internal->compat_decode_frame); + av_packet_unref(avctx->internal->buffer_pkt); + avctx->internal->buffer_pkt_valid = 0; + + av_packet_unref(avctx->internal->ds.in_pkt); + + if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) + ff_thread_flush(avctx); + else if (avctx->codec->flush) + avctx->codec->flush(avctx); + + avctx->pts_correction_last_pts = + avctx->pts_correction_last_dts = INT64_MIN; + + bsfs_flush(avctx); + + if (!avctx->refcounted_frames) + av_frame_unref(avctx->internal->to_free); +} + +void ff_decode_bsfs_uninit(AVCodecContext *avctx) +{ + DecodeFilterContext *s = &avctx->internal->filter; + int i; + + for (i = 0; i < s->nb_bsfs; i++) + av_bsf_free(&s->bsfs[i]); + av_freep(&s->bsfs); + s->nb_bsfs = 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/decode.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/decode.h new file mode 100644 index 0000000000..c3e0e82f4c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/decode.h @@ -0,0 +1,81 @@ +/* + * generic decoding-related code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DECODE_H +#define AVCODEC_DECODE_H + +#include "libavutil/buffer.h" +#include "libavutil/frame.h" +#include "libavutil/hwcontext.h" + +#include "avcodec.h" + +/** + * This struct stores per-frame lavc-internal data and is attached to it via + * private_ref. + */ +typedef struct FrameDecodeData { + /** + * The callback to perform some delayed processing on the frame right + * before it is returned to the caller. + * + * @note This code is called at some unspecified point after the frame is + * returned from the decoder's decode/receive_frame call. Therefore it cannot rely + * on AVCodecContext being in any specific state, so it does not get to + * access AVCodecContext directly at all. All the state it needs must be + * stored in the post_process_opaque object. + */ + int (*post_process)(void *logctx, AVFrame *frame); + void *post_process_opaque; + void (*post_process_opaque_free)(void *opaque); + + /** + * Per-frame private data for hwaccels. + */ + void *hwaccel_priv; + void (*hwaccel_priv_free)(void *priv); +} FrameDecodeData; + +/** + * Called by decoders to get the next packet for decoding. + * + * @param pkt An empty packet to be filled with data. + * @return 0 if a new reference has been successfully written to pkt + * AVERROR(EAGAIN) if no data is currently available + * AVERROR_EOF if and end of stream has been reached, so no more data + * will be available + */ +int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt); + +int ff_decode_bsfs_init(AVCodecContext *avctx); + +void ff_decode_bsfs_uninit(AVCodecContext *avctx); + +/** + * Make sure avctx.hw_frames_ctx is set. If it's not set, the function will + * try to allocate it from hw_device_ctx. If that is not possible, an error + * message is printed, and an error code is returned. + */ +int ff_decode_get_hw_frames_ctx(AVCodecContext *avctx, + enum AVHWDeviceType dev_type); + +int ff_attach_decode_data(AVFrame *frame); + +#endif /* AVCODEC_DECODE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac.c new file mode 100644 index 0000000000..d5870d6c00 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac.c @@ -0,0 +1,408 @@ +/* + * Copyright (C) 2007 Marco Gerards + * Copyright (C) 2009 David Conrad + * Copyright (C) 2011 Jordi Ortiz + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Dirac Decoder + * @author Marco Gerards , David Conrad, Jordi Ortiz + */ + +#include "libavutil/imgutils.h" + +#include "avcodec.h" +#include "dirac.h" +#include "golomb.h" +#include "internal.h" +#include "mpeg12data.h" + +#if CONFIG_DIRAC_PARSE + +typedef struct dirac_source_params { + unsigned width; + unsigned height; + uint8_t chroma_format; ///< 0: 444 1: 422 2: 420 + + uint8_t interlaced; + uint8_t top_field_first; + + uint8_t frame_rate_index; ///< index into dirac_frame_rate[] + uint8_t aspect_ratio_index; ///< index into dirac_aspect_ratio[] + + uint16_t clean_width; + uint16_t clean_height; + uint16_t clean_left_offset; + uint16_t clean_right_offset; + + uint8_t pixel_range_index; ///< index into dirac_pixel_range_presets[] + uint8_t color_spec_index; ///< index into dirac_color_spec_presets[] +} dirac_source_params; + +/* defaults for source parameters */ +static const dirac_source_params dirac_source_parameters_defaults[] = { + { 640, 480, 2, 0, 0, 1, 1, 640, 480, 0, 0, 1, 0 }, + { 176, 120, 2, 0, 0, 9, 2, 176, 120, 0, 0, 1, 1 }, + { 176, 144, 2, 0, 1, 10, 3, 176, 144, 0, 0, 1, 2 }, + { 352, 240, 2, 0, 0, 9, 2, 352, 240, 0, 0, 1, 1 }, + { 352, 288, 2, 0, 1, 10, 3, 352, 288, 0, 0, 1, 2 }, + { 704, 480, 2, 0, 0, 9, 2, 704, 480, 0, 0, 1, 1 }, + { 704, 576, 2, 0, 1, 10, 3, 704, 576, 0, 0, 1, 2 }, + { 720, 480, 1, 1, 0, 4, 2, 704, 480, 8, 0, 3, 1 }, + { 720, 576, 1, 1, 1, 3, 3, 704, 576, 8, 0, 3, 2 }, + + { 1280, 720, 1, 0, 1, 7, 1, 1280, 720, 0, 0, 3, 3 }, + { 1280, 720, 1, 0, 1, 6, 1, 1280, 720, 0, 0, 3, 3 }, + { 1920, 1080, 1, 1, 1, 4, 1, 1920, 1080, 0, 0, 3, 3 }, + { 1920, 1080, 1, 1, 1, 3, 1, 1920, 1080, 0, 0, 3, 3 }, + { 1920, 1080, 1, 0, 1, 7, 1, 1920, 1080, 0, 0, 3, 3 }, + { 1920, 1080, 1, 0, 1, 6, 1, 1920, 1080, 0, 0, 3, 3 }, + { 2048, 1080, 0, 0, 1, 2, 1, 2048, 1080, 0, 0, 4, 4 }, + { 4096, 2160, 0, 0, 1, 2, 1, 4096, 2160, 0, 0, 4, 4 }, + + { 3840, 2160, 1, 0, 1, 7, 1, 3840, 2160, 0, 0, 3, 3 }, + { 3840, 2160, 1, 0, 1, 6, 1, 3840, 2160, 0, 0, 3, 3 }, + { 7680, 4320, 1, 0, 1, 7, 1, 3840, 2160, 0, 0, 3, 3 }, + { 7680, 4320, 1, 0, 1, 6, 1, 3840, 2160, 0, 0, 3, 3 }, +}; + +/* [DIRAC_STD] Table 10.4 - Available preset pixel aspect ratio values */ +static const AVRational dirac_preset_aspect_ratios[] = { + { 1, 1 }, + { 10, 11 }, + { 12, 11 }, + { 40, 33 }, + { 16, 11 }, + { 4, 3 }, +}; + +/* [DIRAC_STD] Values 9,10 of 10.3.5 Frame Rate. + * Table 10.3 Available preset frame rate values + */ +static const AVRational dirac_frame_rate[] = { + { 15000, 1001 }, + { 25, 2 }, +}; + +/* [DIRAC_STD] This should be equivalent to Table 10.5 Available signal + * range presets */ +static const struct { + uint8_t bitdepth; + enum AVColorRange color_range; +} pixel_range_presets[] = { + { 8, AVCOL_RANGE_JPEG }, + { 8, AVCOL_RANGE_MPEG }, + { 10, AVCOL_RANGE_MPEG }, + { 12, AVCOL_RANGE_MPEG }, +}; + +static const enum AVColorPrimaries dirac_primaries[] = { + AVCOL_PRI_BT709, + AVCOL_PRI_SMPTE170M, + AVCOL_PRI_BT470BG, +}; + +static const struct { + enum AVColorPrimaries color_primaries; + enum AVColorSpace colorspace; + enum AVColorTransferCharacteristic color_trc; +} dirac_color_presets[] = { + { AVCOL_PRI_BT709, AVCOL_SPC_BT709, AVCOL_TRC_BT709 }, + { AVCOL_PRI_SMPTE170M, AVCOL_SPC_BT470BG, AVCOL_TRC_BT709 }, + { AVCOL_PRI_BT470BG, AVCOL_SPC_BT470BG, AVCOL_TRC_BT709 }, + { AVCOL_PRI_BT709, AVCOL_SPC_BT709, AVCOL_TRC_BT709 }, + { AVCOL_PRI_BT709, AVCOL_SPC_BT709, AVCOL_TRC_UNSPECIFIED /* DCinema */ }, +}; + +/* [DIRAC_STD] Table 10.2 Supported chroma sampling formats */ +static const enum AVPixelFormat dirac_pix_fmt[][3] = { + {AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12}, + {AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12}, + {AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV420P12}, +}; + +/* [DIRAC_STD] 10.3 Parse Source Parameters. + * source_parameters(base_video_format) */ +static int parse_source_parameters(AVDiracSeqHeader *dsh, GetBitContext *gb, + void *log_ctx) +{ + AVRational frame_rate = { 0, 0 }; + unsigned luma_depth = 8, luma_offset = 16; + int idx; + int chroma_x_shift, chroma_y_shift; + int ret; + + /* [DIRAC_STD] 10.3.2 Frame size. frame_size(video_params) */ + /* [DIRAC_STD] custom_dimensions_flag */ + if (get_bits1(gb)) { + dsh->width = get_interleaved_ue_golomb(gb); /* [DIRAC_STD] FRAME_WIDTH */ + dsh->height = get_interleaved_ue_golomb(gb); /* [DIRAC_STD] FRAME_HEIGHT */ + } + + /* [DIRAC_STD] 10.3.3 Chroma Sampling Format. + * chroma_sampling_format(video_params) */ + /* [DIRAC_STD] custom_chroma_format_flag */ + if (get_bits1(gb)) + /* [DIRAC_STD] CHROMA_FORMAT_INDEX */ + dsh->chroma_format = get_interleaved_ue_golomb(gb); + if (dsh->chroma_format > 2U) { + if (log_ctx) + av_log(log_ctx, AV_LOG_ERROR, "Unknown chroma format %d\n", + dsh->chroma_format); + return AVERROR_INVALIDDATA; + } + + /* [DIRAC_STD] 10.3.4 Scan Format. scan_format(video_params) */ + /* [DIRAC_STD] custom_scan_format_flag */ + if (get_bits1(gb)) + /* [DIRAC_STD] SOURCE_SAMPLING */ + dsh->interlaced = get_interleaved_ue_golomb(gb); + if (dsh->interlaced > 1U) + return AVERROR_INVALIDDATA; + + /* [DIRAC_STD] 10.3.5 Frame Rate. frame_rate(video_params) */ + if (get_bits1(gb)) { /* [DIRAC_STD] custom_frame_rate_flag */ + dsh->frame_rate_index = get_interleaved_ue_golomb(gb); + + if (dsh->frame_rate_index > 10U) + return AVERROR_INVALIDDATA; + + if (!dsh->frame_rate_index) { + /* [DIRAC_STD] FRAME_RATE_NUMER */ + frame_rate.num = get_interleaved_ue_golomb(gb); + /* [DIRAC_STD] FRAME_RATE_DENOM */ + frame_rate.den = get_interleaved_ue_golomb(gb); + } + } + /* [DIRAC_STD] preset_frame_rate(video_params, index) */ + if (dsh->frame_rate_index > 0) { + if (dsh->frame_rate_index <= 8) + frame_rate = ff_mpeg12_frame_rate_tab[dsh->frame_rate_index]; + else + /* [DIRAC_STD] Table 10.3 values 9-10 */ + frame_rate = dirac_frame_rate[dsh->frame_rate_index - 9]; + } + dsh->framerate = frame_rate; + + /* [DIRAC_STD] 10.3.6 Pixel Aspect Ratio. + * pixel_aspect_ratio(video_params) */ + if (get_bits1(gb)) { /* [DIRAC_STD] custom_pixel_aspect_ratio_flag */ + /* [DIRAC_STD] index */ + dsh->aspect_ratio_index = get_interleaved_ue_golomb(gb); + + if (dsh->aspect_ratio_index > 6U) + return AVERROR_INVALIDDATA; + + if (!dsh->aspect_ratio_index) { + dsh->sample_aspect_ratio.num = get_interleaved_ue_golomb(gb); + dsh->sample_aspect_ratio.den = get_interleaved_ue_golomb(gb); + } + } + /* [DIRAC_STD] Take value from Table 10.4 Available preset pixel + * aspect ratio values */ + if (dsh->aspect_ratio_index > 0) + dsh->sample_aspect_ratio = + dirac_preset_aspect_ratios[dsh->aspect_ratio_index - 1]; + + /* [DIRAC_STD] 10.3.7 Clean area. clean_area(video_params) */ + if (get_bits1(gb)) { /* [DIRAC_STD] custom_clean_area_flag */ + /* [DIRAC_STD] CLEAN_WIDTH */ + dsh->clean_width = get_interleaved_ue_golomb(gb); + /* [DIRAC_STD] CLEAN_HEIGHT */ + dsh->clean_height = get_interleaved_ue_golomb(gb); + /* [DIRAC_STD] CLEAN_LEFT_OFFSET */ + dsh->clean_left_offset = get_interleaved_ue_golomb(gb); + /* [DIRAC_STD] CLEAN_RIGHT_OFFSET */ + dsh->clean_right_offset = get_interleaved_ue_golomb(gb); + } + + /* [DIRAC_STD] 10.3.8 Signal range. signal_range(video_params) + * WARNING: Some adaptation seems to be done using the + * AVCOL_RANGE_MPEG/JPEG values */ + if (get_bits1(gb)) { /* [DIRAC_STD] custom_signal_range_flag */ + /* [DIRAC_STD] index */ + dsh->pixel_range_index = get_interleaved_ue_golomb(gb); + + if (dsh->pixel_range_index > 4U) + return AVERROR_INVALIDDATA; + + /* This assumes either fullrange or MPEG levels only */ + if (!dsh->pixel_range_index) { + luma_offset = get_interleaved_ue_golomb(gb); + luma_depth = av_log2(get_interleaved_ue_golomb(gb)) + 1; + get_interleaved_ue_golomb(gb); /* chroma offset */ + get_interleaved_ue_golomb(gb); /* chroma excursion */ + dsh->color_range = luma_offset ? AVCOL_RANGE_MPEG + : AVCOL_RANGE_JPEG; + } + } + /* [DIRAC_STD] Table 10.5 + * Available signal range presets <--> pixel_range_presets */ + if (dsh->pixel_range_index > 0) { + idx = dsh->pixel_range_index - 1; + luma_depth = pixel_range_presets[idx].bitdepth; + dsh->color_range = pixel_range_presets[idx].color_range; + } + + dsh->bit_depth = luma_depth; + + /* Full range 8 bts uses the same pix_fmts as limited range 8 bits */ + dsh->pixel_range_index += dsh->pixel_range_index == 1; + + if (dsh->pixel_range_index < 2U) + return AVERROR_INVALIDDATA; + + dsh->pix_fmt = dirac_pix_fmt[dsh->chroma_format][dsh->pixel_range_index-2]; + ret = av_pix_fmt_get_chroma_sub_sample(dsh->pix_fmt, &chroma_x_shift, &chroma_y_shift); + if (ret) + return ret; + + if ((dsh->width % (1<height % (1<color_spec_index = get_interleaved_ue_golomb(gb); + + if (dsh->color_spec_index > 4U) + return AVERROR_INVALIDDATA; + + dsh->color_primaries = dirac_color_presets[idx].color_primaries; + dsh->colorspace = dirac_color_presets[idx].colorspace; + dsh->color_trc = dirac_color_presets[idx].color_trc; + + if (!dsh->color_spec_index) { + /* [DIRAC_STD] 10.3.9.1 Colour primaries */ + if (get_bits1(gb)) { + idx = get_interleaved_ue_golomb(gb); + if (idx < 3U) + dsh->color_primaries = dirac_primaries[idx]; + } + /* [DIRAC_STD] 10.3.9.2 Colour matrix */ + if (get_bits1(gb)) { + idx = get_interleaved_ue_golomb(gb); + if (!idx) + dsh->colorspace = AVCOL_SPC_BT709; + else if (idx == 1) + dsh->colorspace = AVCOL_SPC_BT470BG; + } + /* [DIRAC_STD] 10.3.9.3 Transfer function */ + if (get_bits1(gb) && !get_interleaved_ue_golomb(gb)) + dsh->color_trc = AVCOL_TRC_BT709; + } + } else { + idx = dsh->color_spec_index; + dsh->color_primaries = dirac_color_presets[idx].color_primaries; + dsh->colorspace = dirac_color_presets[idx].colorspace; + dsh->color_trc = dirac_color_presets[idx].color_trc; + } + + return 0; +} + +/* [DIRAC_STD] 10. Sequence Header. sequence_header() */ +int av_dirac_parse_sequence_header(AVDiracSeqHeader **pdsh, + const uint8_t *buf, size_t buf_size, + void *log_ctx) +{ + AVDiracSeqHeader *dsh; + GetBitContext gb; + unsigned video_format, picture_coding_mode; + int ret; + + dsh = av_mallocz(sizeof(*dsh)); + if (!dsh) + return AVERROR(ENOMEM); + + ret = init_get_bits8(&gb, buf, buf_size); + if (ret < 0) + goto fail; + + /* [DIRAC_SPEC] 10.1 Parse Parameters. parse_parameters() */ + dsh->version.major = get_interleaved_ue_golomb(&gb); + dsh->version.minor = get_interleaved_ue_golomb(&gb); + dsh->profile = get_interleaved_ue_golomb(&gb); + dsh->level = get_interleaved_ue_golomb(&gb); + /* [DIRAC_SPEC] sequence_header() -> base_video_format as defined in + * 10.2 Base Video Format, table 10.1 Dirac predefined video formats */ + video_format = get_interleaved_ue_golomb(&gb); + + if (dsh->version.major < 2 && log_ctx) + av_log(log_ctx, AV_LOG_WARNING, "Stream is old and may not work\n"); + else if (dsh->version.major > 2 && log_ctx) + av_log(log_ctx, AV_LOG_WARNING, "Stream may have unhandled features\n"); + + if (video_format > 20U) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + /* Fill in defaults for the source parameters. */ + dsh->width = dirac_source_parameters_defaults[video_format].width; + dsh->height = dirac_source_parameters_defaults[video_format].height; + dsh->chroma_format = dirac_source_parameters_defaults[video_format].chroma_format; + dsh->interlaced = dirac_source_parameters_defaults[video_format].interlaced; + dsh->top_field_first = dirac_source_parameters_defaults[video_format].top_field_first; + dsh->frame_rate_index = dirac_source_parameters_defaults[video_format].frame_rate_index; + dsh->aspect_ratio_index = dirac_source_parameters_defaults[video_format].aspect_ratio_index; + dsh->clean_width = dirac_source_parameters_defaults[video_format].clean_width; + dsh->clean_height = dirac_source_parameters_defaults[video_format].clean_height; + dsh->clean_left_offset = dirac_source_parameters_defaults[video_format].clean_left_offset; + dsh->clean_right_offset = dirac_source_parameters_defaults[video_format].clean_right_offset; + dsh->pixel_range_index = dirac_source_parameters_defaults[video_format].pixel_range_index; + dsh->color_spec_index = dirac_source_parameters_defaults[video_format].color_spec_index; + + /* [DIRAC_STD] 10.3 Source Parameters + * Override the defaults. */ + ret = parse_source_parameters(dsh, &gb, log_ctx); + if (ret < 0) + goto fail; + + /* [DIRAC_STD] picture_coding_mode shall be 0 for fields and 1 for frames + * currently only used to signal field coding */ + picture_coding_mode = get_interleaved_ue_golomb(&gb); + if (picture_coding_mode != 0) { + if (log_ctx) { + av_log(log_ctx, AV_LOG_ERROR, "Unsupported picture coding mode %d", + picture_coding_mode); + } + ret = AVERROR_INVALIDDATA; + goto fail; + } + + *pdsh = dsh; + return 0; +fail: + av_freep(&dsh); + *pdsh = NULL; + return ret; +} +#else +int av_dirac_parse_sequence_header(AVDiracSeqHeader **pdsh, + const uint8_t *buf, size_t buf_size, + void *log_ctx) +{ + return AVERROR(ENOSYS); +} +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac.h new file mode 100644 index 0000000000..e6d9d346d9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2007 Marco Gerards + * Copyright (C) 2009 David Conrad + * Copyright (C) 2011 Jordi Ortiz + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DIRAC_H +#define AVCODEC_DIRAC_H + +/** + * @file + * Interface to Dirac Decoder/Encoder + * @author Marco Gerards + * @author David Conrad + * @author Jordi Ortiz + */ + +#include "avcodec.h" + +/** + * The spec limits the number of wavelet decompositions to 4 for both + * level 1 (VC-2) and 128 (long-gop default). + * 5 decompositions is the maximum before >16-bit buffers are needed. + * Schroedinger allows this for DD 9,7 and 13,7 wavelets only, limiting + * the others to 4 decompositions (or 3 for the fidelity filter). + * + * We use this instead of MAX_DECOMPOSITIONS to save some memory. + */ +#define MAX_DWT_LEVELS 5 + +/** + * Parse code values: + * + * Dirac Specification -> + * 9.6.1 Table 9.1 + * + * VC-2 Specification -> + * 10.4.1 Table 10.1 + */ + +enum DiracParseCodes { + DIRAC_PCODE_SEQ_HEADER = 0x00, + DIRAC_PCODE_END_SEQ = 0x10, + DIRAC_PCODE_AUX = 0x20, + DIRAC_PCODE_PAD = 0x30, + DIRAC_PCODE_PICTURE_CODED = 0x08, + DIRAC_PCODE_PICTURE_RAW = 0x48, + DIRAC_PCODE_PICTURE_LOW_DEL = 0xC8, + DIRAC_PCODE_PICTURE_HQ = 0xE8, + DIRAC_PCODE_INTER_NOREF_CO1 = 0x0A, + DIRAC_PCODE_INTER_NOREF_CO2 = 0x09, + DIRAC_PCODE_INTER_REF_CO1 = 0x0D, + DIRAC_PCODE_INTER_REF_CO2 = 0x0E, + DIRAC_PCODE_INTRA_REF_CO = 0x0C, + DIRAC_PCODE_INTRA_REF_RAW = 0x4C, + DIRAC_PCODE_INTRA_REF_PICT = 0xCC, + DIRAC_PCODE_MAGIC = 0x42424344, +}; + +typedef struct DiracVersionInfo { + int major; + int minor; +} DiracVersionInfo; + +typedef struct AVDiracSeqHeader { + unsigned width; + unsigned height; + uint8_t chroma_format; ///< 0: 444 1: 422 2: 420 + + uint8_t interlaced; + uint8_t top_field_first; + + uint8_t frame_rate_index; ///< index into dirac_frame_rate[] + uint8_t aspect_ratio_index; ///< index into dirac_aspect_ratio[] + + uint16_t clean_width; + uint16_t clean_height; + uint16_t clean_left_offset; + uint16_t clean_right_offset; + + uint8_t pixel_range_index; ///< index into dirac_pixel_range_presets[] + uint8_t color_spec_index; ///< index into dirac_color_spec_presets[] + + int profile; + int level; + + AVRational framerate; + AVRational sample_aspect_ratio; + + enum AVPixelFormat pix_fmt; + enum AVColorRange color_range; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace colorspace; + + DiracVersionInfo version; + int bit_depth; +} AVDiracSeqHeader; + +/** + * Parse a Dirac sequence header. + * + * @param dsh this function will allocate and fill an AVDiracSeqHeader struct + * and write it into this pointer. The caller must free it with + * av_free(). + * @param buf the data buffer + * @param buf_size the size of the data buffer in bytes + * @param log_ctx if non-NULL, this function will log errors here + * @return 0 on success, a negative AVERROR code on failure + */ +int av_dirac_parse_sequence_header(AVDiracSeqHeader **dsh, + const uint8_t *buf, size_t buf_size, + void *log_ctx); + +#endif /* AVCODEC_DIRAC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_arith.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_arith.h new file mode 100644 index 0000000000..79526a7ca3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_arith.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2007 Marco Gerards + * Copyright (C) 2009 David Conrad + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Arithmetic decoder for Dirac + * @author Marco Gerards + */ + +#ifndef AVCODEC_DIRAC_ARITH_H +#define AVCODEC_DIRAC_ARITH_H + +#include "libavutil/x86/asm.h" +#include "bytestream.h" +#include "get_bits.h" + +enum dirac_arith_contexts { + CTX_ZPZN_F1, + CTX_ZPNN_F1, + CTX_NPZN_F1, + CTX_NPNN_F1, + CTX_ZP_F2, + CTX_ZP_F3, + CTX_ZP_F4, + CTX_ZP_F5, + CTX_ZP_F6, + CTX_NP_F2, + CTX_NP_F3, + CTX_NP_F4, + CTX_NP_F5, + CTX_NP_F6, + CTX_COEFF_DATA, + CTX_SIGN_NEG, + CTX_SIGN_ZERO, + CTX_SIGN_POS, + CTX_ZERO_BLOCK, + CTX_DELTA_Q_F, + CTX_DELTA_Q_DATA, + CTX_DELTA_Q_SIGN, + + DIRAC_CTX_COUNT +}; + +// Dirac resets the arith decoder between decoding various types of data, +// so many contexts are never used simultaneously. Thus, we can reduce +// the number of contexts needed by reusing them. +#define CTX_SB_F1 CTX_ZP_F5 +#define CTX_SB_DATA 0 +#define CTX_PMODE_REF1 0 +#define CTX_PMODE_REF2 1 +#define CTX_GLOBAL_BLOCK 2 +#define CTX_MV_F1 CTX_ZP_F2 +#define CTX_MV_DATA 0 +#define CTX_DC_F1 CTX_ZP_F5 +#define CTX_DC_DATA 0 + +typedef struct { + unsigned low; + uint16_t range; + int16_t counter; + + const uint8_t *bytestream; + const uint8_t *bytestream_end; + + uint16_t contexts[DIRAC_CTX_COUNT]; + int error; + int overread; +} DiracArith; + +extern const uint8_t ff_dirac_next_ctx[DIRAC_CTX_COUNT]; +extern const uint16_t ff_dirac_prob[256]; +extern int16_t ff_dirac_prob_branchless[256][2]; + +static inline void renorm(DiracArith *c) +{ +#if HAVE_FAST_CLZ + int shift = 14 - av_log2_16bit(c->range-1) + ((c->range-1)>>15); + + c->low <<= shift; + c->range <<= shift; + c->counter += shift; +#else + while (c->range <= 0x4000) { + c->low <<= 1; + c->range <<= 1; + c->counter++; + } +#endif +} + +static inline void refill(DiracArith *c) +{ + int counter = c->counter; + + if (counter >= 0) { + int new = bytestream_get_be16(&c->bytestream); + + // the spec defines overread bits to be 1, and streams rely on this + if (c->bytestream > c->bytestream_end) { + new |= 0xff; + if (c->bytestream > c->bytestream_end+1) + new |= 0xff00; + + c->bytestream = c->bytestream_end; + c->overread ++; + if (c->overread > 4) + c->error = AVERROR_INVALIDDATA; + } + + c->low += new << counter; + counter -= 16; + } + c->counter = counter; +} + +static inline int dirac_get_arith_bit(DiracArith *c, int ctx) +{ + int prob_zero = c->contexts[ctx]; + int range_times_prob, bit; + unsigned low = c->low; + int range = c->range; + + range_times_prob = (c->range * prob_zero) >> 16; + +#if ARCH_X86 && HAVE_FAST_CMOV && HAVE_INLINE_ASM && HAVE_6REGS + low -= range_times_prob << 16; + range -= range_times_prob; + bit = 0; + __asm__( + "cmpl %5, %4 \n\t" + "setae %b0 \n\t" + "cmovb %3, %2 \n\t" + "cmovb %5, %1 \n\t" + : "+q"(bit), "+r"(range), "+r"(low) + : "r"(c->low), "r"(c->low>>16), + "r"(range_times_prob) + ); +#else + bit = (low >> 16) >= range_times_prob; + if (bit) { + low -= range_times_prob << 16; + range -= range_times_prob; + } else { + range = range_times_prob; + } +#endif + + c->contexts[ctx] += ff_dirac_prob_branchless[prob_zero>>8][bit]; + c->low = low; + c->range = range; + + renorm(c); + refill(c); + return bit; +} + +static inline int dirac_get_arith_uint(DiracArith *c, int follow_ctx, int data_ctx) +{ + int ret = 1; + while (!dirac_get_arith_bit(c, follow_ctx)) { + if (ret >= 0x40000000) { + av_log(NULL, AV_LOG_ERROR, "dirac_get_arith_uint overflow\n"); + c->error = AVERROR_INVALIDDATA; + return -1; + } + ret <<= 1; + ret += dirac_get_arith_bit(c, data_ctx); + follow_ctx = ff_dirac_next_ctx[follow_ctx]; + } + return ret-1; +} + +static inline int dirac_get_arith_int(DiracArith *c, int follow_ctx, int data_ctx) +{ + int ret = dirac_get_arith_uint(c, follow_ctx, data_ctx); + if (ret && dirac_get_arith_bit(c, data_ctx+1)) + ret = -ret; + return ret; +} + +void ff_dirac_init_arith_tables(void); +void ff_dirac_init_arith_decoder(DiracArith *c, GetBitContext *gb, int length); + +#endif /* AVCODEC_DIRAC_ARITH_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_dwt.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_dwt.h new file mode 100644 index 0000000000..994dc21d70 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_dwt.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2004-2010 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DIRAC_DWT_H +#define AVCODEC_DIRAC_DWT_H + +#include + +typedef int DWTELEM; +typedef short IDWTELEM; + +#define MAX_DWT_SUPPORT 8 +#define MAX_DECOMPOSITIONS 8 + +typedef struct DWTCompose { + uint8_t *b[MAX_DWT_SUPPORT]; + int y; +} DWTCompose; + +typedef struct DWTPlane { + int width; + int height; + int stride; + uint8_t *buf; + uint8_t *buf_base; + uint8_t *tmp; +} DWTPlane; + +struct DWTContext; + +// Possible prototypes for vertical_compose functions +typedef void (*vertical_compose_2tap)(uint8_t *b0, uint8_t *b1, int width); +typedef void (*vertical_compose_3tap)(uint8_t *b0, uint8_t *b1, uint8_t *b2, int width); +typedef void (*vertical_compose_5tap)(uint8_t *b0, uint8_t *b1, uint8_t *b2, uint8_t *b3, uint8_t *b4, int width); +typedef void (*vertical_compose_9tap)(uint8_t *dst, uint8_t *b[8], int width); + +typedef struct DWTContext { + uint8_t *buffer; + uint8_t *temp; + int width; + int height; + int stride; + int decomposition_count; + int support; + + void (*spatial_compose)(struct DWTContext *cs, int level, int width, int height, int stride); + void (*vertical_compose_l0)(void); + void (*vertical_compose_h0)(void); + void (*vertical_compose_l1)(void); + void (*vertical_compose_h1)(void); + void (*vertical_compose)(void); ///< one set of lowpass and highpass combined + void (*horizontal_compose)(uint8_t *b, uint8_t *tmp, int width); + + DWTCompose cs[MAX_DECOMPOSITIONS]; +} DWTContext; + +enum dwt_type { + DWT_SNOW_DAUB9_7, + DWT_SNOW_LEGALL5_3, + DWT_DIRAC_DD9_7, + DWT_DIRAC_LEGALL5_3, + DWT_DIRAC_DD13_7, + DWT_DIRAC_HAAR0, + DWT_DIRAC_HAAR1, + DWT_DIRAC_FIDELITY, + DWT_DIRAC_DAUB9_7, + DWT_NUM_TYPES +}; + +// -1 if an error occurred, e.g. the dwt_type isn't recognized +int ff_spatial_idwt_init(DWTContext *d, DWTPlane *p, enum dwt_type type, + int decomposition_count, int bit_depth); +void ff_spatial_idwt_init_x86(DWTContext *d, enum dwt_type type); + +void ff_spatial_idwt_slice2(DWTContext *d, int y); + +// shared stuff for simd optimizations +#define COMPOSE_53iL0(b0, b1, b2)\ + (b1 - (unsigned)((int)(b0 + (unsigned)(b2) + 2) >> 2)) + +#define COMPOSE_DIRAC53iH0(b0, b1, b2)\ + (b1 + (unsigned)((int)(b0 + (unsigned)(b2) + 1) >> 1)) + +#define COMPOSE_DD97iH0(b0, b1, b2, b3, b4)\ + (int)(((unsigned)(b2) + ((int)(9U*b1 + 9U*b3 - b4 - b0 + 8) >> 4))) + +#define COMPOSE_DD137iL0(b0, b1, b2, b3, b4)\ + (int)(((unsigned)(b2) - ((int)(9U*b1 + 9U*b3 - b4 - b0 + 16) >> 5))) + +#define COMPOSE_HAARiL0(b0, b1)\ + ((int)(b0 - (unsigned)((int)(b1 + 1U) >> 1))) + +#define COMPOSE_HAARiH0(b0, b1)\ + ((int)(b0 + (unsigned)(b1))) + +#define COMPOSE_FIDELITYiL0(b0, b1, b2, b3, b4, b5, b6, b7, b8)\ + ((unsigned)b4 - ((int)(-8*(b0+(unsigned)b8) + 21*(b1+(unsigned)b7) - 46*(b2+(unsigned)b6) + 161*(b3+(unsigned)b5) + 128) >> 8)) + +#define COMPOSE_FIDELITYiH0(b0, b1, b2, b3, b4, b5, b6, b7, b8)\ + ((unsigned)b4 + ((int)(-2*(b0+(unsigned)b8) + 10*(b1+(unsigned)b7) - 25*(b2+(unsigned)b6) + 81*(b3+(unsigned)b5) + 128) >> 8)) + +#define COMPOSE_DAUB97iL1(b0, b1, b2)\ + ((unsigned)(b1) - ((int)(1817*(b0 + (unsigned)b2) + 2048) >> 12)) + +#define COMPOSE_DAUB97iH1(b0, b1, b2)\ + ((unsigned)(b1) - ((int)( 113*(b0 + (unsigned)b2) + 64) >> 7)) + +#define COMPOSE_DAUB97iL0(b0, b1, b2)\ + ((unsigned)(b1) + ((int)( 217*(b0 + (unsigned)b2) + 2048) >> 12)) + +#define COMPOSE_DAUB97iH0(b0, b1, b2)\ + ((unsigned)(b1) + ((int)(6497*(b0 + (unsigned)b2) + 2048) >> 12)) + + +#endif /* AVCODEC_DWT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_vlc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_vlc.h new file mode 100644 index 0000000000..42ae41b00a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dirac_vlc.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 Open Broadcast Systems Ltd. + * Author 2016 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DIRAC_VLC_H +#define AVCODEC_DIRAC_VLC_H + +#include "libavutil/avutil.h" + +/* Can be 32 bits wide for some performance gain on some machines, but it will + * incorrectly decode very long coefficients (usually only 1 or 2 per frame) */ +typedef uint64_t residual; + +#define LUT_BITS 8 + +/* Exactly 64 bytes */ +typedef struct DiracGolombLUT { + residual preamble, leftover; + int32_t ready[LUT_BITS]; + int32_t preamble_bits, leftover_bits, ready_num; + int8_t need_s, sign; +} DiracGolombLUT; + +av_cold int ff_dirac_golomb_reader_init(DiracGolombLUT **lut_ctx); + +int ff_dirac_golomb_read_32bit(DiracGolombLUT *lut_ctx, const uint8_t *buf, + int bytes, uint8_t *dst, int coeffs); + +int ff_dirac_golomb_read_16bit(DiracGolombLUT *lut_ctx, const uint8_t *buf, + int bytes, uint8_t *_dst, int coeffs); + +av_cold void ff_dirac_golomb_reader_end(DiracGolombLUT **lut_ctx); + +#endif /* AVCODEC_DIRAC_VLC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/diracdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/diracdsp.h new file mode 100644 index 0000000000..224828d880 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/diracdsp.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 David Conrad + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DIRACDSP_H +#define AVCODEC_DIRACDSP_H + +#include +#include + +typedef void (*dirac_weight_func)(uint8_t *block, int stride, int log2_denom, int weight, int h); +typedef void (*dirac_biweight_func)(uint8_t *dst, const uint8_t *src, int stride, int log2_denom, int weightd, int weights, int h); + +typedef struct { + void (*dirac_hpel_filter)(uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, const uint8_t *src, int stride, int width, int height); + /** + * dirac_pixels_tab[width][subpel] + * width is 2 for 32, 1 for 16, 0 for 8 + * subpel is 0 for fpel and hpel (only need to copy from the first plane in src) + * 1 if an average of the first 2 planes is needed (TODO: worth it?) + * 2 for general qpel (avg of 4) + * 3 for general epel (biweight of 4 using the weights in src[4]) + * src[0-3] is each of the hpel planes + * src[4] is the 1/8 pel weights if needed + */ + void (*put_dirac_pixels_tab[3][4])(uint8_t *dst, const uint8_t *src[5], int stride, int h); + void (*avg_dirac_pixels_tab[3][4])(uint8_t *dst, const uint8_t *src[5], int stride, int h); + + void (*put_signed_rect_clamped[3])(uint8_t *dst/*align 16*/, int dst_stride, const uint8_t *src/*align 16*/, int src_stride, int width, int height/*mod 2*/); + void (*put_rect_clamped)(uint8_t *dst/*align 16*/, int dst_stride, const uint8_t *src/*align 16*/, int src_stride, int width, int height/*mod 2*/); + void (*add_rect_clamped)(uint8_t *dst/*align 16*/, const uint16_t *src/*align 16*/, int stride, const int16_t *idwt/*align 16*/, int idwt_stride, int width, int height/*mod 2*/); + void (*add_dirac_obmc[3])(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); + + /* 0-1: int16_t and int32_t asm/c, 2-3: int16 and int32_t, C only */ + void (*dequant_subband[4])(uint8_t *src, uint8_t *dst, ptrdiff_t stride, const int qf, const int qs, int tot_v, int tot_h); + + dirac_weight_func weight_dirac_pixels_tab[3]; + dirac_biweight_func biweight_dirac_pixels_tab[3]; +} DiracDSPContext; + +#define DECL_DIRAC_PIXOP(PFX, EXT) \ + void ff_ ## PFX ## _dirac_pixels8_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h); \ + void ff_ ## PFX ## _dirac_pixels16_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h); \ + void ff_ ## PFX ## _dirac_pixels32_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h) + +DECL_DIRAC_PIXOP(put, c); +DECL_DIRAC_PIXOP(avg, c); +DECL_DIRAC_PIXOP(put, l2_c); +DECL_DIRAC_PIXOP(avg, l2_c); +DECL_DIRAC_PIXOP(put, l4_c); +DECL_DIRAC_PIXOP(avg, l4_c); + +void ff_diracdsp_init(DiracDSPContext *c); +void ff_diracdsp_init_x86(DiracDSPContext* c); + +#endif /* AVCODEC_DIRACDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/diractab.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/diractab.h new file mode 100644 index 0000000000..2423b07293 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/diractab.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 Open Broadcast Systems Ltd. + * Author (C) 2016 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DIRACTAB_H +#define AVCODEC_DIRACTAB_H + +#include + +/* Tables here are shared between the Dirac/VC-2 decoder and the VC-2 encoder */ + +/* Default quantization tables for each wavelet transform */ +extern const uint8_t ff_dirac_default_qmat[7][4][4]; + +/* Scaling factors needed for quantization/dequantization */ +extern const int32_t ff_dirac_qscale_tab[116]; + +/* Scaling offsets needed for quantization/dequantization, for intra frames */ +extern const int32_t ff_dirac_qoffset_intra_tab[120]; + +/* Scaling offsets needed for quantization/dequantization, for inter frames */ +extern const int ff_dirac_qoffset_inter_tab[122]; + +#define DIRAC_MAX_QUANT_INDEX (FF_ARRAY_ELEMS(ff_dirac_qscale_tab)) + +#endif /* AVCODEC_DIRACTAB_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile.c new file mode 100644 index 0000000000..66505c886b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile.c @@ -0,0 +1,341 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include + +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/log.h" +#include "libavutil/pixdesc.h" + +#include "avcodec.h" +#include "dv_profile.h" +#include "dv_profile_internal.h" + +#if CONFIG_DVPROFILE + +static const uint8_t dv_audio_shuffle525[10][9] = { + { 0, 30, 60, 20, 50, 80, 10, 40, 70 }, /* 1st channel */ + { 6, 36, 66, 26, 56, 86, 16, 46, 76 }, + { 12, 42, 72, 2, 32, 62, 22, 52, 82 }, + { 18, 48, 78, 8, 38, 68, 28, 58, 88 }, + { 24, 54, 84, 14, 44, 74, 4, 34, 64 }, + + { 1, 31, 61, 21, 51, 81, 11, 41, 71 }, /* 2nd channel */ + { 7, 37, 67, 27, 57, 87, 17, 47, 77 }, + { 13, 43, 73, 3, 33, 63, 23, 53, 83 }, + { 19, 49, 79, 9, 39, 69, 29, 59, 89 }, + { 25, 55, 85, 15, 45, 75, 5, 35, 65 }, +}; + +static const uint8_t dv_audio_shuffle625[12][9] = { + { 0, 36, 72, 26, 62, 98, 16, 52, 88 }, /* 1st channel */ + { 6, 42, 78, 32, 68, 104, 22, 58, 94 }, + { 12, 48, 84, 2, 38, 74, 28, 64, 100 }, + { 18, 54, 90, 8, 44, 80, 34, 70, 106 }, + { 24, 60, 96, 14, 50, 86, 4, 40, 76 }, + { 30, 66, 102, 20, 56, 92, 10, 46, 82 }, + + { 1, 37, 73, 27, 63, 99, 17, 53, 89 }, /* 2nd channel */ + { 7, 43, 79, 33, 69, 105, 23, 59, 95 }, + { 13, 49, 85, 3, 39, 75, 29, 65, 101 }, + { 19, 55, 91, 9, 45, 81, 35, 71, 107 }, + { 25, 61, 97, 15, 51, 87, 5, 41, 77 }, + { 31, 67, 103, 21, 57, 93, 11, 47, 83 }, +}; + +/* macroblock bit budgets */ +static const uint8_t block_sizes_dv2550[8] = { + 112, 112, 112, 112, 80, 80, 0, 0, +}; + +static const uint8_t block_sizes_dv100[8] = { + 80, 80, 80, 80, 80, 80, 64, 64, +}; + +static const AVDVProfile dv_profiles[] = { + { .dsf = 0, + .video_stype = 0x0, + .frame_size = 120000, /* IEC 61834, SMPTE-314M - 525/60 (NTSC) */ + .difseg_size = 10, + .n_difchan = 1, + .time_base = { 1001, 30000 }, + .ltc_divisor = 30, + .height = 480, + .width = 720, + .sar = { { 8, 9 }, { 32, 27 } }, + .pix_fmt = AV_PIX_FMT_YUV411P, + .bpm = 6, + .block_sizes = block_sizes_dv2550, + .audio_stride = 90, + .audio_min_samples = { 1580, 1452, 1053 }, /* for 48, 44.1 and 32kHz */ + .audio_samples_dist = { 1600, 1602, 1602, 1602, 1602 }, /* per SMPTE-314M */ + .audio_shuffle = dv_audio_shuffle525, }, + { .dsf = 1, + .video_stype = 0x0, + .frame_size = 144000, /* IEC 61834 - 625/50 (PAL) */ + .difseg_size = 12, + .n_difchan = 1, + .time_base = { 1, 25 }, + .ltc_divisor = 25, + .height = 576, + .width = 720, + .sar = { { 16, 15 }, { 64, 45 } }, + .pix_fmt = AV_PIX_FMT_YUV420P, + .bpm = 6, + .block_sizes = block_sizes_dv2550, + .audio_stride = 108, + .audio_min_samples = { 1896, 1742, 1264 }, /* for 48, 44.1 and 32kHz */ + .audio_samples_dist = { 1920, 1920, 1920, 1920, 1920 }, + .audio_shuffle = dv_audio_shuffle625, }, + { .dsf = 1, + .video_stype = 0x0, + .frame_size = 144000, /* SMPTE-314M - 625/50 (PAL) */ + .difseg_size = 12, + .n_difchan = 1, + .time_base = { 1, 25 }, + .ltc_divisor = 25, + .height = 576, + .width = 720, + .sar = { { 16, 15 }, { 64, 45 } }, + .pix_fmt = AV_PIX_FMT_YUV411P, + .bpm = 6, + .block_sizes = block_sizes_dv2550, + .audio_stride = 108, + .audio_min_samples = { 1896, 1742, 1264 }, /* for 48, 44.1 and 32kHz */ + .audio_samples_dist = { 1920, 1920, 1920, 1920, 1920 }, + .audio_shuffle = dv_audio_shuffle625, }, + { .dsf = 0, + .video_stype = 0x4, + .frame_size = 240000, /* SMPTE-314M - 525/60 (NTSC) 50 Mbps */ + .difseg_size = 10, /* also known as "DVCPRO50" */ + .n_difchan = 2, + .time_base = { 1001, 30000 }, + .ltc_divisor = 30, + .height = 480, + .width = 720, + .sar = { { 8, 9 }, { 32, 27 } }, + .pix_fmt = AV_PIX_FMT_YUV422P, + .bpm = 6, + .block_sizes = block_sizes_dv2550, + .audio_stride = 90, + .audio_min_samples = { 1580, 1452, 1053 }, /* for 48, 44.1 and 32kHz */ + .audio_samples_dist = { 1600, 1602, 1602, 1602, 1602 }, /* per SMPTE-314M */ + .audio_shuffle = dv_audio_shuffle525, }, + { .dsf = 1, + .video_stype = 0x4, + .frame_size = 288000, /* SMPTE-314M - 625/50 (PAL) 50 Mbps */ + .difseg_size = 12, /* also known as "DVCPRO50" */ + .n_difchan = 2, + .time_base = { 1, 25 }, + .ltc_divisor = 25, + .height = 576, + .width = 720, + .sar = { { 16, 15 }, { 64, 45 } }, + .pix_fmt = AV_PIX_FMT_YUV422P, + .bpm = 6, + .block_sizes = block_sizes_dv2550, + .audio_stride = 108, + .audio_min_samples = { 1896, 1742, 1264 }, /* for 48, 44.1 and 32kHz */ + .audio_samples_dist = { 1920, 1920, 1920, 1920, 1920 }, + .audio_shuffle = dv_audio_shuffle625, }, + { .dsf = 0, + .video_stype = 0x14, + .frame_size = 480000, /* SMPTE-370M - 1080i60 100 Mbps */ + .difseg_size = 10, /* also known as "DVCPRO HD" */ + .n_difchan = 4, + .time_base = { 1001, 30000 }, + .ltc_divisor = 30, + .height = 1080, + .width = 1280, + .sar = { { 1, 1 }, { 3, 2 } }, + .pix_fmt = AV_PIX_FMT_YUV422P, + .bpm = 8, + .block_sizes = block_sizes_dv100, + .audio_stride = 90, + .audio_min_samples = { 1580, 1452, 1053 }, /* for 48, 44.1 and 32kHz */ + .audio_samples_dist = { 1600, 1602, 1602, 1602, 1602 }, /* per SMPTE-314M */ + .audio_shuffle = dv_audio_shuffle525, }, + { .dsf = 1, + .video_stype = 0x14, + .frame_size = 576000, /* SMPTE-370M - 1080i50 100 Mbps */ + .difseg_size = 12, /* also known as "DVCPRO HD" */ + .n_difchan = 4, + .time_base = { 1, 25 }, + .ltc_divisor = 25, + .height = 1080, + .width = 1440, + .sar = { { 1, 1 }, { 4, 3 } }, + .pix_fmt = AV_PIX_FMT_YUV422P, + .bpm = 8, + .block_sizes = block_sizes_dv100, + .audio_stride = 108, + .audio_min_samples = { 1896, 1742, 1264 }, /* for 48, 44.1 and 32kHz */ + .audio_samples_dist = { 1920, 1920, 1920, 1920, 1920 }, + .audio_shuffle = dv_audio_shuffle625, }, + { .dsf = 0, + .video_stype = 0x18, + .frame_size = 240000, /* SMPTE-370M - 720p60 100 Mbps */ + .difseg_size = 10, /* also known as "DVCPRO HD" */ + .n_difchan = 2, + .time_base = { 1001, 60000 }, + .ltc_divisor = 60, + .height = 720, + .width = 960, + .sar = { { 1, 1 }, { 4, 3 } }, + .pix_fmt = AV_PIX_FMT_YUV422P, + .bpm = 8, + .block_sizes = block_sizes_dv100, + .audio_stride = 90, + .audio_min_samples = { 1580, 1452, 1053 }, /* for 48, 44.1 and 32kHz */ + .audio_samples_dist = { 1600, 1602, 1602, 1602, 1602 }, /* per SMPTE-314M */ + .audio_shuffle = dv_audio_shuffle525, }, + { .dsf = 1, + .video_stype = 0x18, + .frame_size = 288000, /* SMPTE-370M - 720p50 100 Mbps */ + .difseg_size = 12, /* also known as "DVCPRO HD" */ + .n_difchan = 2, + .time_base = { 1, 50 }, + .ltc_divisor = 50, + .height = 720, + .width = 960, + .sar = { { 1, 1 }, { 4, 3 } }, + .pix_fmt = AV_PIX_FMT_YUV422P, + .bpm = 8, + .block_sizes = block_sizes_dv100, + .audio_stride = 90, + .audio_min_samples = { 1896, 1742, 1264 }, /* for 48, 44.1 and 32kHz */ + .audio_samples_dist = { 1920, 1920, 1920, 1920, 1920 }, + .audio_shuffle = dv_audio_shuffle625, }, + { .dsf = 1, + .video_stype = 0x1, + .frame_size = 144000, /* IEC 61883-5 - 625/50 (PAL) */ + .difseg_size = 12, + .n_difchan = 1, + .time_base = { 1, 25 }, + .ltc_divisor = 25, + .height = 576, + .width = 720, + .sar = { { 16, 15 }, { 64, 45 } }, + .pix_fmt = AV_PIX_FMT_YUV420P, + .bpm = 6, + .block_sizes = block_sizes_dv2550, + .audio_stride = 108, + .audio_min_samples = { 1896, 1742, 1264 }, /* for 48, 44.1 and 32kHz */ + .audio_samples_dist = { 1920, 1920, 1920, 1920, 1920 }, + .audio_shuffle = dv_audio_shuffle625, } +}; + +void ff_dv_print_profiles(void *logctx, int loglevel) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(dv_profiles); i++) { + const AVDVProfile *p = &dv_profiles[i]; + av_log(logctx, loglevel, + "Frame size: %dx%d; pixel format: %s, framerate: %d/%d\n", + p->width, p->height, av_get_pix_fmt_name(p->pix_fmt), + p->time_base.den, p->time_base.num); + } +} + +#endif /* CONFIG_DVPROFILE */ + +const AVDVProfile* ff_dv_frame_profile(AVCodecContext* codec, const AVDVProfile *sys, + const uint8_t *frame, unsigned buf_size) +{ +#if CONFIG_DVPROFILE + int i, dsf, stype; + + if(buf_size < DV_PROFILE_BYTES) + return NULL; + + dsf = (frame[3] & 0x80) >> 7; + stype = frame[80 * 5 + 48 + 3] & 0x1f; + + /* 576i50 25Mbps 4:1:1 is a special case */ + if ((dsf == 1 && stype == 0 && frame[4] & 0x07 /* the APT field */) || + (stype == 31 && codec && codec->codec_tag==AV_RL32("SL25") && codec->coded_width==720 && codec->coded_height==576)) + return &dv_profiles[2]; + + if( stype == 0 + && codec + && (codec->codec_tag==AV_RL32("dvsd") || codec->codec_tag==AV_RL32("CDVC")) + && codec->coded_width ==720 + && codec->coded_height==576) + return &dv_profiles[1]; + + for (i = 0; i < FF_ARRAY_ELEMS(dv_profiles); i++) + if (dsf == dv_profiles[i].dsf && stype == dv_profiles[i].video_stype) + return &dv_profiles[i]; + + /* check if old sys matches and assumes corrupted input */ + if (sys && buf_size == sys->frame_size) + return sys; + + /* hack for trac issue #217, dv files created with QuickTime 3 */ + if ((frame[3] & 0x7f) == 0x3f && frame[80 * 5 + 48 + 3] == 0xff) + return &dv_profiles[dsf]; +#endif + + return NULL; +} + +const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys, + const uint8_t *frame, unsigned buf_size) +{ + return ff_dv_frame_profile(NULL, sys, frame, buf_size); +} + +const AVDVProfile *av_dv_codec_profile(int width, int height, + enum AVPixelFormat pix_fmt) +{ +#if CONFIG_DVPROFILE + return av_dv_codec_profile2(width, height, pix_fmt, (AVRational){0, 0}); +#endif + + return NULL; +} + +const AVDVProfile *av_dv_codec_profile2(int width, int height, + enum AVPixelFormat pix_fmt, + AVRational frame_rate) +{ + const AVDVProfile *p = NULL; +#if CONFIG_DVPROFILE + int i; + /* frame rate is necessary to select between 720p50 and 720p60 profiles */ + int invalid_framerate = frame_rate.num == 0 || frame_rate.den == 0; + + for (i = 0; i < FF_ARRAY_ELEMS(dv_profiles); i++) + if (height == dv_profiles[i].height && + pix_fmt == dv_profiles[i].pix_fmt && + width == dv_profiles[i].width) + { + if( invalid_framerate || av_div_q(dv_profiles[i].time_base, frame_rate).num == 1 ) + return &dv_profiles[i]; + + if(!p) + p = &dv_profiles[i]; + } +#endif + + return p; +} + diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile.h new file mode 100644 index 0000000000..9380a66f07 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile.h @@ -0,0 +1,83 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DV_PROFILE_H +#define AVCODEC_DV_PROFILE_H + +#include + +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" +#include "avcodec.h" + +/* minimum number of bytes to read from a DV stream in order to + * determine the profile */ +#define DV_PROFILE_BYTES (6 * 80) /* 6 DIF blocks */ + + +/* + * AVDVProfile is used to express the differences between various + * DV flavors. For now it's primarily used for differentiating + * 525/60 and 625/50, but the plans are to use it for various + * DV specs as well (e.g. SMPTE314M vs. IEC 61834). + */ +typedef struct AVDVProfile { + int dsf; /* value of the dsf in the DV header */ + int video_stype; /* stype for VAUX source pack */ + int frame_size; /* total size of one frame in bytes */ + int difseg_size; /* number of DIF segments per DIF channel */ + int n_difchan; /* number of DIF channels per frame */ + AVRational time_base; /* 1/framerate */ + int ltc_divisor; /* FPS from the LTS standpoint */ + int height; /* picture height in pixels */ + int width; /* picture width in pixels */ + AVRational sar[2]; /* sample aspect ratios for 4:3 and 16:9 */ + enum AVPixelFormat pix_fmt; /* picture pixel format */ + int bpm; /* blocks per macroblock */ + const uint8_t *block_sizes; /* AC block sizes, in bits */ + int audio_stride; /* size of audio_shuffle table */ + int audio_min_samples[3]; /* min amount of audio samples */ + /* for 48kHz, 44.1kHz and 32kHz */ + int audio_samples_dist[5]; /* how many samples are supposed to be */ + /* in each frame in a 5 frames window */ + const uint8_t (*audio_shuffle)[9]; /* PCM shuffling table */ +} AVDVProfile; + +/** + * Get a DV profile for the provided compressed frame. + * + * @param sys the profile used for the previous frame, may be NULL + * @param frame the compressed data buffer + * @param buf_size size of the buffer in bytes + * @return the DV profile for the supplied data or NULL on failure + */ +const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys, + const uint8_t *frame, unsigned buf_size); + +/** + * Get a DV profile for the provided stream parameters. + */ +const AVDVProfile *av_dv_codec_profile(int width, int height, enum AVPixelFormat pix_fmt); + +/** + * Get a DV profile for the provided stream parameters. + * The frame rate is used as a best-effort parameter. + */ +const AVDVProfile *av_dv_codec_profile2(int width, int height, enum AVPixelFormat pix_fmt, AVRational frame_rate); + +#endif /* AVCODEC_DV_PROFILE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile_internal.h new file mode 100644 index 0000000000..67d3a2b79a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dv_profile_internal.h @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DV_PROFILE_INTERNAL_H +#define AVCODEC_DV_PROFILE_INTERNAL_H + +#include "dv_profile.h" + +/** + * Print all allowed DV profiles into logctx at specified logging level. + */ +void ff_dv_print_profiles(void *logctx, int loglevel); + +/** + * Get a DV profile for the provided compressed frame. + */ +const AVDVProfile* ff_dv_frame_profile(AVCodecContext* codec, const AVDVProfile *sys, + const uint8_t *frame, unsigned buf_size); + +#endif /* AVCODEC_DV_PROFILE_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dxva2.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dxva2.h new file mode 100644 index 0000000000..22c93992f2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/dxva2.h @@ -0,0 +1,93 @@ +/* + * DXVA2 HW acceleration + * + * copyright (c) 2009 Laurent Aimar + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DXVA2_H +#define AVCODEC_DXVA2_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_dxva2 + * Public libavcodec DXVA2 header. + */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif + +#include +#include +#include + +/** + * @defgroup lavc_codec_hwaccel_dxva2 DXVA2 + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG 1 ///< Work around for DXVA2 and old UVD/UVD+ ATI video cards +#define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 ///< Work around for DXVA2 and old Intel GPUs with ClearVideo interface + +/** + * This structure is used to provides the necessary configurations and data + * to the DXVA2 FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct dxva_context { + /** + * DXVA2 decoder object + */ + IDirectXVideoDecoder *decoder; + + /** + * DXVA2 configuration used to create the decoder + */ + const DXVA2_ConfigPictureDecode *cfg; + + /** + * The number of surface in the surface array + */ + unsigned surface_count; + + /** + * The array of Direct3D surfaces used to create the decoder + */ + LPDIRECT3DSURFACE9 *surface; + + /** + * A bit field configuring the workarounds needed for using the decoder + */ + uint64_t workaround; + + /** + * Private to the FFmpeg AVHWAccel implementation + */ + unsigned report_id; +}; + +/** + * @} + */ + +#endif /* AVCODEC_DXVA2_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/encode.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/encode.c new file mode 100644 index 0000000000..d12c42526b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/encode.c @@ -0,0 +1,447 @@ +/* + * generic encoding-related code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/frame.h" +#include "libavutil/imgutils.h" +#include "libavutil/internal.h" +#include "libavutil/samplefmt.h" + +#include "avcodec.h" +#include "frame_thread_encoder.h" +#include "internal.h" + +int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int64_t min_size) +{ + if (avpkt->size < 0) { + av_log(avctx, AV_LOG_ERROR, "Invalid negative user packet size %d\n", avpkt->size); + return AVERROR(EINVAL); + } + if (size < 0 || size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { + av_log(avctx, AV_LOG_ERROR, "Invalid minimum required packet size %"PRId64" (max allowed is %d)\n", + size, INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE); + return AVERROR(EINVAL); + } + + if (avctx && 2*min_size < size) { // FIXME The factor needs to be finetuned + av_assert0(!avpkt->data || avpkt->data != avctx->internal->byte_buffer); + if (!avpkt->data || avpkt->size < size) { + av_fast_padded_malloc(&avctx->internal->byte_buffer, &avctx->internal->byte_buffer_size, size); + avpkt->data = avctx->internal->byte_buffer; + avpkt->size = avctx->internal->byte_buffer_size; + } + } + + if (avpkt->data) { + AVBufferRef *buf = avpkt->buf; + + if (avpkt->size < size) { + av_log(avctx, AV_LOG_ERROR, "User packet is too small (%d < %"PRId64")\n", avpkt->size, size); + return AVERROR(EINVAL); + } + + av_init_packet(avpkt); + avpkt->buf = buf; + avpkt->size = size; + return 0; + } else { + int ret = av_new_packet(avpkt, size); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "Failed to allocate packet of size %"PRId64"\n", size); + return ret; + } +} + +int ff_alloc_packet(AVPacket *avpkt, int size) +{ + return ff_alloc_packet2(NULL, avpkt, size, 0); +} + +/** + * Pad last frame with silence. + */ +static int pad_last_frame(AVCodecContext *s, AVFrame **dst, const AVFrame *src) +{ + AVFrame *frame = NULL; + int ret; + + if (!(frame = av_frame_alloc())) + return AVERROR(ENOMEM); + + frame->format = src->format; + frame->channel_layout = src->channel_layout; + frame->channels = src->channels; + frame->nb_samples = s->frame_size; + ret = av_frame_get_buffer(frame, 32); + if (ret < 0) + goto fail; + + ret = av_frame_copy_props(frame, src); + if (ret < 0) + goto fail; + + if ((ret = av_samples_copy(frame->extended_data, src->extended_data, 0, 0, + src->nb_samples, s->channels, s->sample_fmt)) < 0) + goto fail; + if ((ret = av_samples_set_silence(frame->extended_data, src->nb_samples, + frame->nb_samples - src->nb_samples, + s->channels, s->sample_fmt)) < 0) + goto fail; + + *dst = frame; + + return 0; + +fail: + av_frame_free(&frame); + return ret; +} + +int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx, + AVPacket *avpkt, + const AVFrame *frame, + int *got_packet_ptr) +{ + AVFrame *extended_frame = NULL; + AVFrame *padded_frame = NULL; + int ret; + AVPacket user_pkt = *avpkt; + int needs_realloc = !user_pkt.data; + + *got_packet_ptr = 0; + + if (!avctx->codec->encode2) { + av_log(avctx, AV_LOG_ERROR, "This encoder requires using the avcodec_send_frame() API.\n"); + return AVERROR(ENOSYS); + } + + if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY) && !frame) { + av_packet_unref(avpkt); + return 0; + } + + /* ensure that extended_data is properly set */ + if (frame && !frame->extended_data) { + if (av_sample_fmt_is_planar(avctx->sample_fmt) && + avctx->channels > AV_NUM_DATA_POINTERS) { + av_log(avctx, AV_LOG_ERROR, "Encoding to a planar sample format, " + "with more than %d channels, but extended_data is not set.\n", + AV_NUM_DATA_POINTERS); + return AVERROR(EINVAL); + } + av_log(avctx, AV_LOG_WARNING, "extended_data is not set.\n"); + + extended_frame = av_frame_alloc(); + if (!extended_frame) + return AVERROR(ENOMEM); + + memcpy(extended_frame, frame, sizeof(AVFrame)); + extended_frame->extended_data = extended_frame->data; + frame = extended_frame; + } + + /* extract audio service type metadata */ + if (frame) { + AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_AUDIO_SERVICE_TYPE); + if (sd && sd->size >= sizeof(enum AVAudioServiceType)) + avctx->audio_service_type = *(enum AVAudioServiceType*)sd->data; + } + + /* check for valid frame size */ + if (frame) { + if (avctx->codec->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME) { + if (frame->nb_samples > avctx->frame_size) { + av_log(avctx, AV_LOG_ERROR, "more samples than frame size (avcodec_encode_audio2)\n"); + ret = AVERROR(EINVAL); + goto end; + } + } else if (!(avctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)) { + if (frame->nb_samples < avctx->frame_size && + !avctx->internal->last_audio_frame) { + ret = pad_last_frame(avctx, &padded_frame, frame); + if (ret < 0) + goto end; + + frame = padded_frame; + avctx->internal->last_audio_frame = 1; + } + + if (frame->nb_samples != avctx->frame_size) { + av_log(avctx, AV_LOG_ERROR, "nb_samples (%d) != frame_size (%d) (avcodec_encode_audio2)\n", frame->nb_samples, avctx->frame_size); + ret = AVERROR(EINVAL); + goto end; + } + } + } + + av_assert0(avctx->codec->encode2); + + ret = avctx->codec->encode2(avctx, avpkt, frame, got_packet_ptr); + if (!ret) { + if (*got_packet_ptr) { + if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) { + if (avpkt->pts == AV_NOPTS_VALUE) + avpkt->pts = frame->pts; + if (!avpkt->duration) + avpkt->duration = ff_samples_to_time_base(avctx, + frame->nb_samples); + } + avpkt->dts = avpkt->pts; + } else { + avpkt->size = 0; + } + } + if (avpkt->data && avpkt->data == avctx->internal->byte_buffer) { + needs_realloc = 0; + if (user_pkt.data) { + if (user_pkt.size >= avpkt->size) { + memcpy(user_pkt.data, avpkt->data, avpkt->size); + } else { + av_log(avctx, AV_LOG_ERROR, "Provided packet is too small, needs to be %d\n", avpkt->size); + avpkt->size = user_pkt.size; + ret = -1; + } + avpkt->buf = user_pkt.buf; + avpkt->data = user_pkt.data; + } else if (!avpkt->buf) { + ret = av_packet_make_refcounted(avpkt); + if (ret < 0) + goto end; + } + } + + if (!ret) { + if (needs_realloc && avpkt->data) { + ret = av_buffer_realloc(&avpkt->buf, avpkt->size + AV_INPUT_BUFFER_PADDING_SIZE); + if (ret >= 0) + avpkt->data = avpkt->buf->data; + } + if (frame) + avctx->frame_number++; + } + + if (ret < 0 || !*got_packet_ptr) { + av_packet_unref(avpkt); + goto end; + } + + /* NOTE: if we add any audio encoders which output non-keyframe packets, + * this needs to be moved to the encoders, but for now we can do it + * here to simplify things */ + avpkt->flags |= AV_PKT_FLAG_KEY; + +end: + av_frame_free(&padded_frame); + av_free(extended_frame); + + return ret; +} + +int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx, + AVPacket *avpkt, + const AVFrame *frame, + int *got_packet_ptr) +{ + int ret; + AVPacket user_pkt = *avpkt; + int needs_realloc = !user_pkt.data; + + *got_packet_ptr = 0; + + if (!avctx->codec->encode2) { + av_log(avctx, AV_LOG_ERROR, "This encoder requires using the avcodec_send_frame() API.\n"); + return AVERROR(ENOSYS); + } + + if(CONFIG_FRAME_THREAD_ENCODER && + avctx->internal->frame_thread_encoder && (avctx->active_thread_type&FF_THREAD_FRAME)) + return ff_thread_video_encode_frame(avctx, avpkt, frame, got_packet_ptr); + + if ((avctx->flags&AV_CODEC_FLAG_PASS1) && avctx->stats_out) + avctx->stats_out[0] = '\0'; + + if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY) && !frame) { + av_packet_unref(avpkt); + return 0; + } + + if (av_image_check_size2(avctx->width, avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx)) + return AVERROR(EINVAL); + + if (frame && frame->format == AV_PIX_FMT_NONE) + av_log(avctx, AV_LOG_WARNING, "AVFrame.format is not set\n"); + if (frame && (frame->width == 0 || frame->height == 0)) + av_log(avctx, AV_LOG_WARNING, "AVFrame.width or height is not set\n"); + + av_assert0(avctx->codec->encode2); + + ret = avctx->codec->encode2(avctx, avpkt, frame, got_packet_ptr); + av_assert0(ret <= 0); + + emms_c(); + + if (avpkt->data && avpkt->data == avctx->internal->byte_buffer) { + needs_realloc = 0; + if (user_pkt.data) { + if (user_pkt.size >= avpkt->size) { + memcpy(user_pkt.data, avpkt->data, avpkt->size); + } else { + av_log(avctx, AV_LOG_ERROR, "Provided packet is too small, needs to be %d\n", avpkt->size); + avpkt->size = user_pkt.size; + ret = -1; + } + avpkt->buf = user_pkt.buf; + avpkt->data = user_pkt.data; + } else if (!avpkt->buf) { + ret = av_packet_make_refcounted(avpkt); + if (ret < 0) + return ret; + } + } + + if (!ret) { + if (!*got_packet_ptr) + avpkt->size = 0; + else if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) + avpkt->pts = avpkt->dts = frame->pts; + + if (needs_realloc && avpkt->data) { + ret = av_buffer_realloc(&avpkt->buf, avpkt->size + AV_INPUT_BUFFER_PADDING_SIZE); + if (ret >= 0) + avpkt->data = avpkt->buf->data; + } + + if (frame) + avctx->frame_number++; + } + + if (ret < 0 || !*got_packet_ptr) + av_packet_unref(avpkt); + + return ret; +} + +int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVSubtitle *sub) +{ + int ret; + if (sub->start_display_time) { + av_log(avctx, AV_LOG_ERROR, "start_display_time must be 0.\n"); + return -1; + } + + ret = avctx->codec->encode_sub(avctx, buf, buf_size, sub); + avctx->frame_number++; + return ret; +} + +static int do_encode(AVCodecContext *avctx, const AVFrame *frame, int *got_packet) +{ + int ret; + *got_packet = 0; + + av_packet_unref(avctx->internal->buffer_pkt); + avctx->internal->buffer_pkt_valid = 0; + + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + ret = avcodec_encode_video2(avctx, avctx->internal->buffer_pkt, + frame, got_packet); + } else if (avctx->codec_type == AVMEDIA_TYPE_AUDIO) { + ret = avcodec_encode_audio2(avctx, avctx->internal->buffer_pkt, + frame, got_packet); + } else { + ret = AVERROR(EINVAL); + } + + if (ret >= 0 && *got_packet) { + // Encoders must always return ref-counted buffers. + // Side-data only packets have no data and can be not ref-counted. + av_assert0(!avctx->internal->buffer_pkt->data || avctx->internal->buffer_pkt->buf); + avctx->internal->buffer_pkt_valid = 1; + ret = 0; + } else { + av_packet_unref(avctx->internal->buffer_pkt); + } + + return ret; +} + +int attribute_align_arg avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame) +{ + if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec)) + return AVERROR(EINVAL); + + if (avctx->internal->draining) + return AVERROR_EOF; + + if (!frame) { + avctx->internal->draining = 1; + + if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) + return 0; + } + + if (avctx->codec->send_frame) + return avctx->codec->send_frame(avctx, frame); + + // Emulation via old API. Do it here instead of avcodec_receive_packet, because: + // 1. if the AVFrame is not refcounted, the copying will be much more + // expensive than copying the packet data + // 2. assume few users use non-refcounted AVPackets, so usually no copy is + // needed + + if (avctx->internal->buffer_pkt_valid) + return AVERROR(EAGAIN); + + return do_encode(avctx, frame, &(int){0}); +} + +int attribute_align_arg avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) +{ + av_packet_unref(avpkt); + + if (!avcodec_is_open(avctx) || !av_codec_is_encoder(avctx->codec)) + return AVERROR(EINVAL); + + if (avctx->codec->receive_packet) { + if (avctx->internal->draining && !(avctx->codec->capabilities & AV_CODEC_CAP_DELAY)) + return AVERROR_EOF; + return avctx->codec->receive_packet(avctx, avpkt); + } + + // Emulation via old API. + + if (!avctx->internal->buffer_pkt_valid) { + int got_packet; + int ret; + if (!avctx->internal->draining) + return AVERROR(EAGAIN); + ret = do_encode(avctx, NULL, &got_packet); + if (ret < 0) + return ret; + if (ret >= 0 && !got_packet) + return AVERROR_EOF; + } + + av_packet_move_ref(avpkt, avctx->internal->buffer_pkt); + avctx->internal->buffer_pkt_valid = 0; + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/error_resilience.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/error_resilience.c new file mode 100644 index 0000000000..ca2287198b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/error_resilience.c @@ -0,0 +1,1366 @@ +/* + * Error resilience / concealment + * + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Error resilience / concealment. + */ + +#include + +#include "libavutil/internal.h" +#include "avcodec.h" +#include "error_resilience.h" +#include "me_cmp.h" +#include "mpegutils.h" +#include "mpegvideo.h" +#include "rectangle.h" +#include "thread.h" +#include "version.h" + +/** + * @param stride the number of MVs to get to the next row + * @param mv_step the number of MVs per row or column in a macroblock + */ +static void set_mv_strides(ERContext *s, ptrdiff_t *mv_step, ptrdiff_t *stride) +{ + if (s->avctx->codec_id == AV_CODEC_ID_H264) { + av_assert0(s->quarter_sample); + *mv_step = 4; + *stride = s->mb_width * 4; + } else { + *mv_step = 2; + *stride = s->b8_stride; + } +} + +/** + * Replace the current MB with a flat dc-only version. + */ +static void put_dc(ERContext *s, uint8_t *dest_y, uint8_t *dest_cb, + uint8_t *dest_cr, int mb_x, int mb_y) +{ + int *linesize = s->cur_pic.f->linesize; + int dc, dcu, dcv, y, i; + for (i = 0; i < 4; i++) { + dc = s->dc_val[0][mb_x * 2 + (i & 1) + (mb_y * 2 + (i >> 1)) * s->b8_stride]; + if (dc < 0) + dc = 0; + else if (dc > 2040) + dc = 2040; + for (y = 0; y < 8; y++) { + int x; + for (x = 0; x < 8; x++) + dest_y[x + (i & 1) * 8 + (y + (i >> 1) * 8) * linesize[0]] = dc / 8; + } + } + dcu = s->dc_val[1][mb_x + mb_y * s->mb_stride]; + dcv = s->dc_val[2][mb_x + mb_y * s->mb_stride]; + if (dcu < 0) + dcu = 0; + else if (dcu > 2040) + dcu = 2040; + if (dcv < 0) + dcv = 0; + else if (dcv > 2040) + dcv = 2040; + + if (dest_cr) + for (y = 0; y < 8; y++) { + int x; + for (x = 0; x < 8; x++) { + dest_cb[x + y * linesize[1]] = dcu / 8; + dest_cr[x + y * linesize[2]] = dcv / 8; + } + } +} + +static void filter181(int16_t *data, int width, int height, ptrdiff_t stride) +{ + int x, y; + + /* horizontal filter */ + for (y = 1; y < height - 1; y++) { + int prev_dc = data[0 + y * stride]; + + for (x = 1; x < width - 1; x++) { + int dc; + dc = -prev_dc + + data[x + y * stride] * 8 - + data[x + 1 + y * stride]; + dc = (av_clip(dc, INT_MIN/10923, INT_MAX/10923 - 32768) * 10923 + 32768) >> 16; + prev_dc = data[x + y * stride]; + data[x + y * stride] = dc; + } + } + + /* vertical filter */ + for (x = 1; x < width - 1; x++) { + int prev_dc = data[x]; + + for (y = 1; y < height - 1; y++) { + int dc; + + dc = -prev_dc + + data[x + y * stride] * 8 - + data[x + (y + 1) * stride]; + dc = (av_clip(dc, INT_MIN/10923, INT_MAX/10923 - 32768) * 10923 + 32768) >> 16; + prev_dc = data[x + y * stride]; + data[x + y * stride] = dc; + } + } +} + +/** + * guess the dc of blocks which do not have an undamaged dc + * @param w width in 8 pixel blocks + * @param h height in 8 pixel blocks + */ +static void guess_dc(ERContext *s, int16_t *dc, int w, + int h, ptrdiff_t stride, int is_luma) +{ + int b_x, b_y; + int16_t (*col )[4] = av_malloc_array(stride, h*sizeof( int16_t)*4); + uint32_t (*dist)[4] = av_malloc_array(stride, h*sizeof(uint32_t)*4); + + if(!col || !dist) { + av_log(s->avctx, AV_LOG_ERROR, "guess_dc() is out of memory\n"); + goto fail; + } + + for(b_y=0; b_y>is_luma) + (b_y>>is_luma)*s->mb_stride; + int error_j= s->error_status_table[mb_index_j]; + int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]); + if(intra_j==0 || !(error_j&ER_DC_ERROR)){ + color= dc[b_x + b_y*stride]; + distance= b_x; + } + col [b_x + b_y*stride][1]= color; + dist[b_x + b_y*stride][1]= distance >= 0 ? b_x-distance : 9999; + } + color= 1024; + distance= -1; + for(b_x=w-1; b_x>=0; b_x--){ + int mb_index_j= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride; + int error_j= s->error_status_table[mb_index_j]; + int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]); + if(intra_j==0 || !(error_j&ER_DC_ERROR)){ + color= dc[b_x + b_y*stride]; + distance= b_x; + } + col [b_x + b_y*stride][0]= color; + dist[b_x + b_y*stride][0]= distance >= 0 ? distance-b_x : 9999; + } + } + for(b_x=0; b_x>is_luma) + (b_y>>is_luma)*s->mb_stride; + int error_j= s->error_status_table[mb_index_j]; + int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]); + if(intra_j==0 || !(error_j&ER_DC_ERROR)){ + color= dc[b_x + b_y*stride]; + distance= b_y; + } + col [b_x + b_y*stride][3]= color; + dist[b_x + b_y*stride][3]= distance >= 0 ? b_y-distance : 9999; + } + color= 1024; + distance= -1; + for(b_y=h-1; b_y>=0; b_y--){ + int mb_index_j= (b_x>>is_luma) + (b_y>>is_luma)*s->mb_stride; + int error_j= s->error_status_table[mb_index_j]; + int intra_j = IS_INTRA(s->cur_pic.mb_type[mb_index_j]); + if(intra_j==0 || !(error_j&ER_DC_ERROR)){ + color= dc[b_x + b_y*stride]; + distance= b_y; + } + col [b_x + b_y*stride][2]= color; + dist[b_x + b_y*stride][2]= distance >= 0 ? distance-b_y : 9999; + } + } + + for (b_y = 0; b_y < h; b_y++) { + for (b_x = 0; b_x < w; b_x++) { + int mb_index, error, j; + int64_t guess, weight_sum; + mb_index = (b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride; + error = s->error_status_table[mb_index]; + + if (IS_INTER(s->cur_pic.mb_type[mb_index])) + continue; // inter + if (!(error & ER_DC_ERROR)) + continue; // dc-ok + + weight_sum = 0; + guess = 0; + for (j = 0; j < 4; j++) { + int64_t weight = 256 * 256 * 256 * 16 / FFMAX(dist[b_x + b_y*stride][j], 1); + guess += weight*(int64_t)col[b_x + b_y*stride][j]; + weight_sum += weight; + } + guess = (guess + weight_sum / 2) / weight_sum; + dc[b_x + b_y * stride] = guess; + } + } + +fail: + av_freep(&col); + av_freep(&dist); +} + +/** + * simple horizontal deblocking filter used for error resilience + * @param w width in 8 pixel blocks + * @param h height in 8 pixel blocks + */ +static void h_block_filter(ERContext *s, uint8_t *dst, int w, + int h, ptrdiff_t stride, int is_luma) +{ + int b_x, b_y; + ptrdiff_t mvx_stride, mvy_stride; + const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; + set_mv_strides(s, &mvx_stride, &mvy_stride); + mvx_stride >>= is_luma; + mvy_stride *= mvx_stride; + + for (b_y = 0; b_y < h; b_y++) { + for (b_x = 0; b_x < w - 1; b_x++) { + int y; + int left_status = s->error_status_table[( b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride]; + int right_status = s->error_status_table[((b_x + 1) >> is_luma) + (b_y >> is_luma) * s->mb_stride]; + int left_intra = IS_INTRA(s->cur_pic.mb_type[( b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride]); + int right_intra = IS_INTRA(s->cur_pic.mb_type[((b_x + 1) >> is_luma) + (b_y >> is_luma) * s->mb_stride]); + int left_damage = left_status & ER_MB_ERROR; + int right_damage = right_status & ER_MB_ERROR; + int offset = b_x * 8 + b_y * stride * 8; + int16_t *left_mv = s->cur_pic.motion_val[0][mvy_stride * b_y + mvx_stride * b_x]; + int16_t *right_mv = s->cur_pic.motion_val[0][mvy_stride * b_y + mvx_stride * (b_x + 1)]; + if (!(left_damage || right_damage)) + continue; // both undamaged + if ((!left_intra) && (!right_intra) && + FFABS(left_mv[0] - right_mv[0]) + + FFABS(left_mv[1] + right_mv[1]) < 2) + continue; + + for (y = 0; y < 8; y++) { + int a, b, c, d; + + a = dst[offset + 7 + y * stride] - dst[offset + 6 + y * stride]; + b = dst[offset + 8 + y * stride] - dst[offset + 7 + y * stride]; + c = dst[offset + 9 + y * stride] - dst[offset + 8 + y * stride]; + + d = FFABS(b) - ((FFABS(a) + FFABS(c) + 1) >> 1); + d = FFMAX(d, 0); + if (b < 0) + d = -d; + + if (d == 0) + continue; + + if (!(left_damage && right_damage)) + d = d * 16 / 9; + + if (left_damage) { + dst[offset + 7 + y * stride] = cm[dst[offset + 7 + y * stride] + ((d * 7) >> 4)]; + dst[offset + 6 + y * stride] = cm[dst[offset + 6 + y * stride] + ((d * 5) >> 4)]; + dst[offset + 5 + y * stride] = cm[dst[offset + 5 + y * stride] + ((d * 3) >> 4)]; + dst[offset + 4 + y * stride] = cm[dst[offset + 4 + y * stride] + ((d * 1) >> 4)]; + } + if (right_damage) { + dst[offset + 8 + y * stride] = cm[dst[offset + 8 + y * stride] - ((d * 7) >> 4)]; + dst[offset + 9 + y * stride] = cm[dst[offset + 9 + y * stride] - ((d * 5) >> 4)]; + dst[offset + 10+ y * stride] = cm[dst[offset + 10 + y * stride] - ((d * 3) >> 4)]; + dst[offset + 11+ y * stride] = cm[dst[offset + 11 + y * stride] - ((d * 1) >> 4)]; + } + } + } + } +} + +/** + * simple vertical deblocking filter used for error resilience + * @param w width in 8 pixel blocks + * @param h height in 8 pixel blocks + */ +static void v_block_filter(ERContext *s, uint8_t *dst, int w, int h, + ptrdiff_t stride, int is_luma) +{ + int b_x, b_y; + ptrdiff_t mvx_stride, mvy_stride; + const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; + set_mv_strides(s, &mvx_stride, &mvy_stride); + mvx_stride >>= is_luma; + mvy_stride *= mvx_stride; + + for (b_y = 0; b_y < h - 1; b_y++) { + for (b_x = 0; b_x < w; b_x++) { + int x; + int top_status = s->error_status_table[(b_x >> is_luma) + (b_y >> is_luma) * s->mb_stride]; + int bottom_status = s->error_status_table[(b_x >> is_luma) + ((b_y + 1) >> is_luma) * s->mb_stride]; + int top_intra = IS_INTRA(s->cur_pic.mb_type[(b_x >> is_luma) + ( b_y >> is_luma) * s->mb_stride]); + int bottom_intra = IS_INTRA(s->cur_pic.mb_type[(b_x >> is_luma) + ((b_y + 1) >> is_luma) * s->mb_stride]); + int top_damage = top_status & ER_MB_ERROR; + int bottom_damage = bottom_status & ER_MB_ERROR; + int offset = b_x * 8 + b_y * stride * 8; + + int16_t *top_mv = s->cur_pic.motion_val[0][mvy_stride * b_y + mvx_stride * b_x]; + int16_t *bottom_mv = s->cur_pic.motion_val[0][mvy_stride * (b_y + 1) + mvx_stride * b_x]; + + if (!(top_damage || bottom_damage)) + continue; // both undamaged + + if ((!top_intra) && (!bottom_intra) && + FFABS(top_mv[0] - bottom_mv[0]) + + FFABS(top_mv[1] + bottom_mv[1]) < 2) + continue; + + for (x = 0; x < 8; x++) { + int a, b, c, d; + + a = dst[offset + x + 7 * stride] - dst[offset + x + 6 * stride]; + b = dst[offset + x + 8 * stride] - dst[offset + x + 7 * stride]; + c = dst[offset + x + 9 * stride] - dst[offset + x + 8 * stride]; + + d = FFABS(b) - ((FFABS(a) + FFABS(c) + 1) >> 1); + d = FFMAX(d, 0); + if (b < 0) + d = -d; + + if (d == 0) + continue; + + if (!(top_damage && bottom_damage)) + d = d * 16 / 9; + + if (top_damage) { + dst[offset + x + 7 * stride] = cm[dst[offset + x + 7 * stride] + ((d * 7) >> 4)]; + dst[offset + x + 6 * stride] = cm[dst[offset + x + 6 * stride] + ((d * 5) >> 4)]; + dst[offset + x + 5 * stride] = cm[dst[offset + x + 5 * stride] + ((d * 3) >> 4)]; + dst[offset + x + 4 * stride] = cm[dst[offset + x + 4 * stride] + ((d * 1) >> 4)]; + } + if (bottom_damage) { + dst[offset + x + 8 * stride] = cm[dst[offset + x + 8 * stride] - ((d * 7) >> 4)]; + dst[offset + x + 9 * stride] = cm[dst[offset + x + 9 * stride] - ((d * 5) >> 4)]; + dst[offset + x + 10 * stride] = cm[dst[offset + x + 10 * stride] - ((d * 3) >> 4)]; + dst[offset + x + 11 * stride] = cm[dst[offset + x + 11 * stride] - ((d * 1) >> 4)]; + } + } + } + } +} + +#define MV_FROZEN 8 +#define MV_CHANGED 4 +#define MV_UNCHANGED 2 +#define MV_LISTED 1 +static av_always_inline void add_blocklist(int (*blocklist)[2], int *blocklist_length, uint8_t *fixed, int mb_x, int mb_y, int mb_xy) +{ + if (fixed[mb_xy]) + return; + fixed[mb_xy] = MV_LISTED; + blocklist[ *blocklist_length ][0] = mb_x; + blocklist[(*blocklist_length)++][1] = mb_y; +} + +static void guess_mv(ERContext *s) +{ + int (*blocklist)[2], (*next_blocklist)[2]; + uint8_t *fixed; + const ptrdiff_t mb_stride = s->mb_stride; + const int mb_width = s->mb_width; + int mb_height = s->mb_height; + int i, depth, num_avail; + int mb_x, mb_y; + ptrdiff_t mot_step, mot_stride; + int blocklist_length, next_blocklist_length; + + if (s->last_pic.f && s->last_pic.f->data[0]) + mb_height = FFMIN(mb_height, (s->last_pic.f->height+15)>>4); + if (s->next_pic.f && s->next_pic.f->data[0]) + mb_height = FFMIN(mb_height, (s->next_pic.f->height+15)>>4); + + blocklist = (int (*)[2])s->er_temp_buffer; + next_blocklist = blocklist + s->mb_stride * s->mb_height; + fixed = (uint8_t *)(next_blocklist + s->mb_stride * s->mb_height); + + set_mv_strides(s, &mot_step, &mot_stride); + + num_avail = 0; + if (s->last_pic.motion_val[0]) + ff_thread_await_progress(s->last_pic.tf, mb_height-1, 0); + for (i = 0; i < mb_width * mb_height; i++) { + const int mb_xy = s->mb_index2xy[i]; + int f = 0; + int error = s->error_status_table[mb_xy]; + + if (IS_INTRA(s->cur_pic.mb_type[mb_xy])) + f = MV_FROZEN; // intra // FIXME check + if (!(error & ER_MV_ERROR)) + f = MV_FROZEN; // inter with undamaged MV + + fixed[mb_xy] = f; + if (f == MV_FROZEN) + num_avail++; + else if(s->last_pic.f->data[0] && s->last_pic.motion_val[0]){ + const int mb_y= mb_xy / s->mb_stride; + const int mb_x= mb_xy % s->mb_stride; + const int mot_index= (mb_x + mb_y*mot_stride) * mot_step; + s->cur_pic.motion_val[0][mot_index][0]= s->last_pic.motion_val[0][mot_index][0]; + s->cur_pic.motion_val[0][mot_index][1]= s->last_pic.motion_val[0][mot_index][1]; + s->cur_pic.ref_index[0][4*mb_xy] = s->last_pic.ref_index[0][4*mb_xy]; + } + } + + if ((!(s->avctx->error_concealment&FF_EC_GUESS_MVS)) || + num_avail <= FFMAX(mb_width, mb_height) / 2) { + for (mb_y = 0; mb_y < mb_height; mb_y++) { + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + const int mb_xy = mb_x + mb_y * s->mb_stride; + int mv_dir = (s->last_pic.f && s->last_pic.f->data[0]) ? MV_DIR_FORWARD : MV_DIR_BACKWARD; + + if (IS_INTRA(s->cur_pic.mb_type[mb_xy])) + continue; + if (!(s->error_status_table[mb_xy] & ER_MV_ERROR)) + continue; + + s->mv[0][0][0] = 0; + s->mv[0][0][1] = 0; + s->decode_mb(s->opaque, 0, mv_dir, MV_TYPE_16X16, &s->mv, + mb_x, mb_y, 0, 0); + } + } + return; + } + + blocklist_length = 0; + for (mb_y = 0; mb_y < mb_height; mb_y++) { + for (mb_x = 0; mb_x < mb_width; mb_x++) { + const int mb_xy = mb_x + mb_y * mb_stride; + if (fixed[mb_xy] == MV_FROZEN) { + if (mb_x) add_blocklist(blocklist, &blocklist_length, fixed, mb_x - 1, mb_y, mb_xy - 1); + if (mb_y) add_blocklist(blocklist, &blocklist_length, fixed, mb_x, mb_y - 1, mb_xy - mb_stride); + if (mb_x+1 < mb_width) add_blocklist(blocklist, &blocklist_length, fixed, mb_x + 1, mb_y, mb_xy + 1); + if (mb_y+1 < mb_height) add_blocklist(blocklist, &blocklist_length, fixed, mb_x, mb_y + 1, mb_xy + mb_stride); + } + } + } + + for (depth = 0; ; depth++) { + int changed, pass, none_left; + int blocklist_index; + + none_left = 1; + changed = 1; + for (pass = 0; (changed || pass < 2) && pass < 10; pass++) { + int score_sum = 0; + + changed = 0; + for (blocklist_index = 0; blocklist_index < blocklist_length; blocklist_index++) { + const int mb_x = blocklist[blocklist_index][0]; + const int mb_y = blocklist[blocklist_index][1]; + const int mb_xy = mb_x + mb_y * mb_stride; + int mv_predictor[8][2]; + int ref[8]; + int pred_count; + int j; + int best_score; + int best_pred; + int mot_index; + int prev_x, prev_y, prev_ref; + + if ((mb_x ^ mb_y ^ pass) & 1) + continue; + av_assert2(fixed[mb_xy] != MV_FROZEN); + + + av_assert1(!IS_INTRA(s->cur_pic.mb_type[mb_xy])); + av_assert1(s->last_pic.f && s->last_pic.f->data[0]); + + j = 0; + if (mb_x > 0) + j |= fixed[mb_xy - 1]; + if (mb_x + 1 < mb_width) + j |= fixed[mb_xy + 1]; + if (mb_y > 0) + j |= fixed[mb_xy - mb_stride]; + if (mb_y + 1 < mb_height) + j |= fixed[mb_xy + mb_stride]; + + av_assert2(j & MV_FROZEN); + + if (!(j & MV_CHANGED) && pass > 1) + continue; + + none_left = 0; + pred_count = 0; + mot_index = (mb_x + mb_y * mot_stride) * mot_step; + + if (mb_x > 0 && fixed[mb_xy - 1] > 1) { + mv_predictor[pred_count][0] = + s->cur_pic.motion_val[0][mot_index - mot_step][0]; + mv_predictor[pred_count][1] = + s->cur_pic.motion_val[0][mot_index - mot_step][1]; + ref[pred_count] = + s->cur_pic.ref_index[0][4 * (mb_xy - 1)]; + pred_count++; + } + if (mb_x + 1 < mb_width && fixed[mb_xy + 1] > 1) { + mv_predictor[pred_count][0] = + s->cur_pic.motion_val[0][mot_index + mot_step][0]; + mv_predictor[pred_count][1] = + s->cur_pic.motion_val[0][mot_index + mot_step][1]; + ref[pred_count] = + s->cur_pic.ref_index[0][4 * (mb_xy + 1)]; + pred_count++; + } + if (mb_y > 0 && fixed[mb_xy - mb_stride] > 1) { + mv_predictor[pred_count][0] = + s->cur_pic.motion_val[0][mot_index - mot_stride * mot_step][0]; + mv_predictor[pred_count][1] = + s->cur_pic.motion_val[0][mot_index - mot_stride * mot_step][1]; + ref[pred_count] = + s->cur_pic.ref_index[0][4 * (mb_xy - s->mb_stride)]; + pred_count++; + } + if (mb_y + 1 1) { + mv_predictor[pred_count][0] = + s->cur_pic.motion_val[0][mot_index + mot_stride * mot_step][0]; + mv_predictor[pred_count][1] = + s->cur_pic.motion_val[0][mot_index + mot_stride * mot_step][1]; + ref[pred_count] = + s->cur_pic.ref_index[0][4 * (mb_xy + s->mb_stride)]; + pred_count++; + } + if (pred_count == 0) + continue; + + if (pred_count > 1) { + int sum_x = 0, sum_y = 0, sum_r = 0; + int max_x, max_y, min_x, min_y, max_r, min_r; + + for (j = 0; j < pred_count; j++) { + sum_x += mv_predictor[j][0]; + sum_y += mv_predictor[j][1]; + sum_r += ref[j]; + if (j && ref[j] != ref[j - 1]) + goto skip_mean_and_median; + } + + /* mean */ + mv_predictor[pred_count][0] = sum_x / j; + mv_predictor[pred_count][1] = sum_y / j; + ref[pred_count] = sum_r / j; + + /* median */ + if (pred_count >= 3) { + min_y = min_x = min_r = 99999; + max_y = max_x = max_r = -99999; + } else { + min_x = min_y = max_x = max_y = min_r = max_r = 0; + } + for (j = 0; j < pred_count; j++) { + max_x = FFMAX(max_x, mv_predictor[j][0]); + max_y = FFMAX(max_y, mv_predictor[j][1]); + max_r = FFMAX(max_r, ref[j]); + min_x = FFMIN(min_x, mv_predictor[j][0]); + min_y = FFMIN(min_y, mv_predictor[j][1]); + min_r = FFMIN(min_r, ref[j]); + } + mv_predictor[pred_count + 1][0] = sum_x - max_x - min_x; + mv_predictor[pred_count + 1][1] = sum_y - max_y - min_y; + ref[pred_count + 1] = sum_r - max_r - min_r; + + if (pred_count == 4) { + mv_predictor[pred_count + 1][0] /= 2; + mv_predictor[pred_count + 1][1] /= 2; + ref[pred_count + 1] /= 2; + } + pred_count += 2; + } + +skip_mean_and_median: + /* zero MV */ + mv_predictor[pred_count][0] = + mv_predictor[pred_count][1] = + ref[pred_count] = 0; + pred_count++; + + prev_x = s->cur_pic.motion_val[0][mot_index][0]; + prev_y = s->cur_pic.motion_val[0][mot_index][1]; + prev_ref = s->cur_pic.ref_index[0][4 * mb_xy]; + + /* last MV */ + mv_predictor[pred_count][0] = prev_x; + mv_predictor[pred_count][1] = prev_y; + ref[pred_count] = prev_ref; + pred_count++; + + best_pred = 0; + best_score = 256 * 256 * 256 * 64; + for (j = 0; j < pred_count; j++) { + int *linesize = s->cur_pic.f->linesize; + int score = 0; + uint8_t *src = s->cur_pic.f->data[0] + + mb_x * 16 + mb_y * 16 * linesize[0]; + + s->cur_pic.motion_val[0][mot_index][0] = + s->mv[0][0][0] = mv_predictor[j][0]; + s->cur_pic.motion_val[0][mot_index][1] = + s->mv[0][0][1] = mv_predictor[j][1]; + + // predictor intra or otherwise not available + if (ref[j] < 0) + continue; + + s->decode_mb(s->opaque, ref[j], MV_DIR_FORWARD, + MV_TYPE_16X16, &s->mv, mb_x, mb_y, 0, 0); + + if (mb_x > 0 && fixed[mb_xy - 1] > 1) { + int k; + for (k = 0; k < 16; k++) + score += FFABS(src[k * linesize[0] - 1] - + src[k * linesize[0]]); + } + if (mb_x + 1 < mb_width && fixed[mb_xy + 1] > 1) { + int k; + for (k = 0; k < 16; k++) + score += FFABS(src[k * linesize[0] + 15] - + src[k * linesize[0] + 16]); + } + if (mb_y > 0 && fixed[mb_xy - mb_stride] > 1) { + int k; + for (k = 0; k < 16; k++) + score += FFABS(src[k - linesize[0]] - src[k]); + } + if (mb_y + 1 < mb_height && fixed[mb_xy + mb_stride] > 1) { + int k; + for (k = 0; k < 16; k++) + score += FFABS(src[k + linesize[0] * 15] - + src[k + linesize[0] * 16]); + } + + if (score <= best_score) { // <= will favor the last MV + best_score = score; + best_pred = j; + } + } + score_sum += best_score; + s->mv[0][0][0] = mv_predictor[best_pred][0]; + s->mv[0][0][1] = mv_predictor[best_pred][1]; + + for (i = 0; i < mot_step; i++) + for (j = 0; j < mot_step; j++) { + s->cur_pic.motion_val[0][mot_index + i + j * mot_stride][0] = s->mv[0][0][0]; + s->cur_pic.motion_val[0][mot_index + i + j * mot_stride][1] = s->mv[0][0][1]; + } + + s->decode_mb(s->opaque, ref[best_pred], MV_DIR_FORWARD, + MV_TYPE_16X16, &s->mv, mb_x, mb_y, 0, 0); + + + if (s->mv[0][0][0] != prev_x || s->mv[0][0][1] != prev_y) { + fixed[mb_xy] = MV_CHANGED; + changed++; + } else + fixed[mb_xy] = MV_UNCHANGED; + } + } + + if (none_left) + return; + + next_blocklist_length = 0; + + for (blocklist_index = 0; blocklist_index < blocklist_length; blocklist_index++) { + const int mb_x = blocklist[blocklist_index][0]; + const int mb_y = blocklist[blocklist_index][1]; + const int mb_xy = mb_x + mb_y * mb_stride; + + if (fixed[mb_xy] & (MV_CHANGED|MV_UNCHANGED|MV_FROZEN)) { + fixed[mb_xy] = MV_FROZEN; + if (mb_x > 0) + add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x - 1, mb_y, mb_xy - 1); + if (mb_y > 0) + add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x, mb_y - 1, mb_xy - mb_stride); + if (mb_x + 1 < mb_width) + add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x + 1, mb_y, mb_xy + 1); + if (mb_y + 1 < mb_height) + add_blocklist(next_blocklist, &next_blocklist_length, fixed, mb_x, mb_y + 1, mb_xy + mb_stride); + } + } + av_assert0(next_blocklist_length <= mb_height * mb_width); + FFSWAP(int , blocklist_length, next_blocklist_length); + FFSWAP(void*, blocklist, next_blocklist); + } +} + +static int is_intra_more_likely(ERContext *s) +{ + int is_intra_likely, i, j, undamaged_count, skip_amount, mb_x, mb_y; + + if (!s->last_pic.f || !s->last_pic.f->data[0]) + return 1; // no previous frame available -> use spatial prediction + + if (s->avctx->error_concealment & FF_EC_FAVOR_INTER) + return 0; + + undamaged_count = 0; + for (i = 0; i < s->mb_num; i++) { + const int mb_xy = s->mb_index2xy[i]; + const int error = s->error_status_table[mb_xy]; + if (!((error & ER_DC_ERROR) && (error & ER_MV_ERROR))) + undamaged_count++; + } + + if (undamaged_count < 5) + return 0; // almost all MBs damaged -> use temporal prediction + + // prevent dsp.sad() check, that requires access to the image + if (CONFIG_XVMC && + s->avctx->hwaccel && s->avctx->hwaccel->decode_mb && + s->cur_pic.f->pict_type == AV_PICTURE_TYPE_I) + return 1; + + skip_amount = FFMAX(undamaged_count / 50, 1); // check only up to 50 MBs + is_intra_likely = 0; + + j = 0; + for (mb_y = 0; mb_y < s->mb_height - 1; mb_y++) { + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + int error; + const int mb_xy = mb_x + mb_y * s->mb_stride; + + error = s->error_status_table[mb_xy]; + if ((error & ER_DC_ERROR) && (error & ER_MV_ERROR)) + continue; // skip damaged + + j++; + // skip a few to speed things up + if ((j % skip_amount) != 0) + continue; + + if (s->cur_pic.f->pict_type == AV_PICTURE_TYPE_I) { + int *linesize = s->cur_pic.f->linesize; + uint8_t *mb_ptr = s->cur_pic.f->data[0] + + mb_x * 16 + mb_y * 16 * linesize[0]; + uint8_t *last_mb_ptr = s->last_pic.f->data[0] + + mb_x * 16 + mb_y * 16 * linesize[0]; + + if (s->avctx->codec_id == AV_CODEC_ID_H264) { + // FIXME + } else { + ff_thread_await_progress(s->last_pic.tf, mb_y, 0); + } + is_intra_likely += s->mecc.sad[0](NULL, last_mb_ptr, mb_ptr, + linesize[0], 16); + // FIXME need await_progress() here + is_intra_likely -= s->mecc.sad[0](NULL, last_mb_ptr, + last_mb_ptr + linesize[0] * 16, + linesize[0], 16); + } else { + if (IS_INTRA(s->cur_pic.mb_type[mb_xy])) + is_intra_likely++; + else + is_intra_likely--; + } + } + } +// av_log(NULL, AV_LOG_ERROR, "is_intra_likely: %d type:%d\n", is_intra_likely, s->pict_type); + return is_intra_likely > 0; +} + +void ff_er_frame_start(ERContext *s) +{ + if (!s->avctx->error_concealment) + return; + + if (!s->mecc_inited) { + ff_me_cmp_init(&s->mecc, s->avctx); + s->mecc_inited = 1; + } + + memset(s->error_status_table, ER_MB_ERROR | VP_START | ER_MB_END, + s->mb_stride * s->mb_height * sizeof(uint8_t)); + atomic_init(&s->error_count, 3 * s->mb_num); + s->error_occurred = 0; +} + +static int er_supported(ERContext *s) +{ + if(s->avctx->hwaccel && s->avctx->hwaccel->decode_slice || + !s->cur_pic.f || + s->cur_pic.field_picture + ) + return 0; + return 1; +} + +/** + * Add a slice. + * @param endx x component of the last macroblock, can be -1 + * for the last of the previous line + * @param status the status at the end (ER_MV_END, ER_AC_ERROR, ...), it is + * assumed that no earlier end or error of the same type occurred + */ +void ff_er_add_slice(ERContext *s, int startx, int starty, + int endx, int endy, int status) +{ + const int start_i = av_clip(startx + starty * s->mb_width, 0, s->mb_num - 1); + const int end_i = av_clip(endx + endy * s->mb_width, 0, s->mb_num); + const int start_xy = s->mb_index2xy[start_i]; + const int end_xy = s->mb_index2xy[end_i]; + int mask = -1; + + if (s->avctx->hwaccel && s->avctx->hwaccel->decode_slice) + return; + + if (start_i > end_i || start_xy > end_xy) { + av_log(s->avctx, AV_LOG_ERROR, + "internal error, slice end before start\n"); + return; + } + + if (!s->avctx->error_concealment) + return; + + mask &= ~VP_START; + if (status & (ER_AC_ERROR | ER_AC_END)) { + mask &= ~(ER_AC_ERROR | ER_AC_END); + atomic_fetch_add(&s->error_count, start_i - end_i - 1); + } + if (status & (ER_DC_ERROR | ER_DC_END)) { + mask &= ~(ER_DC_ERROR | ER_DC_END); + atomic_fetch_add(&s->error_count, start_i - end_i - 1); + } + if (status & (ER_MV_ERROR | ER_MV_END)) { + mask &= ~(ER_MV_ERROR | ER_MV_END); + atomic_fetch_add(&s->error_count, start_i - end_i - 1); + } + + if (status & ER_MB_ERROR) { + s->error_occurred = 1; + atomic_store(&s->error_count, INT_MAX); + } + + if (mask == ~0x7F) { + memset(&s->error_status_table[start_xy], 0, + (end_xy - start_xy) * sizeof(uint8_t)); + } else { + int i; + for (i = start_xy; i < end_xy; i++) + s->error_status_table[i] &= mask; + } + + if (end_i == s->mb_num) + atomic_store(&s->error_count, INT_MAX); + else { + s->error_status_table[end_xy] &= mask; + s->error_status_table[end_xy] |= status; + } + + s->error_status_table[start_xy] |= VP_START; + + if (start_xy > 0 && !(s->avctx->active_thread_type & FF_THREAD_SLICE) && + er_supported(s) && s->avctx->skip_top * s->mb_width < start_i) { + int prev_status = s->error_status_table[s->mb_index2xy[start_i - 1]]; + + prev_status &= ~ VP_START; + if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END)) { + s->error_occurred = 1; + atomic_store(&s->error_count, INT_MAX); + } + } +} + +void ff_er_frame_end(ERContext *s) +{ + int *linesize = NULL; + int i, mb_x, mb_y, error, error_type, dc_error, mv_error, ac_error; + int distance; + int threshold_part[4] = { 100, 100, 100 }; + int threshold = 50; + int is_intra_likely; + int size = s->b8_stride * 2 * s->mb_height; + + /* We do not support ER of field pictures yet, + * though it should not crash if enabled. */ + if (!s->avctx->error_concealment || !atomic_load(&s->error_count) || + s->avctx->lowres || + !er_supported(s) || + atomic_load(&s->error_count) == 3 * s->mb_width * + (s->avctx->skip_top + s->avctx->skip_bottom)) { + return; + } + linesize = s->cur_pic.f->linesize; + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + int status = s->error_status_table[mb_x + (s->mb_height - 1) * s->mb_stride]; + if (status != 0x7F) + break; + } + + if ( mb_x == s->mb_width + && s->avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO + && (FFALIGN(s->avctx->height, 16)&16) + && atomic_load(&s->error_count) == 3 * s->mb_width * (s->avctx->skip_top + s->avctx->skip_bottom + 1) + ) { + av_log(s->avctx, AV_LOG_DEBUG, "ignoring last missing slice\n"); + return; + } + + if (s->last_pic.f) { + if (s->last_pic.f->width != s->cur_pic.f->width || + s->last_pic.f->height != s->cur_pic.f->height || + s->last_pic.f->format != s->cur_pic.f->format) { + av_log(s->avctx, AV_LOG_WARNING, "Cannot use previous picture in error concealment\n"); + memset(&s->last_pic, 0, sizeof(s->last_pic)); + } + } + if (s->next_pic.f) { + if (s->next_pic.f->width != s->cur_pic.f->width || + s->next_pic.f->height != s->cur_pic.f->height || + s->next_pic.f->format != s->cur_pic.f->format) { + av_log(s->avctx, AV_LOG_WARNING, "Cannot use next picture in error concealment\n"); + memset(&s->next_pic, 0, sizeof(s->next_pic)); + } + } + + if (!s->cur_pic.motion_val[0] || !s->cur_pic.ref_index[0]) { + av_log(s->avctx, AV_LOG_ERROR, "Warning MVs not available\n"); + + for (i = 0; i < 2; i++) { + s->ref_index_buf[i] = av_buffer_allocz(s->mb_stride * s->mb_height * 4 * sizeof(uint8_t)); + s->motion_val_buf[i] = av_buffer_allocz((size + 4) * 2 * sizeof(uint16_t)); + if (!s->ref_index_buf[i] || !s->motion_val_buf[i]) + break; + s->cur_pic.ref_index[i] = s->ref_index_buf[i]->data; + s->cur_pic.motion_val[i] = (int16_t (*)[2])s->motion_val_buf[i]->data + 4; + } + if (i < 2) { + for (i = 0; i < 2; i++) { + av_buffer_unref(&s->ref_index_buf[i]); + av_buffer_unref(&s->motion_val_buf[i]); + s->cur_pic.ref_index[i] = NULL; + s->cur_pic.motion_val[i] = NULL; + } + return; + } + } + + if (s->avctx->debug & FF_DEBUG_ER) { + for (mb_y = 0; mb_y < s->mb_height; mb_y++) { + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + int status = s->error_status_table[mb_x + mb_y * s->mb_stride]; + + av_log(s->avctx, AV_LOG_DEBUG, "%2X ", status); + } + av_log(s->avctx, AV_LOG_DEBUG, "\n"); + } + } + +#if 1 + /* handle overlapping slices */ + for (error_type = 1; error_type <= 3; error_type++) { + int end_ok = 0; + + for (i = s->mb_num - 1; i >= 0; i--) { + const int mb_xy = s->mb_index2xy[i]; + int error = s->error_status_table[mb_xy]; + + if (error & (1 << error_type)) + end_ok = 1; + if (error & (8 << error_type)) + end_ok = 1; + + if (!end_ok) + s->error_status_table[mb_xy] |= 1 << error_type; + + if (error & VP_START) + end_ok = 0; + } + } +#endif +#if 1 + /* handle slices with partitions of different length */ + if (s->partitioned_frame) { + int end_ok = 0; + + for (i = s->mb_num - 1; i >= 0; i--) { + const int mb_xy = s->mb_index2xy[i]; + int error = s->error_status_table[mb_xy]; + + if (error & ER_AC_END) + end_ok = 0; + if ((error & ER_MV_END) || + (error & ER_DC_END) || + (error & ER_AC_ERROR)) + end_ok = 1; + + if (!end_ok) + s->error_status_table[mb_xy]|= ER_AC_ERROR; + + if (error & VP_START) + end_ok = 0; + } + } +#endif + /* handle missing slices */ + if (s->avctx->err_recognition & AV_EF_EXPLODE) { + int end_ok = 1; + + // FIXME + 100 hack + for (i = s->mb_num - 2; i >= s->mb_width + 100; i--) { + const int mb_xy = s->mb_index2xy[i]; + int error1 = s->error_status_table[mb_xy]; + int error2 = s->error_status_table[s->mb_index2xy[i + 1]]; + + if (error1 & VP_START) + end_ok = 1; + + if (error2 == (VP_START | ER_MB_ERROR | ER_MB_END) && + error1 != (VP_START | ER_MB_ERROR | ER_MB_END) && + ((error1 & ER_AC_END) || (error1 & ER_DC_END) || + (error1 & ER_MV_END))) { + // end & uninit + end_ok = 0; + } + + if (!end_ok) + s->error_status_table[mb_xy] |= ER_MB_ERROR; + } + } + +#if 1 + /* backward mark errors */ + distance = 9999999; + for (error_type = 1; error_type <= 3; error_type++) { + for (i = s->mb_num - 1; i >= 0; i--) { + const int mb_xy = s->mb_index2xy[i]; + int error = s->error_status_table[mb_xy]; + + if (!s->mbskip_table || !s->mbskip_table[mb_xy]) // FIXME partition specific + distance++; + if (error & (1 << error_type)) + distance = 0; + + if (s->partitioned_frame) { + if (distance < threshold_part[error_type - 1]) + s->error_status_table[mb_xy] |= 1 << error_type; + } else { + if (distance < threshold) + s->error_status_table[mb_xy] |= 1 << error_type; + } + + if (error & VP_START) + distance = 9999999; + } + } +#endif + + /* forward mark errors */ + error = 0; + for (i = 0; i < s->mb_num; i++) { + const int mb_xy = s->mb_index2xy[i]; + int old_error = s->error_status_table[mb_xy]; + + if (old_error & VP_START) { + error = old_error & ER_MB_ERROR; + } else { + error |= old_error & ER_MB_ERROR; + s->error_status_table[mb_xy] |= error; + } + } +#if 1 + /* handle not partitioned case */ + if (!s->partitioned_frame) { + for (i = 0; i < s->mb_num; i++) { + const int mb_xy = s->mb_index2xy[i]; + int error = s->error_status_table[mb_xy]; + if (error & ER_MB_ERROR) + error |= ER_MB_ERROR; + s->error_status_table[mb_xy] = error; + } + } +#endif + + dc_error = ac_error = mv_error = 0; + for (i = 0; i < s->mb_num; i++) { + const int mb_xy = s->mb_index2xy[i]; + int error = s->error_status_table[mb_xy]; + if (error & ER_DC_ERROR) + dc_error++; + if (error & ER_AC_ERROR) + ac_error++; + if (error & ER_MV_ERROR) + mv_error++; + } + av_log(s->avctx, AV_LOG_INFO, "concealing %d DC, %d AC, %d MV errors in %c frame\n", + dc_error, ac_error, mv_error, av_get_picture_type_char(s->cur_pic.f->pict_type)); + + s->cur_pic.f->decode_error_flags |= FF_DECODE_ERROR_CONCEALMENT_ACTIVE; + + is_intra_likely = is_intra_more_likely(s); + + /* set unknown mb-type to most likely */ + for (i = 0; i < s->mb_num; i++) { + const int mb_xy = s->mb_index2xy[i]; + int error = s->error_status_table[mb_xy]; + if (!((error & ER_DC_ERROR) && (error & ER_MV_ERROR))) + continue; + + if (is_intra_likely) + s->cur_pic.mb_type[mb_xy] = MB_TYPE_INTRA4x4; + else + s->cur_pic.mb_type[mb_xy] = MB_TYPE_16x16 | MB_TYPE_L0; + } + + // change inter to intra blocks if no reference frames are available + if (!(s->last_pic.f && s->last_pic.f->data[0]) && + !(s->next_pic.f && s->next_pic.f->data[0])) + for (i = 0; i < s->mb_num; i++) { + const int mb_xy = s->mb_index2xy[i]; + if (!IS_INTRA(s->cur_pic.mb_type[mb_xy])) + s->cur_pic.mb_type[mb_xy] = MB_TYPE_INTRA4x4; + } + + /* handle inter blocks with damaged AC */ + for (mb_y = 0; mb_y < s->mb_height; mb_y++) { + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + const int mb_xy = mb_x + mb_y * s->mb_stride; + const int mb_type = s->cur_pic.mb_type[mb_xy]; + const int dir = !(s->last_pic.f && s->last_pic.f->data[0]); + const int mv_dir = dir ? MV_DIR_BACKWARD : MV_DIR_FORWARD; + int mv_type; + + int error = s->error_status_table[mb_xy]; + + if (IS_INTRA(mb_type)) + continue; // intra + if (error & ER_MV_ERROR) + continue; // inter with damaged MV + if (!(error & ER_AC_ERROR)) + continue; // undamaged inter + + if (IS_8X8(mb_type)) { + int mb_index = mb_x * 2 + mb_y * 2 * s->b8_stride; + int j; + mv_type = MV_TYPE_8X8; + for (j = 0; j < 4; j++) { + s->mv[0][j][0] = s->cur_pic.motion_val[dir][mb_index + (j & 1) + (j >> 1) * s->b8_stride][0]; + s->mv[0][j][1] = s->cur_pic.motion_val[dir][mb_index + (j & 1) + (j >> 1) * s->b8_stride][1]; + } + } else { + mv_type = MV_TYPE_16X16; + s->mv[0][0][0] = s->cur_pic.motion_val[dir][mb_x * 2 + mb_y * 2 * s->b8_stride][0]; + s->mv[0][0][1] = s->cur_pic.motion_val[dir][mb_x * 2 + mb_y * 2 * s->b8_stride][1]; + } + + s->decode_mb(s->opaque, 0 /* FIXME H.264 partitioned slices need this set */, + mv_dir, mv_type, &s->mv, mb_x, mb_y, 0, 0); + } + } + + /* guess MVs */ + if (s->cur_pic.f->pict_type == AV_PICTURE_TYPE_B) { + for (mb_y = 0; mb_y < s->mb_height; mb_y++) { + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + int xy = mb_x * 2 + mb_y * 2 * s->b8_stride; + const int mb_xy = mb_x + mb_y * s->mb_stride; + const int mb_type = s->cur_pic.mb_type[mb_xy]; + int mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD; + + int error = s->error_status_table[mb_xy]; + + if (IS_INTRA(mb_type)) + continue; + if (!(error & ER_MV_ERROR)) + continue; // inter with undamaged MV + if (!(error & ER_AC_ERROR)) + continue; // undamaged inter + + if (!(s->last_pic.f && s->last_pic.f->data[0])) + mv_dir &= ~MV_DIR_FORWARD; + if (!(s->next_pic.f && s->next_pic.f->data[0])) + mv_dir &= ~MV_DIR_BACKWARD; + + if (s->pp_time) { + int time_pp = s->pp_time; + int time_pb = s->pb_time; + + av_assert0(s->avctx->codec_id != AV_CODEC_ID_H264); + ff_thread_await_progress(s->next_pic.tf, mb_y, 0); + + s->mv[0][0][0] = s->next_pic.motion_val[0][xy][0] * time_pb / time_pp; + s->mv[0][0][1] = s->next_pic.motion_val[0][xy][1] * time_pb / time_pp; + s->mv[1][0][0] = s->next_pic.motion_val[0][xy][0] * (time_pb - time_pp) / time_pp; + s->mv[1][0][1] = s->next_pic.motion_val[0][xy][1] * (time_pb - time_pp) / time_pp; + } else { + s->mv[0][0][0] = 0; + s->mv[0][0][1] = 0; + s->mv[1][0][0] = 0; + s->mv[1][0][1] = 0; + } + + s->decode_mb(s->opaque, 0, mv_dir, MV_TYPE_16X16, &s->mv, + mb_x, mb_y, 0, 0); + } + } + } else + guess_mv(s); + + /* the filters below manipulate raw image, skip them */ + if (CONFIG_XVMC && s->avctx->hwaccel && s->avctx->hwaccel->decode_mb) + goto ec_clean; + /* fill DC for inter blocks */ + for (mb_y = 0; mb_y < s->mb_height; mb_y++) { + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + int dc, dcu, dcv, y, n; + int16_t *dc_ptr; + uint8_t *dest_y, *dest_cb, *dest_cr; + const int mb_xy = mb_x + mb_y * s->mb_stride; + const int mb_type = s->cur_pic.mb_type[mb_xy]; + + // error = s->error_status_table[mb_xy]; + + if (IS_INTRA(mb_type) && s->partitioned_frame) + continue; + // if (error & ER_MV_ERROR) + // continue; // inter data damaged FIXME is this good? + + dest_y = s->cur_pic.f->data[0] + mb_x * 16 + mb_y * 16 * linesize[0]; + dest_cb = s->cur_pic.f->data[1] + mb_x * 8 + mb_y * 8 * linesize[1]; + dest_cr = s->cur_pic.f->data[2] + mb_x * 8 + mb_y * 8 * linesize[2]; + + dc_ptr = &s->dc_val[0][mb_x * 2 + mb_y * 2 * s->b8_stride]; + for (n = 0; n < 4; n++) { + dc = 0; + for (y = 0; y < 8; y++) { + int x; + for (x = 0; x < 8; x++) + dc += dest_y[x + (n & 1) * 8 + + (y + (n >> 1) * 8) * linesize[0]]; + } + dc_ptr[(n & 1) + (n >> 1) * s->b8_stride] = (dc + 4) >> 3; + } + + if (!s->cur_pic.f->data[2]) + continue; + + dcu = dcv = 0; + for (y = 0; y < 8; y++) { + int x; + for (x = 0; x < 8; x++) { + dcu += dest_cb[x + y * linesize[1]]; + dcv += dest_cr[x + y * linesize[2]]; + } + } + s->dc_val[1][mb_x + mb_y * s->mb_stride] = (dcu + 4) >> 3; + s->dc_val[2][mb_x + mb_y * s->mb_stride] = (dcv + 4) >> 3; + } + } +#if 1 + /* guess DC for damaged blocks */ + guess_dc(s, s->dc_val[0], s->mb_width*2, s->mb_height*2, s->b8_stride, 1); + guess_dc(s, s->dc_val[1], s->mb_width , s->mb_height , s->mb_stride, 0); + guess_dc(s, s->dc_val[2], s->mb_width , s->mb_height , s->mb_stride, 0); +#endif + + /* filter luma DC */ + filter181(s->dc_val[0], s->mb_width * 2, s->mb_height * 2, s->b8_stride); + +#if 1 + /* render DC only intra */ + for (mb_y = 0; mb_y < s->mb_height; mb_y++) { + for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + uint8_t *dest_y, *dest_cb, *dest_cr; + const int mb_xy = mb_x + mb_y * s->mb_stride; + const int mb_type = s->cur_pic.mb_type[mb_xy]; + + int error = s->error_status_table[mb_xy]; + + if (IS_INTER(mb_type)) + continue; + if (!(error & ER_AC_ERROR)) + continue; // undamaged + + dest_y = s->cur_pic.f->data[0] + mb_x * 16 + mb_y * 16 * linesize[0]; + dest_cb = s->cur_pic.f->data[1] + mb_x * 8 + mb_y * 8 * linesize[1]; + dest_cr = s->cur_pic.f->data[2] + mb_x * 8 + mb_y * 8 * linesize[2]; + if (!s->cur_pic.f->data[2]) + dest_cb = dest_cr = NULL; + + put_dc(s, dest_y, dest_cb, dest_cr, mb_x, mb_y); + } + } +#endif + + if (s->avctx->error_concealment & FF_EC_DEBLOCK) { + /* filter horizontal block boundaries */ + h_block_filter(s, s->cur_pic.f->data[0], s->mb_width * 2, + s->mb_height * 2, linesize[0], 1); + + /* filter vertical block boundaries */ + v_block_filter(s, s->cur_pic.f->data[0], s->mb_width * 2, + s->mb_height * 2, linesize[0], 1); + + if (s->cur_pic.f->data[2]) { + h_block_filter(s, s->cur_pic.f->data[1], s->mb_width, + s->mb_height, linesize[1], 0); + h_block_filter(s, s->cur_pic.f->data[2], s->mb_width, + s->mb_height, linesize[2], 0); + v_block_filter(s, s->cur_pic.f->data[1], s->mb_width, + s->mb_height, linesize[1], 0); + v_block_filter(s, s->cur_pic.f->data[2], s->mb_width, + s->mb_height, linesize[2], 0); + } + } + +ec_clean: + /* clean a few tables */ + for (i = 0; i < s->mb_num; i++) { + const int mb_xy = s->mb_index2xy[i]; + int error = s->error_status_table[mb_xy]; + + if (s->mbskip_table && s->cur_pic.f->pict_type != AV_PICTURE_TYPE_B && + (error & (ER_DC_ERROR | ER_MV_ERROR | ER_AC_ERROR))) { + s->mbskip_table[mb_xy] = 0; + } + if (s->mbintra_table) + s->mbintra_table[mb_xy] = 1; + } + + for (i = 0; i < 2; i++) { + av_buffer_unref(&s->ref_index_buf[i]); + av_buffer_unref(&s->motion_val_buf[i]); + s->cur_pic.ref_index[i] = NULL; + s->cur_pic.motion_val[i] = NULL; + } + + memset(&s->cur_pic, 0, sizeof(ERPicture)); + memset(&s->last_pic, 0, sizeof(ERPicture)); + memset(&s->next_pic, 0, sizeof(ERPicture)); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/error_resilience.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/error_resilience.h new file mode 100644 index 0000000000..664a765659 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/error_resilience.h @@ -0,0 +1,97 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_ERROR_RESILIENCE_H +#define AVCODEC_ERROR_RESILIENCE_H + +#include +#include + +#include "avcodec.h" +#include "me_cmp.h" +#include "thread.h" + +///< current MB is the first after a resync marker +#define VP_START 1 +#define ER_AC_ERROR 2 +#define ER_DC_ERROR 4 +#define ER_MV_ERROR 8 +#define ER_AC_END 16 +#define ER_DC_END 32 +#define ER_MV_END 64 + +#define ER_MB_ERROR (ER_AC_ERROR|ER_DC_ERROR|ER_MV_ERROR) +#define ER_MB_END (ER_AC_END|ER_DC_END|ER_MV_END) + +typedef struct ERPicture { + AVFrame *f; + ThreadFrame *tf; + + // it is the caller's responsibility to allocate these buffers + int16_t (*motion_val[2])[2]; + int8_t *ref_index[2]; + + uint32_t *mb_type; + int field_picture; +} ERPicture; + +typedef struct ERContext { + AVCodecContext *avctx; + MECmpContext mecc; + int mecc_inited; + + int *mb_index2xy; + int mb_num; + int mb_width, mb_height; + ptrdiff_t mb_stride; + ptrdiff_t b8_stride; + + atomic_int error_count; + int error_occurred; + uint8_t *error_status_table; + uint8_t *er_temp_buffer; + int16_t *dc_val[3]; + uint8_t *mbskip_table; + uint8_t *mbintra_table; + int mv[2][4][2]; + + ERPicture cur_pic; + ERPicture last_pic; + ERPicture next_pic; + + AVBufferRef *ref_index_buf[2]; + AVBufferRef *motion_val_buf[2]; + + uint16_t pp_time; + uint16_t pb_time; + int quarter_sample; + int partitioned_frame; + int ref_count; + + void (*decode_mb)(void *opaque, int ref, int mv_dir, int mv_type, + int (*mv)[2][4][2], + int mb_x, int mb_y, int mb_intra, int mb_skipped); + void *opaque; +} ERContext; + +void ff_er_frame_start(ERContext *s); +void ff_er_frame_end(ERContext *s); +void ff_er_add_slice(ERContext *s, int startx, int starty, int endx, int endy, + int status); + +#endif /* AVCODEC_ERROR_RESILIENCE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fdctdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fdctdsp.h new file mode 100644 index 0000000000..3e1f683b9e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fdctdsp.h @@ -0,0 +1,37 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_FDCTDSP_H +#define AVCODEC_FDCTDSP_H + +#include + +#include "avcodec.h" + +typedef struct FDCTDSPContext { + void (*fdct)(int16_t *block /* align 16 */); + void (*fdct248)(int16_t *block /* align 16 */); +} FDCTDSPContext; + +void ff_fdctdsp_init(FDCTDSPContext *c, AVCodecContext *avctx); +void ff_fdctdsp_init_ppc(FDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); +void ff_fdctdsp_init_x86(FDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); + +#endif /* AVCODEC_FDCTDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft-internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft-internal.h new file mode 100644 index 0000000000..0a8f7d05cf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft-internal.h @@ -0,0 +1,94 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_FFT_INTERNAL_H +#define AVCODEC_FFT_INTERNAL_H + +#if FFT_FLOAT + +#define FIX15(v) (v) +#define sqrthalf (float)M_SQRT1_2 + +#define BF(x, y, a, b) do { \ + x = a - b; \ + y = a + b; \ + } while (0) + +#define CMUL(dre, dim, are, aim, bre, bim) do { \ + (dre) = (are) * (bre) - (aim) * (bim); \ + (dim) = (are) * (bim) + (aim) * (bre); \ + } while (0) + +#else + +#define SCALE_FLOAT(a, bits) lrint((a) * (double)(1 << (bits))) + +#if FFT_FIXED_32 + +#define CMUL(dre, dim, are, aim, bre, bim) do { \ + int64_t accu; \ + (accu) = (int64_t)(bre) * (are); \ + (accu) -= (int64_t)(bim) * (aim); \ + (dre) = (int)(((accu) + 0x40000000) >> 31); \ + (accu) = (int64_t)(bre) * (aim); \ + (accu) += (int64_t)(bim) * (are); \ + (dim) = (int)(((accu) + 0x40000000) >> 31); \ + } while (0) + +#define FIX15(a) av_clip(SCALE_FLOAT(a, 31), -2147483647, 2147483647) + +#else /* FFT_FIXED_32 */ + +#include "fft.h" +#include "mathops.h" + +void ff_mdct_calcw_c(FFTContext *s, FFTDouble *output, const FFTSample *input); + +#define FIX15(a) av_clip(SCALE_FLOAT(a, 15), -32767, 32767) + +#define sqrthalf ((int16_t)((1<<15)*M_SQRT1_2)) + +#define BF(x, y, a, b) do { \ + x = (a - b) >> 1; \ + y = (a + b) >> 1; \ + } while (0) + +#define CMULS(dre, dim, are, aim, bre, bim, sh) do { \ + (dre) = (MUL16(are, bre) - MUL16(aim, bim)) >> sh; \ + (dim) = (MUL16(are, bim) + MUL16(aim, bre)) >> sh; \ + } while (0) + +#define CMUL(dre, dim, are, aim, bre, bim) \ + CMULS(dre, dim, are, aim, bre, bim, 15) + +#define CMULL(dre, dim, are, aim, bre, bim) \ + CMULS(dre, dim, are, aim, bre, bim, 0) + +#endif /* FFT_FIXED_32 */ + +#endif /* FFT_FLOAT */ + +#define ff_imdct_calc_c FFT_NAME(ff_imdct_calc_c) +#define ff_imdct_half_c FFT_NAME(ff_imdct_half_c) +#define ff_mdct_calc_c FFT_NAME(ff_mdct_calc_c) + +void ff_imdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_mdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input); + +#endif /* AVCODEC_FFT_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft.h new file mode 100644 index 0000000000..c858570a21 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_FFT_H +#define AVCODEC_FFT_H + +#ifndef FFT_FLOAT +#define FFT_FLOAT 1 +#endif + +#ifndef FFT_FIXED_32 +#define FFT_FIXED_32 0 +#endif + +#include +#include "config.h" +#include "libavutil/mem.h" + +#if FFT_FLOAT + +#include "avfft.h" + +#define FFT_NAME(x) x + +typedef float FFTDouble; + +#else + +#if FFT_FIXED_32 + +#define Q31(x) (int)((x)*2147483648.0 + 0.5) +#define FFT_NAME(x) x ## _fixed_32 + +typedef int32_t FFTSample; + +#else /* FFT_FIXED_32 */ + +#define FFT_NAME(x) x ## _fixed + +typedef int16_t FFTSample; + +#endif /* FFT_FIXED_32 */ + +typedef struct FFTComplex { + FFTSample re, im; +} FFTComplex; + +typedef int FFTDouble; +typedef struct FFTContext FFTContext; + +#endif /* FFT_FLOAT */ + +typedef struct FFTDComplex { + FFTDouble re, im; +} FFTDComplex; + +/* FFT computation */ + +enum fft_permutation_type { + FF_FFT_PERM_DEFAULT, + FF_FFT_PERM_SWAP_LSBS, + FF_FFT_PERM_AVX, +}; + +enum mdct_permutation_type { + FF_MDCT_PERM_NONE, + FF_MDCT_PERM_INTERLEAVE, +}; + +struct FFTContext { + int nbits; + int inverse; + uint16_t *revtab; + FFTComplex *tmp_buf; + int mdct_size; /* size of MDCT (i.e. number of input data * 2) */ + int mdct_bits; /* n = 2^nbits */ + /* pre/post rotation tables */ + FFTSample *tcos; + FFTSample *tsin; + /** + * Do the permutation needed BEFORE calling fft_calc(). + */ + void (*fft_permute)(struct FFTContext *s, FFTComplex *z); + /** + * Do a complex FFT with the parameters defined in ff_fft_init(). The + * input data must be permuted before. No 1.0/sqrt(n) normalization is done. + */ + void (*fft_calc)(struct FFTContext *s, FFTComplex *z); + void (*imdct_calc)(struct FFTContext *s, FFTSample *output, const FFTSample *input); + void (*imdct_half)(struct FFTContext *s, FFTSample *output, const FFTSample *input); + void (*mdct_calc)(struct FFTContext *s, FFTSample *output, const FFTSample *input); + void (*mdct_calcw)(struct FFTContext *s, FFTDouble *output, const FFTSample *input); + enum fft_permutation_type fft_permutation; + enum mdct_permutation_type mdct_permutation; + uint32_t *revtab32; +}; + +#if CONFIG_HARDCODED_TABLES +#define COSTABLE_CONST const +#else +#define COSTABLE_CONST +#endif + +#define COSTABLE(size) \ + COSTABLE_CONST DECLARE_ALIGNED(32, FFTSample, FFT_NAME(ff_cos_##size))[size/2] + +extern COSTABLE(16); +extern COSTABLE(32); +extern COSTABLE(64); +extern COSTABLE(128); +extern COSTABLE(256); +extern COSTABLE(512); +extern COSTABLE(1024); +extern COSTABLE(2048); +extern COSTABLE(4096); +extern COSTABLE(8192); +extern COSTABLE(16384); +extern COSTABLE(32768); +extern COSTABLE(65536); +extern COSTABLE(131072); +extern COSTABLE_CONST FFTSample* const FFT_NAME(ff_cos_tabs)[18]; + +#define ff_init_ff_cos_tabs FFT_NAME(ff_init_ff_cos_tabs) + +/** + * Initialize the cosine table in ff_cos_tabs[index] + * @param index index in ff_cos_tabs array of the table to initialize + */ +void ff_init_ff_cos_tabs(int index); + +#define ff_fft_init FFT_NAME(ff_fft_init) +#define ff_fft_end FFT_NAME(ff_fft_end) + +/** + * Set up a complex FFT. + * @param nbits log2 of the length of the input array + * @param inverse if 0 perform the forward transform, if 1 perform the inverse + */ +int ff_fft_init(FFTContext *s, int nbits, int inverse); + +void ff_fft_init_aarch64(FFTContext *s); +void ff_fft_init_x86(FFTContext *s); +void ff_fft_init_arm(FFTContext *s); +void ff_fft_init_mips(FFTContext *s); +void ff_fft_init_ppc(FFTContext *s); + +void ff_fft_fixed_init_arm(FFTContext *s); + +void ff_fft_end(FFTContext *s); + +#define ff_mdct_init FFT_NAME(ff_mdct_init) +#define ff_mdct_end FFT_NAME(ff_mdct_end) + +int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale); +void ff_mdct_end(FFTContext *s); + +#endif /* AVCODEC_FFT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_fixed.c new file mode 100644 index 0000000000..3d3bd2fca6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_fixed.c @@ -0,0 +1,21 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FFT_FLOAT 0 +#define FFT_FIXED_32 0 +#include "fft_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_fixed_32.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_fixed_32.c new file mode 100644 index 0000000000..fbdbf847e2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_fixed_32.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Authors: Stanislav Ocovaj (socovaj@mips.com) + * Goran Cordasic (goran@mips.com) + * Djordje Pesut (djordje@mips.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FFT_FLOAT 0 +#define FFT_FIXED_32 1 +#include "fft_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_float.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_float.c new file mode 100644 index 0000000000..73cc98d0d4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_float.c @@ -0,0 +1,21 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FFT_FLOAT 1 +#define FFT_FIXED_32 0 +#include "fft_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_init.c new file mode 100644 index 0000000000..928f1dcda7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_init.c @@ -0,0 +1,61 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" + +#include "fft.h" + +av_cold void ff_fft_init_x86(FFTContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (s->nbits > 16) + return; + +#if ARCH_X86_32 + if (EXTERNAL_AMD3DNOW(cpu_flags)) { + s->imdct_calc = ff_imdct_calc_3dnow; + s->imdct_half = ff_imdct_half_3dnow; + s->fft_calc = ff_fft_calc_3dnow; + } + + if (EXTERNAL_AMD3DNOWEXT(cpu_flags)) { + s->imdct_calc = ff_imdct_calc_3dnowext; + s->imdct_half = ff_imdct_half_3dnowext; + s->fft_calc = ff_fft_calc_3dnowext; + } +#endif /* ARCH_X86_32 */ + + if (EXTERNAL_SSE(cpu_flags)) { + s->imdct_calc = ff_imdct_calc_sse; + s->imdct_half = ff_imdct_half_sse; + s->fft_permute = ff_fft_permute_sse; + s->fft_calc = ff_fft_calc_sse; + s->fft_permutation = FF_FFT_PERM_SWAP_LSBS; + } + + if (EXTERNAL_AVX_FAST(cpu_flags) && s->nbits >= 5) { + s->imdct_half = ff_imdct_half_avx; + s->fft_calc = ff_fft_calc_avx; + s->fft_permutation = FF_FFT_PERM_AVX; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_init_table.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_init_table.c new file mode 100644 index 0000000000..c488018f62 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_init_table.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2012 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Authors: Stanislav Ocovaj (socovaj@mips.com) + * Goran Cordasic (goran@mips.com) + * Djordje Pesut (djordje@mips.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * definitions and initialization of LUT table for FFT + */ +#include "libavcodec/fft_table.h" + +const int32_t ff_w_tab_sr[MAX_FFT_SIZE/(4*16)] = { +2147483647, 2147483016, 2147481121, 2147477963, 2147473542, 2147467857, 2147460908, 2147452697, +2147443222, 2147432484, 2147420483, 2147407218, 2147392690, 2147376899, 2147359845, 2147341527, +2147321946, 2147301102, 2147278995, 2147255625, 2147230991, 2147205094, 2147177934, 2147149511, +2147119825, 2147088876, 2147056664, 2147023188, 2146988450, 2146952448, 2146915184, 2146876656, +2146836866, 2146795813, 2146753497, 2146709917, 2146665076, 2146618971, 2146571603, 2146522973, +2146473080, 2146421924, 2146369505, 2146315824, 2146260881, 2146204674, 2146147205, 2146088474, +2146028480, 2145967224, 2145904705, 2145840924, 2145775880, 2145709574, 2145642006, 2145573176, +2145503083, 2145431729, 2145359112, 2145285233, 2145210092, 2145133690, 2145056025, 2144977098, +2144896910, 2144815460, 2144732748, 2144648774, 2144563539, 2144477042, 2144389283, 2144300264, +2144209982, 2144118439, 2144025635, 2143931570, 2143836244, 2143739656, 2143641807, 2143542697, +2143442326, 2143340694, 2143237802, 2143133648, 2143028234, 2142921559, 2142813624, 2142704427, +2142593971, 2142482254, 2142369276, 2142255039, 2142139541, 2142022783, 2141904764, 2141785486, +2141664948, 2141543150, 2141420092, 2141295774, 2141170197, 2141043360, 2140915264, 2140785908, +2140655293, 2140523418, 2140390284, 2140255892, 2140120240, 2139983329, 2139845159, 2139705730, +2139565043, 2139423097, 2139279892, 2139135429, 2138989708, 2138842728, 2138694490, 2138544994, +2138394240, 2138242228, 2138088958, 2137934430, 2137778644, 2137621601, 2137463301, 2137303743, +2137142927, 2136980855, 2136817525, 2136652938, 2136487095, 2136319994, 2136151637, 2135982023, +2135811153, 2135639026, 2135465642, 2135291003, 2135115107, 2134937956, 2134759548, 2134579885, +2134398966, 2134216791, 2134033361, 2133848675, 2133662734, 2133475538, 2133287087, 2133097381, +2132906420, 2132714204, 2132520734, 2132326009, 2132130030, 2131932796, 2131734309, 2131534567, +2131333572, 2131131322, 2130927819, 2130723062, 2130517052, 2130309789, 2130101272, 2129891502, +2129680480, 2129468204, 2129254676, 2129039895, 2128823862, 2128606576, 2128388038, 2128168248, +2127947206, 2127724913, 2127501367, 2127276570, 2127050522, 2126823222, 2126594672, 2126364870, +2126133817, 2125901514, 2125667960, 2125433155, 2125197100, 2124959795, 2124721240, 2124481435, +2124240380, 2123998076, 2123754522, 2123509718, 2123263666, 2123016364, 2122767814, 2122518015, +2122266967, 2122014670, 2121761126, 2121506333, 2121250292, 2120993003, 2120734467, 2120474683, +2120213651, 2119951372, 2119687847, 2119423074, 2119157054, 2118889788, 2118621275, 2118351516, +2118080511, 2117808259, 2117534762, 2117260020, 2116984031, 2116706797, 2116428319, 2116148595, +2115867626, 2115585412, 2115301954, 2115017252, 2114731305, 2114444114, 2114155680, 2113866001, +2113575080, 2113282914, 2112989506, 2112694855, 2112398960, 2112101824, 2111803444, 2111503822, +2111202959, 2110900853, 2110597505, 2110292916, 2109987085, 2109680013, 2109371700, 2109062146, +2108751352, 2108439317, 2108126041, 2107811526, 2107495770, 2107178775, 2106860540, 2106541065, +2106220352, 2105898399, 2105575208, 2105250778, 2104925109, 2104598202, 2104270057, 2103940674, +2103610054, 2103278196, 2102945101, 2102610768, 2102275199, 2101938393, 2101600350, 2101261071, +2100920556, 2100578805, 2100235819, 2099891596, 2099546139, 2099199446, 2098851519, 2098502357, +2098151960, 2097800329, 2097447464, 2097093365, 2096738032, 2096381466, 2096023667, 2095664635, +2095304370, 2094942872, 2094580142, 2094216179, 2093850985, 2093484559, 2093116901, 2092748012, +2092377892, 2092006541, 2091633960, 2091260147, 2090885105, 2090508833, 2090131331, 2089752599, +2089372638, 2088991448, 2088609029, 2088225381, 2087840505, 2087454400, 2087067068, 2086678508, +2086288720, 2085897705, 2085505463, 2085111994, 2084717298, 2084321376, 2083924228, 2083525854, +2083126254, 2082725429, 2082323379, 2081920103, 2081515603, 2081109879, 2080702930, 2080294757, +2079885360, 2079474740, 2079062896, 2078649830, 2078235540, 2077820028, 2077403294, 2076985338, +2076566160, 2076145760, 2075724139, 2075301296, 2074877233, 2074451950, 2074025446, 2073597721, +2073168777, 2072738614, 2072307231, 2071874629, 2071440808, 2071005769, 2070569511, 2070132035, +2069693342, 2069253430, 2068812302, 2068369957, 2067926394, 2067481616, 2067035621, 2066588410, +2066139983, 2065690341, 2065239484, 2064787411, 2064334124, 2063879623, 2063423908, 2062966978, +2062508835, 2062049479, 2061588910, 2061127128, 2060664133, 2060199927, 2059734508, 2059267877, +2058800036, 2058330983, 2057860719, 2057389244, 2056916560, 2056442665, 2055967560, 2055491246, +2055013723, 2054534991, 2054055050, 2053573901, 2053091544, 2052607979, 2052123207, 2051637227, +2051150040, 2050661647, 2050172048, 2049681242, 2049189231, 2048696014, 2048201592, 2047705965, +2047209133, 2046711097, 2046211857, 2045711414, 2045209767, 2044706916, 2044202863, 2043697608, +2043191150, 2042683490, 2042174628, 2041664565, 2041153301, 2040640837, 2040127172, 2039612306, +2039096241, 2038578976, 2038060512, 2037540850, 2037019988, 2036497928, 2035974670, 2035450215, +2034924562, 2034397712, 2033869665, 2033340422, 2032809982, 2032278347, 2031745516, 2031211490, +2030676269, 2030139853, 2029602243, 2029063439, 2028523442, 2027982251, 2027439867, 2026896291, +2026351522, 2025805561, 2025258408, 2024710064, 2024160529, 2023609803, 2023057887, 2022504780, +2021950484, 2021394998, 2020838323, 2020280460, 2019721407, 2019161167, 2018599739, 2018037123, +2017473321, 2016908331, 2016342155, 2015774793, 2015206245, 2014636511, 2014065592, 2013493489, +2012920201, 2012345729, 2011770073, 2011193233, 2010615210, 2010036005, 2009455617, 2008874047, +2008291295, 2007707362, 2007122248, 2006535953, 2005948478, 2005359822, 2004769987, 2004178973, +2003586779, 2002993407, 2002398857, 2001803128, 2001206222, 2000608139, 2000008879, 1999408442, +1998806829, 1998204040, 1997600076, 1996994937, 1996388622, 1995781134, 1995172471, 1994562635, +1993951625, 1993339442, 1992726087, 1992111559, 1991495860, 1990878989, 1990260946, 1989641733, +1989021350, 1988399796, 1987777073, 1987153180, 1986528118, 1985901888, 1985274489, 1984645923, +1984016189, 1983385288, 1982753220, 1982119985, 1981485585, 1980850019, 1980213288, 1979575392, +1978936331, 1978296106, 1977654717, 1977012165, 1976368450, 1975723572, 1975077532, 1974430331, +1973781967, 1973132443, 1972481757, 1971829912, 1971176906, 1970522741, 1969867417, 1969210933, +1968553292, 1967894492, 1967234535, 1966573420, 1965911148, 1965247720, 1964583136, 1963917396, +1963250501, 1962582451, 1961913246, 1961242888, 1960571375, 1959898709, 1959224890, 1958549919, +1957873796, 1957196520, 1956518093, 1955838516, 1955157788, 1954475909, 1953792881, 1953108703, +1952423377, 1951736902, 1951049279, 1950360508, 1949670589, 1948979524, 1948287312, 1947593954, +1946899451, 1946203802, 1945507008, 1944809070, 1944109987, 1943409761, 1942708392, 1942005880, +1941302225, 1940597428, 1939891490, 1939184411, 1938476190, 1937766830, 1937056329, 1936344689, +1935631910, 1934917992, 1934202936, 1933486742, 1932769411, 1932050943, 1931331338, 1930610597, +1929888720, 1929165708, 1928441561, 1927716279, 1926989864, 1926262315, 1925533633, 1924803818, +1924072871, 1923340791, 1922607581, 1921873239, 1921137767, 1920401165, 1919663432, 1918924571, +1918184581, 1917443462, 1916701216, 1915957841, 1915213340, 1914467712, 1913720958, 1912973078, +1912224073, 1911473942, 1910722688, 1909970309, 1909216806, 1908462181, 1907706433, 1906949562, +1906191570, 1905432457, 1904672222, 1903910867, 1903148392, 1902384797, 1901620084, 1900854251, +1900087301, 1899319232, 1898550047, 1897779744, 1897008325, 1896235790, 1895462140, 1894687374, +1893911494, 1893134500, 1892356392, 1891577171, 1890796837, 1890015391, 1889232832, 1888449163, +1887664383, 1886878492, 1886091491, 1885303381, 1884514161, 1883723833, 1882932397, 1882139853, +1881346202, 1880551444, 1879755580, 1878958610, 1878160535, 1877361354, 1876561070, 1875759681, +1874957189, 1874153594, 1873348897, 1872543097, 1871736196, 1870928194, 1870119091, 1869308888, +1868497586, 1867685184, 1866871683, 1866057085, 1865241388, 1864424594, 1863606704, 1862787717, +1861967634, 1861146456, 1860324183, 1859500816, 1858676355, 1857850800, 1857024153, 1856196413, +1855367581, 1854537657, 1853706643, 1852874538, 1852041343, 1851207059, 1850371686, 1849535224, +1848697674, 1847859036, 1847019312, 1846178501, 1845336604, 1844493621, 1843649553, 1842804401, +1841958164, 1841110844, 1840262441, 1839412956, 1838562388, 1837710739, 1836858008, 1836004197, +1835149306, 1834293336, 1833436286, 1832578158, 1831718951, 1830858668, 1829997307, 1829134869, +1828271356, 1827406767, 1826541103, 1825674364, 1824806552, 1823937666, 1823067707, 1822196675, +1821324572, 1820451397, 1819577151, 1818701835, 1817825449, 1816947994, 1816069469, 1815189877, +1814309216, 1813427489, 1812544694, 1811660833, 1810775906, 1809889915, 1809002858, 1808114737, +1807225553, 1806335305, 1805443995, 1804551623, 1803658189, 1802763694, 1801868139, 1800971523, +1800073849, 1799175115, 1798275323, 1797374472, 1796472565, 1795569601, 1794665580, 1793760504, +1792854372, 1791947186, 1791038946, 1790129652, 1789219305, 1788307905, 1787395453, 1786481950, +1785567396, 1784651792, 1783735137, 1782817434, 1781898681, 1780978881, 1780058032, 1779136137, +1778213194, 1777289206, 1776364172, 1775438094, 1774510970, 1773582803, 1772653593, 1771723340, +1770792044, 1769859707, 1768926328, 1767991909, 1767056450, 1766119952, 1765182414, 1764243838, +1763304224, 1762363573, 1761421885, 1760479161, 1759535401, 1758590607, 1757644777, 1756697914, +1755750017, 1754801087, 1753851126, 1752900132, 1751948107, 1750995052, 1750040966, 1749085851, +1748129707, 1747172535, 1746214334, 1745255107, 1744294853, 1743333573, 1742371267, 1741407936, +1740443581, 1739478202, 1738511799, 1737544374, 1736575927, 1735606458, 1734635968, 1733664458, +1732691928, 1731718378, 1730743810, 1729768224, 1728791620, 1727813999, 1726835361, 1725855708, +1724875040, 1723893357, 1722910659, 1721926948, 1720942225, 1719956488, 1718969740, 1717981981, +1716993211, 1716003431, 1715012642, 1714020844, 1713028037, 1712034223, 1711039401, 1710043573, +1709046739, 1708048900, 1707050055, 1706050207, 1705049355, 1704047500, 1703044642, 1702040783, +1701035922, 1700030061, 1699023199, 1698015339, 1697006479, 1695996621, 1694985765, 1693973912, +1692961062, 1691947217, 1690932376, 1689916541, 1688899711, 1687881888, 1686863072, 1685843263, +1684822463, 1683800672, 1682777890, 1681754118, 1680729357, 1679703608, 1678676870, 1677649144, +1676620432, 1675590733, 1674560049, 1673528379, 1672495725, 1671462087, 1670427466, 1669391862, +1668355276, 1667317709, 1666279161, 1665239632, 1664199124, 1663157637, 1662115172, 1661071729, +1660027308, 1658981911, 1657935539, 1656888190, 1655839867, 1654790570, 1653740300, 1652689057, +1651636841, 1650583654, 1649529496, 1648474367, 1647418269, 1646361202, 1645303166, 1644244162, +1643184191, 1642123253, 1641061349, 1639998480, 1638934646, 1637869848, 1636804087, 1635737362, +1634669676, 1633601027, 1632531418, 1631460848, 1630389319, 1629316830, 1628243383, 1627168978, +1626093616, 1625017297, 1623940023, 1622861793, 1621782608, 1620702469, 1619621377, 1618539332, +1617456335, 1616372386, 1615287487, 1614201637, 1613114838, 1612027089, 1610938393, 1609848749, +1608758157, 1607666620, 1606574136, 1605480708, 1604386335, 1603291018, 1602194758, 1601097555, +1599999411, 1598900325, 1597800299, 1596699333, 1595597428, 1594494583, 1593390801, 1592286082, +1591180426, 1590073833, 1588966306, 1587857843, 1586748447, 1585638117, 1584526854, 1583414660, +1582301533, 1581187476, 1580072489, 1578956572, 1577839726, 1576721952, 1575603251, 1574483623, +1573363068, 1572241588, 1571119183, 1569995854, 1568871601, 1567746425, 1566620327, 1565493307, +1564365367, 1563236506, 1562106725, 1560976026, 1559844408, 1558711873, 1557578421, 1556444052, +1555308768, 1554172569, 1553035455, 1551897428, 1550758488, 1549618636, 1548477872, 1547336197, +1546193612, 1545050118, 1543905714, 1542760402, 1541614183, 1540467057, 1539319024, 1538170087, +1537020244, 1535869497, 1534717846, 1533565293, 1532411837, 1531257480, 1530102222, 1528946064, +1527789007, 1526631051, 1525472197, 1524312445, 1523151797, 1521990252, 1520827813, 1519664478, +1518500250, 1517335128, 1516169114, 1515002208, 1513834411, 1512665723, 1511496145, 1510325678, +1509154322, 1507982079, 1506808949, 1505634932, 1504460029, 1503284242, 1502107570, 1500930014, +1499751576, 1498572255, 1497392053, 1496210969, 1495029006, 1493846163, 1492662441, 1491477842, +1490292364, 1489106011, 1487918781, 1486730675, 1485541696, 1484351842, 1483161115, 1481969516, +1480777044, 1479583702, 1478389489, 1477194407, 1475998456, 1474801636, 1473603949, 1472405394, +1471205974, 1470005688, 1468804538, 1467602523, 1466399645, 1465195904, 1463991302, 1462785838, +1461579514, 1460372329, 1459164286, 1457955385, 1456745625, 1455535009, 1454323536, 1453111208, +1451898025, 1450683988, 1449469098, 1448253355, 1447036760, 1445819314, 1444601017, 1443381870, +1442161874, 1440941030, 1439719338, 1438496799, 1437273414, 1436049184, 1434824109, 1433598189, +1432371426, 1431143821, 1429915374, 1428686085, 1427455956, 1426224988, 1424993180, 1423760534, +1422527051, 1421292730, 1420057574, 1418821582, 1417584755, 1416347095, 1415108601, 1413869275, +1412629117, 1411388129, 1410146309, 1408903661, 1407660183, 1406415878, 1405170745, 1403924785, +1402678000, 1401430389, 1400181954, 1398932695, 1397682613, 1396431709, 1395179984, 1393927438, +1392674072, 1391419886, 1390164882, 1388909060, 1387652422, 1386394966, 1385136696, 1383877610, +1382617710, 1381356997, 1380095472, 1378833134, 1377569986, 1376306026, 1375041258, 1373775680, +1372509294, 1371242101, 1369974101, 1368705296, 1367435685, 1366165269, 1364894050, 1363622028, +1362349204, 1361075579, 1359801152, 1358525926, 1357249901, 1355973077, 1354695455, 1353417037, +1352137822, 1350857812, 1349577007, 1348295409, 1347013017, 1345729833, 1344445857, 1343161090, +1341875533, 1340589187, 1339302052, 1338014129, 1336725419, 1335435923, 1334145641, 1332854574, +1331562723, 1330270089, 1328976672, 1327682474, 1326387494, 1325091734, 1323795195, 1322497877, +1321199781, 1319900907, 1318601257, 1317300832, 1315999631, 1314697657, 1313394909, 1312091388, +1310787095, 1309482032, 1308176198, 1306869594, 1305562222, 1304254082, 1302945174, 1301635500, +1300325060, 1299013855, 1297701886, 1296389154, 1295075659, 1293761402, 1292446384, 1291130606, +1289814068, 1288496772, 1287178717, 1285859905, 1284540337, 1283220013, 1281898935, 1280577102, +1279254516, 1277931177, 1276607086, 1275282245, 1273956653, 1272630312, 1271303222, 1269975384, +1268646800, 1267317469, 1265987392, 1264656571, 1263325005, 1261992697, 1260659646, 1259325853, +1257991320, 1256656047, 1255320034, 1253983283, 1252645794, 1251307568, 1249968606, 1248628909, +1247288478, 1245947312, 1244605414, 1243262783, 1241919421, 1240575329, 1239230506, 1237884955, +1236538675, 1235191668, 1233843935, 1232495475, 1231146291, 1229796382, 1228445750, 1227094395, +1225742318, 1224389521, 1223036002, 1221681765, 1220326809, 1218971135, 1217614743, 1216257636, +1214899813, 1213541275, 1212182024, 1210822059, 1209461382, 1208099993, 1206737894, 1205375085, +1204011567, 1202647340, 1201282407, 1199916766, 1198550419, 1197183368, 1195815612, 1194447153, +1193077991, 1191708127, 1190337562, 1188966297, 1187594332, 1186221669, 1184848308, 1183474250, +1182099496, 1180724046, 1179347902, 1177971064, 1176593533, 1175215310, 1173836395, 1172456790, +1171076495, 1169695512, 1168313840, 1166931481, 1165548435, 1164164704, 1162780288, 1161395188, +1160009405, 1158622939, 1157235792, 1155847964, 1154459456, 1153070269, 1151680403, 1150289860, +1148898640, 1147506745, 1146114174, 1144720929, 1143327011, 1141932420, 1140537158, 1139141224, +1137744621, 1136347348, 1134949406, 1133550797, 1132151521, 1130751579, 1129350972, 1127949701, +1126547765, 1125145168, 1123741908, 1122337987, 1120933406, 1119528166, 1118122267, 1116715710, +1115308496, 1113900627, 1112492101, 1111082922, 1109673089, 1108262603, 1106851465, 1105439676, +1104027237, 1102614148, 1101200410, 1099786025, 1098370993, 1096955314, 1095538991, 1094122023, +1092704411, 1091286156, 1089867259, 1088447722, 1087027544, 1085606726, 1084185270, 1082763176, +1081340445, 1079917078, 1078493076, 1077068439, 1075643169, 1074217266, 1072790730, 1071363564, +1069935768, 1068507342, 1067078288, 1065648605, 1064218296, 1062787361, 1061355801, 1059923616, +1058490808, 1057057377, 1055623324, 1054188651, 1052753357, 1051317443, 1049880912, 1048443763, +1047005996, 1045567615, 1044128617, 1042689006, 1041248781, 1039807944, 1038366495, 1036924436, +1035481766, 1034038487, 1032594600, 1031150105, 1029705004, 1028259297, 1026812985, 1025366069, +1023918550, 1022470428, 1021021705, 1019572382, 1018122458, 1016671936, 1015220816, 1013769098, +1012316784, 1010863875, 1009410370, 1007956272, 1006501581, 1005046298, 1003590424, 1002133959, +1000676905, 999219262, 997761031, 996302214, 994842810, 993382821, 991922248, 990461091, +988999351, 987537030, 986074127, 984610645, 983146583, 981681943, 980216726, 978750932, +977284562, 975817617, 974350098, 972882006, 971413342, 969944106, 968474300, 967003923, +965532978, 964061465, 962589385, 961116739, 959643527, 958169751, 956695411, 955220508, +953745043, 952269017, 950792431, 949315286, 947837582, 946359321, 944880503, 943401129, +941921200, 940440717, 938959681, 937478092, 935995952, 934513261, 933030021, 931546231, +930061894, 928577010, 927091579, 925605603, 924119082, 922632018, 921144411, 919656262, +918167572, 916678342, 915188572, 913698265, 912207419, 910716038, 909224120, 907731667, +906238681, 904745161, 903251110, 901756526, 900261413, 898765769, 897269597, 895772898, +894275671, 892777918, 891279640, 889780838, 888281512, 886781663, 885281293, 883780402, +882278992, 880777062, 879274614, 877771649, 876268167, 874764170, 873259659, 871754633, +870249095, 868743045, 867236484, 865729413, 864221832, 862713743, 861205147, 859696043, +858186435, 856676321, 855165703, 853654582, 852142959, 850630835, 849118210, 847605086, +846091463, 844577343, 843062726, 841547612, 840032004, 838515901, 836999305, 835482217, +833964638, 832446567, 830928007, 829408958, 827889422, 826369398, 824848888, 823327893, +821806413, 820284450, 818762005, 817239078, 815715670, 814191782, 812667415, 811142571, +809617249, 808091450, 806565177, 805038429, 803511207, 801983513, 800455346, 798926709, +797397602, 795868026, 794337982, 792807470, 791276492, 789745049, 788213141, 786680769, +785147934, 783614638, 782080880, 780546663, 779011986, 777476851, 775941259, 774405210, +772868706, 771331747, 769794334, 768256469, 766718151, 765179382, 763640164, 762100496, +760560380, 759019816, 757478806, 755937350, 754395449, 752853105, 751310318, 749767089, +748223418, 746679308, 745134758, 743589770, 742044345, 740498483, 738952186, 737405453, +735858287, 734310688, 732762657, 731214195, 729665303, 728115982, 726566232, 725016055, +723465451, 721914422, 720362968, 718811090, 717258790, 715706067, 714152924, 712599360, +711045377, 709490976, 707936158, 706380923, 704825272, 703269207, 701712728, 700155836, +698598533, 697040818, 695482694, 693924160, 692365218, 690805869, 689246113, 687685952, +686125387, 684564417, 683003045, 681441272, 679879097, 678316522, 676753549, 675190177, +673626408, 672062243, 670497682, 668932727, 667367379, 665801638, 664235505, 662668981, +661102068, 659534766, 657967075, 656398998, 654830535, 653261686, 651692453, 650122837, +648552838, 646982457, 645411696, 643840556, 642269036, 640697139, 639124865, 637552215, +635979190, 634405791, 632832018, 631257873, 629683357, 628108471, 626533215, 624957590, +623381598, 621805239, 620228514, 618651424, 617073971, 615496154, 613917975, 612339436, +610760536, 609181276, 607601658, 606021683, 604441352, 602860664, 601279623, 599698227, +598116479, 596534378, 594951927, 593369126, 591785976, 590202477, 588618632, 587034440, +585449903, 583865021, 582279796, 580694229, 579108320, 577522070, 575935480, 574348552, +572761285, 571173682, 569585743, 567997469, 566408860, 564819919, 563230645, 561641039, +560051104, 558460839, 556870245, 555279324, 553688076, 552096502, 550504604, 548912382, +547319836, 545726969, 544133781, 542540273, 540946445, 539352300, 537757837, 536163058, +534567963, 532972554, 531376831, 529780796, 528184449, 526587791, 524990824, 523393547, +521795963, 520198072, 518599875, 517001373, 515402566, 513803457, 512204045, 510604332, +509004318, 507404005, 505803394, 504202485, 502601279, 500999778, 499397982, 497795892, +496193509, 494590835, 492987869, 491384614, 489781069, 488177236, 486573117, 484968710, +483364019, 481759043, 480153784, 478548243, 476942419, 475336316, 473729932, 472123270, +470516330, 468909114, 467301622, 465693854, 464085813, 462477499, 460868912, 459260055, +457650927, 456041530, 454431865, 452821933, 451211734, 449601270, 447990541, 446379549, +444768294, 443156777, 441545000, 439932963, 438320667, 436708113, 435095303, 433482236, +431868915, 430255339, 428641511, 427027430, 425413098, 423798515, 422183684, 420568604, +418953276, 417337703, 415721883, 414105819, 412489512, 410872962, 409256170, 407639137, +406021865, 404404353, 402786604, 401168618, 399550396, 397931939, 396313247, 394694323, +393075166, 391455778, 389836160, 388216313, 386596237, 384975934, 383355404, 381734649, +380113669, 378492466, 376871039, 375249392, 373627523, 372005435, 370383128, 368760603, +367137861, 365514903, 363891730, 362268343, 360644742, 359020930, 357396906, 355772673, +354148230, 352523578, 350898719, 349273654, 347648383, 346022908, 344397230, 342771348, +341145265, 339518981, 337892498, 336265816, 334638936, 333011859, 331384586, 329757119, +328129457, 326501602, 324873555, 323245317, 321616889, 319988272, 318359466, 316730474, +315101295, 313471930, 311842381, 310212649, 308582734, 306952638, 305322361, 303691904, +302061269, 300430456, 298799466, 297168301, 295536961, 293905447, 292273760, 290641901, +289009871, 287377671, 285745302, 284112765, 282480061, 280847190, 279214155, 277580955, +275947592, 274314066, 272680379, 271046532, 269412525, 267778360, 266144038, 264509558, +262874923, 261240134, 259605191, 257970095, 256334847, 254699448, 253063900, 251428203, +249792358, 248156366, 246520228, 244883945, 243247518, 241610947, 239974235, 238337382, +236700388, 235063255, 233425984, 231788575, 230151030, 228513350, 226875535, 225237587, +223599506, 221961294, 220322951, 218684479, 217045878, 215407149, 213768293, 212129312, +210490206, 208850976, 207211624, 205572149, 203932553, 202292838, 200653003, 199013051, +197372981, 195732795, 194092495, 192452080, 190811551, 189170911, 187530159, 185889297, +184248325, 182607245, 180966058, 179324764, 177683365, 176041861, 174400254, 172758544, +171116733, 169474820, 167832808, 166190698, 164548489, 162906184, 161263783, 159621287, +157978697, 156336015, 154693240, 153050374, 151407418, 149764374, 148121241, 146478021, +144834714, 143191323, 141547847, 139904288, 138260647, 136616925, 134973122, 133329239, +131685278, 130041240, 128397125, 126752935, 125108670, 123464332, 121819921, 120175438, +118530885, 116886262, 115241570, 113596810, 111951983, 110307091, 108662134, 107017112, +105372028, 103726882, 102081675, 100436408, 98791081, 97145697, 95500255, 93854758, + 92209205, 90563597, 88917937, 87272224, 85626460, 83980645, 82334782, 80688869, + 79042909, 77396903, 75750851, 74104755, 72458615, 70812432, 69166208, 67519943, + 65873638, 64227295, 62580914, 60934496, 59288042, 57641553, 55995030, 54348475, + 52701887, 51055268, 49408620, 47761942, 46115236, 44468503, 42821744, 41174960, + 39528151, 37881320, 36234466, 34587590, 32940695, 31293780, 29646846, 27999895, + 26352928, 24705945, 23058947, 21411936, 19764913, 18117878, 16470832, 14823776, + 13176712, 11529640, 9882561, 8235476, 6588387, 4941294, 3294197, 1647099 +}; + +uint16_t ff_fft_offsets_lut[21845]; + +void ff_fft_lut_init(uint16_t *table, int off, int size, int *index) +{ + if (size < 16) { + table[*index] = off >> 2; + (*index)++; + } + else { + ff_fft_lut_init(table, off, size>>1, index); + ff_fft_lut_init(table, off+(size>>1), size>>2, index); + ff_fft_lut_init(table, off+3*(size>>2), size>>2, index); + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_table.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_table.h new file mode 100644 index 0000000000..ed0a6588b4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_table.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Authors: Stanislav Ocovaj (socovaj@mips.com) + * Goran Cordasic (goran@mips.com) + * Djordje Pesut (djordje@mips.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * definitions and tables for FFT + */ +#ifndef AVCODEC_FFT_TABLE_H +#define AVCODEC_FFT_TABLE_H + +#include "libavcodec/fft.h" + +#define MAX_LOG2_NFFT 17 //!< Specifies maximum allowed fft size +#define MAX_FFT_SIZE (1 << MAX_LOG2_NFFT) + +extern const int32_t ff_w_tab_sr[]; +extern uint16_t ff_fft_offsets_lut[]; +void ff_fft_lut_init(uint16_t *table, int off, int size, int *index); + +#endif /* AVCODEC_FFT_TABLE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_template.c new file mode 100644 index 0000000000..20a62e4290 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/fft_template.c @@ -0,0 +1,639 @@ +/* + * FFT/IFFT transforms + * Copyright (c) 2008 Loren Merritt + * Copyright (c) 2002 Fabrice Bellard + * Partly based on libdjbfft by D. J. Bernstein + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * FFT/IFFT transforms. + */ + +#include +#include +#include "libavutil/mathematics.h" +#include "libavutil/thread.h" +#include "fft.h" +#include "fft-internal.h" + +#if FFT_FIXED_32 +#include "fft_table.h" + +static void av_cold fft_lut_init(void) +{ + int n = 0; + ff_fft_lut_init(ff_fft_offsets_lut, 0, 1 << 17, &n); +} + +#else /* FFT_FIXED_32 */ + +/* cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse */ +#if !CONFIG_HARDCODED_TABLES +COSTABLE(16); +COSTABLE(32); +COSTABLE(64); +COSTABLE(128); +COSTABLE(256); +COSTABLE(512); +COSTABLE(1024); +COSTABLE(2048); +COSTABLE(4096); +COSTABLE(8192); +COSTABLE(16384); +COSTABLE(32768); +COSTABLE(65536); +COSTABLE(131072); + +static av_cold void init_ff_cos_tabs(int index) +{ + int i; + int m = 1<> 1; + if(!(i&m)) return split_radix_permutation(i, m, inverse)*2; + m >>= 1; + if(inverse == !(i&m)) return split_radix_permutation(i, m, inverse)*4 + 1; + else return split_radix_permutation(i, m, inverse)*4 - 1; +} + +av_cold void ff_init_ff_cos_tabs(int index) +{ +#if (!CONFIG_HARDCODED_TABLES) && (!FFT_FIXED_32) + ff_thread_once(&cos_tabs_init_once[index].control, cos_tabs_init_once[index].func); +#endif +} + +static const int avx_tab[] = { + 0, 4, 1, 5, 8, 12, 9, 13, 2, 6, 3, 7, 10, 14, 11, 15 +}; + +static int is_second_half_of_fft32(int i, int n) +{ + if (n <= 32) + return i >= 16; + else if (i < n/2) + return is_second_half_of_fft32(i, n/2); + else if (i < 3*n/4) + return is_second_half_of_fft32(i - n/2, n/4); + else + return is_second_half_of_fft32(i - 3*n/4, n/4); +} + +static av_cold void fft_perm_avx(FFTContext *s) +{ + int i; + int n = 1 << s->nbits; + + for (i = 0; i < n; i += 16) { + int k; + if (is_second_half_of_fft32(i, n)) { + for (k = 0; k < 16; k++) + s->revtab[-split_radix_permutation(i + k, n, s->inverse) & (n - 1)] = + i + avx_tab[k]; + + } else { + for (k = 0; k < 16; k++) { + int j = i + k; + j = (j & ~7) | ((j >> 1) & 3) | ((j << 2) & 4); + s->revtab[-split_radix_permutation(i + k, n, s->inverse) & (n - 1)] = j; + } + } + } +} + +av_cold int ff_fft_init(FFTContext *s, int nbits, int inverse) +{ + int i, j, n; + + s->revtab = NULL; + s->revtab32 = NULL; + + if (nbits < 2 || nbits > 17) + goto fail; + s->nbits = nbits; + n = 1 << nbits; + + if (nbits <= 16) { + s->revtab = av_malloc(n * sizeof(uint16_t)); + if (!s->revtab) + goto fail; + } else { + s->revtab32 = av_malloc(n * sizeof(uint32_t)); + if (!s->revtab32) + goto fail; + } + s->tmp_buf = av_malloc(n * sizeof(FFTComplex)); + if (!s->tmp_buf) + goto fail; + s->inverse = inverse; + s->fft_permutation = FF_FFT_PERM_DEFAULT; + + s->fft_permute = fft_permute_c; + s->fft_calc = fft_calc_c; +#if CONFIG_MDCT + s->imdct_calc = ff_imdct_calc_c; + s->imdct_half = ff_imdct_half_c; + s->mdct_calc = ff_mdct_calc_c; +#endif + +#if FFT_FIXED_32 + { + static AVOnce control = AV_ONCE_INIT; + ff_thread_once(&control, fft_lut_init); + } +#else /* FFT_FIXED_32 */ +#if FFT_FLOAT + if (ARCH_AARCH64) ff_fft_init_aarch64(s); + if (ARCH_ARM) ff_fft_init_arm(s); + if (ARCH_PPC) ff_fft_init_ppc(s); + if (ARCH_X86) ff_fft_init_x86(s); + if (CONFIG_MDCT) s->mdct_calcw = s->mdct_calc; + if (HAVE_MIPSFPU) ff_fft_init_mips(s); +#else + if (CONFIG_MDCT) s->mdct_calcw = ff_mdct_calcw_c; + if (ARCH_ARM) ff_fft_fixed_init_arm(s); +#endif + for(j=4; j<=nbits; j++) { + ff_init_ff_cos_tabs(j); + } +#endif /* FFT_FIXED_32 */ + + + if (s->fft_permutation == FF_FFT_PERM_AVX) { + fft_perm_avx(s); + } else { +#define PROCESS_FFT_PERM_SWAP_LSBS(num) do {\ + for(i = 0; i < n; i++) {\ + int k;\ + j = i;\ + j = (j & ~3) | ((j >> 1) & 1) | ((j << 1) & 2);\ + k = -split_radix_permutation(i, n, s->inverse) & (n - 1);\ + s->revtab##num[k] = j;\ + } \ +} while(0); + +#define PROCESS_FFT_PERM_DEFAULT(num) do {\ + for(i = 0; i < n; i++) {\ + int k;\ + j = i;\ + k = -split_radix_permutation(i, n, s->inverse) & (n - 1);\ + s->revtab##num[k] = j;\ + } \ +} while(0); + +#define SPLIT_RADIX_PERMUTATION(num) do { \ + if (s->fft_permutation == FF_FFT_PERM_SWAP_LSBS) {\ + PROCESS_FFT_PERM_SWAP_LSBS(num) \ + } else {\ + PROCESS_FFT_PERM_DEFAULT(num) \ + }\ +} while(0); + + if (s->revtab) + SPLIT_RADIX_PERMUTATION() + if (s->revtab32) + SPLIT_RADIX_PERMUTATION(32) + +#undef PROCESS_FFT_PERM_DEFAULT +#undef PROCESS_FFT_PERM_SWAP_LSBS +#undef SPLIT_RADIX_PERMUTATION + } + + return 0; + fail: + av_freep(&s->revtab); + av_freep(&s->revtab32); + av_freep(&s->tmp_buf); + return -1; +} + +static void fft_permute_c(FFTContext *s, FFTComplex *z) +{ + int j, np; + const uint16_t *revtab = s->revtab; + const uint32_t *revtab32 = s->revtab32; + np = 1 << s->nbits; + /* TODO: handle split-radix permute in a more optimal way, probably in-place */ + if (revtab) { + for(j=0;jtmp_buf[revtab[j]] = z[j]; + } else + for(j=0;jtmp_buf[revtab32[j]] = z[j]; + + memcpy(z, s->tmp_buf, np * sizeof(FFTComplex)); +} + +av_cold void ff_fft_end(FFTContext *s) +{ + av_freep(&s->revtab); + av_freep(&s->revtab32); + av_freep(&s->tmp_buf); +} + +#if FFT_FIXED_32 + +static void fft_calc_c(FFTContext *s, FFTComplex *z) { + + int nbits, i, n, num_transforms, offset, step; + int n4, n2, n34; + unsigned tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; + FFTComplex *tmpz; + const int fft_size = (1 << s->nbits); + int64_t accu; + + num_transforms = (0x2aab >> (16 - s->nbits)) | 1; + + for (n=0; n> 1) | 1; + + for (n=0; n> 31); + accu = (int64_t)Q31(M_SQRT1_2)*(int)(tmp3 - tmp4); + tmp7 = (int32_t)((accu + 0x40000000) >> 31); + accu = (int64_t)Q31(M_SQRT1_2)*(int)(tmp2 - tmp1); + tmp6 = (int32_t)((accu + 0x40000000) >> 31); + accu = (int64_t)Q31(M_SQRT1_2)*(int)(tmp3 + tmp4); + tmp8 = (int32_t)((accu + 0x40000000) >> 31); + tmp1 = tmp5 + tmp7; + tmp3 = tmp5 - tmp7; + tmp2 = tmp6 + tmp8; + tmp4 = tmp6 - tmp8; + + tmpz[5].re = tmpz[1].re - tmp1; + tmpz[1].re = tmpz[1].re + tmp1; + tmpz[5].im = tmpz[1].im - tmp2; + tmpz[1].im = tmpz[1].im + tmp2; + tmpz[7].re = tmpz[3].re - tmp4; + tmpz[3].re = tmpz[3].re + tmp4; + tmpz[7].im = tmpz[3].im + tmp3; + tmpz[3].im = tmpz[3].im - tmp3; + } + + step = 1 << ((MAX_LOG2_NFFT-4) - 4); + n4 = 4; + + for (nbits=4; nbits<=s->nbits; nbits++){ + n2 = 2*n4; + n34 = 3*n4; + num_transforms = (num_transforms >> 1) | 1; + + for (n=0; n> 31); + accu = (int64_t)w_re*tmpz[ n2+i].im; + accu -= (int64_t)w_im*tmpz[ n2+i].re; + tmp2 = (int32_t)((accu + 0x40000000) >> 31); + accu = (int64_t)w_re*tmpz[n34+i].re; + accu -= (int64_t)w_im*tmpz[n34+i].im; + tmp3 = (int32_t)((accu + 0x40000000) >> 31); + accu = (int64_t)w_re*tmpz[n34+i].im; + accu += (int64_t)w_im*tmpz[n34+i].re; + tmp4 = (int32_t)((accu + 0x40000000) >> 31); + + tmp5 = tmp1 + tmp3; + tmp1 = tmp1 - tmp3; + tmp6 = tmp2 + tmp4; + tmp2 = tmp2 - tmp4; + + tmpz[ n2+i].re = tmpz[ i].re - tmp5; + tmpz[ i].re = tmpz[ i].re + tmp5; + tmpz[ n2+i].im = tmpz[ i].im - tmp6; + tmpz[ i].im = tmpz[ i].im + tmp6; + tmpz[n34+i].re = tmpz[n4+i].re - tmp2; + tmpz[ n4+i].re = tmpz[n4+i].re + tmp2; + tmpz[n34+i].im = tmpz[n4+i].im + tmp1; + tmpz[ n4+i].im = tmpz[n4+i].im - tmp1; + + w_re_ptr += step; + w_im_ptr -= step; + } + } + step >>= 1; + n4 <<= 1; + } +} + +#else /* FFT_FIXED_32 */ + +#define BUTTERFLIES(a0,a1,a2,a3) {\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, a0.re, t5);\ + BF(a3.im, a1.im, a1.im, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, a1.re, t4);\ + BF(a2.im, a0.im, a0.im, t6);\ +} + +// force loading all the inputs before storing any. +// this is slightly slower for small data, but avoids store->load aliasing +// for addresses separated by large powers of 2. +#define BUTTERFLIES_BIG(a0,a1,a2,a3) {\ + FFTSample r0=a0.re, i0=a0.im, r1=a1.re, i1=a1.im;\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, r0, t5);\ + BF(a3.im, a1.im, i1, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, r1, t4);\ + BF(a2.im, a0.im, i0, t6);\ +} + +#define TRANSFORM(a0,a1,a2,a3,wre,wim) {\ + CMUL(t1, t2, a2.re, a2.im, wre, -wim);\ + CMUL(t5, t6, a3.re, a3.im, wre, wim);\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +#define TRANSFORM_ZERO(a0,a1,a2,a3) {\ + t1 = a2.re;\ + t2 = a2.im;\ + t5 = a3.re;\ + t6 = a3.im;\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +/* z[0...8n-1], w[1...2n-1] */ +#define PASS(name)\ +static void name(FFTComplex *z, const FFTSample *wre, unsigned int n)\ +{\ + FFTDouble t1, t2, t3, t4, t5, t6;\ + int o1 = 2*n;\ + int o2 = 4*n;\ + int o3 = 6*n;\ + const FFTSample *wim = wre+o1;\ + n--;\ +\ + TRANSFORM_ZERO(z[0],z[o1],z[o2],z[o3]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + do {\ + z += 2;\ + wre += 2;\ + wim -= 2;\ + TRANSFORM(z[0],z[o1],z[o2],z[o3],wre[0],wim[0]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + } while(--n);\ +} + +PASS(pass) +#if !CONFIG_SMALL +#undef BUTTERFLIES +#define BUTTERFLIES BUTTERFLIES_BIG +PASS(pass_big) +#endif + +#define DECL_FFT(n,n2,n4)\ +static void fft##n(FFTComplex *z)\ +{\ + fft##n2(z);\ + fft##n4(z+n4*2);\ + fft##n4(z+n4*3);\ + pass(z,FFT_NAME(ff_cos_##n),n4/2);\ +} + +static void fft4(FFTComplex *z) +{ + FFTDouble t1, t2, t3, t4, t5, t6, t7, t8; + + BF(t3, t1, z[0].re, z[1].re); + BF(t8, t6, z[3].re, z[2].re); + BF(z[2].re, z[0].re, t1, t6); + BF(t4, t2, z[0].im, z[1].im); + BF(t7, t5, z[2].im, z[3].im); + BF(z[3].im, z[1].im, t4, t8); + BF(z[3].re, z[1].re, t3, t7); + BF(z[2].im, z[0].im, t2, t5); +} + +static void fft8(FFTComplex *z) +{ + FFTDouble t1, t2, t3, t4, t5, t6; + + fft4(z); + + BF(t1, z[5].re, z[4].re, -z[5].re); + BF(t2, z[5].im, z[4].im, -z[5].im); + BF(t5, z[7].re, z[6].re, -z[7].re); + BF(t6, z[7].im, z[6].im, -z[7].im); + + BUTTERFLIES(z[0],z[2],z[4],z[6]); + TRANSFORM(z[1],z[3],z[5],z[7],sqrthalf,sqrthalf); +} + +#if !CONFIG_SMALL +static void fft16(FFTComplex *z) +{ + FFTDouble t1, t2, t3, t4, t5, t6; + FFTSample cos_16_1 = FFT_NAME(ff_cos_16)[1]; + FFTSample cos_16_3 = FFT_NAME(ff_cos_16)[3]; + + fft8(z); + fft4(z+8); + fft4(z+12); + + TRANSFORM_ZERO(z[0],z[4],z[8],z[12]); + TRANSFORM(z[2],z[6],z[10],z[14],sqrthalf,sqrthalf); + TRANSFORM(z[1],z[5],z[9],z[13],cos_16_1,cos_16_3); + TRANSFORM(z[3],z[7],z[11],z[15],cos_16_3,cos_16_1); +} +#else +DECL_FFT(16,8,4) +#endif +DECL_FFT(32,16,8) +DECL_FFT(64,32,16) +DECL_FFT(128,64,32) +DECL_FFT(256,128,64) +DECL_FFT(512,256,128) +#if !CONFIG_SMALL +#define pass pass_big +#endif +DECL_FFT(1024,512,256) +DECL_FFT(2048,1024,512) +DECL_FFT(4096,2048,1024) +DECL_FFT(8192,4096,2048) +DECL_FFT(16384,8192,4096) +DECL_FFT(32768,16384,8192) +DECL_FFT(65536,32768,16384) +DECL_FFT(131072,65536,32768) + +static void (* const fft_dispatch[])(FFTComplex*) = { + fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024, + fft2048, fft4096, fft8192, fft16384, fft32768, fft65536, fft131072 +}; + +static void fft_calc_c(FFTContext *s, FFTComplex *z) +{ + fft_dispatch[s->nbits-2](z); +} +#endif /* FFT_FIXED_32 */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/frame_thread_encoder.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/frame_thread_encoder.c new file mode 100644 index 0000000000..55756c4c54 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/frame_thread_encoder.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "frame_thread_encoder.h" + +#include "libavutil/fifo.h" +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/thread.h" +#include "avcodec.h" +#include "internal.h" +#include "thread.h" + +#define MAX_THREADS 64 +#define BUFFER_SIZE (2*MAX_THREADS) + +typedef struct{ + void *indata; + void *outdata; + int64_t return_code; + unsigned index; +} Task; + +typedef struct{ + AVCodecContext *parent_avctx; + pthread_mutex_t buffer_mutex; + + AVFifoBuffer *task_fifo; + pthread_mutex_t task_fifo_mutex; + pthread_cond_t task_fifo_cond; + + Task finished_tasks[BUFFER_SIZE]; + pthread_mutex_t finished_task_mutex; + pthread_cond_t finished_task_cond; + + unsigned task_index; + unsigned finished_task_index; + + pthread_t worker[MAX_THREADS]; + atomic_int exit; +} ThreadContext; + +static void * attribute_align_arg worker(void *v){ + AVCodecContext *avctx = v; + ThreadContext *c = avctx->internal->frame_thread_encoder; + AVPacket *pkt = NULL; + + while (!atomic_load(&c->exit)) { + int got_packet, ret; + AVFrame *frame; + Task task; + + if(!pkt) pkt = av_packet_alloc(); + if(!pkt) continue; + av_init_packet(pkt); + + pthread_mutex_lock(&c->task_fifo_mutex); + while (av_fifo_size(c->task_fifo) <= 0 || atomic_load(&c->exit)) { + if (atomic_load(&c->exit)) { + pthread_mutex_unlock(&c->task_fifo_mutex); + goto end; + } + pthread_cond_wait(&c->task_fifo_cond, &c->task_fifo_mutex); + } + av_fifo_generic_read(c->task_fifo, &task, sizeof(task), NULL); + pthread_mutex_unlock(&c->task_fifo_mutex); + frame = task.indata; + + ret = avcodec_encode_video2(avctx, pkt, frame, &got_packet); + pthread_mutex_lock(&c->buffer_mutex); + av_frame_unref(frame); + pthread_mutex_unlock(&c->buffer_mutex); + av_frame_free(&frame); + if(got_packet) { + int ret2 = av_packet_make_refcounted(pkt); + if (ret >= 0 && ret2 < 0) + ret = ret2; + } else { + pkt->data = NULL; + pkt->size = 0; + } + pthread_mutex_lock(&c->finished_task_mutex); + c->finished_tasks[task.index].outdata = pkt; pkt = NULL; + c->finished_tasks[task.index].return_code = ret; + pthread_cond_signal(&c->finished_task_cond); + pthread_mutex_unlock(&c->finished_task_mutex); + } +end: + av_free(pkt); + pthread_mutex_lock(&c->buffer_mutex); + avcodec_close(avctx); + pthread_mutex_unlock(&c->buffer_mutex); + av_freep(&avctx); + return NULL; +} + +int ff_frame_thread_encoder_init(AVCodecContext *avctx, AVDictionary *options){ + int i=0; + ThreadContext *c; + + + if( !(avctx->thread_type & FF_THREAD_FRAME) + || !(avctx->codec->capabilities & AV_CODEC_CAP_INTRA_ONLY)) + return 0; + + if( !avctx->thread_count + && avctx->codec_id == AV_CODEC_ID_MJPEG + && !(avctx->flags & AV_CODEC_FLAG_QSCALE)) { + av_log(avctx, AV_LOG_DEBUG, + "Forcing thread count to 1 for MJPEG encoding, use -thread_type slice " + "or a constant quantizer if you want to use multiple cpu cores\n"); + avctx->thread_count = 1; + } + if( avctx->thread_count > 1 + && avctx->codec_id == AV_CODEC_ID_MJPEG + && !(avctx->flags & AV_CODEC_FLAG_QSCALE)) + av_log(avctx, AV_LOG_WARNING, + "MJPEG CBR encoding works badly with frame multi-threading, consider " + "using -threads 1, -thread_type slice or a constant quantizer.\n"); + + if (avctx->codec_id == AV_CODEC_ID_HUFFYUV || + avctx->codec_id == AV_CODEC_ID_FFVHUFF) { + int warn = 0; + int context_model = 0; + AVDictionaryEntry *con = av_dict_get(options, "context", NULL, AV_DICT_MATCH_CASE); + + if (con && con->value) + context_model = atoi(con->value); + + if (avctx->flags & AV_CODEC_FLAG_PASS1) + warn = 1; + else if(context_model > 0) { + AVDictionaryEntry *t = av_dict_get(options, "non_deterministic", + NULL, AV_DICT_MATCH_CASE); + warn = !t || !t->value || !atoi(t->value) ? 1 : 0; + } + // huffyuv does not support these with multiple frame threads currently + if (warn) { + av_log(avctx, AV_LOG_WARNING, + "Forcing thread count to 1 for huffyuv encoding with first pass or context 1\n"); + avctx->thread_count = 1; + } + } + + if(!avctx->thread_count) { + avctx->thread_count = av_cpu_count(); + avctx->thread_count = FFMIN(avctx->thread_count, MAX_THREADS); + } + + if(avctx->thread_count <= 1) + return 0; + + if(avctx->thread_count > MAX_THREADS) + return AVERROR(EINVAL); + + av_assert0(!avctx->internal->frame_thread_encoder); + c = avctx->internal->frame_thread_encoder = av_mallocz(sizeof(ThreadContext)); + if(!c) + return AVERROR(ENOMEM); + + c->parent_avctx = avctx; + + c->task_fifo = av_fifo_alloc_array(BUFFER_SIZE, sizeof(Task)); + if(!c->task_fifo) + goto fail; + + pthread_mutex_init(&c->task_fifo_mutex, NULL); + pthread_mutex_init(&c->finished_task_mutex, NULL); + pthread_mutex_init(&c->buffer_mutex, NULL); + pthread_cond_init(&c->task_fifo_cond, NULL); + pthread_cond_init(&c->finished_task_cond, NULL); + atomic_init(&c->exit, 0); + + for(i=0; ithread_count ; i++){ + AVDictionary *tmp = NULL; + int ret; + void *tmpv; + AVCodecContext *thread_avctx = avcodec_alloc_context3(avctx->codec); + if(!thread_avctx) + goto fail; + tmpv = thread_avctx->priv_data; + *thread_avctx = *avctx; + ret = av_opt_copy(thread_avctx, avctx); + if (ret < 0) + goto fail; + thread_avctx->priv_data = tmpv; + thread_avctx->internal = NULL; + if (avctx->codec->priv_class) { + int ret = av_opt_copy(thread_avctx->priv_data, avctx->priv_data); + if (ret < 0) + goto fail; + } else + memcpy(thread_avctx->priv_data, avctx->priv_data, avctx->codec->priv_data_size); + thread_avctx->thread_count = 1; + thread_avctx->active_thread_type &= ~FF_THREAD_FRAME; + + av_dict_copy(&tmp, options, 0); + av_dict_set(&tmp, "threads", "1", 0); + if(avcodec_open2(thread_avctx, avctx->codec, &tmp) < 0) { + av_dict_free(&tmp); + goto fail; + } + av_dict_free(&tmp); + av_assert0(!thread_avctx->internal->frame_thread_encoder); + thread_avctx->internal->frame_thread_encoder = c; + if(pthread_create(&c->worker[i], NULL, worker, thread_avctx)) { + goto fail; + } + } + + avctx->active_thread_type = FF_THREAD_FRAME; + + return 0; +fail: + avctx->thread_count = i; + av_log(avctx, AV_LOG_ERROR, "ff_frame_thread_encoder_init failed\n"); + ff_frame_thread_encoder_free(avctx); + return -1; +} + +void ff_frame_thread_encoder_free(AVCodecContext *avctx){ + int i; + ThreadContext *c= avctx->internal->frame_thread_encoder; + + pthread_mutex_lock(&c->task_fifo_mutex); + atomic_store(&c->exit, 1); + pthread_cond_broadcast(&c->task_fifo_cond); + pthread_mutex_unlock(&c->task_fifo_mutex); + + for (i=0; ithread_count; i++) { + pthread_join(c->worker[i], NULL); + } + + while (av_fifo_size(c->task_fifo) > 0) { + Task task; + AVFrame *frame; + av_fifo_generic_read(c->task_fifo, &task, sizeof(task), NULL); + frame = task.indata; + av_frame_free(&frame); + task.indata = NULL; + } + + for (i=0; ifinished_tasks[i].outdata != NULL) { + AVPacket *pkt = c->finished_tasks[i].outdata; + av_packet_free(&pkt); + c->finished_tasks[i].outdata = NULL; + } + } + + pthread_mutex_destroy(&c->task_fifo_mutex); + pthread_mutex_destroy(&c->finished_task_mutex); + pthread_mutex_destroy(&c->buffer_mutex); + pthread_cond_destroy(&c->task_fifo_cond); + pthread_cond_destroy(&c->finished_task_cond); + av_fifo_freep(&c->task_fifo); + av_freep(&avctx->internal->frame_thread_encoder); +} + +int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet_ptr){ + ThreadContext *c = avctx->internal->frame_thread_encoder; + Task task; + int ret; + + av_assert1(!*got_packet_ptr); + + if(frame){ + AVFrame *new = av_frame_alloc(); + if(!new) + return AVERROR(ENOMEM); + ret = av_frame_ref(new, frame); + if(ret < 0) { + av_frame_free(&new); + return ret; + } + + task.index = c->task_index; + task.indata = (void*)new; + pthread_mutex_lock(&c->task_fifo_mutex); + av_fifo_generic_write(c->task_fifo, &task, sizeof(task), NULL); + pthread_cond_signal(&c->task_fifo_cond); + pthread_mutex_unlock(&c->task_fifo_mutex); + + c->task_index = (c->task_index+1) % BUFFER_SIZE; + } + + pthread_mutex_lock(&c->finished_task_mutex); + if (c->task_index == c->finished_task_index || + (frame && !c->finished_tasks[c->finished_task_index].outdata && + (c->task_index - c->finished_task_index) % BUFFER_SIZE <= avctx->thread_count)) { + pthread_mutex_unlock(&c->finished_task_mutex); + return 0; + } + + while (!c->finished_tasks[c->finished_task_index].outdata) { + pthread_cond_wait(&c->finished_task_cond, &c->finished_task_mutex); + } + task = c->finished_tasks[c->finished_task_index]; + *pkt = *(AVPacket*)(task.outdata); + if(pkt->data) + *got_packet_ptr = 1; + av_freep(&c->finished_tasks[c->finished_task_index].outdata); + c->finished_task_index = (c->finished_task_index+1) % BUFFER_SIZE; + pthread_mutex_unlock(&c->finished_task_mutex); + + return task.return_code; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/frame_thread_encoder.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/frame_thread_encoder.h new file mode 100644 index 0000000000..1f79553f20 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/frame_thread_encoder.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_FRAME_THREAD_ENCODER_H +#define AVCODEC_FRAME_THREAD_ENCODER_H + +#include "avcodec.h" + +int ff_frame_thread_encoder_init(AVCodecContext *avctx, AVDictionary *options); +void ff_frame_thread_encoder_free(AVCodecContext *avctx); +int ff_thread_video_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet_ptr); + +#endif /* AVCODEC_FRAME_THREAD_ENCODER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/get_bits.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/get_bits.h new file mode 100644 index 0000000000..c4ab607744 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/get_bits.h @@ -0,0 +1,868 @@ +/* + * Copyright (c) 2004 Michael Niedermayer + * Copyright (c) 2016 Alexandra H谩jkov谩 + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * bitstream reader API header. + */ + +#ifndef AVCODEC_GET_BITS_H +#define AVCODEC_GET_BITS_H + +#include + +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/log.h" +#include "libavutil/avassert.h" +#include "avcodec.h" +#include "mathops.h" +#include "vlc.h" + +/* + * Safe bitstream reading: + * optionally, the get_bits API can check to ensure that we + * don't read past input buffer boundaries. This is protected + * with CONFIG_SAFE_BITSTREAM_READER at the global level, and + * then below that with UNCHECKED_BITSTREAM_READER at the per- + * decoder level. This means that decoders that check internally + * can "#define UNCHECKED_BITSTREAM_READER 1" to disable + * overread checks. + * Boundary checking causes a minor performance penalty so for + * applications that won't want/need this, it can be disabled + * globally using "#define CONFIG_SAFE_BITSTREAM_READER 0". + */ +#ifndef UNCHECKED_BITSTREAM_READER +#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER +#endif + +#ifndef CACHED_BITSTREAM_READER +#define CACHED_BITSTREAM_READER 0 +#endif + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; +#if CACHED_BITSTREAM_READER + uint64_t cache; + unsigned bits_left; +#endif + int index; + int size_in_bits; + int size_in_bits_plus8; +} GetBitContext; + +static inline unsigned int get_bits(GetBitContext *s, int n); +static inline void skip_bits(GetBitContext *s, int n); +static inline unsigned int show_bits(GetBitContext *s, int n); + +/* Bitstream reader API docs: + * name + * arbitrary name which is used as prefix for the internal variables + * + * gb + * getbitcontext + * + * OPEN_READER(name, gb) + * load gb into local variables + * + * CLOSE_READER(name, gb) + * store local vars in gb + * + * UPDATE_CACHE(name, gb) + * Refill the internal cache from the bitstream. + * After this call at least MIN_CACHE_BITS will be available. + * + * GET_CACHE(name, gb) + * Will output the contents of the internal cache, + * next bit is MSB of 32 or 64 bits (FIXME 64 bits). + * + * SHOW_UBITS(name, gb, num) + * Will return the next num bits. + * + * SHOW_SBITS(name, gb, num) + * Will return the next num bits and do sign extension. + * + * SKIP_BITS(name, gb, num) + * Will skip over the next num bits. + * Note, this is equivalent to SKIP_CACHE; SKIP_COUNTER. + * + * SKIP_CACHE(name, gb, num) + * Will remove the next num bits from the cache (note SKIP_COUNTER + * MUST be called before UPDATE_CACHE / CLOSE_READER). + * + * SKIP_COUNTER(name, gb, num) + * Will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS). + * + * LAST_SKIP_BITS(name, gb, num) + * Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER. + * + * BITS_LEFT(name, gb) + * Return the number of bits left + * + * For examples see get_bits, show_bits, skip_bits, get_vlc. + */ + +#if CACHED_BITSTREAM_READER +# define MIN_CACHE_BITS 64 +#elif defined LONG_BITSTREAM_READER +# define MIN_CACHE_BITS 32 +#else +# define MIN_CACHE_BITS 25 +#endif + +#if !CACHED_BITSTREAM_READER + +#define OPEN_READER_NOSIZE(name, gb) \ + unsigned int name ## _index = (gb)->index; \ + unsigned int av_unused name ## _cache + +#if UNCHECKED_BITSTREAM_READER +#define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb) + +#define BITS_AVAILABLE(name, gb) 1 +#else +#define OPEN_READER(name, gb) \ + OPEN_READER_NOSIZE(name, gb); \ + unsigned int name ## _size_plus8 = (gb)->size_in_bits_plus8 + +#define BITS_AVAILABLE(name, gb) name ## _index < name ## _size_plus8 +#endif + +#define CLOSE_READER(name, gb) (gb)->index = name ## _index + +# ifdef LONG_BITSTREAM_READER + +# define UPDATE_CACHE_LE(name, gb) name ## _cache = \ + AV_RL64((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) + +# define UPDATE_CACHE_BE(name, gb) name ## _cache = \ + AV_RB64((gb)->buffer + (name ## _index >> 3)) >> (32 - (name ## _index & 7)) + +#else + +# define UPDATE_CACHE_LE(name, gb) name ## _cache = \ + AV_RL32((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) + +# define UPDATE_CACHE_BE(name, gb) name ## _cache = \ + AV_RB32((gb)->buffer + (name ## _index >> 3)) << (name ## _index & 7) + +#endif + + +#ifdef BITSTREAM_READER_LE + +# define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) + +# define SKIP_CACHE(name, gb, num) name ## _cache >>= (num) + +#else + +# define UPDATE_CACHE(name, gb) UPDATE_CACHE_BE(name, gb) + +# define SKIP_CACHE(name, gb, num) name ## _cache <<= (num) + +#endif + +#if UNCHECKED_BITSTREAM_READER +# define SKIP_COUNTER(name, gb, num) name ## _index += (num) +#else +# define SKIP_COUNTER(name, gb, num) \ + name ## _index = FFMIN(name ## _size_plus8, name ## _index + (num)) +#endif + +#define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name ## _index)) + +#define SKIP_BITS(name, gb, num) \ + do { \ + SKIP_CACHE(name, gb, num); \ + SKIP_COUNTER(name, gb, num); \ + } while (0) + +#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) + +#define SHOW_UBITS_LE(name, gb, num) zero_extend(name ## _cache, num) +#define SHOW_SBITS_LE(name, gb, num) sign_extend(name ## _cache, num) + +#define SHOW_UBITS_BE(name, gb, num) NEG_USR32(name ## _cache, num) +#define SHOW_SBITS_BE(name, gb, num) NEG_SSR32(name ## _cache, num) + +#ifdef BITSTREAM_READER_LE +# define SHOW_UBITS(name, gb, num) SHOW_UBITS_LE(name, gb, num) +# define SHOW_SBITS(name, gb, num) SHOW_SBITS_LE(name, gb, num) +#else +# define SHOW_UBITS(name, gb, num) SHOW_UBITS_BE(name, gb, num) +# define SHOW_SBITS(name, gb, num) SHOW_SBITS_BE(name, gb, num) +#endif + +#define GET_CACHE(name, gb) ((uint32_t) name ## _cache) + +#endif + +static inline int get_bits_count(const GetBitContext *s) +{ +#if CACHED_BITSTREAM_READER + return s->index - s->bits_left; +#else + return s->index; +#endif +} + +#if CACHED_BITSTREAM_READER +static inline void refill_32(GetBitContext *s, int is_le) +{ +#if !UNCHECKED_BITSTREAM_READER + if (s->index >> 3 >= s->buffer_end - s->buffer) + return; +#endif + + if (is_le) + s->cache = (uint64_t)AV_RL32(s->buffer + (s->index >> 3)) << s->bits_left | s->cache; + else + s->cache = s->cache | (uint64_t)AV_RB32(s->buffer + (s->index >> 3)) << (32 - s->bits_left); + s->index += 32; + s->bits_left += 32; +} + +static inline void refill_64(GetBitContext *s, int is_le) +{ +#if !UNCHECKED_BITSTREAM_READER + if (s->index >> 3 >= s->buffer_end - s->buffer) + return; +#endif + + if (is_le) + s->cache = AV_RL64(s->buffer + (s->index >> 3)); + else + s->cache = AV_RB64(s->buffer + (s->index >> 3)); + s->index += 64; + s->bits_left = 64; +} + +static inline uint64_t get_val(GetBitContext *s, unsigned n, int is_le) +{ + uint64_t ret; + av_assert2(n>0 && n<=63); + if (is_le) { + ret = s->cache & ((UINT64_C(1) << n) - 1); + s->cache >>= n; + } else { + ret = s->cache >> (64 - n); + s->cache <<= n; + } + s->bits_left -= n; + return ret; +} + +static inline unsigned show_val(const GetBitContext *s, unsigned n) +{ +#ifdef BITSTREAM_READER_LE + return s->cache & ((UINT64_C(1) << n) - 1); +#else + return s->cache >> (64 - n); +#endif +} +#endif + +/** + * Skips the specified number of bits. + * @param n the number of bits to skip, + * For the UNCHECKED_BITSTREAM_READER this must not cause the distance + * from the start to overflow int32_t. Staying within the bitstream + padding + * is sufficient, too. + */ +static inline void skip_bits_long(GetBitContext *s, int n) +{ +#if CACHED_BITSTREAM_READER + skip_bits(s, n); +#else +#if UNCHECKED_BITSTREAM_READER + s->index += n; +#else + s->index += av_clip(n, -s->index, s->size_in_bits_plus8 - s->index); +#endif +#endif +} + +#if CACHED_BITSTREAM_READER +static inline void skip_remaining(GetBitContext *s, unsigned n) +{ +#ifdef BITSTREAM_READER_LE + s->cache >>= n; +#else + s->cache <<= n; +#endif + s->bits_left -= n; +} +#endif + +/** + * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB). + * if MSB not set it is negative + * @param n length in bits + */ +static inline int get_xbits(GetBitContext *s, int n) +{ +#if CACHED_BITSTREAM_READER + int32_t cache = show_bits(s, 32); + int sign = ~cache >> 31; + skip_remaining(s, n); + + return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign; +#else + register int sign; + register int32_t cache; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + cache = GET_CACHE(re, s); + sign = ~cache >> 31; + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return (NEG_USR32(sign ^ cache, n) ^ sign) - sign; +#endif +} + +#if !CACHED_BITSTREAM_READER +static inline int get_xbits_le(GetBitContext *s, int n) +{ + register int sign; + register int32_t cache; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE_LE(re, s); + cache = GET_CACHE(re, s); + sign = sign_extend(~cache, n) >> 31; + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return (zero_extend(sign ^ cache, n) ^ sign) - sign; +} +#endif + +static inline int get_sbits(GetBitContext *s, int n) +{ + register int tmp; +#if CACHED_BITSTREAM_READER + av_assert2(n>0 && n<=25); + tmp = sign_extend(get_bits(s, n), n); +#else + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_SBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +#endif + return tmp; +} + +/** + * Read 1-25 bits. + */ +static inline unsigned int get_bits(GetBitContext *s, int n) +{ + register unsigned int tmp; +#if CACHED_BITSTREAM_READER + + av_assert2(n>0 && n<=32); + if (n > s->bits_left) { +#ifdef BITSTREAM_READER_LE + refill_32(s, 1); +#else + refill_32(s, 0); +#endif + if (s->bits_left < 32) + s->bits_left = n; + } + +#ifdef BITSTREAM_READER_LE + tmp = get_val(s, n, 1); +#else + tmp = get_val(s, n, 0); +#endif +#else + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +#endif + av_assert2(tmp < UINT64_C(1) << n); + return tmp; +} + +/** + * Read 0-25 bits. + */ +static av_always_inline int get_bitsz(GetBitContext *s, int n) +{ + return n ? get_bits(s, n) : 0; +} + +static inline unsigned int get_bits_le(GetBitContext *s, int n) +{ +#if CACHED_BITSTREAM_READER + av_assert2(n>0 && n<=32); + if (n > s->bits_left) { + refill_32(s, 1); + if (s->bits_left < 32) + s->bits_left = n; + } + + return get_val(s, n, 1); +#else + register int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE_LE(re, s); + tmp = SHOW_UBITS_LE(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +#endif +} + +/** + * Show 1-25 bits. + */ +static inline unsigned int show_bits(GetBitContext *s, int n) +{ + register unsigned int tmp; +#if CACHED_BITSTREAM_READER + if (n > s->bits_left) +#ifdef BITSTREAM_READER_LE + refill_32(s, 1); +#else + refill_32(s, 0); +#endif + + tmp = show_val(s, n); +#else + OPEN_READER_NOSIZE(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); +#endif + return tmp; +} + +static inline void skip_bits(GetBitContext *s, int n) +{ +#if CACHED_BITSTREAM_READER + if (n < s->bits_left) + skip_remaining(s, n); + else { + n -= s->bits_left; + s->cache = 0; + s->bits_left = 0; + + if (n >= 64) { + unsigned skip = (n / 8) * 8; + + n -= skip; + s->index += skip; + } +#ifdef BITSTREAM_READER_LE + refill_64(s, 1); +#else + refill_64(s, 0); +#endif + if (n) + skip_remaining(s, n); + } +#else + OPEN_READER(re, s); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +#endif +} + +static inline unsigned int get_bits1(GetBitContext *s) +{ +#if CACHED_BITSTREAM_READER + if (!s->bits_left) +#ifdef BITSTREAM_READER_LE + refill_64(s, 1); +#else + refill_64(s, 0); +#endif + +#ifdef BITSTREAM_READER_LE + return get_val(s, 1, 1); +#else + return get_val(s, 1, 0); +#endif +#else + unsigned int index = s->index; + uint8_t result = s->buffer[index >> 3]; +#ifdef BITSTREAM_READER_LE + result >>= index & 7; + result &= 1; +#else + result <<= index & 7; + result >>= 8 - 1; +#endif +#if !UNCHECKED_BITSTREAM_READER + if (s->index < s->size_in_bits_plus8) +#endif + index++; + s->index = index; + + return result; +#endif +} + +static inline unsigned int show_bits1(GetBitContext *s) +{ + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s) +{ + skip_bits(s, 1); +} + +/** + * Read 0-32 bits. + */ +static inline unsigned int get_bits_long(GetBitContext *s, int n) +{ + av_assert2(n>=0 && n<=32); + if (!n) { + return 0; +#if CACHED_BITSTREAM_READER + } + return get_bits(s, n); +#else + } else if (n <= MIN_CACHE_BITS) { + return get_bits(s, n); + } else { +#ifdef BITSTREAM_READER_LE + unsigned ret = get_bits(s, 16); + return ret | (get_bits(s, n - 16) << 16); +#else + unsigned ret = get_bits(s, 16) << (n - 16); + return ret | get_bits(s, n - 16); +#endif + } +#endif +} + +/** + * Read 0-64 bits. + */ +static inline uint64_t get_bits64(GetBitContext *s, int n) +{ + if (n <= 32) { + return get_bits_long(s, n); + } else { +#ifdef BITSTREAM_READER_LE + uint64_t ret = get_bits_long(s, 32); + return ret | (uint64_t) get_bits_long(s, n - 32) << 32; +#else + uint64_t ret = (uint64_t) get_bits_long(s, n - 32) << 32; + return ret | get_bits_long(s, 32); +#endif + } +} + +/** + * Read 0-32 bits as a signed integer. + */ +static inline int get_sbits_long(GetBitContext *s, int n) +{ + // sign_extend(x, 0) is undefined + if (!n) + return 0; + + return sign_extend(get_bits_long(s, n), n); +} + +/** + * Show 0-32 bits. + */ +static inline unsigned int show_bits_long(GetBitContext *s, int n) +{ + if (n <= MIN_CACHE_BITS) { + return show_bits(s, n); + } else { + GetBitContext gb = *s; + return get_bits_long(&gb, n); + } +} + +static inline int check_marker(void *logctx, GetBitContext *s, const char *msg) +{ + int bit = get_bits1(s); + if (!bit) + av_log(logctx, AV_LOG_INFO, "Marker bit missing at %d of %d %s\n", + get_bits_count(s) - 1, s->size_in_bits, msg); + + return bit; +} + +static inline int init_get_bits_xe(GetBitContext *s, const uint8_t *buffer, + int bit_size, int is_le) +{ + int buffer_size; + int ret = 0; + + if (bit_size >= INT_MAX - FFMAX(7, AV_INPUT_BUFFER_PADDING_SIZE*8) || bit_size < 0 || !buffer) { + bit_size = 0; + buffer = NULL; + ret = AVERROR_INVALIDDATA; + } + + buffer_size = (bit_size + 7) >> 3; + + s->buffer = buffer; + s->size_in_bits = bit_size; + s->size_in_bits_plus8 = bit_size + 8; + s->buffer_end = buffer + buffer_size; + s->index = 0; + +#if CACHED_BITSTREAM_READER + s->cache = 0; + s->bits_left = 0; + refill_64(s, is_le); +#endif + + return ret; +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param bit_size the size of the buffer in bits + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, + int bit_size) +{ +#ifdef BITSTREAM_READER_LE + return init_get_bits_xe(s, buffer, bit_size, 1); +#else + return init_get_bits_xe(s, buffer, bit_size, 0); +#endif +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param byte_size the size of the buffer in bytes + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits8(GetBitContext *s, const uint8_t *buffer, + int byte_size) +{ + if (byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits(s, buffer, byte_size * 8); +} + +static inline int init_get_bits8_le(GetBitContext *s, const uint8_t *buffer, + int byte_size) +{ + if (byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits_xe(s, buffer, byte_size * 8, 1); +} + +static inline const uint8_t *align_get_bits(GetBitContext *s) +{ + int n = -get_bits_count(s) & 7; + if (n) + skip_bits(s, n); + return s->buffer + (s->index >> 3); +} + +/** + * If the vlc code is invalid and max_depth=1, then no bits will be removed. + * If the vlc code is invalid and max_depth>1, then the number of bits removed + * is undefined. + */ +#define GET_VLC(code, name, gb, table, bits, max_depth) \ + do { \ + int n, nb_bits; \ + unsigned int index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + code = table[index][0]; \ + n = table[index][1]; \ + \ + if (max_depth > 1 && n < 0) { \ + LAST_SKIP_BITS(name, gb, bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index][0]; \ + n = table[index][1]; \ + if (max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index][0]; \ + n = table[index][1]; \ + } \ + } \ + SKIP_BITS(name, gb, n); \ + } while (0) + +#define GET_RL_VLC(level, run, name, gb, table, bits, \ + max_depth, need_update) \ + do { \ + int n, nb_bits; \ + unsigned int index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + level = table[index].level; \ + n = table[index].len; \ + \ + if (max_depth > 1 && n < 0) { \ + SKIP_BITS(name, gb, bits); \ + if (need_update) { \ + UPDATE_CACHE(name, gb); \ + } \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + level; \ + level = table[index].level; \ + n = table[index].len; \ + if (max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + if (need_update) { \ + UPDATE_CACHE(name, gb); \ + } \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + level; \ + level = table[index].level; \ + n = table[index].len; \ + } \ + } \ + run = table[index].run; \ + SKIP_BITS(name, gb, n); \ + } while (0) + +/* Return the LUT element for the given bitstream configuration. */ +static inline int set_idx(GetBitContext *s, int code, int *n, int *nb_bits, + VLC_TYPE (*table)[2]) +{ + unsigned idx; + + *nb_bits = -*n; + idx = show_bits(s, *nb_bits) + code; + *n = table[idx][1]; + + return table[idx][0]; +} + +/** + * Parse a vlc code. + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be read to completely + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + * @returns the code parsed or -1 if no vlc matches + */ +static av_always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], + int bits, int max_depth) +{ +#if CACHED_BITSTREAM_READER + int nb_bits; + unsigned idx = show_bits(s, bits); + int code = table[idx][0]; + int n = table[idx][1]; + + if (max_depth > 1 && n < 0) { + skip_remaining(s, bits); + code = set_idx(s, code, &n, &nb_bits, table); + if (max_depth > 2 && n < 0) { + skip_remaining(s, nb_bits); + code = set_idx(s, code, &n, &nb_bits, table); + } + } + skip_remaining(s, n); + + return code; +#else + int code; + + OPEN_READER(re, s); + UPDATE_CACHE(re, s); + + GET_VLC(code, re, s, table, bits, max_depth); + + CLOSE_READER(re, s); + + return code; +#endif +} + +static inline int decode012(GetBitContext *gb) +{ + int n; + n = get_bits1(gb); + if (n == 0) + return 0; + else + return get_bits1(gb) + 1; +} + +static inline int decode210(GetBitContext *gb) +{ + if (get_bits1(gb)) + return 0; + else + return 2 - get_bits1(gb); +} + +static inline int get_bits_left(GetBitContext *gb) +{ + return gb->size_in_bits - get_bits_count(gb); +} + +static inline int skip_1stop_8data_bits(GetBitContext *gb) +{ + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + + while (get_bits1(gb)) { + skip_bits(gb, 8); + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + } + + return 0; +} + +#endif /* AVCODEC_GET_BITS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/golomb.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/golomb.c new file mode 100644 index 0000000000..937ac22ce1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/golomb.c @@ -0,0 +1,173 @@ +/* + * exp golomb vlc stuff + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief + * exp golomb vlc stuff + * @author Michael Niedermayer + */ + +#include "libavutil/common.h" + +const uint8_t ff_golomb_vlc_len[512]={ +19,17,15,15,13,13,13,13,11,11,11,11,11,11,11,11,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, +7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 +}; + +const uint8_t ff_ue_golomb_vlc_code[512]={ +32,32,32,32,32,32,32,32,31,32,32,32,32,32,32,32,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, + 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,10,10,10,10,11,11,11,11,12,12,12,12,13,13,13,13,14,14,14,14, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +const int8_t ff_se_golomb_vlc_code[512]={ + 17, 17, 17, 17, 17, 17, 17, 17, 16, 17, 17, 17, 17, 17, 17, 17, 8, -8, 9, -9, 10,-10, 11,-11, 12,-12, 13,-13, 14,-14, 15,-15, + 4, 4, 4, 4, -4, -4, -4, -4, 5, 5, 5, 5, -5, -5, -5, -5, 6, 6, 6, 6, -6, -6, -6, -6, 7, 7, 7, 7, -7, -7, -7, -7, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + + +const uint8_t ff_ue_golomb_len[256]={ + 1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,13, +13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, +13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,17, +}; + +const uint8_t ff_interleaved_golomb_vlc_len[256]={ +9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, +9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, +9,9,7,7,9,9,7,7,5,5,5,5,5,5,5,5, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +}; + +const uint8_t ff_interleaved_ue_golomb_vlc_code[256]={ + 15,16,7, 7, 17,18,8, 8, 3, 3, 3, 3, 3, 3, 3, 3, + 19,20,9, 9, 21,22,10,10,4, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 23,24,11,11,25,26,12,12,5, 5, 5, 5, 5, 5, 5, 5, + 27,28,13,13,29,30,14,14,6, 6, 6, 6, 6, 6, 6, 6, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const int8_t ff_interleaved_se_golomb_vlc_code[256]={ + 8, -8, 4, 4, 9, -9, -4, -4, 2, 2, 2, 2, 2, 2, 2, 2, + 10,-10, 5, 5, 11,-11, -5, -5, -2, -2, -2, -2, -2, -2, -2, -2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 12,-12, 6, 6, 13,-13, -6, -6, 3, 3, 3, 3, 3, 3, 3, 3, + 14,-14, 7, 7, 15,-15, -7, -7, -3, -3, -3, -3, -3, -3, -3, -3, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const uint8_t ff_interleaved_dirac_golomb_vlc_code[256]={ +0, 1, 0, 0, 2, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +4, 5, 2, 2, 6, 7, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +8, 9, 4, 4, 10,11,5, 5, 2, 2, 2, 2, 2, 2, 2, 2, +12,13,6, 6, 14,15,7, 7, 3, 3, 3, 3, 3, 3, 3, 3, +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/golomb.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/golomb.h new file mode 100644 index 0000000000..5cdfa0945d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/golomb.h @@ -0,0 +1,747 @@ +/* + * exp golomb vlc stuff + * Copyright (c) 2003 Michael Niedermayer + * Copyright (c) 2004 Alex Beregszaszi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief + * exp golomb vlc stuff + * @author Michael Niedermayer and Alex Beregszaszi + */ + +#ifndef AVCODEC_GOLOMB_H +#define AVCODEC_GOLOMB_H + +#include + +#include "get_bits.h" +#include "put_bits.h" + +#define INVALID_VLC 0x80000000 + +extern const uint8_t ff_golomb_vlc_len[512]; +extern const uint8_t ff_ue_golomb_vlc_code[512]; +extern const int8_t ff_se_golomb_vlc_code[512]; +extern const uint8_t ff_ue_golomb_len[256]; + +extern const uint8_t ff_interleaved_golomb_vlc_len[256]; +extern const uint8_t ff_interleaved_ue_golomb_vlc_code[256]; +extern const int8_t ff_interleaved_se_golomb_vlc_code[256]; +extern const uint8_t ff_interleaved_dirac_golomb_vlc_code[256]; + +/** + * Read an unsigned Exp-Golomb code in the range 0 to 8190. + * + * @returns the read value or a negative error code. + */ +static inline int get_ue_golomb(GetBitContext *gb) +{ + unsigned int buf; + +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + if (buf >= (1 << 27)) { + buf >>= 32 - 9; + skip_bits_long(gb, ff_golomb_vlc_len[buf]); + + return ff_ue_golomb_vlc_code[buf]; + } else { + int log = 2 * av_log2(buf) - 31; + buf >>= log; + buf--; + skip_bits_long(gb, 32 - log); + + return buf; + } +#else + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf >= (1 << 27)) { + buf >>= 32 - 9; + LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_ue_golomb_vlc_code[buf]; + } else { + int log = 2 * av_log2(buf) - 31; + LAST_SKIP_BITS(re, gb, 32 - log); + CLOSE_READER(re, gb); + if (log < 7) { + av_log(NULL, AV_LOG_ERROR, "Invalid UE golomb code\n"); + return AVERROR_INVALIDDATA; + } + buf >>= log; + buf--; + + return buf; + } +#endif +} + +/** + * Read an unsigned Exp-Golomb code in the range 0 to UINT32_MAX-1. + */ +static inline unsigned get_ue_golomb_long(GetBitContext *gb) +{ + unsigned buf, log; + + buf = show_bits_long(gb, 32); + log = 31 - av_log2(buf); + skip_bits_long(gb, log); + + return get_bits_long(gb, log + 1) - 1; +} + +/** + * read unsigned exp golomb code, constraint to a max of 31. + * the return value is undefined if the stored value exceeds 31. + */ +static inline int get_ue_golomb_31(GetBitContext *gb) +{ + unsigned int buf; + +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + buf >>= 32 - 9; + skip_bits_long(gb, ff_golomb_vlc_len[buf]); +#else + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + buf >>= 32 - 9; + LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); +#endif + + return ff_ue_golomb_vlc_code[buf]; +} + +static inline unsigned get_interleaved_ue_golomb(GetBitContext *gb) +{ + uint32_t buf; + +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + if (buf & 0xAA800000) { + buf >>= 32 - 8; + skip_bits_long(gb, ff_interleaved_golomb_vlc_len[buf]); + + return ff_interleaved_ue_golomb_vlc_code[buf]; + } else { + unsigned ret = 1; + + do { + buf >>= 32 - 8; + skip_bits_long(gb, FFMIN(ff_interleaved_golomb_vlc_len[buf], 8)); + + if (ff_interleaved_golomb_vlc_len[buf] != 9) { + ret <<= (ff_interleaved_golomb_vlc_len[buf] - 1) >> 1; + ret |= ff_interleaved_dirac_golomb_vlc_code[buf]; + break; + } + ret = (ret << 4) | ff_interleaved_dirac_golomb_vlc_code[buf]; + buf = show_bits_long(gb, 32); + } while (get_bits_left(gb) > 0); + + return ret - 1; + } +#else + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf & 0xAA800000) { + buf >>= 32 - 8; + LAST_SKIP_BITS(re, gb, ff_interleaved_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_interleaved_ue_golomb_vlc_code[buf]; + } else { + unsigned ret = 1; + + do { + buf >>= 32 - 8; + LAST_SKIP_BITS(re, gb, + FFMIN(ff_interleaved_golomb_vlc_len[buf], 8)); + + if (ff_interleaved_golomb_vlc_len[buf] != 9) { + ret <<= (ff_interleaved_golomb_vlc_len[buf] - 1) >> 1; + ret |= ff_interleaved_dirac_golomb_vlc_code[buf]; + break; + } + ret = (ret << 4) | ff_interleaved_dirac_golomb_vlc_code[buf]; + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + } while (ret<0x8000000U && BITS_AVAILABLE(re, gb)); + + CLOSE_READER(re, gb); + return ret - 1; + } +#endif +} + +/** + * read unsigned truncated exp golomb code. + */ +static inline int get_te0_golomb(GetBitContext *gb, int range) +{ + av_assert2(range >= 1); + + if (range == 1) + return 0; + else if (range == 2) + return get_bits1(gb) ^ 1; + else + return get_ue_golomb(gb); +} + +/** + * read unsigned truncated exp golomb code. + */ +static inline int get_te_golomb(GetBitContext *gb, int range) +{ + av_assert2(range >= 1); + + if (range == 2) + return get_bits1(gb) ^ 1; + else + return get_ue_golomb(gb); +} + +/** + * read signed exp golomb code. + */ +static inline int get_se_golomb(GetBitContext *gb) +{ + unsigned int buf; + +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + if (buf >= (1 << 27)) { + buf >>= 32 - 9; + skip_bits_long(gb, ff_golomb_vlc_len[buf]); + + return ff_se_golomb_vlc_code[buf]; + } else { + int log = 2 * av_log2(buf) - 31; + buf >>= log; + + skip_bits_long(gb, 32 - log); + + if (buf & 1) + buf = -(buf >> 1); + else + buf = (buf >> 1); + + return buf; + } +#else + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf >= (1 << 27)) { + buf >>= 32 - 9; + LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_se_golomb_vlc_code[buf]; + } else { + int log = av_log2(buf), sign; + LAST_SKIP_BITS(re, gb, 31 - log); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + buf >>= log; + + LAST_SKIP_BITS(re, gb, 32 - log); + CLOSE_READER(re, gb); + + sign = -(buf & 1); + buf = ((buf >> 1) ^ sign) - sign; + + return buf; + } +#endif +} + +static inline int get_se_golomb_long(GetBitContext *gb) +{ + unsigned int buf = get_ue_golomb_long(gb); + int sign = (buf & 1) - 1; + return ((buf >> 1) ^ sign) + 1; +} + +static inline int get_interleaved_se_golomb(GetBitContext *gb) +{ + unsigned int buf; + +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + if (buf & 0xAA800000) { + buf >>= 32 - 8; + skip_bits_long(gb, ff_interleaved_golomb_vlc_len[buf]); + + return ff_interleaved_se_golomb_vlc_code[buf]; + } else { + int log; + skip_bits(gb, 8); + buf |= 1 | show_bits_long(gb, 24); + + if ((buf & 0xAAAAAAAA) == 0) + return INVALID_VLC; + + for (log = 31; (buf & 0x80000000) == 0; log--) + buf = (buf << 2) - ((buf << log) >> (log - 1)) + (buf >> 30); + + skip_bits_long(gb, 63 - 2 * log - 8); + + return (signed) (((((buf << log) >> log) - 1) ^ -(buf & 0x1)) + 1) >> 1; + } +#else + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + if (buf & 0xAA800000) { + buf >>= 32 - 8; + LAST_SKIP_BITS(re, gb, ff_interleaved_golomb_vlc_len[buf]); + CLOSE_READER(re, gb); + + return ff_interleaved_se_golomb_vlc_code[buf]; + } else { + int log; + LAST_SKIP_BITS(re, gb, 8); + UPDATE_CACHE(re, gb); + buf |= 1 | (GET_CACHE(re, gb) >> 8); + + if ((buf & 0xAAAAAAAA) == 0) + return INVALID_VLC; + + for (log = 31; (buf & 0x80000000) == 0; log--) + buf = (buf << 2) - ((buf << log) >> (log - 1)) + (buf >> 30); + + LAST_SKIP_BITS(re, gb, 63 - 2 * log - 8); + CLOSE_READER(re, gb); + + return (signed) (((((buf << log) >> log) - 1) ^ -(buf & 0x1)) + 1) >> 1; + } +#endif +} + +static inline int dirac_get_se_golomb(GetBitContext *gb) +{ + uint32_t ret = get_interleaved_ue_golomb(gb); + + if (ret) { + int sign = -get_bits1(gb); + ret = (ret ^ sign) - sign; + } + + return ret; +} + +/** + * read unsigned golomb rice code (ffv1). + */ +static inline int get_ur_golomb(GetBitContext *gb, int k, int limit, + int esc_len) +{ + unsigned int buf; + int log; + +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + log = av_log2(buf); + + if (log > 31 - limit) { + buf >>= log - k; + buf += (30 - log) << k; + skip_bits_long(gb, 32 + k - log); + + return buf; + } else { + skip_bits_long(gb, limit); + buf = get_bits_long(gb, esc_len); + + return buf + limit - 1; + } +#else + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + log = av_log2(buf); + + if (log > 31 - limit) { + buf >>= log - k; + buf += (30U - log) << k; + LAST_SKIP_BITS(re, gb, 32 + k - log); + CLOSE_READER(re, gb); + + return buf; + } else { + LAST_SKIP_BITS(re, gb, limit); + UPDATE_CACHE(re, gb); + + buf = SHOW_UBITS(re, gb, esc_len); + + LAST_SKIP_BITS(re, gb, esc_len); + CLOSE_READER(re, gb); + + return buf + limit - 1; + } +#endif +} + +/** + * read unsigned golomb rice code (jpegls). + */ +static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit, + int esc_len) +{ + unsigned int buf; + int log; + +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + log = av_log2(buf); + + if (log - k >= 1 && 32 - log < limit) { + buf >>= log - k; + buf += (30 - log) << k; + skip_bits_long(gb, 32 + k - log); + + return buf; + } else { + int i; + for (i = 0; + i < limit && get_bits1(gb) == 0 && get_bits_left(gb) > 0; + i++); + + if (i < limit - 1) { + buf = get_bits_long(gb, k); + + return buf + (i << k); + } else if (i == limit - 1) { + buf = get_bits_long(gb, esc_len); + + return buf + 1; + } else + return -1; + } +#else + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + log = av_log2(buf); + + av_assert2(k <= 31); + + if (log - k >= 32 - MIN_CACHE_BITS + (MIN_CACHE_BITS == 32) && + 32 - log < limit) { + buf >>= log - k; + buf += (30U - log) << k; + LAST_SKIP_BITS(re, gb, 32 + k - log); + CLOSE_READER(re, gb); + + return buf; + } else { + int i; + for (i = 0; i + MIN_CACHE_BITS <= limit && SHOW_UBITS(re, gb, MIN_CACHE_BITS) == 0; i += MIN_CACHE_BITS) { + if (gb->size_in_bits <= re_index) { + CLOSE_READER(re, gb); + return -1; + } + LAST_SKIP_BITS(re, gb, MIN_CACHE_BITS); + UPDATE_CACHE(re, gb); + } + for (; i < limit && SHOW_UBITS(re, gb, 1) == 0; i++) { + SKIP_BITS(re, gb, 1); + } + LAST_SKIP_BITS(re, gb, 1); + UPDATE_CACHE(re, gb); + + if (i < limit - 1) { + if (k) { + if (k > MIN_CACHE_BITS - 1) { + buf = SHOW_UBITS(re, gb, 16) << (k-16); + LAST_SKIP_BITS(re, gb, 16); + UPDATE_CACHE(re, gb); + buf |= SHOW_UBITS(re, gb, k-16); + LAST_SKIP_BITS(re, gb, k-16); + } else { + buf = SHOW_UBITS(re, gb, k); + LAST_SKIP_BITS(re, gb, k); + } + } else { + buf = 0; + } + + buf += ((SUINT)i << k); + } else if (i == limit - 1) { + buf = SHOW_UBITS(re, gb, esc_len); + LAST_SKIP_BITS(re, gb, esc_len); + + buf ++; + } else { + buf = -1; + } + CLOSE_READER(re, gb); + return buf; + } +#endif +} + +/** + * read signed golomb rice code (ffv1). + */ +static inline int get_sr_golomb(GetBitContext *gb, int k, int limit, + int esc_len) +{ + unsigned v = get_ur_golomb(gb, k, limit, esc_len); + return (v >> 1) ^ -(v & 1); +} + +/** + * read signed golomb rice code (flac). + */ +static inline int get_sr_golomb_flac(GetBitContext *gb, int k, int limit, + int esc_len) +{ + unsigned v = get_ur_golomb_jpegls(gb, k, limit, esc_len); + return (v >> 1) ^ -(v & 1); +} + +/** + * read unsigned golomb rice code (shorten). + */ +static inline unsigned int get_ur_golomb_shorten(GetBitContext *gb, int k) +{ + return get_ur_golomb_jpegls(gb, k, INT_MAX, 0); +} + +/** + * read signed golomb rice code (shorten). + */ +static inline int get_sr_golomb_shorten(GetBitContext *gb, int k) +{ + int uvar = get_ur_golomb_jpegls(gb, k + 1, INT_MAX, 0); + return (uvar >> 1) ^ -(uvar & 1); +} + +#ifdef TRACE + +static inline int get_ue(GetBitContext *s, const char *file, const char *func, + int line) +{ + int show = show_bits(s, 24); + int pos = get_bits_count(s); + int i = get_ue_golomb(s); + int len = get_bits_count(s) - pos; + int bits = show >> (24 - len); + + av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d ue @%5d in %s %s:%d\n", + bits, len, i, pos, file, func, line); + + return i; +} + +static inline int get_se(GetBitContext *s, const char *file, const char *func, + int line) +{ + int show = show_bits(s, 24); + int pos = get_bits_count(s); + int i = get_se_golomb(s); + int len = get_bits_count(s) - pos; + int bits = show >> (24 - len); + + av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d se @%5d in %s %s:%d\n", + bits, len, i, pos, file, func, line); + + return i; +} + +static inline int get_te(GetBitContext *s, int r, char *file, const char *func, + int line) +{ + int show = show_bits(s, 24); + int pos = get_bits_count(s); + int i = get_te0_golomb(s, r); + int len = get_bits_count(s) - pos; + int bits = show >> (24 - len); + + av_log(NULL, AV_LOG_DEBUG, "%5d %2d %3d te @%5d in %s %s:%d\n", + bits, len, i, pos, file, func, line); + + return i; +} + +#define get_ue_golomb(a) get_ue(a, __FILE__, __func__, __LINE__) +#define get_se_golomb(a) get_se(a, __FILE__, __func__, __LINE__) +#define get_te_golomb(a, r) get_te(a, r, __FILE__, __func__, __LINE__) +#define get_te0_golomb(a, r) get_te(a, r, __FILE__, __func__, __LINE__) + +#endif /* TRACE */ + +/** + * write unsigned exp golomb code. 2^16 - 2 at most + */ +static inline void set_ue_golomb(PutBitContext *pb, int i) +{ + av_assert2(i >= 0); + av_assert2(i <= 0xFFFE); + + if (i < 256) + put_bits(pb, ff_ue_golomb_len[i], i + 1); + else { + int e = av_log2(i + 1); + put_bits(pb, 2 * e + 1, i + 1); + } +} + +/** + * write unsigned exp golomb code. 2^32-2 at most. + */ +static inline void set_ue_golomb_long(PutBitContext *pb, uint32_t i) +{ + av_assert2(i <= (UINT32_MAX - 1)); + + if (i < 256) + put_bits(pb, ff_ue_golomb_len[i], i + 1); + else { + int e = av_log2(i + 1); + put_bits64(pb, 2 * e + 1, i + 1); + } +} + +/** + * write truncated unsigned exp golomb code. + */ +static inline void set_te_golomb(PutBitContext *pb, int i, int range) +{ + av_assert2(range >= 1); + av_assert2(i <= range); + + if (range == 2) + put_bits(pb, 1, i ^ 1); + else + set_ue_golomb(pb, i); +} + +/** + * write signed exp golomb code. 16 bits at most. + */ +static inline void set_se_golomb(PutBitContext *pb, int i) +{ + i = 2 * i - 1; + if (i < 0) + i ^= -1; //FIXME check if gcc does the right thing + set_ue_golomb(pb, i); +} + +/** + * write unsigned golomb rice code (ffv1). + */ +static inline void set_ur_golomb(PutBitContext *pb, int i, int k, int limit, + int esc_len) +{ + int e; + + av_assert2(i >= 0); + + e = i >> k; + if (e < limit) + put_bits(pb, e + k + 1, (1 << k) + av_mod_uintp2(i, k)); + else + put_bits(pb, limit + esc_len, i - limit + 1); +} + +/** + * write unsigned golomb rice code (jpegls). + */ +static inline void set_ur_golomb_jpegls(PutBitContext *pb, int i, int k, + int limit, int esc_len) +{ + int e; + + av_assert2(i >= 0); + + e = (i >> k) + 1; + if (e < limit) { + while (e > 31) { + put_bits(pb, 31, 0); + e -= 31; + } + put_bits(pb, e, 1); + if (k) + put_sbits(pb, k, i); + } else { + while (limit > 31) { + put_bits(pb, 31, 0); + limit -= 31; + } + put_bits(pb, limit, 1); + put_bits(pb, esc_len, i - 1); + } +} + +/** + * write signed golomb rice code (ffv1). + */ +static inline void set_sr_golomb(PutBitContext *pb, int i, int k, int limit, + int esc_len) +{ + int v; + + v = -2 * i - 1; + v ^= (v >> 31); + + set_ur_golomb(pb, v, k, limit, esc_len); +} + +/** + * write signed golomb rice code (flac). + */ +static inline void set_sr_golomb_flac(PutBitContext *pb, int i, int k, + int limit, int esc_len) +{ + int v; + + v = -2 * i - 1; + v ^= (v >> 31); + + set_ur_golomb_jpegls(pb, v, k, limit, esc_len); +} + +#endif /* AVCODEC_GOLOMB_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h263dsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h263dsp.c new file mode 100644 index 0000000000..b3c0bcd450 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h263dsp.c @@ -0,0 +1,126 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/common.h" +#include "config.h" +#include "h263dsp.h" + +const uint8_t ff_h263_loop_filter_strength[32] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, + 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12 +}; + +static void h263_h_loop_filter_c(uint8_t *src, int stride, int qscale) +{ + int y; + const int strength = ff_h263_loop_filter_strength[qscale]; + + for (y = 0; y < 8; y++) { + int d1, d2, ad1; + int p0 = src[y * stride - 2]; + int p1 = src[y * stride - 1]; + int p2 = src[y * stride + 0]; + int p3 = src[y * stride + 1]; + int d = (p0 - p3 + 4 * (p2 - p1)) / 8; + + if (d < -2 * strength) + d1 = 0; + else if (d < -strength) + d1 = -2 * strength - d; + else if (d < strength) + d1 = d; + else if (d < 2 * strength) + d1 = 2 * strength - d; + else + d1 = 0; + + p1 += d1; + p2 -= d1; + if (p1 & 256) + p1 = ~(p1 >> 31); + if (p2 & 256) + p2 = ~(p2 >> 31); + + src[y * stride - 1] = p1; + src[y * stride + 0] = p2; + + ad1 = FFABS(d1) >> 1; + + d2 = av_clip((p0 - p3) / 4, -ad1, ad1); + + src[y * stride - 2] = p0 - d2; + src[y * stride + 1] = p3 + d2; + } +} + +static void h263_v_loop_filter_c(uint8_t *src, int stride, int qscale) +{ + int x; + const int strength = ff_h263_loop_filter_strength[qscale]; + + for (x = 0; x < 8; x++) { + int d1, d2, ad1; + int p0 = src[x - 2 * stride]; + int p1 = src[x - 1 * stride]; + int p2 = src[x + 0 * stride]; + int p3 = src[x + 1 * stride]; + int d = (p0 - p3 + 4 * (p2 - p1)) / 8; + + if (d < -2 * strength) + d1 = 0; + else if (d < -strength) + d1 = -2 * strength - d; + else if (d < strength) + d1 = d; + else if (d < 2 * strength) + d1 = 2 * strength - d; + else + d1 = 0; + + p1 += d1; + p2 -= d1; + if (p1 & 256) + p1 = ~(p1 >> 31); + if (p2 & 256) + p2 = ~(p2 >> 31); + + src[x - 1 * stride] = p1; + src[x + 0 * stride] = p2; + + ad1 = FFABS(d1) >> 1; + + d2 = av_clip((p0 - p3) / 4, -ad1, ad1); + + src[x - 2 * stride] = p0 - d2; + src[x + stride] = p3 + d2; + } +} + +av_cold void ff_h263dsp_init(H263DSPContext *ctx) +{ + ctx->h263_h_loop_filter = h263_h_loop_filter_c; + ctx->h263_v_loop_filter = h263_v_loop_filter_c; + + if (ARCH_X86) + ff_h263dsp_init_x86(ctx); + if (ARCH_MIPS) + ff_h263dsp_init_mips(ctx); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h263dsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h263dsp.h new file mode 100644 index 0000000000..1abea3ca8c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h263dsp.h @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_H263DSP_H +#define AVCODEC_H263DSP_H + +#include + +extern const uint8_t ff_h263_loop_filter_strength[32]; + +typedef struct H263DSPContext { + void (*h263_h_loop_filter)(uint8_t *src, int stride, int qscale); + void (*h263_v_loop_filter)(uint8_t *src, int stride, int qscale); +} H263DSPContext; + +void ff_h263dsp_init(H263DSPContext *ctx); +void ff_h263dsp_init_x86(H263DSPContext *ctx); +void ff_h263dsp_init_mips(H263DSPContext *ctx); + +#endif /* AVCODEC_H263DSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h264chroma.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h264chroma.c new file mode 100644 index 0000000000..c2f1f30f5a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h264chroma.c @@ -0,0 +1,59 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "h264chroma.h" + +#define BIT_DEPTH 8 +#include "h264chroma_template.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 16 +#include "h264chroma_template.c" +#undef BIT_DEPTH + +#define SET_CHROMA(depth) \ + c->put_h264_chroma_pixels_tab[0] = put_h264_chroma_mc8_ ## depth ## _c; \ + c->put_h264_chroma_pixels_tab[1] = put_h264_chroma_mc4_ ## depth ## _c; \ + c->put_h264_chroma_pixels_tab[2] = put_h264_chroma_mc2_ ## depth ## _c; \ + c->put_h264_chroma_pixels_tab[3] = put_h264_chroma_mc1_ ## depth ## _c; \ + c->avg_h264_chroma_pixels_tab[0] = avg_h264_chroma_mc8_ ## depth ## _c; \ + c->avg_h264_chroma_pixels_tab[1] = avg_h264_chroma_mc4_ ## depth ## _c; \ + c->avg_h264_chroma_pixels_tab[2] = avg_h264_chroma_mc2_ ## depth ## _c; \ + c->avg_h264_chroma_pixels_tab[3] = avg_h264_chroma_mc1_ ## depth ## _c; \ + +av_cold void ff_h264chroma_init(H264ChromaContext *c, int bit_depth) +{ + if (bit_depth > 8 && bit_depth <= 16) { + SET_CHROMA(16); + } else { + SET_CHROMA(8); + } + + if (ARCH_AARCH64) + ff_h264chroma_init_aarch64(c, bit_depth); + if (ARCH_ARM) + ff_h264chroma_init_arm(c, bit_depth); + if (ARCH_PPC) + ff_h264chroma_init_ppc(c, bit_depth); + if (ARCH_X86) + ff_h264chroma_init_x86(c, bit_depth); + if (ARCH_MIPS) + ff_h264chroma_init_mips(c, bit_depth); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h264chroma.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h264chroma.h new file mode 100644 index 0000000000..5c89fd12df --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/h264chroma.h @@ -0,0 +1,40 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_H264CHROMA_H +#define AVCODEC_H264CHROMA_H + +#include +#include + +typedef void (*h264_chroma_mc_func)(uint8_t *dst /*align 8*/, uint8_t *src /*align 1*/, ptrdiff_t srcStride, int h, int x, int y); + +typedef struct H264ChromaContext { + h264_chroma_mc_func put_h264_chroma_pixels_tab[4]; + h264_chroma_mc_func avg_h264_chroma_pixels_tab[4]; +} H264ChromaContext; + +void ff_h264chroma_init(H264ChromaContext *c, int bit_depth); + +void ff_h264chroma_init_aarch64(H264ChromaContext *c, int bit_depth); +void ff_h264chroma_init_arm(H264ChromaContext *c, int bit_depth); +void ff_h264chroma_init_ppc(H264ChromaContext *c, int bit_depth); +void ff_h264chroma_init_x86(H264ChromaContext *c, int bit_depth); +void ff_h264chroma_init_mips(H264ChromaContext *c, int bit_depth); + +#endif /* AVCODEC_H264CHROMA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hpeldsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hpeldsp.c new file mode 100644 index 0000000000..8e2fd8fcf5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hpeldsp.c @@ -0,0 +1,370 @@ +/* + * Half-pel DSP functions. + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * gmc & q-pel & 32/64 bit based MC by Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Half-pel DSP functions. + */ + +#include "libavutil/attributes.h" +#include "libavutil/intreadwrite.h" +#include "hpeldsp.h" + +#define BIT_DEPTH 8 +#include "hpel_template.c" +#include "pel_template.c" + +#define PIXOP2(OPNAME, OP) \ +static inline void OPNAME ## _no_rnd_pixels8_l2_8(uint8_t *dst, \ + const uint8_t *src1, \ + const uint8_t *src2, \ + int dst_stride, \ + int src_stride1, \ + int src_stride2, \ + int h) \ +{ \ + int i; \ + \ + for (i = 0; i < h; i++) { \ + uint32_t a, b; \ + a = AV_RN32(&src1[i * src_stride1]); \ + b = AV_RN32(&src2[i * src_stride2]); \ + OP(*((uint32_t *) &dst[i * dst_stride]), \ + no_rnd_avg32(a, b)); \ + a = AV_RN32(&src1[i * src_stride1 + 4]); \ + b = AV_RN32(&src2[i * src_stride2 + 4]); \ + OP(*((uint32_t *) &dst[i * dst_stride + 4]), \ + no_rnd_avg32(a, b)); \ + } \ +} \ + \ +static inline void OPNAME ## _no_rnd_pixels8_x2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + OPNAME ## _no_rnd_pixels8_l2_8(block, pixels, pixels + 1, \ + line_size, line_size, line_size, h); \ +} \ + \ +static inline void OPNAME ## _pixels8_x2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + OPNAME ## _pixels8_l2_8(block, pixels, pixels + 1, \ + line_size, line_size, line_size, h); \ +} \ + \ +static inline void OPNAME ## _no_rnd_pixels8_y2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + OPNAME ## _no_rnd_pixels8_l2_8(block, pixels, pixels + line_size, \ + line_size, line_size, line_size, h); \ +} \ + \ +static inline void OPNAME ## _pixels8_y2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + OPNAME ## _pixels8_l2_8(block, pixels, pixels + line_size, \ + line_size, line_size, line_size, h); \ +} \ + \ +static inline void OPNAME ## _pixels4_x2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + OPNAME ## _pixels4_l2_8(block, pixels, pixels + 1, \ + line_size, line_size, line_size, h); \ +} \ + \ +static inline void OPNAME ## _pixels4_y2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + OPNAME ## _pixels4_l2_8(block, pixels, pixels + line_size, \ + line_size, line_size, line_size, h); \ +} \ + \ +static inline void OPNAME ## _pixels2_x2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + OPNAME ## _pixels2_l2_8(block, pixels, pixels + 1, \ + line_size, line_size, line_size, h); \ +} \ + \ +static inline void OPNAME ## _pixels2_y2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + OPNAME ## _pixels2_l2_8(block, pixels, pixels + line_size, \ + line_size, line_size, line_size, h); \ +} \ + \ +static inline void OPNAME ## _pixels2_xy2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + int i, a1, b1; \ + int a0 = pixels[0]; \ + int b0 = pixels[1] + 2; \ + \ + a0 += b0; \ + b0 += pixels[2]; \ + pixels += line_size; \ + for (i = 0; i < h; i += 2) { \ + a1 = pixels[0]; \ + b1 = pixels[1]; \ + a1 += b1; \ + b1 += pixels[2]; \ + \ + block[0] = (a1 + a0) >> 2; /* FIXME non put */ \ + block[1] = (b1 + b0) >> 2; \ + \ + pixels += line_size; \ + block += line_size; \ + \ + a0 = pixels[0]; \ + b0 = pixels[1] + 2; \ + a0 += b0; \ + b0 += pixels[2]; \ + \ + block[0] = (a1 + a0) >> 2; \ + block[1] = (b1 + b0) >> 2; \ + pixels += line_size; \ + block += line_size; \ + } \ +} \ + \ +static inline void OPNAME ## _pixels4_xy2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + /* FIXME HIGH BIT DEPTH */ \ + int i; \ + const uint32_t a = AV_RN32(pixels); \ + const uint32_t b = AV_RN32(pixels + 1); \ + uint32_t l0 = (a & 0x03030303UL) + \ + (b & 0x03030303UL) + \ + 0x02020202UL; \ + uint32_t h0 = ((a & 0xFCFCFCFCUL) >> 2) + \ + ((b & 0xFCFCFCFCUL) >> 2); \ + uint32_t l1, h1; \ + \ + pixels += line_size; \ + for (i = 0; i < h; i += 2) { \ + uint32_t a = AV_RN32(pixels); \ + uint32_t b = AV_RN32(pixels + 1); \ + l1 = (a & 0x03030303UL) + \ + (b & 0x03030303UL); \ + h1 = ((a & 0xFCFCFCFCUL) >> 2) + \ + ((b & 0xFCFCFCFCUL) >> 2); \ + OP(*((uint32_t *) block), h0 + h1 + \ + (((l0 + l1) >> 2) & 0x0F0F0F0FUL)); \ + pixels += line_size; \ + block += line_size; \ + a = AV_RN32(pixels); \ + b = AV_RN32(pixels + 1); \ + l0 = (a & 0x03030303UL) + \ + (b & 0x03030303UL) + \ + 0x02020202UL; \ + h0 = ((a & 0xFCFCFCFCUL) >> 2) + \ + ((b & 0xFCFCFCFCUL) >> 2); \ + OP(*((uint32_t *) block), h0 + h1 + \ + (((l0 + l1) >> 2) & 0x0F0F0F0FUL)); \ + pixels += line_size; \ + block += line_size; \ + } \ +} \ + \ +static inline void OPNAME ## _pixels8_xy2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + /* FIXME HIGH BIT DEPTH */ \ + int j; \ + \ + for (j = 0; j < 2; j++) { \ + int i; \ + const uint32_t a = AV_RN32(pixels); \ + const uint32_t b = AV_RN32(pixels + 1); \ + uint32_t l0 = (a & 0x03030303UL) + \ + (b & 0x03030303UL) + \ + 0x02020202UL; \ + uint32_t h0 = ((a & 0xFCFCFCFCUL) >> 2) + \ + ((b & 0xFCFCFCFCUL) >> 2); \ + uint32_t l1, h1; \ + \ + pixels += line_size; \ + for (i = 0; i < h; i += 2) { \ + uint32_t a = AV_RN32(pixels); \ + uint32_t b = AV_RN32(pixels + 1); \ + l1 = (a & 0x03030303UL) + \ + (b & 0x03030303UL); \ + h1 = ((a & 0xFCFCFCFCUL) >> 2) + \ + ((b & 0xFCFCFCFCUL) >> 2); \ + OP(*((uint32_t *) block), h0 + h1 + \ + (((l0 + l1) >> 2) & 0x0F0F0F0FUL)); \ + pixels += line_size; \ + block += line_size; \ + a = AV_RN32(pixels); \ + b = AV_RN32(pixels + 1); \ + l0 = (a & 0x03030303UL) + \ + (b & 0x03030303UL) + \ + 0x02020202UL; \ + h0 = ((a & 0xFCFCFCFCUL) >> 2) + \ + ((b & 0xFCFCFCFCUL) >> 2); \ + OP(*((uint32_t *) block), h0 + h1 + \ + (((l0 + l1) >> 2) & 0x0F0F0F0FUL)); \ + pixels += line_size; \ + block += line_size; \ + } \ + pixels += 4 - line_size * (h + 1); \ + block += 4 - line_size * h; \ + } \ +} \ + \ +static inline void OPNAME ## _no_rnd_pixels8_xy2_8_c(uint8_t *block, \ + const uint8_t *pixels, \ + ptrdiff_t line_size, \ + int h) \ +{ \ + /* FIXME HIGH BIT DEPTH */ \ + int j; \ + \ + for (j = 0; j < 2; j++) { \ + int i; \ + const uint32_t a = AV_RN32(pixels); \ + const uint32_t b = AV_RN32(pixels + 1); \ + uint32_t l0 = (a & 0x03030303UL) + \ + (b & 0x03030303UL) + \ + 0x01010101UL; \ + uint32_t h0 = ((a & 0xFCFCFCFCUL) >> 2) + \ + ((b & 0xFCFCFCFCUL) >> 2); \ + uint32_t l1, h1; \ + \ + pixels += line_size; \ + for (i = 0; i < h; i += 2) { \ + uint32_t a = AV_RN32(pixels); \ + uint32_t b = AV_RN32(pixels + 1); \ + l1 = (a & 0x03030303UL) + \ + (b & 0x03030303UL); \ + h1 = ((a & 0xFCFCFCFCUL) >> 2) + \ + ((b & 0xFCFCFCFCUL) >> 2); \ + OP(*((uint32_t *) block), h0 + h1 + \ + (((l0 + l1) >> 2) & 0x0F0F0F0FUL)); \ + pixels += line_size; \ + block += line_size; \ + a = AV_RN32(pixels); \ + b = AV_RN32(pixels + 1); \ + l0 = (a & 0x03030303UL) + \ + (b & 0x03030303UL) + \ + 0x01010101UL; \ + h0 = ((a & 0xFCFCFCFCUL) >> 2) + \ + ((b & 0xFCFCFCFCUL) >> 2); \ + OP(*((uint32_t *) block), h0 + h1 + \ + (((l0 + l1) >> 2) & 0x0F0F0F0FUL)); \ + pixels += line_size; \ + block += line_size; \ + } \ + pixels += 4 - line_size * (h + 1); \ + block += 4 - line_size * h; \ + } \ +} \ + \ +CALL_2X_PIXELS(OPNAME ## _pixels16_x2_8_c, \ + OPNAME ## _pixels8_x2_8_c, \ + 8) \ +CALL_2X_PIXELS(OPNAME ## _pixels16_y2_8_c, \ + OPNAME ## _pixels8_y2_8_c, \ + 8) \ +CALL_2X_PIXELS(OPNAME ## _pixels16_xy2_8_c, \ + OPNAME ## _pixels8_xy2_8_c, \ + 8) \ +CALL_2X_PIXELS(OPNAME ## _no_rnd_pixels16_8_c, \ + OPNAME ## _pixels8_8_c, \ + 8) \ +CALL_2X_PIXELS(OPNAME ## _no_rnd_pixels16_x2_8_c, \ + OPNAME ## _no_rnd_pixels8_x2_8_c, \ + 8) \ +CALL_2X_PIXELS(OPNAME ## _no_rnd_pixels16_y2_8_c, \ + OPNAME ## _no_rnd_pixels8_y2_8_c, \ + 8) \ +CALL_2X_PIXELS(OPNAME ## _no_rnd_pixels16_xy2_8_c, \ + OPNAME ## _no_rnd_pixels8_xy2_8_c, \ + 8) \ + +#define op_avg(a, b) a = rnd_avg32(a, b) +#define op_put(a, b) a = b +#define put_no_rnd_pixels8_8_c put_pixels8_8_c +PIXOP2(avg, op_avg) +PIXOP2(put, op_put) +#undef op_avg +#undef op_put + +av_cold void ff_hpeldsp_init(HpelDSPContext *c, int flags) +{ +#define hpel_funcs(prefix, idx, num) \ + c->prefix ## _pixels_tab idx [0] = prefix ## _pixels ## num ## _8_c; \ + c->prefix ## _pixels_tab idx [1] = prefix ## _pixels ## num ## _x2_8_c; \ + c->prefix ## _pixels_tab idx [2] = prefix ## _pixels ## num ## _y2_8_c; \ + c->prefix ## _pixels_tab idx [3] = prefix ## _pixels ## num ## _xy2_8_c + + hpel_funcs(put, [0], 16); + hpel_funcs(put, [1], 8); + hpel_funcs(put, [2], 4); + hpel_funcs(put, [3], 2); + hpel_funcs(put_no_rnd, [0], 16); + hpel_funcs(put_no_rnd, [1], 8); + hpel_funcs(avg, [0], 16); + hpel_funcs(avg, [1], 8); + hpel_funcs(avg, [2], 4); + hpel_funcs(avg, [3], 2); + hpel_funcs(avg_no_rnd,, 16); + + if (ARCH_AARCH64) + ff_hpeldsp_init_aarch64(c, flags); + if (ARCH_ALPHA) + ff_hpeldsp_init_alpha(c, flags); + if (ARCH_ARM) + ff_hpeldsp_init_arm(c, flags); + if (ARCH_PPC) + ff_hpeldsp_init_ppc(c, flags); + if (ARCH_X86) + ff_hpeldsp_init_x86(c, flags); + if (ARCH_MIPS) + ff_hpeldsp_init_mips(c, flags); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hpeldsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hpeldsp.h new file mode 100644 index 0000000000..768139bfc9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hpeldsp.h @@ -0,0 +1,106 @@ +/* + * Half-pel DSP functions. + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Half-pel DSP functions. + */ + +#ifndef AVCODEC_HPELDSP_H +#define AVCODEC_HPELDSP_H + +#include +#include + +/* add and put pixel (decoding) */ +// blocksizes for hpel_pixels_func are 8x4,8x8 16x8 16x16 +// h for hpel_pixels_func is limited to {width/2, width} but never larger +// than 16 and never smaller than 4 +typedef void (*op_pixels_func)(uint8_t *block /*align width (8 or 16)*/, + const uint8_t *pixels /*align 1*/, + ptrdiff_t line_size, int h); + +/** + * Half-pel DSP context. + */ +typedef struct HpelDSPContext { + /** + * Halfpel motion compensation with rounding (a+b+1)>>1. + * this is an array[4][4] of motion compensation functions for 4 + * horizontal blocksizes (8,16) and the 4 halfpel positions
      + * *pixels_tab[ 0->16xH 1->8xH ][ xhalfpel + 2*yhalfpel ] + * @param block destination where the result is stored + * @param pixels source + * @param line_size number of bytes in a horizontal line of block + * @param h height + */ + op_pixels_func put_pixels_tab[4][4]; + + /** + * Halfpel motion compensation with rounding (a+b+1)>>1. + * This is an array[4][4] of motion compensation functions for 4 + * horizontal blocksizes (8,16) and the 4 halfpel positions
      + * *pixels_tab[ 0->16xH 1->8xH ][ xhalfpel + 2*yhalfpel ] + * @param block destination into which the result is averaged (a+b+1)>>1 + * @param pixels source + * @param line_size number of bytes in a horizontal line of block + * @param h height + */ + op_pixels_func avg_pixels_tab[4][4]; + + /** + * Halfpel motion compensation with no rounding (a+b)>>1. + * this is an array[4][4] of motion compensation functions for 2 + * horizontal blocksizes (8,16) and the 4 halfpel positions
      + * *pixels_tab[ 0->16xH 1->8xH ][ xhalfpel + 2*yhalfpel ] + * @param block destination where the result is stored + * @param pixels source + * @param line_size number of bytes in a horizontal line of block + * @param h height + * @note The size is kept at [4][4] to match the above pixel_tabs and avoid + * out of bounds reads in the motion estimation code. + */ + op_pixels_func put_no_rnd_pixels_tab[4][4]; + + /** + * Halfpel motion compensation with no rounding (a+b)>>1. + * this is an array[4] of motion compensation functions for 1 + * horizontal blocksize (16) and the 4 halfpel positions
      + * *pixels_tab[0][ xhalfpel + 2*yhalfpel ] + * @param block destination into which the result is averaged (a+b)>>1 + * @param pixels source + * @param line_size number of bytes in a horizontal line of block + * @param h height + */ + op_pixels_func avg_no_rnd_pixels_tab[4]; +} HpelDSPContext; + +void ff_hpeldsp_init(HpelDSPContext *c, int flags); + +void ff_hpeldsp_init_aarch64(HpelDSPContext *c, int flags); +void ff_hpeldsp_init_alpha(HpelDSPContext *c, int flags); +void ff_hpeldsp_init_arm(HpelDSPContext *c, int flags); +void ff_hpeldsp_init_ppc(HpelDSPContext *c, int flags); +void ff_hpeldsp_init_x86(HpelDSPContext *c, int flags); +void ff_hpeldsp_init_mips(HpelDSPContext *c, int flags); + +#endif /* AVCODEC_HPELDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hwaccel.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hwaccel.h new file mode 100644 index 0000000000..3aaa92571c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hwaccel.h @@ -0,0 +1,84 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_HWACCEL_H +#define AVCODEC_HWACCEL_H + +#include "avcodec.h" +#include "hwaccels.h" + + +#define HWACCEL_CAP_ASYNC_SAFE (1 << 0) + + +typedef struct AVCodecHWConfigInternal { + /** + * This is the structure which will be returned to the user by + * avcodec_get_hw_config(). + */ + AVCodecHWConfig public; + /** + * If this configuration uses a hwaccel, a pointer to it. + * If not, NULL. + */ + const AVHWAccel *hwaccel; +} AVCodecHWConfigInternal; + + +// These macros are used to simplify AVCodecHWConfigInternal definitions. + +#define HW_CONFIG_HWACCEL(device, frames, ad_hoc, format, device_type_, name) \ + &(const AVCodecHWConfigInternal) { \ + .public = { \ + .pix_fmt = AV_PIX_FMT_ ## format, \ + .methods = (device ? AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX : 0) | \ + (frames ? AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX : 0) | \ + (ad_hoc ? AV_CODEC_HW_CONFIG_METHOD_AD_HOC : 0), \ + .device_type = AV_HWDEVICE_TYPE_ ## device_type_, \ + }, \ + .hwaccel = &name, \ + } + +#define HW_CONFIG_INTERNAL(format) \ + &(const AVCodecHWConfigInternal) { \ + .public = { \ + .pix_fmt = AV_PIX_FMT_ ## format, \ + .methods = AV_CODEC_HW_CONFIG_METHOD_INTERNAL, \ + .device_type = AV_HWDEVICE_TYPE_NONE, \ + }, \ + .hwaccel = NULL, \ + } + +#define HWACCEL_DXVA2(codec) \ + HW_CONFIG_HWACCEL(1, 1, 1, DXVA2_VLD, DXVA2, ff_ ## codec ## _dxva2_hwaccel) +#define HWACCEL_D3D11VA2(codec) \ + HW_CONFIG_HWACCEL(1, 1, 0, D3D11, D3D11VA, ff_ ## codec ## _d3d11va2_hwaccel) +#define HWACCEL_NVDEC(codec) \ + HW_CONFIG_HWACCEL(1, 1, 0, CUDA, CUDA, ff_ ## codec ## _nvdec_hwaccel) +#define HWACCEL_VAAPI(codec) \ + HW_CONFIG_HWACCEL(1, 1, 1, VAAPI, VAAPI, ff_ ## codec ## _vaapi_hwaccel) +#define HWACCEL_VDPAU(codec) \ + HW_CONFIG_HWACCEL(1, 1, 1, VDPAU, VDPAU, ff_ ## codec ## _vdpau_hwaccel) +#define HWACCEL_VIDEOTOOLBOX(codec) \ + HW_CONFIG_HWACCEL(1, 1, 1, VIDEOTOOLBOX, VIDEOTOOLBOX, ff_ ## codec ## _videotoolbox_hwaccel) +#define HWACCEL_D3D11VA(codec) \ + HW_CONFIG_HWACCEL(0, 0, 1, D3D11VA_VLD, NONE, ff_ ## codec ## _d3d11va_hwaccel) +#define HWACCEL_XVMC(codec) \ + HW_CONFIG_HWACCEL(0, 0, 1, XVMC, NONE, ff_ ## codec ## _xvmc_hwaccel) + +#endif /* AVCODEC_HWACCEL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hwaccels.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hwaccels.h new file mode 100644 index 0000000000..7d73da8676 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/hwaccels.h @@ -0,0 +1,78 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_HWACCELS_H +#define AVCODEC_HWACCELS_H + +#include "avcodec.h" + +extern const AVHWAccel ff_h263_vaapi_hwaccel; +extern const AVHWAccel ff_h263_videotoolbox_hwaccel; +extern const AVHWAccel ff_h264_d3d11va_hwaccel; +extern const AVHWAccel ff_h264_d3d11va2_hwaccel; +extern const AVHWAccel ff_h264_dxva2_hwaccel; +extern const AVHWAccel ff_h264_nvdec_hwaccel; +extern const AVHWAccel ff_h264_vaapi_hwaccel; +extern const AVHWAccel ff_h264_vdpau_hwaccel; +extern const AVHWAccel ff_h264_videotoolbox_hwaccel; +extern const AVHWAccel ff_hevc_d3d11va_hwaccel; +extern const AVHWAccel ff_hevc_d3d11va2_hwaccel; +extern const AVHWAccel ff_hevc_dxva2_hwaccel; +extern const AVHWAccel ff_hevc_nvdec_hwaccel; +extern const AVHWAccel ff_hevc_vaapi_hwaccel; +extern const AVHWAccel ff_hevc_vdpau_hwaccel; +extern const AVHWAccel ff_hevc_videotoolbox_hwaccel; +extern const AVHWAccel ff_mjpeg_nvdec_hwaccel; +extern const AVHWAccel ff_mjpeg_vaapi_hwaccel; +extern const AVHWAccel ff_mpeg1_nvdec_hwaccel; +extern const AVHWAccel ff_mpeg1_vdpau_hwaccel; +extern const AVHWAccel ff_mpeg1_videotoolbox_hwaccel; +extern const AVHWAccel ff_mpeg1_xvmc_hwaccel; +extern const AVHWAccel ff_mpeg2_d3d11va_hwaccel; +extern const AVHWAccel ff_mpeg2_d3d11va2_hwaccel; +extern const AVHWAccel ff_mpeg2_nvdec_hwaccel; +extern const AVHWAccel ff_mpeg2_dxva2_hwaccel; +extern const AVHWAccel ff_mpeg2_vaapi_hwaccel; +extern const AVHWAccel ff_mpeg2_vdpau_hwaccel; +extern const AVHWAccel ff_mpeg2_videotoolbox_hwaccel; +extern const AVHWAccel ff_mpeg2_xvmc_hwaccel; +extern const AVHWAccel ff_mpeg4_nvdec_hwaccel; +extern const AVHWAccel ff_mpeg4_vaapi_hwaccel; +extern const AVHWAccel ff_mpeg4_vdpau_hwaccel; +extern const AVHWAccel ff_mpeg4_videotoolbox_hwaccel; +extern const AVHWAccel ff_vc1_d3d11va_hwaccel; +extern const AVHWAccel ff_vc1_d3d11va2_hwaccel; +extern const AVHWAccel ff_vc1_dxva2_hwaccel; +extern const AVHWAccel ff_vc1_nvdec_hwaccel; +extern const AVHWAccel ff_vc1_vaapi_hwaccel; +extern const AVHWAccel ff_vc1_vdpau_hwaccel; +extern const AVHWAccel ff_vp8_nvdec_hwaccel; +extern const AVHWAccel ff_vp8_vaapi_hwaccel; +extern const AVHWAccel ff_vp9_d3d11va_hwaccel; +extern const AVHWAccel ff_vp9_d3d11va2_hwaccel; +extern const AVHWAccel ff_vp9_dxva2_hwaccel; +extern const AVHWAccel ff_vp9_nvdec_hwaccel; +extern const AVHWAccel ff_vp9_vaapi_hwaccel; +extern const AVHWAccel ff_wmv3_d3d11va_hwaccel; +extern const AVHWAccel ff_wmv3_d3d11va2_hwaccel; +extern const AVHWAccel ff_wmv3_dxva2_hwaccel; +extern const AVHWAccel ff_wmv3_nvdec_hwaccel; +extern const AVHWAccel ff_wmv3_vaapi_hwaccel; +extern const AVHWAccel ff_wmv3_vdpau_hwaccel; + +#endif /* AVCODEC_HWACCELS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/idctdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/idctdsp.h new file mode 100644 index 0000000000..ca21a31a02 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/idctdsp.h @@ -0,0 +1,122 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_IDCTDSP_H +#define AVCODEC_IDCTDSP_H + +#include + +#include "config.h" + +#include "avcodec.h" + +/** + * Scantable. + */ +typedef struct ScanTable { + const uint8_t *scantable; + uint8_t permutated[64]; + uint8_t raster_end[64]; +} ScanTable; + +enum idct_permutation_type { + FF_IDCT_PERM_NONE, + FF_IDCT_PERM_LIBMPEG2, + FF_IDCT_PERM_SIMPLE, + FF_IDCT_PERM_TRANSPOSE, + FF_IDCT_PERM_PARTTRANS, + FF_IDCT_PERM_SSE2, +}; + +void ff_init_scantable(uint8_t *permutation, ScanTable *st, + const uint8_t *src_scantable); +void ff_init_scantable_permutation(uint8_t *idct_permutation, + enum idct_permutation_type perm_type); +int ff_init_scantable_permutation_x86(uint8_t *idct_permutation, + enum idct_permutation_type perm_type); + +typedef struct IDCTDSPContext { + /* pixel ops : interface with DCT */ + void (*put_pixels_clamped)(const int16_t *block /* align 16 */, + uint8_t *av_restrict pixels /* align 8 */, + ptrdiff_t line_size); + void (*put_signed_pixels_clamped)(const int16_t *block /* align 16 */, + uint8_t *av_restrict pixels /* align 8 */, + ptrdiff_t line_size); + void (*add_pixels_clamped)(const int16_t *block /* align 16 */, + uint8_t *av_restrict pixels /* align 8 */, + ptrdiff_t line_size); + + void (*idct)(int16_t *block /* align 16 */); + + /** + * block -> idct -> clip to unsigned 8 bit -> dest. + * (-1392, 0, 0, ...) -> idct -> (-174, -174, ...) -> put -> (0, 0, ...) + * @param line_size size in bytes of a horizontal line of dest + */ + void (*idct_put)(uint8_t *dest /* align 8 */, + ptrdiff_t line_size, int16_t *block /* align 16 */); + + /** + * block -> idct -> add dest -> clip to unsigned 8 bit -> dest. + * @param line_size size in bytes of a horizontal line of dest + */ + void (*idct_add)(uint8_t *dest /* align 8 */, + ptrdiff_t line_size, int16_t *block /* align 16 */); + + /** + * IDCT input permutation. + * Several optimized IDCTs need a permutated input (relative to the + * normal order of the reference IDCT). + * This permutation must be performed before the idct_put/add. + * Note, normally this can be merged with the zigzag/alternate scan
      + * An example to avoid confusion: + * - (->decode coeffs -> zigzag reorder -> dequant -> reference IDCT -> ...) + * - (x -> reference DCT -> reference IDCT -> x) + * - (x -> reference DCT -> simple_mmx_perm = idct_permutation + * -> simple_idct_mmx -> x) + * - (-> decode coeffs -> zigzag reorder -> simple_mmx_perm -> dequant + * -> simple_idct_mmx -> ...) + */ + uint8_t idct_permutation[64]; + enum idct_permutation_type perm_type; + + int mpeg4_studio_profile; +} IDCTDSPContext; + +void ff_put_pixels_clamped_c(const int16_t *block, uint8_t *av_restrict pixels, + ptrdiff_t line_size); +void ff_add_pixels_clamped_c(const int16_t *block, uint8_t *av_restrict pixels, + ptrdiff_t line_size); + +void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx); + +void ff_idctdsp_init_aarch64(IDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); +void ff_idctdsp_init_alpha(IDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); +void ff_idctdsp_init_arm(IDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); +void ff_idctdsp_init_ppc(IDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); +void ff_idctdsp_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); +void ff_idctdsp_init_mips(IDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); + +#endif /* AVCODEC_IDCTDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/iirfilter.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/iirfilter.c new file mode 100644 index 0000000000..b202515827 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/iirfilter.c @@ -0,0 +1,327 @@ +/* + * IIR filter + * Copyright (c) 2008 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * different IIR filters implementation + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/common.h" + +#include "iirfilter.h" + +/** + * IIR filter global parameters + */ +typedef struct FFIIRFilterCoeffs { + int order; + float gain; + int *cx; + float *cy; +} FFIIRFilterCoeffs; + +/** + * IIR filter state + */ +typedef struct FFIIRFilterState { + float x[1]; +} FFIIRFilterState; + +/// maximum supported filter order +#define MAXORDER 30 + +static av_cold int butterworth_init_coeffs(void *avc, + struct FFIIRFilterCoeffs *c, + enum IIRFilterMode filt_mode, + int order, float cutoff_ratio, + float stopband) +{ + int i, j; + double wa; + double p[MAXORDER + 1][2]; + + if (filt_mode != FF_FILTER_MODE_LOWPASS) { + av_log(avc, AV_LOG_ERROR, "Butterworth filter currently only supports " + "low-pass filter mode\n"); + return -1; + } + if (order & 1) { + av_log(avc, AV_LOG_ERROR, "Butterworth filter currently only supports " + "even filter orders\n"); + return -1; + } + + wa = 2 * tan(M_PI * 0.5 * cutoff_ratio); + + c->cx[0] = 1; + for (i = 1; i < (order >> 1) + 1; i++) + c->cx[i] = c->cx[i - 1] * (order - i + 1LL) / i; + + p[0][0] = 1.0; + p[0][1] = 0.0; + for (i = 1; i <= order; i++) + p[i][0] = p[i][1] = 0.0; + for (i = 0; i < order; i++) { + double zp[2]; + double th = (i + (order >> 1) + 0.5) * M_PI / order; + double a_re, a_im, c_re, c_im; + zp[0] = cos(th) * wa; + zp[1] = sin(th) * wa; + a_re = zp[0] + 2.0; + c_re = zp[0] - 2.0; + a_im = + c_im = zp[1]; + zp[0] = (a_re * c_re + a_im * c_im) / (c_re * c_re + c_im * c_im); + zp[1] = (a_im * c_re - a_re * c_im) / (c_re * c_re + c_im * c_im); + + for (j = order; j >= 1; j--) { + a_re = p[j][0]; + a_im = p[j][1]; + p[j][0] = a_re * zp[0] - a_im * zp[1] + p[j - 1][0]; + p[j][1] = a_re * zp[1] + a_im * zp[0] + p[j - 1][1]; + } + a_re = p[0][0] * zp[0] - p[0][1] * zp[1]; + p[0][1] = p[0][0] * zp[1] + p[0][1] * zp[0]; + p[0][0] = a_re; + } + c->gain = p[order][0]; + for (i = 0; i < order; i++) { + c->gain += p[i][0]; + c->cy[i] = (-p[i][0] * p[order][0] + -p[i][1] * p[order][1]) / + (p[order][0] * p[order][0] + p[order][1] * p[order][1]); + } + c->gain /= 1 << order; + + return 0; +} + +static av_cold int biquad_init_coeffs(void *avc, struct FFIIRFilterCoeffs *c, + enum IIRFilterMode filt_mode, int order, + float cutoff_ratio, float stopband) +{ + double cos_w0, sin_w0; + double a0, x0, x1; + + if (filt_mode != FF_FILTER_MODE_HIGHPASS && + filt_mode != FF_FILTER_MODE_LOWPASS) { + av_log(avc, AV_LOG_ERROR, "Biquad filter currently only supports " + "high-pass and low-pass filter modes\n"); + return -1; + } + if (order != 2) { + av_log(avc, AV_LOG_ERROR, "Biquad filter must have order of 2\n"); + return -1; + } + + cos_w0 = cos(M_PI * cutoff_ratio); + sin_w0 = sin(M_PI * cutoff_ratio); + + a0 = 1.0 + (sin_w0 / 2.0); + + if (filt_mode == FF_FILTER_MODE_HIGHPASS) { + c->gain = ((1.0 + cos_w0) / 2.0) / a0; + x0 = ((1.0 + cos_w0) / 2.0) / a0; + x1 = (-(1.0 + cos_w0)) / a0; + } else { // FF_FILTER_MODE_LOWPASS + c->gain = ((1.0 - cos_w0) / 2.0) / a0; + x0 = ((1.0 - cos_w0) / 2.0) / a0; + x1 = (1.0 - cos_w0) / a0; + } + c->cy[0] = (-1.0 + (sin_w0 / 2.0)) / a0; + c->cy[1] = (2.0 * cos_w0) / a0; + + // divide by gain to make the x coeffs integers. + // during filtering, the delay state will include the gain multiplication + c->cx[0] = lrintf(x0 / c->gain); + c->cx[1] = lrintf(x1 / c->gain); + + return 0; +} + +av_cold struct FFIIRFilterCoeffs *ff_iir_filter_init_coeffs(void *avc, + enum IIRFilterType filt_type, + enum IIRFilterMode filt_mode, + int order, float cutoff_ratio, + float stopband, float ripple) +{ + FFIIRFilterCoeffs *c; + int ret = 0; + + if (order <= 0 || order > MAXORDER || cutoff_ratio >= 1.0) + return NULL; + + FF_ALLOCZ_OR_GOTO(avc, c, sizeof(FFIIRFilterCoeffs), + init_fail); + FF_ALLOC_OR_GOTO(avc, c->cx, sizeof(c->cx[0]) * ((order >> 1) + 1), + init_fail); + FF_ALLOC_OR_GOTO(avc, c->cy, sizeof(c->cy[0]) * order, + init_fail); + c->order = order; + + switch (filt_type) { + case FF_FILTER_TYPE_BUTTERWORTH: + ret = butterworth_init_coeffs(avc, c, filt_mode, order, cutoff_ratio, + stopband); + break; + case FF_FILTER_TYPE_BIQUAD: + ret = biquad_init_coeffs(avc, c, filt_mode, order, cutoff_ratio, + stopband); + break; + default: + av_log(avc, AV_LOG_ERROR, "filter type is not currently implemented\n"); + goto init_fail; + } + + if (!ret) + return c; + +init_fail: + ff_iir_filter_free_coeffsp(&c); + return NULL; +} + +av_cold struct FFIIRFilterState *ff_iir_filter_init_state(int order) +{ + FFIIRFilterState *s = av_mallocz(sizeof(FFIIRFilterState) + sizeof(s->x[0]) * (order - 1)); + return s; +} + +#define CONV_S16(dest, source) dest = av_clip_int16(lrintf(source)); + +#define CONV_FLT(dest, source) dest = source; + +#define FILTER_BW_O4_1(i0, i1, i2, i3, fmt) \ + in = *src0 * c->gain + \ + c->cy[0] * s->x[i0] + \ + c->cy[1] * s->x[i1] + \ + c->cy[2] * s->x[i2] + \ + c->cy[3] * s->x[i3]; \ + res = (s->x[i0] + in) * 1 + \ + (s->x[i1] + s->x[i3]) * 4 + \ + s->x[i2] * 6; \ + CONV_ ## fmt(*dst0, res) \ + s->x[i0] = in; \ + src0 += sstep; \ + dst0 += dstep; + +#define FILTER_BW_O4(type, fmt) { \ + int i; \ + const type *src0 = src; \ + type *dst0 = dst; \ + for (i = 0; i < size; i += 4) { \ + float in, res; \ + FILTER_BW_O4_1(0, 1, 2, 3, fmt); \ + FILTER_BW_O4_1(1, 2, 3, 0, fmt); \ + FILTER_BW_O4_1(2, 3, 0, 1, fmt); \ + FILTER_BW_O4_1(3, 0, 1, 2, fmt); \ + } \ +} + +#define FILTER_DIRECT_FORM_II(type, fmt) { \ + int i; \ + const type *src0 = src; \ + type *dst0 = dst; \ + for (i = 0; i < size; i++) { \ + int j; \ + float in, res; \ + in = *src0 * c->gain; \ + for (j = 0; j < c->order; j++) \ + in += c->cy[j] * s->x[j]; \ + res = s->x[0] + in + s->x[c->order >> 1] * c->cx[c->order >> 1]; \ + for (j = 1; j < c->order >> 1; j++) \ + res += (s->x[j] + s->x[c->order - j]) * c->cx[j]; \ + for (j = 0; j < c->order - 1; j++) \ + s->x[j] = s->x[j + 1]; \ + CONV_ ## fmt(*dst0, res) \ + s->x[c->order - 1] = in; \ + src0 += sstep; \ + dst0 += dstep; \ + } \ +} + +#define FILTER_O2(type, fmt) { \ + int i; \ + const type *src0 = src; \ + type *dst0 = dst; \ + for (i = 0; i < size; i++) { \ + float in = *src0 * c->gain + \ + s->x[0] * c->cy[0] + \ + s->x[1] * c->cy[1]; \ + CONV_ ## fmt(*dst0, s->x[0] + in + s->x[1] * c->cx[1]) \ + s->x[0] = s->x[1]; \ + s->x[1] = in; \ + src0 += sstep; \ + dst0 += dstep; \ + } \ +} + +void ff_iir_filter(const struct FFIIRFilterCoeffs *c, + struct FFIIRFilterState *s, int size, + const int16_t *src, ptrdiff_t sstep, + int16_t *dst, ptrdiff_t dstep) +{ + if (c->order == 2) { + FILTER_O2(int16_t, S16) + } else if (c->order == 4) { + FILTER_BW_O4(int16_t, S16) + } else { + FILTER_DIRECT_FORM_II(int16_t, S16) + } +} + +void ff_iir_filter_flt(const struct FFIIRFilterCoeffs *c, + struct FFIIRFilterState *s, int size, + const float *src, ptrdiff_t sstep, + float *dst, ptrdiff_t dstep) +{ + if (c->order == 2) { + FILTER_O2(float, FLT) + } else if (c->order == 4) { + FILTER_BW_O4(float, FLT) + } else { + FILTER_DIRECT_FORM_II(float, FLT) + } +} + +av_cold void ff_iir_filter_free_statep(struct FFIIRFilterState **state) +{ + av_freep(state); +} + +av_cold void ff_iir_filter_free_coeffsp(struct FFIIRFilterCoeffs **coeffsp) +{ + struct FFIIRFilterCoeffs *coeffs = *coeffsp; + if (coeffs) { + av_freep(&coeffs->cx); + av_freep(&coeffs->cy); + } + av_freep(coeffsp); +} + +void ff_iir_filter_init(FFIIRFilterContext *f) { + f->filter_flt = ff_iir_filter_flt; + + if (HAVE_MIPSFPU) + ff_iir_filter_init_mips(f); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/iirfilter.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/iirfilter.h new file mode 100644 index 0000000000..5ffa1ce53a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/iirfilter.h @@ -0,0 +1,147 @@ +/* + * IIR filter + * Copyright (c) 2008 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * IIR filter interface + */ + +#ifndef AVCODEC_IIRFILTER_H +#define AVCODEC_IIRFILTER_H + +#include +#include + +struct FFIIRFilterCoeffs; +struct FFIIRFilterState; + +enum IIRFilterType{ + FF_FILTER_TYPE_BESSEL, + FF_FILTER_TYPE_BIQUAD, + FF_FILTER_TYPE_BUTTERWORTH, + FF_FILTER_TYPE_CHEBYSHEV, + FF_FILTER_TYPE_ELLIPTIC, +}; + +enum IIRFilterMode{ + FF_FILTER_MODE_LOWPASS, + FF_FILTER_MODE_HIGHPASS, + FF_FILTER_MODE_BANDPASS, + FF_FILTER_MODE_BANDSTOP, +}; + +typedef struct FFIIRFilterContext { + /** + * Perform IIR filtering on floating-point input samples. + * + * @param coeffs pointer to filter coefficients + * @param state pointer to filter state + * @param size input length + * @param src source samples + * @param sstep source stride + * @param dst filtered samples (destination may be the same as input) + * @param dstep destination stride + */ + void (*filter_flt)(const struct FFIIRFilterCoeffs *coeffs, + struct FFIIRFilterState *state, int size, + const float *src, ptrdiff_t sstep, float *dst, ptrdiff_t dstep); +} FFIIRFilterContext; + +/** + * Initialize FFIIRFilterContext + */ +void ff_iir_filter_init(FFIIRFilterContext *f); +void ff_iir_filter_init_mips(FFIIRFilterContext *f); + +/** + * Initialize filter coefficients. + * + * @param avc a pointer to an arbitrary struct of which the first + * field is a pointer to an AVClass struct + * @param filt_type filter type (e.g. Butterworth) + * @param filt_mode filter mode (e.g. lowpass) + * @param order filter order + * @param cutoff_ratio cutoff to input frequency ratio + * @param stopband stopband to input frequency ratio (used by bandpass and bandstop filter modes) + * @param ripple ripple factor (used only in Chebyshev filters) + * + * @return pointer to filter coefficients structure or NULL if filter cannot be created + */ +struct FFIIRFilterCoeffs* ff_iir_filter_init_coeffs(void *avc, + enum IIRFilterType filt_type, + enum IIRFilterMode filt_mode, + int order, float cutoff_ratio, + float stopband, float ripple); + +/** + * Create new filter state. + * + * @param order filter order + * + * @return pointer to new filter state or NULL if state creation fails + */ +struct FFIIRFilterState* ff_iir_filter_init_state(int order); + +/** + * Free filter coefficients. + * + * @param coeffs pointer allocated with ff_iir_filter_init_coeffs() + */ +void ff_iir_filter_free_coeffsp(struct FFIIRFilterCoeffs **coeffs); + +/** + * Free and zero filter state. + * + * @param state pointer to pointer allocated with ff_iir_filter_init_state() + */ +void ff_iir_filter_free_statep(struct FFIIRFilterState **state); + +/** + * Perform IIR filtering on signed 16-bit input samples. + * + * @param coeffs pointer to filter coefficients + * @param state pointer to filter state + * @param size input length + * @param src source samples + * @param sstep source stride + * @param dst filtered samples (destination may be the same as input) + * @param dstep destination stride + */ +void ff_iir_filter(const struct FFIIRFilterCoeffs *coeffs, struct FFIIRFilterState *state, + int size, const int16_t *src, ptrdiff_t sstep, int16_t *dst, ptrdiff_t dstep); + +/** + * Perform IIR filtering on floating-point input samples. + * + * @param coeffs pointer to filter coefficients + * @param state pointer to filter state + * @param size input length + * @param src source samples + * @param sstep source stride + * @param dst filtered samples (destination may be the same as input) + * @param dstep destination stride + */ +void ff_iir_filter_flt(const struct FFIIRFilterCoeffs *coeffs, + struct FFIIRFilterState *state, int size, + const float *src, ptrdiff_t sstep, + float *dst, ptrdiff_t dstep); + +#endif /* AVCODEC_IIRFILTER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/imgconvert.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/imgconvert.c new file mode 100644 index 0000000000..1fd636c83d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/imgconvert.c @@ -0,0 +1,232 @@ +/* + * Misc image conversion routines + * Copyright (c) 2001, 2002, 2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * misc image conversion routines + */ + +#include "avcodec.h" +#include "internal.h" +#include "mathops.h" +#include "libavutil/avassert.h" +#include "libavutil/colorspace.h" +#include "libavutil/common.h" +#include "libavutil/pixdesc.h" +#include "libavutil/internal.h" +#include "libavutil/imgutils.h" + +#if FF_API_GETCHROMA +void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + *h_shift = desc->log2_chroma_w; + *v_shift = desc->log2_chroma_h; +} +#endif + +int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha) +{ + return av_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha); +} + +enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr) +{ + return av_find_best_pix_fmt_of_2(dst_pix_fmt1, dst_pix_fmt2, src_pix_fmt, has_alpha, loss_ptr); +} + +enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr) +{ + return avcodec_find_best_pix_fmt_of_2(dst_pix_fmt1, dst_pix_fmt2, src_pix_fmt, has_alpha, loss_ptr); +} + +enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr){ + int i; + + enum AVPixelFormat best = AV_PIX_FMT_NONE; + int loss; + + for (i=0; pix_fmt_list[i] != AV_PIX_FMT_NONE; i++) { + loss = loss_ptr ? *loss_ptr : 0; + best = avcodec_find_best_pix_fmt_of_2(best, pix_fmt_list[i], src_pix_fmt, has_alpha, &loss); + } + + if (loss_ptr) + *loss_ptr = loss; + return best; +} + +#if FF_API_AVPICTURE +FF_DISABLE_DEPRECATION_WARNINGS +/* return true if yuv planar */ +static inline int is_yuv_planar(const AVPixFmtDescriptor *desc) +{ + int i; + int planes[4] = { 0 }; + + if ( desc->flags & AV_PIX_FMT_FLAG_RGB + || !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) + return 0; + + /* set the used planes */ + for (i = 0; i < desc->nb_components; i++) + planes[desc->comp[i].plane] = 1; + + /* if there is an unused plane, the format is not planar */ + for (i = 0; i < desc->nb_components; i++) + if (!planes[i]) + return 0; + return 1; +} + +int av_picture_crop(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int top_band, int left_band) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int y_shift; + int x_shift; + int max_step[4]; + + if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB) + return -1; + + y_shift = desc->log2_chroma_h; + x_shift = desc->log2_chroma_w; + av_image_fill_max_pixsteps(max_step, NULL, desc); + + if (is_yuv_planar(desc)) { + dst->data[0] = src->data[0] + (top_band * src->linesize[0]) + left_band; + dst->data[1] = src->data[1] + ((top_band >> y_shift) * src->linesize[1]) + (left_band >> x_shift); + dst->data[2] = src->data[2] + ((top_band >> y_shift) * src->linesize[2]) + (left_band >> x_shift); + } else{ + if(top_band % (1<data[0] = src->data[0] + (top_band * src->linesize[0]) + (left_band * max_step[0]); + } + + dst->linesize[0] = src->linesize[0]; + dst->linesize[1] = src->linesize[1]; + dst->linesize[2] = src->linesize[2]; + return 0; +} + +int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, + enum AVPixelFormat pix_fmt, int padtop, int padbottom, int padleft, int padright, + int *color) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + uint8_t *optr; + int y_shift; + int x_shift; + int yheight; + int i, y; + int max_step[4]; + + if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB) + return -1; + + if (!is_yuv_planar(desc)) { + if (src) + return -1; //TODO: Not yet implemented + + av_image_fill_max_pixsteps(max_step, NULL, desc); + + if (padtop || padleft) { + memset(dst->data[0], color[0], + dst->linesize[0] * padtop + (padleft * max_step[0])); + } + + if (padleft || padright) { + optr = dst->data[0] + dst->linesize[0] * padtop + + (dst->linesize[0] - (padright * max_step[0])); + yheight = height - 1 - (padtop + padbottom); + for (y = 0; y < yheight; y++) { + memset(optr, color[0], (padleft + padright) * max_step[0]); + optr += dst->linesize[0]; + } + } + + if (padbottom || padright) { + optr = dst->data[0] + dst->linesize[0] * (height - padbottom) - + (padright * max_step[0]); + memset(optr, color[0], dst->linesize[0] * padbottom + + (padright * max_step[0])); + } + + return 0; + } + + for (i = 0; i < 3; i++) { + x_shift = i ? desc->log2_chroma_w : 0; + y_shift = i ? desc->log2_chroma_h : 0; + + if (padtop || padleft) { + memset(dst->data[i], color[i], + dst->linesize[i] * (padtop >> y_shift) + (padleft >> x_shift)); + } + + if (padleft || padright) { + optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) + + (dst->linesize[i] - (padright >> x_shift)); + yheight = (height - 1 - (padtop + padbottom)) >> y_shift; + for (y = 0; y < yheight; y++) { + memset(optr, color[i], (padleft + padright) >> x_shift); + optr += dst->linesize[i]; + } + } + + if (src) { /* first line */ + uint8_t *iptr = src->data[i]; + optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) + + (padleft >> x_shift); + memcpy(optr, iptr, (width - padleft - padright) >> x_shift); + iptr += src->linesize[i]; + optr = dst->data[i] + dst->linesize[i] * (padtop >> y_shift) + + (dst->linesize[i] - (padright >> x_shift)); + yheight = (height - 1 - (padtop + padbottom)) >> y_shift; + for (y = 0; y < yheight; y++) { + memset(optr, color[i], (padleft + padright) >> x_shift); + memcpy(optr + ((padleft + padright) >> x_shift), iptr, + (width - padleft - padright) >> x_shift); + iptr += src->linesize[i]; + optr += dst->linesize[i]; + } + } + + if (padbottom || padright) { + optr = dst->data[i] + dst->linesize[i] * + ((height - padbottom) >> y_shift) - (padright >> x_shift); + memset(optr, color[i],dst->linesize[i] * + (padbottom >> y_shift) + (padright >> x_shift)); + } + } + + return 0; +} +FF_ENABLE_DEPRECATION_WARNINGS +#endif /* FF_API_AVPICTURE */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/internal.h new file mode 100644 index 0000000000..5096ffa1d9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/internal.h @@ -0,0 +1,433 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal api header. + */ + +#ifndef AVCODEC_INTERNAL_H +#define AVCODEC_INTERNAL_H + +#include + +#include "libavutil/buffer.h" +#include "libavutil/channel_layout.h" +#include "libavutil/mathematics.h" +#include "libavutil/pixfmt.h" +#include "avcodec.h" +#include "config.h" + +/** + * The codec does not modify any global variables in the init function, + * allowing to call the init function without locking any global mutexes. + */ +#define FF_CODEC_CAP_INIT_THREADSAFE (1 << 0) +/** + * The codec allows calling the close function for deallocation even if + * the init function returned a failure. Without this capability flag, a + * codec does such cleanup internally when returning failures from the + * init function and does not expect the close function to be called at + * all. + */ +#define FF_CODEC_CAP_INIT_CLEANUP (1 << 1) +/** + * Decoders marked with FF_CODEC_CAP_SETS_PKT_DTS want to set + * AVFrame.pkt_dts manually. If the flag is set, decode.c won't overwrite + * this field. If it's unset, decode.c tries to guess the pkt_dts field + * from the input AVPacket. + */ +#define FF_CODEC_CAP_SETS_PKT_DTS (1 << 2) +/** + * The decoder extracts and fills its parameters even if the frame is + * skipped due to the skip_frame setting. + */ +#define FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM (1 << 3) +/** + * The decoder sets the cropping fields in the output frames manually. + * If this cap is set, the generic code will initialize output frame + * dimensions to coded rather than display values. + */ +#define FF_CODEC_CAP_EXPORTS_CROPPING (1 << 4) +/** + * Codec initializes slice-based threading with a main function + */ +#define FF_CODEC_CAP_SLICE_THREAD_HAS_MF (1 << 5) + +#ifdef TRACE +# define ff_tlog(ctx, ...) av_log(ctx, AV_LOG_TRACE, __VA_ARGS__) +#else +# define ff_tlog(ctx, ...) do { } while(0) +#endif + + +#define FF_DEFAULT_QUANT_BIAS 999999 + +#define FF_QSCALE_TYPE_MPEG1 0 +#define FF_QSCALE_TYPE_MPEG2 1 +#define FF_QSCALE_TYPE_H264 2 +#define FF_QSCALE_TYPE_VP56 3 + +#define FF_SANE_NB_CHANNELS 256U + +#define FF_SIGNBIT(x) ((x) >> CHAR_BIT * sizeof(x) - 1) + +#if HAVE_SIMD_ALIGN_64 +# define STRIDE_ALIGN 64 /* AVX-512 */ +#elif HAVE_SIMD_ALIGN_32 +# define STRIDE_ALIGN 32 +#elif HAVE_SIMD_ALIGN_16 +# define STRIDE_ALIGN 16 +#else +# define STRIDE_ALIGN 8 +#endif + +typedef struct FramePool { + /** + * Pools for each data plane. For audio all the planes have the same size, + * so only pools[0] is used. + */ + AVBufferPool *pools[4]; + + /* + * Pool parameters + */ + int format; + int width, height; + int stride_align[AV_NUM_DATA_POINTERS]; + int linesize[4]; + int planes; + int channels; + int samples; +} FramePool; + +typedef struct DecodeSimpleContext { + AVPacket *in_pkt; + AVFrame *out_frame; +} DecodeSimpleContext; + +typedef struct DecodeFilterContext { + AVBSFContext **bsfs; + int nb_bsfs; +} DecodeFilterContext; + +typedef struct AVCodecInternal { + /** + * Whether the parent AVCodecContext is a copy of the context which had + * init() called on it. + * This is used by multithreading - shared tables and picture pointers + * should be freed from the original context only. + */ + int is_copy; + + /** + * Whether to allocate progress for frame threading. + * + * The codec must set it to 1 if it uses ff_thread_await/report_progress(), + * then progress will be allocated in ff_thread_get_buffer(). The frames + * then MUST be freed with ff_thread_release_buffer(). + * + * If the codec does not need to call the progress functions (there are no + * dependencies between the frames), it should leave this at 0. Then it can + * decode straight to the user-provided frames (which the user will then + * free with av_frame_unref()), there is no need to call + * ff_thread_release_buffer(). + */ + int allocate_progress; + + /** + * An audio frame with less than required samples has been submitted and + * padded with silence. Reject all subsequent frames. + */ + int last_audio_frame; + + AVFrame *to_free; + + FramePool *pool; + + void *thread_ctx; + + DecodeSimpleContext ds; + DecodeFilterContext filter; + + /** + * Properties (timestamps+side data) extracted from the last packet passed + * for decoding. + */ + AVPacket *last_pkt_props; + + /** + * temporary buffer used for encoders to store their bitstream + */ + uint8_t *byte_buffer; + unsigned int byte_buffer_size; + + void *frame_thread_encoder; + + /** + * Number of audio samples to skip at the start of the next decoded frame + */ + int skip_samples; + + /** + * hwaccel-specific private data + */ + void *hwaccel_priv_data; + + /** + * checks API usage: after codec draining, flush is required to resume operation + */ + int draining; + + /** + * buffers for using new encode/decode API through legacy API + */ + AVPacket *buffer_pkt; + int buffer_pkt_valid; // encoding: packet without data can be valid + AVFrame *buffer_frame; + int draining_done; + /* set to 1 when the caller is using the old decoding API */ + int compat_decode; + int compat_decode_warned; + /* this variable is set by the decoder internals to signal to the old + * API compat wrappers the amount of data consumed from the last packet */ + size_t compat_decode_consumed; + /* when a partial packet has been consumed, this stores the remaining size + * of the packet (that should be submitted in the next decode call */ + size_t compat_decode_partial_size; + AVFrame *compat_decode_frame; + + int showed_multi_packet_warning; + + int skip_samples_multiplier; + + /* to prevent infinite loop on errors when draining */ + int nb_draining_errors; + + /* used when avctx flag AV_CODEC_FLAG_DROPCHANGED is set */ + int changed_frames_dropped; + int initial_format; + int initial_width, initial_height; + int initial_sample_rate; + int initial_channels; + uint64_t initial_channel_layout; +} AVCodecInternal; + +struct AVCodecDefault { + const uint8_t *key; + const uint8_t *value; +}; + +extern const uint8_t ff_log2_run[41]; + +/** + * Return the index into tab at which {a,b} match elements {[0],[1]} of tab. + * If there is no such matching pair then size is returned. + */ +int ff_match_2uint16(const uint16_t (*tab)[2], int size, int a, int b); + +unsigned int avpriv_toupper4(unsigned int x); + +void ff_color_frame(AVFrame *frame, const int color[4]); + +/** + * Maximum size in bytes of extradata. + * This value was chosen such that every bit of the buffer is + * addressable by a 32-bit signed integer as used by get_bits. + */ +#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) + +/** + * Check AVPacket size and/or allocate data. + * + * Encoders supporting AVCodec.encode2() can use this as a convenience to + * ensure the output packet data is large enough, whether provided by the user + * or allocated in this function. + * + * @param avctx the AVCodecContext of the encoder + * @param avpkt the AVPacket + * If avpkt->data is already set, avpkt->size is checked + * to ensure it is large enough. + * If avpkt->data is NULL, a new buffer is allocated. + * avpkt->size is set to the specified size. + * All other AVPacket fields will be reset with av_init_packet(). + * @param size the minimum required packet size + * @param min_size This is a hint to the allocation algorithm, which indicates + * to what minimal size the caller might later shrink the packet + * to. Encoders often allocate packets which are larger than the + * amount of data that is written into them as the exact amount is + * not known at the time of allocation. min_size represents the + * size a packet might be shrunk to by the caller. Can be set to + * 0. setting this roughly correctly allows the allocation code + * to choose between several allocation strategies to improve + * speed slightly. + * @return non negative on success, negative error code on failure + */ +int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int64_t min_size); + +attribute_deprecated int ff_alloc_packet(AVPacket *avpkt, int size); + +/** + * Rescale from sample rate to AVCodecContext.time_base. + */ +static av_always_inline int64_t ff_samples_to_time_base(AVCodecContext *avctx, + int64_t samples) +{ + if(samples == AV_NOPTS_VALUE) + return AV_NOPTS_VALUE; + return av_rescale_q(samples, (AVRational){ 1, avctx->sample_rate }, + avctx->time_base); +} + +/** + * 2^(x) for integer x + * @return correctly rounded float + */ +static av_always_inline float ff_exp2fi(int x) { + /* Normal range */ + if (-126 <= x && x <= 128) + return av_int2float((x+127) << 23); + /* Too large */ + else if (x > 128) + return INFINITY; + /* Subnormal numbers */ + else if (x > -150) + return av_int2float(1 << (x+149)); + /* Negligibly small */ + else + return 0; +} + +/** + * Get a buffer for a frame. This is a wrapper around + * AVCodecContext.get_buffer() and should be used instead calling get_buffer() + * directly. + */ +int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags); + +/** + * Identical in function to av_frame_make_writable(), except it uses + * ff_get_buffer() to allocate the buffer when needed. + */ +int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame); + +int ff_thread_can_start_frame(AVCodecContext *avctx); + +int avpriv_h264_has_num_reorder_frames(AVCodecContext *avctx); + +/** + * Call avcodec_open2 recursively by decrementing counter, unlocking mutex, + * calling the function and then restoring again. Assumes the mutex is + * already locked + */ +int ff_codec_open2_recursive(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); + +/** + * Finalize buf into extradata and set its size appropriately. + */ +int avpriv_bprint_to_extradata(AVCodecContext *avctx, struct AVBPrint *buf); + +const uint8_t *avpriv_find_start_code(const uint8_t *p, + const uint8_t *end, + uint32_t *state); + +int avpriv_codec_get_cap_skip_frame_fill_param(const AVCodec *codec); + +/** + * Check that the provided frame dimensions are valid and set them on the codec + * context. + */ +int ff_set_dimensions(AVCodecContext *s, int width, int height); + +/** + * Check that the provided sample aspect ratio is valid and set it on the codec + * context. + */ +int ff_set_sar(AVCodecContext *avctx, AVRational sar); + +/** + * Add or update AV_FRAME_DATA_MATRIXENCODING side data. + */ +int ff_side_data_update_matrix_encoding(AVFrame *frame, + enum AVMatrixEncoding matrix_encoding); + +/** + * Select the (possibly hardware accelerated) pixel format. + * This is a wrapper around AVCodecContext.get_format() and should be used + * instead of calling get_format() directly. + * + * The list of pixel formats must contain at least one valid entry, and is + * terminated with AV_PIX_FMT_NONE. If it is possible to decode to software, + * the last entry in the list must be the most accurate software format. + * If it is not possible to decode to software, AVCodecContext.sw_pix_fmt + * must be set before calling this function. + */ +int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt); + +/** + * Set various frame properties from the codec context / packet data. + */ +int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame); + +/** + * Add a CPB properties side data to an encoding context. + */ +AVCPBProperties *ff_add_cpb_side_data(AVCodecContext *avctx); + +int ff_side_data_set_encoder_stats(AVPacket *pkt, int quality, int64_t *error, int error_count, int pict_type); + +/** + * Check AVFrame for A53 side data and allocate and fill SEI message with A53 info + * + * @param frame Raw frame to get A53 side data from + * @param prefix_len Number of bytes to allocate before SEI message + * @param data Pointer to a variable to store allocated memory + * Upon return the variable will hold NULL on error or if frame has no A53 info. + * Otherwise it will point to prefix_len uninitialized bytes followed by + * *sei_size SEI message + * @param sei_size Pointer to a variable to store generated SEI message length + * @return Zero on success, negative error code on failure + */ +int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len, + void **data, size_t *sei_size); + +/** + * Get an estimated video bitrate based on frame size, frame rate and coded + * bits per pixel. + */ +int64_t ff_guess_coded_bitrate(AVCodecContext *avctx); + +/** + * Check if a value is in the list. If not, return the default value + * + * @param ctx Context for the log msg + * @param val_name Name of the checked value, for log msg + * @param array_valid_values Array of valid int, ended with INT_MAX + * @param default_value Value return if checked value is not in the array + * @return Value or default_value. + */ +int ff_int_from_list_or_default(void *ctx, const char * val_name, int val, + const int * array_valid_values, int default_value); + +#if defined(_WIN32) && CONFIG_SHARED && !defined(BUILDING_avcodec) +# define av_export_avcodec __declspec(dllimport) +#else +# define av_export_avcodec +#endif + +#endif /* AVCODEC_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/jni.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/jni.c new file mode 100644 index 0000000000..85dcf2abaf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/jni.c @@ -0,0 +1,79 @@ +/* + * JNI public API functions + * + * Copyright (c) 2015-2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include + +#include "libavutil/error.h" +#include "jni.h" + +#if CONFIG_JNI +#include +#include + +#include "libavutil/log.h" +#include "ffjni.h" + +void *java_vm; +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +int av_jni_set_java_vm(void *vm, void *log_ctx) +{ + int ret = 0; + + pthread_mutex_lock(&lock); + if (java_vm == NULL) { + java_vm = vm; + } else if (java_vm != vm) { + ret = AVERROR(EINVAL); + av_log(log_ctx, AV_LOG_ERROR, "A Java virtual machine has already been set"); + } + pthread_mutex_unlock(&lock); + + return ret; +} + +void *av_jni_get_java_vm(void *log_ctx) +{ + void *vm; + + pthread_mutex_lock(&lock); + vm = java_vm; + pthread_mutex_unlock(&lock); + + return vm; +} + +#else + +int av_jni_set_java_vm(void *vm, void *log_ctx) +{ + return AVERROR(ENOSYS); +} + +void *av_jni_get_java_vm(void *log_ctx) +{ + return NULL; +} + +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/jni.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/jni.h new file mode 100644 index 0000000000..dd99e92611 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/jni.h @@ -0,0 +1,46 @@ +/* + * JNI public API functions + * + * Copyright (c) 2015-2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_JNI_H +#define AVCODEC_JNI_H + +/* + * Manually set a Java virtual machine which will be used to retrieve the JNI + * environment. Once a Java VM is set it cannot be changed afterwards, meaning + * you can call multiple times av_jni_set_java_vm with the same Java VM pointer + * however it will error out if you try to set a different Java VM. + * + * @param vm Java virtual machine + * @param log_ctx context used for logging, can be NULL + * @return 0 on success, < 0 otherwise + */ +int av_jni_set_java_vm(void *vm, void *log_ctx); + +/* + * Get the Java virtual machine which has been set with av_jni_set_java_vm. + * + * @param vm Java virtual machine + * @return a pointer to the Java virtual machine + */ +void *av_jni_get_java_vm(void *log_ctx); + +#endif /* AVCODEC_JNI_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/kbdwin.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/kbdwin.c new file mode 100644 index 0000000000..bf32aeb317 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/kbdwin.c @@ -0,0 +1,57 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/mathematics.h" +#include "libavutil/attributes.h" +#include "kbdwin.h" + +#define BESSEL_I0_ITER 50 // default: 50 iterations of Bessel I0 approximation + +av_cold void ff_kbd_window_init(float *window, float alpha, int n) +{ + int i, j; + double sum = 0.0, bessel, tmp; + double local_window[FF_KBD_WINDOW_MAX]; + double alpha2 = (alpha * M_PI / n) * (alpha * M_PI / n); + + av_assert0(n <= FF_KBD_WINDOW_MAX); + + for (i = 0; i < n; i++) { + tmp = i * (n - i) * alpha2; + bessel = 1.0; + for (j = BESSEL_I0_ITER; j > 0; j--) + bessel = bessel * tmp / (j * j) + 1; + sum += bessel; + local_window[i] = sum; + } + + sum++; + for (i = 0; i < n; i++) + window[i] = sqrt(local_window[i] / sum); +} + +av_cold void ff_kbd_window_init_fixed(int32_t *window, float alpha, int n) +{ + int i; + float local_window[FF_KBD_WINDOW_MAX]; + + ff_kbd_window_init(local_window, alpha, n); + for (i = 0; i < n; i++) + window[i] = (int)floor(2147483647.0 * local_window[i] + 0.5); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/kbdwin.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/kbdwin.h new file mode 100644 index 0000000000..4185c4206f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/kbdwin.h @@ -0,0 +1,38 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_KBDWIN_H +#define AVCODEC_KBDWIN_H + +#include + +/** + * Maximum window size for ff_kbd_window_init. + */ +#define FF_KBD_WINDOW_MAX 1024 + +/** + * Generate a Kaiser-Bessel Derived Window. + * @param window pointer to half window + * @param alpha determines window shape + * @param n size of half window, max FF_KBD_WINDOW_MAX + */ +void ff_kbd_window_init(float *window, float alpha, int n); +void ff_kbd_window_init_fixed(int32_t *window, float alpha, int n); + +#endif /* AVCODEC_KBDWIN_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/latm_parser.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/latm_parser.c new file mode 100644 index 0000000000..3820f58d69 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/latm_parser.c @@ -0,0 +1,112 @@ +/* + * copyright (c) 2008 Paul Kendall + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AAC LATM parser + */ + +#include +#include "parser.h" + +#define LATM_HEADER 0x56e000 // 0x2b7 (11 bits) +#define LATM_MASK 0xFFE000 // top 11 bits +#define LATM_SIZE_MASK 0x001FFF // bottom 13 bits + +typedef struct LATMParseContext{ + ParseContext pc; + int count; +} LATMParseContext; + +/** + * Find the end of the current frame in the bitstream. + * @return the position of the first byte of the next frame, or -1 + */ +static int latm_find_frame_end(AVCodecParserContext *s1, const uint8_t *buf, + int buf_size) +{ + LATMParseContext *s = s1->priv_data; + ParseContext *pc = &s->pc; + int pic_found, i; + uint32_t state; + + pic_found = pc->frame_start_found; + state = pc->state; + + if (!pic_found) { + for (i = 0; i < buf_size; i++) { + state = (state<<8) | buf[i]; + if ((state & LATM_MASK) == LATM_HEADER) { + i++; + s->count = -i; + pic_found = 1; + break; + } + } + } + + if (pic_found) { + /* EOF considered as end of frame */ + if (buf_size == 0) + return 0; + if ((state & LATM_SIZE_MASK) - s->count <= buf_size) { + pc->frame_start_found = 0; + pc->state = -1; + return (state & LATM_SIZE_MASK) - s->count; + } + } + + s->count += buf_size; + pc->frame_start_found = pic_found; + pc->state = state; + + return END_NOT_FOUND; +} + +static int latm_parse(AVCodecParserContext *s1, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + LATMParseContext *s = s1->priv_data; + ParseContext *pc = &s->pc; + int next; + + if (s1->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + next = latm_find_frame_end(s1, buf, buf_size); + + if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + } + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +AVCodecParser ff_aac_latm_parser = { + .codec_ids = { AV_CODEC_ID_AAC_LATM }, + .priv_data_size = sizeof(LATMParseContext), + .parser_parse = latm_parse, + .parser_close = ff_parse_close +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopus.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopus.c new file mode 100644 index 0000000000..16395c73df --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopus.c @@ -0,0 +1,48 @@ +/* + * libopus encoder/decoder common code + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/error.h" +#include "libopus.h" + +int ff_opus_error_to_averror(int err) +{ + switch (err) { + case OPUS_BAD_ARG: + return AVERROR(EINVAL); + case OPUS_BUFFER_TOO_SMALL: + return AVERROR_UNKNOWN; + case OPUS_INTERNAL_ERROR: + return AVERROR(EFAULT); + case OPUS_INVALID_PACKET: + return AVERROR_INVALIDDATA; + case OPUS_UNIMPLEMENTED: + return AVERROR(ENOSYS); + case OPUS_INVALID_STATE: + return AVERROR_UNKNOWN; + case OPUS_ALLOC_FAIL: + return AVERROR(ENOMEM); + default: + return AVERROR(EINVAL); + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopus.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopus.h new file mode 100644 index 0000000000..a8223d1d6f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopus.h @@ -0,0 +1,27 @@ +/* + * libopus encoder/decoder common code + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_LIBOPUS_H +#define AVCODEC_LIBOPUS_H + +int ff_opus_error_to_averror(int err); + +#endif /* AVCODEC_LIBOPUS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopusdec.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopusdec.c new file mode 100644 index 0000000000..1724a49906 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopusdec.c @@ -0,0 +1,245 @@ +/* + * Opus decoder using libopus + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavutil/internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/ffmath.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "internal.h" +#include "vorbis.h" +#include "mathops.h" +#include "libopus.h" + +struct libopus_context { + AVClass *class; + OpusMSDecoder *dec; + int pre_skip; +#ifndef OPUS_SET_GAIN + union { int i; double d; } gain; +#endif +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + int apply_phase_inv; +#endif +}; + +#define OPUS_HEAD_SIZE 19 + +static av_cold int libopus_decode_init(AVCodecContext *avc) +{ + struct libopus_context *opus = avc->priv_data; + int ret, channel_map = 0, gain_db = 0, nb_streams, nb_coupled; + uint8_t mapping_arr[8] = { 0, 1 }, *mapping; + + avc->channels = avc->extradata_size >= 10 ? avc->extradata[9] : (avc->channels == 1) ? 1 : 2; + if (avc->channels <= 0) { + av_log(avc, AV_LOG_WARNING, + "Invalid number of channels %d, defaulting to stereo\n", avc->channels); + avc->channels = 2; + } + + avc->sample_rate = 48000; + avc->sample_fmt = avc->request_sample_fmt == AV_SAMPLE_FMT_FLT ? + AV_SAMPLE_FMT_FLT : AV_SAMPLE_FMT_S16; + avc->channel_layout = avc->channels > 8 ? 0 : + ff_vorbis_channel_layouts[avc->channels - 1]; + + if (avc->extradata_size >= OPUS_HEAD_SIZE) { + opus->pre_skip = AV_RL16(avc->extradata + 10); + gain_db = sign_extend(AV_RL16(avc->extradata + 16), 16); + channel_map = AV_RL8 (avc->extradata + 18); + } + if (avc->extradata_size >= OPUS_HEAD_SIZE + 2 + avc->channels) { + nb_streams = avc->extradata[OPUS_HEAD_SIZE + 0]; + nb_coupled = avc->extradata[OPUS_HEAD_SIZE + 1]; + if (nb_streams + nb_coupled != avc->channels) + av_log(avc, AV_LOG_WARNING, "Inconsistent channel mapping.\n"); + mapping = avc->extradata + OPUS_HEAD_SIZE + 2; + } else { + if (avc->channels > 2 || channel_map) { + av_log(avc, AV_LOG_ERROR, + "No channel mapping for %d channels.\n", avc->channels); + return AVERROR(EINVAL); + } + nb_streams = 1; + nb_coupled = avc->channels > 1; + mapping = mapping_arr; + } + + if (avc->channels > 2 && avc->channels <= 8) { + const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[avc->channels - 1]; + int ch; + + /* Remap channels from Vorbis order to ffmpeg order */ + for (ch = 0; ch < avc->channels; ch++) + mapping_arr[ch] = mapping[vorbis_offset[ch]]; + mapping = mapping_arr; + } + + opus->dec = opus_multistream_decoder_create(avc->sample_rate, avc->channels, + nb_streams, nb_coupled, + mapping, &ret); + if (!opus->dec) { + av_log(avc, AV_LOG_ERROR, "Unable to create decoder: %s\n", + opus_strerror(ret)); + return ff_opus_error_to_averror(ret); + } + +#ifdef OPUS_SET_GAIN + ret = opus_multistream_decoder_ctl(opus->dec, OPUS_SET_GAIN(gain_db)); + if (ret != OPUS_OK) + av_log(avc, AV_LOG_WARNING, "Failed to set gain: %s\n", + opus_strerror(ret)); +#else + { + double gain_lin = ff_exp10(gain_db / (20.0 * 256)); + if (avc->sample_fmt == AV_SAMPLE_FMT_FLT) + opus->gain.d = gain_lin; + else + opus->gain.i = FFMIN(gain_lin * 65536, INT_MAX); + } +#endif + +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + ret = opus_multistream_decoder_ctl(opus->dec, + OPUS_SET_PHASE_INVERSION_DISABLED(!opus->apply_phase_inv)); + if (ret != OPUS_OK) + av_log(avc, AV_LOG_WARNING, + "Unable to set phase inversion: %s\n", + opus_strerror(ret)); +#endif + + /* Decoder delay (in samples) at 48kHz */ + avc->delay = avc->internal->skip_samples = opus->pre_skip; + + return 0; +} + +static av_cold int libopus_decode_close(AVCodecContext *avc) +{ + struct libopus_context *opus = avc->priv_data; + + if (opus->dec) { + opus_multistream_decoder_destroy(opus->dec); + opus->dec = NULL; + } + return 0; +} + +#define MAX_FRAME_SIZE (960 * 6) + +static int libopus_decode(AVCodecContext *avc, void *data, + int *got_frame_ptr, AVPacket *pkt) +{ + struct libopus_context *opus = avc->priv_data; + AVFrame *frame = data; + int ret, nb_samples; + + frame->nb_samples = MAX_FRAME_SIZE; + if ((ret = ff_get_buffer(avc, frame, 0)) < 0) + return ret; + + if (avc->sample_fmt == AV_SAMPLE_FMT_S16) + nb_samples = opus_multistream_decode(opus->dec, pkt->data, pkt->size, + (opus_int16 *)frame->data[0], + frame->nb_samples, 0); + else + nb_samples = opus_multistream_decode_float(opus->dec, pkt->data, pkt->size, + (float *)frame->data[0], + frame->nb_samples, 0); + + if (nb_samples < 0) { + av_log(avc, AV_LOG_ERROR, "Decoding error: %s\n", + opus_strerror(nb_samples)); + return ff_opus_error_to_averror(nb_samples); + } + +#ifndef OPUS_SET_GAIN + { + int i = avc->channels * nb_samples; + if (avc->sample_fmt == AV_SAMPLE_FMT_FLT) { + float *pcm = (float *)frame->data[0]; + for (; i > 0; i--, pcm++) + *pcm = av_clipf(*pcm * opus->gain.d, -1, 1); + } else { + int16_t *pcm = (int16_t *)frame->data[0]; + for (; i > 0; i--, pcm++) + *pcm = av_clip_int16(((int64_t)opus->gain.i * *pcm) >> 16); + } + } +#endif + + frame->nb_samples = nb_samples; + *got_frame_ptr = 1; + + return pkt->size; +} + +static void libopus_flush(AVCodecContext *avc) +{ + struct libopus_context *opus = avc->priv_data; + + opus_multistream_decoder_ctl(opus->dec, OPUS_RESET_STATE); + /* The stream can have been extracted by a tool that is not Opus-aware. + Therefore, any packet can become the first of the stream. */ + avc->internal->skip_samples = opus->pre_skip; +} + + +#define OFFSET(x) offsetof(struct libopus_context, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption libopusdec_options[] = { +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + { "apply_phase_inv", "Apply intensity stereo phase inversion", OFFSET(apply_phase_inv), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, +#endif + { NULL }, +}; + +static const AVClass libopusdec_class = { + .class_name = "libopusdec", + .item_name = av_default_item_name, + .option = libopusdec_options, + .version = LIBAVUTIL_VERSION_INT, +}; + + +AVCodec ff_libopus_decoder = { + .name = "libopus", + .long_name = NULL_IF_CONFIG_SMALL("libopus Opus"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_OPUS, + .priv_data_size = sizeof(struct libopus_context), + .init = libopus_decode_init, + .close = libopus_decode_close, + .decode = libopus_decode, + .flush = libopus_flush, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_NONE }, + .priv_class = &libopusdec_class, + .wrapper_name = "libopus", +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopusenc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopusenc.c new file mode 100644 index 0000000000..7c025a66d7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/libopusenc.c @@ -0,0 +1,594 @@ +/* + * Opus encoder using libopus + * Copyright (c) 2012 Nathan Caldwell + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavutil/opt.h" +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" +#include "libopus.h" +#include "vorbis.h" +#include "audio_frame_queue.h" + +typedef struct LibopusEncOpts { + int vbr; + int application; + int packet_loss; + int complexity; + float frame_duration; + int packet_size; + int max_bandwidth; + int mapping_family; +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + int apply_phase_inv; +#endif +} LibopusEncOpts; + +typedef struct LibopusEncContext { + AVClass *class; + OpusMSEncoder *enc; + int stream_count; + uint8_t *samples; + LibopusEncOpts opts; + AudioFrameQueue afq; + const uint8_t *encoder_channel_map; +} LibopusEncContext; + +static const uint8_t opus_coupled_streams[8] = { + 0, 1, 1, 2, 2, 2, 2, 3 +}; + +/* Opus internal to Vorbis channel order mapping written in the header */ +static const uint8_t opus_vorbis_channel_map[8][8] = { + { 0 }, + { 0, 1 }, + { 0, 2, 1 }, + { 0, 1, 2, 3 }, + { 0, 4, 1, 2, 3 }, + { 0, 4, 1, 2, 3, 5 }, + { 0, 4, 1, 2, 3, 5, 6 }, + { 0, 6, 1, 2, 3, 4, 5, 7 }, +}; + +/* libavcodec to libopus channel order mapping, passed to libopus */ +static const uint8_t libavcodec_libopus_channel_map[8][8] = { + { 0 }, + { 0, 1 }, + { 0, 1, 2 }, + { 0, 1, 2, 3 }, + { 0, 1, 3, 4, 2 }, + { 0, 1, 4, 5, 2, 3 }, + { 0, 1, 5, 6, 2, 4, 3 }, + { 0, 1, 6, 7, 4, 5, 2, 3 }, +}; + +static void libopus_write_header(AVCodecContext *avctx, int stream_count, + int coupled_stream_count, + int mapping_family, + const uint8_t *channel_mapping) +{ + uint8_t *p = avctx->extradata; + int channels = avctx->channels; + + bytestream_put_buffer(&p, "OpusHead", 8); + bytestream_put_byte(&p, 1); /* Version */ + bytestream_put_byte(&p, channels); + bytestream_put_le16(&p, avctx->initial_padding); /* Lookahead samples at 48kHz */ + bytestream_put_le32(&p, avctx->sample_rate); /* Original sample rate */ + bytestream_put_le16(&p, 0); /* Gain of 0dB is recommended. */ + + /* Channel mapping */ + bytestream_put_byte(&p, mapping_family); + if (mapping_family != 0) { + bytestream_put_byte(&p, stream_count); + bytestream_put_byte(&p, coupled_stream_count); + bytestream_put_buffer(&p, channel_mapping, channels); + } +} + +static int libopus_configure_encoder(AVCodecContext *avctx, OpusMSEncoder *enc, + LibopusEncOpts *opts) +{ + int ret; + + if (avctx->global_quality) { + av_log(avctx, AV_LOG_ERROR, + "Quality-based encoding not supported, " + "please specify a bitrate and VBR setting.\n"); + return AVERROR(EINVAL); + } + + ret = opus_multistream_encoder_ctl(enc, OPUS_SET_BITRATE(avctx->bit_rate)); + if (ret != OPUS_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to set bitrate: %s\n", opus_strerror(ret)); + return ret; + } + + ret = opus_multistream_encoder_ctl(enc, + OPUS_SET_COMPLEXITY(opts->complexity)); + if (ret != OPUS_OK) + av_log(avctx, AV_LOG_WARNING, + "Unable to set complexity: %s\n", opus_strerror(ret)); + + ret = opus_multistream_encoder_ctl(enc, OPUS_SET_VBR(!!opts->vbr)); + if (ret != OPUS_OK) + av_log(avctx, AV_LOG_WARNING, + "Unable to set VBR: %s\n", opus_strerror(ret)); + + ret = opus_multistream_encoder_ctl(enc, + OPUS_SET_VBR_CONSTRAINT(opts->vbr == 2)); + if (ret != OPUS_OK) + av_log(avctx, AV_LOG_WARNING, + "Unable to set constrained VBR: %s\n", opus_strerror(ret)); + + ret = opus_multistream_encoder_ctl(enc, + OPUS_SET_PACKET_LOSS_PERC(opts->packet_loss)); + if (ret != OPUS_OK) + av_log(avctx, AV_LOG_WARNING, + "Unable to set expected packet loss percentage: %s\n", + opus_strerror(ret)); + + if (avctx->cutoff) { + ret = opus_multistream_encoder_ctl(enc, + OPUS_SET_MAX_BANDWIDTH(opts->max_bandwidth)); + if (ret != OPUS_OK) + av_log(avctx, AV_LOG_WARNING, + "Unable to set maximum bandwidth: %s\n", opus_strerror(ret)); + } + +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + ret = opus_multistream_encoder_ctl(enc, + OPUS_SET_PHASE_INVERSION_DISABLED(!opts->apply_phase_inv)); + if (ret != OPUS_OK) + av_log(avctx, AV_LOG_WARNING, + "Unable to set phase inversion: %s\n", + opus_strerror(ret)); +#endif + return OPUS_OK; +} + +static int libopus_check_max_channels(AVCodecContext *avctx, + int max_channels) { + if (avctx->channels > max_channels) { + av_log(avctx, AV_LOG_ERROR, "Opus mapping family undefined for %d channels.\n", + avctx->channels); + return AVERROR(EINVAL); + } + + return 0; +} + +static int libopus_check_vorbis_layout(AVCodecContext *avctx, int mapping_family) { + av_assert2(avctx->channels < FF_ARRAY_ELEMS(ff_vorbis_channel_layouts)); + + if (!avctx->channel_layout) { + av_log(avctx, AV_LOG_WARNING, + "No channel layout specified. Opus encoder will use Vorbis " + "channel layout for %d channels.\n", avctx->channels); + } else if (avctx->channel_layout != ff_vorbis_channel_layouts[avctx->channels - 1]) { + char name[32]; + av_get_channel_layout_string(name, sizeof(name), avctx->channels, + avctx->channel_layout); + av_log(avctx, AV_LOG_ERROR, + "Invalid channel layout %s for specified mapping family %d.\n", + name, mapping_family); + + return AVERROR(EINVAL); + } + + return 0; +} + +static int libopus_validate_layout_and_get_channel_map( + AVCodecContext *avctx, + int mapping_family, + const uint8_t ** channel_map_result) +{ + const uint8_t * channel_map = NULL; + int ret; + + switch (mapping_family) { + case -1: + ret = libopus_check_max_channels(avctx, 8); + if (ret == 0) { + ret = libopus_check_vorbis_layout(avctx, mapping_family); + /* Channels do not need to be reordered. */ + } + + break; + case 0: + ret = libopus_check_max_channels(avctx, 2); + if (ret == 0) { + ret = libopus_check_vorbis_layout(avctx, mapping_family); + } + break; + case 1: + /* Opus expects channels to be in Vorbis order. */ + ret = libopus_check_max_channels(avctx, 8); + if (ret == 0) { + ret = libopus_check_vorbis_layout(avctx, mapping_family); + channel_map = ff_vorbis_channel_layout_offsets[avctx->channels - 1]; + } + break; + case 255: + ret = libopus_check_max_channels(avctx, 254); + break; + default: + av_log(avctx, AV_LOG_WARNING, + "Unknown channel mapping family %d. Output channel layout may be invalid.\n", + mapping_family); + ret = 0; + } + + *channel_map_result = channel_map; + return ret; +} + +static av_cold int libopus_encode_init(AVCodecContext *avctx) +{ + LibopusEncContext *opus = avctx->priv_data; + OpusMSEncoder *enc; + uint8_t libopus_channel_mapping[255]; + int ret = OPUS_OK; + int av_ret; + int coupled_stream_count, header_size, frame_size; + int mapping_family; + + frame_size = opus->opts.frame_duration * 48000 / 1000; + switch (frame_size) { + case 120: + case 240: + if (opus->opts.application != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + av_log(avctx, AV_LOG_WARNING, + "LPC mode cannot be used with a frame duration of less " + "than 10ms. Enabling restricted low-delay mode.\n" + "Use a longer frame duration if this is not what you want.\n"); + /* Frame sizes less than 10 ms can only use MDCT mode, so switching to + * RESTRICTED_LOWDELAY avoids an unnecessary extra 2.5ms lookahead. */ + opus->opts.application = OPUS_APPLICATION_RESTRICTED_LOWDELAY; + case 480: + case 960: + case 1920: + case 2880: +#ifdef OPUS_FRAMESIZE_120_MS + case 3840: + case 4800: + case 5760: +#endif + opus->opts.packet_size = + avctx->frame_size = frame_size * avctx->sample_rate / 48000; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Invalid frame duration: %g.\n" + "Frame duration must be exactly one of: 2.5, 5, 10, 20, 40" +#ifdef OPUS_FRAMESIZE_120_MS + ", 60, 80, 100 or 120.\n", +#else + " or 60.\n", +#endif + opus->opts.frame_duration); + return AVERROR(EINVAL); + } + + if (avctx->compression_level < 0 || avctx->compression_level > 10) { + av_log(avctx, AV_LOG_WARNING, + "Compression level must be in the range 0 to 10. " + "Defaulting to 10.\n"); + opus->opts.complexity = 10; + } else { + opus->opts.complexity = avctx->compression_level; + } + + if (avctx->cutoff) { + switch (avctx->cutoff) { + case 4000: + opus->opts.max_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + break; + case 6000: + opus->opts.max_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + break; + case 8000: + opus->opts.max_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + break; + case 12000: + opus->opts.max_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + break; + case 20000: + opus->opts.max_bandwidth = OPUS_BANDWIDTH_FULLBAND; + break; + default: + av_log(avctx, AV_LOG_WARNING, + "Invalid frequency cutoff: %d. Using default maximum bandwidth.\n" + "Cutoff frequency must be exactly one of: 4000, 6000, 8000, 12000 or 20000.\n", + avctx->cutoff); + avctx->cutoff = 0; + } + } + + /* Channels may need to be reordered to match opus mapping. */ + av_ret = libopus_validate_layout_and_get_channel_map(avctx, opus->opts.mapping_family, + &opus->encoder_channel_map); + if (av_ret) { + return av_ret; + } + + if (opus->opts.mapping_family == -1) { + /* By default, use mapping family 1 for the header but use the older + * libopus multistream API to avoid surround masking. */ + + /* Set the mapping family so that the value is correct in the header */ + mapping_family = avctx->channels > 2 ? 1 : 0; + coupled_stream_count = opus_coupled_streams[avctx->channels - 1]; + opus->stream_count = avctx->channels - coupled_stream_count; + memcpy(libopus_channel_mapping, + opus_vorbis_channel_map[avctx->channels - 1], + avctx->channels * sizeof(*libopus_channel_mapping)); + + enc = opus_multistream_encoder_create( + avctx->sample_rate, avctx->channels, opus->stream_count, + coupled_stream_count, + libavcodec_libopus_channel_map[avctx->channels - 1], + opus->opts.application, &ret); + } else { + /* Use the newer multistream API. The encoder will set the channel + * mapping and coupled stream counts to its internal defaults and will + * use surround masking analysis to save bits. */ + mapping_family = opus->opts.mapping_family; + enc = opus_multistream_surround_encoder_create( + avctx->sample_rate, avctx->channels, mapping_family, + &opus->stream_count, &coupled_stream_count, libopus_channel_mapping, + opus->opts.application, &ret); + } + + if (ret != OPUS_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to create encoder: %s\n", opus_strerror(ret)); + return ff_opus_error_to_averror(ret); + } + + if (!avctx->bit_rate) { + /* Sane default copied from opusenc */ + avctx->bit_rate = 64000 * opus->stream_count + + 32000 * coupled_stream_count; + av_log(avctx, AV_LOG_WARNING, + "No bit rate set. Defaulting to %"PRId64" bps.\n", avctx->bit_rate); + } + + if (avctx->bit_rate < 500 || avctx->bit_rate > 256000 * avctx->channels) { + av_log(avctx, AV_LOG_ERROR, "The bit rate %"PRId64" bps is unsupported. " + "Please choose a value between 500 and %d.\n", avctx->bit_rate, + 256000 * avctx->channels); + ret = AVERROR(EINVAL); + goto fail; + } + + ret = libopus_configure_encoder(avctx, enc, &opus->opts); + if (ret != OPUS_OK) { + ret = ff_opus_error_to_averror(ret); + goto fail; + } + + /* Header includes channel mapping table if and only if mapping family is NOT 0 */ + header_size = 19 + (mapping_family == 0 ? 0 : 2 + avctx->channels); + avctx->extradata = av_malloc(header_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) { + av_log(avctx, AV_LOG_ERROR, "Failed to allocate extradata.\n"); + ret = AVERROR(ENOMEM); + goto fail; + } + avctx->extradata_size = header_size; + + opus->samples = av_mallocz_array(frame_size, avctx->channels * + av_get_bytes_per_sample(avctx->sample_fmt)); + if (!opus->samples) { + av_log(avctx, AV_LOG_ERROR, "Failed to allocate samples buffer.\n"); + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = opus_multistream_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&avctx->initial_padding)); + if (ret != OPUS_OK) + av_log(avctx, AV_LOG_WARNING, + "Unable to get number of lookahead samples: %s\n", + opus_strerror(ret)); + + libopus_write_header(avctx, opus->stream_count, coupled_stream_count, + mapping_family, libopus_channel_mapping); + + ff_af_queue_init(avctx, &opus->afq); + + opus->enc = enc; + + return 0; + +fail: + opus_multistream_encoder_destroy(enc); + av_freep(&avctx->extradata); + return ret; +} + +static void libopus_copy_samples_with_channel_map( + uint8_t *dst, const uint8_t *src, const uint8_t *channel_map, + int nb_channels, int nb_samples, int bytes_per_sample) { + int sample, channel; + for (sample = 0; sample < nb_samples; ++sample) { + for (channel = 0; channel < nb_channels; ++channel) { + const size_t src_pos = bytes_per_sample * (nb_channels * sample + channel); + const size_t dst_pos = bytes_per_sample * (nb_channels * sample + channel_map[channel]); + + memcpy(&dst[dst_pos], &src[src_pos], bytes_per_sample); + } + } +} + +static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + LibopusEncContext *opus = avctx->priv_data; + const int bytes_per_sample = av_get_bytes_per_sample(avctx->sample_fmt); + const int sample_size = avctx->channels * bytes_per_sample; + uint8_t *audio; + int ret; + int discard_padding; + + if (frame) { + ret = ff_af_queue_add(&opus->afq, frame); + if (ret < 0) + return ret; + if (opus->encoder_channel_map != NULL) { + audio = opus->samples; + libopus_copy_samples_with_channel_map( + audio, frame->data[0], opus->encoder_channel_map, + avctx->channels, frame->nb_samples, bytes_per_sample); + } else if (frame->nb_samples < opus->opts.packet_size) { + audio = opus->samples; + memcpy(audio, frame->data[0], frame->nb_samples * sample_size); + } else + audio = frame->data[0]; + } else { + if (!opus->afq.remaining_samples || (!opus->afq.frame_alloc && !opus->afq.frame_count)) + return 0; + audio = opus->samples; + memset(audio, 0, opus->opts.packet_size * sample_size); + } + + /* Maximum packet size taken from opusenc in opus-tools. 120ms packets + * consist of 6 frames in one packet. The maximum frame size is 1275 + * bytes along with the largest possible packet header of 7 bytes. */ + if ((ret = ff_alloc_packet2(avctx, avpkt, (1275 * 6 + 7) * opus->stream_count, 0)) < 0) + return ret; + + if (avctx->sample_fmt == AV_SAMPLE_FMT_FLT) + ret = opus_multistream_encode_float(opus->enc, (float *)audio, + opus->opts.packet_size, + avpkt->data, avpkt->size); + else + ret = opus_multistream_encode(opus->enc, (opus_int16 *)audio, + opus->opts.packet_size, + avpkt->data, avpkt->size); + + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "Error encoding frame: %s\n", opus_strerror(ret)); + return ff_opus_error_to_averror(ret); + } + + av_shrink_packet(avpkt, ret); + + ff_af_queue_remove(&opus->afq, opus->opts.packet_size, + &avpkt->pts, &avpkt->duration); + + discard_padding = opus->opts.packet_size - avpkt->duration; + // Check if subtraction resulted in an overflow + if ((discard_padding < opus->opts.packet_size) != (avpkt->duration > 0)) { + av_packet_unref(avpkt); + av_free(avpkt); + return AVERROR(EINVAL); + } + if (discard_padding > 0) { + uint8_t* side_data = av_packet_new_side_data(avpkt, + AV_PKT_DATA_SKIP_SAMPLES, + 10); + if(!side_data) { + av_packet_unref(avpkt); + av_free(avpkt); + return AVERROR(ENOMEM); + } + AV_WL32(side_data + 4, discard_padding); + } + + *got_packet_ptr = 1; + + return 0; +} + +static av_cold int libopus_encode_close(AVCodecContext *avctx) +{ + LibopusEncContext *opus = avctx->priv_data; + + opus_multistream_encoder_destroy(opus->enc); + + ff_af_queue_close(&opus->afq); + + av_freep(&opus->samples); + av_freep(&avctx->extradata); + + return 0; +} + +#define OFFSET(x) offsetof(LibopusEncContext, opts.x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption libopus_options[] = { + { "application", "Intended application type", OFFSET(application), AV_OPT_TYPE_INT, { .i64 = OPUS_APPLICATION_AUDIO }, OPUS_APPLICATION_VOIP, OPUS_APPLICATION_RESTRICTED_LOWDELAY, FLAGS, "application" }, + { "voip", "Favor improved speech intelligibility", 0, AV_OPT_TYPE_CONST, { .i64 = OPUS_APPLICATION_VOIP }, 0, 0, FLAGS, "application" }, + { "audio", "Favor faithfulness to the input", 0, AV_OPT_TYPE_CONST, { .i64 = OPUS_APPLICATION_AUDIO }, 0, 0, FLAGS, "application" }, + { "lowdelay", "Restrict to only the lowest delay modes", 0, AV_OPT_TYPE_CONST, { .i64 = OPUS_APPLICATION_RESTRICTED_LOWDELAY }, 0, 0, FLAGS, "application" }, + { "frame_duration", "Duration of a frame in milliseconds", OFFSET(frame_duration), AV_OPT_TYPE_FLOAT, { .dbl = 20.0 }, 2.5, 120.0, FLAGS }, + { "packet_loss", "Expected packet loss percentage", OFFSET(packet_loss), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, FLAGS }, + { "vbr", "Variable bit rate mode", OFFSET(vbr), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 2, FLAGS, "vbr" }, + { "off", "Use constant bit rate", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "vbr" }, + { "on", "Use variable bit rate", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, "vbr" }, + { "constrained", "Use constrained VBR", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, FLAGS, "vbr" }, + { "mapping_family", "Channel Mapping Family", OFFSET(mapping_family), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, FLAGS, "mapping_family" }, +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + { "apply_phase_inv", "Apply intensity stereo phase inversion", OFFSET(apply_phase_inv), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, +#endif + { NULL }, +}; + +static const AVClass libopus_class = { + .class_name = "libopus", + .item_name = av_default_item_name, + .option = libopus_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVCodecDefault libopus_defaults[] = { + { "b", "0" }, + { "compression_level", "10" }, + { NULL }, +}; + +static const int libopus_sample_rates[] = { + 48000, 24000, 16000, 12000, 8000, 0, +}; + +AVCodec ff_libopus_encoder = { + .name = "libopus", + .long_name = NULL_IF_CONFIG_SMALL("libopus Opus"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_OPUS, + .priv_data_size = sizeof(LibopusEncContext), + .init = libopus_encode_init, + .encode2 = libopus_encode, + .close = libopus_encode_close, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SMALL_LAST_FRAME, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_NONE }, + .supported_samplerates = libopus_sample_rates, + .priv_class = &libopus_class, + .defaults = libopus_defaults, + .wrapper_name = "libopus", +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/lpc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/lpc.c new file mode 100644 index 0000000000..f8da1e1266 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/lpc.c @@ -0,0 +1,325 @@ +/* + * LPC utility code + * Copyright (c) 2006 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/lls.h" + +#define LPC_USE_DOUBLE +#include "lpc.h" +#include "libavutil/avassert.h" + + +/** + * Apply Welch window function to audio block + */ +static void lpc_apply_welch_window_c(const int32_t *data, int len, + double *w_data) +{ + int i, n2; + double w; + double c; + + n2 = (len >> 1); + c = 2.0 / (len - 1.0); + + if (len & 1) { + for(i=0; i qmax) && (sh > min_shift)) { + sh--; + } + + /* since negative shift values are unsupported in decoder, scale down + coefficients instead */ + if(sh == 0 && cmax > qmax) { + double scale = ((double)qmax) / cmax; + for(i=0; i=min_order-1; i--) { + if(ref[i] > 0.10) { + est = i+1; + break; + } + } + return est; +} + +int ff_lpc_calc_ref_coefs(LPCContext *s, + const int32_t *samples, int order, double *ref) +{ + double autoc[MAX_LPC_ORDER + 1]; + + s->lpc_apply_welch_window(samples, s->blocksize, s->windowed_samples); + s->lpc_compute_autocorr(s->windowed_samples, s->blocksize, order, autoc); + compute_ref_coefs(autoc, order, ref, NULL); + + return order; +} + +double ff_lpc_calc_ref_coefs_f(LPCContext *s, const float *samples, int len, + int order, double *ref) +{ + int i; + double signal = 0.0f, avg_err = 0.0f; + double autoc[MAX_LPC_ORDER+1] = {0}, error[MAX_LPC_ORDER+1] = {0}; + const double a = 0.5f, b = 1.0f - a; + + /* Apply windowing */ + for (i = 0; i <= len / 2; i++) { + double weight = a - b*cos((2*M_PI*i)/(len - 1)); + s->windowed_samples[i] = weight*samples[i]; + s->windowed_samples[len-1-i] = weight*samples[len-1-i]; + } + + s->lpc_compute_autocorr(s->windowed_samples, len, order, autoc); + signal = autoc[0]; + compute_ref_coefs(autoc, order, ref, error); + for (i = 0; i < order; i++) + avg_err = (avg_err + error[i])/2.0f; + return signal/avg_err; +} + +/** + * Calculate LPC coefficients for multiple orders + * + * @param lpc_type LPC method for determining coefficients, + * see #FFLPCType for details + */ +int ff_lpc_calc_coefs(LPCContext *s, + const int32_t *samples, int blocksize, int min_order, + int max_order, int precision, + int32_t coefs[][MAX_LPC_ORDER], int *shift, + enum FFLPCType lpc_type, int lpc_passes, + int omethod, int min_shift, int max_shift, int zero_shift) +{ + double autoc[MAX_LPC_ORDER+1]; + double ref[MAX_LPC_ORDER] = { 0 }; + double lpc[MAX_LPC_ORDER][MAX_LPC_ORDER]; + int i, j, pass = 0; + int opt_order; + + av_assert2(max_order >= MIN_LPC_ORDER && max_order <= MAX_LPC_ORDER && + lpc_type > FF_LPC_TYPE_FIXED); + av_assert0(lpc_type == FF_LPC_TYPE_CHOLESKY || lpc_type == FF_LPC_TYPE_LEVINSON); + + /* reinit LPC context if parameters have changed */ + if (blocksize != s->blocksize || max_order != s->max_order || + lpc_type != s->lpc_type) { + ff_lpc_end(s); + ff_lpc_init(s, blocksize, max_order, lpc_type); + } + + if(lpc_passes <= 0) + lpc_passes = 2; + + if (lpc_type == FF_LPC_TYPE_LEVINSON || (lpc_type == FF_LPC_TYPE_CHOLESKY && lpc_passes > 1)) { + s->lpc_apply_welch_window(samples, blocksize, s->windowed_samples); + + s->lpc_compute_autocorr(s->windowed_samples, blocksize, max_order, autoc); + + compute_lpc_coefs(autoc, max_order, &lpc[0][0], MAX_LPC_ORDER, 0, 1); + + for(i=0; ills_models; + LOCAL_ALIGNED(32, double, var, [FFALIGN(MAX_LPC_ORDER+1,4)]); + double av_uninit(weight); + memset(var, 0, FFALIGN(MAX_LPC_ORDER+1,4)*sizeof(*var)); + + for(j=0; j>pass) + fabs(eval - var[0]); + inv = 1/eval; + rinv = sqrt(inv); + for(j=0; j<=max_order; j++) + var[j] *= rinv; + weight += inv; + }else + weight++; + + m[pass&1].update_lls(&m[pass&1], var); + } + avpriv_solve_lls(&m[pass&1], 0.001, 0); + } + + for(i=0; i0; i--) + ref[i] = ref[i-1] - ref[i]; + } + + opt_order = max_order; + + if(omethod == ORDER_METHOD_EST) { + opt_order = estimate_best_order(ref, min_order, max_order); + i = opt_order-1; + quantize_lpc_coefs(lpc[i], i+1, precision, coefs[i], &shift[i], + min_shift, max_shift, zero_shift); + } else { + for(i=min_order-1; iblocksize = blocksize; + s->max_order = max_order; + s->lpc_type = lpc_type; + + s->windowed_buffer = av_mallocz((blocksize + 2 + FFALIGN(max_order, 4)) * + sizeof(*s->windowed_samples)); + if (!s->windowed_buffer) + return AVERROR(ENOMEM); + s->windowed_samples = s->windowed_buffer + FFALIGN(max_order, 4); + + s->lpc_apply_welch_window = lpc_apply_welch_window_c; + s->lpc_compute_autocorr = lpc_compute_autocorr_c; + + if (ARCH_X86) + ff_lpc_init_x86(s); + + return 0; +} + +av_cold void ff_lpc_end(LPCContext *s) +{ + av_freep(&s->windowed_buffer); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/lpc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/lpc.h new file mode 100644 index 0000000000..88ca247f87 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/lpc.h @@ -0,0 +1,212 @@ +/* + * LPC utility code + * Copyright (c) 2006 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_LPC_H +#define AVCODEC_LPC_H + +#include +#include "libavutil/avassert.h" +#include "libavutil/lls.h" +#include "aac_defines.h" + +#define ORDER_METHOD_EST 0 +#define ORDER_METHOD_2LEVEL 1 +#define ORDER_METHOD_4LEVEL 2 +#define ORDER_METHOD_8LEVEL 3 +#define ORDER_METHOD_SEARCH 4 +#define ORDER_METHOD_LOG 5 + +#define MIN_LPC_ORDER 1 +#define MAX_LPC_ORDER 32 + +/** + * LPC analysis type + */ +enum FFLPCType { + FF_LPC_TYPE_DEFAULT = -1, ///< use the codec default LPC type + FF_LPC_TYPE_NONE = 0, ///< do not use LPC prediction or use all zero coefficients + FF_LPC_TYPE_FIXED = 1, ///< fixed LPC coefficients + FF_LPC_TYPE_LEVINSON = 2, ///< Levinson-Durbin recursion + FF_LPC_TYPE_CHOLESKY = 3, ///< Cholesky factorization + FF_LPC_TYPE_NB , ///< Not part of ABI +}; + +typedef struct LPCContext { + int blocksize; + int max_order; + enum FFLPCType lpc_type; + double *windowed_buffer; + double *windowed_samples; + + /** + * Apply a Welch window to an array of input samples. + * The output samples have the same scale as the input, but are in double + * sample format. + * @param data input samples + * @param len number of input samples + * @param w_data output samples + */ + void (*lpc_apply_welch_window)(const int32_t *data, int len, + double *w_data); + /** + * Perform autocorrelation on input samples with delay of 0 to lag. + * @param data input samples. + * constraints: no alignment needed, but must have at + * least lag*sizeof(double) valid bytes preceding it, and + * size must be at least (len+1)*sizeof(double) if data is + * 16-byte aligned or (len+2)*sizeof(double) if data is + * unaligned. + * @param len number of input samples to process + * @param lag maximum delay to calculate + * @param autoc output autocorrelation coefficients. + * constraints: array size must be at least lag+1. + */ + void (*lpc_compute_autocorr)(const double *data, int len, int lag, + double *autoc); + + // TODO: these should be allocated to reduce ABI compatibility issues + LLSModel lls_models[2]; +} LPCContext; + + +/** + * Calculate LPC coefficients for multiple orders + */ +int ff_lpc_calc_coefs(LPCContext *s, + const int32_t *samples, int blocksize, int min_order, + int max_order, int precision, + int32_t coefs[][MAX_LPC_ORDER], int *shift, + enum FFLPCType lpc_type, int lpc_passes, + int omethod, int min_shift, int max_shift, int zero_shift); + +int ff_lpc_calc_ref_coefs(LPCContext *s, + const int32_t *samples, int order, double *ref); + +double ff_lpc_calc_ref_coefs_f(LPCContext *s, const float *samples, int len, + int order, double *ref); + +/** + * Initialize LPCContext. + */ +int ff_lpc_init(LPCContext *s, int blocksize, int max_order, + enum FFLPCType lpc_type); +void ff_lpc_init_x86(LPCContext *s); + +/** + * Uninitialize LPCContext. + */ +void ff_lpc_end(LPCContext *s); + +#if USE_FIXED +typedef int LPC_TYPE; +typedef unsigned LPC_TYPE_U; +#else +#ifdef LPC_USE_DOUBLE +typedef double LPC_TYPE; +typedef double LPC_TYPE_U; +#else +typedef float LPC_TYPE; +typedef float LPC_TYPE_U; +#endif +#endif // USE_FIXED + +/** + * Schur recursion. + * Produces reflection coefficients from autocorrelation data. + */ +static inline void compute_ref_coefs(const LPC_TYPE *autoc, int max_order, + LPC_TYPE *ref, LPC_TYPE *error) +{ + int i, j; + LPC_TYPE err; + LPC_TYPE gen0[MAX_LPC_ORDER], gen1[MAX_LPC_ORDER]; + + for (i = 0; i < max_order; i++) + gen0[i] = gen1[i] = autoc[i + 1]; + + err = autoc[0]; + ref[0] = -gen1[0] / err; + err += gen1[0] * ref[0]; + if (error) + error[0] = err; + for (i = 1; i < max_order; i++) { + for (j = 0; j < max_order - i; j++) { + gen1[j] = gen1[j + 1] + ref[i - 1] * gen0[j]; + gen0[j] = gen1[j + 1] * ref[i - 1] + gen0[j]; + } + ref[i] = -gen1[0] / err; + err += gen1[0] * ref[i]; + if (error) + error[i] = err; + } +} + +/** + * Levinson-Durbin recursion. + * Produce LPC coefficients from autocorrelation data. + */ +static inline int AAC_RENAME(compute_lpc_coefs)(const LPC_TYPE *autoc, int max_order, + LPC_TYPE *lpc, int lpc_stride, int fail, + int normalize) +{ + int i, j; + LPC_TYPE err = 0; + LPC_TYPE *lpc_last = lpc; + + av_assert2(normalize || !fail); + + if (normalize) + err = *autoc++; + + if (fail && (autoc[max_order - 1] == 0 || err <= 0)) + return -1; + + for(i=0; i>1; j++) { + LPC_TYPE f = lpc_last[ j]; + LPC_TYPE b = lpc_last[i-1-j]; + lpc[ j] = f + (LPC_TYPE_U)AAC_MUL26(r, b); + lpc[i-1-j] = b + (LPC_TYPE_U)AAC_MUL26(r, f); + } + + if (fail && err < 0) + return -1; + + lpc_last = lpc; + lpc += lpc_stride; + } + + return 0; +} + +#endif /* AVCODEC_LPC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mathops.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mathops.h new file mode 100644 index 0000000000..1c35664318 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mathops.h @@ -0,0 +1,251 @@ +/* + * simple math operations + * Copyright (c) 2001, 2002 Fabrice Bellard + * Copyright (c) 2006 Michael Niedermayer et al + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVCODEC_MATHOPS_H +#define AVCODEC_MATHOPS_H + +#include + +#include "libavutil/common.h" +#include "libavutil/reverse.h" +#include "config.h" + +#define MAX_NEG_CROP 1024 + +extern const uint32_t ff_inverse[257]; +extern const uint8_t ff_sqrt_tab[256]; +extern const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP]; +extern const uint8_t ff_zigzag_direct[64]; +extern const uint8_t ff_zigzag_scan[16+1]; + +#if ARCH_ARM +# include "arm/mathops.h" +#elif ARCH_AVR32 +# include "avr32/mathops.h" +#elif ARCH_MIPS +# include "mips/mathops.h" +#elif ARCH_PPC +# include "ppc/mathops.h" +#elif ARCH_X86 +# include "x86/mathops.h" +#endif + +/* generic implementation */ + +#ifndef MUL64 +# define MUL64(a,b) ((int64_t)(a) * (int64_t)(b)) +#endif + +#ifndef MULL +# define MULL(a,b,s) (MUL64(a, b) >> (s)) +#endif + +#ifndef MULH +static av_always_inline int MULH(int a, int b){ + return MUL64(a, b) >> 32; +} +#endif + +#ifndef UMULH +static av_always_inline unsigned UMULH(unsigned a, unsigned b){ + return ((uint64_t)(a) * (uint64_t)(b))>>32; +} +#endif + +#ifndef MAC64 +# define MAC64(d, a, b) ((d) += MUL64(a, b)) +#endif + +#ifndef MLS64 +# define MLS64(d, a, b) ((d) -= MUL64(a, b)) +#endif + +/* signed 16x16 -> 32 multiply add accumulate */ +#ifndef MAC16 +# define MAC16(rt, ra, rb) rt += (ra) * (rb) +#endif + +/* signed 16x16 -> 32 multiply */ +#ifndef MUL16 +# define MUL16(ra, rb) ((ra) * (rb)) +#endif + +#ifndef MLS16 +# define MLS16(rt, ra, rb) ((rt) -= (ra) * (rb)) +#endif + +/* median of 3 */ +#ifndef mid_pred +#define mid_pred mid_pred +static inline av_const int mid_pred(int a, int b, int c) +{ + if(a>b){ + if(c>b){ + if(c>a) b=a; + else b=c; + } + }else{ + if(b>c){ + if(c>a) b=c; + else b=a; + } + } + return b; +} +#endif + +#ifndef median4 +#define median4 median4 +static inline av_const int median4(int a, int b, int c, int d) +{ + if (a < b) { + if (c < d) return (FFMIN(b, d) + FFMAX(a, c)) / 2; + else return (FFMIN(b, c) + FFMAX(a, d)) / 2; + } else { + if (c < d) return (FFMIN(a, d) + FFMAX(b, c)) / 2; + else return (FFMIN(a, c) + FFMAX(b, d)) / 2; + } +} +#endif + +#ifndef sign_extend +static inline av_const int sign_extend(int val, unsigned bits) +{ + unsigned shift = 8 * sizeof(int) - bits; + union { unsigned u; int s; } v = { (unsigned) val << shift }; + return v.s >> shift; +} +#endif + +#ifndef zero_extend +static inline av_const unsigned zero_extend(unsigned val, unsigned bits) +{ + return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits); +} +#endif + +#ifndef COPY3_IF_LT +#define COPY3_IF_LT(x, y, a, b, c, d)\ +if ((y) < (x)) {\ + (x) = (y);\ + (a) = (b);\ + (c) = (d);\ +} +#endif + +#ifndef MASK_ABS +#define MASK_ABS(mask, level) do { \ + mask = level >> 31; \ + level = (level ^ mask) - mask; \ + } while (0) +#endif + +#ifndef NEG_SSR32 +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +#endif + +#ifndef NEG_USR32 +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +#if HAVE_BIGENDIAN +# ifndef PACK_2U8 +# define PACK_2U8(a,b) (((a) << 8) | (b)) +# endif +# ifndef PACK_4U8 +# define PACK_4U8(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +# endif +# ifndef PACK_2U16 +# define PACK_2U16(a,b) (((a) << 16) | (b)) +# endif +#else +# ifndef PACK_2U8 +# define PACK_2U8(a,b) (((b) << 8) | (a)) +# endif +# ifndef PACK_4U2 +# define PACK_4U8(a,b,c,d) (((d) << 24) | ((c) << 16) | ((b) << 8) | (a)) +# endif +# ifndef PACK_2U16 +# define PACK_2U16(a,b) (((b) << 16) | (a)) +# endif +#endif + +#ifndef PACK_2S8 +# define PACK_2S8(a,b) PACK_2U8((a)&255, (b)&255) +#endif +#ifndef PACK_4S8 +# define PACK_4S8(a,b,c,d) PACK_4U8((a)&255, (b)&255, (c)&255, (d)&255) +#endif +#ifndef PACK_2S16 +# define PACK_2S16(a,b) PACK_2U16((a)&0xffff, (b)&0xffff) +#endif + +#ifndef FASTDIV +# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a) * ff_inverse[b]) >> 32)) +#endif /* FASTDIV */ + +#ifndef ff_sqrt +#define ff_sqrt ff_sqrt +static inline av_const unsigned int ff_sqrt(unsigned int a) +{ + unsigned int b; + + if (a < 255) return (ff_sqrt_tab[a + 1] - 1) >> 4; + else if (a < (1 << 12)) b = ff_sqrt_tab[a >> 4] >> 2; +#if !CONFIG_SMALL + else if (a < (1 << 14)) b = ff_sqrt_tab[a >> 6] >> 1; + else if (a < (1 << 16)) b = ff_sqrt_tab[a >> 8] ; +#endif + else { + int s = av_log2_16bit(a >> 16) >> 1; + unsigned int c = a >> (s + 2); + b = ff_sqrt_tab[c >> (s + 8)]; + b = FASTDIV(c,b) + (b << s); + } + + return b - (a < b * b); +} +#endif + +static inline av_const float ff_sqrf(float a) +{ + return a*a; +} + +static inline int8_t ff_u8_to_s8(uint8_t a) +{ + union { + uint8_t u8; + int8_t s8; + } b; + b.u8 = a; + return b.s8; +} + +static av_always_inline uint32_t bitswap_32(uint32_t x) +{ + return (uint32_t)ff_reverse[ x & 0xFF] << 24 | + (uint32_t)ff_reverse[(x >> 8) & 0xFF] << 16 | + (uint32_t)ff_reverse[(x >> 16) & 0xFF] << 8 | + (uint32_t)ff_reverse[ x >> 24]; +} + +#endif /* AVCODEC_MATHOPS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mathtables.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mathtables.c new file mode 100644 index 0000000000..81eabc7a65 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mathtables.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "mathops.h" + +/* a*inverse[b]>>32 == a/b for all 0<=a<=16909558 && 2<=b<=256 + * for a>16909558, is an overestimate by less than 1 part in 1<<24 */ +const uint32_t ff_inverse[257]={ + 0, 4294967295U,2147483648U,1431655766, 1073741824, 858993460, 715827883, 613566757, + 536870912, 477218589, 429496730, 390451573, 357913942, 330382100, 306783379, 286331154, + 268435456, 252645136, 238609295, 226050911, 214748365, 204522253, 195225787, 186737709, + 178956971, 171798692, 165191050, 159072863, 153391690, 148102321, 143165577, 138547333, + 134217728, 130150525, 126322568, 122713352, 119304648, 116080198, 113025456, 110127367, + 107374183, 104755300, 102261127, 99882961, 97612894, 95443718, 93368855, 91382283, + 89478486, 87652394, 85899346, 84215046, 82595525, 81037119, 79536432, 78090315, + 76695845, 75350304, 74051161, 72796056, 71582789, 70409300, 69273667, 68174085, + 67108864, 66076420, 65075263, 64103990, 63161284, 62245903, 61356676, 60492498, + 59652324, 58835169, 58040099, 57266231, 56512728, 55778797, 55063684, 54366675, + 53687092, 53024288, 52377650, 51746594, 51130564, 50529028, 49941481, 49367441, + 48806447, 48258060, 47721859, 47197443, 46684428, 46182445, 45691142, 45210183, + 44739243, 44278014, 43826197, 43383509, 42949673, 42524429, 42107523, 41698712, + 41297763, 40904451, 40518560, 40139882, 39768216, 39403370, 39045158, 38693400, + 38347923, 38008561, 37675152, 37347542, 37025581, 36709123, 36398028, 36092163, + 35791395, 35495598, 35204650, 34918434, 34636834, 34359739, 34087043, 33818641, + 33554432, 33294321, 33038210, 32786010, 32537632, 32292988, 32051995, 31814573, + 31580642, 31350127, 31122952, 30899046, 30678338, 30460761, 30246249, 30034737, + 29826162, 29620465, 29417585, 29217465, 29020050, 28825284, 28633116, 28443493, + 28256364, 28071682, 27889399, 27709467, 27531842, 27356480, 27183338, 27012373, + 26843546, 26676816, 26512144, 26349493, 26188825, 26030105, 25873297, 25718368, + 25565282, 25414008, 25264514, 25116768, 24970741, 24826401, 24683721, 24542671, + 24403224, 24265352, 24129030, 23994231, 23860930, 23729102, 23598722, 23469767, + 23342214, 23216040, 23091223, 22967740, 22845571, 22724695, 22605092, 22486740, + 22369622, 22253717, 22139007, 22025474, 21913099, 21801865, 21691755, 21582751, + 21474837, 21367997, 21262215, 21157475, 21053762, 20951060, 20849356, 20748635, + 20648882, 20550083, 20452226, 20355296, 20259280, 20164166, 20069941, 19976593, + 19884108, 19792477, 19701685, 19611723, 19522579, 19434242, 19346700, 19259944, + 19173962, 19088744, 19004281, 18920561, 18837576, 18755316, 18673771, 18592933, + 18512791, 18433337, 18354562, 18276457, 18199014, 18122225, 18046082, 17970575, + 17895698, 17821442, 17747799, 17674763, 17602325, 17530479, 17459217, 17388532, + 17318417, 17248865, 17179870, 17111424, 17043522, 16976156, 16909321, 16843010, + 16777216 +}; + +const uint8_t ff_sqrt_tab[256]={ + 0, 16, 23, 28, 32, 36, 40, 43, 46, 48, 51, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 77, 79, 80, 82, 84, 85, 87, 88, 90, + 91, 92, 94, 95, 96, 98, 99,100,102,103,104,105,107,108,109,110,111,112,114,115,116,117,118,119,120,121,122,123,124,125,126,127, +128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,144,145,146,147,148,149,150,151,151,152,153,154,155,156,156, +157,158,159,160,160,161,162,163,164,164,165,166,167,168,168,169,170,171,171,172,173,174,174,175,176,176,177,178,179,179,180,181, +182,182,183,184,184,185,186,186,187,188,188,189,190,190,191,192,192,193,194,194,195,196,196,197,198,198,199,200,200,201,202,202, +203,204,204,205,205,206,207,207,208,208,209,210,210,211,212,212,213,213,214,215,215,216,216,217,218,218,219,219,220,220,221,222, +222,223,223,224,224,225,226,226,227,227,228,228,229,230,230,231,231,232,232,233,233,234,235,235,236,236,237,237,238,238,239,239, +240,240,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255,255,255 +}; + +#define times4(x) x, x, x, x +#define times256(x) times4(times4(times4(times4(times4(x))))) + +const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP] = { +times256(0x00), +0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, +0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, +0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, +0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, +0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, +0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, +0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F, +0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, +0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, +0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, +0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, +0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, +0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, +0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, +0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, +times256(0xFF) +}; + +const uint8_t ff_zigzag_direct[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +const uint8_t ff_zigzag_scan[16+1] = { + 0 + 0 * 4, 1 + 0 * 4, 0 + 1 * 4, 0 + 2 * 4, + 1 + 1 * 4, 2 + 0 * 4, 3 + 0 * 4, 2 + 1 * 4, + 1 + 2 * 4, 0 + 3 * 4, 1 + 3 * 4, 2 + 2 * 4, + 3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.asm new file mode 100644 index 0000000000..2a2cdbd21b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.asm @@ -0,0 +1,221 @@ +;****************************************************************************** +;* SIMD optimized non-power-of-two MDCT functions +;* +;* Copyright (C) 2017 Rostislav Pehlivanov +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA 32 + +perm_neg: dd 2, 5, 3, 4, 6, 1, 7, 0 +perm_pos: dd 0, 7, 1, 6, 4, 3, 5, 2 +sign_adjust_r: times 4 dd 0x80000000, 0x00000000 + +sign_adjust_5: dd 0x00000000, 0x80000000, 0x80000000, 0x00000000 + +SECTION .text + +%if ARCH_X86_64 + +;***************************************************************************************** +;void ff_fft15_avx(FFTComplex *out, FFTComplex *in, FFTComplex *exptab, ptrdiff_t stride); +;***************************************************************************************** +%macro FFT5 3 ; %1 - in_offset, %2 - dst1 (64bit used), %3 - dst2 + VBROADCASTSD m0, [inq + %1] ; in[ 0].re, in[ 0].im, in[ 0].re, in[ 0].im + movsd xm1, [inq + 1*16 + 8 + %1] ; in[ 3].re, in[ 3].im, 0, 0 + movsd xm4, [inq + 6*16 + 0 + %1] ; in[12].re, in[12].im, 0, 0 + movhps xm1, [inq + 3*16 + 0 + %1] ; in[ 3].re, in[ 3].im, in[ 6].re, in[ 6].im + movhps xm4, [inq + 4*16 + 8 + %1] ; in[12].re, in[12].im, in[ 9].re, in[ 9].im + + subps xm2, xm1, xm4 ; t[2].im, t[2].re, t[3].im, t[3].re + addps xm1, xm4 ; t[0].re, t[0].im, t[1].re, t[1].im + + movhlps %2, xm1 ; t[0].re, t[1].re, t[0].im, t[1].im + addps %2, xm1 + addps %2, xm0 ; DC[0].re, DC[0].im, junk... + movlhps %2, %2 ; DC[0].re, DC[0].im, DC[0].re, DC[0].im + + shufps xm3, xm1, xm2, q0110 ; t[0].re, t[0].im, t[2].re, t[2].im + shufps xm1, xm2, q2332 ; t[1].re, t[1].im, t[3].re, t[3].im + + mulps xm%3, xm1, xm5 + mulps xm4, xm3, xm6 + mulps xm1, xm6 + + xorps xm1, xm7 + mulps xm3, xm5 + addsubps xm3, xm1 ; t[0].re, t[0].im, t[2].re, t[2].im + subps xm%3, xm4 ; t[4].re, t[4].im, t[5].re, t[5].im + + movhlps xm2, xm%3, xm3 ; t[2].re, t[2].im, t[5].re, t[5].im + movlhps xm3, xm%3 ; t[0].re, t[0].im, t[4].re, t[4].im + + xorps xm2, xm7 + addps xm%3, xm2, xm3 + subps xm3, xm2 + + shufps xm3, xm3, q1032 + vinsertf128 m%3, m%3, xm3, 1 ; All ACs (tmp[1] through to tmp[4]) + addps m%3, m%3, m0 ; Finally offset with DCs +%endmacro + +%macro BUTTERFLIES_DC 1 ; %1 - exptab_offset + mulps xm0, xm9, [exptabq + %1 + 16*0] + mulps xm1, xm10, [exptabq + %1 + 16*1] + + haddps xm0, xm1 + movhlps xm1, xm0 ; t[0].re, t[1].re, t[0].im, t[1].im + + addps xm0, xm1 + addps xm0, xm8 + + movsd [outq], xm0 +%endmacro + +%macro BUTTERFLIES_AC 1 ; %1 - exptab_offset + mulps m0, m12, [exptabq + 64*0 + 0*mmsize + %1] + mulps m1, m12, [exptabq + 64*0 + 1*mmsize + %1] + mulps m2, m13, [exptabq + 64*1 + 0*mmsize + %1] + mulps m3, m13, [exptabq + 64*1 + 1*mmsize + %1] + + addps m0, m0, m2 + addps m1, m1, m3 + addps m0, m0, m11 + + shufps m1, m1, m1, q2301 + addps m0, m0, m1 + + vextractf128 xm1, m0, 1 + + movlps [outq + strideq*1], xm0 + movhps [outq + strideq*2], xm0 + movlps [outq + stride3q], xm1 + movhps [outq + strideq*4], xm1 +%endmacro + +INIT_YMM avx +cglobal fft15, 4, 5, 14, out, in, exptab, stride, stride5 + shl strideq, 3 + + movaps xm5, [exptabq + 480 + 16*0] + movaps xm6, [exptabq + 480 + 16*1] + movaps xm7, [sign_adjust_5] + + FFT5 0, xm8, 11 + FFT5 8, xm9, 12 + FFT5 16, xm10, 13 + +%define stride3q inq + lea stride3q, [strideq + strideq*2] + lea stride5q, [strideq + strideq*4] + + BUTTERFLIES_DC (8*6 + 4*0)*2*4 + BUTTERFLIES_AC (8*0 + 0*0)*2*4 + + add outq, stride5q + BUTTERFLIES_DC (8*6 + 4*1)*2*4 + BUTTERFLIES_AC (8*2 + 0*0)*2*4 + + add outq, stride5q + BUTTERFLIES_DC (8*6 + 4*2)*2*4 + BUTTERFLIES_AC (8*4 + 0*0)*2*4 + + RET + +%endif ; ARCH_X86_64 + +;******************************************************************************************************* +;void ff_mdct15_postreindex(FFTComplex *out, FFTComplex *in, FFTComplex *exp, int *lut, ptrdiff_t len8); +;******************************************************************************************************* +%macro LUT_LOAD_4D 3 + mov r4d, [lutq + %3q*4 + 0] + movsd xmm%1, [inq + r4q*8] + mov r4d, [lutq + %3q*4 + 4] + movhps xmm%1, [inq + r4q*8] +%if cpuflag(avx2) + mov r4d, [lutq + %3q*4 + 8] + movsd %2, [inq + r4q*8] + mov r4d, [lutq + %3q*4 + 12] + movhps %2, [inq + r4q*8] + vinsertf128 %1, %1, %2, 1 +%endif +%endmacro + +%macro POSTROTATE_FN 1 +cglobal mdct15_postreindex, 5, 7, 8 + cpuflag(avx2)*2, out, in, exp, lut, len8, offset_p, offset_n + + xor offset_nq, offset_nq + lea offset_pq, [len8q*2 - %1] + + movaps m7, [sign_adjust_r] + +%if cpuflag(avx2) + movaps m8, [perm_pos] + movaps m9, [perm_neg] +%endif + +.loop: + movups m0, [expq + offset_pq*8] ; exp[p0].re, exp[p0].im, exp[p1].re, exp[p1].im, exp[p2].re, exp[p2].im, exp[p3].re, exp[p3].im + movups m1, [expq + offset_nq*8] ; exp[n3].re, exp[n3].im, exp[n2].re, exp[n2].im, exp[n1].re, exp[n1].im, exp[n0].re, exp[n0].im + + LUT_LOAD_4D m3, xm4, offset_p ; in[p0].re, in[p0].im, in[p1].re, in[p1].im, in[p2].re, in[p2].im, in[p3].re, in[p3].im + LUT_LOAD_4D m4, xm5, offset_n ; in[n3].re, in[n3].im, in[n2].re, in[n2].im, in[n1].re, in[n1].im, in[n0].re, in[n0].im + + mulps m5, m3, m0 ; in[p].reim * exp[p].reim + mulps m6, m4, m1 ; in[n].reim * exp[n].reim + + xorps m5, m7 ; in[p].re *= -1, in[p].im *= 1 + xorps m6, m7 ; in[n].re *= -1, in[n].im *= 1 + + shufps m3, m3, m3, q2301 ; in[p].imre + shufps m4, m4, m4, q2301 ; in[n].imre + + mulps m3, m0 ; in[p].imre * exp[p].reim + mulps m4, m1 ; in[n].imre * exp[n].reim + + haddps m3, m6 ; out[n0].im, out[n1].im, out[n3].re, out[n2].re, out[n2].im, out[n3].im, out[n1].re, out[n0].re + haddps m5, m4 ; out[p0].re, out[p1].re, out[p3].im, out[p2].im, out[p2].re, out[p3].re, out[p1].im, out[p0].im + +%if cpuflag(avx2) + vpermps m3, m9, m3 ; out[n3].im, out[n3].re, out[n2].im, out[n2].re, out[n1].im, out[n1].re, out[n0].im, out[n0].re + vpermps m5, m8, m5 ; out[p0].re, out[p0].im, out[p1].re, out[p1].im, out[p2].re, out[p2].im, out[p3].re, out[p3].im +%else + shufps m3, m3, m3, q0312 + shufps m5, m5, m5, q2130 +%endif + + movups [outq + offset_nq*8], m3 + movups [outq + offset_pq*8], m5 + + sub offset_pq, %1 + add offset_nq, %1 + cmp offset_nq, offset_pq + jle .loop + + REP_RET +%endmacro + +INIT_XMM sse3 +POSTROTATE_FN 2 + +%if ARCH_X86_64 && HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +POSTROTATE_FN 4 +%endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.c new file mode 100644 index 0000000000..6f35059bfe --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2013-2014 Mozilla Corporation + * Copyright (c) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Celt non-power of 2 iMDCT + */ + +#include +#include +#include + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/common.h" + +#include "mdct15.h" + +#define FFT_FLOAT 1 +#include "fft-internal.h" + +#define CMUL3(c, a, b) CMUL((c).re, (c).im, (a).re, (a).im, (b).re, (b).im) + +av_cold void ff_mdct15_uninit(MDCT15Context **ps) +{ + MDCT15Context *s = *ps; + + if (!s) + return; + + ff_fft_end(&s->ptwo_fft); + + av_freep(&s->pfa_prereindex); + av_freep(&s->pfa_postreindex); + av_freep(&s->twiddle_exptab); + av_freep(&s->tmp); + + av_freep(ps); +} + +static inline int init_pfa_reindex_tabs(MDCT15Context *s) +{ + int i, j; + const int b_ptwo = s->ptwo_fft.nbits; /* Bits for the power of two FFTs */ + const int l_ptwo = 1 << b_ptwo; /* Total length for the power of two FFTs */ + const int inv_1 = l_ptwo << ((4 - b_ptwo) & 3); /* (2^b_ptwo)^-1 mod 15 */ + const int inv_2 = 0xeeeeeeef & ((1U << b_ptwo) - 1); /* 15^-1 mod 2^b_ptwo */ + + s->pfa_prereindex = av_malloc_array(15 * l_ptwo, sizeof(*s->pfa_prereindex)); + if (!s->pfa_prereindex) + return 1; + + s->pfa_postreindex = av_malloc_array(15 * l_ptwo, sizeof(*s->pfa_postreindex)); + if (!s->pfa_postreindex) + return 1; + + /* Pre/Post-reindex */ + for (i = 0; i < l_ptwo; i++) { + for (j = 0; j < 15; j++) { + const int q_pre = ((l_ptwo * j)/15 + i) >> b_ptwo; + const int q_post = (((j*inv_1)/15) + (i*inv_2)) >> b_ptwo; + const int k_pre = 15*i + (j - q_pre*15)*(1 << b_ptwo); + const int k_post = i*inv_2*15 + j*inv_1 - 15*q_post*l_ptwo; + s->pfa_prereindex[i*15 + j] = k_pre << 1; + s->pfa_postreindex[k_post] = l_ptwo*j + i; + } + } + + return 0; +} + +/* Stride is hardcoded to 3 */ +static inline void fft5(FFTComplex *out, FFTComplex *in, FFTComplex exptab[2]) +{ + FFTComplex z0[4], t[6]; + + t[0].re = in[3].re + in[12].re; + t[0].im = in[3].im + in[12].im; + t[1].im = in[3].re - in[12].re; + t[1].re = in[3].im - in[12].im; + t[2].re = in[6].re + in[ 9].re; + t[2].im = in[6].im + in[ 9].im; + t[3].im = in[6].re - in[ 9].re; + t[3].re = in[6].im - in[ 9].im; + + out[0].re = in[0].re + in[3].re + in[6].re + in[9].re + in[12].re; + out[0].im = in[0].im + in[3].im + in[6].im + in[9].im + in[12].im; + + t[4].re = exptab[0].re * t[2].re - exptab[1].re * t[0].re; + t[4].im = exptab[0].re * t[2].im - exptab[1].re * t[0].im; + t[0].re = exptab[0].re * t[0].re - exptab[1].re * t[2].re; + t[0].im = exptab[0].re * t[0].im - exptab[1].re * t[2].im; + t[5].re = exptab[0].im * t[3].re - exptab[1].im * t[1].re; + t[5].im = exptab[0].im * t[3].im - exptab[1].im * t[1].im; + t[1].re = exptab[0].im * t[1].re + exptab[1].im * t[3].re; + t[1].im = exptab[0].im * t[1].im + exptab[1].im * t[3].im; + + z0[0].re = t[0].re - t[1].re; + z0[0].im = t[0].im - t[1].im; + z0[1].re = t[4].re + t[5].re; + z0[1].im = t[4].im + t[5].im; + + z0[2].re = t[4].re - t[5].re; + z0[2].im = t[4].im - t[5].im; + z0[3].re = t[0].re + t[1].re; + z0[3].im = t[0].im + t[1].im; + + out[1].re = in[0].re + z0[3].re; + out[1].im = in[0].im + z0[0].im; + out[2].re = in[0].re + z0[2].re; + out[2].im = in[0].im + z0[1].im; + out[3].re = in[0].re + z0[1].re; + out[3].im = in[0].im + z0[2].im; + out[4].re = in[0].re + z0[0].re; + out[4].im = in[0].im + z0[3].im; +} + +static void fft15_c(FFTComplex *out, FFTComplex *in, FFTComplex *exptab, ptrdiff_t stride) +{ + int k; + FFTComplex tmp1[5], tmp2[5], tmp3[5]; + + fft5(tmp1, in + 0, exptab + 19); + fft5(tmp2, in + 1, exptab + 19); + fft5(tmp3, in + 2, exptab + 19); + + for (k = 0; k < 5; k++) { + FFTComplex t[2]; + + CMUL3(t[0], tmp2[k], exptab[k]); + CMUL3(t[1], tmp3[k], exptab[2 * k]); + out[stride*k].re = tmp1[k].re + t[0].re + t[1].re; + out[stride*k].im = tmp1[k].im + t[0].im + t[1].im; + + CMUL3(t[0], tmp2[k], exptab[k + 5]); + CMUL3(t[1], tmp3[k], exptab[2 * (k + 5)]); + out[stride*(k + 5)].re = tmp1[k].re + t[0].re + t[1].re; + out[stride*(k + 5)].im = tmp1[k].im + t[0].im + t[1].im; + + CMUL3(t[0], tmp2[k], exptab[k + 10]); + CMUL3(t[1], tmp3[k], exptab[2 * k + 5]); + out[stride*(k + 10)].re = tmp1[k].re + t[0].re + t[1].re; + out[stride*(k + 10)].im = tmp1[k].im + t[0].im + t[1].im; + } +} + +static void mdct15(MDCT15Context *s, float *dst, const float *src, ptrdiff_t stride) +{ + int i, j; + const int len4 = s->len4, len3 = len4 * 3, len8 = len4 >> 1; + const int l_ptwo = 1 << s->ptwo_fft.nbits; + FFTComplex fft15in[15]; + + /* Folding and pre-reindexing */ + for (i = 0; i < l_ptwo; i++) { + for (j = 0; j < 15; j++) { + const int k = s->pfa_prereindex[i*15 + j]; + FFTComplex tmp, exp = s->twiddle_exptab[k >> 1]; + if (k < len4) { + tmp.re = -src[ len4 + k] + src[1*len4 - 1 - k]; + tmp.im = -src[ len3 + k] - src[1*len3 - 1 - k]; + } else { + tmp.re = -src[ len4 + k] - src[5*len4 - 1 - k]; + tmp.im = src[-len4 + k] - src[1*len3 - 1 - k]; + } + CMUL(fft15in[j].im, fft15in[j].re, tmp.re, tmp.im, exp.re, exp.im); + } + s->fft15(s->tmp + s->ptwo_fft.revtab[i], fft15in, s->exptab, l_ptwo); + } + + /* Then a 15xN FFT (where N is a power of two) */ + for (i = 0; i < 15; i++) + s->ptwo_fft.fft_calc(&s->ptwo_fft, s->tmp + l_ptwo*i); + + /* Reindex again, apply twiddles and output */ + for (i = 0; i < len8; i++) { + const int i0 = len8 + i, i1 = len8 - i - 1; + const int s0 = s->pfa_postreindex[i0], s1 = s->pfa_postreindex[i1]; + + CMUL(dst[2*i1*stride + stride], dst[2*i0*stride], s->tmp[s0].re, s->tmp[s0].im, + s->twiddle_exptab[i0].im, s->twiddle_exptab[i0].re); + CMUL(dst[2*i0*stride + stride], dst[2*i1*stride], s->tmp[s1].re, s->tmp[s1].im, + s->twiddle_exptab[i1].im, s->twiddle_exptab[i1].re); + } +} + +static void imdct15_half(MDCT15Context *s, float *dst, const float *src, + ptrdiff_t stride) +{ + FFTComplex fft15in[15]; + FFTComplex *z = (FFTComplex *)dst; + int i, j, len8 = s->len4 >> 1, l_ptwo = 1 << s->ptwo_fft.nbits; + const float *in1 = src, *in2 = src + (s->len2 - 1) * stride; + + /* Reindex input, putting it into a buffer and doing an Nx15 FFT */ + for (i = 0; i < l_ptwo; i++) { + for (j = 0; j < 15; j++) { + const int k = s->pfa_prereindex[i*15 + j]; + FFTComplex tmp = { in2[-k*stride], in1[k*stride] }; + CMUL3(fft15in[j], tmp, s->twiddle_exptab[k >> 1]); + } + s->fft15(s->tmp + s->ptwo_fft.revtab[i], fft15in, s->exptab, l_ptwo); + } + + /* Then a 15xN FFT (where N is a power of two) */ + for (i = 0; i < 15; i++) + s->ptwo_fft.fft_calc(&s->ptwo_fft, s->tmp + l_ptwo*i); + + /* Reindex again, apply twiddles and output */ + s->postreindex(z, s->tmp, s->twiddle_exptab, s->pfa_postreindex, len8); +} + +static void postrotate_c(FFTComplex *out, FFTComplex *in, FFTComplex *exp, + int *lut, ptrdiff_t len8) +{ + int i; + + /* Reindex again, apply twiddles and output */ + for (i = 0; i < len8; i++) { + const int i0 = len8 + i, i1 = len8 - i - 1; + const int s0 = lut[i0], s1 = lut[i1]; + + CMUL(out[i1].re, out[i0].im, in[s1].im, in[s1].re, exp[i1].im, exp[i1].re); + CMUL(out[i0].re, out[i1].im, in[s0].im, in[s0].re, exp[i0].im, exp[i0].re); + } +} + +av_cold int ff_mdct15_init(MDCT15Context **ps, int inverse, int N, double scale) +{ + MDCT15Context *s; + double alpha, theta; + int len2 = 15 * (1 << N); + int len = 2 * len2; + int i; + + /* Tested and verified to work on everything in between */ + if ((N < 2) || (N > 13)) + return AVERROR(EINVAL); + + s = av_mallocz(sizeof(*s)); + if (!s) + return AVERROR(ENOMEM); + + s->fft_n = N - 1; + s->len4 = len2 / 2; + s->len2 = len2; + s->inverse = inverse; + s->fft15 = fft15_c; + s->mdct = mdct15; + s->imdct_half = imdct15_half; + s->postreindex = postrotate_c; + + if (ff_fft_init(&s->ptwo_fft, N - 1, s->inverse) < 0) + goto fail; + + if (init_pfa_reindex_tabs(s)) + goto fail; + + s->tmp = av_malloc_array(len, 2 * sizeof(*s->tmp)); + if (!s->tmp) + goto fail; + + s->twiddle_exptab = av_malloc_array(s->len4, sizeof(*s->twiddle_exptab)); + if (!s->twiddle_exptab) + goto fail; + + theta = 0.125f + (scale < 0 ? s->len4 : 0); + scale = sqrt(fabs(scale)); + for (i = 0; i < s->len4; i++) { + alpha = 2 * M_PI * (i + theta) / len; + s->twiddle_exptab[i].re = cosf(alpha) * scale; + s->twiddle_exptab[i].im = sinf(alpha) * scale; + } + + /* 15-point FFT exptab */ + for (i = 0; i < 19; i++) { + if (i < 15) { + double theta = (2.0f * M_PI * i) / 15.0f; + if (!s->inverse) + theta *= -1; + s->exptab[i].re = cosf(theta); + s->exptab[i].im = sinf(theta); + } else { /* Wrap around to simplify fft15 */ + s->exptab[i] = s->exptab[i - 15]; + } + } + + /* 5-point FFT exptab */ + s->exptab[19].re = cosf(2.0f * M_PI / 5.0f); + s->exptab[19].im = sinf(2.0f * M_PI / 5.0f); + s->exptab[20].re = cosf(1.0f * M_PI / 5.0f); + s->exptab[20].im = sinf(1.0f * M_PI / 5.0f); + + /* Invert the phase for an inverse transform, do nothing for a forward transform */ + if (s->inverse) { + s->exptab[19].im *= -1; + s->exptab[20].im *= -1; + } + + if (ARCH_X86) + ff_mdct15_init_x86(s); + + *ps = s; + + return 0; + +fail: + ff_mdct15_uninit(&s); + return AVERROR(ENOMEM); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.h new file mode 100644 index 0000000000..42e60f3e10 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MDCT15_H +#define AVCODEC_MDCT15_H + +#include + +#include "fft.h" + +typedef struct MDCT15Context { + int fft_n; + int len2; + int len4; + int inverse; + int *pfa_prereindex; + int *pfa_postreindex; + + FFTContext ptwo_fft; + FFTComplex *tmp; + FFTComplex *twiddle_exptab; + + DECLARE_ALIGNED(32, FFTComplex, exptab)[64]; + + /* 15-point FFT */ + void (*fft15)(FFTComplex *out, FFTComplex *in, FFTComplex *exptab, ptrdiff_t stride); + + /* PFA postrotate and exptab */ + void (*postreindex)(FFTComplex *out, FFTComplex *in, FFTComplex *exp, int *lut, ptrdiff_t len8); + + /* Calculate a full 2N -> N MDCT */ + void (*mdct)(struct MDCT15Context *s, float *dst, const float *src, ptrdiff_t stride); + + /* Calculate the middle half of the iMDCT */ + void (*imdct_half)(struct MDCT15Context *s, float *dst, const float *src, + ptrdiff_t stride); +} MDCT15Context; + +/* Init an (i)MDCT of the length 2 * 15 * (2^N) */ +int ff_mdct15_init(MDCT15Context **ps, int inverse, int N, double scale); +void ff_mdct15_uninit(MDCT15Context **ps); + +void ff_mdct15_init_x86(MDCT15Context *s); + +#endif /* AVCODEC_MDCT15_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15_init.c new file mode 100644 index 0000000000..444801d9cf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct15_init.c @@ -0,0 +1,99 @@ +/* + * SIMD optimized non-power-of-two MDCT functions + * + * Copyright (C) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/x86/cpu.h" +#include "libavcodec/mdct15.h" + +void ff_mdct15_postreindex_sse3(FFTComplex *out, FFTComplex *in, FFTComplex *exp, int *lut, ptrdiff_t len8); +void ff_mdct15_postreindex_avx2(FFTComplex *out, FFTComplex *in, FFTComplex *exp, int *lut, ptrdiff_t len8); + +void ff_fft15_avx(FFTComplex *out, FFTComplex *in, FFTComplex *exptab, ptrdiff_t stride); + +static void perm_twiddles(MDCT15Context *s) +{ + int k; + FFTComplex tmp[30]; + + /* 5-point FFT twiddles */ + s->exptab[60].re = s->exptab[60].im = s->exptab[19].re; + s->exptab[61].re = s->exptab[61].im = s->exptab[19].im; + s->exptab[62].re = s->exptab[62].im = s->exptab[20].re; + s->exptab[63].re = s->exptab[63].im = s->exptab[20].im; + + /* 15-point FFT twiddles */ + for (k = 0; k < 5; k++) { + tmp[6*k + 0] = s->exptab[k + 0]; + tmp[6*k + 2] = s->exptab[k + 5]; + tmp[6*k + 4] = s->exptab[k + 10]; + + tmp[6*k + 1] = s->exptab[2 * (k + 0)]; + tmp[6*k + 3] = s->exptab[2 * (k + 5)]; + tmp[6*k + 5] = s->exptab[2 * k + 5 ]; + } + + for (k = 0; k < 6; k++) { + FFTComplex ac_exp[] = { + { tmp[6*1 + k].re, tmp[6*1 + k].re }, + { tmp[6*2 + k].re, tmp[6*2 + k].re }, + { tmp[6*3 + k].re, tmp[6*3 + k].re }, + { tmp[6*4 + k].re, tmp[6*4 + k].re }, + { tmp[6*1 + k].im, -tmp[6*1 + k].im }, + { tmp[6*2 + k].im, -tmp[6*2 + k].im }, + { tmp[6*3 + k].im, -tmp[6*3 + k].im }, + { tmp[6*4 + k].im, -tmp[6*4 + k].im }, + }; + memcpy(s->exptab + 8*k, ac_exp, 8*sizeof(FFTComplex)); + } + + /* Specialcase when k = 0 */ + for (k = 0; k < 3; k++) { + FFTComplex dc_exp[] = { + { tmp[2*k + 0].re, -tmp[2*k + 0].im }, + { tmp[2*k + 0].im, tmp[2*k + 0].re }, + { tmp[2*k + 1].re, -tmp[2*k + 1].im }, + { tmp[2*k + 1].im, tmp[2*k + 1].re }, + }; + memcpy(s->exptab + 8*6 + 4*k, dc_exp, 4*sizeof(FFTComplex)); + } +} + +av_cold void ff_mdct15_init_x86(MDCT15Context *s) +{ + int adjust_twiddles = 0; + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE3(cpu_flags)) + s->postreindex = ff_mdct15_postreindex_sse3; + + if (ARCH_X86_64 && EXTERNAL_AVX(cpu_flags)) { + s->fft15 = ff_fft15_avx; + adjust_twiddles = 1; + } + + if (ARCH_X86_64 && EXTERNAL_AVX2_FAST(cpu_flags)) + s->postreindex = ff_mdct15_postreindex_avx2; + + if (adjust_twiddles) + perm_twiddles(s); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct_fixed.c new file mode 100644 index 0000000000..aabf0c88f8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mdct_fixed.c @@ -0,0 +1,65 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FFT_FLOAT 0 +#define FFT_FIXED_32 0 +#include "mdct_template.c" + +/* same as ff_mdct_calcw_c with double-width unscaled output */ +void ff_mdct_calcw_c(FFTContext *s, FFTDouble *out, const FFTSample *input) +{ + int i, j, n, n8, n4, n2, n3; + FFTDouble re, im; + const uint16_t *revtab = s->revtab; + const FFTSample *tcos = s->tcos; + const FFTSample *tsin = s->tsin; + FFTComplex *x = s->tmp_buf; + FFTDComplex *o = (FFTDComplex *)out; + + n = 1 << s->mdct_bits; + n2 = n >> 1; + n4 = n >> 2; + n8 = n >> 3; + n3 = 3 * n4; + + /* pre rotation */ + for(i=0;ifft_calc(s, x); + + /* post rotation */ + for(i=0;i +#include +#include "libavutil/common.h" +#include "libavutil/libm.h" +#include "libavutil/mathematics.h" +#include "fft.h" +#include "fft-internal.h" + +/** + * @file + * MDCT/IMDCT transforms. + */ + +#if FFT_FLOAT +# define RSCALE(x, y) ((x) + (y)) +#else +#if FFT_FIXED_32 +# define RSCALE(x, y) ((int)((x) + (unsigned)(y) + 32) >> 6) +#else /* FFT_FIXED_32 */ +# define RSCALE(x, y) ((int)((x) + (unsigned)(y)) >> 1) +#endif /* FFT_FIXED_32 */ +#endif + +/** + * init MDCT or IMDCT computation. + */ +av_cold int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale) +{ + int n, n4, i; + double alpha, theta; + int tstep; + + memset(s, 0, sizeof(*s)); + n = 1 << nbits; + s->mdct_bits = nbits; + s->mdct_size = n; + n4 = n >> 2; + s->mdct_permutation = FF_MDCT_PERM_NONE; + + if (ff_fft_init(s, s->mdct_bits - 2, inverse) < 0) + goto fail; + + s->tcos = av_malloc_array(n/2, sizeof(FFTSample)); + if (!s->tcos) + goto fail; + + switch (s->mdct_permutation) { + case FF_MDCT_PERM_NONE: + s->tsin = s->tcos + n4; + tstep = 1; + break; + case FF_MDCT_PERM_INTERLEAVE: + s->tsin = s->tcos + 1; + tstep = 2; + break; + default: + goto fail; + } + + theta = 1.0 / 8.0 + (scale < 0 ? n4 : 0); + scale = sqrt(fabs(scale)); + for(i=0;itcos[i*tstep] = lrint(-cos(alpha) * 2147483648.0); + s->tsin[i*tstep] = lrint(-sin(alpha) * 2147483648.0); +#else + s->tcos[i*tstep] = FIX15(-cos(alpha) * scale); + s->tsin[i*tstep] = FIX15(-sin(alpha) * scale); +#endif + } + return 0; + fail: + ff_mdct_end(s); + return -1; +} + +/** + * Compute the middle half of the inverse MDCT of size N = 2^nbits, + * thus excluding the parts that can be derived by symmetry + * @param output N/2 samples + * @param input N/2 samples + */ +void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + int k, n8, n4, n2, n, j; + const uint16_t *revtab = s->revtab; + const FFTSample *tcos = s->tcos; + const FFTSample *tsin = s->tsin; + const FFTSample *in1, *in2; + FFTComplex *z = (FFTComplex *)output; + + n = 1 << s->mdct_bits; + n2 = n >> 1; + n4 = n >> 2; + n8 = n >> 3; + + /* pre rotation */ + in1 = input; + in2 = input + n2 - 1; + for(k = 0; k < n4; k++) { + j=revtab[k]; + CMUL(z[j].re, z[j].im, *in2, *in1, tcos[k], tsin[k]); + in1 += 2; + in2 -= 2; + } + s->fft_calc(s, z); + + /* post rotation + reordering */ + for(k = 0; k < n8; k++) { + FFTSample r0, i0, r1, i1; + CMUL(r0, i1, z[n8-k-1].im, z[n8-k-1].re, tsin[n8-k-1], tcos[n8-k-1]); + CMUL(r1, i0, z[n8+k ].im, z[n8+k ].re, tsin[n8+k ], tcos[n8+k ]); + z[n8-k-1].re = r0; + z[n8-k-1].im = i0; + z[n8+k ].re = r1; + z[n8+k ].im = i1; + } +} + +/** + * Compute inverse MDCT of size N = 2^nbits + * @param output N samples + * @param input N/2 samples + */ +void ff_imdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input) +{ + int k; + int n = 1 << s->mdct_bits; + int n2 = n >> 1; + int n4 = n >> 2; + + ff_imdct_half_c(s, output+n4, input); + + for(k = 0; k < n4; k++) { + output[k] = -output[n2-k-1]; + output[n-k-1] = output[n2+k]; + } +} + +/** + * Compute MDCT of size N = 2^nbits + * @param input N samples + * @param out N/2 samples + */ +void ff_mdct_calc_c(FFTContext *s, FFTSample *out, const FFTSample *input) +{ + int i, j, n, n8, n4, n2, n3; + FFTDouble re, im; + const uint16_t *revtab = s->revtab; + const FFTSample *tcos = s->tcos; + const FFTSample *tsin = s->tsin; + FFTComplex *x = (FFTComplex *)out; + + n = 1 << s->mdct_bits; + n2 = n >> 1; + n4 = n >> 2; + n8 = n >> 3; + n3 = 3 * n4; + + /* pre rotation */ + for(i=0;ifft_calc(s, x); + + /* post rotation */ + for(i=0;itcos); + ff_fft_end(s); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/me_cmp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/me_cmp.c new file mode 100644 index 0000000000..ae248c52f8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/me_cmp.c @@ -0,0 +1,1098 @@ +/* + * DSP utils + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/internal.h" +#include "avcodec.h" +#include "copy_block.h" +#include "simple_idct.h" +#include "me_cmp.h" +#include "mpegvideo.h" +#include "config.h" + +/* (i - 256) * (i - 256) */ +const uint32_t ff_square_tab[512] = { + 65536, 65025, 64516, 64009, 63504, 63001, 62500, 62001, 61504, 61009, 60516, 60025, 59536, 59049, 58564, 58081, + 57600, 57121, 56644, 56169, 55696, 55225, 54756, 54289, 53824, 53361, 52900, 52441, 51984, 51529, 51076, 50625, + 50176, 49729, 49284, 48841, 48400, 47961, 47524, 47089, 46656, 46225, 45796, 45369, 44944, 44521, 44100, 43681, + 43264, 42849, 42436, 42025, 41616, 41209, 40804, 40401, 40000, 39601, 39204, 38809, 38416, 38025, 37636, 37249, + 36864, 36481, 36100, 35721, 35344, 34969, 34596, 34225, 33856, 33489, 33124, 32761, 32400, 32041, 31684, 31329, + 30976, 30625, 30276, 29929, 29584, 29241, 28900, 28561, 28224, 27889, 27556, 27225, 26896, 26569, 26244, 25921, + 25600, 25281, 24964, 24649, 24336, 24025, 23716, 23409, 23104, 22801, 22500, 22201, 21904, 21609, 21316, 21025, + 20736, 20449, 20164, 19881, 19600, 19321, 19044, 18769, 18496, 18225, 17956, 17689, 17424, 17161, 16900, 16641, + 16384, 16129, 15876, 15625, 15376, 15129, 14884, 14641, 14400, 14161, 13924, 13689, 13456, 13225, 12996, 12769, + 12544, 12321, 12100, 11881, 11664, 11449, 11236, 11025, 10816, 10609, 10404, 10201, 10000, 9801, 9604, 9409, + 9216, 9025, 8836, 8649, 8464, 8281, 8100, 7921, 7744, 7569, 7396, 7225, 7056, 6889, 6724, 6561, + 6400, 6241, 6084, 5929, 5776, 5625, 5476, 5329, 5184, 5041, 4900, 4761, 4624, 4489, 4356, 4225, + 4096, 3969, 3844, 3721, 3600, 3481, 3364, 3249, 3136, 3025, 2916, 2809, 2704, 2601, 2500, 2401, + 2304, 2209, 2116, 2025, 1936, 1849, 1764, 1681, 1600, 1521, 1444, 1369, 1296, 1225, 1156, 1089, + 1024, 961, 900, 841, 784, 729, 676, 625, 576, 529, 484, 441, 400, 361, 324, 289, + 256, 225, 196, 169, 144, 121, 100, 81, 64, 49, 36, 25, 16, 9, 4, 1, + 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, + 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, + 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, + 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, + 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, + 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, + 9216, 9409, 9604, 9801, 10000, 10201, 10404, 10609, 10816, 11025, 11236, 11449, 11664, 11881, 12100, 12321, + 12544, 12769, 12996, 13225, 13456, 13689, 13924, 14161, 14400, 14641, 14884, 15129, 15376, 15625, 15876, 16129, + 16384, 16641, 16900, 17161, 17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600, 19881, 20164, 20449, + 20736, 21025, 21316, 21609, 21904, 22201, 22500, 22801, 23104, 23409, 23716, 24025, 24336, 24649, 24964, 25281, + 25600, 25921, 26244, 26569, 26896, 27225, 27556, 27889, 28224, 28561, 28900, 29241, 29584, 29929, 30276, 30625, + 30976, 31329, 31684, 32041, 32400, 32761, 33124, 33489, 33856, 34225, 34596, 34969, 35344, 35721, 36100, 36481, + 36864, 37249, 37636, 38025, 38416, 38809, 39204, 39601, 40000, 40401, 40804, 41209, 41616, 42025, 42436, 42849, + 43264, 43681, 44100, 44521, 44944, 45369, 45796, 46225, 46656, 47089, 47524, 47961, 48400, 48841, 49284, 49729, + 50176, 50625, 51076, 51529, 51984, 52441, 52900, 53361, 53824, 54289, 54756, 55225, 55696, 56169, 56644, 57121, + 57600, 58081, 58564, 59049, 59536, 60025, 60516, 61009, 61504, 62001, 62500, 63001, 63504, 64009, 64516, 65025, +}; + +static int sse4_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + const uint32_t *sq = ff_square_tab + 256; + + for (i = 0; i < h; i++) { + s += sq[pix1[0] - pix2[0]]; + s += sq[pix1[1] - pix2[1]]; + s += sq[pix1[2] - pix2[2]]; + s += sq[pix1[3] - pix2[3]]; + pix1 += stride; + pix2 += stride; + } + return s; +} + +static int sse8_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + const uint32_t *sq = ff_square_tab + 256; + + for (i = 0; i < h; i++) { + s += sq[pix1[0] - pix2[0]]; + s += sq[pix1[1] - pix2[1]]; + s += sq[pix1[2] - pix2[2]]; + s += sq[pix1[3] - pix2[3]]; + s += sq[pix1[4] - pix2[4]]; + s += sq[pix1[5] - pix2[5]]; + s += sq[pix1[6] - pix2[6]]; + s += sq[pix1[7] - pix2[7]]; + pix1 += stride; + pix2 += stride; + } + return s; +} + +static int sse16_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + const uint32_t *sq = ff_square_tab + 256; + + for (i = 0; i < h; i++) { + s += sq[pix1[0] - pix2[0]]; + s += sq[pix1[1] - pix2[1]]; + s += sq[pix1[2] - pix2[2]]; + s += sq[pix1[3] - pix2[3]]; + s += sq[pix1[4] - pix2[4]]; + s += sq[pix1[5] - pix2[5]]; + s += sq[pix1[6] - pix2[6]]; + s += sq[pix1[7] - pix2[7]]; + s += sq[pix1[8] - pix2[8]]; + s += sq[pix1[9] - pix2[9]]; + s += sq[pix1[10] - pix2[10]]; + s += sq[pix1[11] - pix2[11]]; + s += sq[pix1[12] - pix2[12]]; + s += sq[pix1[13] - pix2[13]]; + s += sq[pix1[14] - pix2[14]]; + s += sq[pix1[15] - pix2[15]]; + + pix1 += stride; + pix2 += stride; + } + return s; +} + +static int sum_abs_dctelem_c(int16_t *block) +{ + int sum = 0, i; + + for (i = 0; i < 64; i++) + sum += FFABS(block[i]); + return sum; +} + +#define avg2(a, b) (((a) + (b) + 1) >> 1) +#define avg4(a, b, c, d) (((a) + (b) + (c) + (d) + 2) >> 2) + +static inline int pix_abs16_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + + for (i = 0; i < h; i++) { + s += abs(pix1[0] - pix2[0]); + s += abs(pix1[1] - pix2[1]); + s += abs(pix1[2] - pix2[2]); + s += abs(pix1[3] - pix2[3]); + s += abs(pix1[4] - pix2[4]); + s += abs(pix1[5] - pix2[5]); + s += abs(pix1[6] - pix2[6]); + s += abs(pix1[7] - pix2[7]); + s += abs(pix1[8] - pix2[8]); + s += abs(pix1[9] - pix2[9]); + s += abs(pix1[10] - pix2[10]); + s += abs(pix1[11] - pix2[11]); + s += abs(pix1[12] - pix2[12]); + s += abs(pix1[13] - pix2[13]); + s += abs(pix1[14] - pix2[14]); + s += abs(pix1[15] - pix2[15]); + pix1 += stride; + pix2 += stride; + } + return s; +} + +static inline int pix_median_abs16_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i, j; + +#define V(x) (pix1[x] - pix2[x]) + + s += abs(V(0)); + s += abs(V(1) - V(0)); + s += abs(V(2) - V(1)); + s += abs(V(3) - V(2)); + s += abs(V(4) - V(3)); + s += abs(V(5) - V(4)); + s += abs(V(6) - V(5)); + s += abs(V(7) - V(6)); + s += abs(V(8) - V(7)); + s += abs(V(9) - V(8)); + s += abs(V(10) - V(9)); + s += abs(V(11) - V(10)); + s += abs(V(12) - V(11)); + s += abs(V(13) - V(12)); + s += abs(V(14) - V(13)); + s += abs(V(15) - V(14)); + + pix1 += stride; + pix2 += stride; + + for (i = 1; i < h; i++) { + s += abs(V(0) - V(-stride)); + for (j = 1; j < 16; j++) + s += abs(V(j) - mid_pred(V(j-stride), V(j-1), V(j-stride) + V(j-1) - V(j-stride-1))); + pix1 += stride; + pix2 += stride; + + } +#undef V + return s; +} + +static int pix_abs16_x2_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + + for (i = 0; i < h; i++) { + s += abs(pix1[0] - avg2(pix2[0], pix2[1])); + s += abs(pix1[1] - avg2(pix2[1], pix2[2])); + s += abs(pix1[2] - avg2(pix2[2], pix2[3])); + s += abs(pix1[3] - avg2(pix2[3], pix2[4])); + s += abs(pix1[4] - avg2(pix2[4], pix2[5])); + s += abs(pix1[5] - avg2(pix2[5], pix2[6])); + s += abs(pix1[6] - avg2(pix2[6], pix2[7])); + s += abs(pix1[7] - avg2(pix2[7], pix2[8])); + s += abs(pix1[8] - avg2(pix2[8], pix2[9])); + s += abs(pix1[9] - avg2(pix2[9], pix2[10])); + s += abs(pix1[10] - avg2(pix2[10], pix2[11])); + s += abs(pix1[11] - avg2(pix2[11], pix2[12])); + s += abs(pix1[12] - avg2(pix2[12], pix2[13])); + s += abs(pix1[13] - avg2(pix2[13], pix2[14])); + s += abs(pix1[14] - avg2(pix2[14], pix2[15])); + s += abs(pix1[15] - avg2(pix2[15], pix2[16])); + pix1 += stride; + pix2 += stride; + } + return s; +} + +static int pix_abs16_y2_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + uint8_t *pix3 = pix2 + stride; + + for (i = 0; i < h; i++) { + s += abs(pix1[0] - avg2(pix2[0], pix3[0])); + s += abs(pix1[1] - avg2(pix2[1], pix3[1])); + s += abs(pix1[2] - avg2(pix2[2], pix3[2])); + s += abs(pix1[3] - avg2(pix2[3], pix3[3])); + s += abs(pix1[4] - avg2(pix2[4], pix3[4])); + s += abs(pix1[5] - avg2(pix2[5], pix3[5])); + s += abs(pix1[6] - avg2(pix2[6], pix3[6])); + s += abs(pix1[7] - avg2(pix2[7], pix3[7])); + s += abs(pix1[8] - avg2(pix2[8], pix3[8])); + s += abs(pix1[9] - avg2(pix2[9], pix3[9])); + s += abs(pix1[10] - avg2(pix2[10], pix3[10])); + s += abs(pix1[11] - avg2(pix2[11], pix3[11])); + s += abs(pix1[12] - avg2(pix2[12], pix3[12])); + s += abs(pix1[13] - avg2(pix2[13], pix3[13])); + s += abs(pix1[14] - avg2(pix2[14], pix3[14])); + s += abs(pix1[15] - avg2(pix2[15], pix3[15])); + pix1 += stride; + pix2 += stride; + pix3 += stride; + } + return s; +} + +static int pix_abs16_xy2_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + uint8_t *pix3 = pix2 + stride; + + for (i = 0; i < h; i++) { + s += abs(pix1[0] - avg4(pix2[0], pix2[1], pix3[0], pix3[1])); + s += abs(pix1[1] - avg4(pix2[1], pix2[2], pix3[1], pix3[2])); + s += abs(pix1[2] - avg4(pix2[2], pix2[3], pix3[2], pix3[3])); + s += abs(pix1[3] - avg4(pix2[3], pix2[4], pix3[3], pix3[4])); + s += abs(pix1[4] - avg4(pix2[4], pix2[5], pix3[4], pix3[5])); + s += abs(pix1[5] - avg4(pix2[5], pix2[6], pix3[5], pix3[6])); + s += abs(pix1[6] - avg4(pix2[6], pix2[7], pix3[6], pix3[7])); + s += abs(pix1[7] - avg4(pix2[7], pix2[8], pix3[7], pix3[8])); + s += abs(pix1[8] - avg4(pix2[8], pix2[9], pix3[8], pix3[9])); + s += abs(pix1[9] - avg4(pix2[9], pix2[10], pix3[9], pix3[10])); + s += abs(pix1[10] - avg4(pix2[10], pix2[11], pix3[10], pix3[11])); + s += abs(pix1[11] - avg4(pix2[11], pix2[12], pix3[11], pix3[12])); + s += abs(pix1[12] - avg4(pix2[12], pix2[13], pix3[12], pix3[13])); + s += abs(pix1[13] - avg4(pix2[13], pix2[14], pix3[13], pix3[14])); + s += abs(pix1[14] - avg4(pix2[14], pix2[15], pix3[14], pix3[15])); + s += abs(pix1[15] - avg4(pix2[15], pix2[16], pix3[15], pix3[16])); + pix1 += stride; + pix2 += stride; + pix3 += stride; + } + return s; +} + +static inline int pix_abs8_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + + for (i = 0; i < h; i++) { + s += abs(pix1[0] - pix2[0]); + s += abs(pix1[1] - pix2[1]); + s += abs(pix1[2] - pix2[2]); + s += abs(pix1[3] - pix2[3]); + s += abs(pix1[4] - pix2[4]); + s += abs(pix1[5] - pix2[5]); + s += abs(pix1[6] - pix2[6]); + s += abs(pix1[7] - pix2[7]); + pix1 += stride; + pix2 += stride; + } + return s; +} + +static inline int pix_median_abs8_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i, j; + +#define V(x) (pix1[x] - pix2[x]) + + s += abs(V(0)); + s += abs(V(1) - V(0)); + s += abs(V(2) - V(1)); + s += abs(V(3) - V(2)); + s += abs(V(4) - V(3)); + s += abs(V(5) - V(4)); + s += abs(V(6) - V(5)); + s += abs(V(7) - V(6)); + + pix1 += stride; + pix2 += stride; + + for (i = 1; i < h; i++) { + s += abs(V(0) - V(-stride)); + for (j = 1; j < 8; j++) + s += abs(V(j) - mid_pred(V(j-stride), V(j-1), V(j-stride) + V(j-1) - V(j-stride-1))); + pix1 += stride; + pix2 += stride; + + } +#undef V + return s; +} + +static int pix_abs8_x2_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + + for (i = 0; i < h; i++) { + s += abs(pix1[0] - avg2(pix2[0], pix2[1])); + s += abs(pix1[1] - avg2(pix2[1], pix2[2])); + s += abs(pix1[2] - avg2(pix2[2], pix2[3])); + s += abs(pix1[3] - avg2(pix2[3], pix2[4])); + s += abs(pix1[4] - avg2(pix2[4], pix2[5])); + s += abs(pix1[5] - avg2(pix2[5], pix2[6])); + s += abs(pix1[6] - avg2(pix2[6], pix2[7])); + s += abs(pix1[7] - avg2(pix2[7], pix2[8])); + pix1 += stride; + pix2 += stride; + } + return s; +} + +static int pix_abs8_y2_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + uint8_t *pix3 = pix2 + stride; + + for (i = 0; i < h; i++) { + s += abs(pix1[0] - avg2(pix2[0], pix3[0])); + s += abs(pix1[1] - avg2(pix2[1], pix3[1])); + s += abs(pix1[2] - avg2(pix2[2], pix3[2])); + s += abs(pix1[3] - avg2(pix2[3], pix3[3])); + s += abs(pix1[4] - avg2(pix2[4], pix3[4])); + s += abs(pix1[5] - avg2(pix2[5], pix3[5])); + s += abs(pix1[6] - avg2(pix2[6], pix3[6])); + s += abs(pix1[7] - avg2(pix2[7], pix3[7])); + pix1 += stride; + pix2 += stride; + pix3 += stride; + } + return s; +} + +static int pix_abs8_xy2_c(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int s = 0, i; + uint8_t *pix3 = pix2 + stride; + + for (i = 0; i < h; i++) { + s += abs(pix1[0] - avg4(pix2[0], pix2[1], pix3[0], pix3[1])); + s += abs(pix1[1] - avg4(pix2[1], pix2[2], pix3[1], pix3[2])); + s += abs(pix1[2] - avg4(pix2[2], pix2[3], pix3[2], pix3[3])); + s += abs(pix1[3] - avg4(pix2[3], pix2[4], pix3[3], pix3[4])); + s += abs(pix1[4] - avg4(pix2[4], pix2[5], pix3[4], pix3[5])); + s += abs(pix1[5] - avg4(pix2[5], pix2[6], pix3[5], pix3[6])); + s += abs(pix1[6] - avg4(pix2[6], pix2[7], pix3[6], pix3[7])); + s += abs(pix1[7] - avg4(pix2[7], pix2[8], pix3[7], pix3[8])); + pix1 += stride; + pix2 += stride; + pix3 += stride; + } + return s; +} + +static int nsse16_c(MpegEncContext *c, uint8_t *s1, uint8_t *s2, + ptrdiff_t stride, int h) +{ + int score1 = 0, score2 = 0, x, y; + + for (y = 0; y < h; y++) { + for (x = 0; x < 16; x++) + score1 += (s1[x] - s2[x]) * (s1[x] - s2[x]); + if (y + 1 < h) { + for (x = 0; x < 15; x++) + score2 += FFABS(s1[x] - s1[x + stride] - + s1[x + 1] + s1[x + stride + 1]) - + FFABS(s2[x] - s2[x + stride] - + s2[x + 1] + s2[x + stride + 1]); + } + s1 += stride; + s2 += stride; + } + + if (c) + return score1 + FFABS(score2) * c->avctx->nsse_weight; + else + return score1 + FFABS(score2) * 8; +} + +static int nsse8_c(MpegEncContext *c, uint8_t *s1, uint8_t *s2, + ptrdiff_t stride, int h) +{ + int score1 = 0, score2 = 0, x, y; + + for (y = 0; y < h; y++) { + for (x = 0; x < 8; x++) + score1 += (s1[x] - s2[x]) * (s1[x] - s2[x]); + if (y + 1 < h) { + for (x = 0; x < 7; x++) + score2 += FFABS(s1[x] - s1[x + stride] - + s1[x + 1] + s1[x + stride + 1]) - + FFABS(s2[x] - s2[x + stride] - + s2[x + 1] + s2[x + stride + 1]); + } + s1 += stride; + s2 += stride; + } + + if (c) + return score1 + FFABS(score2) * c->avctx->nsse_weight; + else + return score1 + FFABS(score2) * 8; +} + +static int zero_cmp(MpegEncContext *s, uint8_t *a, uint8_t *b, + ptrdiff_t stride, int h) +{ + return 0; +} + +void ff_set_cmp(MECmpContext *c, me_cmp_func *cmp, int type) +{ + int i; + + memset(cmp, 0, sizeof(void *) * 6); + + for (i = 0; i < 6; i++) { + switch (type & 0xFF) { + case FF_CMP_SAD: + cmp[i] = c->sad[i]; + break; + case FF_CMP_MEDIAN_SAD: + cmp[i] = c->median_sad[i]; + break; + case FF_CMP_SATD: + cmp[i] = c->hadamard8_diff[i]; + break; + case FF_CMP_SSE: + cmp[i] = c->sse[i]; + break; + case FF_CMP_DCT: + cmp[i] = c->dct_sad[i]; + break; + case FF_CMP_DCT264: + cmp[i] = c->dct264_sad[i]; + break; + case FF_CMP_DCTMAX: + cmp[i] = c->dct_max[i]; + break; + case FF_CMP_PSNR: + cmp[i] = c->quant_psnr[i]; + break; + case FF_CMP_BIT: + cmp[i] = c->bit[i]; + break; + case FF_CMP_RD: + cmp[i] = c->rd[i]; + break; + case FF_CMP_VSAD: + cmp[i] = c->vsad[i]; + break; + case FF_CMP_VSSE: + cmp[i] = c->vsse[i]; + break; + case FF_CMP_ZERO: + cmp[i] = zero_cmp; + break; + case FF_CMP_NSSE: + cmp[i] = c->nsse[i]; + break; +#if CONFIG_DWT + case FF_CMP_W53: + cmp[i]= c->w53[i]; + break; + case FF_CMP_W97: + cmp[i]= c->w97[i]; + break; +#endif + default: + av_log(NULL, AV_LOG_ERROR, + "internal error in cmp function selection\n"); + } + } +} + +#define BUTTERFLY2(o1, o2, i1, i2) \ + o1 = (i1) + (i2); \ + o2 = (i1) - (i2); + +#define BUTTERFLY1(x, y) \ + { \ + int a, b; \ + a = x; \ + b = y; \ + x = a + b; \ + y = a - b; \ + } + +#define BUTTERFLYA(x, y) (FFABS((x) + (y)) + FFABS((x) - (y))) + +static int hadamard8_diff8x8_c(MpegEncContext *s, uint8_t *dst, + uint8_t *src, ptrdiff_t stride, int h) +{ + int i, temp[64], sum = 0; + + av_assert2(h == 8); + + for (i = 0; i < 8; i++) { + // FIXME: try pointer walks + BUTTERFLY2(temp[8 * i + 0], temp[8 * i + 1], + src[stride * i + 0] - dst[stride * i + 0], + src[stride * i + 1] - dst[stride * i + 1]); + BUTTERFLY2(temp[8 * i + 2], temp[8 * i + 3], + src[stride * i + 2] - dst[stride * i + 2], + src[stride * i + 3] - dst[stride * i + 3]); + BUTTERFLY2(temp[8 * i + 4], temp[8 * i + 5], + src[stride * i + 4] - dst[stride * i + 4], + src[stride * i + 5] - dst[stride * i + 5]); + BUTTERFLY2(temp[8 * i + 6], temp[8 * i + 7], + src[stride * i + 6] - dst[stride * i + 6], + src[stride * i + 7] - dst[stride * i + 7]); + + BUTTERFLY1(temp[8 * i + 0], temp[8 * i + 2]); + BUTTERFLY1(temp[8 * i + 1], temp[8 * i + 3]); + BUTTERFLY1(temp[8 * i + 4], temp[8 * i + 6]); + BUTTERFLY1(temp[8 * i + 5], temp[8 * i + 7]); + + BUTTERFLY1(temp[8 * i + 0], temp[8 * i + 4]); + BUTTERFLY1(temp[8 * i + 1], temp[8 * i + 5]); + BUTTERFLY1(temp[8 * i + 2], temp[8 * i + 6]); + BUTTERFLY1(temp[8 * i + 3], temp[8 * i + 7]); + } + + for (i = 0; i < 8; i++) { + BUTTERFLY1(temp[8 * 0 + i], temp[8 * 1 + i]); + BUTTERFLY1(temp[8 * 2 + i], temp[8 * 3 + i]); + BUTTERFLY1(temp[8 * 4 + i], temp[8 * 5 + i]); + BUTTERFLY1(temp[8 * 6 + i], temp[8 * 7 + i]); + + BUTTERFLY1(temp[8 * 0 + i], temp[8 * 2 + i]); + BUTTERFLY1(temp[8 * 1 + i], temp[8 * 3 + i]); + BUTTERFLY1(temp[8 * 4 + i], temp[8 * 6 + i]); + BUTTERFLY1(temp[8 * 5 + i], temp[8 * 7 + i]); + + sum += BUTTERFLYA(temp[8 * 0 + i], temp[8 * 4 + i]) + + BUTTERFLYA(temp[8 * 1 + i], temp[8 * 5 + i]) + + BUTTERFLYA(temp[8 * 2 + i], temp[8 * 6 + i]) + + BUTTERFLYA(temp[8 * 3 + i], temp[8 * 7 + i]); + } + return sum; +} + +static int hadamard8_intra8x8_c(MpegEncContext *s, uint8_t *src, + uint8_t *dummy, ptrdiff_t stride, int h) +{ + int i, temp[64], sum = 0; + + av_assert2(h == 8); + + for (i = 0; i < 8; i++) { + // FIXME: try pointer walks + BUTTERFLY2(temp[8 * i + 0], temp[8 * i + 1], + src[stride * i + 0], src[stride * i + 1]); + BUTTERFLY2(temp[8 * i + 2], temp[8 * i + 3], + src[stride * i + 2], src[stride * i + 3]); + BUTTERFLY2(temp[8 * i + 4], temp[8 * i + 5], + src[stride * i + 4], src[stride * i + 5]); + BUTTERFLY2(temp[8 * i + 6], temp[8 * i + 7], + src[stride * i + 6], src[stride * i + 7]); + + BUTTERFLY1(temp[8 * i + 0], temp[8 * i + 2]); + BUTTERFLY1(temp[8 * i + 1], temp[8 * i + 3]); + BUTTERFLY1(temp[8 * i + 4], temp[8 * i + 6]); + BUTTERFLY1(temp[8 * i + 5], temp[8 * i + 7]); + + BUTTERFLY1(temp[8 * i + 0], temp[8 * i + 4]); + BUTTERFLY1(temp[8 * i + 1], temp[8 * i + 5]); + BUTTERFLY1(temp[8 * i + 2], temp[8 * i + 6]); + BUTTERFLY1(temp[8 * i + 3], temp[8 * i + 7]); + } + + for (i = 0; i < 8; i++) { + BUTTERFLY1(temp[8 * 0 + i], temp[8 * 1 + i]); + BUTTERFLY1(temp[8 * 2 + i], temp[8 * 3 + i]); + BUTTERFLY1(temp[8 * 4 + i], temp[8 * 5 + i]); + BUTTERFLY1(temp[8 * 6 + i], temp[8 * 7 + i]); + + BUTTERFLY1(temp[8 * 0 + i], temp[8 * 2 + i]); + BUTTERFLY1(temp[8 * 1 + i], temp[8 * 3 + i]); + BUTTERFLY1(temp[8 * 4 + i], temp[8 * 6 + i]); + BUTTERFLY1(temp[8 * 5 + i], temp[8 * 7 + i]); + + sum += + BUTTERFLYA(temp[8 * 0 + i], temp[8 * 4 + i]) + + BUTTERFLYA(temp[8 * 1 + i], temp[8 * 5 + i]) + + BUTTERFLYA(temp[8 * 2 + i], temp[8 * 6 + i]) + + BUTTERFLYA(temp[8 * 3 + i], temp[8 * 7 + i]); + } + + sum -= FFABS(temp[8 * 0] + temp[8 * 4]); // -mean + + return sum; +} + +static int dct_sad8x8_c(MpegEncContext *s, uint8_t *src1, + uint8_t *src2, ptrdiff_t stride, int h) +{ + LOCAL_ALIGNED_16(int16_t, temp, [64]); + + av_assert2(h == 8); + + s->pdsp.diff_pixels_unaligned(temp, src1, src2, stride); + s->fdsp.fdct(temp); + return s->mecc.sum_abs_dctelem(temp); +} + +#if CONFIG_GPL +#define DCT8_1D \ + { \ + const int s07 = SRC(0) + SRC(7); \ + const int s16 = SRC(1) + SRC(6); \ + const int s25 = SRC(2) + SRC(5); \ + const int s34 = SRC(3) + SRC(4); \ + const int a0 = s07 + s34; \ + const int a1 = s16 + s25; \ + const int a2 = s07 - s34; \ + const int a3 = s16 - s25; \ + const int d07 = SRC(0) - SRC(7); \ + const int d16 = SRC(1) - SRC(6); \ + const int d25 = SRC(2) - SRC(5); \ + const int d34 = SRC(3) - SRC(4); \ + const int a4 = d16 + d25 + (d07 + (d07 >> 1)); \ + const int a5 = d07 - d34 - (d25 + (d25 >> 1)); \ + const int a6 = d07 + d34 - (d16 + (d16 >> 1)); \ + const int a7 = d16 - d25 + (d34 + (d34 >> 1)); \ + DST(0, a0 + a1); \ + DST(1, a4 + (a7 >> 2)); \ + DST(2, a2 + (a3 >> 1)); \ + DST(3, a5 + (a6 >> 2)); \ + DST(4, a0 - a1); \ + DST(5, a6 - (a5 >> 2)); \ + DST(6, (a2 >> 1) - a3); \ + DST(7, (a4 >> 2) - a7); \ + } + +static int dct264_sad8x8_c(MpegEncContext *s, uint8_t *src1, + uint8_t *src2, ptrdiff_t stride, int h) +{ + int16_t dct[8][8]; + int i, sum = 0; + + s->pdsp.diff_pixels_unaligned(dct[0], src1, src2, stride); + +#define SRC(x) dct[i][x] +#define DST(x, v) dct[i][x] = v + for (i = 0; i < 8; i++) + DCT8_1D +#undef SRC +#undef DST + +#define SRC(x) dct[x][i] +#define DST(x, v) sum += FFABS(v) + for (i = 0; i < 8; i++) + DCT8_1D +#undef SRC +#undef DST + return sum; +} +#endif + +static int dct_max8x8_c(MpegEncContext *s, uint8_t *src1, + uint8_t *src2, ptrdiff_t stride, int h) +{ + LOCAL_ALIGNED_16(int16_t, temp, [64]); + int sum = 0, i; + + av_assert2(h == 8); + + s->pdsp.diff_pixels_unaligned(temp, src1, src2, stride); + s->fdsp.fdct(temp); + + for (i = 0; i < 64; i++) + sum = FFMAX(sum, FFABS(temp[i])); + + return sum; +} + +static int quant_psnr8x8_c(MpegEncContext *s, uint8_t *src1, + uint8_t *src2, ptrdiff_t stride, int h) +{ + LOCAL_ALIGNED_16(int16_t, temp, [64 * 2]); + int16_t *const bak = temp + 64; + int sum = 0, i; + + av_assert2(h == 8); + s->mb_intra = 0; + + s->pdsp.diff_pixels_unaligned(temp, src1, src2, stride); + + memcpy(bak, temp, 64 * sizeof(int16_t)); + + s->block_last_index[0 /* FIXME */] = + s->fast_dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); + s->dct_unquantize_inter(s, temp, 0, s->qscale); + ff_simple_idct_int16_8bit(temp); // FIXME + + for (i = 0; i < 64; i++) + sum += (temp[i] - bak[i]) * (temp[i] - bak[i]); + + return sum; +} + +static int rd8x8_c(MpegEncContext *s, uint8_t *src1, uint8_t *src2, + ptrdiff_t stride, int h) +{ + const uint8_t *scantable = s->intra_scantable.permutated; + LOCAL_ALIGNED_16(int16_t, temp, [64]); + LOCAL_ALIGNED_16(uint8_t, lsrc1, [64]); + LOCAL_ALIGNED_16(uint8_t, lsrc2, [64]); + int i, last, run, bits, level, distortion, start_i; + const int esc_length = s->ac_esc_length; + uint8_t *length, *last_length; + + av_assert2(h == 8); + + copy_block8(lsrc1, src1, 8, stride, 8); + copy_block8(lsrc2, src2, 8, stride, 8); + + s->pdsp.diff_pixels(temp, lsrc1, lsrc2, 8); + + s->block_last_index[0 /* FIXME */] = + last = + s->fast_dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); + + bits = 0; + + if (s->mb_intra) { + start_i = 1; + length = s->intra_ac_vlc_length; + last_length = s->intra_ac_vlc_last_length; + bits += s->luma_dc_vlc_length[temp[0] + 256]; // FIXME: chroma + } else { + start_i = 0; + length = s->inter_ac_vlc_length; + last_length = s->inter_ac_vlc_last_length; + } + + if (last >= start_i) { + run = 0; + for (i = start_i; i < last; i++) { + int j = scantable[i]; + level = temp[j]; + + if (level) { + level += 64; + if ((level & (~127)) == 0) + bits += length[UNI_AC_ENC_INDEX(run, level)]; + else + bits += esc_length; + run = 0; + } else + run++; + } + i = scantable[last]; + + level = temp[i] + 64; + + av_assert2(level - 64); + + if ((level & (~127)) == 0) { + bits += last_length[UNI_AC_ENC_INDEX(run, level)]; + } else + bits += esc_length; + } + + if (last >= 0) { + if (s->mb_intra) + s->dct_unquantize_intra(s, temp, 0, s->qscale); + else + s->dct_unquantize_inter(s, temp, 0, s->qscale); + } + + s->idsp.idct_add(lsrc2, 8, temp); + + distortion = s->mecc.sse[1](NULL, lsrc2, lsrc1, 8, 8); + + return distortion + ((bits * s->qscale * s->qscale * 109 + 64) >> 7); +} + +static int bit8x8_c(MpegEncContext *s, uint8_t *src1, uint8_t *src2, + ptrdiff_t stride, int h) +{ + const uint8_t *scantable = s->intra_scantable.permutated; + LOCAL_ALIGNED_16(int16_t, temp, [64]); + int i, last, run, bits, level, start_i; + const int esc_length = s->ac_esc_length; + uint8_t *length, *last_length; + + av_assert2(h == 8); + + s->pdsp.diff_pixels_unaligned(temp, src1, src2, stride); + + s->block_last_index[0 /* FIXME */] = + last = + s->fast_dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); + + bits = 0; + + if (s->mb_intra) { + start_i = 1; + length = s->intra_ac_vlc_length; + last_length = s->intra_ac_vlc_last_length; + bits += s->luma_dc_vlc_length[temp[0] + 256]; // FIXME: chroma + } else { + start_i = 0; + length = s->inter_ac_vlc_length; + last_length = s->inter_ac_vlc_last_length; + } + + if (last >= start_i) { + run = 0; + for (i = start_i; i < last; i++) { + int j = scantable[i]; + level = temp[j]; + + if (level) { + level += 64; + if ((level & (~127)) == 0) + bits += length[UNI_AC_ENC_INDEX(run, level)]; + else + bits += esc_length; + run = 0; + } else + run++; + } + i = scantable[last]; + + level = temp[i] + 64; + + av_assert2(level - 64); + + if ((level & (~127)) == 0) + bits += last_length[UNI_AC_ENC_INDEX(run, level)]; + else + bits += esc_length; + } + + return bits; +} + +#define VSAD_INTRA(size) \ +static int vsad_intra ## size ## _c(MpegEncContext *c, \ + uint8_t *s, uint8_t *dummy, \ + ptrdiff_t stride, int h) \ +{ \ + int score = 0, x, y; \ + \ + for (y = 1; y < h; y++) { \ + for (x = 0; x < size; x += 4) { \ + score += FFABS(s[x] - s[x + stride]) + \ + FFABS(s[x + 1] - s[x + stride + 1]) + \ + FFABS(s[x + 2] - s[x + 2 + stride]) + \ + FFABS(s[x + 3] - s[x + 3 + stride]); \ + } \ + s += stride; \ + } \ + \ + return score; \ +} +VSAD_INTRA(8) +VSAD_INTRA(16) + +#define VSAD(size) \ +static int vsad ## size ## _c(MpegEncContext *c, \ + uint8_t *s1, uint8_t *s2, \ + ptrdiff_t stride, int h) \ +{ \ + int score = 0, x, y; \ + \ + for (y = 1; y < h; y++) { \ + for (x = 0; x < size; x++) \ + score += FFABS(s1[x] - s2[x] - s1[x + stride] + s2[x + stride]); \ + s1 += stride; \ + s2 += stride; \ + } \ + \ + return score; \ +} +VSAD(8) +VSAD(16) + +#define SQ(a) ((a) * (a)) +#define VSSE_INTRA(size) \ +static int vsse_intra ## size ## _c(MpegEncContext *c, \ + uint8_t *s, uint8_t *dummy, \ + ptrdiff_t stride, int h) \ +{ \ + int score = 0, x, y; \ + \ + for (y = 1; y < h; y++) { \ + for (x = 0; x < size; x += 4) { \ + score += SQ(s[x] - s[x + stride]) + \ + SQ(s[x + 1] - s[x + stride + 1]) + \ + SQ(s[x + 2] - s[x + stride + 2]) + \ + SQ(s[x + 3] - s[x + stride + 3]); \ + } \ + s += stride; \ + } \ + \ + return score; \ +} +VSSE_INTRA(8) +VSSE_INTRA(16) + +#define VSSE(size) \ +static int vsse ## size ## _c(MpegEncContext *c, uint8_t *s1, uint8_t *s2, \ + ptrdiff_t stride, int h) \ +{ \ + int score = 0, x, y; \ + \ + for (y = 1; y < h; y++) { \ + for (x = 0; x < size; x++) \ + score += SQ(s1[x] - s2[x] - s1[x + stride] + s2[x + stride]); \ + s1 += stride; \ + s2 += stride; \ + } \ + \ + return score; \ +} +VSSE(8) +VSSE(16) + +#define WRAPPER8_16_SQ(name8, name16) \ +static int name16(MpegEncContext *s, uint8_t *dst, uint8_t *src, \ + ptrdiff_t stride, int h) \ +{ \ + int score = 0; \ + \ + score += name8(s, dst, src, stride, 8); \ + score += name8(s, dst + 8, src + 8, stride, 8); \ + if (h == 16) { \ + dst += 8 * stride; \ + src += 8 * stride; \ + score += name8(s, dst, src, stride, 8); \ + score += name8(s, dst + 8, src + 8, stride, 8); \ + } \ + return score; \ +} + +WRAPPER8_16_SQ(hadamard8_diff8x8_c, hadamard8_diff16_c) +WRAPPER8_16_SQ(hadamard8_intra8x8_c, hadamard8_intra16_c) +WRAPPER8_16_SQ(dct_sad8x8_c, dct_sad16_c) +#if CONFIG_GPL +WRAPPER8_16_SQ(dct264_sad8x8_c, dct264_sad16_c) +#endif +WRAPPER8_16_SQ(dct_max8x8_c, dct_max16_c) +WRAPPER8_16_SQ(quant_psnr8x8_c, quant_psnr16_c) +WRAPPER8_16_SQ(rd8x8_c, rd16_c) +WRAPPER8_16_SQ(bit8x8_c, bit16_c) + +int ff_check_alignment(void) +{ + static int did_fail = 0; + LOCAL_ALIGNED_16(int, aligned, [4]); + + if ((intptr_t)aligned & 15) { + if (!did_fail) { +#if HAVE_MMX || HAVE_ALTIVEC + av_log(NULL, AV_LOG_ERROR, + "Compiler did not align stack variables. Libavcodec has been miscompiled\n" + "and may be very slow or crash. This is not a bug in libavcodec,\n" + "but in the compiler. You may try recompiling using gcc >= 4.2.\n" + "Do not report crashes to FFmpeg developers.\n"); +#endif + did_fail=1; + } + return -1; + } + return 0; +} + +av_cold void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx) +{ + ff_check_alignment(); + + c->sum_abs_dctelem = sum_abs_dctelem_c; + + /* TODO [0] 16 [1] 8 */ + c->pix_abs[0][0] = pix_abs16_c; + c->pix_abs[0][1] = pix_abs16_x2_c; + c->pix_abs[0][2] = pix_abs16_y2_c; + c->pix_abs[0][3] = pix_abs16_xy2_c; + c->pix_abs[1][0] = pix_abs8_c; + c->pix_abs[1][1] = pix_abs8_x2_c; + c->pix_abs[1][2] = pix_abs8_y2_c; + c->pix_abs[1][3] = pix_abs8_xy2_c; + +#define SET_CMP_FUNC(name) \ + c->name[0] = name ## 16_c; \ + c->name[1] = name ## 8x8_c; + + SET_CMP_FUNC(hadamard8_diff) + c->hadamard8_diff[4] = hadamard8_intra16_c; + c->hadamard8_diff[5] = hadamard8_intra8x8_c; + SET_CMP_FUNC(dct_sad) + SET_CMP_FUNC(dct_max) +#if CONFIG_GPL + SET_CMP_FUNC(dct264_sad) +#endif + c->sad[0] = pix_abs16_c; + c->sad[1] = pix_abs8_c; + c->sse[0] = sse16_c; + c->sse[1] = sse8_c; + c->sse[2] = sse4_c; + SET_CMP_FUNC(quant_psnr) + SET_CMP_FUNC(rd) + SET_CMP_FUNC(bit) + c->vsad[0] = vsad16_c; + c->vsad[1] = vsad8_c; + c->vsad[4] = vsad_intra16_c; + c->vsad[5] = vsad_intra8_c; + c->vsse[0] = vsse16_c; + c->vsse[1] = vsse8_c; + c->vsse[4] = vsse_intra16_c; + c->vsse[5] = vsse_intra8_c; + c->nsse[0] = nsse16_c; + c->nsse[1] = nsse8_c; +#if CONFIG_SNOW_DECODER || CONFIG_SNOW_ENCODER + ff_dsputil_init_dwt(c); +#endif + + if (ARCH_ALPHA) + ff_me_cmp_init_alpha(c, avctx); + if (ARCH_ARM) + ff_me_cmp_init_arm(c, avctx); + if (ARCH_PPC) + ff_me_cmp_init_ppc(c, avctx); + if (ARCH_X86) + ff_me_cmp_init_x86(c, avctx); + if (ARCH_MIPS) + ff_me_cmp_init_mips(c, avctx); + + c->median_sad[0] = pix_median_abs16_c; + c->median_sad[1] = pix_median_abs8_c; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/me_cmp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/me_cmp.h new file mode 100644 index 0000000000..0a589e3c3d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/me_cmp.h @@ -0,0 +1,95 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_ME_CMP_H +#define AVCODEC_ME_CMP_H + +#include + +#include "avcodec.h" + +extern const uint32_t ff_square_tab[512]; + + +/* minimum alignment rules ;) + * If you notice errors in the align stuff, need more alignment for some ASM code + * for some CPU or need to use a function with less aligned data then send a mail + * to the ffmpeg-devel mailing list, ... + * + * !warning These alignments might not match reality, (missing attribute((align)) + * stuff somewhere possible). + * I (Michael) did not check them, these are just the alignments which I think + * could be reached easily ... + * + * !future video codecs might need functions with less strict alignment + */ + +struct MpegEncContext; +/* Motion estimation: + * h is limited to { width / 2, width, 2 * width }, + * but never larger than 16 and never smaller than 2. + * Although currently h < 4 is not used as functions with + * width < 8 are neither used nor implemented. */ +typedef int (*me_cmp_func)(struct MpegEncContext *c, + uint8_t *blk1 /* align width (8 or 16) */, + uint8_t *blk2 /* align 1 */, ptrdiff_t stride, + int h); + +typedef struct MECmpContext { + int (*sum_abs_dctelem)(int16_t *block /* align 16 */); + + me_cmp_func sad[6]; /* identical to pix_absAxA except additional void * */ + me_cmp_func sse[6]; + me_cmp_func hadamard8_diff[6]; + me_cmp_func dct_sad[6]; + me_cmp_func quant_psnr[6]; + me_cmp_func bit[6]; + me_cmp_func rd[6]; + me_cmp_func vsad[6]; + me_cmp_func vsse[6]; + me_cmp_func nsse[6]; + me_cmp_func w53[6]; + me_cmp_func w97[6]; + me_cmp_func dct_max[6]; + me_cmp_func dct264_sad[6]; + + me_cmp_func me_pre_cmp[6]; + me_cmp_func me_cmp[6]; + me_cmp_func me_sub_cmp[6]; + me_cmp_func mb_cmp[6]; + me_cmp_func ildct_cmp[6]; // only width 16 used + me_cmp_func frame_skip_cmp[6]; // only width 8 used + + me_cmp_func pix_abs[2][4]; + me_cmp_func median_sad[6]; +} MECmpContext; + +int ff_check_alignment(void); + +void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx); +void ff_me_cmp_init_alpha(MECmpContext *c, AVCodecContext *avctx); +void ff_me_cmp_init_arm(MECmpContext *c, AVCodecContext *avctx); +void ff_me_cmp_init_ppc(MECmpContext *c, AVCodecContext *avctx); +void ff_me_cmp_init_x86(MECmpContext *c, AVCodecContext *avctx); +void ff_me_cmp_init_mips(MECmpContext *c, AVCodecContext *avctx); + +void ff_set_cmp(MECmpContext *c, me_cmp_func *cmp, int type); + +void ff_dsputil_init_dwt(MECmpContext *c); + +#endif /* AVCODEC_ME_CMP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec.c new file mode 100644 index 0000000000..aa14624fd0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec.c @@ -0,0 +1,149 @@ +/* + * Android MediaCodec public API functions + * + * Copyright (c) 2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/error.h" + +#include "mediacodec.h" + +#if CONFIG_MEDIACODEC + +#include + +#include "libavcodec/avcodec.h" +#include "libavutil/mem.h" + +#include "ffjni.h" +#include "mediacodecdec_common.h" +#include "version.h" + +AVMediaCodecContext *av_mediacodec_alloc_context(void) +{ + return av_mallocz(sizeof(AVMediaCodecContext)); +} + +int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface) +{ + int ret = 0; + JNIEnv *env = NULL; + + env = ff_jni_get_env(avctx); + if (!env) { + return AVERROR_EXTERNAL; + } + + ctx->surface = (*env)->NewGlobalRef(env, surface); + if (ctx->surface) { + avctx->hwaccel_context = ctx; + } else { + av_log(avctx, AV_LOG_ERROR, "Could not create new global reference\n"); + ret = AVERROR_EXTERNAL; + } + + return ret; +} + +void av_mediacodec_default_free(AVCodecContext *avctx) +{ + JNIEnv *env = NULL; + + AVMediaCodecContext *ctx = avctx->hwaccel_context; + + if (!ctx) { + return; + } + + env = ff_jni_get_env(avctx); + if (!env) { + return; + } + + if (ctx->surface) { + (*env)->DeleteGlobalRef(env, ctx->surface); + ctx->surface = NULL; + } + + av_freep(&avctx->hwaccel_context); +} + +int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render) +{ + MediaCodecDecContext *ctx = buffer->ctx; + int released = atomic_fetch_add(&buffer->released, 1); + + if (!released && (ctx->delay_flush || buffer->serial == atomic_load(&ctx->serial))) { + atomic_fetch_sub(&ctx->hw_buffer_count, 1); + av_log(ctx->avctx, AV_LOG_DEBUG, + "Releasing output buffer %zd (%p) ts=%"PRId64" with render=%d [%d pending]\n", + buffer->index, buffer, buffer->pts, render, atomic_load(&ctx->hw_buffer_count)); + return ff_AMediaCodec_releaseOutputBuffer(ctx->codec, buffer->index, render); + } + + return 0; +} + +int av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time) +{ + MediaCodecDecContext *ctx = buffer->ctx; + int released = atomic_fetch_add(&buffer->released, 1); + + if (!released && (ctx->delay_flush || buffer->serial == atomic_load(&ctx->serial))) { + atomic_fetch_sub(&ctx->hw_buffer_count, 1); + av_log(ctx->avctx, AV_LOG_DEBUG, + "Rendering output buffer %zd (%p) ts=%"PRId64" with time=%"PRId64" [%d pending]\n", + buffer->index, buffer, buffer->pts, time, atomic_load(&ctx->hw_buffer_count)); + return ff_AMediaCodec_releaseOutputBufferAtTime(ctx->codec, buffer->index, time); + } + + return 0; +} + +#else + +#include + +AVMediaCodecContext *av_mediacodec_alloc_context(void) +{ + return NULL; +} + +int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface) +{ + return AVERROR(ENOSYS); +} + +void av_mediacodec_default_free(AVCodecContext *avctx) +{ +} + +int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render) +{ + return AVERROR(ENOSYS); +} + +int av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time) +{ + return AVERROR(ENOSYS); +} + +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec.h new file mode 100644 index 0000000000..4c8545df03 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec.h @@ -0,0 +1,101 @@ +/* + * Android MediaCodec public API + * + * Copyright (c) 2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MEDIACODEC_H +#define AVCODEC_MEDIACODEC_H + +#include "libavcodec/avcodec.h" + +/** + * This structure holds a reference to a android/view/Surface object that will + * be used as output by the decoder. + * + */ +typedef struct AVMediaCodecContext { + + /** + * android/view/Surface object reference. + */ + void *surface; + +} AVMediaCodecContext; + +/** + * Allocate and initialize a MediaCodec context. + * + * When decoding with MediaCodec is finished, the caller must free the + * MediaCodec context with av_mediacodec_default_free. + * + * @return a pointer to a newly allocated AVMediaCodecContext on success, NULL otherwise + */ +AVMediaCodecContext *av_mediacodec_alloc_context(void); + +/** + * Convenience function that sets up the MediaCodec context. + * + * @param avctx codec context + * @param ctx MediaCodec context to initialize + * @param surface reference to an android/view/Surface + * @return 0 on success, < 0 otherwise + */ +int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface); + +/** + * This function must be called to free the MediaCodec context initialized with + * av_mediacodec_default_init(). + * + * @param avctx codec context + */ +void av_mediacodec_default_free(AVCodecContext *avctx); + +/** + * Opaque structure representing a MediaCodec buffer to render. + */ +typedef struct MediaCodecBuffer AVMediaCodecBuffer; + +/** + * Release a MediaCodec buffer and render it to the surface that is associated + * with the decoder. This function should only be called once on a given + * buffer, once released the underlying buffer returns to the codec, thus + * subsequent calls to this function will have no effect. + * + * @param buffer the buffer to render + * @param render 1 to release and render the buffer to the surface or 0 to + * discard the buffer + * @return 0 on success, < 0 otherwise + */ +int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render); + +/** + * Release a MediaCodec buffer and render it at the given time to the surface + * that is associated with the decoder. The timestamp must be within one second + * of the current java/lang/System#nanoTime() (which is implemented using + * CLOCK_MONOTONIC on Android). See the Android MediaCodec documentation + * of android/media/MediaCodec#releaseOutputBuffer(int,long) for more details. + * + * @param buffer the buffer to render + * @param time timestamp in nanoseconds of when to render the buffer + * @return 0 on success, < 0 otherwise + */ +int av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time); + +#endif /* AVCODEC_MEDIACODEC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_surface.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_surface.h new file mode 100644 index 0000000000..0178b8ae71 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_surface.h @@ -0,0 +1,31 @@ +/* + * Android MediaCodec Surface functions + * + * Copyright (c) 2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MEDIACODEC_SURFACE_H +#define AVCODEC_MEDIACODEC_SURFACE_H + +#include "libavcodec/avcodec.h" + +void *ff_mediacodec_surface_ref(void *surface, void *log_ctx); +int ff_mediacodec_surface_unref(void *surface, void *log_ctx); + +#endif /* AVCODEC_MEDIACODEC_SURFACE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_sw_buffer.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_sw_buffer.h new file mode 100644 index 0000000000..574fb529d4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_sw_buffer.h @@ -0,0 +1,62 @@ +/* + * Android MediaCodec software buffer copy functions + * + * Copyright (c) 2015-2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MEDIACODEC_SW_BUFFER_H +#define AVCODEC_MEDIACODEC_SW_BUFFER_H + +#include + +#include "libavutil/frame.h" + +#include "avcodec.h" +#include "mediacodec_wrapper.h" +#include "mediacodecdec_common.h" + +void ff_mediacodec_sw_buffer_copy_yuv420_planar(AVCodecContext *avctx, + MediaCodecDecContext *s, + uint8_t *data, + size_t size, + FFAMediaCodecBufferInfo *info, + AVFrame *frame); + +void ff_mediacodec_sw_buffer_copy_yuv420_semi_planar(AVCodecContext *avctx, + MediaCodecDecContext *s, + uint8_t *data, + size_t size, + FFAMediaCodecBufferInfo *info, + AVFrame *frame); + +void ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar(AVCodecContext *avctx, + MediaCodecDecContext *s, + uint8_t *data, + size_t size, + FFAMediaCodecBufferInfo *info, + AVFrame *frame); + +void ff_mediacodec_sw_buffer_copy_yuv420_packed_semi_planar_64x32Tile2m8ka(AVCodecContext *avctx, + MediaCodecDecContext *s, + uint8_t *data, + size_t size, + FFAMediaCodecBufferInfo *info, + AVFrame *frame); + +#endif /* AVCODEC_MEDIACODEC_SW_BUFFER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_wrapper.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_wrapper.h new file mode 100644 index 0000000000..b106ff315a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodec_wrapper.h @@ -0,0 +1,131 @@ +/* + * Android MediaCodec Wrapper + * + * Copyright (c) 2015-2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MEDIACODEC_WRAPPER_H +#define AVCODEC_MEDIACODEC_WRAPPER_H + +#include +#include + +#include "avcodec.h" + +/** + * The following API around MediaCodec and MediaFormat is based on the + * NDK one provided by Google since Android 5.0. + * + * Differences from the NDK API: + * + * Buffers returned by ff_AMediaFormat_toString and ff_AMediaFormat_getString + * are newly allocated buffer and must be freed by the user after use. + * + * The MediaCrypto API is not implemented. + * + * ff_AMediaCodec_infoTryAgainLater, ff_AMediaCodec_infoOutputBuffersChanged, + * ff_AMediaCodec_infoOutputFormatChanged, ff_AMediaCodec_cleanOutputBuffers + * ff_AMediaCodec_getName and ff_AMediaCodec_getBufferFlagEndOfStream are not + * part of the original NDK API and are convenience functions to hide JNI + * implementation. + * + * The API around MediaCodecList is not part of the NDK (and is lacking as + * we still need to retrieve the codec name to work around faulty decoders + * and encoders). + * + * For documentation, please refers to NdkMediaCodec.h NdkMediaFormat.h and + * http://developer.android.com/reference/android/media/MediaCodec.html. + * + */ + +int ff_AMediaCodecProfile_getProfileFromAVCodecContext(AVCodecContext *avctx); + +char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int encoder, void *log_ctx); + +struct FFAMediaFormat; +typedef struct FFAMediaFormat FFAMediaFormat; + +FFAMediaFormat *ff_AMediaFormat_new(void); +int ff_AMediaFormat_delete(FFAMediaFormat* format); + +char* ff_AMediaFormat_toString(FFAMediaFormat* format); + +int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t *out); +int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t *out); +int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *out); +int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** data, size_t *size); +int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const char **out); + +void ff_AMediaFormat_setInt32(FFAMediaFormat* format, const char* name, int32_t value); +void ff_AMediaFormat_setInt64(FFAMediaFormat* format, const char* name, int64_t value); +void ff_AMediaFormat_setFloat(FFAMediaFormat* format, const char* name, float value); +void ff_AMediaFormat_setString(FFAMediaFormat* format, const char* name, const char* value); +void ff_AMediaFormat_setBuffer(FFAMediaFormat* format, const char* name, void* data, size_t size); + +struct FFAMediaCodec; +typedef struct FFAMediaCodec FFAMediaCodec; +typedef struct FFAMediaCodecCryptoInfo FFAMediaCodecCryptoInfo; + +struct FFAMediaCodecBufferInfo { + int32_t offset; + int32_t size; + int64_t presentationTimeUs; + uint32_t flags; +}; +typedef struct FFAMediaCodecBufferInfo FFAMediaCodecBufferInfo; + +char *ff_AMediaCodec_getName(FFAMediaCodec *codec); + +FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name); +FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime_type); +FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime_type); + +int ff_AMediaCodec_configure(FFAMediaCodec* codec, const FFAMediaFormat* format, void* surface, void *crypto, uint32_t flags); +int ff_AMediaCodec_start(FFAMediaCodec* codec); +int ff_AMediaCodec_stop(FFAMediaCodec* codec); +int ff_AMediaCodec_flush(FFAMediaCodec* codec); +int ff_AMediaCodec_delete(FFAMediaCodec* codec); + +uint8_t* ff_AMediaCodec_getInputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size); +uint8_t* ff_AMediaCodec_getOutputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size); + +ssize_t ff_AMediaCodec_dequeueInputBuffer(FFAMediaCodec* codec, int64_t timeoutUs); +int ff_AMediaCodec_queueInputBuffer(FFAMediaCodec* codec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags); + +ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBufferInfo *info, int64_t timeoutUs); +FFAMediaFormat* ff_AMediaCodec_getOutputFormat(FFAMediaCodec* codec); + +int ff_AMediaCodec_releaseOutputBuffer(FFAMediaCodec* codec, size_t idx, int render); +int ff_AMediaCodec_releaseOutputBufferAtTime(FFAMediaCodec *codec, size_t idx, int64_t timestampNs); + +int ff_AMediaCodec_infoTryAgainLater(FFAMediaCodec *codec, ssize_t idx); +int ff_AMediaCodec_infoOutputBuffersChanged(FFAMediaCodec *codec, ssize_t idx); +int ff_AMediaCodec_infoOutputFormatChanged(FFAMediaCodec *codec, ssize_t indx); + +int ff_AMediaCodec_getBufferFlagCodecConfig (FFAMediaCodec *codec); +int ff_AMediaCodec_getBufferFlagEndOfStream(FFAMediaCodec *codec); +int ff_AMediaCodec_getBufferFlagKeyFrame(FFAMediaCodec *codec); + +int ff_AMediaCodec_getConfigureFlagEncode(FFAMediaCodec *codec); + +int ff_AMediaCodec_cleanOutputBuffers(FFAMediaCodec *codec); + +int ff_Build_SDK_INT(AVCodecContext *avctx); + +#endif /* AVCODEC_MEDIACODEC_WRAPPER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodecdec_common.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodecdec_common.h new file mode 100644 index 0000000000..0b21129fee --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mediacodecdec_common.h @@ -0,0 +1,109 @@ +/* + * Android MediaCodec decoder + * + * Copyright (c) 2015-2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MEDIACODECDEC_COMMON_H +#define AVCODEC_MEDIACODECDEC_COMMON_H + +#include +#include +#include +#include + +#include "libavutil/frame.h" +#include "libavutil/pixfmt.h" + +#include "avcodec.h" +#include "mediacodec_wrapper.h" + +typedef struct MediaCodecDecContext { + + AVCodecContext *avctx; + atomic_int refcount; + atomic_int hw_buffer_count; + + char *codec_name; + + FFAMediaCodec *codec; + FFAMediaFormat *format; + + void *surface; + + int started; + int draining; + int flushing; + int eos; + + int width; + int height; + int stride; + int slice_height; + int color_format; + int crop_top; + int crop_bottom; + int crop_left; + int crop_right; + int display_width; + int display_height; + + uint64_t output_buffer_count; + ssize_t current_input_buffer; + + bool delay_flush; + atomic_int serial; + +} MediaCodecDecContext; + +int ff_mediacodec_dec_init(AVCodecContext *avctx, + MediaCodecDecContext *s, + const char *mime, + FFAMediaFormat *format); + +int ff_mediacodec_dec_send(AVCodecContext *avctx, + MediaCodecDecContext *s, + AVPacket *pkt, + bool wait); + +int ff_mediacodec_dec_receive(AVCodecContext *avctx, + MediaCodecDecContext *s, + AVFrame *frame, + bool wait); + +int ff_mediacodec_dec_flush(AVCodecContext *avctx, + MediaCodecDecContext *s); + +int ff_mediacodec_dec_close(AVCodecContext *avctx, + MediaCodecDecContext *s); + +int ff_mediacodec_dec_is_flushing(AVCodecContext *avctx, + MediaCodecDecContext *s); + +typedef struct MediaCodecBuffer { + + MediaCodecDecContext *ctx; + ssize_t index; + int64_t pts; + atomic_int released; + int serial; + +} MediaCodecBuffer; + +#endif /* AVCODEC_MEDIACODECDEC_COMMON_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc.h new file mode 100644 index 0000000000..d7ddc35ef5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc.h @@ -0,0 +1,111 @@ +/* + * MJPEG encoder + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2003 Alex Beregszaszi + * Copyright (c) 2003-2004 Michael Niedermayer + * + * Support for external huffman table, various fixes (AVID workaround), + * aspecting, new decode_frame mechanism and apple mjpeg-b support + * by Alex Beregszaszi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * MJPEG encoder. + */ + +#ifndef AVCODEC_MJPEGENC_H +#define AVCODEC_MJPEGENC_H + +#include + +#include "mjpeg.h" +#include "mpegvideo.h" +#include "put_bits.h" + +/** + * Buffer of JPEG frame data. + * + * Optimal Huffman table generation requires the frame data to be loaded into + * a buffer so that the tables can be computed. + * There are at most mb_width*mb_height*12*64 of these per frame. + */ +typedef struct MJpegHuffmanCode { + // 0=DC lum, 1=DC chrom, 2=AC lum, 3=AC chrom + uint8_t table_id; ///< The Huffman table id associated with the data. + uint8_t code; ///< The exponent. + uint16_t mant; ///< The mantissa. +} MJpegHuffmanCode; + +/** + * Holds JPEG frame data and Huffman table data. + */ +typedef struct MJpegContext { + //FIXME use array [3] instead of lumi / chroma, for easier addressing + uint8_t huff_size_dc_luminance[12]; ///< DC luminance Huffman table size. + uint16_t huff_code_dc_luminance[12]; ///< DC luminance Huffman table codes. + uint8_t huff_size_dc_chrominance[12]; ///< DC chrominance Huffman table size. + uint16_t huff_code_dc_chrominance[12]; ///< DC chrominance Huffman table codes. + + uint8_t huff_size_ac_luminance[256]; ///< AC luminance Huffman table size. + uint16_t huff_code_ac_luminance[256]; ///< AC luminance Huffman table codes. + uint8_t huff_size_ac_chrominance[256]; ///< AC chrominance Huffman table size. + uint16_t huff_code_ac_chrominance[256]; ///< AC chrominance Huffman table codes. + + /** Storage for AC luminance VLC (in MpegEncContext) */ + uint8_t uni_ac_vlc_len[64 * 64 * 2]; + /** Storage for AC chrominance VLC (in MpegEncContext) */ + uint8_t uni_chroma_ac_vlc_len[64 * 64 * 2]; + + // Default DC tables have exactly 12 values + uint8_t bits_dc_luminance[17]; ///< DC luminance Huffman bits. + uint8_t val_dc_luminance[12]; ///< DC luminance Huffman values. + uint8_t bits_dc_chrominance[17]; ///< DC chrominance Huffman bits. + uint8_t val_dc_chrominance[12]; ///< DC chrominance Huffman values. + + // 8-bit JPEG has max 256 values + uint8_t bits_ac_luminance[17]; ///< AC luminance Huffman bits. + uint8_t val_ac_luminance[256]; ///< AC luminance Huffman values. + uint8_t bits_ac_chrominance[17]; ///< AC chrominance Huffman bits. + uint8_t val_ac_chrominance[256]; ///< AC chrominance Huffman values. + + size_t huff_ncode; ///< Number of current entries in the buffer. + MJpegHuffmanCode *huff_buffer; ///< Buffer for Huffman code values. +} MJpegContext; + +/** + * Enum for the Huffman encoding strategy. + */ +enum HuffmanTableOption { + HUFFMAN_TABLE_DEFAULT = 0, ///< Use the default Huffman tables. + HUFFMAN_TABLE_OPTIMAL = 1, ///< Compute and use optimal Huffman tables. + NB_HUFFMAN_TABLE_OPTION = 2 +}; + +static inline void put_marker(PutBitContext *p, enum JpegMarker code) +{ + put_bits(p, 8, 0xff); + put_bits(p, 8, code); +} + +int ff_mjpeg_encode_init(MpegEncContext *s); +void ff_mjpeg_encode_close(MpegEncContext *s); +void ff_mjpeg_encode_mb(MpegEncContext *s, int16_t block[12][64]); + +#endif /* AVCODEC_MJPEGENC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_common.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_common.h new file mode 100644 index 0000000000..e8698d18c6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_common.h @@ -0,0 +1,46 @@ +/* + * lossless JPEG shared bits + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MJPEGENC_COMMON_H +#define AVCODEC_MJPEGENC_COMMON_H + +#include + +#include "avcodec.h" +#include "idctdsp.h" +#include "mpegvideo.h" +#include "put_bits.h" + +void ff_mjpeg_encode_picture_header(AVCodecContext *avctx, PutBitContext *pb, + ScanTable *intra_scantable, int pred, + uint16_t luma_intra_matrix[64], + uint16_t chroma_intra_matrix[64]); +void ff_mjpeg_encode_picture_frame(MpegEncContext *s); +void ff_mjpeg_encode_picture_trailer(PutBitContext *pb, int header_bits); +void ff_mjpeg_escape_FF(PutBitContext *pb, int start); +int ff_mjpeg_encode_stuffing(MpegEncContext *s); +void ff_mjpeg_init_hvsample(AVCodecContext *avctx, int hsample[4], int vsample[4]); + +void ff_mjpeg_encode_dc(PutBitContext *pb, int val, + uint8_t *huff_size, uint16_t *huff_code); + +av_cold void ff_init_uni_ac_vlc(const uint8_t huff_size_ac[256], uint8_t *uni_ac_vlc_len); + +#endif /* AVCODEC_MJPEGENC_COMMON_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_huffman.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_huffman.c new file mode 100644 index 0000000000..0e63f8066b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_huffman.c @@ -0,0 +1,192 @@ +/* + * MJPEG encoder + * Copyright (c) 2016 William Ma, Ted Ying, Jerry Jiang + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/error.h" +#include "libavutil/qsort.h" +#include "mjpegenc_huffman.h" + +/** + * Comparison function for two PTables by prob + * + * @param a First PTable to compare + * @param b Second PTable to compare + * @return < 0 for less than, 0 for equals, > 0 for greater than + */ +static int compare_by_prob(const void *a, const void *b) +{ + PTable a_val = *(PTable *) a; + PTable b_val = *(PTable *) b; + return a_val.prob - b_val.prob; +} + +/** + * Comparison function for two HuffTables by length + * + * @param a First HuffTable to compare + * @param b Second HuffTable to compare + * @return < 0 for less than, 0 for equals, > 0 for greater than + */ +static int compare_by_length(const void *a, const void *b) +{ + HuffTable a_val = *(HuffTable *) a; + HuffTable b_val = *(HuffTable *) b; + return a_val.length - b_val.length; +} + +/** + * Computes the length of the Huffman encoding for each distinct input value. + * Uses package merge algorithm as follows: + * 1. start with an empty list, lets call it list(0), set i = 0 + * 2. add 1 entry to list(i) for each symbol we have and give each a score equal to the probability of the respective symbol + * 3. merge the 2 symbols of least score and put them in list(i+1), and remove them from list(i). The new score will be the sum of the 2 scores + * 4. if there is more than 1 symbol left in the current list(i), then goto 3 + * 5. i++ + * 6. if i < 16 goto 2 + * 7. select the n-1 elements in the last list with the lowest score (n = the number of symbols) + * 8. the length of the huffman code for symbol s will be equal to the number of times the symbol occurs in the select elements + * Go to guru.multimedia.cx/small-tasks-for-ffmpeg/ for more details + * + * All probabilities should be positive integers. The output is sorted by code, + * not by length. + * + * @param prob_table input array of a PTable for each distinct input value + * @param distincts output array of a HuffTable that will be populated by this function + * @param size size of the prob_table array + * @param max_length max length of an encoding + */ +void ff_mjpegenc_huffman_compute_bits(PTable *prob_table, HuffTable *distincts, int size, int max_length) +{ + PackageMergerList list_a, list_b, *to = &list_a, *from = &list_b, *temp; + + int times, i, j, k; + + int nbits[257] = {0}; + + int min; + + av_assert0(max_length > 0); + + to->nitems = 0; + from->nitems = 0; + to->item_idx[0] = 0; + from->item_idx[0] = 0; + AV_QSORT(prob_table, size, PTable, compare_by_prob); + + for (times = 0; times <= max_length; times++) { + to->nitems = 0; + to->item_idx[0] = 0; + + j = 0; + k = 0; + + if (times < max_length) { + i = 0; + } + while (i < size || j + 1 < from->nitems) { + to->nitems++; + to->item_idx[to->nitems] = to->item_idx[to->nitems - 1]; + if (i < size && + (j + 1 >= from->nitems || + prob_table[i].prob < + from->probability[j] + from->probability[j + 1])) { + to->items[to->item_idx[to->nitems]++] = prob_table[i].value; + to->probability[to->nitems - 1] = prob_table[i].prob; + i++; + } else { + for (k = from->item_idx[j]; k < from->item_idx[j + 2]; k++) { + to->items[to->item_idx[to->nitems]++] = from->items[k]; + } + to->probability[to->nitems - 1] = + from->probability[j] + from->probability[j + 1]; + j += 2; + } + } + temp = to; + to = from; + from = temp; + } + + min = (size - 1 < from->nitems) ? size - 1 : from->nitems; + for (i = 0; i < from->item_idx[min]; i++) { + nbits[from->items[i]]++; + } + // we don't want to return the 256 bit count (it was just in here to prevent + // all 1s encoding) + j = 0; + for (i = 0; i < 256; i++) { + if (nbits[i] > 0) { + distincts[j].code = i; + distincts[j].length = nbits[i]; + j++; + } + } +} + +void ff_mjpeg_encode_huffman_init(MJpegEncHuffmanContext *s) +{ + memset(s->val_count, 0, sizeof(s->val_count)); +} + +/** + * Produces a Huffman encoding with a given input + * + * @param s input to encode + * @param bits output array where the ith character represents how many input values have i length encoding + * @param val output array of input values sorted by their encoded length + * @param max_nval maximum number of distinct input values + */ +void ff_mjpeg_encode_huffman_close(MJpegEncHuffmanContext *s, uint8_t bits[17], + uint8_t val[], int max_nval) +{ + int i, j; + int nval = 0; + PTable val_counts[257]; + HuffTable distincts[256]; + + for (i = 0; i < 256; i++) { + if (s->val_count[i]) nval++; + } + av_assert0 (nval <= max_nval); + + j = 0; + for (i = 0; i < 256; i++) { + if (s->val_count[i]) { + val_counts[j].value = i; + val_counts[j].prob = s->val_count[i]; + j++; + } + } + val_counts[j].value = 256; + val_counts[j].prob = 0; + ff_mjpegenc_huffman_compute_bits(val_counts, distincts, nval + 1, 16); + AV_QSORT(distincts, nval, HuffTable, compare_by_length); + + memset(bits, 0, sizeof(bits[0]) * 17); + for (i = 0; i < nval; i++) { + val[i] = distincts[i].code; + bits[distincts[i].length]++; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_huffman.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_huffman.h new file mode 100644 index 0000000000..5fe65504e4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mjpegenc_huffman.h @@ -0,0 +1,76 @@ +/* + * MJPEG encoder + * Copyright (c) 2016 William Ma, Ted Ying, Jerry Jiang + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Huffman table generation for MJPEG encoder. + */ + +#ifndef AVCODEC_MJPEGENC_HUFFMAN_H +#define AVCODEC_MJPEGENC_HUFFMAN_H + +#include + +typedef struct MJpegEncHuffmanContext { + int val_count[256]; +} MJpegEncHuffmanContext; + +// Uses the package merge algorithm to compute the Huffman table. +void ff_mjpeg_encode_huffman_init(MJpegEncHuffmanContext *s); +static inline void ff_mjpeg_encode_huffman_increment(MJpegEncHuffmanContext *s, + uint8_t val) +{ + s->val_count[val]++; +} +void ff_mjpeg_encode_huffman_close(MJpegEncHuffmanContext *s, + uint8_t bits[17], uint8_t val[], + int max_nval); + + +/** + * Used to assign a occurrence count or "probability" to an input value + */ +typedef struct PTable { + int value; ///< input value + int prob; ///< number of occurences of this value in input +} PTable; + +/** + * Used to store intermediate lists in the package merge algorithm + */ +typedef struct PackageMergerList { + int nitems; ///< number of items in the list and probability ex. 4 + int item_idx[515]; ///< index range for each item in items 0, 2, 5, 9, 13 + int probability[514]; ///< probability of each item 3, 8, 18, 46 + int items[257 * 16]; ///< chain of all individual values that make up items A, B, A, B, C, A, B, C, D, C, D, D, E +} PackageMergerList; + +/** + * Used to store optimal huffman encoding results + */ +typedef struct HuffTable { + int code; ///< code is the input value + int length; ///< length of the encoding +} HuffTable; + +void ff_mjpegenc_huffman_compute_bits(PTable *prob_table, HuffTable *distincts, + int size, int max_length); +#endif /* AVCODEC_MJPEGENC_HUFFMAN_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/motion_est.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/motion_est.c new file mode 100644 index 0000000000..759eea479d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/motion_est.c @@ -0,0 +1,1741 @@ +/* + * Motion estimation + * Copyright (c) 2000,2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * new motion estimation (X1/EPZS) by Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Motion estimation. + */ + +#include +#include +#include + +#include "avcodec.h" +#include "internal.h" +#include "mathops.h" +#include "motion_est.h" +#include "mpegutils.h" +#include "mpegvideo.h" + +#define P_LEFT P[1] +#define P_TOP P[2] +#define P_TOPRIGHT P[3] +#define P_MEDIAN P[4] +#define P_MV1 P[9] + +#define ME_MAP_SHIFT 3 +#define ME_MAP_MV_BITS 11 + +static int sad_hpel_motion_search(MpegEncContext * s, + int *mx_ptr, int *my_ptr, int dmin, + int src_index, int ref_index, + int size, int h); + +static inline unsigned update_map_generation(MotionEstContext *c) +{ + c->map_generation+= 1<<(ME_MAP_MV_BITS*2); + if(c->map_generation==0){ + c->map_generation= 1<<(ME_MAP_MV_BITS*2); + memset(c->map, 0, sizeof(uint32_t)*ME_MAP_SIZE); + } + return c->map_generation; +} + +/* shape adaptive search stuff */ +typedef struct Minima{ + int height; + int x, y; + int checked; +}Minima; + +static int minima_cmp(const void *a, const void *b){ + const Minima *da = (const Minima *) a; + const Minima *db = (const Minima *) b; + + return da->height - db->height; +} + +#define FLAG_QPEL 1 //must be 1 +#define FLAG_CHROMA 2 +#define FLAG_DIRECT 4 + +static inline void init_ref(MotionEstContext *c, uint8_t *src[3], uint8_t *ref[3], uint8_t *ref2[3], int x, int y, int ref_index){ + const int offset[3]= { + y*c-> stride + x, + ((y*c->uvstride + x)>>1), + ((y*c->uvstride + x)>>1), + }; + int i; + for(i=0; i<3; i++){ + c->src[0][i]= src [i] + offset[i]; + c->ref[0][i]= ref [i] + offset[i]; + } + if(ref_index){ + for(i=0; i<3; i++){ + c->ref[ref_index][i]= ref2[i] + offset[i]; + } + } +} + +static int get_flags(MotionEstContext *c, int direct, int chroma){ + return ((c->avctx->flags&AV_CODEC_FLAG_QPEL) ? FLAG_QPEL : 0) + + (direct ? FLAG_DIRECT : 0) + + (chroma ? FLAG_CHROMA : 0); +} + +static av_always_inline int cmp_direct_inline(MpegEncContext *s, const int x, const int y, const int subx, const int suby, + const int size, const int h, int ref_index, int src_index, + me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, int qpel){ + MotionEstContext * const c= &s->me; + const int stride= c->stride; + const int hx= subx + (x<<(1+qpel)); + const int hy= suby + (y<<(1+qpel)); + uint8_t * const * const ref= c->ref[ref_index]; + uint8_t * const * const src= c->src[src_index]; + int d; + //FIXME check chroma 4mv, (no crashes ...) + av_assert2(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)); + if(x >= c->xmin && hx <= c->xmax<<(qpel+1) && y >= c->ymin && hy <= c->ymax<<(qpel+1)){ + const int time_pp= s->pp_time; + const int time_pb= s->pb_time; + const int mask= 2*qpel+1; + if(s->mv_type==MV_TYPE_8X8){ + int i; + for(i=0; i<4; i++){ + int fx = c->direct_basis_mv[i][0] + hx; + int fy = c->direct_basis_mv[i][1] + hy; + int bx = hx ? fx - c->co_located_mv[i][0] : c->co_located_mv[i][0]*(time_pb - time_pp)/time_pp + ((i &1)<<(qpel+4)); + int by = hy ? fy - c->co_located_mv[i][1] : c->co_located_mv[i][1]*(time_pb - time_pp)/time_pp + ((i>>1)<<(qpel+4)); + int fxy= (fx&mask) + ((fy&mask)<<(qpel+1)); + int bxy= (bx&mask) + ((by&mask)<<(qpel+1)); + + uint8_t *dst= c->temp + 8*(i&1) + 8*stride*(i>>1); + if(qpel){ + c->qpel_put[1][fxy](dst, ref[0] + (fx>>2) + (fy>>2)*stride, stride); + c->qpel_avg[1][bxy](dst, ref[8] + (bx>>2) + (by>>2)*stride, stride); + }else{ + c->hpel_put[1][fxy](dst, ref[0] + (fx>>1) + (fy>>1)*stride, stride, 8); + c->hpel_avg[1][bxy](dst, ref[8] + (bx>>1) + (by>>1)*stride, stride, 8); + } + } + }else{ + int fx = c->direct_basis_mv[0][0] + hx; + int fy = c->direct_basis_mv[0][1] + hy; + int bx = hx ? fx - c->co_located_mv[0][0] : (c->co_located_mv[0][0]*(time_pb - time_pp)/time_pp); + int by = hy ? fy - c->co_located_mv[0][1] : (c->co_located_mv[0][1]*(time_pb - time_pp)/time_pp); + int fxy= (fx&mask) + ((fy&mask)<<(qpel+1)); + int bxy= (bx&mask) + ((by&mask)<<(qpel+1)); + + if(qpel){ + c->qpel_put[1][fxy](c->temp , ref[0] + (fx>>2) + (fy>>2)*stride , stride); + c->qpel_put[1][fxy](c->temp + 8 , ref[0] + (fx>>2) + (fy>>2)*stride + 8 , stride); + c->qpel_put[1][fxy](c->temp + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8*stride, stride); + c->qpel_put[1][fxy](c->temp + 8 + 8*stride, ref[0] + (fx>>2) + (fy>>2)*stride + 8 + 8*stride, stride); + c->qpel_avg[1][bxy](c->temp , ref[8] + (bx>>2) + (by>>2)*stride , stride); + c->qpel_avg[1][bxy](c->temp + 8 , ref[8] + (bx>>2) + (by>>2)*stride + 8 , stride); + c->qpel_avg[1][bxy](c->temp + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8*stride, stride); + c->qpel_avg[1][bxy](c->temp + 8 + 8*stride, ref[8] + (bx>>2) + (by>>2)*stride + 8 + 8*stride, stride); + }else{ + av_assert2((fx>>1) + 16*s->mb_x >= -16); + av_assert2((fy>>1) + 16*s->mb_y >= -16); + av_assert2((fx>>1) + 16*s->mb_x <= s->width); + av_assert2((fy>>1) + 16*s->mb_y <= s->height); + av_assert2((bx>>1) + 16*s->mb_x >= -16); + av_assert2((by>>1) + 16*s->mb_y >= -16); + av_assert2((bx>>1) + 16*s->mb_x <= s->width); + av_assert2((by>>1) + 16*s->mb_y <= s->height); + + c->hpel_put[0][fxy](c->temp, ref[0] + (fx>>1) + (fy>>1)*stride, stride, 16); + c->hpel_avg[0][bxy](c->temp, ref[8] + (bx>>1) + (by>>1)*stride, stride, 16); + } + } + d = cmp_func(s, c->temp, src[0], stride, 16); + }else + d= 256*256*256*32; + return d; +} + +static av_always_inline int cmp_inline(MpegEncContext *s, const int x, const int y, const int subx, const int suby, + const int size, const int h, int ref_index, int src_index, + me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, int qpel, int chroma){ + MotionEstContext * const c= &s->me; + const int stride= c->stride; + const int uvstride= c->uvstride; + const int dxy= subx + (suby<<(1+qpel)); //FIXME log2_subpel? + const int hx= subx + x*(1<<(1+qpel)); + const int hy= suby + y*(1<<(1+qpel)); + uint8_t * const * const ref= c->ref[ref_index]; + uint8_t * const * const src= c->src[src_index]; + int d; + //FIXME check chroma 4mv, (no crashes ...) + int uvdxy; /* no, it might not be used uninitialized */ + if(dxy){ + if(qpel){ + if (h << size == 16) { + c->qpel_put[size][dxy](c->temp, ref[0] + x + y*stride, stride); //FIXME prototype (add h) + } else if (size == 0 && h == 8) { + c->qpel_put[1][dxy](c->temp , ref[0] + x + y*stride , stride); + c->qpel_put[1][dxy](c->temp + 8, ref[0] + x + y*stride + 8, stride); + } else + av_assert2(0); + if(chroma){ + int cx= hx/2; + int cy= hy/2; + cx= (cx>>1)|(cx&1); + cy= (cy>>1)|(cy&1); + uvdxy= (cx&1) + 2*(cy&1); + // FIXME x/y wrong, but MPEG-4 qpel is sick anyway, we should drop as much of it as possible in favor for H.264 + } + }else{ + c->hpel_put[size][dxy](c->temp, ref[0] + x + y*stride, stride, h); + if(chroma) + uvdxy= dxy | (x&1) | (2*(y&1)); + } + d = cmp_func(s, c->temp, src[0], stride, h); + }else{ + d = cmp_func(s, src[0], ref[0] + x + y*stride, stride, h); + if(chroma) + uvdxy= (x&1) + 2*(y&1); + } + if(chroma){ + uint8_t * const uvtemp= c->temp + 16*stride; + c->hpel_put[size+1][uvdxy](uvtemp , ref[1] + (x>>1) + (y>>1)*uvstride, uvstride, h>>1); + c->hpel_put[size+1][uvdxy](uvtemp+8, ref[2] + (x>>1) + (y>>1)*uvstride, uvstride, h>>1); + d += chroma_cmp_func(s, uvtemp , src[1], uvstride, h>>1); + d += chroma_cmp_func(s, uvtemp+8, src[2], uvstride, h>>1); + } + return d; +} + +static int cmp_simple(MpegEncContext *s, const int x, const int y, + int ref_index, int src_index, + me_cmp_func cmp_func, me_cmp_func chroma_cmp_func){ + return cmp_inline(s,x,y,0,0,0,16,ref_index,src_index, cmp_func, chroma_cmp_func, 0, 0); +} + +static int cmp_fpel_internal(MpegEncContext *s, const int x, const int y, + const int size, const int h, int ref_index, int src_index, + me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ + if(flags&FLAG_DIRECT){ + return cmp_direct_inline(s,x,y,0,0,size,h,ref_index,src_index, cmp_func, chroma_cmp_func, flags&FLAG_QPEL); + }else{ + return cmp_inline(s,x,y,0,0,size,h,ref_index,src_index, cmp_func, chroma_cmp_func, 0, flags&FLAG_CHROMA); + } +} + +static int cmp_internal(MpegEncContext *s, const int x, const int y, const int subx, const int suby, + const int size, const int h, int ref_index, int src_index, + me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ + if(flags&FLAG_DIRECT){ + return cmp_direct_inline(s,x,y,subx,suby,size,h,ref_index,src_index, cmp_func, chroma_cmp_func, flags&FLAG_QPEL); + }else{ + return cmp_inline(s,x,y,subx,suby,size,h,ref_index,src_index, cmp_func, chroma_cmp_func, flags&FLAG_QPEL, flags&FLAG_CHROMA); + } +} + +/** @brief compares a block (either a full macroblock or a partition thereof) + against a proposed motion-compensated prediction of that block + */ +static av_always_inline int cmp(MpegEncContext *s, const int x, const int y, const int subx, const int suby, + const int size, const int h, int ref_index, int src_index, + me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ + if(av_builtin_constant_p(flags) && av_builtin_constant_p(h) && av_builtin_constant_p(size) + && av_builtin_constant_p(subx) && av_builtin_constant_p(suby) + && flags==0 && h==16 && size==0 && subx==0 && suby==0){ + return cmp_simple(s,x,y,ref_index,src_index, cmp_func, chroma_cmp_func); + }else if(av_builtin_constant_p(subx) && av_builtin_constant_p(suby) + && subx==0 && suby==0){ + return cmp_fpel_internal(s,x,y,size,h,ref_index,src_index, cmp_func, chroma_cmp_func,flags); + }else{ + return cmp_internal(s,x,y,subx,suby,size,h,ref_index,src_index, cmp_func, chroma_cmp_func, flags); + } +} + +static int cmp_hpel(MpegEncContext *s, const int x, const int y, const int subx, const int suby, + const int size, const int h, int ref_index, int src_index, + me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ + if(flags&FLAG_DIRECT){ + return cmp_direct_inline(s,x,y,subx,suby,size,h,ref_index,src_index, cmp_func, chroma_cmp_func, 0); + }else{ + return cmp_inline(s,x,y,subx,suby,size,h,ref_index,src_index, cmp_func, chroma_cmp_func, 0, flags&FLAG_CHROMA); + } +} + +static int cmp_qpel(MpegEncContext *s, const int x, const int y, const int subx, const int suby, + const int size, const int h, int ref_index, int src_index, + me_cmp_func cmp_func, me_cmp_func chroma_cmp_func, const int flags){ + if(flags&FLAG_DIRECT){ + return cmp_direct_inline(s,x,y,subx,suby,size,h,ref_index,src_index, cmp_func, chroma_cmp_func, 1); + }else{ + return cmp_inline(s,x,y,subx,suby,size,h,ref_index,src_index, cmp_func, chroma_cmp_func, 1, flags&FLAG_CHROMA); + } +} + +#include "motion_est_template.c" + +static int zero_cmp(MpegEncContext *s, uint8_t *a, uint8_t *b, + ptrdiff_t stride, int h) +{ + return 0; +} + +static void zero_hpel(uint8_t *a, const uint8_t *b, ptrdiff_t stride, int h){ +} + +int ff_init_me(MpegEncContext *s){ + MotionEstContext * const c= &s->me; + int cache_size= FFMIN(ME_MAP_SIZE>>ME_MAP_SHIFT, 1<avctx->dia_size)&255, FFABS(s->avctx->pre_dia_size)&255); + + if(FFMIN(s->avctx->dia_size, s->avctx->pre_dia_size) < -FFMIN(ME_MAP_SIZE, MAX_SAB_SIZE)){ + av_log(s->avctx, AV_LOG_ERROR, "ME_MAP size is too small for SAB diamond\n"); + return -1; + } + + c->avctx= s->avctx; + + if(s->codec_id == AV_CODEC_ID_H261) + c->avctx->me_sub_cmp = c->avctx->me_cmp; + + if(cache_size < 2*dia_size && !c->stride){ + av_log(s->avctx, AV_LOG_INFO, "ME_MAP size may be a little small for the selected diamond size\n"); + } + + ff_set_cmp(&s->mecc, s->mecc.me_pre_cmp, c->avctx->me_pre_cmp); + ff_set_cmp(&s->mecc, s->mecc.me_cmp, c->avctx->me_cmp); + ff_set_cmp(&s->mecc, s->mecc.me_sub_cmp, c->avctx->me_sub_cmp); + ff_set_cmp(&s->mecc, s->mecc.mb_cmp, c->avctx->mb_cmp); + + c->flags = get_flags(c, 0, c->avctx->me_cmp &FF_CMP_CHROMA); + c->sub_flags= get_flags(c, 0, c->avctx->me_sub_cmp&FF_CMP_CHROMA); + c->mb_flags = get_flags(c, 0, c->avctx->mb_cmp &FF_CMP_CHROMA); + +/*FIXME s->no_rounding b_type*/ + if (s->avctx->flags & AV_CODEC_FLAG_QPEL) { + c->sub_motion_search= qpel_motion_search; + c->qpel_avg = s->qdsp.avg_qpel_pixels_tab; + if (s->no_rounding) + c->qpel_put = s->qdsp.put_no_rnd_qpel_pixels_tab; + else + c->qpel_put = s->qdsp.put_qpel_pixels_tab; + }else{ + if(c->avctx->me_sub_cmp&FF_CMP_CHROMA) + c->sub_motion_search= hpel_motion_search; + else if( c->avctx->me_sub_cmp == FF_CMP_SAD + && c->avctx-> me_cmp == FF_CMP_SAD + && c->avctx-> mb_cmp == FF_CMP_SAD) + c->sub_motion_search= sad_hpel_motion_search; // 2050 vs. 2450 cycles + else + c->sub_motion_search= hpel_motion_search; + } + c->hpel_avg = s->hdsp.avg_pixels_tab; + if (s->no_rounding) + c->hpel_put = s->hdsp.put_no_rnd_pixels_tab; + else + c->hpel_put = s->hdsp.put_pixels_tab; + + if(s->linesize){ + c->stride = s->linesize; + c->uvstride= s->uvlinesize; + }else{ + c->stride = 16*s->mb_width + 32; + c->uvstride= 8*s->mb_width + 16; + } + + /* 8x8 fullpel search would need a 4x4 chroma compare, which we do + * not have yet, and even if we had, the motion estimation code + * does not expect it. */ + if (s->codec_id != AV_CODEC_ID_SNOW) { + if ((c->avctx->me_cmp & FF_CMP_CHROMA) /* && !s->mecc.me_cmp[2] */) + s->mecc.me_cmp[2] = zero_cmp; + if ((c->avctx->me_sub_cmp & FF_CMP_CHROMA) && !s->mecc.me_sub_cmp[2]) + s->mecc.me_sub_cmp[2] = zero_cmp; + c->hpel_put[2][0]= c->hpel_put[2][1]= + c->hpel_put[2][2]= c->hpel_put[2][3]= zero_hpel; + } + + if(s->codec_id == AV_CODEC_ID_H261){ + c->sub_motion_search= no_sub_motion_search; + } + + return 0; +} + +#define CHECK_SAD_HALF_MV(suffix, x, y) \ +{\ + d = s->mecc.pix_abs[size][(x ? 1 : 0) + (y ? 2 : 0)](NULL, pix, ptr + ((x) >> 1), stride, h); \ + d += (mv_penalty[pen_x + x] + mv_penalty[pen_y + y])*penalty_factor;\ + COPY3_IF_LT(dminh, d, dx, x, dy, y)\ +} + +static int sad_hpel_motion_search(MpegEncContext * s, + int *mx_ptr, int *my_ptr, int dmin, + int src_index, int ref_index, + int size, int h) +{ + MotionEstContext * const c= &s->me; + const int penalty_factor= c->sub_penalty_factor; + int mx, my, dminh; + uint8_t *pix, *ptr; + int stride= c->stride; + LOAD_COMMON + + av_assert2(c->sub_flags == 0); + + if(c->skip){ + *mx_ptr = 0; + *my_ptr = 0; + return dmin; + } + + pix = c->src[src_index][0]; + + mx = *mx_ptr; + my = *my_ptr; + ptr = c->ref[ref_index][0] + (my * stride) + mx; + + dminh = dmin; + + if (mx > xmin && mx < xmax && + my > ymin && my < ymax) { + int dx=0, dy=0; + int d, pen_x, pen_y; + const int index= my*(1<mb_x + s->mb_y*s->mb_stride; + + s->p_mv_table[xy][0] = mx; + s->p_mv_table[xy][1] = my; + + /* has already been set to the 4 MV if 4MV is done */ + if(mv4){ + int mot_xy= s->block_index[0]; + + s->current_picture.motion_val[0][mot_xy ][0] = mx; + s->current_picture.motion_val[0][mot_xy ][1] = my; + s->current_picture.motion_val[0][mot_xy + 1][0] = mx; + s->current_picture.motion_val[0][mot_xy + 1][1] = my; + + mot_xy += s->b8_stride; + s->current_picture.motion_val[0][mot_xy ][0] = mx; + s->current_picture.motion_val[0][mot_xy ][1] = my; + s->current_picture.motion_val[0][mot_xy + 1][0] = mx; + s->current_picture.motion_val[0][mot_xy + 1][1] = my; + } +} + +/** + * get fullpel ME search limits. + */ +static inline void get_limits(MpegEncContext *s, int x, int y) +{ + MotionEstContext * const c= &s->me; + int range= c->avctx->me_range >> (1 + !!(c->flags&FLAG_QPEL)); + int max_range = MAX_MV >> (1 + !!(c->flags&FLAG_QPEL)); +/* + if(c->avctx->me_range) c->range= c->avctx->me_range >> 1; + else c->range= 16; +*/ + if (s->unrestricted_mv) { + c->xmin = - x - 16; + c->ymin = - y - 16; + c->xmax = - x + s->width; + c->ymax = - y + s->height; + } else if (s->out_format == FMT_H261){ + // Search range of H.261 is different from other codec standards + c->xmin = (x > 15) ? - 15 : 0; + c->ymin = (y > 15) ? - 15 : 0; + c->xmax = (x < s->mb_width * 16 - 16) ? 15 : 0; + c->ymax = (y < s->mb_height * 16 - 16) ? 15 : 0; + } else { + c->xmin = - x; + c->ymin = - y; + c->xmax = - x + s->mb_width *16 - 16; + c->ymax = - y + s->mb_height*16 - 16; + } + if(!range || range > max_range) + range = max_range; + if(range){ + c->xmin = FFMAX(c->xmin,-range); + c->xmax = FFMIN(c->xmax, range); + c->ymin = FFMAX(c->ymin,-range); + c->ymax = FFMIN(c->ymax, range); + } +} + +static inline void init_mv4_ref(MotionEstContext *c){ + const int stride= c->stride; + + c->ref[1][0] = c->ref[0][0] + 8; + c->ref[2][0] = c->ref[0][0] + 8*stride; + c->ref[3][0] = c->ref[2][0] + 8; + c->src[1][0] = c->src[0][0] + 8; + c->src[2][0] = c->src[0][0] + 8*stride; + c->src[3][0] = c->src[2][0] + 8; +} + +static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) +{ + MotionEstContext * const c= &s->me; + const int size= 1; + const int h=8; + int block; + int P[10][2]; + int dmin_sum=0, mx4_sum=0, my4_sum=0, i; + int same=1; + const int stride= c->stride; + uint8_t *mv_penalty= c->current_mv_penalty; + int safety_clipping= s->unrestricted_mv && (s->width&15) && (s->height&15); + + init_mv4_ref(c); + + for(block=0; block<4; block++){ + int mx4, my4; + int pred_x4, pred_y4; + int dmin4; + static const int off[4]= {2, 1, 1, -1}; + const int mot_stride = s->b8_stride; + const int mot_xy = s->block_index[block]; + + if(safety_clipping){ + c->xmax = - 16*s->mb_x + s->width - 8*(block &1); + c->ymax = - 16*s->mb_y + s->height - 8*(block>>1); + } + + P_LEFT[0] = s->current_picture.motion_val[0][mot_xy - 1][0]; + P_LEFT[1] = s->current_picture.motion_val[0][mot_xy - 1][1]; + + if(P_LEFT[0] > (c->xmax<xmax<first_slice_line && block<2) { + c->pred_x= pred_x4= P_LEFT[0]; + c->pred_y= pred_y4= P_LEFT[1]; + } else { + P_TOP[0] = s->current_picture.motion_val[0][mot_xy - mot_stride ][0]; + P_TOP[1] = s->current_picture.motion_val[0][mot_xy - mot_stride ][1]; + P_TOPRIGHT[0] = s->current_picture.motion_val[0][mot_xy - mot_stride + off[block]][0]; + P_TOPRIGHT[1] = s->current_picture.motion_val[0][mot_xy - mot_stride + off[block]][1]; + if(P_TOP[1] > (c->ymax<ymax<xmin<xmin< (c->xmax<xmax< (c->ymax<ymax<pred_x= pred_x4 = P_MEDIAN[0]; + c->pred_y= pred_y4 = P_MEDIAN[1]; + } + P_MV1[0]= mx; + P_MV1[1]= my; + if(safety_clipping) + for(i=1; i<10; i++){ + if (s->first_slice_line && block<2 && i>1 && i<9) + continue; + if (i>4 && i<9) + continue; + if(P[i][0] > (c->xmax<xmax< (c->ymax<ymax<p_mv_table, (1<<16)>>shift, 1); + + dmin4= c->sub_motion_search(s, &mx4, &my4, dmin4, block, block, size, h); + + if (s->mecc.me_sub_cmp[0] != s->mecc.mb_cmp[0]) { + int dxy; + const int offset= ((block&1) + (block>>1)*stride)*8; + uint8_t *dest_y = c->scratchpad + offset; + if(s->quarter_sample){ + uint8_t *ref= c->ref[block][0] + (mx4>>2) + (my4>>2)*stride; + dxy = ((my4 & 3) << 2) | (mx4 & 3); + + if(s->no_rounding) + s->qdsp.put_no_rnd_qpel_pixels_tab[1][dxy](dest_y, ref, stride); + else + s->qdsp.put_qpel_pixels_tab[1][dxy](dest_y, ref, stride); + }else{ + uint8_t *ref= c->ref[block][0] + (mx4>>1) + (my4>>1)*stride; + dxy = ((my4 & 1) << 1) | (mx4 & 1); + + if(s->no_rounding) + s->hdsp.put_no_rnd_pixels_tab[1][dxy](dest_y , ref , stride, h); + else + s->hdsp.put_pixels_tab [1][dxy](dest_y , ref , stride, h); + } + dmin_sum+= (mv_penalty[mx4-pred_x4] + mv_penalty[my4-pred_y4])*c->mb_penalty_factor; + }else + dmin_sum+= dmin4; + + if(s->quarter_sample){ + mx4_sum+= mx4/2; + my4_sum+= my4/2; + }else{ + mx4_sum+= mx4; + my4_sum+= my4; + } + + s->current_picture.motion_val[0][s->block_index[block]][0] = mx4; + s->current_picture.motion_val[0][s->block_index[block]][1] = my4; + + if(mx4 != mx || my4 != my) same=0; + } + + if(same) + return INT_MAX; + + if (s->mecc.me_sub_cmp[0] != s->mecc.mb_cmp[0]) { + dmin_sum += s->mecc.mb_cmp[0](s, + s->new_picture.f->data[0] + + s->mb_x * 16 + s->mb_y * 16 * stride, + c->scratchpad, stride, 16); + } + + if(c->avctx->mb_cmp&FF_CMP_CHROMA){ + int dxy; + int mx, my; + int offset; + + mx= ff_h263_round_chroma(mx4_sum); + my= ff_h263_round_chroma(my4_sum); + dxy = ((my & 1) << 1) | (mx & 1); + + offset= (s->mb_x*8 + (mx>>1)) + (s->mb_y*8 + (my>>1))*s->uvlinesize; + + if(s->no_rounding){ + s->hdsp.put_no_rnd_pixels_tab[1][dxy](c->scratchpad , s->last_picture.f->data[1] + offset, s->uvlinesize, 8); + s->hdsp.put_no_rnd_pixels_tab[1][dxy](c->scratchpad + 8, s->last_picture.f->data[2] + offset, s->uvlinesize, 8); + }else{ + s->hdsp.put_pixels_tab [1][dxy](c->scratchpad , s->last_picture.f->data[1] + offset, s->uvlinesize, 8); + s->hdsp.put_pixels_tab [1][dxy](c->scratchpad + 8, s->last_picture.f->data[2] + offset, s->uvlinesize, 8); + } + + dmin_sum += s->mecc.mb_cmp[1](s, s->new_picture.f->data[1] + s->mb_x * 8 + s->mb_y * 8 * s->uvlinesize, c->scratchpad, s->uvlinesize, 8); + dmin_sum += s->mecc.mb_cmp[1](s, s->new_picture.f->data[2] + s->mb_x * 8 + s->mb_y * 8 * s->uvlinesize, c->scratchpad + 8, s->uvlinesize, 8); + } + + c->pred_x= mx; + c->pred_y= my; + + switch(c->avctx->mb_cmp&0xFF){ + /*case FF_CMP_SSE: + return dmin_sum+ 32*s->qscale*s->qscale;*/ + case FF_CMP_RD: + return dmin_sum; + default: + return dmin_sum+ 11*c->mb_penalty_factor; + } +} + +static inline void init_interlaced_ref(MpegEncContext *s, int ref_index){ + MotionEstContext * const c= &s->me; + + c->ref[1+ref_index][0] = c->ref[0+ref_index][0] + s->linesize; + c->src[1][0] = c->src[0][0] + s->linesize; + if(c->flags & FLAG_CHROMA){ + c->ref[1+ref_index][1] = c->ref[0+ref_index][1] + s->uvlinesize; + c->ref[1+ref_index][2] = c->ref[0+ref_index][2] + s->uvlinesize; + c->src[1][1] = c->src[0][1] + s->uvlinesize; + c->src[1][2] = c->src[0][2] + s->uvlinesize; + } +} + +static int interlaced_search(MpegEncContext *s, int ref_index, + int16_t (*mv_tables[2][2])[2], uint8_t *field_select_tables[2], int mx, int my, int user_field_select) +{ + MotionEstContext * const c= &s->me; + const int size=0; + const int h=8; + int block; + int P[10][2]; + uint8_t * const mv_penalty= c->current_mv_penalty; + int same=1; + const int stride= 2*s->linesize; + int dmin_sum= 0; + const int mot_stride= s->mb_stride; + const int xy= s->mb_x + s->mb_y*mot_stride; + + c->ymin>>=1; + c->ymax>>=1; + c->stride<<=1; + c->uvstride<<=1; + init_interlaced_ref(s, ref_index); + + for(block=0; block<2; block++){ + int field_select; + int best_dmin= INT_MAX; + int best_field= -1; + + for(field_select=0; field_select<2; field_select++){ + int dmin, mx_i, my_i; + int16_t (*mv_table)[2]= mv_tables[block][field_select]; + + if(user_field_select){ + av_assert1(field_select==0 || field_select==1); + av_assert1(field_select_tables[block][xy]==0 || field_select_tables[block][xy]==1); + if(field_select_tables[block][xy] != field_select) + continue; + } + + P_LEFT[0] = mv_table[xy - 1][0]; + P_LEFT[1] = mv_table[xy - 1][1]; + if(P_LEFT[0] > (c->xmax<<1)) P_LEFT[0] = (c->xmax<<1); + + c->pred_x= P_LEFT[0]; + c->pred_y= P_LEFT[1]; + + if(!s->first_slice_line){ + P_TOP[0] = mv_table[xy - mot_stride][0]; + P_TOP[1] = mv_table[xy - mot_stride][1]; + P_TOPRIGHT[0] = mv_table[xy - mot_stride + 1][0]; + P_TOPRIGHT[1] = mv_table[xy - mot_stride + 1][1]; + if(P_TOP[1] > (c->ymax<<1)) P_TOP[1] = (c->ymax<<1); + if(P_TOPRIGHT[0] < (c->xmin<<1)) P_TOPRIGHT[0]= (c->xmin<<1); + if(P_TOPRIGHT[0] > (c->xmax<<1)) P_TOPRIGHT[0]= (c->xmax<<1); + if(P_TOPRIGHT[1] > (c->ymax<<1)) P_TOPRIGHT[1]= (c->ymax<<1); + + P_MEDIAN[0]= mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]); + P_MEDIAN[1]= mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]); + } + P_MV1[0]= mx; //FIXME not correct if block != field_select + P_MV1[1]= my / 2; + + dmin = epzs_motion_search2(s, &mx_i, &my_i, P, block, field_select+ref_index, mv_table, (1<<16)>>1, 0); + + dmin= c->sub_motion_search(s, &mx_i, &my_i, dmin, block, field_select+ref_index, size, h); + + mv_table[xy][0]= mx_i; + mv_table[xy][1]= my_i; + + if (s->mecc.me_sub_cmp[0] != s->mecc.mb_cmp[0]) { + int dxy; + + //FIXME chroma ME + uint8_t *ref= c->ref[field_select+ref_index][0] + (mx_i>>1) + (my_i>>1)*stride; + dxy = ((my_i & 1) << 1) | (mx_i & 1); + + if(s->no_rounding){ + s->hdsp.put_no_rnd_pixels_tab[size][dxy](c->scratchpad, ref , stride, h); + }else{ + s->hdsp.put_pixels_tab [size][dxy](c->scratchpad, ref , stride, h); + } + dmin = s->mecc.mb_cmp[size](s, c->src[block][0], c->scratchpad, stride, h); + dmin+= (mv_penalty[mx_i-c->pred_x] + mv_penalty[my_i-c->pred_y] + 1)*c->mb_penalty_factor; + }else + dmin+= c->mb_penalty_factor; //field_select bits + + dmin += field_select != block; //slightly prefer same field + + if(dmin < best_dmin){ + best_dmin= dmin; + best_field= field_select; + } + } + { + int16_t (*mv_table)[2]= mv_tables[block][best_field]; + + if(mv_table[xy][0] != mx) same=0; //FIXME check if these checks work and are any good at all + if(mv_table[xy][1]&1) same=0; + if(mv_table[xy][1]*2 != my) same=0; + if(best_field != block) same=0; + } + + field_select_tables[block][xy]= best_field; + dmin_sum += best_dmin; + } + + c->ymin<<=1; + c->ymax<<=1; + c->stride>>=1; + c->uvstride>>=1; + + if(same) + return INT_MAX; + + switch(c->avctx->mb_cmp&0xFF){ + /*case FF_CMP_SSE: + return dmin_sum+ 32*s->qscale*s->qscale;*/ + case FF_CMP_RD: + return dmin_sum; + default: + return dmin_sum+ 11*c->mb_penalty_factor; + } +} + +static inline int get_penalty_factor(int lambda, int lambda2, int type){ + switch(type&0xFF){ + default: + case FF_CMP_SAD: + return lambda>>FF_LAMBDA_SHIFT; + case FF_CMP_DCT: + return (3*lambda)>>(FF_LAMBDA_SHIFT+1); + case FF_CMP_W53: + return (4*lambda)>>(FF_LAMBDA_SHIFT); + case FF_CMP_W97: + return (2*lambda)>>(FF_LAMBDA_SHIFT); + case FF_CMP_SATD: + case FF_CMP_DCT264: + return (2*lambda)>>FF_LAMBDA_SHIFT; + case FF_CMP_RD: + case FF_CMP_PSNR: + case FF_CMP_SSE: + case FF_CMP_NSSE: + return lambda2>>FF_LAMBDA_SHIFT; + case FF_CMP_BIT: + case FF_CMP_MEDIAN_SAD: + return 1; + } +} + +void ff_estimate_p_frame_motion(MpegEncContext * s, + int mb_x, int mb_y) +{ + MotionEstContext * const c= &s->me; + uint8_t *pix, *ppix; + int sum, mx = 0, my = 0, dmin = 0; + int varc; ///< the variance of the block (sum of squared (p[y][x]-average)) + int vard; ///< sum of squared differences with the estimated motion vector + int P[10][2]; + const int shift= 1+s->quarter_sample; + int mb_type=0; + Picture * const pic= &s->current_picture; + + init_ref(c, s->new_picture.f->data, s->last_picture.f->data, NULL, 16*mb_x, 16*mb_y, 0); + + av_assert0(s->quarter_sample==0 || s->quarter_sample==1); + av_assert0(s->linesize == c->stride); + av_assert0(s->uvlinesize == c->uvstride); + + c->penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp); + c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp); + c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp); + c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_DMV; + + get_limits(s, 16*mb_x, 16*mb_y); + c->skip=0; + + /* intra / predictive decision */ + pix = c->src[0][0]; + sum = s->mpvencdsp.pix_sum(pix, s->linesize); + varc = s->mpvencdsp.pix_norm1(pix, s->linesize) - + (((unsigned) sum * sum) >> 8) + 500; + + pic->mb_mean[s->mb_stride * mb_y + mb_x] = (sum+128)>>8; + pic->mb_var [s->mb_stride * mb_y + mb_x] = (varc+128)>>8; + c->mb_var_sum_temp += (varc+128)>>8; + + if (s->motion_est != FF_ME_ZERO) { + const int mot_stride = s->b8_stride; + const int mot_xy = s->block_index[0]; + + P_LEFT[0] = s->current_picture.motion_val[0][mot_xy - 1][0]; + P_LEFT[1] = s->current_picture.motion_val[0][mot_xy - 1][1]; + + if (P_LEFT[0] > (c->xmax << shift)) + P_LEFT[0] = c->xmax << shift; + + if (!s->first_slice_line) { + P_TOP[0] = s->current_picture.motion_val[0][mot_xy - mot_stride ][0]; + P_TOP[1] = s->current_picture.motion_val[0][mot_xy - mot_stride ][1]; + P_TOPRIGHT[0] = s->current_picture.motion_val[0][mot_xy - mot_stride + 2][0]; + P_TOPRIGHT[1] = s->current_picture.motion_val[0][mot_xy - mot_stride + 2][1]; + if (P_TOP[1] > (c->ymax << shift)) + P_TOP[1] = c->ymax << shift; + if (P_TOPRIGHT[0] < (c->xmin * (1 << shift))) + P_TOPRIGHT[0] = c->xmin * (1 << shift); + if (P_TOPRIGHT[1] > (c->ymax * (1 << shift))) + P_TOPRIGHT[1] = c->ymax * (1 << shift); + + P_MEDIAN[0] = mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]); + P_MEDIAN[1] = mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]); + + if (s->out_format == FMT_H263) { + c->pred_x = P_MEDIAN[0]; + c->pred_y = P_MEDIAN[1]; + } else { /* MPEG-1 at least */ + c->pred_x = P_LEFT[0]; + c->pred_y = P_LEFT[1]; + } + } else { + c->pred_x = P_LEFT[0]; + c->pred_y = P_LEFT[1]; + } + dmin = ff_epzs_motion_search(s, &mx, &my, P, 0, 0, s->p_mv_table, (1<<16)>>shift, 0, 16); + } + + /* At this point (mx,my) are full-pell and the relative displacement */ + ppix = c->ref[0][0] + (my * s->linesize) + mx; + + vard = s->mecc.sse[0](NULL, pix, ppix, s->linesize, 16); + + pic->mc_mb_var[s->mb_stride * mb_y + mb_x] = (vard+128)>>8; + c->mc_mb_var_sum_temp += (vard+128)>>8; + + if (c->avctx->mb_decision > FF_MB_DECISION_SIMPLE) { + int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); + int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; + c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score); + + if (vard*2 + 200*256 > varc) + mb_type|= CANDIDATE_MB_TYPE_INTRA; + if (varc*2 + 200*256 > vard || s->qscale > 24){ +// if (varc*2 + 200*256 + 50*(s->lambda2>>FF_LAMBDA_SHIFT) > vard){ + mb_type|= CANDIDATE_MB_TYPE_INTER; + c->sub_motion_search(s, &mx, &my, dmin, 0, 0, 0, 16); + if (s->mpv_flags & FF_MPV_FLAG_MV0) + if(mx || my) + mb_type |= CANDIDATE_MB_TYPE_SKIPPED; //FIXME check difference + }else{ + mx <<=shift; + my <<=shift; + } + if ((s->avctx->flags & AV_CODEC_FLAG_4MV) + && !c->skip && varc>50<<8 && vard>10<<8){ + if(h263_mv4_search(s, mx, my, shift) < INT_MAX) + mb_type|=CANDIDATE_MB_TYPE_INTER4V; + + set_p_mv_tables(s, mx, my, 0); + }else + set_p_mv_tables(s, mx, my, 1); + if ((s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) + && !c->skip){ //FIXME varc/d checks + if(interlaced_search(s, 0, s->p_field_mv_table, s->p_field_select_table, mx, my, 0) < INT_MAX) + mb_type |= CANDIDATE_MB_TYPE_INTER_I; + } + }else{ + int intra_score, i; + mb_type= CANDIDATE_MB_TYPE_INTER; + + dmin= c->sub_motion_search(s, &mx, &my, dmin, 0, 0, 0, 16); + if(c->avctx->me_sub_cmp != c->avctx->mb_cmp && !c->skip) + dmin= get_mb_score(s, mx, my, 0, 0, 0, 16, 1); + + if ((s->avctx->flags & AV_CODEC_FLAG_4MV) + && !c->skip && varc>50<<8 && vard>10<<8){ + int dmin4= h263_mv4_search(s, mx, my, shift); + if(dmin4 < dmin){ + mb_type= CANDIDATE_MB_TYPE_INTER4V; + dmin=dmin4; + } + } + if ((s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) + && !c->skip){ //FIXME varc/d checks + int dmin_i= interlaced_search(s, 0, s->p_field_mv_table, s->p_field_select_table, mx, my, 0); + if(dmin_i < dmin){ + mb_type = CANDIDATE_MB_TYPE_INTER_I; + dmin= dmin_i; + } + } + + set_p_mv_tables(s, mx, my, mb_type!=CANDIDATE_MB_TYPE_INTER4V); + + /* get intra luma score */ + if((c->avctx->mb_cmp&0xFF)==FF_CMP_SSE){ + intra_score= varc - 500; + }else{ + unsigned mean = (sum+128)>>8; + mean*= 0x01010101; + + for(i=0; i<16; i++){ + *(uint32_t*)(&c->scratchpad[i*s->linesize+ 0]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->linesize+ 4]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->linesize+ 8]) = mean; + *(uint32_t*)(&c->scratchpad[i*s->linesize+12]) = mean; + } + + intra_score= s->mecc.mb_cmp[0](s, c->scratchpad, pix, s->linesize, 16); + } + intra_score += c->mb_penalty_factor*16; + + if(intra_score < dmin){ + mb_type= CANDIDATE_MB_TYPE_INTRA; + s->current_picture.mb_type[mb_y*s->mb_stride + mb_x] = CANDIDATE_MB_TYPE_INTRA; //FIXME cleanup + }else + s->current_picture.mb_type[mb_y*s->mb_stride + mb_x] = 0; + + { + int p_score= FFMIN(vard, varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*100); + int i_score= varc-500+(s->lambda2>>FF_LAMBDA_SHIFT)*20; + c->scene_change_score+= ff_sqrt(p_score) - ff_sqrt(i_score); + } + } + + s->mb_type[mb_y*s->mb_stride + mb_x]= mb_type; +} + +int ff_pre_estimate_p_frame_motion(MpegEncContext * s, + int mb_x, int mb_y) +{ + MotionEstContext * const c= &s->me; + int mx, my, dmin; + int P[10][2]; + const int shift= 1+s->quarter_sample; + const int xy= mb_x + mb_y*s->mb_stride; + init_ref(c, s->new_picture.f->data, s->last_picture.f->data, NULL, 16*mb_x, 16*mb_y, 0); + + av_assert0(s->quarter_sample==0 || s->quarter_sample==1); + + c->pre_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_pre_cmp); + c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_DMV; + + get_limits(s, 16*mb_x, 16*mb_y); + c->skip=0; + + P_LEFT[0] = s->p_mv_table[xy + 1][0]; + P_LEFT[1] = s->p_mv_table[xy + 1][1]; + + if(P_LEFT[0] < (c->xmin<xmin<first_slice_line) { + c->pred_x= P_LEFT[0]; + c->pred_y= P_LEFT[1]; + P_TOP[0]= P_TOPRIGHT[0]= P_MEDIAN[0]= + P_TOP[1]= P_TOPRIGHT[1]= P_MEDIAN[1]= 0; //FIXME + } else { + P_TOP[0] = s->p_mv_table[xy + s->mb_stride ][0]; + P_TOP[1] = s->p_mv_table[xy + s->mb_stride ][1]; + P_TOPRIGHT[0] = s->p_mv_table[xy + s->mb_stride - 1][0]; + P_TOPRIGHT[1] = s->p_mv_table[xy + s->mb_stride - 1][1]; + if(P_TOP[1] < (c->ymin<ymin< (c->xmax<xmax<ymin<ymin<pred_x = P_MEDIAN[0]; + c->pred_y = P_MEDIAN[1]; + } + + dmin = ff_epzs_motion_search(s, &mx, &my, P, 0, 0, s->p_mv_table, (1<<16)>>shift, 0, 16); + + s->p_mv_table[xy][0] = mx<p_mv_table[xy][1] = my<me; + int mx = 0, my = 0, dmin = 0; + int P[10][2]; + const int shift= 1+s->quarter_sample; + const int mot_stride = s->mb_stride; + const int mot_xy = mb_y*mot_stride + mb_x; + uint8_t * const mv_penalty= c->mv_penalty[f_code] + MAX_DMV; + int mv_scale; + + c->penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_cmp); + c->sub_penalty_factor= get_penalty_factor(s->lambda, s->lambda2, c->avctx->me_sub_cmp); + c->mb_penalty_factor = get_penalty_factor(s->lambda, s->lambda2, c->avctx->mb_cmp); + c->current_mv_penalty= mv_penalty; + + get_limits(s, 16*mb_x, 16*mb_y); + + if (s->motion_est != FF_ME_ZERO) { + P_LEFT[0] = mv_table[mot_xy - 1][0]; + P_LEFT[1] = mv_table[mot_xy - 1][1]; + + if (P_LEFT[0] > (c->xmax << shift)) P_LEFT[0] = (c->xmax << shift); + + /* special case for first line */ + if (!s->first_slice_line) { + P_TOP[0] = mv_table[mot_xy - mot_stride ][0]; + P_TOP[1] = mv_table[mot_xy - mot_stride ][1]; + P_TOPRIGHT[0] = mv_table[mot_xy - mot_stride + 1][0]; + P_TOPRIGHT[1] = mv_table[mot_xy - mot_stride + 1][1]; + if (P_TOP[1] > (c->ymax << shift)) P_TOP[1] = (c->ymax << shift); + if (P_TOPRIGHT[0] < (c->xmin << shift)) P_TOPRIGHT[0] = (c->xmin << shift); + if (P_TOPRIGHT[1] > (c->ymax << shift)) P_TOPRIGHT[1] = (c->ymax << shift); + + P_MEDIAN[0] = mid_pred(P_LEFT[0], P_TOP[0], P_TOPRIGHT[0]); + P_MEDIAN[1] = mid_pred(P_LEFT[1], P_TOP[1], P_TOPRIGHT[1]); + } + c->pred_x = P_LEFT[0]; + c->pred_y = P_LEFT[1]; + + if(mv_table == s->b_forw_mv_table){ + mv_scale= (s->pb_time<<16) / (s->pp_time<pb_time - s->pp_time)<<16) / (s->pp_time<p_mv_table, mv_scale, 0, 16); + } + + dmin= c->sub_motion_search(s, &mx, &my, dmin, 0, ref_index, 0, 16); + + if(c->avctx->me_sub_cmp != c->avctx->mb_cmp && !c->skip) + dmin= get_mb_score(s, mx, my, 0, ref_index, 0, 16, 1); + +// s->mb_type[mb_y*s->mb_width + mb_x]= mb_type; + mv_table[mot_xy][0]= mx; + mv_table[mot_xy][1]= my; + + return dmin; +} + +static inline int check_bidir_mv(MpegEncContext * s, + int motion_fx, int motion_fy, + int motion_bx, int motion_by, + int pred_fx, int pred_fy, + int pred_bx, int pred_by, + int size, int h) +{ + //FIXME optimize? + //FIXME better f_code prediction (max mv & distance) + //FIXME pointers + MotionEstContext * const c= &s->me; + uint8_t * const mv_penalty_f= c->mv_penalty[s->f_code] + MAX_DMV; // f_code of the prev frame + uint8_t * const mv_penalty_b= c->mv_penalty[s->b_code] + MAX_DMV; // f_code of the prev frame + int stride= c->stride; + uint8_t *dest_y = c->scratchpad; + uint8_t *ptr; + int dxy; + int src_x, src_y; + int fbmin; + uint8_t **src_data= c->src[0]; + uint8_t **ref_data= c->ref[0]; + uint8_t **ref2_data= c->ref[2]; + + if(s->quarter_sample){ + dxy = ((motion_fy & 3) << 2) | (motion_fx & 3); + src_x = motion_fx >> 2; + src_y = motion_fy >> 2; + + ptr = ref_data[0] + (src_y * stride) + src_x; + s->qdsp.put_qpel_pixels_tab[0][dxy](dest_y, ptr, stride); + + dxy = ((motion_by & 3) << 2) | (motion_bx & 3); + src_x = motion_bx >> 2; + src_y = motion_by >> 2; + + ptr = ref2_data[0] + (src_y * stride) + src_x; + s->qdsp.avg_qpel_pixels_tab[size][dxy](dest_y, ptr, stride); + }else{ + dxy = ((motion_fy & 1) << 1) | (motion_fx & 1); + src_x = motion_fx >> 1; + src_y = motion_fy >> 1; + + ptr = ref_data[0] + (src_y * stride) + src_x; + s->hdsp.put_pixels_tab[size][dxy](dest_y , ptr , stride, h); + + dxy = ((motion_by & 1) << 1) | (motion_bx & 1); + src_x = motion_bx >> 1; + src_y = motion_by >> 1; + + ptr = ref2_data[0] + (src_y * stride) + src_x; + s->hdsp.avg_pixels_tab[size][dxy](dest_y , ptr , stride, h); + } + + fbmin = (mv_penalty_f[motion_fx-pred_fx] + mv_penalty_f[motion_fy-pred_fy])*c->mb_penalty_factor + +(mv_penalty_b[motion_bx-pred_bx] + mv_penalty_b[motion_by-pred_by])*c->mb_penalty_factor + + s->mecc.mb_cmp[size](s, src_data[0], dest_y, stride, h); // FIXME new_pic + + if(c->avctx->mb_cmp&FF_CMP_CHROMA){ + } + //FIXME CHROMA !!! + + return fbmin; +} + +/* refine the bidir vectors in hq mode and return the score in both lq & hq mode*/ +static inline int bidir_refine(MpegEncContext * s, int mb_x, int mb_y) +{ + MotionEstContext * const c= &s->me; + const int mot_stride = s->mb_stride; + const int xy = mb_y *mot_stride + mb_x; + int fbmin; + int pred_fx= s->b_bidir_forw_mv_table[xy-1][0]; + int pred_fy= s->b_bidir_forw_mv_table[xy-1][1]; + int pred_bx= s->b_bidir_back_mv_table[xy-1][0]; + int pred_by= s->b_bidir_back_mv_table[xy-1][1]; + int motion_fx= s->b_bidir_forw_mv_table[xy][0]= s->b_forw_mv_table[xy][0]; + int motion_fy= s->b_bidir_forw_mv_table[xy][1]= s->b_forw_mv_table[xy][1]; + int motion_bx= s->b_bidir_back_mv_table[xy][0]= s->b_back_mv_table[xy][0]; + int motion_by= s->b_bidir_back_mv_table[xy][1]= s->b_back_mv_table[xy][1]; + const int flags= c->sub_flags; + const int qpel= flags&FLAG_QPEL; + const int shift= 1+qpel; + const int xmin= c->xmin<ymin<xmax<ymax<avctx->bidir_refine){ + int end; + static const uint8_t limittab[5]={0,8,32,64,80}; + const int limit= limittab[s->avctx->bidir_refine]; + static const int8_t vect[][4]={ +{ 0, 0, 0, 1}, { 0, 0, 0,-1}, { 0, 0, 1, 0}, { 0, 0,-1, 0}, { 0, 1, 0, 0}, { 0,-1, 0, 0}, { 1, 0, 0, 0}, {-1, 0, 0, 0}, + +{ 0, 0, 1, 1}, { 0, 0,-1,-1}, { 0, 1, 1, 0}, { 0,-1,-1, 0}, { 1, 1, 0, 0}, {-1,-1, 0, 0}, { 1, 0, 0, 1}, {-1, 0, 0,-1}, +{ 0, 1, 0, 1}, { 0,-1, 0,-1}, { 1, 0, 1, 0}, {-1, 0,-1, 0}, +{ 0, 0,-1, 1}, { 0, 0, 1,-1}, { 0,-1, 1, 0}, { 0, 1,-1, 0}, {-1, 1, 0, 0}, { 1,-1, 0, 0}, { 1, 0, 0,-1}, {-1, 0, 0, 1}, +{ 0,-1, 0, 1}, { 0, 1, 0,-1}, {-1, 0, 1, 0}, { 1, 0,-1, 0}, + +{ 0, 1, 1, 1}, { 0,-1,-1,-1}, { 1, 1, 1, 0}, {-1,-1,-1, 0}, { 1, 1, 0, 1}, {-1,-1, 0,-1}, { 1, 0, 1, 1}, {-1, 0,-1,-1}, +{ 0,-1, 1, 1}, { 0, 1,-1,-1}, {-1, 1, 1, 0}, { 1,-1,-1, 0}, { 1, 1, 0,-1}, {-1,-1, 0, 1}, { 1, 0,-1, 1}, {-1, 0, 1,-1}, +{ 0, 1,-1, 1}, { 0,-1, 1,-1}, { 1,-1, 1, 0}, {-1, 1,-1, 0}, {-1, 1, 0, 1}, { 1,-1, 0,-1}, { 1, 0, 1,-1}, {-1, 0,-1, 1}, +{ 0, 1, 1,-1}, { 0,-1,-1, 1}, { 1, 1,-1, 0}, {-1,-1, 1, 0}, { 1,-1, 0, 1}, {-1, 1, 0,-1}, {-1, 0, 1, 1}, { 1, 0,-1,-1}, + +{ 1, 1, 1, 1}, {-1,-1,-1,-1}, +{ 1, 1, 1,-1}, {-1,-1,-1, 1}, { 1, 1,-1, 1}, {-1,-1, 1,-1}, { 1,-1, 1, 1}, {-1, 1,-1,-1}, {-1, 1, 1, 1}, { 1,-1,-1,-1}, +{ 1, 1,-1,-1}, {-1,-1, 1, 1}, { 1,-1,-1, 1}, {-1, 1, 1,-1}, { 1,-1, 1,-1}, {-1, 1,-1, 1}, + }; + static const uint8_t hash[]={ +HASH8( 0, 0, 0, 1), HASH8( 0, 0, 0,-1), HASH8( 0, 0, 1, 0), HASH8( 0, 0,-1, 0), HASH8( 0, 1, 0, 0), HASH8( 0,-1, 0, 0), HASH8( 1, 0, 0, 0), HASH8(-1, 0, 0, 0), + +HASH8( 0, 0, 1, 1), HASH8( 0, 0,-1,-1), HASH8( 0, 1, 1, 0), HASH8( 0,-1,-1, 0), HASH8( 1, 1, 0, 0), HASH8(-1,-1, 0, 0), HASH8( 1, 0, 0, 1), HASH8(-1, 0, 0,-1), +HASH8( 0, 1, 0, 1), HASH8( 0,-1, 0,-1), HASH8( 1, 0, 1, 0), HASH8(-1, 0,-1, 0), +HASH8( 0, 0,-1, 1), HASH8( 0, 0, 1,-1), HASH8( 0,-1, 1, 0), HASH8( 0, 1,-1, 0), HASH8(-1, 1, 0, 0), HASH8( 1,-1, 0, 0), HASH8( 1, 0, 0,-1), HASH8(-1, 0, 0, 1), +HASH8( 0,-1, 0, 1), HASH8( 0, 1, 0,-1), HASH8(-1, 0, 1, 0), HASH8( 1, 0,-1, 0), + +HASH8( 0, 1, 1, 1), HASH8( 0,-1,-1,-1), HASH8( 1, 1, 1, 0), HASH8(-1,-1,-1, 0), HASH8( 1, 1, 0, 1), HASH8(-1,-1, 0,-1), HASH8( 1, 0, 1, 1), HASH8(-1, 0,-1,-1), +HASH8( 0,-1, 1, 1), HASH8( 0, 1,-1,-1), HASH8(-1, 1, 1, 0), HASH8( 1,-1,-1, 0), HASH8( 1, 1, 0,-1), HASH8(-1,-1, 0, 1), HASH8( 1, 0,-1, 1), HASH8(-1, 0, 1,-1), +HASH8( 0, 1,-1, 1), HASH8( 0,-1, 1,-1), HASH8( 1,-1, 1, 0), HASH8(-1, 1,-1, 0), HASH8(-1, 1, 0, 1), HASH8( 1,-1, 0,-1), HASH8( 1, 0, 1,-1), HASH8(-1, 0,-1, 1), +HASH8( 0, 1, 1,-1), HASH8( 0,-1,-1, 1), HASH8( 1, 1,-1, 0), HASH8(-1,-1, 1, 0), HASH8( 1,-1, 0, 1), HASH8(-1, 1, 0,-1), HASH8(-1, 0, 1, 1), HASH8( 1, 0,-1,-1), + +HASH8( 1, 1, 1, 1), HASH8(-1,-1,-1,-1), +HASH8( 1, 1, 1,-1), HASH8(-1,-1,-1, 1), HASH8( 1, 1,-1, 1), HASH8(-1,-1, 1,-1), HASH8( 1,-1, 1, 1), HASH8(-1, 1,-1,-1), HASH8(-1, 1, 1, 1), HASH8( 1,-1,-1,-1), +HASH8( 1, 1,-1,-1), HASH8(-1,-1, 1, 1), HASH8( 1,-1,-1, 1), HASH8(-1, 1, 1,-1), HASH8( 1,-1, 1,-1), HASH8(-1, 1,-1, 1), +}; + +#define CHECK_BIDIR(fx,fy,bx,by)\ + if( !map[(hashidx+HASH(fx,fy,bx,by))&255]\ + &&(fx<=0 || motion_fx+fx<=xmax) && (fy<=0 || motion_fy+fy<=ymax) && (bx<=0 || motion_bx+bx<=xmax) && (by<=0 || motion_by+by<=ymax)\ + &&(fx>=0 || motion_fx+fx>=xmin) && (fy>=0 || motion_fy+fy>=ymin) && (bx>=0 || motion_bx+bx>=xmin) && (by>=0 || motion_by+by>=ymin)){\ + int score;\ + map[(hashidx+HASH(fx,fy,bx,by))&255] = 1;\ + score= check_bidir_mv(s, motion_fx+fx, motion_fy+fy, motion_bx+bx, motion_by+by, pred_fx, pred_fy, pred_bx, pred_by, 0, 16);\ + if(score < fbmin){\ + hashidx += HASH(fx,fy,bx,by);\ + fbmin= score;\ + motion_fx+=fx;\ + motion_fy+=fy;\ + motion_bx+=bx;\ + motion_by+=by;\ + end=0;\ + }\ + } +#define CHECK_BIDIR2(a,b,c,d)\ +CHECK_BIDIR(a,b,c,d)\ +CHECK_BIDIR(-(a),-(b),-(c),-(d)) + + do{ + int i; + int borderdist=0; + end=1; + + CHECK_BIDIR2(0,0,0,1) + CHECK_BIDIR2(0,0,1,0) + CHECK_BIDIR2(0,1,0,0) + CHECK_BIDIR2(1,0,0,0) + + for(i=8; ib_bidir_forw_mv_table[xy][0]= motion_fx; + s->b_bidir_forw_mv_table[xy][1]= motion_fy; + s->b_bidir_back_mv_table[xy][0]= motion_bx; + s->b_bidir_back_mv_table[xy][1]= motion_by; + + return fbmin; +} + +static inline int direct_search(MpegEncContext * s, int mb_x, int mb_y) +{ + MotionEstContext * const c= &s->me; + int P[10][2]; + const int mot_stride = s->mb_stride; + const int mot_xy = mb_y*mot_stride + mb_x; + const int shift= 1+s->quarter_sample; + int dmin, i; + const int time_pp= s->pp_time; + const int time_pb= s->pb_time; + int mx, my, xmin, xmax, ymin, ymax; + int16_t (*mv_table)[2]= s->b_direct_mv_table; + + c->current_mv_penalty= c->mv_penalty[1] + MAX_DMV; + ymin= xmin=(-32)>>shift; + ymax= xmax= 31>>shift; + + if (IS_8X8(s->next_picture.mb_type[mot_xy])) { + s->mv_type= MV_TYPE_8X8; + }else{ + s->mv_type= MV_TYPE_16X16; + } + + for(i=0; i<4; i++){ + int index= s->block_index[i]; + int min, max; + + c->co_located_mv[i][0] = s->next_picture.motion_val[0][index][0]; + c->co_located_mv[i][1] = s->next_picture.motion_val[0][index][1]; + c->direct_basis_mv[i][0]= c->co_located_mv[i][0]*time_pb/time_pp + ((i& 1)<<(shift+3)); + c->direct_basis_mv[i][1]= c->co_located_mv[i][1]*time_pb/time_pp + ((i>>1)<<(shift+3)); +// c->direct_basis_mv[1][i][0]= c->co_located_mv[i][0]*(time_pb - time_pp)/time_pp + ((i &1)<<(shift+3); +// c->direct_basis_mv[1][i][1]= c->co_located_mv[i][1]*(time_pb - time_pp)/time_pp + ((i>>1)<<(shift+3); + + max= FFMAX(c->direct_basis_mv[i][0], c->direct_basis_mv[i][0] - c->co_located_mv[i][0])>>shift; + min= FFMIN(c->direct_basis_mv[i][0], c->direct_basis_mv[i][0] - c->co_located_mv[i][0])>>shift; + max+= 16*mb_x + 1; // +-1 is for the simpler rounding + min+= 16*mb_x - 1; + xmax= FFMIN(xmax, s->width - max); + xmin= FFMAX(xmin, - 16 - min); + + max= FFMAX(c->direct_basis_mv[i][1], c->direct_basis_mv[i][1] - c->co_located_mv[i][1])>>shift; + min= FFMIN(c->direct_basis_mv[i][1], c->direct_basis_mv[i][1] - c->co_located_mv[i][1])>>shift; + max+= 16*mb_y + 1; // +-1 is for the simpler rounding + min+= 16*mb_y - 1; + ymax= FFMIN(ymax, s->height - max); + ymin= FFMAX(ymin, - 16 - min); + + if(s->mv_type == MV_TYPE_16X16) break; + } + + av_assert2(xmax <= 15 && ymax <= 15 && xmin >= -16 && ymin >= -16); + + if(xmax < 0 || xmin >0 || ymax < 0 || ymin > 0){ + s->b_direct_mv_table[mot_xy][0]= 0; + s->b_direct_mv_table[mot_xy][1]= 0; + + return 256*256*256*64; + } + + c->xmin= xmin; + c->ymin= ymin; + c->xmax= xmax; + c->ymax= ymax; + c->flags |= FLAG_DIRECT; + c->sub_flags |= FLAG_DIRECT; + c->pred_x=0; + c->pred_y=0; + + P_LEFT[0] = av_clip(mv_table[mot_xy - 1][0], xmin<first_slice_line) { //FIXME maybe allow this over thread boundary as it is clipped + P_TOP[0] = av_clip(mv_table[mot_xy - mot_stride ][0], xmin<sub_flags&FLAG_QPEL) + dmin = qpel_motion_search(s, &mx, &my, dmin, 0, 0, 0, 16); + else + dmin = hpel_motion_search(s, &mx, &my, dmin, 0, 0, 0, 16); + + if(c->avctx->me_sub_cmp != c->avctx->mb_cmp && !c->skip) + dmin= get_mb_score(s, mx, my, 0, 0, 0, 16, 1); + + get_limits(s, 16*mb_x, 16*mb_y); //restore c->?min/max, maybe not needed + + mv_table[mot_xy][0]= mx; + mv_table[mot_xy][1]= my; + c->flags &= ~FLAG_DIRECT; + c->sub_flags &= ~FLAG_DIRECT; + + return dmin; +} + +void ff_estimate_b_frame_motion(MpegEncContext * s, + int mb_x, int mb_y) +{ + MotionEstContext * const c= &s->me; + const int penalty_factor= c->mb_penalty_factor; + int fmin, bmin, dmin, fbmin, bimin, fimin; + int type=0; + const int xy = mb_y*s->mb_stride + mb_x; + init_ref(c, s->new_picture.f->data, s->last_picture.f->data, + s->next_picture.f->data, 16 * mb_x, 16 * mb_y, 2); + + get_limits(s, 16*mb_x, 16*mb_y); + + c->skip=0; + + if (s->codec_id == AV_CODEC_ID_MPEG4 && s->next_picture.mbskip_table[xy]) { + int score= direct_search(s, mb_x, mb_y); //FIXME just check 0,0 + + score= ((unsigned)(score*score + 128*256))>>16; + c->mc_mb_var_sum_temp += score; + s->current_picture.mc_mb_var[mb_y*s->mb_stride + mb_x] = score; //FIXME use SSE + s->mb_type[mb_y*s->mb_stride + mb_x]= CANDIDATE_MB_TYPE_DIRECT0; + + return; + } + + if (s->codec_id == AV_CODEC_ID_MPEG4) + dmin= direct_search(s, mb_x, mb_y); + else + dmin= INT_MAX; +// FIXME penalty stuff for non-MPEG-4 + c->skip=0; + fmin = estimate_motion_b(s, mb_x, mb_y, s->b_forw_mv_table, 0, s->f_code) + + 3 * penalty_factor; + + c->skip=0; + bmin = estimate_motion_b(s, mb_x, mb_y, s->b_back_mv_table, 2, s->b_code) + + 2 * penalty_factor; + ff_dlog(s, " %d %d ", s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1]); + + c->skip=0; + fbmin= bidir_refine(s, mb_x, mb_y) + penalty_factor; + ff_dlog(s, "%d %d %d %d\n", dmin, fmin, bmin, fbmin); + + if (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME) { +//FIXME mb type penalty + c->skip=0; + c->current_mv_penalty= c->mv_penalty[s->f_code] + MAX_DMV; + fimin= interlaced_search(s, 0, + s->b_field_mv_table[0], s->b_field_select_table[0], + s->b_forw_mv_table[xy][0], s->b_forw_mv_table[xy][1], 0); + c->current_mv_penalty= c->mv_penalty[s->b_code] + MAX_DMV; + bimin= interlaced_search(s, 2, + s->b_field_mv_table[1], s->b_field_select_table[1], + s->b_back_mv_table[xy][0], s->b_back_mv_table[xy][1], 0); + }else + fimin= bimin= INT_MAX; + + { + int score= fmin; + type = CANDIDATE_MB_TYPE_FORWARD; + + if (dmin <= score){ + score = dmin; + type = CANDIDATE_MB_TYPE_DIRECT; + } + if(bmin>16; + c->mc_mb_var_sum_temp += score; + s->current_picture.mc_mb_var[mb_y*s->mb_stride + mb_x] = score; //FIXME use SSE + } + + if(c->avctx->mb_decision > FF_MB_DECISION_SIMPLE){ + type= CANDIDATE_MB_TYPE_FORWARD | CANDIDATE_MB_TYPE_BACKWARD | CANDIDATE_MB_TYPE_BIDIR | CANDIDATE_MB_TYPE_DIRECT; + if(fimin < INT_MAX) + type |= CANDIDATE_MB_TYPE_FORWARD_I; + if(bimin < INT_MAX) + type |= CANDIDATE_MB_TYPE_BACKWARD_I; + if(fimin < INT_MAX && bimin < INT_MAX){ + type |= CANDIDATE_MB_TYPE_BIDIR_I; + } + //FIXME something smarter + if(dmin>256*256*16) type&= ~CANDIDATE_MB_TYPE_DIRECT; //do not try direct mode if it is invalid for this MB + if (s->codec_id == AV_CODEC_ID_MPEG4 && type&CANDIDATE_MB_TYPE_DIRECT && + s->mpv_flags & FF_MPV_FLAG_MV0 && *(uint32_t*)s->b_direct_mv_table[xy]) + type |= CANDIDATE_MB_TYPE_DIRECT0; + } + + s->mb_type[mb_y*s->mb_stride + mb_x]= type; +} + +/* find best f_code for ME which do unlimited searches */ +int ff_get_best_fcode(MpegEncContext * s, int16_t (*mv_table)[2], int type) +{ + if (s->motion_est != FF_ME_ZERO) { + int score[8]; + int i, y, range= s->avctx->me_range ? s->avctx->me_range : (INT_MAX/2); + uint8_t * fcode_tab= s->fcode_tab; + int best_fcode=-1; + int best_score=-10000000; + + if(s->msmpeg4_version) + range= FFMIN(range, 16); + else if(s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL) + range= FFMIN(range, 256); + + for(i=0; i<8; i++) score[i]= s->mb_num*(8-i); + + for(y=0; ymb_height; y++){ + int x; + int xy= y*s->mb_stride; + for(x=0; xmb_width; x++){ + if(s->mb_type[xy] & type){ + int mx= mv_table[xy][0]; + int my= mv_table[xy][1]; + int fcode= FFMAX(fcode_tab[mx + MAX_MV], + fcode_tab[my + MAX_MV]); + int j; + + if(mx >= range || mx < -range || + my >= range || my < -range) + continue; + + for(j=0; jpict_type==AV_PICTURE_TYPE_B || s->current_picture.mc_mb_var[xy] < s->current_picture.mb_var[xy]) + score[j]-= 170; + } + } + xy++; + } + } + + for(i=1; i<8; i++){ + if(score[i] > best_score){ + best_score= score[i]; + best_fcode= i; + } + } + + return best_fcode; + }else{ + return 1; + } +} + +void ff_fix_long_p_mvs(MpegEncContext * s) +{ + MotionEstContext * const c= &s->me; + const int f_code= s->f_code; + int y, range; + av_assert0(s->pict_type==AV_PICTURE_TYPE_P); + + range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version) ? 8 : 16) << f_code); + + av_assert0(range <= 16 || !s->msmpeg4_version); + av_assert0(range <=256 || !(s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->avctx->strict_std_compliance >= FF_COMPLIANCE_NORMAL)); + + if(c->avctx->me_range && range > c->avctx->me_range) range= c->avctx->me_range; + + if (s->avctx->flags & AV_CODEC_FLAG_4MV) { + const int wrap= s->b8_stride; + + /* clip / convert to intra 8x8 type MVs */ + for(y=0; ymb_height; y++){ + int xy= y*2*wrap; + int i= y*s->mb_stride; + int x; + + for(x=0; xmb_width; x++){ + if(s->mb_type[i]&CANDIDATE_MB_TYPE_INTER4V){ + int block; + for(block=0; block<4; block++){ + int off= (block& 1) + (block>>1)*wrap; + int mx = s->current_picture.motion_val[0][ xy + off ][0]; + int my = s->current_picture.motion_val[0][ xy + off ][1]; + + if( mx >=range || mx <-range + || my >=range || my <-range){ + s->mb_type[i] &= ~CANDIDATE_MB_TYPE_INTER4V; + s->mb_type[i] |= CANDIDATE_MB_TYPE_INTRA; + s->current_picture.mb_type[i] = CANDIDATE_MB_TYPE_INTRA; + } + } + } + xy+=2; + i++; + } + } + } +} + +/** + * @param truncate 1 for truncation, 0 for using intra + */ +void ff_fix_long_mvs(MpegEncContext * s, uint8_t *field_select_table, int field_select, + int16_t (*mv_table)[2], int f_code, int type, int truncate) +{ + MotionEstContext * const c= &s->me; + int y, h_range, v_range; + + // RAL: 8 in MPEG-1, 16 in MPEG-4 + int range = (((s->out_format == FMT_MPEG1 || s->msmpeg4_version) ? 8 : 16) << f_code); + + if(c->avctx->me_range && range > c->avctx->me_range) range= c->avctx->me_range; + + h_range= range; + v_range= field_select_table ? range>>1 : range; + + /* clip / convert to intra 16x16 type MVs */ + for(y=0; ymb_height; y++){ + int x; + int xy= y*s->mb_stride; + for(x=0; xmb_width; x++){ + if (s->mb_type[xy] & type){ // RAL: "type" test added... + if (!field_select_table || field_select_table[xy] == field_select) { + if( mv_table[xy][0] >=h_range || mv_table[xy][0] <-h_range + || mv_table[xy][1] >=v_range || mv_table[xy][1] <-v_range){ + + if(truncate){ + if (mv_table[xy][0] > h_range-1) mv_table[xy][0]= h_range-1; + else if(mv_table[xy][0] < -h_range ) mv_table[xy][0]= -h_range; + if (mv_table[xy][1] > v_range-1) mv_table[xy][1]= v_range-1; + else if(mv_table[xy][1] < -v_range ) mv_table[xy][1]= -v_range; + }else{ + s->mb_type[xy] &= ~type; + s->mb_type[xy] |= CANDIDATE_MB_TYPE_INTRA; + mv_table[xy][0]= + mv_table[xy][1]= 0; + } + } + } + } + xy++; + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/motion_est.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/motion_est.h new file mode 100644 index 0000000000..3b3a8d7341 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/motion_est.h @@ -0,0 +1,135 @@ +/* + * Motion estimation + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MOTION_EST_H +#define AVCODEC_MOTION_EST_H + +#include + +#include "avcodec.h" +#include "hpeldsp.h" +#include "qpeldsp.h" + +struct MpegEncContext; + +#if ARCH_IA64 // Limit static arrays to avoid gcc failing "short data segment overflowed" +#define MAX_MV 1024 +#else +#define MAX_MV 4096 +#endif +#define MAX_DMV (2*MAX_MV) +#define ME_MAP_SIZE 64 + +#define FF_ME_ZERO 0 +#define FF_ME_EPZS 1 +#define FF_ME_XONE 2 + +/** + * Motion estimation context. + */ +typedef struct MotionEstContext { + AVCodecContext *avctx; + int skip; ///< set if ME is skipped for the current MB + int co_located_mv[4][2]; ///< mv from last P-frame for direct mode ME + int direct_basis_mv[4][2]; + uint8_t *scratchpad; /**< data area for the ME algo, so that + * the ME does not need to malloc/free. */ + uint8_t *best_mb; + uint8_t *temp_mb[2]; + uint8_t *temp; + int best_bits; + uint32_t *map; ///< map to avoid duplicate evaluations + uint32_t *score_map; ///< map to store the scores + unsigned map_generation; + int pre_penalty_factor; + int penalty_factor; /**< an estimate of the bits required to + * code a given mv value, e.g. (1,0) takes + * more bits than (0,0). We have to + * estimate whether any reduction in + * residual is worth the extra bits. */ + int sub_penalty_factor; + int mb_penalty_factor; + int flags; + int sub_flags; + int mb_flags; + int pre_pass; ///< = 1 for the pre pass + int dia_size; + int xmin; + int xmax; + int ymin; + int ymax; + int pred_x; + int pred_y; + uint8_t *src[4][4]; + uint8_t *ref[4][4]; + int stride; + int uvstride; + /* temp variables for picture complexity calculation */ + int64_t mc_mb_var_sum_temp; + int64_t mb_var_sum_temp; + int scene_change_score; + + op_pixels_func(*hpel_put)[4]; + op_pixels_func(*hpel_avg)[4]; + qpel_mc_func(*qpel_put)[16]; + qpel_mc_func(*qpel_avg)[16]; + uint8_t (*mv_penalty)[MAX_DMV * 2 + 1]; ///< bit amount needed to encode a MV + uint8_t *current_mv_penalty; + int (*sub_motion_search)(struct MpegEncContext *s, + int *mx_ptr, int *my_ptr, int dmin, + int src_index, int ref_index, + int size, int h); +} MotionEstContext; + +static inline int ff_h263_round_chroma(int x) +{ + //FIXME static or not? + static const uint8_t h263_chroma_roundtab[16] = { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + }; + return h263_chroma_roundtab[x & 0xf] + (x >> 3); +} + +int ff_init_me(struct MpegEncContext *s); + +void ff_estimate_p_frame_motion(struct MpegEncContext *s, int mb_x, int mb_y); +void ff_estimate_b_frame_motion(struct MpegEncContext *s, int mb_x, int mb_y); + +int ff_pre_estimate_p_frame_motion(struct MpegEncContext *s, + int mb_x, int mb_y); + +int ff_epzs_motion_search(struct MpegEncContext *s, int *mx_ptr, int *my_ptr, + int P[10][2], int src_index, int ref_index, + int16_t (*last_mv)[2], int ref_mv_scale, int size, + int h); + +int ff_get_mb_score(struct MpegEncContext *s, int mx, int my, int src_index, + int ref_index, int size, int h, int add_rate); + +int ff_get_best_fcode(struct MpegEncContext *s, + int16_t (*mv_table)[2], int type); + +void ff_fix_long_p_mvs(struct MpegEncContext *s); +void ff_fix_long_mvs(struct MpegEncContext *s, uint8_t *field_select_table, + int field_select, int16_t (*mv_table)[2], int f_code, + int type, int truncate); + +#endif /* AVCODEC_MOTION_EST_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12.c new file mode 100644 index 0000000000..ab6c19c615 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12.c @@ -0,0 +1,332 @@ +/* + * MPEG-1/2 decoder + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * MPEG-1/2 decoder + */ + +#define UNCHECKED_BITSTREAM_READER 1 + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/timecode.h" + +#include "internal.h" +#include "avcodec.h" +#include "mpegvideo.h" +#include "error_resilience.h" +#include "mpeg12.h" +#include "mpeg12data.h" +#include "mpegvideodata.h" +#include "bytestream.h" +#include "thread.h" + +uint8_t ff_mpeg12_static_rl_table_store[2][2][2*MAX_RUN + MAX_LEVEL + 3]; + +static const uint8_t table_mb_ptype[7][2] = { + { 3, 5 }, // 0x01 MB_INTRA + { 1, 2 }, // 0x02 MB_PAT + { 1, 3 }, // 0x08 MB_FOR + { 1, 1 }, // 0x0A MB_FOR|MB_PAT + { 1, 6 }, // 0x11 MB_QUANT|MB_INTRA + { 1, 5 }, // 0x12 MB_QUANT|MB_PAT + { 2, 5 }, // 0x1A MB_QUANT|MB_FOR|MB_PAT +}; + +static const uint8_t table_mb_btype[11][2] = { + { 3, 5 }, // 0x01 MB_INTRA + { 2, 3 }, // 0x04 MB_BACK + { 3, 3 }, // 0x06 MB_BACK|MB_PAT + { 2, 4 }, // 0x08 MB_FOR + { 3, 4 }, // 0x0A MB_FOR|MB_PAT + { 2, 2 }, // 0x0C MB_FOR|MB_BACK + { 3, 2 }, // 0x0E MB_FOR|MB_BACK|MB_PAT + { 1, 6 }, // 0x11 MB_QUANT|MB_INTRA + { 2, 6 }, // 0x16 MB_QUANT|MB_BACK|MB_PAT + { 3, 6 }, // 0x1A MB_QUANT|MB_FOR|MB_PAT + { 2, 5 }, // 0x1E MB_QUANT|MB_FOR|MB_BACK|MB_PAT +}; + +av_cold void ff_init_2d_vlc_rl(RLTable *rl, unsigned static_size, int flags) +{ + int i; + VLC_TYPE table[680][2] = {{0}}; + VLC vlc = { .table = table, .table_allocated = static_size }; + av_assert0(static_size <= FF_ARRAY_ELEMS(table)); + init_vlc(&vlc, TEX_VLC_BITS, rl->n + 2, &rl->table_vlc[0][1], 4, 2, &rl->table_vlc[0][0], 4, 2, INIT_VLC_USE_NEW_STATIC | flags); + + for (i = 0; i < vlc.table_size; i++) { + int code = vlc.table[i][0]; + int len = vlc.table[i][1]; + int level, run; + + if (len == 0) { // illegal code + run = 65; + level = MAX_LEVEL; + } else if (len<0) { //more bits needed + run = 0; + level = code; + } else { + if (code == rl->n) { //esc + run = 65; + level = 0; + } else if (code == rl->n+1) { //eob + run = 0; + level = 127; + } else { + run = rl->table_run [code] + 1; + level = rl->table_level[code]; + } + } + rl->rl_vlc[0][i].len = len; + rl->rl_vlc[0][i].level = level; + rl->rl_vlc[0][i].run = run; + } +} + +av_cold void ff_mpeg12_common_init(MpegEncContext *s) +{ + + s->y_dc_scale_table = + s->c_dc_scale_table = ff_mpeg2_dc_scale_table[s->intra_dc_precision]; + +} + +void ff_mpeg1_clean_buffers(MpegEncContext *s) +{ + s->last_dc[0] = 1 << (7 + s->intra_dc_precision); + s->last_dc[1] = s->last_dc[0]; + s->last_dc[2] = s->last_dc[0]; + memset(s->last_mv, 0, sizeof(s->last_mv)); +} + + +/******************************************/ +/* decoding */ + +VLC ff_mv_vlc; + +VLC ff_dc_lum_vlc; +VLC ff_dc_chroma_vlc; + +VLC ff_mbincr_vlc; +VLC ff_mb_ptype_vlc; +VLC ff_mb_btype_vlc; +VLC ff_mb_pat_vlc; + +av_cold void ff_mpeg12_init_vlcs(void) +{ + static int done = 0; + + if (!done) { + done = 1; + + INIT_VLC_STATIC(&ff_dc_lum_vlc, DC_VLC_BITS, 12, + ff_mpeg12_vlc_dc_lum_bits, 1, 1, + ff_mpeg12_vlc_dc_lum_code, 2, 2, 512); + INIT_VLC_STATIC(&ff_dc_chroma_vlc, DC_VLC_BITS, 12, + ff_mpeg12_vlc_dc_chroma_bits, 1, 1, + ff_mpeg12_vlc_dc_chroma_code, 2, 2, 514); + INIT_VLC_STATIC(&ff_mv_vlc, MV_VLC_BITS, 17, + &ff_mpeg12_mbMotionVectorTable[0][1], 2, 1, + &ff_mpeg12_mbMotionVectorTable[0][0], 2, 1, 518); + INIT_VLC_STATIC(&ff_mbincr_vlc, MBINCR_VLC_BITS, 36, + &ff_mpeg12_mbAddrIncrTable[0][1], 2, 1, + &ff_mpeg12_mbAddrIncrTable[0][0], 2, 1, 538); + INIT_VLC_STATIC(&ff_mb_pat_vlc, MB_PAT_VLC_BITS, 64, + &ff_mpeg12_mbPatTable[0][1], 2, 1, + &ff_mpeg12_mbPatTable[0][0], 2, 1, 512); + + INIT_VLC_STATIC(&ff_mb_ptype_vlc, MB_PTYPE_VLC_BITS, 7, + &table_mb_ptype[0][1], 2, 1, + &table_mb_ptype[0][0], 2, 1, 64); + INIT_VLC_STATIC(&ff_mb_btype_vlc, MB_BTYPE_VLC_BITS, 11, + &table_mb_btype[0][1], 2, 1, + &table_mb_btype[0][0], 2, 1, 64); + ff_rl_init(&ff_rl_mpeg1, ff_mpeg12_static_rl_table_store[0]); + ff_rl_init(&ff_rl_mpeg2, ff_mpeg12_static_rl_table_store[1]); + + INIT_2D_VLC_RL(ff_rl_mpeg1, 680, 0); + INIT_2D_VLC_RL(ff_rl_mpeg2, 674, 0); + } +} + +/** + * Find the end of the current frame in the bitstream. + * @return the position of the first byte of the next frame, or -1 + */ +int ff_mpeg1_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size, AVCodecParserContext *s) +{ + int i; + uint32_t state = pc->state; + + /* EOF considered as end of frame */ + if (buf_size == 0) + return 0; + +/* + 0 frame start -> 1/4 + 1 first_SEQEXT -> 0/2 + 2 first field start -> 3/0 + 3 second_SEQEXT -> 2/0 + 4 searching end +*/ + + for (i = 0; i < buf_size; i++) { + av_assert1(pc->frame_start_found >= 0 && pc->frame_start_found <= 4); + if (pc->frame_start_found & 1) { + if (state == EXT_START_CODE && (buf[i] & 0xF0) != 0x80) + pc->frame_start_found--; + else if (state == EXT_START_CODE + 2) { + if ((buf[i] & 3) == 3) + pc->frame_start_found = 0; + else + pc->frame_start_found = (pc->frame_start_found + 1) & 3; + } + state++; + } else { + i = avpriv_find_start_code(buf + i, buf + buf_size, &state) - buf - 1; + if (pc->frame_start_found == 0 && state >= SLICE_MIN_START_CODE && state <= SLICE_MAX_START_CODE) { + i++; + pc->frame_start_found = 4; + } + if (state == SEQ_END_CODE) { + pc->frame_start_found = 0; + pc->state=-1; + return i+1; + } + if (pc->frame_start_found == 2 && state == SEQ_START_CODE) + pc->frame_start_found = 0; + if (pc->frame_start_found < 4 && state == EXT_START_CODE) + pc->frame_start_found++; + if (pc->frame_start_found == 4 && (state & 0xFFFFFF00) == 0x100) { + if (state < SLICE_MIN_START_CODE || state > SLICE_MAX_START_CODE) { + pc->frame_start_found = 0; + pc->state = -1; + return i - 3; + } + } + if (pc->frame_start_found == 0 && s && state == PICTURE_START_CODE) { + ff_fetch_timestamp(s, i - 3, 1, i > 3); + } + } + } + pc->state = state; + return END_NOT_FOUND; +} + +#define MAX_INDEX (64 - 1) + +int ff_mpeg1_decode_block_intra(GetBitContext *gb, + const uint16_t *quant_matrix, + uint8_t *const scantable, int last_dc[3], + int16_t *block, int index, int qscale) +{ + int dc, diff, i = 0, component; + RLTable *rl = &ff_rl_mpeg1; + + /* DC coefficient */ + component = index <= 3 ? 0 : index - 4 + 1; + + diff = decode_dc(gb, component); + if (diff >= 0xffff) + return AVERROR_INVALIDDATA; + + dc = last_dc[component]; + dc += diff; + last_dc[component] = dc; + + block[0] = dc * quant_matrix[0]; + + { + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + if (((int32_t)GET_CACHE(re, gb)) <= (int32_t)0xBFFFFFFF) + goto end; + + /* now quantify & encode AC coefficients */ + while (1) { + int level, run, j; + + GET_RL_VLC(level, run, re, gb, rl->rl_vlc[0], + TEX_VLC_BITS, 2, 0); + + if (level != 0) { + i += run; + if (i > MAX_INDEX) + break; + + j = scantable[i]; + level = (level * qscale * quant_matrix[j]) >> 4; + level = (level - 1) | 1; + level = (level ^ SHOW_SBITS(re, gb, 1)) - + SHOW_SBITS(re, gb, 1); + SKIP_BITS(re, gb, 1); + } else { + /* escape */ + run = SHOW_UBITS(re, gb, 6) + 1; + LAST_SKIP_BITS(re, gb, 6); + UPDATE_CACHE(re, gb); + level = SHOW_SBITS(re, gb, 8); + SKIP_BITS(re, gb, 8); + + if (level == -128) { + level = SHOW_UBITS(re, gb, 8) - 256; + SKIP_BITS(re, gb, 8); + } else if (level == 0) { + level = SHOW_UBITS(re, gb, 8); + SKIP_BITS(re, gb, 8); + } + + i += run; + if (i > MAX_INDEX) + break; + + j = scantable[i]; + if (level < 0) { + level = -level; + level = (level * qscale * quant_matrix[j]) >> 4; + level = (level - 1) | 1; + level = -level; + } else { + level = (level * qscale * quant_matrix[j]) >> 4; + level = (level - 1) | 1; + } + } + + block[j] = level; + if (((int32_t)GET_CACHE(re, gb)) <= (int32_t)0xBFFFFFFF) + break; + + UPDATE_CACHE(re, gb); + } +end: + LAST_SKIP_BITS(re, gb, 2); + CLOSE_READER(re, gb); + } + + if (i > MAX_INDEX) + i = AVERROR_INVALIDDATA; + + return i; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12.h new file mode 100644 index 0000000000..1ec99f17e1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12.h @@ -0,0 +1,80 @@ +/* + * MPEG-1/2 common code + * Copyright (c) 2007 Aurelien Jacobs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MPEG12_H +#define AVCODEC_MPEG12_H + +#include "mpeg12vlc.h" +#include "mpegvideo.h" + +extern uint8_t ff_mpeg12_static_rl_table_store[2][2][2*MAX_RUN + MAX_LEVEL + 3]; + +void ff_mpeg12_common_init(MpegEncContext *s); + +#define INIT_2D_VLC_RL(rl, static_size, flags)\ +{\ + static RL_VLC_ELEM rl_vlc_table[static_size];\ + rl.rl_vlc[0] = rl_vlc_table;\ + ff_init_2d_vlc_rl(&rl, static_size, flags);\ +} + +void ff_init_2d_vlc_rl(RLTable *rl, unsigned static_size, int flags); + +static inline int decode_dc(GetBitContext *gb, int component) +{ + int code, diff; + + if (component == 0) { + code = get_vlc2(gb, ff_dc_lum_vlc.table, DC_VLC_BITS, 2); + } else { + code = get_vlc2(gb, ff_dc_chroma_vlc.table, DC_VLC_BITS, 2); + } + if (code < 0){ + av_log(NULL, AV_LOG_ERROR, "invalid dc code at\n"); + return 0xffff; + } + if (code == 0) { + diff = 0; + } else { + diff = get_xbits(gb, code); + } + return diff; +} + +int ff_mpeg1_decode_block_intra(GetBitContext *gb, + const uint16_t *quant_matrix, + uint8_t *const scantable, int last_dc[3], + int16_t *block, int index, int qscale); + +void ff_mpeg1_clean_buffers(MpegEncContext *s); +int ff_mpeg1_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size, AVCodecParserContext *s); + +void ff_mpeg1_encode_picture_header(MpegEncContext *s, int picture_number); +void ff_mpeg1_encode_mb(MpegEncContext *s, int16_t block[8][64], + int motion_x, int motion_y); +void ff_mpeg1_encode_init(MpegEncContext *s); +void ff_mpeg1_encode_slice_header(MpegEncContext *s); + +void ff_mpeg12_find_best_frame_rate(AVRational frame_rate, + int *code, int *ext_n, int *ext_d, + int nonstandard); + +#endif /* AVCODEC_MPEG12_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12data.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12data.c new file mode 100644 index 0000000000..4da96d7da3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12data.c @@ -0,0 +1,412 @@ +/* + * MPEG-1/2 tables + * copyright (c) 2000,2001 Fabrice Bellard + * copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * MPEG-1/2 tables. + */ + +#include "mpeg12data.h" + +const uint16_t ff_mpeg1_default_intra_matrix[256] = { + 8, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83 +}; + +const uint16_t ff_mpeg1_default_non_intra_matrix[64] = { + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, +}; + +const uint16_t ff_mpeg12_vlc_dc_lum_code[12] = { + 0x4, 0x0, 0x1, 0x5, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe, 0x1ff, +}; +const unsigned char ff_mpeg12_vlc_dc_lum_bits[12] = { + 3, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 9, +}; + +const uint16_t ff_mpeg12_vlc_dc_chroma_code[12] = { + 0x0, 0x1, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe, 0x3fe, 0x3ff, +}; +const unsigned char ff_mpeg12_vlc_dc_chroma_bits[12] = { + 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, +}; + +static const uint16_t mpeg1_vlc[113][2] = { + { 0x3, 2 }, { 0x4, 4 }, { 0x5, 5 }, { 0x6, 7 }, + { 0x26, 8 }, { 0x21, 8 }, { 0xa, 10 }, { 0x1d, 12 }, + { 0x18, 12 }, { 0x13, 12 }, { 0x10, 12 }, { 0x1a, 13 }, + { 0x19, 13 }, { 0x18, 13 }, { 0x17, 13 }, { 0x1f, 14 }, + { 0x1e, 14 }, { 0x1d, 14 }, { 0x1c, 14 }, { 0x1b, 14 }, + { 0x1a, 14 }, { 0x19, 14 }, { 0x18, 14 }, { 0x17, 14 }, + { 0x16, 14 }, { 0x15, 14 }, { 0x14, 14 }, { 0x13, 14 }, + { 0x12, 14 }, { 0x11, 14 }, { 0x10, 14 }, { 0x18, 15 }, + { 0x17, 15 }, { 0x16, 15 }, { 0x15, 15 }, { 0x14, 15 }, + { 0x13, 15 }, { 0x12, 15 }, { 0x11, 15 }, { 0x10, 15 }, + { 0x3, 3 }, { 0x6, 6 }, { 0x25, 8 }, { 0xc, 10 }, + { 0x1b, 12 }, { 0x16, 13 }, { 0x15, 13 }, { 0x1f, 15 }, + { 0x1e, 15 }, { 0x1d, 15 }, { 0x1c, 15 }, { 0x1b, 15 }, + { 0x1a, 15 }, { 0x19, 15 }, { 0x13, 16 }, { 0x12, 16 }, + { 0x11, 16 }, { 0x10, 16 }, { 0x5, 4 }, { 0x4, 7 }, + { 0xb, 10 }, { 0x14, 12 }, { 0x14, 13 }, { 0x7, 5 }, + { 0x24, 8 }, { 0x1c, 12 }, { 0x13, 13 }, { 0x6, 5 }, + { 0xf, 10 }, { 0x12, 12 }, { 0x7, 6 }, { 0x9, 10 }, + { 0x12, 13 }, { 0x5, 6 }, { 0x1e, 12 }, { 0x14, 16 }, + { 0x4, 6 }, { 0x15, 12 }, { 0x7, 7 }, { 0x11, 12 }, + { 0x5, 7 }, { 0x11, 13 }, { 0x27, 8 }, { 0x10, 13 }, + { 0x23, 8 }, { 0x1a, 16 }, { 0x22, 8 }, { 0x19, 16 }, + { 0x20, 8 }, { 0x18, 16 }, { 0xe, 10 }, { 0x17, 16 }, + { 0xd, 10 }, { 0x16, 16 }, { 0x8, 10 }, { 0x15, 16 }, + { 0x1f, 12 }, { 0x1a, 12 }, { 0x19, 12 }, { 0x17, 12 }, + { 0x16, 12 }, { 0x1f, 13 }, { 0x1e, 13 }, { 0x1d, 13 }, + { 0x1c, 13 }, { 0x1b, 13 }, { 0x1f, 16 }, { 0x1e, 16 }, + { 0x1d, 16 }, { 0x1c, 16 }, { 0x1b, 16 }, + { 0x1, 6 }, /* escape */ + { 0x2, 2 }, /* EOB */ +}; + +static const uint16_t mpeg2_vlc[113][2] = { + {0x02, 2}, {0x06, 3}, {0x07, 4}, {0x1c, 5}, + {0x1d, 5}, {0x05, 6}, {0x04, 6}, {0x7b, 7}, + {0x7c, 7}, {0x23, 8}, {0x22, 8}, {0xfa, 8}, + {0xfb, 8}, {0xfe, 8}, {0xff, 8}, {0x1f,14}, + {0x1e,14}, {0x1d,14}, {0x1c,14}, {0x1b,14}, + {0x1a,14}, {0x19,14}, {0x18,14}, {0x17,14}, + {0x16,14}, {0x15,14}, {0x14,14}, {0x13,14}, + {0x12,14}, {0x11,14}, {0x10,14}, {0x18,15}, + {0x17,15}, {0x16,15}, {0x15,15}, {0x14,15}, + {0x13,15}, {0x12,15}, {0x11,15}, {0x10,15}, + {0x02, 3}, {0x06, 5}, {0x79, 7}, {0x27, 8}, + {0x20, 8}, {0x16,13}, {0x15,13}, {0x1f,15}, + {0x1e,15}, {0x1d,15}, {0x1c,15}, {0x1b,15}, + {0x1a,15}, {0x19,15}, {0x13,16}, {0x12,16}, + {0x11,16}, {0x10,16}, {0x05, 5}, {0x07, 7}, + {0xfc, 8}, {0x0c,10}, {0x14,13}, {0x07, 5}, + {0x26, 8}, {0x1c,12}, {0x13,13}, {0x06, 6}, + {0xfd, 8}, {0x12,12}, {0x07, 6}, {0x04, 9}, + {0x12,13}, {0x06, 7}, {0x1e,12}, {0x14,16}, + {0x04, 7}, {0x15,12}, {0x05, 7}, {0x11,12}, + {0x78, 7}, {0x11,13}, {0x7a, 7}, {0x10,13}, + {0x21, 8}, {0x1a,16}, {0x25, 8}, {0x19,16}, + {0x24, 8}, {0x18,16}, {0x05, 9}, {0x17,16}, + {0x07, 9}, {0x16,16}, {0x0d,10}, {0x15,16}, + {0x1f,12}, {0x1a,12}, {0x19,12}, {0x17,12}, + {0x16,12}, {0x1f,13}, {0x1e,13}, {0x1d,13}, + {0x1c,13}, {0x1b,13}, {0x1f,16}, {0x1e,16}, + {0x1d,16}, {0x1c,16}, {0x1b,16}, + {0x01,6}, /* escape */ + {0x06,4}, /* EOB */ +}; + +static const int8_t mpeg1_level[111] = { + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 1, 2, 3, 4, 5, 1, + 2, 3, 4, 1, 2, 3, 1, 2, + 3, 1, 2, 3, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, + 1, 2, 1, 2, 1, 2, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, +}; + +static const int8_t mpeg1_run[111] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 2, 3, + 3, 3, 3, 4, 4, 4, 5, 5, + 5, 6, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, + 13, 13, 14, 14, 15, 15, 16, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, +}; + +RLTable ff_rl_mpeg1 = { + 111, + 111, + mpeg1_vlc, + mpeg1_run, + mpeg1_level, +}; + +RLTable ff_rl_mpeg2 = { + 111, + 111, + mpeg2_vlc, + mpeg1_run, + mpeg1_level, +}; + +const uint8_t ff_mpeg12_mbAddrIncrTable[36][2] = { + {0x1, 1}, + {0x3, 3}, + {0x2, 3}, + {0x3, 4}, + {0x2, 4}, + {0x3, 5}, + {0x2, 5}, + {0x7, 7}, + {0x6, 7}, + {0xb, 8}, + {0xa, 8}, + {0x9, 8}, + {0x8, 8}, + {0x7, 8}, + {0x6, 8}, + {0x17, 10}, + {0x16, 10}, + {0x15, 10}, + {0x14, 10}, + {0x13, 10}, + {0x12, 10}, + {0x23, 11}, + {0x22, 11}, + {0x21, 11}, + {0x20, 11}, + {0x1f, 11}, + {0x1e, 11}, + {0x1d, 11}, + {0x1c, 11}, + {0x1b, 11}, + {0x1a, 11}, + {0x19, 11}, + {0x18, 11}, + {0x8, 11}, /* escape */ + {0xf, 11}, /* stuffing */ + {0x0, 8}, /* end (and 15 more 0 bits should follow) */ +}; + +const uint8_t ff_mpeg12_mbPatTable[64][2] = { + {0x1, 9}, + {0xb, 5}, + {0x9, 5}, + {0xd, 6}, + {0xd, 4}, + {0x17, 7}, + {0x13, 7}, + {0x1f, 8}, + {0xc, 4}, + {0x16, 7}, + {0x12, 7}, + {0x1e, 8}, + {0x13, 5}, + {0x1b, 8}, + {0x17, 8}, + {0x13, 8}, + {0xb, 4}, + {0x15, 7}, + {0x11, 7}, + {0x1d, 8}, + {0x11, 5}, + {0x19, 8}, + {0x15, 8}, + {0x11, 8}, + {0xf, 6}, + {0xf, 8}, + {0xd, 8}, + {0x3, 9}, + {0xf, 5}, + {0xb, 8}, + {0x7, 8}, + {0x7, 9}, + {0xa, 4}, + {0x14, 7}, + {0x10, 7}, + {0x1c, 8}, + {0xe, 6}, + {0xe, 8}, + {0xc, 8}, + {0x2, 9}, + {0x10, 5}, + {0x18, 8}, + {0x14, 8}, + {0x10, 8}, + {0xe, 5}, + {0xa, 8}, + {0x6, 8}, + {0x6, 9}, + {0x12, 5}, + {0x1a, 8}, + {0x16, 8}, + {0x12, 8}, + {0xd, 5}, + {0x9, 8}, + {0x5, 8}, + {0x5, 9}, + {0xc, 5}, + {0x8, 8}, + {0x4, 8}, + {0x4, 9}, + {0x7, 3}, + {0xa, 5}, + {0x8, 5}, + {0xc, 6} +}; + +const uint8_t ff_mpeg12_mbMotionVectorTable[17][2] = { +{ 0x1, 1 }, +{ 0x1, 2 }, +{ 0x1, 3 }, +{ 0x1, 4 }, +{ 0x3, 6 }, +{ 0x5, 7 }, +{ 0x4, 7 }, +{ 0x3, 7 }, +{ 0xb, 9 }, +{ 0xa, 9 }, +{ 0x9, 9 }, +{ 0x11, 10 }, +{ 0x10, 10 }, +{ 0xf, 10 }, +{ 0xe, 10 }, +{ 0xd, 10 }, +{ 0xc, 10 }, +}; + +const AVRational ff_mpeg2_frame_rate_tab[] = { + { 1, 1}, + { 2, 1}, + { 3, 1}, + { 4, 1}, + { 5, 1}, + { 6, 1}, + { 8, 1}, + { 9, 1}, + { 10, 1}, + { 12, 1}, + { 15, 1}, + { 16, 1}, + { 18, 1}, + { 20, 1}, + { 24, 1}, + { 25, 1}, + { 30, 1}, + { 32, 1}, + { 36, 1}, + { 40, 1}, + { 45, 1}, + { 48, 1}, + { 50, 1}, + { 60, 1}, + { 72, 1}, + { 75, 1}, + { 80, 1}, + { 90, 1}, + { 96, 1}, + { 100, 1}, + { 120, 1}, + { 150, 1}, + { 180, 1}, + { 200, 1}, + { 240, 1}, + { 750, 1001}, + { 800, 1001}, + { 960, 1001}, + { 1000, 1001}, + { 1200, 1001}, + { 1250, 1001}, + { 1500, 1001}, + { 1600, 1001}, + { 1875, 1001}, + { 2000, 1001}, + { 2400, 1001}, + { 2500, 1001}, + { 3000, 1001}, + { 3750, 1001}, + { 4000, 1001}, + { 4800, 1001}, + { 5000, 1001}, + { 6000, 1001}, + { 7500, 1001}, + { 8000, 1001}, + { 10000, 1001}, + { 12000, 1001}, + { 15000, 1001}, + { 20000, 1001}, + { 24000, 1001}, + { 30000, 1001}, + { 60000, 1001}, + { 0, 0}, +}; + +const float ff_mpeg1_aspect[16]={ + 0.0000, + 1.0000, + 0.6735, + 0.7031, + + 0.7615, + 0.8055, + 0.8437, + 0.8935, + + 0.9157, + 0.9815, + 1.0255, + 1.0695, + + 1.0950, + 1.1575, + 1.2015, +}; + +const AVRational ff_mpeg2_aspect[16]={ + {0,1}, + {1,1}, + {4,3}, + {16,9}, + {221,100}, + {0,1}, + {0,1}, + {0,1}, + {0,1}, + {0,1}, + {0,1}, + {0,1}, + {0,1}, + {0,1}, + {0,1}, + {0,1}, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12data.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12data.h new file mode 100644 index 0000000000..f51faf4607 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12data.h @@ -0,0 +1,57 @@ +/* + * MPEG-1/2 tables + * copyright (c) 2000,2001 Fabrice Bellard + * copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * MPEG-1/2 tables. + */ + +#ifndef AVCODEC_MPEG12DATA_H +#define AVCODEC_MPEG12DATA_H + +#include +#include "libavutil/rational.h" +#include "rl.h" + +extern const uint16_t ff_mpeg1_default_intra_matrix[]; +extern const uint16_t ff_mpeg1_default_non_intra_matrix[64]; + +extern const uint16_t ff_mpeg12_vlc_dc_lum_code[12]; +extern const unsigned char ff_mpeg12_vlc_dc_lum_bits[12]; +extern const uint16_t ff_mpeg12_vlc_dc_chroma_code[12]; +extern const unsigned char ff_mpeg12_vlc_dc_chroma_bits[12]; + +extern RLTable ff_rl_mpeg1; +extern RLTable ff_rl_mpeg2; + +extern const uint8_t ff_mpeg12_mbAddrIncrTable[36][2]; +extern const uint8_t ff_mpeg12_mbPatTable[64][2]; + +extern const uint8_t ff_mpeg12_mbMotionVectorTable[17][2]; + +extern const AVRational ff_mpeg12_frame_rate_tab[]; +extern const AVRational ff_mpeg2_frame_rate_tab[]; + +extern const float ff_mpeg1_aspect[16]; +extern const AVRational ff_mpeg2_aspect[16]; + +#endif /* AVCODEC_MPEG12DATA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12framerate.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12framerate.c new file mode 100644 index 0000000000..ab3d351173 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12framerate.c @@ -0,0 +1,103 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/rational.h" + +#include "mpeg12.h" +#include "mpeg12data.h" + +const AVRational ff_mpeg12_frame_rate_tab[16] = { + { 0, 0}, + {24000, 1001}, + { 24, 1}, + { 25, 1}, + {30000, 1001}, + { 30, 1}, + { 50, 1}, + {60000, 1001}, + { 60, 1}, + // Xing's 15fps: (9) + { 15, 1}, + // libmpeg3's "Unofficial economy rates": (10-13) + { 5, 1}, + { 10, 1}, + { 12, 1}, + { 15, 1}, + { 0, 0}, +}; + +void ff_mpeg12_find_best_frame_rate(AVRational frame_rate, + int *code, int *ext_n, int *ext_d, + int nonstandard) +{ + int mpeg2 = ext_n && ext_d; + int max_code = nonstandard ? 12 : 8; + int c, n, d, best_c, best_n, best_d; + AVRational best_error = { INT_MAX, 1 }; + + // Default to NTSC if the inputs make no sense. + best_c = 4; + best_n = best_d = 1; + + for (c = 1; c <= max_code; c++) { + if (av_cmp_q(frame_rate, ff_mpeg12_frame_rate_tab[c]) == 0) { + best_c = c; + goto found; + } + } + + for (c = 1; c <= max_code; c++) { + for (n = 1; n <= (mpeg2 ? 4 : 1); n++) { + for (d = 1; d <= (mpeg2 ? 32 : 1); d++) { + AVRational test, error; + int cmp; + + test = av_mul_q(ff_mpeg12_frame_rate_tab[c], + (AVRational) { n, d }); + + cmp = av_cmp_q(test, frame_rate); + if (cmp == 0) { + best_c = c; + best_n = n; + best_d = d; + goto found; + } + + if (cmp < 0) + error = av_div_q(frame_rate, test); + else + error = av_div_q(test, frame_rate); + + cmp = av_cmp_q(error, best_error); + if (cmp < 0 || (cmp == 0 && n == 1 && d == 1)) { + best_c = c; + best_n = n; + best_d = d; + best_error = error; + } + } + } + } + +found: + *code = best_c; + if (mpeg2) { + *ext_n = best_n - 1; + *ext_d = best_d - 1; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12vlc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12vlc.h new file mode 100644 index 0000000000..c5abae96b6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg12vlc.h @@ -0,0 +1,52 @@ +/* + * MPEG-1/2 VLC + * copyright (c) 2000,2001 Fabrice Bellard + * copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * MPEG-1/2 VLC. + */ + +#ifndef AVCODEC_MPEG12VLC_H +#define AVCODEC_MPEG12VLC_H + +#include "vlc.h" + +#define DC_VLC_BITS 9 +#define MV_VLC_BITS 9 +#define TEX_VLC_BITS 9 + +#define MBINCR_VLC_BITS 9 +#define MB_PAT_VLC_BITS 9 +#define MB_PTYPE_VLC_BITS 6 +#define MB_BTYPE_VLC_BITS 6 + +extern VLC ff_dc_lum_vlc; +extern VLC ff_dc_chroma_vlc; +extern VLC ff_mbincr_vlc; +extern VLC ff_mb_ptype_vlc; +extern VLC ff_mb_btype_vlc; +extern VLC ff_mb_pat_vlc; +extern VLC ff_mv_vlc; + +void ff_mpeg12_init_vlcs(void); + +#endif /* AVCODEC_MPEG12VLC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg4audio.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg4audio.c new file mode 100644 index 0000000000..219714752f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg4audio.c @@ -0,0 +1,169 @@ +/* + * MPEG-4 Audio common code + * Copyright (c) 2008 Baptiste Coudurier + * Copyright (c) 2009 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "get_bits.h" +#include "put_bits.h" +#include "mpeg4audio.h" + +/** + * Parse MPEG-4 audio configuration for ALS object type. + * @param[in] gb bit reader context + * @param[in] c MPEG4AudioConfig structure to fill + * @return on success 0 is returned, otherwise a value < 0 + */ +static int parse_config_ALS(GetBitContext *gb, MPEG4AudioConfig *c) +{ + if (get_bits_left(gb) < 112) + return AVERROR_INVALIDDATA; + + if (get_bits_long(gb, 32) != MKBETAG('A','L','S','\0')) + return AVERROR_INVALIDDATA; + + // override AudioSpecificConfig channel configuration and sample rate + // which are buggy in old ALS conformance files + c->sample_rate = get_bits_long(gb, 32); + + if (c->sample_rate <= 0) { + av_log(NULL, AV_LOG_ERROR, "Invalid sample rate %d\n", c->sample_rate); + return AVERROR_INVALIDDATA; + } + + // skip number of samples + skip_bits_long(gb, 32); + + // read number of channels + c->chan_config = 0; + c->channels = get_bits(gb, 16) + 1; + + return 0; +} + +/* XXX: make sure to update the copies in the different encoders if you change + * this table */ +const int avpriv_mpeg4audio_sample_rates[16] = { + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000, 7350 +}; + +const uint8_t ff_mpeg4audio_channels[8] = { + 0, 1, 2, 3, 4, 5, 6, 8 +}; + +static inline int get_object_type(GetBitContext *gb) +{ + int object_type = get_bits(gb, 5); + if (object_type == AOT_ESCAPE) + object_type = 32 + get_bits(gb, 6); + return object_type; +} + +static inline int get_sample_rate(GetBitContext *gb, int *index) +{ + *index = get_bits(gb, 4); + return *index == 0x0f ? get_bits(gb, 24) : + avpriv_mpeg4audio_sample_rates[*index]; +} + +int ff_mpeg4audio_get_config_gb(MPEG4AudioConfig *c, GetBitContext *gb, + int sync_extension) +{ + int specific_config_bitindex, ret; + int start_bit_index = get_bits_count(gb); + c->object_type = get_object_type(gb); + c->sample_rate = get_sample_rate(gb, &c->sampling_index); + c->chan_config = get_bits(gb, 4); + if (c->chan_config < FF_ARRAY_ELEMS(ff_mpeg4audio_channels)) + c->channels = ff_mpeg4audio_channels[c->chan_config]; + c->sbr = -1; + c->ps = -1; + if (c->object_type == AOT_SBR || (c->object_type == AOT_PS && + // check for W6132 Annex YYYY draft MP3onMP4 + !(show_bits(gb, 3) & 0x03 && !(show_bits(gb, 9) & 0x3F)))) { + if (c->object_type == AOT_PS) + c->ps = 1; + c->ext_object_type = AOT_SBR; + c->sbr = 1; + c->ext_sample_rate = get_sample_rate(gb, &c->ext_sampling_index); + c->object_type = get_object_type(gb); + if (c->object_type == AOT_ER_BSAC) + c->ext_chan_config = get_bits(gb, 4); + } else { + c->ext_object_type = AOT_NULL; + c->ext_sample_rate = 0; + } + specific_config_bitindex = get_bits_count(gb); + + if (c->object_type == AOT_ALS) { + skip_bits(gb, 5); + if (show_bits_long(gb, 24) != MKBETAG('\0','A','L','S')) + skip_bits_long(gb, 24); + + specific_config_bitindex = get_bits_count(gb); + + ret = parse_config_ALS(gb, c); + if (ret < 0) + return ret; + } + + if (c->ext_object_type != AOT_SBR && sync_extension) { + while (get_bits_left(gb) > 15) { + if (show_bits(gb, 11) == 0x2b7) { // sync extension + get_bits(gb, 11); + c->ext_object_type = get_object_type(gb); + if (c->ext_object_type == AOT_SBR && (c->sbr = get_bits1(gb)) == 1) { + c->ext_sample_rate = get_sample_rate(gb, &c->ext_sampling_index); + if (c->ext_sample_rate == c->sample_rate) + c->sbr = -1; + } + if (get_bits_left(gb) > 11 && get_bits(gb, 11) == 0x548) + c->ps = get_bits1(gb); + break; + } else + get_bits1(gb); // skip 1 bit + } + } + + //PS requires SBR + if (!c->sbr) + c->ps = 0; + //Limit implicit PS to the HE-AACv2 Profile + if ((c->ps == -1 && c->object_type != AOT_AAC_LC) || c->channels & ~0x01) + c->ps = 0; + + return specific_config_bitindex - start_bit_index; +} + +int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf, + int bit_size, int sync_extension) +{ + GetBitContext gb; + int ret; + + if (bit_size <= 0) + return AVERROR_INVALIDDATA; + + ret = init_get_bits(&gb, buf, bit_size); + if (ret < 0) + return ret; + + return ff_mpeg4audio_get_config_gb(c, &gb, sync_extension); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg4audio.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg4audio.h new file mode 100644 index 0000000000..b9cea8af17 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpeg4audio.h @@ -0,0 +1,162 @@ +/* + * MPEG-4 Audio common header + * Copyright (c) 2008 Baptiste Coudurier + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MPEG4AUDIO_H +#define AVCODEC_MPEG4AUDIO_H + +#include + +#include "libavutil/attributes.h" + +#include "get_bits.h" +#include "internal.h" +#include "put_bits.h" + +typedef struct MPEG4AudioConfig { + int object_type; + int sampling_index; + int sample_rate; + int chan_config; + int sbr; ///< -1 implicit, 1 presence + int ext_object_type; + int ext_sampling_index; + int ext_sample_rate; + int ext_chan_config; + int channels; + int ps; ///< -1 implicit, 1 presence + int frame_length_short; +} MPEG4AudioConfig; + +extern av_export_avcodec const int avpriv_mpeg4audio_sample_rates[16]; +extern const uint8_t ff_mpeg4audio_channels[8]; + +/** + * Parse MPEG-4 systems extradata from a potentially unaligned GetBitContext to retrieve audio configuration. + * @param[in] c MPEG4AudioConfig structure to fill. + * @param[in] gb Extradata from container. + * @param[in] sync_extension look for a sync extension after config if true. + * @return On error -1 is returned, on success AudioSpecificConfig bit index in extradata. + */ +int ff_mpeg4audio_get_config_gb(MPEG4AudioConfig *c, GetBitContext *gb, + int sync_extension); + +/** + * Parse MPEG-4 systems extradata from a raw buffer to retrieve audio configuration. + * @param[in] c MPEG4AudioConfig structure to fill. + * @param[in] buf Extradata from container. + * @param[in] bit_size Extradata size in bits. + * @param[in] sync_extension look for a sync extension after config if true. + * @return On error -1 is returned, on success AudioSpecificConfig bit index in extradata. + */ +int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf, + int bit_size, int sync_extension); + +enum AudioObjectType { + AOT_NULL, + // Support? Name + AOT_AAC_MAIN, ///< Y Main + AOT_AAC_LC, ///< Y Low Complexity + AOT_AAC_SSR, ///< N (code in SoC repo) Scalable Sample Rate + AOT_AAC_LTP, ///< Y Long Term Prediction + AOT_SBR, ///< Y Spectral Band Replication + AOT_AAC_SCALABLE, ///< N Scalable + AOT_TWINVQ, ///< N Twin Vector Quantizer + AOT_CELP, ///< N Code Excited Linear Prediction + AOT_HVXC, ///< N Harmonic Vector eXcitation Coding + AOT_TTSI = 12, ///< N Text-To-Speech Interface + AOT_MAINSYNTH, ///< N Main Synthesis + AOT_WAVESYNTH, ///< N Wavetable Synthesis + AOT_MIDI, ///< N General MIDI + AOT_SAFX, ///< N Algorithmic Synthesis and Audio Effects + AOT_ER_AAC_LC, ///< N Error Resilient Low Complexity + AOT_ER_AAC_LTP = 19, ///< N Error Resilient Long Term Prediction + AOT_ER_AAC_SCALABLE, ///< N Error Resilient Scalable + AOT_ER_TWINVQ, ///< N Error Resilient Twin Vector Quantizer + AOT_ER_BSAC, ///< N Error Resilient Bit-Sliced Arithmetic Coding + AOT_ER_AAC_LD, ///< N Error Resilient Low Delay + AOT_ER_CELP, ///< N Error Resilient Code Excited Linear Prediction + AOT_ER_HVXC, ///< N Error Resilient Harmonic Vector eXcitation Coding + AOT_ER_HILN, ///< N Error Resilient Harmonic and Individual Lines plus Noise + AOT_ER_PARAM, ///< N Error Resilient Parametric + AOT_SSC, ///< N SinuSoidal Coding + AOT_PS, ///< N Parametric Stereo + AOT_SURROUND, ///< N MPEG Surround + AOT_ESCAPE, ///< Y Escape Value + AOT_L1, ///< Y Layer 1 + AOT_L2, ///< Y Layer 2 + AOT_L3, ///< Y Layer 3 + AOT_DST, ///< N Direct Stream Transfer + AOT_ALS, ///< Y Audio LosslesS + AOT_SLS, ///< N Scalable LosslesS + AOT_SLS_NON_CORE, ///< N Scalable LosslesS (non core) + AOT_ER_AAC_ELD, ///< N Error Resilient Enhanced Low Delay + AOT_SMR_SIMPLE, ///< N Symbolic Music Representation Simple + AOT_SMR_MAIN, ///< N Symbolic Music Representation Main + AOT_USAC_NOSBR, ///< N Unified Speech and Audio Coding (no SBR) + AOT_SAOC, ///< N Spatial Audio Object Coding + AOT_LD_SURROUND, ///< N Low Delay MPEG Surround + AOT_USAC, ///< N Unified Speech and Audio Coding +}; + +#define MAX_PCE_SIZE 320 /// 16; bits -= 16) + ff_pce_copy_bits(pb, gb, 16); + if (bits) + ff_pce_copy_bits(pb, gb, bits); + avpriv_align_put_bits(pb); + align_get_bits(gb); + comment_size = ff_pce_copy_bits(pb, gb, 8); + for (; comment_size > 0; comment_size--) + ff_pce_copy_bits(pb, gb, 8); + + return put_bits_count(pb) - offset; +} + +#endif /* AVCODEC_MPEG4AUDIO_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegpicture.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegpicture.c new file mode 100644 index 0000000000..ecbd77d50e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegpicture.c @@ -0,0 +1,483 @@ +/* + * Mpeg video formats-related picture management functions + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/pixdesc.h" +#include "libavutil/imgutils.h" + +#include "avcodec.h" +#include "motion_est.h" +#include "mpegpicture.h" +#include "mpegutils.h" + +static int make_tables_writable(Picture *pic) +{ + int ret, i; +#define MAKE_WRITABLE(table) \ +do {\ + if (pic->table &&\ + (ret = av_buffer_make_writable(&pic->table)) < 0)\ + return ret;\ +} while (0) + + MAKE_WRITABLE(mb_var_buf); + MAKE_WRITABLE(mc_mb_var_buf); + MAKE_WRITABLE(mb_mean_buf); + MAKE_WRITABLE(mbskip_table_buf); + MAKE_WRITABLE(qscale_table_buf); + MAKE_WRITABLE(mb_type_buf); + + for (i = 0; i < 2; i++) { + MAKE_WRITABLE(motion_val_buf[i]); + MAKE_WRITABLE(ref_index_buf[i]); + } + + return 0; +} + +int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me, + ScratchpadContext *sc, int linesize) +{ +# define EMU_EDGE_HEIGHT (4 * 70) + int alloc_size = FFALIGN(FFABS(linesize) + 64, 32); + + if (avctx->hwaccel) + return 0; + + if (linesize < 24) { + av_log(avctx, AV_LOG_ERROR, "Image too small, temporary buffers cannot function\n"); + return AVERROR_PATCHWELCOME; + } + + if (av_image_check_size2(alloc_size, EMU_EDGE_HEIGHT, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0) + return AVERROR(ENOMEM); + + // edge emu needs blocksize + filter length - 1 + // (= 17x17 for halfpel / 21x21 for H.264) + // VC-1 computes luma and chroma simultaneously and needs 19X19 + 9x9 + // at uvlinesize. It supports only YUV420 so 24x24 is enough + // linesize * interlaced * MBsize + // we also use this buffer for encoding in encode_mb_internal() needig an additional 32 lines + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, sc->edge_emu_buffer, alloc_size, EMU_EDGE_HEIGHT, + fail); + + FF_ALLOCZ_ARRAY_OR_GOTO(avctx, me->scratchpad, alloc_size, 4 * 16 * 2, + fail) + me->temp = me->scratchpad; + sc->rd_scratchpad = me->scratchpad; + sc->b_scratchpad = me->scratchpad; + sc->obmc_scratchpad = me->scratchpad + 16; + + return 0; +fail: + av_freep(&sc->edge_emu_buffer); + return AVERROR(ENOMEM); +} + +/** + * Allocate a frame buffer + */ +static int alloc_frame_buffer(AVCodecContext *avctx, Picture *pic, + MotionEstContext *me, ScratchpadContext *sc, + int chroma_x_shift, int chroma_y_shift, + int linesize, int uvlinesize) +{ + int edges_needed = av_codec_is_encoder(avctx->codec); + int r, ret; + + pic->tf.f = pic->f; + if (avctx->codec_id != AV_CODEC_ID_WMV3IMAGE && + avctx->codec_id != AV_CODEC_ID_VC1IMAGE && + avctx->codec_id != AV_CODEC_ID_MSS2) { + if (edges_needed) { + pic->f->width = avctx->width + 2 * EDGE_WIDTH; + pic->f->height = avctx->height + 2 * EDGE_WIDTH; + } + + r = ff_thread_get_buffer(avctx, &pic->tf, + pic->reference ? AV_GET_BUFFER_FLAG_REF : 0); + } else { + pic->f->width = avctx->width; + pic->f->height = avctx->height; + pic->f->format = avctx->pix_fmt; + r = avcodec_default_get_buffer2(avctx, pic->f, 0); + } + + if (r < 0 || !pic->f->buf[0]) { + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed (%d %p)\n", + r, pic->f->data[0]); + return -1; + } + + if (edges_needed) { + int i; + for (i = 0; pic->f->data[i]; i++) { + int offset = (EDGE_WIDTH >> (i ? chroma_y_shift : 0)) * + pic->f->linesize[i] + + (EDGE_WIDTH >> (i ? chroma_x_shift : 0)); + pic->f->data[i] += offset; + } + pic->f->width = avctx->width; + pic->f->height = avctx->height; + } + + if (avctx->hwaccel) { + assert(!pic->hwaccel_picture_private); + if (avctx->hwaccel->frame_priv_data_size) { + pic->hwaccel_priv_buf = av_buffer_allocz(avctx->hwaccel->frame_priv_data_size); + if (!pic->hwaccel_priv_buf) { + av_log(avctx, AV_LOG_ERROR, "alloc_frame_buffer() failed (hwaccel private data allocation)\n"); + return -1; + } + pic->hwaccel_picture_private = pic->hwaccel_priv_buf->data; + } + } + + if ((linesize && linesize != pic->f->linesize[0]) || + (uvlinesize && uvlinesize != pic->f->linesize[1])) { + av_log(avctx, AV_LOG_ERROR, + "get_buffer() failed (stride changed: linesize=%d/%d uvlinesize=%d/%d)\n", + linesize, pic->f->linesize[0], + uvlinesize, pic->f->linesize[1]); + ff_mpeg_unref_picture(avctx, pic); + return -1; + } + + if (av_pix_fmt_count_planes(pic->f->format) > 2 && + pic->f->linesize[1] != pic->f->linesize[2]) { + av_log(avctx, AV_LOG_ERROR, + "get_buffer() failed (uv stride mismatch)\n"); + ff_mpeg_unref_picture(avctx, pic); + return -1; + } + + if (!sc->edge_emu_buffer && + (ret = ff_mpeg_framesize_alloc(avctx, me, sc, + pic->f->linesize[0])) < 0) { + av_log(avctx, AV_LOG_ERROR, + "get_buffer() failed to allocate context scratch buffers.\n"); + ff_mpeg_unref_picture(avctx, pic); + return ret; + } + + return 0; +} + +static int alloc_picture_tables(AVCodecContext *avctx, Picture *pic, int encoding, int out_format, + int mb_stride, int mb_width, int mb_height, int b8_stride) +{ + const int big_mb_num = mb_stride * (mb_height + 1) + 1; + const int mb_array_size = mb_stride * mb_height; + const int b8_array_size = b8_stride * mb_height * 2; + int i; + + + pic->mbskip_table_buf = av_buffer_allocz(mb_array_size + 2); + pic->qscale_table_buf = av_buffer_allocz(big_mb_num + mb_stride); + pic->mb_type_buf = av_buffer_allocz((big_mb_num + mb_stride) * + sizeof(uint32_t)); + if (!pic->mbskip_table_buf || !pic->qscale_table_buf || !pic->mb_type_buf) + return AVERROR(ENOMEM); + + if (encoding) { + pic->mb_var_buf = av_buffer_allocz(mb_array_size * sizeof(int16_t)); + pic->mc_mb_var_buf = av_buffer_allocz(mb_array_size * sizeof(int16_t)); + pic->mb_mean_buf = av_buffer_allocz(mb_array_size); + if (!pic->mb_var_buf || !pic->mc_mb_var_buf || !pic->mb_mean_buf) + return AVERROR(ENOMEM); + } + + if (out_format == FMT_H263 || encoding || +#if FF_API_DEBUG_MV + avctx->debug_mv || +#endif + (avctx->flags2 & AV_CODEC_FLAG2_EXPORT_MVS)) { + int mv_size = 2 * (b8_array_size + 4) * sizeof(int16_t); + int ref_index_size = 4 * mb_array_size; + + for (i = 0; mv_size && i < 2; i++) { + pic->motion_val_buf[i] = av_buffer_allocz(mv_size); + pic->ref_index_buf[i] = av_buffer_allocz(ref_index_size); + if (!pic->motion_val_buf[i] || !pic->ref_index_buf[i]) + return AVERROR(ENOMEM); + } + } + + pic->alloc_mb_width = mb_width; + pic->alloc_mb_height = mb_height; + + return 0; +} + +/** + * Allocate a Picture. + * The pixels are allocated/set by calling get_buffer() if shared = 0 + */ +int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me, + ScratchpadContext *sc, int shared, int encoding, + int chroma_x_shift, int chroma_y_shift, int out_format, + int mb_stride, int mb_width, int mb_height, int b8_stride, + ptrdiff_t *linesize, ptrdiff_t *uvlinesize) +{ + int i, ret; + + if (pic->qscale_table_buf) + if ( pic->alloc_mb_width != mb_width + || pic->alloc_mb_height != mb_height) + ff_free_picture_tables(pic); + + if (shared) { + av_assert0(pic->f->data[0]); + pic->shared = 1; + } else { + av_assert0(!pic->f->buf[0]); + if (alloc_frame_buffer(avctx, pic, me, sc, + chroma_x_shift, chroma_y_shift, + *linesize, *uvlinesize) < 0) + return -1; + + *linesize = pic->f->linesize[0]; + *uvlinesize = pic->f->linesize[1]; + } + + if (!pic->qscale_table_buf) + ret = alloc_picture_tables(avctx, pic, encoding, out_format, + mb_stride, mb_width, mb_height, b8_stride); + else + ret = make_tables_writable(pic); + if (ret < 0) + goto fail; + + if (encoding) { + pic->mb_var = (uint16_t*)pic->mb_var_buf->data; + pic->mc_mb_var = (uint16_t*)pic->mc_mb_var_buf->data; + pic->mb_mean = pic->mb_mean_buf->data; + } + + pic->mbskip_table = pic->mbskip_table_buf->data; + pic->qscale_table = pic->qscale_table_buf->data + 2 * mb_stride + 1; + pic->mb_type = (uint32_t*)pic->mb_type_buf->data + 2 * mb_stride + 1; + + if (pic->motion_val_buf[0]) { + for (i = 0; i < 2; i++) { + pic->motion_val[i] = (int16_t (*)[2])pic->motion_val_buf[i]->data + 4; + pic->ref_index[i] = pic->ref_index_buf[i]->data; + } + } + + return 0; +fail: + av_log(avctx, AV_LOG_ERROR, "Error allocating a picture.\n"); + ff_mpeg_unref_picture(avctx, pic); + ff_free_picture_tables(pic); + return AVERROR(ENOMEM); +} + +/** + * Deallocate a picture. + */ +void ff_mpeg_unref_picture(AVCodecContext *avctx, Picture *pic) +{ + int off = offsetof(Picture, mb_mean) + sizeof(pic->mb_mean); + + pic->tf.f = pic->f; + /* WM Image / Screen codecs allocate internal buffers with different + * dimensions / colorspaces; ignore user-defined callbacks for these. */ + if (avctx->codec_id != AV_CODEC_ID_WMV3IMAGE && + avctx->codec_id != AV_CODEC_ID_VC1IMAGE && + avctx->codec_id != AV_CODEC_ID_MSS2) + ff_thread_release_buffer(avctx, &pic->tf); + else if (pic->f) + av_frame_unref(pic->f); + + av_buffer_unref(&pic->hwaccel_priv_buf); + + if (pic->needs_realloc) + ff_free_picture_tables(pic); + + memset((uint8_t*)pic + off, 0, sizeof(*pic) - off); +} + +int ff_update_picture_tables(Picture *dst, Picture *src) +{ + int i; + +#define UPDATE_TABLE(table) \ +do { \ + if (src->table && \ + (!dst->table || dst->table->buffer != src->table->buffer)) { \ + av_buffer_unref(&dst->table); \ + dst->table = av_buffer_ref(src->table); \ + if (!dst->table) { \ + ff_free_picture_tables(dst); \ + return AVERROR(ENOMEM); \ + } \ + } \ +} while (0) + + UPDATE_TABLE(mb_var_buf); + UPDATE_TABLE(mc_mb_var_buf); + UPDATE_TABLE(mb_mean_buf); + UPDATE_TABLE(mbskip_table_buf); + UPDATE_TABLE(qscale_table_buf); + UPDATE_TABLE(mb_type_buf); + for (i = 0; i < 2; i++) { + UPDATE_TABLE(motion_val_buf[i]); + UPDATE_TABLE(ref_index_buf[i]); + } + + dst->mb_var = src->mb_var; + dst->mc_mb_var = src->mc_mb_var; + dst->mb_mean = src->mb_mean; + dst->mbskip_table = src->mbskip_table; + dst->qscale_table = src->qscale_table; + dst->mb_type = src->mb_type; + for (i = 0; i < 2; i++) { + dst->motion_val[i] = src->motion_val[i]; + dst->ref_index[i] = src->ref_index[i]; + } + + dst->alloc_mb_width = src->alloc_mb_width; + dst->alloc_mb_height = src->alloc_mb_height; + + return 0; +} + +int ff_mpeg_ref_picture(AVCodecContext *avctx, Picture *dst, Picture *src) +{ + int ret; + + av_assert0(!dst->f->buf[0]); + av_assert0(src->f->buf[0]); + + src->tf.f = src->f; + dst->tf.f = dst->f; + ret = ff_thread_ref_frame(&dst->tf, &src->tf); + if (ret < 0) + goto fail; + + ret = ff_update_picture_tables(dst, src); + if (ret < 0) + goto fail; + + if (src->hwaccel_picture_private) { + dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf); + if (!dst->hwaccel_priv_buf) { + ret = AVERROR(ENOMEM); + goto fail; + } + dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data; + } + + dst->field_picture = src->field_picture; + dst->mb_var_sum = src->mb_var_sum; + dst->mc_mb_var_sum = src->mc_mb_var_sum; + dst->b_frame_score = src->b_frame_score; + dst->needs_realloc = src->needs_realloc; + dst->reference = src->reference; + dst->shared = src->shared; + + memcpy(dst->encoding_error, src->encoding_error, + sizeof(dst->encoding_error)); + + return 0; +fail: + ff_mpeg_unref_picture(avctx, dst); + return ret; +} + +static inline int pic_is_unused(Picture *pic) +{ + if (!pic->f->buf[0]) + return 1; + if (pic->needs_realloc && !(pic->reference & DELAYED_PIC_REF)) + return 1; + return 0; +} + +static int find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared) +{ + int i; + + if (shared) { + for (i = 0; i < MAX_PICTURE_COUNT; i++) { + if (!picture[i].f->buf[0]) + return i; + } + } else { + for (i = 0; i < MAX_PICTURE_COUNT; i++) { + if (pic_is_unused(&picture[i])) + return i; + } + } + + av_log(avctx, AV_LOG_FATAL, + "Internal error, picture buffer overflow\n"); + /* We could return -1, but the codec would crash trying to draw into a + * non-existing frame anyway. This is safer than waiting for a random crash. + * Also the return of this is never useful, an encoder must only allocate + * as much as allowed in the specification. This has no relationship to how + * much libavcodec could allocate (and MAX_PICTURE_COUNT is always large + * enough for such valid streams). + * Plus, a decoder has to check stream validity and remove frames if too + * many reference frames are around. Waiting for "OOM" is not correct at + * all. Similarly, missing reference frames have to be replaced by + * interpolated/MC frames, anything else is a bug in the codec ... + */ + abort(); + return -1; +} + +int ff_find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared) +{ + int ret = find_unused_picture(avctx, picture, shared); + + if (ret >= 0 && ret < MAX_PICTURE_COUNT) { + if (picture[ret].needs_realloc) { + picture[ret].needs_realloc = 0; + ff_free_picture_tables(&picture[ret]); + ff_mpeg_unref_picture(avctx, &picture[ret]); + } + } + return ret; +} + +void ff_free_picture_tables(Picture *pic) +{ + int i; + + pic->alloc_mb_width = + pic->alloc_mb_height = 0; + + av_buffer_unref(&pic->mb_var_buf); + av_buffer_unref(&pic->mc_mb_var_buf); + av_buffer_unref(&pic->mb_mean_buf); + av_buffer_unref(&pic->mbskip_table_buf); + av_buffer_unref(&pic->qscale_table_buf); + av_buffer_unref(&pic->mb_type_buf); + + for (i = 0; i < 2; i++) { + av_buffer_unref(&pic->motion_val_buf[i]); + av_buffer_unref(&pic->ref_index_buf[i]); + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegpicture.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegpicture.h new file mode 100644 index 0000000000..2db3d6733a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegpicture.h @@ -0,0 +1,114 @@ +/* + * Mpeg video formats-related defines and utility functions + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MPEGPICTURE_H +#define AVCODEC_MPEGPICTURE_H + +#include + +#include "libavutil/frame.h" + +#include "avcodec.h" +#include "motion_est.h" +#include "thread.h" + +#define MAX_PICTURE_COUNT 36 +#define EDGE_WIDTH 16 + +typedef struct ScratchpadContext { + uint8_t *edge_emu_buffer; ///< temporary buffer for if MVs point to out-of-frame data + uint8_t *rd_scratchpad; ///< scratchpad for rate distortion mb decision + uint8_t *obmc_scratchpad; + uint8_t *b_scratchpad; ///< scratchpad used for writing into write only buffers +} ScratchpadContext; + +/** + * Picture. + */ +typedef struct Picture { + struct AVFrame *f; + ThreadFrame tf; + + AVBufferRef *qscale_table_buf; + int8_t *qscale_table; + + AVBufferRef *motion_val_buf[2]; + int16_t (*motion_val[2])[2]; + + AVBufferRef *mb_type_buf; + uint32_t *mb_type; ///< types and macros are defined in mpegutils.h + + AVBufferRef *mbskip_table_buf; + uint8_t *mbskip_table; + + AVBufferRef *ref_index_buf[2]; + int8_t *ref_index[2]; + + AVBufferRef *mb_var_buf; + uint16_t *mb_var; ///< Table for MB variances + + AVBufferRef *mc_mb_var_buf; + uint16_t *mc_mb_var; ///< Table for motion compensated MB variances + + int alloc_mb_width; ///< mb_width used to allocate tables + int alloc_mb_height; ///< mb_height used to allocate tables + + AVBufferRef *mb_mean_buf; + uint8_t *mb_mean; ///< Table for MB luminance + + AVBufferRef *hwaccel_priv_buf; + void *hwaccel_picture_private; ///< Hardware accelerator private data + + int field_picture; ///< whether or not the picture was encoded in separate fields + + int64_t mb_var_sum; ///< sum of MB variance for current frame + int64_t mc_mb_var_sum; ///< motion compensated MB variance for current frame + + int b_frame_score; + int needs_realloc; ///< Picture needs to be reallocated (eg due to a frame size change) + + int reference; + int shared; + + uint64_t encoding_error[AV_NUM_DATA_POINTERS]; +} Picture; + +/** + * Allocate a Picture. + * The pixels are allocated/set by calling get_buffer() if shared = 0. + */ +int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me, + ScratchpadContext *sc, int shared, int encoding, + int chroma_x_shift, int chroma_y_shift, int out_format, + int mb_stride, int mb_width, int mb_height, int b8_stride, + ptrdiff_t *linesize, ptrdiff_t *uvlinesize); + +int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me, + ScratchpadContext *sc, int linesize); + +int ff_mpeg_ref_picture(AVCodecContext *avctx, Picture *dst, Picture *src); +void ff_mpeg_unref_picture(AVCodecContext *avctx, Picture *picture); + +void ff_free_picture_tables(Picture *pic); +int ff_update_picture_tables(Picture *dst, Picture *src); + +int ff_find_unused_picture(AVCodecContext *avctx, Picture *picture, int shared); + +#endif /* AVCODEC_MPEGPICTURE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegutils.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegutils.c new file mode 100644 index 0000000000..3f94540616 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegutils.c @@ -0,0 +1,393 @@ +/* + * Mpeg video formats-related defines and utility functions + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/frame.h" +#include "libavutil/pixdesc.h" +#include "libavutil/motion_vector.h" +#include "libavutil/avassert.h" + +#include "avcodec.h" +#include "mpegutils.h" + +static int add_mb(AVMotionVector *mb, uint32_t mb_type, + int dst_x, int dst_y, + int motion_x, int motion_y, int motion_scale, + int direction) +{ + mb->w = IS_8X8(mb_type) || IS_8X16(mb_type) ? 8 : 16; + mb->h = IS_8X8(mb_type) || IS_16X8(mb_type) ? 8 : 16; + mb->motion_x = motion_x; + mb->motion_y = motion_y; + mb->motion_scale = motion_scale; + mb->dst_x = dst_x; + mb->dst_y = dst_y; + mb->src_x = dst_x + motion_x / motion_scale; + mb->src_y = dst_y + motion_y / motion_scale; + mb->source = direction ? 1 : -1; + mb->flags = 0; // XXX: does mb_type contain extra information that could be exported here? + return 1; +} + +void ff_draw_horiz_band(AVCodecContext *avctx, + AVFrame *cur, AVFrame *last, + int y, int h, int picture_structure, + int first_field, int low_delay) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); + int vshift = desc->log2_chroma_h; + const int field_pic = picture_structure != PICT_FRAME; + if (field_pic) { + h <<= 1; + y <<= 1; + } + + h = FFMIN(h, avctx->height - y); + + if (field_pic && first_field && + !(avctx->slice_flags & SLICE_FLAG_ALLOW_FIELD)) + return; + + if (avctx->draw_horiz_band) { + AVFrame *src; + int offset[AV_NUM_DATA_POINTERS]; + int i; + + if (cur->pict_type == AV_PICTURE_TYPE_B || low_delay || + (avctx->slice_flags & SLICE_FLAG_CODED_ORDER)) + src = cur; + else if (last) + src = last; + else + return; + + if (cur->pict_type == AV_PICTURE_TYPE_B && + picture_structure == PICT_FRAME && + avctx->codec_id != AV_CODEC_ID_SVQ3) { + for (i = 0; i < AV_NUM_DATA_POINTERS; i++) + offset[i] = 0; + } else { + offset[0]= y * src->linesize[0]; + offset[1]= + offset[2]= (y >> vshift) * src->linesize[1]; + for (i = 3; i < AV_NUM_DATA_POINTERS; i++) + offset[i] = 0; + } + + emms_c(); + + avctx->draw_horiz_band(avctx, src, offset, + y, picture_structure, h); + } +} + +void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_table, + uint32_t *mbtype_table, int8_t *qscale_table, int16_t (*motion_val[2])[2], + int *low_delay, + int mb_width, int mb_height, int mb_stride, int quarter_sample) +{ + if ((avctx->flags2 & AV_CODEC_FLAG2_EXPORT_MVS) && mbtype_table && motion_val[0]) { + const int shift = 1 + quarter_sample; + const int scale = 1 << shift; + const int mv_sample_log2 = avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_SVQ3 ? 2 : 1; + const int mv_stride = (mb_width << mv_sample_log2) + + (avctx->codec->id == AV_CODEC_ID_H264 ? 0 : 1); + int mb_x, mb_y, mbcount = 0; + + /* size is width * height * 2 * 4 where 2 is for directions and 4 is + * for the maximum number of MB (4 MB in case of IS_8x8) */ + AVMotionVector *mvs = av_malloc_array(mb_width * mb_height, 2 * 4 * sizeof(AVMotionVector)); + if (!mvs) + return; + + for (mb_y = 0; mb_y < mb_height; mb_y++) { + for (mb_x = 0; mb_x < mb_width; mb_x++) { + int i, direction, mb_type = mbtype_table[mb_x + mb_y * mb_stride]; + for (direction = 0; direction < 2; direction++) { + if (!USES_LIST(mb_type, direction)) + continue; + if (IS_8X8(mb_type)) { + for (i = 0; i < 4; i++) { + int sx = mb_x * 16 + 4 + 8 * (i & 1); + int sy = mb_y * 16 + 4 + 8 * (i >> 1); + int xy = (mb_x * 2 + (i & 1) + + (mb_y * 2 + (i >> 1)) * mv_stride) << (mv_sample_log2 - 1); + int mx = motion_val[direction][xy][0]; + int my = motion_val[direction][xy][1]; + mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); + } + } else if (IS_16X8(mb_type)) { + for (i = 0; i < 2; i++) { + int sx = mb_x * 16 + 8; + int sy = mb_y * 16 + 4 + 8 * i; + int xy = (mb_x * 2 + (mb_y * 2 + i) * mv_stride) << (mv_sample_log2 - 1); + int mx = motion_val[direction][xy][0]; + int my = motion_val[direction][xy][1]; + + if (IS_INTERLACED(mb_type)) + my *= 2; + + mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); + } + } else if (IS_8X16(mb_type)) { + for (i = 0; i < 2; i++) { + int sx = mb_x * 16 + 4 + 8 * i; + int sy = mb_y * 16 + 8; + int xy = (mb_x * 2 + i + mb_y * 2 * mv_stride) << (mv_sample_log2 - 1); + int mx = motion_val[direction][xy][0]; + int my = motion_val[direction][xy][1]; + + if (IS_INTERLACED(mb_type)) + my *= 2; + + mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); + } + } else { + int sx = mb_x * 16 + 8; + int sy = mb_y * 16 + 8; + int xy = (mb_x + mb_y * mv_stride) << mv_sample_log2; + int mx = motion_val[direction][xy][0]; + int my = motion_val[direction][xy][1]; + mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); + } + } + } + } + + if (mbcount) { + AVFrameSideData *sd; + + av_log(avctx, AV_LOG_DEBUG, "Adding %d MVs info to frame %d\n", mbcount, avctx->frame_number); + sd = av_frame_new_side_data(pict, AV_FRAME_DATA_MOTION_VECTORS, mbcount * sizeof(AVMotionVector)); + if (!sd) { + av_freep(&mvs); + return; + } + memcpy(sd->data, mvs, mbcount * sizeof(AVMotionVector)); + } + + av_freep(&mvs); + } + + /* TODO: export all the following to make them accessible for users (and filters) */ + if (avctx->hwaccel || !mbtype_table) + return; + + + if (avctx->debug & (FF_DEBUG_SKIP | FF_DEBUG_QP | FF_DEBUG_MB_TYPE)) { + int x,y; + + av_log(avctx, AV_LOG_DEBUG, "New frame, type: %c\n", + av_get_picture_type_char(pict->pict_type)); + for (y = 0; y < mb_height; y++) { + for (x = 0; x < mb_width; x++) { + if (avctx->debug & FF_DEBUG_SKIP) { + int count = mbskip_table ? mbskip_table[x + y * mb_stride] : 0; + if (count > 9) + count = 9; + av_log(avctx, AV_LOG_DEBUG, "%1d", count); + } + if (avctx->debug & FF_DEBUG_QP) { + av_log(avctx, AV_LOG_DEBUG, "%2d", + qscale_table[x + y * mb_stride]); + } + if (avctx->debug & FF_DEBUG_MB_TYPE) { + int mb_type = mbtype_table[x + y * mb_stride]; + // Type & MV direction + if (IS_PCM(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "P"); + else if (IS_INTRA(mb_type) && IS_ACPRED(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "A"); + else if (IS_INTRA4x4(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "i"); + else if (IS_INTRA16x16(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "I"); + else if (IS_DIRECT(mb_type) && IS_SKIP(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "d"); + else if (IS_DIRECT(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "D"); + else if (IS_GMC(mb_type) && IS_SKIP(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "g"); + else if (IS_GMC(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "G"); + else if (IS_SKIP(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "S"); + else if (!USES_LIST(mb_type, 1)) + av_log(avctx, AV_LOG_DEBUG, ">"); + else if (!USES_LIST(mb_type, 0)) + av_log(avctx, AV_LOG_DEBUG, "<"); + else { + av_assert2(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1)); + av_log(avctx, AV_LOG_DEBUG, "X"); + } + + // segmentation + if (IS_8X8(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "+"); + else if (IS_16X8(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "-"); + else if (IS_8X16(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "|"); + else if (IS_INTRA(mb_type) || IS_16X16(mb_type)) + av_log(avctx, AV_LOG_DEBUG, " "); + else + av_log(avctx, AV_LOG_DEBUG, "?"); + + + if (IS_INTERLACED(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "="); + else + av_log(avctx, AV_LOG_DEBUG, " "); + } + } + av_log(avctx, AV_LOG_DEBUG, "\n"); + } + } + +#if FF_API_DEBUG_MV + if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || + (avctx->debug_mv)) { + int mb_y; + int i, ret; + int h_chroma_shift, v_chroma_shift, block_height; + const int mv_sample_log2 = avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_SVQ3 ? 2 : 1; + const int mv_stride = (mb_width << mv_sample_log2) + + (avctx->codec->id == AV_CODEC_ID_H264 ? 0 : 1); + + if (low_delay) + *low_delay = 0; // needed to see the vectors without trashing the buffers + + ret = av_pix_fmt_get_chroma_sub_sample (avctx->pix_fmt, &h_chroma_shift, &v_chroma_shift); + if (ret) + return ret; + + av_frame_make_writable(pict); + + pict->opaque = NULL; + block_height = 16 >> v_chroma_shift; + + for (mb_y = 0; mb_y < mb_height; mb_y++) { + int mb_x; + for (mb_x = 0; mb_x < mb_width; mb_x++) { + const int mb_index = mb_x + mb_y * mb_stride; + if ((avctx->debug & FF_DEBUG_VIS_QP)) { + uint64_t c = (qscale_table[mb_index] * 128 / 31) * + 0x0101010101010101ULL; + int y; + for (y = 0; y < block_height; y++) { + *(uint64_t *)(pict->data[1] + 8 * mb_x + + (block_height * mb_y + y) * + pict->linesize[1]) = c; + *(uint64_t *)(pict->data[2] + 8 * mb_x + + (block_height * mb_y + y) * + pict->linesize[2]) = c; + } + } + if ((avctx->debug & FF_DEBUG_VIS_MB_TYPE) && + motion_val[0]) { + int mb_type = mbtype_table[mb_index]; + uint64_t u,v; + int y; +#define COLOR(theta, r) \ + u = (int)(128 + r * cos(theta * M_PI / 180)); \ + v = (int)(128 + r * sin(theta * M_PI / 180)); + + + u = v = 128; + if (IS_PCM(mb_type)) { + COLOR(120, 48) + } else if ((IS_INTRA(mb_type) && IS_ACPRED(mb_type)) || + IS_INTRA16x16(mb_type)) { + COLOR(30, 48) + } else if (IS_INTRA4x4(mb_type)) { + COLOR(90, 48) + } else if (IS_DIRECT(mb_type) && IS_SKIP(mb_type)) { + // COLOR(120, 48) + } else if (IS_DIRECT(mb_type)) { + COLOR(150, 48) + } else if (IS_GMC(mb_type) && IS_SKIP(mb_type)) { + COLOR(170, 48) + } else if (IS_GMC(mb_type)) { + COLOR(190, 48) + } else if (IS_SKIP(mb_type)) { + // COLOR(180, 48) + } else if (!USES_LIST(mb_type, 1)) { + COLOR(240, 48) + } else if (!USES_LIST(mb_type, 0)) { + COLOR(0, 48) + } else { + av_assert2(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1)); + COLOR(300,48) + } + + u *= 0x0101010101010101ULL; + v *= 0x0101010101010101ULL; + for (y = 0; y < block_height; y++) { + *(uint64_t *)(pict->data[1] + 8 * mb_x + + (block_height * mb_y + y) * pict->linesize[1]) = u; + *(uint64_t *)(pict->data[2] + 8 * mb_x + + (block_height * mb_y + y) * pict->linesize[2]) = v; + } + + // segmentation + if (IS_8X8(mb_type) || IS_16X8(mb_type)) { + *(uint64_t *)(pict->data[0] + 16 * mb_x + 0 + + (16 * mb_y + 8) * pict->linesize[0]) ^= 0x8080808080808080ULL; + *(uint64_t *)(pict->data[0] + 16 * mb_x + 8 + + (16 * mb_y + 8) * pict->linesize[0]) ^= 0x8080808080808080ULL; + } + if (IS_8X8(mb_type) || IS_8X16(mb_type)) { + for (y = 0; y < 16; y++) + pict->data[0][16 * mb_x + 8 + (16 * mb_y + y) * + pict->linesize[0]] ^= 0x80; + } + if (IS_8X8(mb_type) && mv_sample_log2 >= 2) { + int dm = 1 << (mv_sample_log2 - 2); + for (i = 0; i < 4; i++) { + int sx = mb_x * 16 + 8 * (i & 1); + int sy = mb_y * 16 + 8 * (i >> 1); + int xy = (mb_x * 2 + (i & 1) + + (mb_y * 2 + (i >> 1)) * mv_stride) << (mv_sample_log2 - 1); + // FIXME bidir + int32_t *mv = (int32_t *) &motion_val[0][xy]; + if (mv[0] != mv[dm] || + mv[dm * mv_stride] != mv[dm * (mv_stride + 1)]) + for (y = 0; y < 8; y++) + pict->data[0][sx + 4 + (sy + y) * pict->linesize[0]] ^= 0x80; + if (mv[0] != mv[dm * mv_stride] || mv[dm] != mv[dm * (mv_stride + 1)]) + *(uint64_t *)(pict->data[0] + sx + (sy + 4) * + pict->linesize[0]) ^= 0x8080808080808080ULL; + } + } + + if (IS_INTERLACED(mb_type) && + avctx->codec->id == AV_CODEC_ID_H264) { + // hmm + } + } + if (mbskip_table) + mbskip_table[mb_index] = 0; + } + } + } +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegutils.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegutils.h new file mode 100644 index 0000000000..1ed21c19be --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegutils.h @@ -0,0 +1,148 @@ +/* + * Mpeg video formats-related defines and utility functions + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MPEGUTILS_H +#define AVCODEC_MPEGUTILS_H + +#include + +#include "libavutil/frame.h" + +#include "avcodec.h" +#include "version.h" + +/** + * Return value for header parsers if frame is not coded. + * */ +#define FRAME_SKIPPED 100 + +/* picture type */ +#define PICT_TOP_FIELD 1 +#define PICT_BOTTOM_FIELD 2 +#define PICT_FRAME 3 + +/** + * Value of Picture.reference when Picture is not a reference picture, but + * is held for delayed output. + */ +#define DELAYED_PIC_REF 4 + +#define MAX_MB_BYTES (30 * 16 * 16 * 3 / 8 + 120) +#define MAX_FCODE 7 + +/* MB types */ +#define MB_TYPE_INTRA4x4 (1 << 0) +#define MB_TYPE_INTRA16x16 (1 << 1) // FIXME H.264-specific +#define MB_TYPE_INTRA_PCM (1 << 2) // FIXME H.264-specific +#define MB_TYPE_16x16 (1 << 3) +#define MB_TYPE_16x8 (1 << 4) +#define MB_TYPE_8x16 (1 << 5) +#define MB_TYPE_8x8 (1 << 6) +#define MB_TYPE_INTERLACED (1 << 7) +#define MB_TYPE_DIRECT2 (1 << 8) // FIXME +#define MB_TYPE_ACPRED (1 << 9) +#define MB_TYPE_GMC (1 << 10) +#define MB_TYPE_SKIP (1 << 11) +#define MB_TYPE_P0L0 (1 << 12) +#define MB_TYPE_P1L0 (1 << 13) +#define MB_TYPE_P0L1 (1 << 14) +#define MB_TYPE_P1L1 (1 << 15) +#define MB_TYPE_L0 (MB_TYPE_P0L0 | MB_TYPE_P1L0) +#define MB_TYPE_L1 (MB_TYPE_P0L1 | MB_TYPE_P1L1) +#define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) +#define MB_TYPE_QUANT (1 << 16) +#define MB_TYPE_CBP (1 << 17) + +#define MB_TYPE_INTRA MB_TYPE_INTRA4x4 // default mb_type if there is just one type + +#define IS_INTRA4x4(a) ((a) & MB_TYPE_INTRA4x4) +#define IS_INTRA16x16(a) ((a) & MB_TYPE_INTRA16x16) +#define IS_PCM(a) ((a) & MB_TYPE_INTRA_PCM) +#define IS_INTRA(a) ((a) & 7) +#define IS_INTER(a) ((a) & (MB_TYPE_16x16 | MB_TYPE_16x8 | \ + MB_TYPE_8x16 | MB_TYPE_8x8)) +#define IS_SKIP(a) ((a) & MB_TYPE_SKIP) +#define IS_INTRA_PCM(a) ((a) & MB_TYPE_INTRA_PCM) +#define IS_INTERLACED(a) ((a) & MB_TYPE_INTERLACED) +#define IS_DIRECT(a) ((a) & MB_TYPE_DIRECT2) +#define IS_GMC(a) ((a) & MB_TYPE_GMC) +#define IS_16X16(a) ((a) & MB_TYPE_16x16) +#define IS_16X8(a) ((a) & MB_TYPE_16x8) +#define IS_8X16(a) ((a) & MB_TYPE_8x16) +#define IS_8X8(a) ((a) & MB_TYPE_8x8) +#define IS_SUB_8X8(a) ((a) & MB_TYPE_16x16) // note reused +#define IS_SUB_8X4(a) ((a) & MB_TYPE_16x8) // note reused +#define IS_SUB_4X8(a) ((a) & MB_TYPE_8x16) // note reused +#define IS_SUB_4X4(a) ((a) & MB_TYPE_8x8) // note reused +#define IS_ACPRED(a) ((a) & MB_TYPE_ACPRED) +#define IS_QUANT(a) ((a) & MB_TYPE_QUANT) +#define IS_DIR(a, part, list) ((a) & (MB_TYPE_P0L0 << ((part) + 2 * (list)))) + +// does this mb use listX, note does not work if subMBs +#define USES_LIST(a, list) ((a) & ((MB_TYPE_P0L0 | MB_TYPE_P1L0) << (2 * (list)))) + +#define HAS_CBP(a) ((a) & MB_TYPE_CBP) + +/* MB types for encoding */ +#define CANDIDATE_MB_TYPE_INTRA (1 << 0) +#define CANDIDATE_MB_TYPE_INTER (1 << 1) +#define CANDIDATE_MB_TYPE_INTER4V (1 << 2) +#define CANDIDATE_MB_TYPE_SKIPPED (1 << 3) + +#define CANDIDATE_MB_TYPE_DIRECT (1 << 4) +#define CANDIDATE_MB_TYPE_FORWARD (1 << 5) +#define CANDIDATE_MB_TYPE_BACKWARD (1 << 6) +#define CANDIDATE_MB_TYPE_BIDIR (1 << 7) + +#define CANDIDATE_MB_TYPE_INTER_I (1 << 8) +#define CANDIDATE_MB_TYPE_FORWARD_I (1 << 9) +#define CANDIDATE_MB_TYPE_BACKWARD_I (1 << 10) +#define CANDIDATE_MB_TYPE_BIDIR_I (1 << 11) + +#define CANDIDATE_MB_TYPE_DIRECT0 (1 << 12) + +#define INPLACE_OFFSET 16 + +enum OutputFormat { + FMT_MPEG1, + FMT_H261, + FMT_H263, + FMT_MJPEG, +}; + + +/** + * Draw a horizontal band if supported. + * + * @param h is the normal height, this will be reduced automatically if needed + */ +void ff_draw_horiz_band(AVCodecContext *avctx, AVFrame *cur, AVFrame *last, + int y, int h, int picture_structure, int first_field, + int low_delay); + +/** + * Print debugging info for the given picture. + */ +void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_table, + uint32_t *mbtype_table, int8_t *qscale_table, int16_t (*motion_val[2])[2], + int *low_delay, + int mb_width, int mb_height, int mb_stride, int quarter_sample); + +#endif /* AVCODEC_MPEGUTILS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideo.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideo.c new file mode 100644 index 0000000000..dbb6ab9b39 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideo.c @@ -0,0 +1,2356 @@ +/* + * The simplest mpeg encoder (well, it was the simplest!) + * Copyright (c) 2000,2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * 4MV & hq & B-frame encoding stuff by Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * The simplest mpeg encoder (well, it was the simplest!). + */ + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" +#include "libavutil/internal.h" +#include "libavutil/motion_vector.h" +#include "libavutil/timer.h" +#include "avcodec.h" +#include "blockdsp.h" +#include "h264chroma.h" +#include "idctdsp.h" +#include "internal.h" +#include "mathops.h" +#include "mpeg_er.h" +#include "mpegutils.h" +#include "mpegvideo.h" +#include "mpegvideodata.h" +#include "mjpegenc.h" +#include "msmpeg4.h" +#include "qpeldsp.h" +#include "thread.h" +#include "wmv2.h" +#include + +static void dct_unquantize_mpeg1_intra_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + + nCoeffs= s->block_last_index[n]; + + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + /* XXX: only MPEG-1 */ + quant_matrix = s->intra_matrix; + for(i=1;i<=nCoeffs;i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (int)(level * qscale * quant_matrix[j]) >> 3; + level = (level - 1) | 1; + level = -level; + } else { + level = (int)(level * qscale * quant_matrix[j]) >> 3; + level = (level - 1) | 1; + } + block[j] = level; + } + } +} + +static void dct_unquantize_mpeg1_inter_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + + nCoeffs= s->block_last_index[n]; + + quant_matrix = s->inter_matrix; + for(i=0; i<=nCoeffs; i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 4; + level = (level - 1) | 1; + level = -level; + } else { + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 4; + level = (level - 1) | 1; + } + block[j] = level; + } + } +} + +static void dct_unquantize_mpeg2_intra_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + if(s->alternate_scan) nCoeffs= 63; + else nCoeffs= s->block_last_index[n]; + + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + quant_matrix = s->intra_matrix; + for(i=1;i<=nCoeffs;i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (int)(level * qscale * quant_matrix[j]) >> 4; + level = -level; + } else { + level = (int)(level * qscale * quant_matrix[j]) >> 4; + } + block[j] = level; + } + } +} + +static void dct_unquantize_mpeg2_intra_bitexact(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + int sum=-1; + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + if(s->alternate_scan) nCoeffs= 63; + else nCoeffs= s->block_last_index[n]; + + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + sum += block[0]; + quant_matrix = s->intra_matrix; + for(i=1;i<=nCoeffs;i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (int)(level * qscale * quant_matrix[j]) >> 4; + level = -level; + } else { + level = (int)(level * qscale * quant_matrix[j]) >> 4; + } + block[j] = level; + sum+=level; + } + } + block[63]^=sum&1; +} + +static void dct_unquantize_mpeg2_inter_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, nCoeffs; + const uint16_t *quant_matrix; + int sum=-1; + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + if(s->alternate_scan) nCoeffs= 63; + else nCoeffs= s->block_last_index[n]; + + quant_matrix = s->inter_matrix; + for(i=0; i<=nCoeffs; i++) { + int j= s->intra_scantable.permutated[i]; + level = block[j]; + if (level) { + if (level < 0) { + level = -level; + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 5; + level = -level; + } else { + level = (((level << 1) + 1) * qscale * + ((int) (quant_matrix[j]))) >> 5; + } + block[j] = level; + sum+=level; + } + } + block[63]^=sum&1; +} + +static void dct_unquantize_h263_intra_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, qmul, qadd; + int nCoeffs; + + av_assert2(s->block_last_index[n]>=0 || s->h263_aic); + + qmul = qscale << 1; + + if (!s->h263_aic) { + block[0] *= n < 4 ? s->y_dc_scale : s->c_dc_scale; + qadd = (qscale - 1) | 1; + }else{ + qadd = 0; + } + if(s->ac_pred) + nCoeffs=63; + else + nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; + + for(i=1; i<=nCoeffs; i++) { + level = block[i]; + if (level) { + if (level < 0) { + level = level * qmul - qadd; + } else { + level = level * qmul + qadd; + } + block[i] = level; + } + } +} + +static void dct_unquantize_h263_inter_c(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + int i, level, qmul, qadd; + int nCoeffs; + + av_assert2(s->block_last_index[n]>=0); + + qadd = (qscale - 1) | 1; + qmul = qscale << 1; + + nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ]; + + for(i=0; i<=nCoeffs; i++) { + level = block[i]; + if (level) { + if (level < 0) { + level = level * qmul - qadd; + } else { + level = level * qmul + qadd; + } + block[i] = level; + } + } +} + + +static void gray16(uint8_t *dst, const uint8_t *src, ptrdiff_t linesize, int h) +{ + while(h--) + memset(dst + h*linesize, 128, 16); +} + +static void gray8(uint8_t *dst, const uint8_t *src, ptrdiff_t linesize, int h) +{ + while(h--) + memset(dst + h*linesize, 128, 8); +} + +/* init common dct for both encoder and decoder */ +static av_cold int dct_init(MpegEncContext *s) +{ + ff_blockdsp_init(&s->bdsp, s->avctx); + ff_h264chroma_init(&s->h264chroma, 8); //for lowres + ff_hpeldsp_init(&s->hdsp, s->avctx->flags); + ff_mpegvideodsp_init(&s->mdsp); + ff_videodsp_init(&s->vdsp, s->avctx->bits_per_raw_sample); + + if (s->avctx->debug & FF_DEBUG_NOMC) { + int i; + for (i=0; i<4; i++) { + s->hdsp.avg_pixels_tab[0][i] = gray16; + s->hdsp.put_pixels_tab[0][i] = gray16; + s->hdsp.put_no_rnd_pixels_tab[0][i] = gray16; + + s->hdsp.avg_pixels_tab[1][i] = gray8; + s->hdsp.put_pixels_tab[1][i] = gray8; + s->hdsp.put_no_rnd_pixels_tab[1][i] = gray8; + } + } + + s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_c; + s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_c; + s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_c; + s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_c; + s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_c; + if (s->avctx->flags & AV_CODEC_FLAG_BITEXACT) + s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_bitexact; + s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_c; + + if (HAVE_INTRINSICS_NEON) + ff_mpv_common_init_neon(s); + + if (ARCH_ALPHA) + ff_mpv_common_init_axp(s); + if (ARCH_ARM) + ff_mpv_common_init_arm(s); + if (ARCH_PPC) + ff_mpv_common_init_ppc(s); + if (ARCH_X86) + ff_mpv_common_init_x86(s); + if (ARCH_MIPS) + ff_mpv_common_init_mips(s); + + return 0; +} + +av_cold void ff_mpv_idct_init(MpegEncContext *s) +{ + if (s->codec_id == AV_CODEC_ID_MPEG4) + s->idsp.mpeg4_studio_profile = s->studio_profile; + ff_idctdsp_init(&s->idsp, s->avctx); + + /* load & permutate scantables + * note: only wmv uses different ones + */ + if (s->alternate_scan) { + ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, ff_alternate_vertical_scan); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_alternate_vertical_scan); + } else { + ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, ff_zigzag_direct); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_zigzag_direct); + } + ff_init_scantable(s->idsp.idct_permutation, &s->intra_h_scantable, ff_alternate_horizontal_scan); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_v_scantable, ff_alternate_vertical_scan); +} + +static int alloc_picture(MpegEncContext *s, Picture *pic, int shared) +{ + return ff_alloc_picture(s->avctx, pic, &s->me, &s->sc, shared, 0, + s->chroma_x_shift, s->chroma_y_shift, s->out_format, + s->mb_stride, s->mb_width, s->mb_height, s->b8_stride, + &s->linesize, &s->uvlinesize); +} + +static int init_duplicate_context(MpegEncContext *s) +{ + int y_size = s->b8_stride * (2 * s->mb_height + 1); + int c_size = s->mb_stride * (s->mb_height + 1); + int yc_size = y_size + 2 * c_size; + int i; + + if (s->mb_height & 1) + yc_size += 2*s->b8_stride + 2*s->mb_stride; + + s->sc.edge_emu_buffer = + s->me.scratchpad = + s->me.temp = + s->sc.rd_scratchpad = + s->sc.b_scratchpad = + s->sc.obmc_scratchpad = NULL; + + if (s->encoding) { + FF_ALLOCZ_OR_GOTO(s->avctx, s->me.map, + ME_MAP_SIZE * sizeof(uint32_t), fail) + FF_ALLOCZ_OR_GOTO(s->avctx, s->me.score_map, + ME_MAP_SIZE * sizeof(uint32_t), fail) + if (s->noise_reduction) { + FF_ALLOCZ_OR_GOTO(s->avctx, s->dct_error_sum, + 2 * 64 * sizeof(int), fail) + } + } + FF_ALLOCZ_OR_GOTO(s->avctx, s->blocks, 64 * 12 * 2 * sizeof(int16_t), fail) + s->block = s->blocks[0]; + + for (i = 0; i < 12; i++) { + s->pblocks[i] = &s->block[i]; + } + + FF_ALLOCZ_OR_GOTO(s->avctx, s->block32, sizeof(*s->block32), fail) + s->dpcm_direction = 0; + FF_ALLOCZ_OR_GOTO(s->avctx, s->dpcm_macroblock, sizeof(*s->dpcm_macroblock), fail) + + if (s->avctx->codec_tag == AV_RL32("VCR2")) { + // exchange uv + FFSWAP(void *, s->pblocks[4], s->pblocks[5]); + } + + if (s->out_format == FMT_H263) { + /* ac values */ + FF_ALLOCZ_OR_GOTO(s->avctx, s->ac_val_base, + yc_size * sizeof(int16_t) * 16, fail); + s->ac_val[0] = s->ac_val_base + s->b8_stride + 1; + s->ac_val[1] = s->ac_val_base + y_size + s->mb_stride + 1; + s->ac_val[2] = s->ac_val[1] + c_size; + } + + return 0; +fail: + return -1; // free() through ff_mpv_common_end() +} + +static void free_duplicate_context(MpegEncContext *s) +{ + if (!s) + return; + + av_freep(&s->sc.edge_emu_buffer); + av_freep(&s->me.scratchpad); + s->me.temp = + s->sc.rd_scratchpad = + s->sc.b_scratchpad = + s->sc.obmc_scratchpad = NULL; + + av_freep(&s->dct_error_sum); + av_freep(&s->me.map); + av_freep(&s->me.score_map); + av_freep(&s->blocks); + av_freep(&s->block32); + av_freep(&s->dpcm_macroblock); + av_freep(&s->ac_val_base); + s->block = NULL; +} + +static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) +{ +#define COPY(a) bak->a = src->a + COPY(sc.edge_emu_buffer); + COPY(me.scratchpad); + COPY(me.temp); + COPY(sc.rd_scratchpad); + COPY(sc.b_scratchpad); + COPY(sc.obmc_scratchpad); + COPY(me.map); + COPY(me.score_map); + COPY(blocks); + COPY(block); + COPY(block32); + COPY(dpcm_macroblock); + COPY(dpcm_direction); + COPY(start_mb_y); + COPY(end_mb_y); + COPY(me.map_generation); + COPY(pb); + COPY(dct_error_sum); + COPY(dct_count[0]); + COPY(dct_count[1]); + COPY(ac_val_base); + COPY(ac_val[0]); + COPY(ac_val[1]); + COPY(ac_val[2]); +#undef COPY +} + +int ff_update_duplicate_context(MpegEncContext *dst, MpegEncContext *src) +{ + MpegEncContext bak; + int i, ret; + // FIXME copy only needed parts + // START_TIMER + backup_duplicate_context(&bak, dst); + memcpy(dst, src, sizeof(MpegEncContext)); + backup_duplicate_context(dst, &bak); + for (i = 0; i < 12; i++) { + dst->pblocks[i] = &dst->block[i]; + } + if (dst->avctx->codec_tag == AV_RL32("VCR2")) { + // exchange uv + FFSWAP(void *, dst->pblocks[4], dst->pblocks[5]); + } + if (!dst->sc.edge_emu_buffer && + (ret = ff_mpeg_framesize_alloc(dst->avctx, &dst->me, + &dst->sc, dst->linesize)) < 0) { + av_log(dst->avctx, AV_LOG_ERROR, "failed to allocate context " + "scratch buffers.\n"); + return ret; + } + // STOP_TIMER("update_duplicate_context") + // about 10k cycles / 0.01 sec for 1000frames on 1ghz with 2 threads + return 0; +} + +int ff_mpeg_update_thread_context(AVCodecContext *dst, + const AVCodecContext *src) +{ + int i, ret; + MpegEncContext *s = dst->priv_data, *s1 = src->priv_data; + + if (dst == src) + return 0; + + av_assert0(s != s1); + + // FIXME can parameters change on I-frames? + // in that case dst may need a reinit + if (!s->context_initialized) { + int err; + memcpy(s, s1, sizeof(MpegEncContext)); + + s->avctx = dst; + s->bitstream_buffer = NULL; + s->bitstream_buffer_size = s->allocated_bitstream_buffer_size = 0; + + if (s1->context_initialized){ +// s->picture_range_start += MAX_PICTURE_COUNT; +// s->picture_range_end += MAX_PICTURE_COUNT; + ff_mpv_idct_init(s); + if((err = ff_mpv_common_init(s)) < 0){ + memset(s, 0, sizeof(MpegEncContext)); + s->avctx = dst; + return err; + } + } + } + + if (s->height != s1->height || s->width != s1->width || s->context_reinit) { + s->context_reinit = 0; + s->height = s1->height; + s->width = s1->width; + if ((ret = ff_mpv_common_frame_size_change(s)) < 0) + return ret; + } + + s->avctx->coded_height = s1->avctx->coded_height; + s->avctx->coded_width = s1->avctx->coded_width; + s->avctx->width = s1->avctx->width; + s->avctx->height = s1->avctx->height; + + s->quarter_sample = s1->quarter_sample; + + s->coded_picture_number = s1->coded_picture_number; + s->picture_number = s1->picture_number; + + av_assert0(!s->picture || s->picture != s1->picture); + if(s->picture) + for (i = 0; i < MAX_PICTURE_COUNT; i++) { + ff_mpeg_unref_picture(s->avctx, &s->picture[i]); + if (s1->picture && s1->picture[i].f->buf[0] && + (ret = ff_mpeg_ref_picture(s->avctx, &s->picture[i], &s1->picture[i])) < 0) + return ret; + } + +#define UPDATE_PICTURE(pic)\ +do {\ + ff_mpeg_unref_picture(s->avctx, &s->pic);\ + if (s1->pic.f && s1->pic.f->buf[0])\ + ret = ff_mpeg_ref_picture(s->avctx, &s->pic, &s1->pic);\ + else\ + ret = ff_update_picture_tables(&s->pic, &s1->pic);\ + if (ret < 0)\ + return ret;\ +} while (0) + + UPDATE_PICTURE(current_picture); + UPDATE_PICTURE(last_picture); + UPDATE_PICTURE(next_picture); + +#define REBASE_PICTURE(pic, new_ctx, old_ctx) \ + ((pic && pic >= old_ctx->picture && \ + pic < old_ctx->picture + MAX_PICTURE_COUNT) ? \ + &new_ctx->picture[pic - old_ctx->picture] : NULL) + + s->last_picture_ptr = REBASE_PICTURE(s1->last_picture_ptr, s, s1); + s->current_picture_ptr = REBASE_PICTURE(s1->current_picture_ptr, s, s1); + s->next_picture_ptr = REBASE_PICTURE(s1->next_picture_ptr, s, s1); + + // Error/bug resilience + s->next_p_frame_damaged = s1->next_p_frame_damaged; + s->workaround_bugs = s1->workaround_bugs; + s->padding_bug_score = s1->padding_bug_score; + + // MPEG-4 timing info + memcpy(&s->last_time_base, &s1->last_time_base, + (char *) &s1->pb_field_time + sizeof(s1->pb_field_time) - + (char *) &s1->last_time_base); + + // B-frame info + s->max_b_frames = s1->max_b_frames; + s->low_delay = s1->low_delay; + s->droppable = s1->droppable; + + // DivX handling (doesn't work) + s->divx_packed = s1->divx_packed; + + if (s1->bitstream_buffer) { + if (s1->bitstream_buffer_size + + AV_INPUT_BUFFER_PADDING_SIZE > s->allocated_bitstream_buffer_size) { + av_fast_malloc(&s->bitstream_buffer, + &s->allocated_bitstream_buffer_size, + s1->allocated_bitstream_buffer_size); + if (!s->bitstream_buffer) { + s->bitstream_buffer_size = 0; + return AVERROR(ENOMEM); + } + } + s->bitstream_buffer_size = s1->bitstream_buffer_size; + memcpy(s->bitstream_buffer, s1->bitstream_buffer, + s1->bitstream_buffer_size); + memset(s->bitstream_buffer + s->bitstream_buffer_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + } + + // linesize-dependent scratch buffer allocation + if (!s->sc.edge_emu_buffer) + if (s1->linesize) { + if (ff_mpeg_framesize_alloc(s->avctx, &s->me, + &s->sc, s1->linesize) < 0) { + av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate context " + "scratch buffers.\n"); + return AVERROR(ENOMEM); + } + } else { + av_log(s->avctx, AV_LOG_ERROR, "Context scratch buffers could not " + "be allocated due to unknown size.\n"); + } + + // MPEG-2/interlacing info + memcpy(&s->progressive_sequence, &s1->progressive_sequence, + (char *) &s1->rtp_mode - (char *) &s1->progressive_sequence); + + if (!s1->first_field) { + s->last_pict_type = s1->pict_type; + if (s1->current_picture_ptr) + s->last_lambda_for[s1->pict_type] = s1->current_picture_ptr->f->quality; + } + + return 0; +} + +/** + * Set the given MpegEncContext to common defaults + * (same for encoding and decoding). + * The changed fields will not depend upon the + * prior state of the MpegEncContext. + */ +void ff_mpv_common_defaults(MpegEncContext *s) +{ + s->y_dc_scale_table = + s->c_dc_scale_table = ff_mpeg1_dc_scale_table; + s->chroma_qscale_table = ff_default_chroma_qscale_table; + s->progressive_frame = 1; + s->progressive_sequence = 1; + s->picture_structure = PICT_FRAME; + + s->coded_picture_number = 0; + s->picture_number = 0; + + s->f_code = 1; + s->b_code = 1; + + s->slice_context_count = 1; +} + +/** + * Set the given MpegEncContext to defaults for decoding. + * the changed fields will not depend upon + * the prior state of the MpegEncContext. + */ +void ff_mpv_decode_defaults(MpegEncContext *s) +{ + ff_mpv_common_defaults(s); +} + +void ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx) +{ + s->avctx = avctx; + s->width = avctx->coded_width; + s->height = avctx->coded_height; + s->codec_id = avctx->codec->id; + s->workaround_bugs = avctx->workaround_bugs; + + /* convert fourcc to upper case */ + s->codec_tag = avpriv_toupper4(avctx->codec_tag); +} + +/** + * Initialize and allocates MpegEncContext fields dependent on the resolution. + */ +static int init_context_frame(MpegEncContext *s) +{ + int y_size, c_size, yc_size, i, mb_array_size, mv_table_size, x, y; + + s->mb_width = (s->width + 15) / 16; + s->mb_stride = s->mb_width + 1; + s->b8_stride = s->mb_width * 2 + 1; + mb_array_size = s->mb_height * s->mb_stride; + mv_table_size = (s->mb_height + 2) * s->mb_stride + 1; + + /* set default edge pos, will be overridden + * in decode_header if needed */ + s->h_edge_pos = s->mb_width * 16; + s->v_edge_pos = s->mb_height * 16; + + s->mb_num = s->mb_width * s->mb_height; + + s->block_wrap[0] = + s->block_wrap[1] = + s->block_wrap[2] = + s->block_wrap[3] = s->b8_stride; + s->block_wrap[4] = + s->block_wrap[5] = s->mb_stride; + + y_size = s->b8_stride * (2 * s->mb_height + 1); + c_size = s->mb_stride * (s->mb_height + 1); + yc_size = y_size + 2 * c_size; + + if (s->mb_height & 1) + yc_size += 2*s->b8_stride + 2*s->mb_stride; + + FF_ALLOCZ_OR_GOTO(s->avctx, s->mb_index2xy, (s->mb_num + 1) * sizeof(int), + fail); // error resilience code looks cleaner with this + for (y = 0; y < s->mb_height; y++) + for (x = 0; x < s->mb_width; x++) + s->mb_index2xy[x + y * s->mb_width] = x + y * s->mb_stride; + + s->mb_index2xy[s->mb_height * s->mb_width] = (s->mb_height - 1) * s->mb_stride + s->mb_width; // FIXME really needed? + + if (s->encoding) { + /* Allocate MV tables */ + FF_ALLOCZ_OR_GOTO(s->avctx, s->p_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) + FF_ALLOCZ_OR_GOTO(s->avctx, s->b_forw_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) + FF_ALLOCZ_OR_GOTO(s->avctx, s->b_back_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) + FF_ALLOCZ_OR_GOTO(s->avctx, s->b_bidir_forw_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) + FF_ALLOCZ_OR_GOTO(s->avctx, s->b_bidir_back_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) + FF_ALLOCZ_OR_GOTO(s->avctx, s->b_direct_mv_table_base, mv_table_size * 2 * sizeof(int16_t), fail) + s->p_mv_table = s->p_mv_table_base + s->mb_stride + 1; + s->b_forw_mv_table = s->b_forw_mv_table_base + s->mb_stride + 1; + s->b_back_mv_table = s->b_back_mv_table_base + s->mb_stride + 1; + s->b_bidir_forw_mv_table = s->b_bidir_forw_mv_table_base + s->mb_stride + 1; + s->b_bidir_back_mv_table = s->b_bidir_back_mv_table_base + s->mb_stride + 1; + s->b_direct_mv_table = s->b_direct_mv_table_base + s->mb_stride + 1; + + /* Allocate MB type table */ + FF_ALLOCZ_OR_GOTO(s->avctx, s->mb_type, mb_array_size * sizeof(uint16_t), fail) // needed for encoding + + FF_ALLOCZ_OR_GOTO(s->avctx, s->lambda_table, mb_array_size * sizeof(int), fail) + + FF_ALLOC_OR_GOTO(s->avctx, s->cplx_tab, + mb_array_size * sizeof(float), fail); + FF_ALLOC_OR_GOTO(s->avctx, s->bits_tab, + mb_array_size * sizeof(float), fail); + + } + + if (s->codec_id == AV_CODEC_ID_MPEG4 || + (s->avctx->flags & AV_CODEC_FLAG_INTERLACED_ME)) { + /* interlaced direct mode decoding tables */ + for (i = 0; i < 2; i++) { + int j, k; + for (j = 0; j < 2; j++) { + for (k = 0; k < 2; k++) { + FF_ALLOCZ_OR_GOTO(s->avctx, + s->b_field_mv_table_base[i][j][k], + mv_table_size * 2 * sizeof(int16_t), + fail); + s->b_field_mv_table[i][j][k] = s->b_field_mv_table_base[i][j][k] + + s->mb_stride + 1; + } + FF_ALLOCZ_OR_GOTO(s->avctx, s->b_field_select_table [i][j], mb_array_size * 2 * sizeof(uint8_t), fail) + FF_ALLOCZ_OR_GOTO(s->avctx, s->p_field_mv_table_base[i][j], mv_table_size * 2 * sizeof(int16_t), fail) + s->p_field_mv_table[i][j] = s->p_field_mv_table_base[i][j] + s->mb_stride + 1; + } + FF_ALLOCZ_OR_GOTO(s->avctx, s->p_field_select_table[i], mb_array_size * 2 * sizeof(uint8_t), fail) + } + } + if (s->out_format == FMT_H263) { + /* cbp values */ + FF_ALLOCZ_OR_GOTO(s->avctx, s->coded_block_base, y_size + (s->mb_height&1)*2*s->b8_stride, fail); + s->coded_block = s->coded_block_base + s->b8_stride + 1; + + /* cbp, ac_pred, pred_dir */ + FF_ALLOCZ_OR_GOTO(s->avctx, s->cbp_table , mb_array_size * sizeof(uint8_t), fail); + FF_ALLOCZ_OR_GOTO(s->avctx, s->pred_dir_table, mb_array_size * sizeof(uint8_t), fail); + } + + if (s->h263_pred || s->h263_plus || !s->encoding) { + /* dc values */ + // MN: we need these for error resilience of intra-frames + FF_ALLOCZ_OR_GOTO(s->avctx, s->dc_val_base, yc_size * sizeof(int16_t), fail); + s->dc_val[0] = s->dc_val_base + s->b8_stride + 1; + s->dc_val[1] = s->dc_val_base + y_size + s->mb_stride + 1; + s->dc_val[2] = s->dc_val[1] + c_size; + for (i = 0; i < yc_size; i++) + s->dc_val_base[i] = 1024; + } + + /* which mb is an intra block */ + FF_ALLOCZ_OR_GOTO(s->avctx, s->mbintra_table, mb_array_size, fail); + memset(s->mbintra_table, 1, mb_array_size); + + /* init macroblock skip table */ + FF_ALLOCZ_OR_GOTO(s->avctx, s->mbskip_table, mb_array_size + 2, fail); + // Note the + 1 is for a quicker MPEG-4 slice_end detection + + return ff_mpeg_er_init(s); +fail: + return AVERROR(ENOMEM); +} + +static void clear_context(MpegEncContext *s) +{ + int i, j, k; + + memset(&s->next_picture, 0, sizeof(s->next_picture)); + memset(&s->last_picture, 0, sizeof(s->last_picture)); + memset(&s->current_picture, 0, sizeof(s->current_picture)); + memset(&s->new_picture, 0, sizeof(s->new_picture)); + + memset(s->thread_context, 0, sizeof(s->thread_context)); + + s->me.map = NULL; + s->me.score_map = NULL; + s->dct_error_sum = NULL; + s->block = NULL; + s->blocks = NULL; + s->block32 = NULL; + memset(s->pblocks, 0, sizeof(s->pblocks)); + s->dpcm_direction = 0; + s->dpcm_macroblock = NULL; + s->ac_val_base = NULL; + s->ac_val[0] = + s->ac_val[1] = + s->ac_val[2] =NULL; + s->sc.edge_emu_buffer = NULL; + s->me.scratchpad = NULL; + s->me.temp = + s->sc.rd_scratchpad = + s->sc.b_scratchpad = + s->sc.obmc_scratchpad = NULL; + + + s->bitstream_buffer = NULL; + s->allocated_bitstream_buffer_size = 0; + s->picture = NULL; + s->mb_type = NULL; + s->p_mv_table_base = NULL; + s->b_forw_mv_table_base = NULL; + s->b_back_mv_table_base = NULL; + s->b_bidir_forw_mv_table_base = NULL; + s->b_bidir_back_mv_table_base = NULL; + s->b_direct_mv_table_base = NULL; + s->p_mv_table = NULL; + s->b_forw_mv_table = NULL; + s->b_back_mv_table = NULL; + s->b_bidir_forw_mv_table = NULL; + s->b_bidir_back_mv_table = NULL; + s->b_direct_mv_table = NULL; + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k < 2; k++) { + s->b_field_mv_table_base[i][j][k] = NULL; + s->b_field_mv_table[i][j][k] = NULL; + } + s->b_field_select_table[i][j] = NULL; + s->p_field_mv_table_base[i][j] = NULL; + s->p_field_mv_table[i][j] = NULL; + } + s->p_field_select_table[i] = NULL; + } + + s->dc_val_base = NULL; + s->coded_block_base = NULL; + s->mbintra_table = NULL; + s->cbp_table = NULL; + s->pred_dir_table = NULL; + + s->mbskip_table = NULL; + + s->er.error_status_table = NULL; + s->er.er_temp_buffer = NULL; + s->mb_index2xy = NULL; + s->lambda_table = NULL; + + s->cplx_tab = NULL; + s->bits_tab = NULL; +} + +/** + * init common structure for both encoder and decoder. + * this assumes that some variables like width/height are already set + */ +av_cold int ff_mpv_common_init(MpegEncContext *s) +{ + int i, ret; + int nb_slices = (HAVE_THREADS && + s->avctx->active_thread_type & FF_THREAD_SLICE) ? + s->avctx->thread_count : 1; + + clear_context(s); + + if (s->encoding && s->avctx->slices) + nb_slices = s->avctx->slices; + + if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && !s->progressive_sequence) + s->mb_height = (s->height + 31) / 32 * 2; + else + s->mb_height = (s->height + 15) / 16; + + if (s->avctx->pix_fmt == AV_PIX_FMT_NONE) { + av_log(s->avctx, AV_LOG_ERROR, + "decoding to AV_PIX_FMT_NONE is not supported.\n"); + return -1; + } + + if (nb_slices > MAX_THREADS || (nb_slices > s->mb_height && s->mb_height)) { + int max_slices; + if (s->mb_height) + max_slices = FFMIN(MAX_THREADS, s->mb_height); + else + max_slices = MAX_THREADS; + av_log(s->avctx, AV_LOG_WARNING, "too many threads/slices (%d)," + " reducing to %d\n", nb_slices, max_slices); + nb_slices = max_slices; + } + + if ((s->width || s->height) && + av_image_check_size(s->width, s->height, 0, s->avctx)) + return -1; + + dct_init(s); + + /* set chroma shifts */ + ret = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, + &s->chroma_x_shift, + &s->chroma_y_shift); + if (ret) + return ret; + + FF_ALLOCZ_OR_GOTO(s->avctx, s->picture, + MAX_PICTURE_COUNT * sizeof(Picture), fail); + for (i = 0; i < MAX_PICTURE_COUNT; i++) { + s->picture[i].f = av_frame_alloc(); + if (!s->picture[i].f) + goto fail; + } + s->next_picture.f = av_frame_alloc(); + if (!s->next_picture.f) + goto fail; + s->last_picture.f = av_frame_alloc(); + if (!s->last_picture.f) + goto fail; + s->current_picture.f = av_frame_alloc(); + if (!s->current_picture.f) + goto fail; + s->new_picture.f = av_frame_alloc(); + if (!s->new_picture.f) + goto fail; + + if (init_context_frame(s)) + goto fail; + + s->parse_context.state = -1; + + s->context_initialized = 1; + memset(s->thread_context, 0, sizeof(s->thread_context)); + s->thread_context[0] = s; + +// if (s->width && s->height) { + if (nb_slices > 1) { + for (i = 0; i < nb_slices; i++) { + if (i) { + s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext)); + if (!s->thread_context[i]) + goto fail; + } + if (init_duplicate_context(s->thread_context[i]) < 0) + goto fail; + s->thread_context[i]->start_mb_y = + (s->mb_height * (i) + nb_slices / 2) / nb_slices; + s->thread_context[i]->end_mb_y = + (s->mb_height * (i + 1) + nb_slices / 2) / nb_slices; + } + } else { + if (init_duplicate_context(s) < 0) + goto fail; + s->start_mb_y = 0; + s->end_mb_y = s->mb_height; + } + s->slice_context_count = nb_slices; +// } + + return 0; + fail: + ff_mpv_common_end(s); + return -1; +} + +/** + * Frees and resets MpegEncContext fields depending on the resolution. + * Is used during resolution changes to avoid a full reinitialization of the + * codec. + */ +static void free_context_frame(MpegEncContext *s) +{ + int i, j, k; + + av_freep(&s->mb_type); + av_freep(&s->p_mv_table_base); + av_freep(&s->b_forw_mv_table_base); + av_freep(&s->b_back_mv_table_base); + av_freep(&s->b_bidir_forw_mv_table_base); + av_freep(&s->b_bidir_back_mv_table_base); + av_freep(&s->b_direct_mv_table_base); + s->p_mv_table = NULL; + s->b_forw_mv_table = NULL; + s->b_back_mv_table = NULL; + s->b_bidir_forw_mv_table = NULL; + s->b_bidir_back_mv_table = NULL; + s->b_direct_mv_table = NULL; + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k < 2; k++) { + av_freep(&s->b_field_mv_table_base[i][j][k]); + s->b_field_mv_table[i][j][k] = NULL; + } + av_freep(&s->b_field_select_table[i][j]); + av_freep(&s->p_field_mv_table_base[i][j]); + s->p_field_mv_table[i][j] = NULL; + } + av_freep(&s->p_field_select_table[i]); + } + + av_freep(&s->dc_val_base); + av_freep(&s->coded_block_base); + av_freep(&s->mbintra_table); + av_freep(&s->cbp_table); + av_freep(&s->pred_dir_table); + + av_freep(&s->mbskip_table); + + av_freep(&s->er.error_status_table); + av_freep(&s->er.er_temp_buffer); + av_freep(&s->mb_index2xy); + av_freep(&s->lambda_table); + + av_freep(&s->cplx_tab); + av_freep(&s->bits_tab); + + s->linesize = s->uvlinesize = 0; +} + +int ff_mpv_common_frame_size_change(MpegEncContext *s) +{ + int i, err = 0; + + if (!s->context_initialized) + return AVERROR(EINVAL); + + if (s->slice_context_count > 1) { + for (i = 0; i < s->slice_context_count; i++) { + free_duplicate_context(s->thread_context[i]); + } + for (i = 1; i < s->slice_context_count; i++) { + av_freep(&s->thread_context[i]); + } + } else + free_duplicate_context(s); + + free_context_frame(s); + + if (s->picture) + for (i = 0; i < MAX_PICTURE_COUNT; i++) { + s->picture[i].needs_realloc = 1; + } + + s->last_picture_ptr = + s->next_picture_ptr = + s->current_picture_ptr = NULL; + + // init + if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && !s->progressive_sequence) + s->mb_height = (s->height + 31) / 32 * 2; + else + s->mb_height = (s->height + 15) / 16; + + if ((s->width || s->height) && + (err = av_image_check_size(s->width, s->height, 0, s->avctx)) < 0) + goto fail; + + if ((err = init_context_frame(s))) + goto fail; + + memset(s->thread_context, 0, sizeof(s->thread_context)); + s->thread_context[0] = s; + + if (s->width && s->height) { + int nb_slices = s->slice_context_count; + if (nb_slices > 1) { + for (i = 0; i < nb_slices; i++) { + if (i) { + s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext)); + if (!s->thread_context[i]) { + err = AVERROR(ENOMEM); + goto fail; + } + } + if ((err = init_duplicate_context(s->thread_context[i])) < 0) + goto fail; + s->thread_context[i]->start_mb_y = + (s->mb_height * (i) + nb_slices / 2) / nb_slices; + s->thread_context[i]->end_mb_y = + (s->mb_height * (i + 1) + nb_slices / 2) / nb_slices; + } + } else { + err = init_duplicate_context(s); + if (err < 0) + goto fail; + s->start_mb_y = 0; + s->end_mb_y = s->mb_height; + } + s->slice_context_count = nb_slices; + } + + return 0; + fail: + ff_mpv_common_end(s); + return err; +} + +/* init common structure for both encoder and decoder */ +void ff_mpv_common_end(MpegEncContext *s) +{ + int i; + + if (!s) + return ; + + if (s->slice_context_count > 1) { + for (i = 0; i < s->slice_context_count; i++) { + free_duplicate_context(s->thread_context[i]); + } + for (i = 1; i < s->slice_context_count; i++) { + av_freep(&s->thread_context[i]); + } + s->slice_context_count = 1; + } else free_duplicate_context(s); + + av_freep(&s->parse_context.buffer); + s->parse_context.buffer_size = 0; + + av_freep(&s->bitstream_buffer); + s->allocated_bitstream_buffer_size = 0; + + if (s->picture) { + for (i = 0; i < MAX_PICTURE_COUNT; i++) { + ff_free_picture_tables(&s->picture[i]); + ff_mpeg_unref_picture(s->avctx, &s->picture[i]); + av_frame_free(&s->picture[i].f); + } + } + av_freep(&s->picture); + ff_free_picture_tables(&s->last_picture); + ff_mpeg_unref_picture(s->avctx, &s->last_picture); + av_frame_free(&s->last_picture.f); + ff_free_picture_tables(&s->current_picture); + ff_mpeg_unref_picture(s->avctx, &s->current_picture); + av_frame_free(&s->current_picture.f); + ff_free_picture_tables(&s->next_picture); + ff_mpeg_unref_picture(s->avctx, &s->next_picture); + av_frame_free(&s->next_picture.f); + ff_free_picture_tables(&s->new_picture); + ff_mpeg_unref_picture(s->avctx, &s->new_picture); + av_frame_free(&s->new_picture.f); + + free_context_frame(s); + + s->context_initialized = 0; + s->last_picture_ptr = + s->next_picture_ptr = + s->current_picture_ptr = NULL; + s->linesize = s->uvlinesize = 0; +} + + +static void gray_frame(AVFrame *frame) +{ + int i, h_chroma_shift, v_chroma_shift; + + av_pix_fmt_get_chroma_sub_sample(frame->format, &h_chroma_shift, &v_chroma_shift); + + for(i=0; iheight; i++) + memset(frame->data[0] + frame->linesize[0]*i, 0x80, frame->width); + for(i=0; iheight, v_chroma_shift); i++) { + memset(frame->data[1] + frame->linesize[1]*i, + 0x80, AV_CEIL_RSHIFT(frame->width, h_chroma_shift)); + memset(frame->data[2] + frame->linesize[2]*i, + 0x80, AV_CEIL_RSHIFT(frame->width, h_chroma_shift)); + } +} + +/** + * generic function called after decoding + * the header and before a frame is decoded. + */ +int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx) +{ + int i, ret; + Picture *pic; + s->mb_skipped = 0; + + if (!ff_thread_can_start_frame(avctx)) { + av_log(avctx, AV_LOG_ERROR, "Attempt to start a frame outside SETUP state\n"); + return -1; + } + + /* mark & release old frames */ + if (s->pict_type != AV_PICTURE_TYPE_B && s->last_picture_ptr && + s->last_picture_ptr != s->next_picture_ptr && + s->last_picture_ptr->f->buf[0]) { + ff_mpeg_unref_picture(s->avctx, s->last_picture_ptr); + } + + /* release forgotten pictures */ + /* if (MPEG-124 / H.263) */ + for (i = 0; i < MAX_PICTURE_COUNT; i++) { + if (&s->picture[i] != s->last_picture_ptr && + &s->picture[i] != s->next_picture_ptr && + s->picture[i].reference && !s->picture[i].needs_realloc) { + ff_mpeg_unref_picture(s->avctx, &s->picture[i]); + } + } + + ff_mpeg_unref_picture(s->avctx, &s->current_picture); + ff_mpeg_unref_picture(s->avctx, &s->last_picture); + ff_mpeg_unref_picture(s->avctx, &s->next_picture); + + /* release non reference frames */ + for (i = 0; i < MAX_PICTURE_COUNT; i++) { + if (!s->picture[i].reference) + ff_mpeg_unref_picture(s->avctx, &s->picture[i]); + } + + if (s->current_picture_ptr && !s->current_picture_ptr->f->buf[0]) { + // we already have an unused image + // (maybe it was set before reading the header) + pic = s->current_picture_ptr; + } else { + i = ff_find_unused_picture(s->avctx, s->picture, 0); + if (i < 0) { + av_log(s->avctx, AV_LOG_ERROR, "no frame buffer available\n"); + return i; + } + pic = &s->picture[i]; + } + + pic->reference = 0; + if (!s->droppable) { + if (s->pict_type != AV_PICTURE_TYPE_B) + pic->reference = 3; + } + + pic->f->coded_picture_number = s->coded_picture_number++; + + if (alloc_picture(s, pic, 0) < 0) + return -1; + + s->current_picture_ptr = pic; + // FIXME use only the vars from current_pic + s->current_picture_ptr->f->top_field_first = s->top_field_first; + if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO || + s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + if (s->picture_structure != PICT_FRAME) + s->current_picture_ptr->f->top_field_first = + (s->picture_structure == PICT_TOP_FIELD) == s->first_field; + } + s->current_picture_ptr->f->interlaced_frame = !s->progressive_frame && + !s->progressive_sequence; + s->current_picture_ptr->field_picture = s->picture_structure != PICT_FRAME; + + s->current_picture_ptr->f->pict_type = s->pict_type; + // if (s->avctx->flags && AV_CODEC_FLAG_QSCALE) + // s->current_picture_ptr->quality = s->new_picture_ptr->quality; + s->current_picture_ptr->f->key_frame = s->pict_type == AV_PICTURE_TYPE_I; + + if ((ret = ff_mpeg_ref_picture(s->avctx, &s->current_picture, + s->current_picture_ptr)) < 0) + return ret; + + if (s->pict_type != AV_PICTURE_TYPE_B) { + s->last_picture_ptr = s->next_picture_ptr; + if (!s->droppable) + s->next_picture_ptr = s->current_picture_ptr; + } + ff_dlog(s->avctx, "L%p N%p C%p L%p N%p C%p type:%d drop:%d\n", + s->last_picture_ptr, s->next_picture_ptr,s->current_picture_ptr, + s->last_picture_ptr ? s->last_picture_ptr->f->data[0] : NULL, + s->next_picture_ptr ? s->next_picture_ptr->f->data[0] : NULL, + s->current_picture_ptr ? s->current_picture_ptr->f->data[0] : NULL, + s->pict_type, s->droppable); + + if ((!s->last_picture_ptr || !s->last_picture_ptr->f->buf[0]) && + (s->pict_type != AV_PICTURE_TYPE_I)) { + int h_chroma_shift, v_chroma_shift; + av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, + &h_chroma_shift, &v_chroma_shift); + if (s->pict_type == AV_PICTURE_TYPE_B && s->next_picture_ptr && s->next_picture_ptr->f->buf[0]) + av_log(avctx, AV_LOG_DEBUG, + "allocating dummy last picture for B frame\n"); + else if (s->pict_type != AV_PICTURE_TYPE_I) + av_log(avctx, AV_LOG_ERROR, + "warning: first frame is no keyframe\n"); + + /* Allocate a dummy frame */ + i = ff_find_unused_picture(s->avctx, s->picture, 0); + if (i < 0) { + av_log(s->avctx, AV_LOG_ERROR, "no frame buffer available\n"); + return i; + } + s->last_picture_ptr = &s->picture[i]; + + s->last_picture_ptr->reference = 3; + s->last_picture_ptr->f->key_frame = 0; + s->last_picture_ptr->f->pict_type = AV_PICTURE_TYPE_P; + + if (alloc_picture(s, s->last_picture_ptr, 0) < 0) { + s->last_picture_ptr = NULL; + return -1; + } + + if (!avctx->hwaccel) { + for(i=0; iheight; i++) + memset(s->last_picture_ptr->f->data[0] + s->last_picture_ptr->f->linesize[0]*i, + 0x80, avctx->width); + if (s->last_picture_ptr->f->data[2]) { + for(i=0; iheight, v_chroma_shift); i++) { + memset(s->last_picture_ptr->f->data[1] + s->last_picture_ptr->f->linesize[1]*i, + 0x80, AV_CEIL_RSHIFT(avctx->width, h_chroma_shift)); + memset(s->last_picture_ptr->f->data[2] + s->last_picture_ptr->f->linesize[2]*i, + 0x80, AV_CEIL_RSHIFT(avctx->width, h_chroma_shift)); + } + } + + if(s->codec_id == AV_CODEC_ID_FLV1 || s->codec_id == AV_CODEC_ID_H263){ + for(i=0; iheight; i++) + memset(s->last_picture_ptr->f->data[0] + s->last_picture_ptr->f->linesize[0]*i, 16, avctx->width); + } + } + + ff_thread_report_progress(&s->last_picture_ptr->tf, INT_MAX, 0); + ff_thread_report_progress(&s->last_picture_ptr->tf, INT_MAX, 1); + } + if ((!s->next_picture_ptr || !s->next_picture_ptr->f->buf[0]) && + s->pict_type == AV_PICTURE_TYPE_B) { + /* Allocate a dummy frame */ + i = ff_find_unused_picture(s->avctx, s->picture, 0); + if (i < 0) { + av_log(s->avctx, AV_LOG_ERROR, "no frame buffer available\n"); + return i; + } + s->next_picture_ptr = &s->picture[i]; + + s->next_picture_ptr->reference = 3; + s->next_picture_ptr->f->key_frame = 0; + s->next_picture_ptr->f->pict_type = AV_PICTURE_TYPE_P; + + if (alloc_picture(s, s->next_picture_ptr, 0) < 0) { + s->next_picture_ptr = NULL; + return -1; + } + ff_thread_report_progress(&s->next_picture_ptr->tf, INT_MAX, 0); + ff_thread_report_progress(&s->next_picture_ptr->tf, INT_MAX, 1); + } + +#if 0 // BUFREF-FIXME + memset(s->last_picture.f->data, 0, sizeof(s->last_picture.f->data)); + memset(s->next_picture.f->data, 0, sizeof(s->next_picture.f->data)); +#endif + if (s->last_picture_ptr) { + if (s->last_picture_ptr->f->buf[0] && + (ret = ff_mpeg_ref_picture(s->avctx, &s->last_picture, + s->last_picture_ptr)) < 0) + return ret; + } + if (s->next_picture_ptr) { + if (s->next_picture_ptr->f->buf[0] && + (ret = ff_mpeg_ref_picture(s->avctx, &s->next_picture, + s->next_picture_ptr)) < 0) + return ret; + } + + av_assert0(s->pict_type == AV_PICTURE_TYPE_I || (s->last_picture_ptr && + s->last_picture_ptr->f->buf[0])); + + if (s->picture_structure!= PICT_FRAME) { + int i; + for (i = 0; i < 4; i++) { + if (s->picture_structure == PICT_BOTTOM_FIELD) { + s->current_picture.f->data[i] += + s->current_picture.f->linesize[i]; + } + s->current_picture.f->linesize[i] *= 2; + s->last_picture.f->linesize[i] *= 2; + s->next_picture.f->linesize[i] *= 2; + } + } + + /* set dequantizer, we can't do it during init as + * it might change for MPEG-4 and we can't do it in the header + * decode as init is not called for MPEG-4 there yet */ + if (s->mpeg_quant || s->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + s->dct_unquantize_intra = s->dct_unquantize_mpeg2_intra; + s->dct_unquantize_inter = s->dct_unquantize_mpeg2_inter; + } else if (s->out_format == FMT_H263 || s->out_format == FMT_H261) { + s->dct_unquantize_intra = s->dct_unquantize_h263_intra; + s->dct_unquantize_inter = s->dct_unquantize_h263_inter; + } else { + s->dct_unquantize_intra = s->dct_unquantize_mpeg1_intra; + s->dct_unquantize_inter = s->dct_unquantize_mpeg1_inter; + } + + if (s->avctx->debug & FF_DEBUG_NOMC) { + gray_frame(s->current_picture_ptr->f); + } + + return 0; +} + +/* called after a frame has been decoded. */ +void ff_mpv_frame_end(MpegEncContext *s) +{ + emms_c(); + + if (s->current_picture.reference) + ff_thread_report_progress(&s->current_picture_ptr->tf, INT_MAX, 0); +} + +void ff_print_debug_info(MpegEncContext *s, Picture *p, AVFrame *pict) +{ + ff_print_debug_info2(s->avctx, pict, s->mbskip_table, p->mb_type, + p->qscale_table, p->motion_val, &s->low_delay, + s->mb_width, s->mb_height, s->mb_stride, s->quarter_sample); +} + +int ff_mpv_export_qp_table(MpegEncContext *s, AVFrame *f, Picture *p, int qp_type) +{ + AVBufferRef *ref = av_buffer_ref(p->qscale_table_buf); + int offset = 2*s->mb_stride + 1; + if(!ref) + return AVERROR(ENOMEM); + av_assert0(ref->size >= offset + s->mb_stride * ((f->height+15)/16)); + ref->size -= offset; + ref->data += offset; + return av_frame_set_qp_table(f, ref, s->mb_stride, qp_type); +} + +static inline int hpel_motion_lowres(MpegEncContext *s, + uint8_t *dest, uint8_t *src, + int field_based, int field_select, + int src_x, int src_y, + int width, int height, ptrdiff_t stride, + int h_edge_pos, int v_edge_pos, + int w, int h, h264_chroma_mc_func *pix_op, + int motion_x, int motion_y) +{ + const int lowres = s->avctx->lowres; + const int op_index = FFMIN(lowres, 3); + const int s_mask = (2 << lowres) - 1; + int emu = 0; + int sx, sy; + + if (s->quarter_sample) { + motion_x /= 2; + motion_y /= 2; + } + + sx = motion_x & s_mask; + sy = motion_y & s_mask; + src_x += motion_x >> lowres + 1; + src_y += motion_y >> lowres + 1; + + src += src_y * stride + src_x; + + if ((unsigned)src_x > FFMAX( h_edge_pos - (!!sx) - w, 0) || + (unsigned)src_y > FFMAX((v_edge_pos >> field_based) - (!!sy) - h, 0)) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, src, + s->linesize, s->linesize, + w + 1, (h + 1) << field_based, + src_x, src_y << field_based, + h_edge_pos, v_edge_pos); + src = s->sc.edge_emu_buffer; + emu = 1; + } + + sx = (sx << 2) >> lowres; + sy = (sy << 2) >> lowres; + if (field_select) + src += s->linesize; + pix_op[op_index](dest, src, stride, h, sx, sy); + return emu; +} + +/* apply one mpeg motion vector to the three components */ +static av_always_inline void mpeg_motion_lowres(MpegEncContext *s, + uint8_t *dest_y, + uint8_t *dest_cb, + uint8_t *dest_cr, + int field_based, + int bottom_field, + int field_select, + uint8_t **ref_picture, + h264_chroma_mc_func *pix_op, + int motion_x, int motion_y, + int h, int mb_y) +{ + uint8_t *ptr_y, *ptr_cb, *ptr_cr; + int mx, my, src_x, src_y, uvsrc_x, uvsrc_y, sx, sy, uvsx, uvsy; + ptrdiff_t uvlinesize, linesize; + const int lowres = s->avctx->lowres; + const int op_index = FFMIN(lowres-1+s->chroma_x_shift, 3); + const int block_s = 8>>lowres; + const int s_mask = (2 << lowres) - 1; + const int h_edge_pos = s->h_edge_pos >> lowres; + const int v_edge_pos = s->v_edge_pos >> lowres; + linesize = s->current_picture.f->linesize[0] << field_based; + uvlinesize = s->current_picture.f->linesize[1] << field_based; + + // FIXME obviously not perfect but qpel will not work in lowres anyway + if (s->quarter_sample) { + motion_x /= 2; + motion_y /= 2; + } + + if(field_based){ + motion_y += (bottom_field - field_select)*((1 << lowres)-1); + } + + sx = motion_x & s_mask; + sy = motion_y & s_mask; + src_x = s->mb_x * 2 * block_s + (motion_x >> lowres + 1); + src_y = (mb_y * 2 * block_s >> field_based) + (motion_y >> lowres + 1); + + if (s->out_format == FMT_H263) { + uvsx = ((motion_x >> 1) & s_mask) | (sx & 1); + uvsy = ((motion_y >> 1) & s_mask) | (sy & 1); + uvsrc_x = src_x >> 1; + uvsrc_y = src_y >> 1; + } else if (s->out_format == FMT_H261) { + // even chroma mv's are full pel in H261 + mx = motion_x / 4; + my = motion_y / 4; + uvsx = (2 * mx) & s_mask; + uvsy = (2 * my) & s_mask; + uvsrc_x = s->mb_x * block_s + (mx >> lowres); + uvsrc_y = mb_y * block_s + (my >> lowres); + } else { + if(s->chroma_y_shift){ + mx = motion_x / 2; + my = motion_y / 2; + uvsx = mx & s_mask; + uvsy = my & s_mask; + uvsrc_x = s->mb_x * block_s + (mx >> lowres + 1); + uvsrc_y = (mb_y * block_s >> field_based) + (my >> lowres + 1); + } else { + if(s->chroma_x_shift){ + //Chroma422 + mx = motion_x / 2; + uvsx = mx & s_mask; + uvsy = motion_y & s_mask; + uvsrc_y = src_y; + uvsrc_x = s->mb_x*block_s + (mx >> (lowres+1)); + } else { + //Chroma444 + uvsx = motion_x & s_mask; + uvsy = motion_y & s_mask; + uvsrc_x = src_x; + uvsrc_y = src_y; + } + } + } + + ptr_y = ref_picture[0] + src_y * linesize + src_x; + ptr_cb = ref_picture[1] + uvsrc_y * uvlinesize + uvsrc_x; + ptr_cr = ref_picture[2] + uvsrc_y * uvlinesize + uvsrc_x; + + if ((unsigned) src_x > FFMAX( h_edge_pos - (!!sx) - 2 * block_s, 0) || uvsrc_y<0 || + (unsigned) src_y > FFMAX((v_edge_pos >> field_based) - (!!sy) - h, 0)) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr_y, + linesize >> field_based, linesize >> field_based, + 17, 17 + field_based, + src_x, src_y << field_based, h_edge_pos, + v_edge_pos); + ptr_y = s->sc.edge_emu_buffer; + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + uint8_t *ubuf = s->sc.edge_emu_buffer + 18 * s->linesize; + uint8_t *vbuf =ubuf + 10 * s->uvlinesize; + if (s->workaround_bugs & FF_BUG_IEDGE) + vbuf -= s->uvlinesize; + s->vdsp.emulated_edge_mc(ubuf, ptr_cb, + uvlinesize >> field_based, uvlinesize >> field_based, + 9, 9 + field_based, + uvsrc_x, uvsrc_y << field_based, + h_edge_pos >> 1, v_edge_pos >> 1); + s->vdsp.emulated_edge_mc(vbuf, ptr_cr, + uvlinesize >> field_based,uvlinesize >> field_based, + 9, 9 + field_based, + uvsrc_x, uvsrc_y << field_based, + h_edge_pos >> 1, v_edge_pos >> 1); + ptr_cb = ubuf; + ptr_cr = vbuf; + } + } + + // FIXME use this for field pix too instead of the obnoxious hack which changes picture.f->data + if (bottom_field) { + dest_y += s->linesize; + dest_cb += s->uvlinesize; + dest_cr += s->uvlinesize; + } + + if (field_select) { + ptr_y += s->linesize; + ptr_cb += s->uvlinesize; + ptr_cr += s->uvlinesize; + } + + sx = (sx << 2) >> lowres; + sy = (sy << 2) >> lowres; + pix_op[lowres - 1](dest_y, ptr_y, linesize, h, sx, sy); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + int hc = s->chroma_y_shift ? (h+1-bottom_field)>>1 : h; + uvsx = (uvsx << 2) >> lowres; + uvsy = (uvsy << 2) >> lowres; + if (hc) { + pix_op[op_index](dest_cb, ptr_cb, uvlinesize, hc, uvsx, uvsy); + pix_op[op_index](dest_cr, ptr_cr, uvlinesize, hc, uvsx, uvsy); + } + } + // FIXME h261 lowres loop filter +} + +static inline void chroma_4mv_motion_lowres(MpegEncContext *s, + uint8_t *dest_cb, uint8_t *dest_cr, + uint8_t **ref_picture, + h264_chroma_mc_func * pix_op, + int mx, int my) +{ + const int lowres = s->avctx->lowres; + const int op_index = FFMIN(lowres, 3); + const int block_s = 8 >> lowres; + const int s_mask = (2 << lowres) - 1; + const int h_edge_pos = s->h_edge_pos >> lowres + 1; + const int v_edge_pos = s->v_edge_pos >> lowres + 1; + int emu = 0, src_x, src_y, sx, sy; + ptrdiff_t offset; + uint8_t *ptr; + + if (s->quarter_sample) { + mx /= 2; + my /= 2; + } + + /* In case of 8X8, we construct a single chroma motion vector + with a special rounding */ + mx = ff_h263_round_chroma(mx); + my = ff_h263_round_chroma(my); + + sx = mx & s_mask; + sy = my & s_mask; + src_x = s->mb_x * block_s + (mx >> lowres + 1); + src_y = s->mb_y * block_s + (my >> lowres + 1); + + offset = src_y * s->uvlinesize + src_x; + ptr = ref_picture[1] + offset; + if ((unsigned) src_x > FFMAX(h_edge_pos - (!!sx) - block_s, 0) || + (unsigned) src_y > FFMAX(v_edge_pos - (!!sy) - block_s, 0)) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr, + s->uvlinesize, s->uvlinesize, + 9, 9, + src_x, src_y, h_edge_pos, v_edge_pos); + ptr = s->sc.edge_emu_buffer; + emu = 1; + } + sx = (sx << 2) >> lowres; + sy = (sy << 2) >> lowres; + pix_op[op_index](dest_cb, ptr, s->uvlinesize, block_s, sx, sy); + + ptr = ref_picture[2] + offset; + if (emu) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, ptr, + s->uvlinesize, s->uvlinesize, + 9, 9, + src_x, src_y, h_edge_pos, v_edge_pos); + ptr = s->sc.edge_emu_buffer; + } + pix_op[op_index](dest_cr, ptr, s->uvlinesize, block_s, sx, sy); +} + +/** + * motion compensation of a single macroblock + * @param s context + * @param dest_y luma destination pointer + * @param dest_cb chroma cb/u destination pointer + * @param dest_cr chroma cr/v destination pointer + * @param dir direction (0->forward, 1->backward) + * @param ref_picture array[3] of pointers to the 3 planes of the reference picture + * @param pix_op halfpel motion compensation function (average or put normally) + * the motion vectors are taken from s->mv and the MV type from s->mv_type + */ +static inline void MPV_motion_lowres(MpegEncContext *s, + uint8_t *dest_y, uint8_t *dest_cb, + uint8_t *dest_cr, + int dir, uint8_t **ref_picture, + h264_chroma_mc_func *pix_op) +{ + int mx, my; + int mb_x, mb_y, i; + const int lowres = s->avctx->lowres; + const int block_s = 8 >>lowres; + + mb_x = s->mb_x; + mb_y = s->mb_y; + + switch (s->mv_type) { + case MV_TYPE_16X16: + mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, + 0, 0, 0, + ref_picture, pix_op, + s->mv[dir][0][0], s->mv[dir][0][1], + 2 * block_s, mb_y); + break; + case MV_TYPE_8X8: + mx = 0; + my = 0; + for (i = 0; i < 4; i++) { + hpel_motion_lowres(s, dest_y + ((i & 1) + (i >> 1) * + s->linesize) * block_s, + ref_picture[0], 0, 0, + (2 * mb_x + (i & 1)) * block_s, + (2 * mb_y + (i >> 1)) * block_s, + s->width, s->height, s->linesize, + s->h_edge_pos >> lowres, s->v_edge_pos >> lowres, + block_s, block_s, pix_op, + s->mv[dir][i][0], s->mv[dir][i][1]); + + mx += s->mv[dir][i][0]; + my += s->mv[dir][i][1]; + } + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) + chroma_4mv_motion_lowres(s, dest_cb, dest_cr, ref_picture, + pix_op, mx, my); + break; + case MV_TYPE_FIELD: + if (s->picture_structure == PICT_FRAME) { + /* top field */ + mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, + 1, 0, s->field_select[dir][0], + ref_picture, pix_op, + s->mv[dir][0][0], s->mv[dir][0][1], + block_s, mb_y); + /* bottom field */ + mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, + 1, 1, s->field_select[dir][1], + ref_picture, pix_op, + s->mv[dir][1][0], s->mv[dir][1][1], + block_s, mb_y); + } else { + if (s->picture_structure != s->field_select[dir][0] + 1 && + s->pict_type != AV_PICTURE_TYPE_B && !s->first_field) { + ref_picture = s->current_picture_ptr->f->data; + + } + mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, + 0, 0, s->field_select[dir][0], + ref_picture, pix_op, + s->mv[dir][0][0], + s->mv[dir][0][1], 2 * block_s, mb_y >> 1); + } + break; + case MV_TYPE_16X8: + for (i = 0; i < 2; i++) { + uint8_t **ref2picture; + + if (s->picture_structure == s->field_select[dir][i] + 1 || + s->pict_type == AV_PICTURE_TYPE_B || s->first_field) { + ref2picture = ref_picture; + } else { + ref2picture = s->current_picture_ptr->f->data; + } + + mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, + 0, 0, s->field_select[dir][i], + ref2picture, pix_op, + s->mv[dir][i][0], s->mv[dir][i][1] + + 2 * block_s * i, block_s, mb_y >> 1); + + dest_y += 2 * block_s * s->linesize; + dest_cb += (2 * block_s >> s->chroma_y_shift) * s->uvlinesize; + dest_cr += (2 * block_s >> s->chroma_y_shift) * s->uvlinesize; + } + break; + case MV_TYPE_DMV: + if (s->picture_structure == PICT_FRAME) { + for (i = 0; i < 2; i++) { + int j; + for (j = 0; j < 2; j++) { + mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, + 1, j, j ^ i, + ref_picture, pix_op, + s->mv[dir][2 * i + j][0], + s->mv[dir][2 * i + j][1], + block_s, mb_y); + } + pix_op = s->h264chroma.avg_h264_chroma_pixels_tab; + } + } else { + for (i = 0; i < 2; i++) { + mpeg_motion_lowres(s, dest_y, dest_cb, dest_cr, + 0, 0, s->picture_structure != i + 1, + ref_picture, pix_op, + s->mv[dir][2 * i][0],s->mv[dir][2 * i][1], + 2 * block_s, mb_y >> 1); + + // after put we make avg of the same block + pix_op = s->h264chroma.avg_h264_chroma_pixels_tab; + + // opposite parity is always in the same + // frame if this is second field + if (!s->first_field) { + ref_picture = s->current_picture_ptr->f->data; + } + } + } + break; + default: + av_assert2(0); + } +} + +/** + * find the lowest MB row referenced in the MVs + */ +static int lowest_referenced_row(MpegEncContext *s, int dir) +{ + int my_max = INT_MIN, my_min = INT_MAX, qpel_shift = !s->quarter_sample; + int my, off, i, mvs; + + if (s->picture_structure != PICT_FRAME || s->mcsel) + goto unhandled; + + switch (s->mv_type) { + case MV_TYPE_16X16: + mvs = 1; + break; + case MV_TYPE_16X8: + mvs = 2; + break; + case MV_TYPE_8X8: + mvs = 4; + break; + default: + goto unhandled; + } + + for (i = 0; i < mvs; i++) { + my = s->mv[dir][i][1]; + my_max = FFMAX(my_max, my); + my_min = FFMIN(my_min, my); + } + + off = ((FFMAX(-my_min, my_max)<> 6; + + return av_clip(s->mb_y + off, 0, s->mb_height - 1); +unhandled: + return s->mb_height-1; +} + +/* put block[] to dest[] */ +static inline void put_dct(MpegEncContext *s, + int16_t *block, int i, uint8_t *dest, int line_size, int qscale) +{ + s->dct_unquantize_intra(s, block, i, qscale); + s->idsp.idct_put(dest, line_size, block); +} + +/* add block[] to dest[] */ +static inline void add_dct(MpegEncContext *s, + int16_t *block, int i, uint8_t *dest, int line_size) +{ + if (s->block_last_index[i] >= 0) { + s->idsp.idct_add(dest, line_size, block); + } +} + +static inline void add_dequant_dct(MpegEncContext *s, + int16_t *block, int i, uint8_t *dest, int line_size, int qscale) +{ + if (s->block_last_index[i] >= 0) { + s->dct_unquantize_inter(s, block, i, qscale); + + s->idsp.idct_add(dest, line_size, block); + } +} + +/** + * Clean dc, ac, coded_block for the current non-intra MB. + */ +void ff_clean_intra_table_entries(MpegEncContext *s) +{ + int wrap = s->b8_stride; + int xy = s->block_index[0]; + + s->dc_val[0][xy ] = + s->dc_val[0][xy + 1 ] = + s->dc_val[0][xy + wrap] = + s->dc_val[0][xy + 1 + wrap] = 1024; + /* ac pred */ + memset(s->ac_val[0][xy ], 0, 32 * sizeof(int16_t)); + memset(s->ac_val[0][xy + wrap], 0, 32 * sizeof(int16_t)); + if (s->msmpeg4_version>=3) { + s->coded_block[xy ] = + s->coded_block[xy + 1 ] = + s->coded_block[xy + wrap] = + s->coded_block[xy + 1 + wrap] = 0; + } + /* chroma */ + wrap = s->mb_stride; + xy = s->mb_x + s->mb_y * wrap; + s->dc_val[1][xy] = + s->dc_val[2][xy] = 1024; + /* ac pred */ + memset(s->ac_val[1][xy], 0, 16 * sizeof(int16_t)); + memset(s->ac_val[2][xy], 0, 16 * sizeof(int16_t)); + + s->mbintra_table[xy]= 0; +} + +/* generic function called after a macroblock has been parsed by the + decoder or after it has been encoded by the encoder. + + Important variables used: + s->mb_intra : true if intra macroblock + s->mv_dir : motion vector direction + s->mv_type : motion vector type + s->mv : motion vector + s->interlaced_dct : true if interlaced dct used (mpeg2) + */ +static av_always_inline +void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], + int lowres_flag, int is_mpeg12) +{ + const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; + + if (CONFIG_XVMC && + s->avctx->hwaccel && s->avctx->hwaccel->decode_mb) { + s->avctx->hwaccel->decode_mb(s);//xvmc uses pblocks + return; + } + + if(s->avctx->debug&FF_DEBUG_DCT_COEFF) { + /* print DCT coefficients */ + int i,j; + av_log(s->avctx, AV_LOG_DEBUG, "DCT coeffs of MB at %dx%d:\n", s->mb_x, s->mb_y); + for(i=0; i<6; i++){ + for(j=0; j<64; j++){ + av_log(s->avctx, AV_LOG_DEBUG, "%5d", + block[i][s->idsp.idct_permutation[j]]); + } + av_log(s->avctx, AV_LOG_DEBUG, "\n"); + } + } + + s->current_picture.qscale_table[mb_xy] = s->qscale; + + /* update DC predictors for P macroblocks */ + if (!s->mb_intra) { + if (!is_mpeg12 && (s->h263_pred || s->h263_aic)) { + if(s->mbintra_table[mb_xy]) + ff_clean_intra_table_entries(s); + } else { + s->last_dc[0] = + s->last_dc[1] = + s->last_dc[2] = 128 << s->intra_dc_precision; + } + } + else if (!is_mpeg12 && (s->h263_pred || s->h263_aic)) + s->mbintra_table[mb_xy]=1; + + if ((s->avctx->flags & AV_CODEC_FLAG_PSNR) || s->frame_skip_threshold || s->frame_skip_factor || + !(s->encoding && (s->intra_only || s->pict_type == AV_PICTURE_TYPE_B) && + s->avctx->mb_decision != FF_MB_DECISION_RD)) { // FIXME precalc + uint8_t *dest_y, *dest_cb, *dest_cr; + int dct_linesize, dct_offset; + op_pixels_func (*op_pix)[4]; + qpel_mc_func (*op_qpix)[16]; + const int linesize = s->current_picture.f->linesize[0]; //not s->linesize as this would be wrong for field pics + const int uvlinesize = s->current_picture.f->linesize[1]; + const int readable= s->pict_type != AV_PICTURE_TYPE_B || s->encoding || s->avctx->draw_horiz_band || lowres_flag; + const int block_size= lowres_flag ? 8>>s->avctx->lowres : 8; + + /* avoid copy if macroblock skipped in last frame too */ + /* skip only during decoding as we might trash the buffers during encoding a bit */ + if(!s->encoding){ + uint8_t *mbskip_ptr = &s->mbskip_table[mb_xy]; + + if (s->mb_skipped) { + s->mb_skipped= 0; + av_assert2(s->pict_type!=AV_PICTURE_TYPE_I); + *mbskip_ptr = 1; + } else if(!s->current_picture.reference) { + *mbskip_ptr = 1; + } else{ + *mbskip_ptr = 0; /* not skipped */ + } + } + + dct_linesize = linesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? linesize : linesize * block_size; + + if(readable){ + dest_y= s->dest[0]; + dest_cb= s->dest[1]; + dest_cr= s->dest[2]; + }else{ + dest_y = s->sc.b_scratchpad; + dest_cb= s->sc.b_scratchpad+16*linesize; + dest_cr= s->sc.b_scratchpad+32*linesize; + } + + if (!s->mb_intra) { + /* motion handling */ + /* decoding or more than one mb_type (MC was already done otherwise) */ + if(!s->encoding){ + + if(HAVE_THREADS && s->avctx->active_thread_type&FF_THREAD_FRAME) { + if (s->mv_dir & MV_DIR_FORWARD) { + ff_thread_await_progress(&s->last_picture_ptr->tf, + lowest_referenced_row(s, 0), + 0); + } + if (s->mv_dir & MV_DIR_BACKWARD) { + ff_thread_await_progress(&s->next_picture_ptr->tf, + lowest_referenced_row(s, 1), + 0); + } + } + + if(lowres_flag){ + h264_chroma_mc_func *op_pix = s->h264chroma.put_h264_chroma_pixels_tab; + + if (s->mv_dir & MV_DIR_FORWARD) { + MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 0, s->last_picture.f->data, op_pix); + op_pix = s->h264chroma.avg_h264_chroma_pixels_tab; + } + if (s->mv_dir & MV_DIR_BACKWARD) { + MPV_motion_lowres(s, dest_y, dest_cb, dest_cr, 1, s->next_picture.f->data, op_pix); + } + }else{ + op_qpix = s->me.qpel_put; + if ((!s->no_rounding) || s->pict_type==AV_PICTURE_TYPE_B){ + op_pix = s->hdsp.put_pixels_tab; + }else{ + op_pix = s->hdsp.put_no_rnd_pixels_tab; + } + if (s->mv_dir & MV_DIR_FORWARD) { + ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 0, s->last_picture.f->data, op_pix, op_qpix); + op_pix = s->hdsp.avg_pixels_tab; + op_qpix= s->me.qpel_avg; + } + if (s->mv_dir & MV_DIR_BACKWARD) { + ff_mpv_motion(s, dest_y, dest_cb, dest_cr, 1, s->next_picture.f->data, op_pix, op_qpix); + } + } + } + + /* skip dequant / idct if we are really late ;) */ + if(s->avctx->skip_idct){ + if( (s->avctx->skip_idct >= AVDISCARD_NONREF && s->pict_type == AV_PICTURE_TYPE_B) + ||(s->avctx->skip_idct >= AVDISCARD_NONKEY && s->pict_type != AV_PICTURE_TYPE_I) + || s->avctx->skip_idct >= AVDISCARD_ALL) + goto skip_idct; + } + + /* add dct residue */ + if(s->encoding || !( s->msmpeg4_version || s->codec_id==AV_CODEC_ID_MPEG1VIDEO || s->codec_id==AV_CODEC_ID_MPEG2VIDEO + || (s->codec_id==AV_CODEC_ID_MPEG4 && !s->mpeg_quant))){ + add_dequant_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); + add_dequant_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); + add_dequant_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); + add_dequant_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + if (s->chroma_y_shift){ + add_dequant_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); + add_dequant_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); + }else{ + dct_linesize >>= 1; + dct_offset >>=1; + add_dequant_dct(s, block[4], 4, dest_cb, dct_linesize, s->chroma_qscale); + add_dequant_dct(s, block[5], 5, dest_cr, dct_linesize, s->chroma_qscale); + add_dequant_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->chroma_qscale); + add_dequant_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->chroma_qscale); + } + } + } else if(is_mpeg12 || (s->codec_id != AV_CODEC_ID_WMV2)){ + add_dct(s, block[0], 0, dest_y , dct_linesize); + add_dct(s, block[1], 1, dest_y + block_size, dct_linesize); + add_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize); + add_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + if(s->chroma_y_shift){//Chroma420 + add_dct(s, block[4], 4, dest_cb, uvlinesize); + add_dct(s, block[5], 5, dest_cr, uvlinesize); + }else{ + //chroma422 + dct_linesize = uvlinesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + + add_dct(s, block[4], 4, dest_cb, dct_linesize); + add_dct(s, block[5], 5, dest_cr, dct_linesize); + add_dct(s, block[6], 6, dest_cb+dct_offset, dct_linesize); + add_dct(s, block[7], 7, dest_cr+dct_offset, dct_linesize); + if(!s->chroma_x_shift){//Chroma444 + add_dct(s, block[8], 8, dest_cb+block_size, dct_linesize); + add_dct(s, block[9], 9, dest_cr+block_size, dct_linesize); + add_dct(s, block[10], 10, dest_cb+block_size+dct_offset, dct_linesize); + add_dct(s, block[11], 11, dest_cr+block_size+dct_offset, dct_linesize); + } + } + }//fi gray + } + else if (CONFIG_WMV2_DECODER || CONFIG_WMV2_ENCODER) { + ff_wmv2_add_mb(s, block, dest_y, dest_cb, dest_cr); + } + } else { + /* Only MPEG-4 Simple Studio Profile is supported in > 8-bit mode. + TODO: Integrate 10-bit properly into mpegvideo.c so that ER works properly */ + if (s->avctx->bits_per_raw_sample > 8){ + const int act_block_size = block_size * 2; + + if(s->dpcm_direction == 0) { + s->idsp.idct_put(dest_y, dct_linesize, (int16_t*)(*s->block32)[0]); + s->idsp.idct_put(dest_y + act_block_size, dct_linesize, (int16_t*)(*s->block32)[1]); + s->idsp.idct_put(dest_y + dct_offset, dct_linesize, (int16_t*)(*s->block32)[2]); + s->idsp.idct_put(dest_y + dct_offset + act_block_size, dct_linesize, (int16_t*)(*s->block32)[3]); + + dct_linesize = uvlinesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + + s->idsp.idct_put(dest_cb, dct_linesize, (int16_t*)(*s->block32)[4]); + s->idsp.idct_put(dest_cr, dct_linesize, (int16_t*)(*s->block32)[5]); + s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, (int16_t*)(*s->block32)[6]); + s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, (int16_t*)(*s->block32)[7]); + if(!s->chroma_x_shift){//Chroma444 + s->idsp.idct_put(dest_cb + act_block_size, dct_linesize, (int16_t*)(*s->block32)[8]); + s->idsp.idct_put(dest_cr + act_block_size, dct_linesize, (int16_t*)(*s->block32)[9]); + s->idsp.idct_put(dest_cb + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[10]); + s->idsp.idct_put(dest_cr + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[11]); + } + } else if(s->dpcm_direction == 1) { + int i, w, h; + uint16_t *dest_pcm[3] = {(uint16_t*)dest_y, (uint16_t*)dest_cb, (uint16_t*)dest_cr}; + int linesize[3] = {dct_linesize, uvlinesize, uvlinesize}; + for(i = 0; i < 3; i++) { + int idx = 0; + int vsub = i ? s->chroma_y_shift : 0; + int hsub = i ? s->chroma_x_shift : 0; + for(h = 0; h < (16 >> vsub); h++){ + for(w = 0; w < (16 >> hsub); w++) + dest_pcm[i][w] = (*s->dpcm_macroblock)[i][idx++]; + dest_pcm[i] += linesize[i] / 2; + } + } + } else if(s->dpcm_direction == -1) { + int i, w, h; + uint16_t *dest_pcm[3] = {(uint16_t*)dest_y, (uint16_t*)dest_cb, (uint16_t*)dest_cr}; + int linesize[3] = {dct_linesize, uvlinesize, uvlinesize}; + for(i = 0; i < 3; i++) { + int idx = 0; + int vsub = i ? s->chroma_y_shift : 0; + int hsub = i ? s->chroma_x_shift : 0; + dest_pcm[i] += (linesize[i] / 2) * ((16 >> vsub) - 1); + for(h = (16 >> vsub)-1; h >= 1; h--){ + for(w = (16 >> hsub)-1; w >= 1; w--) + dest_pcm[i][w] = (*s->dpcm_macroblock)[i][idx++]; + dest_pcm[i] -= linesize[i] / 2; + } + } + } + } + /* dct only in intra block */ + else if(s->encoding || !(s->codec_id==AV_CODEC_ID_MPEG1VIDEO || s->codec_id==AV_CODEC_ID_MPEG2VIDEO)){ + put_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); + put_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); + put_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); + put_dct(s, block[3], 3, dest_y + dct_offset + block_size, dct_linesize, s->qscale); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + if(s->chroma_y_shift){ + put_dct(s, block[4], 4, dest_cb, uvlinesize, s->chroma_qscale); + put_dct(s, block[5], 5, dest_cr, uvlinesize, s->chroma_qscale); + }else{ + dct_offset >>=1; + dct_linesize >>=1; + put_dct(s, block[4], 4, dest_cb, dct_linesize, s->chroma_qscale); + put_dct(s, block[5], 5, dest_cr, dct_linesize, s->chroma_qscale); + put_dct(s, block[6], 6, dest_cb + dct_offset, dct_linesize, s->chroma_qscale); + put_dct(s, block[7], 7, dest_cr + dct_offset, dct_linesize, s->chroma_qscale); + } + } + }else{ + s->idsp.idct_put(dest_y, dct_linesize, block[0]); + s->idsp.idct_put(dest_y + block_size, dct_linesize, block[1]); + s->idsp.idct_put(dest_y + dct_offset, dct_linesize, block[2]); + s->idsp.idct_put(dest_y + dct_offset + block_size, dct_linesize, block[3]); + + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + if(s->chroma_y_shift){ + s->idsp.idct_put(dest_cb, uvlinesize, block[4]); + s->idsp.idct_put(dest_cr, uvlinesize, block[5]); + }else{ + + dct_linesize = uvlinesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + + s->idsp.idct_put(dest_cb, dct_linesize, block[4]); + s->idsp.idct_put(dest_cr, dct_linesize, block[5]); + s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, block[6]); + s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, block[7]); + if(!s->chroma_x_shift){//Chroma444 + s->idsp.idct_put(dest_cb + block_size, dct_linesize, block[8]); + s->idsp.idct_put(dest_cr + block_size, dct_linesize, block[9]); + s->idsp.idct_put(dest_cb + block_size + dct_offset, dct_linesize, block[10]); + s->idsp.idct_put(dest_cr + block_size + dct_offset, dct_linesize, block[11]); + } + } + }//gray + } + } +skip_idct: + if(!readable){ + s->hdsp.put_pixels_tab[0][0](s->dest[0], dest_y , linesize,16); + if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { + s->hdsp.put_pixels_tab[s->chroma_x_shift][0](s->dest[1], dest_cb, uvlinesize,16 >> s->chroma_y_shift); + s->hdsp.put_pixels_tab[s->chroma_x_shift][0](s->dest[2], dest_cr, uvlinesize,16 >> s->chroma_y_shift); + } + } + } +} + +void ff_mpv_reconstruct_mb(MpegEncContext *s, int16_t block[12][64]) +{ +#if !CONFIG_SMALL + if(s->out_format == FMT_MPEG1) { + if(s->avctx->lowres) mpv_reconstruct_mb_internal(s, block, 1, 1); + else mpv_reconstruct_mb_internal(s, block, 0, 1); + } else +#endif + if(s->avctx->lowres) mpv_reconstruct_mb_internal(s, block, 1, 0); + else mpv_reconstruct_mb_internal(s, block, 0, 0); +} + +void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h) +{ + ff_draw_horiz_band(s->avctx, s->current_picture_ptr->f, + s->last_picture_ptr ? s->last_picture_ptr->f : NULL, y, h, s->picture_structure, + s->first_field, s->low_delay); +} + +void ff_init_block_index(MpegEncContext *s){ //FIXME maybe rename + const int linesize = s->current_picture.f->linesize[0]; //not s->linesize as this would be wrong for field pics + const int uvlinesize = s->current_picture.f->linesize[1]; + const int width_of_mb = (4 + (s->avctx->bits_per_raw_sample > 8)) - s->avctx->lowres; + const int height_of_mb = 4 - s->avctx->lowres; + + s->block_index[0]= s->b8_stride*(s->mb_y*2 ) - 2 + s->mb_x*2; + s->block_index[1]= s->b8_stride*(s->mb_y*2 ) - 1 + s->mb_x*2; + s->block_index[2]= s->b8_stride*(s->mb_y*2 + 1) - 2 + s->mb_x*2; + s->block_index[3]= s->b8_stride*(s->mb_y*2 + 1) - 1 + s->mb_x*2; + s->block_index[4]= s->mb_stride*(s->mb_y + 1) + s->b8_stride*s->mb_height*2 + s->mb_x - 1; + s->block_index[5]= s->mb_stride*(s->mb_y + s->mb_height + 2) + s->b8_stride*s->mb_height*2 + s->mb_x - 1; + //block_index is not used by mpeg2, so it is not affected by chroma_format + + s->dest[0] = s->current_picture.f->data[0] + (int)((s->mb_x - 1U) << width_of_mb); + s->dest[1] = s->current_picture.f->data[1] + (int)((s->mb_x - 1U) << (width_of_mb - s->chroma_x_shift)); + s->dest[2] = s->current_picture.f->data[2] + (int)((s->mb_x - 1U) << (width_of_mb - s->chroma_x_shift)); + + if(!(s->pict_type==AV_PICTURE_TYPE_B && s->avctx->draw_horiz_band && s->picture_structure==PICT_FRAME)) + { + if(s->picture_structure==PICT_FRAME){ + s->dest[0] += s->mb_y * linesize << height_of_mb; + s->dest[1] += s->mb_y * uvlinesize << (height_of_mb - s->chroma_y_shift); + s->dest[2] += s->mb_y * uvlinesize << (height_of_mb - s->chroma_y_shift); + }else{ + s->dest[0] += (s->mb_y>>1) * linesize << height_of_mb; + s->dest[1] += (s->mb_y>>1) * uvlinesize << (height_of_mb - s->chroma_y_shift); + s->dest[2] += (s->mb_y>>1) * uvlinesize << (height_of_mb - s->chroma_y_shift); + av_assert1((s->mb_y&1) == (s->picture_structure == PICT_BOTTOM_FIELD)); + } + } +} + +void ff_mpeg_flush(AVCodecContext *avctx){ + int i; + MpegEncContext *s = avctx->priv_data; + + if (!s || !s->picture) + return; + + for (i = 0; i < MAX_PICTURE_COUNT; i++) + ff_mpeg_unref_picture(s->avctx, &s->picture[i]); + s->current_picture_ptr = s->last_picture_ptr = s->next_picture_ptr = NULL; + + ff_mpeg_unref_picture(s->avctx, &s->current_picture); + ff_mpeg_unref_picture(s->avctx, &s->last_picture); + ff_mpeg_unref_picture(s->avctx, &s->next_picture); + + s->mb_x= s->mb_y= 0; + s->closed_gop= 0; + + s->parse_context.state= -1; + s->parse_context.frame_start_found= 0; + s->parse_context.overread= 0; + s->parse_context.overread_index= 0; + s->parse_context.index= 0; + s->parse_context.last_index= 0; + s->bitstream_buffer_size=0; + s->pp_time=0; +} + +/** + * set qscale and update qscale dependent variables. + */ +void ff_set_qscale(MpegEncContext * s, int qscale) +{ + if (qscale < 1) + qscale = 1; + else if (qscale > 31) + qscale = 31; + + s->qscale = qscale; + s->chroma_qscale= s->chroma_qscale_table[qscale]; + + s->y_dc_scale= s->y_dc_scale_table[ qscale ]; + s->c_dc_scale= s->c_dc_scale_table[ s->chroma_qscale ]; +} + +void ff_mpv_report_decode_progress(MpegEncContext *s) +{ + if (s->pict_type != AV_PICTURE_TYPE_B && !s->partitioned_frame && !s->er.error_occurred) + ff_thread_report_progress(&s->current_picture_ptr->tf, s->mb_y, 0); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideo.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideo.h new file mode 100644 index 0000000000..e1ff5f97dc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideo.h @@ -0,0 +1,770 @@ +/* + * Generic DCT based hybrid video encoder + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * mpegvideo header. + */ + +#ifndef AVCODEC_MPEGVIDEO_H +#define AVCODEC_MPEGVIDEO_H + +#include + +#include "avcodec.h" +#include "blockdsp.h" +#include "error_resilience.h" +#include "fdctdsp.h" +#include "get_bits.h" +#include "h264chroma.h" +#include "h263dsp.h" +#include "hpeldsp.h" +#include "idctdsp.h" +#include "internal.h" +#include "me_cmp.h" +#include "motion_est.h" +#include "mpegpicture.h" +#include "mpegvideodsp.h" +#include "mpegvideoencdsp.h" +#include "mpegvideodata.h" +#include "pixblockdsp.h" +#include "put_bits.h" +#include "ratecontrol.h" +#include "parser.h" +#include "mpegutils.h" +#include "mpeg12data.h" +#include "qpeldsp.h" +#include "thread.h" +#include "videodsp.h" + +#include "libavutil/opt.h" +#include "libavutil/timecode.h" + +#define MAX_THREADS 32 + +#define MAX_B_FRAMES 16 + +/* Start codes. */ +#define SEQ_END_CODE 0x000001b7 +#define SEQ_START_CODE 0x000001b3 +#define GOP_START_CODE 0x000001b8 +#define PICTURE_START_CODE 0x00000100 +#define SLICE_MIN_START_CODE 0x00000101 +#define SLICE_MAX_START_CODE 0x000001af +#define EXT_START_CODE 0x000001b5 +#define USER_START_CODE 0x000001b2 +#define SLICE_START_CODE 0x000001b7 + + +/** + * MpegEncContext. + */ +typedef struct MpegEncContext { + AVClass *class; + + int y_dc_scale, c_dc_scale; + int ac_pred; + int block_last_index[12]; ///< last non zero coefficient in block + int h263_aic; ///< Advanced INTRA Coding (AIC) + + /* scantables */ + ScanTable inter_scantable; ///< if inter == intra then intra should be used to reduce the cache usage + ScanTable intra_scantable; + ScanTable intra_h_scantable; + ScanTable intra_v_scantable; + + /* WARNING: changes above this line require updates to hardcoded + * offsets used in ASM. */ + + struct AVCodecContext *avctx; + /* the following parameters must be initialized before encoding */ + int width, height;///< picture size. must be a multiple of 16 + int gop_size; + int intra_only; ///< if true, only intra pictures are generated + int64_t bit_rate; ///< wanted bit rate + enum OutputFormat out_format; ///< output format + int h263_pred; ///< use MPEG-4/H.263 ac/dc predictions + int pb_frame; ///< PB-frame mode (0 = none, 1 = base, 2 = improved) + +/* the following codec id fields are deprecated in favor of codec_id */ + int h263_plus; ///< H.263+ headers + int h263_flv; ///< use flv H.263 header + + enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ + int fixed_qscale; ///< fixed qscale if non zero + int encoding; ///< true if we are encoding (vs decoding) + int max_b_frames; ///< max number of B-frames for encoding + int luma_elim_threshold; + int chroma_elim_threshold; + int strict_std_compliance; ///< strictly follow the std (MPEG-4, ...) + int workaround_bugs; ///< workaround bugs in encoders which cannot be detected automatically + int codec_tag; ///< internal codec_tag upper case converted from avctx codec_tag + /* the following fields are managed internally by the encoder */ + + /* sequence parameters */ + int context_initialized; + int input_picture_number; ///< used to set pic->display_picture_number, should not be used for/by anything else + int coded_picture_number; ///< used to set pic->coded_picture_number, should not be used for/by anything else + int picture_number; //FIXME remove, unclear definition + int picture_in_gop_number; ///< 0-> first pic in gop, ... + int mb_width, mb_height; ///< number of MBs horizontally & vertically + int mb_stride; ///< mb_width+1 used for some arrays to allow simple addressing of left & top MBs without sig11 + int b8_stride; ///< 2*mb_width+1 used for some 8x8 block arrays to allow simple addressing + int h_edge_pos, v_edge_pos;///< horizontal / vertical position of the right/bottom edge (pixel replication) + int mb_num; ///< number of MBs of a picture + ptrdiff_t linesize; ///< line size, in bytes, may be different from width + ptrdiff_t uvlinesize; ///< line size, for chroma in bytes, may be different from width + Picture *picture; ///< main picture buffer + Picture **input_picture; ///< next pictures on display order for encoding + Picture **reordered_input_picture; ///< pointer to the next pictures in coded order for encoding + + int64_t user_specified_pts; ///< last non-zero pts from AVFrame which was passed into avcodec_encode_video2() + /** + * pts difference between the first and second input frame, used for + * calculating dts of the first frame when there's a delay */ + int64_t dts_delta; + /** + * reordered pts to be used as dts for the next output frame when there's + * a delay */ + int64_t reordered_pts; + + /** bit output */ + PutBitContext pb; + + int start_mb_y; ///< start mb_y of this thread (so current thread should process start_mb_y <= row < end_mb_y) + int end_mb_y; ///< end mb_y of this thread (so current thread should process start_mb_y <= row < end_mb_y) + struct MpegEncContext *thread_context[MAX_THREADS]; + int slice_context_count; ///< number of used thread_contexts + + /** + * copy of the previous picture structure. + * note, linesize & data, might not match the previous picture (for field pictures) + */ + Picture last_picture; + + /** + * copy of the next picture structure. + * note, linesize & data, might not match the next picture (for field pictures) + */ + Picture next_picture; + + /** + * copy of the source picture structure for encoding. + * note, linesize & data, might not match the source picture (for field pictures) + */ + Picture new_picture; + + /** + * copy of the current picture structure. + * note, linesize & data, might not match the current picture (for field pictures) + */ + Picture current_picture; ///< buffer to store the decompressed current picture + + Picture *last_picture_ptr; ///< pointer to the previous picture. + Picture *next_picture_ptr; ///< pointer to the next picture (for bidir pred) + Picture *current_picture_ptr; ///< pointer to the current picture + int last_dc[3]; ///< last DC values for MPEG-1 + int16_t *dc_val_base; + int16_t *dc_val[3]; ///< used for MPEG-4 DC prediction, all 3 arrays must be continuous + const uint8_t *y_dc_scale_table; ///< qscale -> y_dc_scale table + const uint8_t *c_dc_scale_table; ///< qscale -> c_dc_scale table + const uint8_t *chroma_qscale_table; ///< qscale -> chroma_qscale (H.263) + uint8_t *coded_block_base; + uint8_t *coded_block; ///< used for coded block pattern prediction (msmpeg4v3, wmv1) + int16_t (*ac_val_base)[16]; + int16_t (*ac_val[3])[16]; ///< used for MPEG-4 AC prediction, all 3 arrays must be continuous + int mb_skipped; ///< MUST BE SET only during DECODING + uint8_t *mbskip_table; /**< used to avoid copy if macroblock skipped (for black regions for example) + and used for B-frame encoding & decoding (contains skip table of next P-frame) */ + uint8_t *mbintra_table; ///< used to avoid setting {ac, dc, cbp}-pred stuff to zero on inter MB decoding + uint8_t *cbp_table; ///< used to store cbp, ac_pred for partitioned decoding + uint8_t *pred_dir_table; ///< used to store pred_dir for partitioned decoding + + ScratchpadContext sc; + + int qscale; ///< QP + int chroma_qscale; ///< chroma QP + unsigned int lambda; ///< Lagrange multiplier used in rate distortion + unsigned int lambda2; ///< (lambda*lambda) >> FF_LAMBDA_SHIFT + int *lambda_table; + int adaptive_quant; ///< use adaptive quantization + int dquant; ///< qscale difference to prev qscale + int closed_gop; ///< MPEG1/2 GOP is closed + int pict_type; ///< AV_PICTURE_TYPE_I, AV_PICTURE_TYPE_P, AV_PICTURE_TYPE_B, ... + int vbv_delay; + int last_pict_type; //FIXME removes + int last_non_b_pict_type; ///< used for MPEG-4 gmc B-frames & ratecontrol + int droppable; + int frame_rate_index; + AVRational mpeg2_frame_rate_ext; + int last_lambda_for[5]; ///< last lambda for a specific pict type + int skipdct; ///< skip dct and code zero residual + + /* motion compensation */ + int unrestricted_mv; ///< mv can point outside of the coded picture + int h263_long_vectors; ///< use horrible H.263v1 long vector mode + + BlockDSPContext bdsp; + FDCTDSPContext fdsp; + H264ChromaContext h264chroma; + HpelDSPContext hdsp; + IDCTDSPContext idsp; + MECmpContext mecc; + MpegVideoDSPContext mdsp; + MpegvideoEncDSPContext mpvencdsp; + PixblockDSPContext pdsp; + QpelDSPContext qdsp; + VideoDSPContext vdsp; + H263DSPContext h263dsp; + int f_code; ///< forward MV resolution + int b_code; ///< backward MV resolution for B-frames (MPEG-4) + int16_t (*p_mv_table_base)[2]; + int16_t (*b_forw_mv_table_base)[2]; + int16_t (*b_back_mv_table_base)[2]; + int16_t (*b_bidir_forw_mv_table_base)[2]; + int16_t (*b_bidir_back_mv_table_base)[2]; + int16_t (*b_direct_mv_table_base)[2]; + int16_t (*p_field_mv_table_base[2][2])[2]; + int16_t (*b_field_mv_table_base[2][2][2])[2]; + int16_t (*p_mv_table)[2]; ///< MV table (1MV per MB) P-frame encoding + int16_t (*b_forw_mv_table)[2]; ///< MV table (1MV per MB) forward mode B-frame encoding + int16_t (*b_back_mv_table)[2]; ///< MV table (1MV per MB) backward mode B-frame encoding + int16_t (*b_bidir_forw_mv_table)[2]; ///< MV table (1MV per MB) bidir mode B-frame encoding + int16_t (*b_bidir_back_mv_table)[2]; ///< MV table (1MV per MB) bidir mode B-frame encoding + int16_t (*b_direct_mv_table)[2]; ///< MV table (1MV per MB) direct mode B-frame encoding + int16_t (*p_field_mv_table[2][2])[2]; ///< MV table (2MV per MB) interlaced P-frame encoding + int16_t (*b_field_mv_table[2][2][2])[2];///< MV table (4MV per MB) interlaced B-frame encoding + uint8_t (*p_field_select_table[2]); + uint8_t (*b_field_select_table[2][2]); + int motion_est; ///< ME algorithm + int me_penalty_compensation; + int me_pre; ///< prepass for motion estimation + int mv_dir; +#define MV_DIR_FORWARD 1 +#define MV_DIR_BACKWARD 2 +#define MV_DIRECT 4 ///< bidirectional mode where the difference equals the MV of the last P/S/I-Frame (MPEG-4) + int mv_type; +#define MV_TYPE_16X16 0 ///< 1 vector for the whole mb +#define MV_TYPE_8X8 1 ///< 4 vectors (H.263, MPEG-4 4MV) +#define MV_TYPE_16X8 2 ///< 2 vectors, one per 16x8 block +#define MV_TYPE_FIELD 3 ///< 2 vectors, one per field +#define MV_TYPE_DMV 4 ///< 2 vectors, special mpeg2 Dual Prime Vectors + /**motion vectors for a macroblock + first coordinate : 0 = forward 1 = backward + second " : depend on type + third " : 0 = x, 1 = y + */ + int mv[2][4][2]; + int field_select[2][2]; + int last_mv[2][2][2]; ///< last MV, used for MV prediction in MPEG-1 & B-frame MPEG-4 + uint8_t *fcode_tab; ///< smallest fcode needed for each MV + int16_t direct_scale_mv[2][64]; ///< precomputed to avoid divisions in ff_mpeg4_set_direct_mv + + MotionEstContext me; + + int no_rounding; /**< apply no rounding to motion compensation (MPEG-4, msmpeg4, ...) + for B-frames rounding mode is always 0 */ + + /* macroblock layer */ + int mb_x, mb_y; + int mb_skip_run; + int mb_intra; + uint16_t *mb_type; ///< Table for candidate MB types for encoding (defines in mpegutils.h) + + int block_index[6]; ///< index to current MB in block based arrays with edges + int block_wrap[6]; + uint8_t *dest[3]; + + int *mb_index2xy; ///< mb_index -> mb_x + mb_y*mb_stride + + /** matrix transmitted in the bitstream */ + uint16_t intra_matrix[64]; + uint16_t chroma_intra_matrix[64]; + uint16_t inter_matrix[64]; + uint16_t chroma_inter_matrix[64]; + int force_duplicated_matrix; ///< Force duplication of mjpeg matrices, useful for rtp streaming + + int intra_quant_bias; ///< bias for the quantizer + int inter_quant_bias; ///< bias for the quantizer + int min_qcoeff; ///< minimum encodable coefficient + int max_qcoeff; ///< maximum encodable coefficient + int ac_esc_length; ///< num of bits needed to encode the longest esc + uint8_t *intra_ac_vlc_length; + uint8_t *intra_ac_vlc_last_length; + uint8_t *intra_chroma_ac_vlc_length; + uint8_t *intra_chroma_ac_vlc_last_length; + uint8_t *inter_ac_vlc_length; + uint8_t *inter_ac_vlc_last_length; + uint8_t *luma_dc_vlc_length; +#define UNI_AC_ENC_INDEX(run,level) ((run)*128 + (level)) + + int coded_score[12]; + + /** precomputed matrix (combine qscale and DCT renorm) */ + int (*q_intra_matrix)[64]; + int (*q_chroma_intra_matrix)[64]; + int (*q_inter_matrix)[64]; + /** identical to the above but for MMX & these are not permutated, second 64 entries are bias*/ + uint16_t (*q_intra_matrix16)[2][64]; + uint16_t (*q_chroma_intra_matrix16)[2][64]; + uint16_t (*q_inter_matrix16)[2][64]; + + /* noise reduction */ + int (*dct_error_sum)[64]; + int dct_count[2]; + uint16_t (*dct_offset)[64]; + + /* bit rate control */ + int64_t total_bits; + int frame_bits; ///< bits used for the current frame + int stuffing_bits; ///< bits used for stuffing + int next_lambda; ///< next lambda used for retrying to encode a frame + RateControlContext rc_context; ///< contains stuff only accessed in ratecontrol.c + + /* statistics, used for 2-pass encoding */ + int mv_bits; + int header_bits; + int i_tex_bits; + int p_tex_bits; + int i_count; + int f_count; + int b_count; + int skip_count; + int misc_bits; ///< cbp, mb_type + int last_bits; ///< temp var used for calculating the above vars + + /* error concealment / resync */ + int resync_mb_x; ///< x position of last resync marker + int resync_mb_y; ///< y position of last resync marker + GetBitContext last_resync_gb; ///< used to search for the next resync marker + int mb_num_left; ///< number of MBs left in this video packet (for partitioned Slices only) + int next_p_frame_damaged; ///< set if the next p frame is damaged, to avoid showing trashed B-frames + + ParseContext parse_context; + + /* H.263 specific */ + int gob_index; + int obmc; ///< overlapped block motion compensation + int mb_info; ///< interval for outputting info about mb offsets as side data + int prev_mb_info, last_mb_info; + uint8_t *mb_info_ptr; + int mb_info_size; + int ehc_mode; + int rc_strategy; ///< deprecated + + /* H.263+ specific */ + int umvplus; ///< == H.263+ && unrestricted_mv + int h263_aic_dir; ///< AIC direction: 0 = left, 1 = top + int h263_slice_structured; + int alt_inter_vlc; ///< alternative inter vlc + int modified_quant; + int loop_filter; + int custom_pcf; + + /* MPEG-4 specific */ + int studio_profile; + int dct_precision; + ///< number of bits to represent the fractional part of time (encoder only) + int time_increment_bits; + int last_time_base; + int time_base; ///< time in seconds of last I,P,S Frame + int64_t time; ///< time of current frame + int64_t last_non_b_time; + uint16_t pp_time; ///< time distance between the last 2 p,s,i frames + uint16_t pb_time; ///< time distance between the last b and p,s,i frame + uint16_t pp_field_time; + uint16_t pb_field_time; ///< like above, just for interlaced + int real_sprite_warping_points; + int sprite_offset[2][2]; ///< sprite offset[isChroma][isMVY] + int sprite_delta[2][2]; ///< sprite_delta [isY][isMVY] + int mcsel; + int quant_precision; + int quarter_sample; ///< 1->qpel, 0->half pel ME/MC + int aspect_ratio_info; //FIXME remove + int sprite_warping_accuracy; + int data_partitioning; ///< data partitioning flag from header + int partitioned_frame; ///< is current frame partitioned + int low_delay; ///< no reordering needed / has no B-frames + int vo_type; + PutBitContext tex_pb; ///< used for data partitioned VOPs + PutBitContext pb2; ///< used for data partitioned VOPs + int mpeg_quant; + int padding_bug_score; ///< used to detect the VERY common padding bug in MPEG-4 + + /* divx specific, used to workaround (many) bugs in divx5 */ + int divx_packed; + uint8_t *bitstream_buffer; //Divx 5.01 puts several frames in a single one, this is used to reorder them + int bitstream_buffer_size; + unsigned int allocated_bitstream_buffer_size; + + /* RV10 specific */ + int rv10_version; ///< RV10 version: 0 or 3 + int rv10_first_dc_coded[3]; + + /* MJPEG specific */ + struct MJpegContext *mjpeg_ctx; + int esc_pos; + int pred; + int huffman; + + /* MSMPEG4 specific */ + int mv_table_index; + int rl_table_index; + int rl_chroma_table_index; + int dc_table_index; + int use_skip_mb_code; + int slice_height; ///< in macroblocks + int first_slice_line; ///< used in MPEG-4 too to handle resync markers + int flipflop_rounding; + int msmpeg4_version; ///< 0=not msmpeg4, 1=mp41, 2=mp42, 3=mp43/divx3 4=wmv1/7 5=wmv2/8 + int per_mb_rl_table; + int esc3_level_length; + int esc3_run_length; + /** [mb_intra][isChroma][level][run][last] */ + int (*ac_stats)[2][MAX_LEVEL+1][MAX_RUN+1][2]; + int inter_intra_pred; + int mspel; + + /* decompression specific */ + GetBitContext gb; + + /* MPEG-1 specific */ + int gop_picture_number; ///< index of the first picture of a GOP based on fake_pic_num & MPEG-1 specific + int last_mv_dir; ///< last mv_dir, used for B-frame encoding + uint8_t *vbv_delay_ptr; ///< pointer to vbv_delay in the bitstream + + /* MPEG-2-specific - I wished not to have to support this mess. */ + int progressive_sequence; + int mpeg_f_code[2][2]; + int a53_cc; + + // picture structure defines are loaded from mpegutils.h + int picture_structure; + + int64_t timecode_frame_start; ///< GOP timecode frame start number, in non drop frame format + int intra_dc_precision; + int frame_pred_frame_dct; + int top_field_first; + int concealment_motion_vectors; + int q_scale_type; + int brd_scale; + int intra_vlc_format; + int alternate_scan; + int seq_disp_ext; + int video_format; +#define VIDEO_FORMAT_COMPONENT 0 +#define VIDEO_FORMAT_PAL 1 +#define VIDEO_FORMAT_NTSC 2 +#define VIDEO_FORMAT_SECAM 3 +#define VIDEO_FORMAT_MAC 4 +#define VIDEO_FORMAT_UNSPECIFIED 5 + int repeat_first_field; + int chroma_420_type; + int chroma_format; +#define CHROMA_420 1 +#define CHROMA_422 2 +#define CHROMA_444 3 + int chroma_x_shift;//depend on pix_format, that depend on chroma_format + int chroma_y_shift; + + int progressive_frame; + int full_pel[2]; + int interlaced_dct; + int first_field; ///< is 1 for the first field of a field picture 0 otherwise + int drop_frame_timecode; ///< timecode is in drop frame format. + int scan_offset; ///< reserve space for SVCD scan offset user data. + + /* RTP specific */ + int rtp_mode; + int rtp_payload_size; + + char *tc_opt_str; ///< timecode option string + AVTimecode tc; ///< timecode context + + uint8_t *ptr_lastgob; + int swap_uv; //vcr2 codec is an MPEG-2 variant with U and V swapped + int pack_pblocks; //xvmc needs to keep blocks without gaps. + int16_t (*pblocks[12])[64]; + + int16_t (*block)[64]; ///< points to one of the following blocks + int16_t (*blocks)[12][64]; // for HQ mode we need to keep the best block + int (*decode_mb)(struct MpegEncContext *s, int16_t block[12][64]); // used by some codecs to avoid a switch() + + int32_t (*block32)[12][64]; + int dpcm_direction; // 0 = DCT, 1 = DPCM top to bottom scan, -1 = DPCM bottom to top scan + int16_t (*dpcm_macroblock)[3][256]; + +#define SLICE_OK 0 +#define SLICE_ERROR -1 +#define SLICE_END -2 /// clipping, 1-> use a nice continuous function to limit qscale within qmin/qmax. + */ + float rc_qsquish; + float rc_qmod_amp; + int rc_qmod_freq; + float rc_initial_cplx; + float rc_buffer_aggressivity; + float border_masking; + int lmin, lmax; + int vbv_ignore_qmax; + + char *rc_eq; + + /* temp buffers for rate control */ + float *cplx_tab, *bits_tab; + + /* flag to indicate a reinitialization is required, e.g. after + * a frame size change */ + int context_reinit; + + ERContext er; + + int error_rate; + + /* temporary frames used by b_frame_strategy = 2 */ + AVFrame *tmp_frames[MAX_B_FRAMES + 2]; + int b_frame_strategy; + int b_sensitivity; + + /* frame skip options for encoding */ + int frame_skip_threshold; + int frame_skip_factor; + int frame_skip_exp; + int frame_skip_cmp; + + int scenechange_threshold; + int noise_reduction; +} MpegEncContext; + +/* mpegvideo_enc common options */ +#define FF_MPV_FLAG_SKIP_RD 0x0001 +#define FF_MPV_FLAG_STRICT_GOP 0x0002 +#define FF_MPV_FLAG_QP_RD 0x0004 +#define FF_MPV_FLAG_CBP_RD 0x0008 +#define FF_MPV_FLAG_NAQ 0x0010 +#define FF_MPV_FLAG_MV0 0x0020 + +#define FF_MPV_OPT_CMP_FUNC \ +{ "sad", "Sum of absolute differences, fast", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SAD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "sse", "Sum of squared errors", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SSE }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "satd", "Sum of absolute Hadamard transformed differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SATD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "dct", "Sum of absolute DCT transformed differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCT }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "psnr", "Sum of squared quantization errors, low quality", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_PSNR }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "bit", "Number of bits needed for the block", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_BIT }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "rd", "Rate distortion optimal, slow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_RD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "zero", "Zero", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_ZERO }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "vsad", "Sum of absolute vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSAD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "vsse", "Sum of squared vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSSE }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "nsse", "Noise preserving sum of squared differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_NSSE }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "dct264", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCT264 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "dctmax", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{ "msad", "Sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" } + +#ifndef FF_MPV_OFFSET +#define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x) +#endif +#define FF_MPV_OPT_FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +#define FF_MPV_COMMON_OPTS \ +FF_MPV_OPT_CMP_FUNC, \ +{ "mpv_flags", "Flags common for all mpegvideo-based encoders.", FF_MPV_OFFSET(mpv_flags), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "skip_rd", "RD optimal MB level residual skipping", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_SKIP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "strict_gop", "Strictly enforce gop size", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_STRICT_GOP }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "qp_rd", "Use rate distortion optimization for qp selection", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_QP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "cbp_rd", "use rate distortion optimization for CBP", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_CBP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "naq", "normalize adaptive quantization", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_NAQ }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "mv0", "always try a mb with mv=<0,0>", 0, AV_OPT_TYPE_CONST, { .i64 = FF_MPV_FLAG_MV0 }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "luma_elim_threshold", "single coefficient elimination threshold for luminance (negative values also consider dc coefficient)",\ + FF_MPV_OFFSET(luma_elim_threshold), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS },\ +{ "chroma_elim_threshold", "single coefficient elimination threshold for chrominance (negative values also consider dc coefficient)",\ + FF_MPV_OFFSET(chroma_elim_threshold), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS },\ +{ "quantizer_noise_shaping", NULL, FF_MPV_OFFSET(quantizer_noise_shaping), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FF_MPV_OPT_FLAGS },\ +{ "error_rate", "Simulate errors in the bitstream to test error concealment.", \ + FF_MPV_OFFSET(error_rate), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FF_MPV_OPT_FLAGS },\ +{"qsquish", "how to keep quantizer between qmin and qmax (0 = clip, 1 = use differentiable function)", \ + FF_MPV_OFFSET(rc_qsquish), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0, 99, FF_MPV_OPT_FLAGS}, \ +{"rc_qmod_amp", "experimental quantizer modulation", FF_MPV_OFFSET(rc_qmod_amp), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"rc_qmod_freq", "experimental quantizer modulation", FF_MPV_OFFSET(rc_qmod_freq), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS}, \ +{"rc_eq", "Set rate control equation. When computing the expression, besides the standard functions " \ + "defined in the section 'Expression Evaluation', the following functions are available: " \ + "bits2qp(bits), qp2bits(qp). Also the following constants are available: iTex pTex tex mv " \ + "fCode iCount mcVar var isI isP isB avgQP qComp avgIITex avgPITex avgPPTex avgBPTex avgTex.", \ + FF_MPV_OFFSET(rc_eq), AV_OPT_TYPE_STRING, .flags = FF_MPV_OPT_FLAGS }, \ +{"rc_init_cplx", "initial complexity for 1-pass encoding", FF_MPV_OFFSET(rc_initial_cplx), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"rc_buf_aggressivity", "currently useless", FF_MPV_OFFSET(rc_buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"border_mask", "increase the quantizer for macroblocks close to borders", FF_MPV_OFFSET(border_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, FF_MPV_OPT_FLAGS}, \ +{"lmin", "minimum Lagrange factor (VBR)", FF_MPV_OFFSET(lmin), AV_OPT_TYPE_INT, {.i64 = 2*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"lmax", "maximum Lagrange factor (VBR)", FF_MPV_OFFSET(lmax), AV_OPT_TYPE_INT, {.i64 = 31*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"ibias", "intra quant bias", FF_MPV_OFFSET(intra_quant_bias), AV_OPT_TYPE_INT, {.i64 = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"pbias", "inter quant bias", FF_MPV_OFFSET(inter_quant_bias), AV_OPT_TYPE_INT, {.i64 = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"rc_strategy", "ratecontrol method", FF_MPV_OFFSET(rc_strategy), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FF_MPV_OPT_FLAGS | AV_OPT_FLAG_DEPRECATED, "rc_strategy" }, \ + { "ffmpeg", "deprecated, does nothing", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FF_MPV_OPT_FLAGS | AV_OPT_FLAG_DEPRECATED, "rc_strategy" }, \ + { "xvid", "deprecated, does nothing", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FF_MPV_OPT_FLAGS | AV_OPT_FLAG_DEPRECATED, "rc_strategy" }, \ +{"motion_est", "motion estimation algorithm", FF_MPV_OFFSET(motion_est), AV_OPT_TYPE_INT, {.i64 = FF_ME_EPZS }, FF_ME_ZERO, FF_ME_XONE, FF_MPV_OPT_FLAGS, "motion_est" }, \ +{ "zero", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_ZERO }, 0, 0, FF_MPV_OPT_FLAGS, "motion_est" }, \ +{ "epzs", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_EPZS }, 0, 0, FF_MPV_OPT_FLAGS, "motion_est" }, \ +{ "xone", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_XONE }, 0, 0, FF_MPV_OPT_FLAGS, "motion_est" }, \ +{ "force_duplicated_matrix", "Always write luma and chroma matrix for mjpeg, useful for rtp streaming.", FF_MPV_OFFSET(force_duplicated_matrix), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, FF_MPV_OPT_FLAGS }, \ +{"b_strategy", "Strategy to choose between I/P/B-frames", FF_MPV_OFFSET(b_frame_strategy), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, FF_MPV_OPT_FLAGS }, \ +{"b_sensitivity", "Adjust sensitivity of b_frame_strategy 1", FF_MPV_OFFSET(b_sensitivity), AV_OPT_TYPE_INT, {.i64 = 40 }, 1, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"brd_scale", "Downscale frames for dynamic B-frame decision", FF_MPV_OFFSET(brd_scale), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 3, FF_MPV_OPT_FLAGS }, \ +{"skip_threshold", "Frame skip threshold", FF_MPV_OFFSET(frame_skip_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_factor", "Frame skip factor", FF_MPV_OFFSET(frame_skip_factor), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_exp", "Frame skip exponent", FF_MPV_OFFSET(frame_skip_exp), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"skip_cmp", "Frame skip compare function", FF_MPV_OFFSET(frame_skip_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ +{"sc_threshold", "Scene change threshold", FF_MPV_OFFSET(scenechange_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"noise_reduction", "Noise reduction", FF_MPV_OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"mpeg_quant", "Use MPEG quantizers instead of H.263", FF_MPV_OFFSET(mpeg_quant), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FF_MPV_OPT_FLAGS }, \ +{"ps", "RTP payload size in bytes", FF_MPV_OFFSET(rtp_payload_size), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"mepc", "Motion estimation bitrate penalty compensation (1.0 = 256)", FF_MPV_OFFSET(me_penalty_compensation), AV_OPT_TYPE_INT, {.i64 = 256 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"mepre", "pre motion estimation", FF_MPV_OFFSET(me_pre), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"a53cc", "Use A53 Closed Captions (if available)", FF_MPV_OFFSET(a53_cc), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FF_MPV_OPT_FLAGS }, \ + +extern const AVOption ff_mpv_generic_options[]; + +/** + * Set the given MpegEncContext to common defaults (same for encoding + * and decoding). The changed fields will not depend upon the prior + * state of the MpegEncContext. + */ +void ff_mpv_common_defaults(MpegEncContext *s); + +void ff_dct_encode_init_x86(MpegEncContext *s); + +int ff_mpv_common_init(MpegEncContext *s); +void ff_mpv_common_init_arm(MpegEncContext *s); +void ff_mpv_common_init_axp(MpegEncContext *s); +void ff_mpv_common_init_neon(MpegEncContext *s); +void ff_mpv_common_init_ppc(MpegEncContext *s); +void ff_mpv_common_init_x86(MpegEncContext *s); +void ff_mpv_common_init_mips(MpegEncContext *s); + +int ff_mpv_common_frame_size_change(MpegEncContext *s); +void ff_mpv_common_end(MpegEncContext *s); + +void ff_mpv_decode_defaults(MpegEncContext *s); +void ff_mpv_decode_init(MpegEncContext *s, AVCodecContext *avctx); +void ff_mpv_reconstruct_mb(MpegEncContext *s, int16_t block[12][64]); +void ff_mpv_report_decode_progress(MpegEncContext *s); + +int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx); +void ff_mpv_frame_end(MpegEncContext *s); + +int ff_mpv_encode_init(AVCodecContext *avctx); +void ff_mpv_encode_init_x86(MpegEncContext *s); + +int ff_mpv_encode_end(AVCodecContext *avctx); +int ff_mpv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet); +int ff_mpv_reallocate_putbitbuffer(MpegEncContext *s, size_t threshold, size_t size_increase); + +void ff_clean_intra_table_entries(MpegEncContext *s); +void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h); +void ff_mpeg_flush(AVCodecContext *avctx); + +void ff_print_debug_info(MpegEncContext *s, Picture *p, AVFrame *pict); + +int ff_mpv_export_qp_table(MpegEncContext *s, AVFrame *f, Picture *p, int qp_type); + +void ff_write_quant_matrix(PutBitContext *pb, uint16_t *matrix); + +int ff_update_duplicate_context(MpegEncContext *dst, MpegEncContext *src); +int ff_mpeg_update_thread_context(AVCodecContext *dst, const AVCodecContext *src); +void ff_set_qscale(MpegEncContext * s, int qscale); + +void ff_mpv_idct_init(MpegEncContext *s); +int ff_dct_encode_init(MpegEncContext *s); +void ff_convert_matrix(MpegEncContext *s, int (*qmat)[64], uint16_t (*qmat16)[2][64], + const uint16_t *quant_matrix, int bias, int qmin, int qmax, int intra); +int ff_dct_quantize_c(MpegEncContext *s, int16_t *block, int n, int qscale, int *overflow); +void ff_block_permute(int16_t *block, uint8_t *permutation, + const uint8_t *scantable, int last); +void ff_init_block_index(MpegEncContext *s); + +void ff_mpv_motion(MpegEncContext *s, + uint8_t *dest_y, uint8_t *dest_cb, + uint8_t *dest_cr, int dir, + uint8_t **ref_picture, + op_pixels_func (*pix_op)[4], + qpel_mc_func (*qpix_op)[16]); + +static inline void ff_update_block_index(MpegEncContext *s){ + const int bytes_per_pixel = 1 + (s->avctx->bits_per_raw_sample > 8); + const int block_size= (8*bytes_per_pixel) >> s->avctx->lowres; + + s->block_index[0]+=2; + s->block_index[1]+=2; + s->block_index[2]+=2; + s->block_index[3]+=2; + s->block_index[4]++; + s->block_index[5]++; + s->dest[0]+= 2*block_size; + s->dest[1]+= (2 >> s->chroma_x_shift) * block_size; + s->dest[2]+= (2 >> s->chroma_x_shift) * block_size; +} + +static inline int get_bits_diff(MpegEncContext *s){ + const int bits= put_bits_count(&s->pb); + const int last= s->last_bits; + + s->last_bits = bits; + + return bits - last; +} + +static inline int mpeg_get_qscale(MpegEncContext *s) +{ + int qscale = get_bits(&s->gb, 5); + if (s->q_scale_type) + return ff_mpeg2_non_linear_qscale[qscale]; + else + return qscale << 1; +} + +#endif /* AVCODEC_MPEGVIDEO_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodata.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodata.c new file mode 100644 index 0000000000..5f1d8f7c00 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodata.c @@ -0,0 +1,109 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +const uint8_t ff_default_chroma_qscale_table[32] = { +// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 +}; + +const uint8_t ff_mpeg2_non_linear_qscale[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 10, 12, 14, 16, 18, 20, 22, + 24, 28, 32, 36, 40, 44, 48, 52, + 56, 64, 72, 80, 88, 96, 104, 112, +}; + +const uint8_t ff_mpeg1_dc_scale_table[128] = { +// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +}; + +static const uint8_t mpeg2_dc_scale_table1[128] = { +// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +}; + +static const uint8_t mpeg2_dc_scale_table2[128] = { +// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +}; + +static const uint8_t mpeg2_dc_scale_table3[128] = { +// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +}; + +const uint8_t *const ff_mpeg2_dc_scale_table[4] = { + ff_mpeg1_dc_scale_table, + mpeg2_dc_scale_table1, + mpeg2_dc_scale_table2, + mpeg2_dc_scale_table3, +}; + +const uint8_t ff_alternate_horizontal_scan[64] = { + 0, 1, 2, 3, 8, 9, 16, 17, + 10, 11, 4, 5, 6, 7, 15, 14, + 13, 12, 19, 18, 24, 25, 32, 33, + 26, 27, 20, 21, 22, 23, 28, 29, + 30, 31, 34, 35, 40, 41, 48, 49, + 42, 43, 36, 37, 38, 39, 44, 45, + 46, 47, 50, 51, 56, 57, 58, 59, + 52, 53, 54, 55, 60, 61, 62, 63, +}; + +const uint8_t ff_alternate_vertical_scan[64] = { + 0, 8, 16, 24, 1, 9, 2, 10, + 17, 25, 32, 40, 48, 56, 57, 49, + 41, 33, 26, 18, 3, 11, 4, 12, + 19, 27, 34, 42, 50, 58, 35, 43, + 51, 59, 20, 28, 5, 13, 6, 14, + 21, 29, 36, 44, 52, 60, 37, 45, + 53, 61, 22, 30, 7, 15, 23, 31, + 38, 46, 54, 62, 39, 47, 55, 63, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodata.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodata.h new file mode 100644 index 0000000000..14f4806d66 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodata.h @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MPEGVIDEODATA_H +#define AVCODEC_MPEGVIDEODATA_H + +#include + +/* encoding scans */ +extern const uint8_t ff_alternate_horizontal_scan[64]; +extern const uint8_t ff_alternate_vertical_scan[64]; + +extern const uint8_t ff_mpeg1_dc_scale_table[128]; +extern const uint8_t * const ff_mpeg2_dc_scale_table[4]; + +extern const uint8_t ff_mpeg2_non_linear_qscale[32]; + +extern const uint8_t ff_default_chroma_qscale_table[32]; + +#endif /* AVCODEC_MPEGVIDEODATA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodsp.c new file mode 100644 index 0000000000..a58e45ad43 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodsp.c @@ -0,0 +1,119 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/common.h" +#include "mpegvideodsp.h" + +static void gmc1_c(uint8_t *dst, uint8_t *src, int stride, int h, + int x16, int y16, int rounder) +{ + const int A = (16 - x16) * (16 - y16); + const int B = (x16) * (16 - y16); + const int C = (16 - x16) * (y16); + const int D = (x16) * (y16); + int i; + + for (i = 0; i < h; i++) { + dst[0] = (A * src[0] + B * src[1] + C * src[stride + 0] + D * src[stride + 1] + rounder) >> 8; + dst[1] = (A * src[1] + B * src[2] + C * src[stride + 1] + D * src[stride + 2] + rounder) >> 8; + dst[2] = (A * src[2] + B * src[3] + C * src[stride + 2] + D * src[stride + 3] + rounder) >> 8; + dst[3] = (A * src[3] + B * src[4] + C * src[stride + 3] + D * src[stride + 4] + rounder) >> 8; + dst[4] = (A * src[4] + B * src[5] + C * src[stride + 4] + D * src[stride + 5] + rounder) >> 8; + dst[5] = (A * src[5] + B * src[6] + C * src[stride + 5] + D * src[stride + 6] + rounder) >> 8; + dst[6] = (A * src[6] + B * src[7] + C * src[stride + 6] + D * src[stride + 7] + rounder) >> 8; + dst[7] = (A * src[7] + B * src[8] + C * src[stride + 7] + D * src[stride + 8] + rounder) >> 8; + dst += stride; + src += stride; + } +} + +void ff_gmc_c(uint8_t *dst, uint8_t *src, int stride, int h, int ox, int oy, + int dxx, int dxy, int dyx, int dyy, int shift, int r, + int width, int height) +{ + int y, vx, vy; + const int s = 1 << shift; + + width--; + height--; + + for (y = 0; y < h; y++) { + int x; + + vx = ox; + vy = oy; + for (x = 0; x < 8; x++) { // FIXME: optimize + int index; + int src_x = vx >> 16; + int src_y = vy >> 16; + int frac_x = src_x & (s - 1); + int frac_y = src_y & (s - 1); + + src_x >>= shift; + src_y >>= shift; + + if ((unsigned) src_x < width) { + if ((unsigned) src_y < height) { + index = src_x + src_y * stride; + dst[y * stride + x] = + ((src[index] * (s - frac_x) + + src[index + 1] * frac_x) * (s - frac_y) + + (src[index + stride] * (s - frac_x) + + src[index + stride + 1] * frac_x) * frac_y + + r) >> (shift * 2); + } else { + index = src_x + av_clip(src_y, 0, height) * stride; + dst[y * stride + x] = + ((src[index] * (s - frac_x) + + src[index + 1] * frac_x) * s + + r) >> (shift * 2); + } + } else { + if ((unsigned) src_y < height) { + index = av_clip(src_x, 0, width) + src_y * stride; + dst[y * stride + x] = + ((src[index] * (s - frac_y) + + src[index + stride] * frac_y) * s + + r) >> (shift * 2); + } else { + index = av_clip(src_x, 0, width) + + av_clip(src_y, 0, height) * stride; + dst[y * stride + x] = src[index]; + } + } + + vx += dxx; + vy += dyx; + } + ox += dxy; + oy += dyy; + } +} + +av_cold void ff_mpegvideodsp_init(MpegVideoDSPContext *c) +{ + c->gmc1 = gmc1_c; + c->gmc = ff_gmc_c; + + if (ARCH_PPC) + ff_mpegvideodsp_init_ppc(c); + if (ARCH_X86) + ff_mpegvideodsp_init_x86(c); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodsp.h new file mode 100644 index 0000000000..293e2548d3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideodsp.h @@ -0,0 +1,47 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MPEGVIDEODSP_H +#define AVCODEC_MPEGVIDEODSP_H + +#include + +void ff_gmc_c(uint8_t *dst, uint8_t *src, int stride, int h, int ox, int oy, + int dxx, int dxy, int dyx, int dyy, int shift, int r, + int width, int height); + +typedef struct MpegVideoDSPContext { + /** + * translational global motion compensation. + */ + void (*gmc1)(uint8_t *dst /* align 8 */, uint8_t *src /* align 1 */, + int srcStride, int h, int x16, int y16, int rounder); + /** + * global motion compensation. + */ + void (*gmc)(uint8_t *dst /* align 8 */, uint8_t *src /* align 1 */, + int stride, int h, int ox, int oy, + int dxx, int dxy, int dyx, int dyy, + int shift, int r, int width, int height); +} MpegVideoDSPContext; + +void ff_mpegvideodsp_init(MpegVideoDSPContext *c); +void ff_mpegvideodsp_init_ppc(MpegVideoDSPContext *c); +void ff_mpegvideodsp_init_x86(MpegVideoDSPContext *c); + +#endif /* AVCODEC_MPEGVIDEODSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideoencdsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideoencdsp.c new file mode 100644 index 0000000000..a34ab3553e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideoencdsp.c @@ -0,0 +1,256 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "config.h" +#include "libavutil/avassert.h" +#include "libavutil/attributes.h" +#include "libavutil/imgutils.h" +#include "avcodec.h" +#include "me_cmp.h" +#include "mpegvideoencdsp.h" + +static int try_8x8basis_c(int16_t rem[64], int16_t weight[64], + int16_t basis[64], int scale) +{ + int i; + unsigned int sum = 0; + + for (i = 0; i < 8 * 8; i++) { + int b = rem[i] + ((basis[i] * scale + + (1 << (BASIS_SHIFT - RECON_SHIFT - 1))) >> + (BASIS_SHIFT - RECON_SHIFT)); + int w = weight[i]; + b >>= RECON_SHIFT; + av_assert2(-512 < b && b < 512); + + sum += (w * b) * (w * b) >> 4; + } + return sum >> 2; +} + +static void add_8x8basis_c(int16_t rem[64], int16_t basis[64], int scale) +{ + int i; + + for (i = 0; i < 8 * 8; i++) + rem[i] += (basis[i] * scale + + (1 << (BASIS_SHIFT - RECON_SHIFT - 1))) >> + (BASIS_SHIFT - RECON_SHIFT); +} + +static int pix_sum_c(uint8_t *pix, int line_size) +{ + int s = 0, i, j; + + for (i = 0; i < 16; i++) { + for (j = 0; j < 16; j += 8) { + s += pix[0]; + s += pix[1]; + s += pix[2]; + s += pix[3]; + s += pix[4]; + s += pix[5]; + s += pix[6]; + s += pix[7]; + pix += 8; + } + pix += line_size - 16; + } + return s; +} + +static int pix_norm1_c(uint8_t *pix, int line_size) +{ + int s = 0, i, j; + const uint32_t *sq = ff_square_tab + 256; + + for (i = 0; i < 16; i++) { + for (j = 0; j < 16; j += 8) { +#if HAVE_FAST_64BIT + register uint64_t x = *(uint64_t *) pix; + s += sq[x & 0xff]; + s += sq[(x >> 8) & 0xff]; + s += sq[(x >> 16) & 0xff]; + s += sq[(x >> 24) & 0xff]; + s += sq[(x >> 32) & 0xff]; + s += sq[(x >> 40) & 0xff]; + s += sq[(x >> 48) & 0xff]; + s += sq[(x >> 56) & 0xff]; +#else + register uint32_t x = *(uint32_t *) pix; + s += sq[x & 0xff]; + s += sq[(x >> 8) & 0xff]; + s += sq[(x >> 16) & 0xff]; + s += sq[(x >> 24) & 0xff]; + x = *(uint32_t *) (pix + 4); + s += sq[x & 0xff]; + s += sq[(x >> 8) & 0xff]; + s += sq[(x >> 16) & 0xff]; + s += sq[(x >> 24) & 0xff]; +#endif + pix += 8; + } + pix += line_size - 16; + } + return s; +} + +/* draw the edges of width 'w' of an image of size width, height */ +// FIXME: Check that this is OK for MPEG-4 interlaced. +static void draw_edges_8_c(uint8_t *buf, int wrap, int width, int height, + int w, int h, int sides) +{ + uint8_t *ptr = buf, *last_line; + int i; + + /* left and right */ + for (i = 0; i < height; i++) { + memset(ptr - w, ptr[0], w); + memset(ptr + width, ptr[width - 1], w); + ptr += wrap; + } + + /* top and bottom + corners */ + buf -= w; + last_line = buf + (height - 1) * wrap; + if (sides & EDGE_TOP) + for (i = 0; i < h; i++) + // top + memcpy(buf - (i + 1) * wrap, buf, width + w + w); + if (sides & EDGE_BOTTOM) + for (i = 0; i < h; i++) + // bottom + memcpy(last_line + (i + 1) * wrap, last_line, width + w + w); +} + +/* 2x2 -> 1x1 */ +static void shrink22(uint8_t *dst, int dst_wrap, + const uint8_t *src, int src_wrap, + int width, int height) +{ + int w; + const uint8_t *s1, *s2; + uint8_t *d; + + for (; height > 0; height--) { + s1 = src; + s2 = s1 + src_wrap; + d = dst; + for (w = width; w >= 4; w -= 4) { + d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 2; + d[1] = (s1[2] + s1[3] + s2[2] + s2[3] + 2) >> 2; + d[2] = (s1[4] + s1[5] + s2[4] + s2[5] + 2) >> 2; + d[3] = (s1[6] + s1[7] + s2[6] + s2[7] + 2) >> 2; + s1 += 8; + s2 += 8; + d += 4; + } + for (; w > 0; w--) { + d[0] = (s1[0] + s1[1] + s2[0] + s2[1] + 2) >> 2; + s1 += 2; + s2 += 2; + d++; + } + src += 2 * src_wrap; + dst += dst_wrap; + } +} + +/* 4x4 -> 1x1 */ +static void shrink44(uint8_t *dst, int dst_wrap, + const uint8_t *src, int src_wrap, + int width, int height) +{ + int w; + const uint8_t *s1, *s2, *s3, *s4; + uint8_t *d; + + for (; height > 0; height--) { + s1 = src; + s2 = s1 + src_wrap; + s3 = s2 + src_wrap; + s4 = s3 + src_wrap; + d = dst; + for (w = width; w > 0; w--) { + d[0] = (s1[0] + s1[1] + s1[2] + s1[3] + + s2[0] + s2[1] + s2[2] + s2[3] + + s3[0] + s3[1] + s3[2] + s3[3] + + s4[0] + s4[1] + s4[2] + s4[3] + 8) >> 4; + s1 += 4; + s2 += 4; + s3 += 4; + s4 += 4; + d++; + } + src += 4 * src_wrap; + dst += dst_wrap; + } +} + +/* 8x8 -> 1x1 */ +static void shrink88(uint8_t *dst, int dst_wrap, + const uint8_t *src, int src_wrap, + int width, int height) +{ + int w, i; + + for (; height > 0; height--) { + for(w = width;w > 0; w--) { + int tmp = 0; + for (i = 0; i < 8; i++) { + tmp += src[0] + src[1] + src[2] + src[3] + + src[4] + src[5] + src[6] + src[7]; + src += src_wrap; + } + *(dst++) = (tmp + 32) >> 6; + src += 8 - 8 * src_wrap; + } + src += 8 * src_wrap - 8 * width; + dst += dst_wrap - width; + } +} + +av_cold void ff_mpegvideoencdsp_init(MpegvideoEncDSPContext *c, + AVCodecContext *avctx) +{ + c->try_8x8basis = try_8x8basis_c; + c->add_8x8basis = add_8x8basis_c; + + c->shrink[0] = av_image_copy_plane; + c->shrink[1] = shrink22; + c->shrink[2] = shrink44; + c->shrink[3] = shrink88; + + c->pix_sum = pix_sum_c; + c->pix_norm1 = pix_norm1_c; + + c->draw_edges = draw_edges_8_c; + + if (ARCH_ARM) + ff_mpegvideoencdsp_init_arm(c, avctx); + if (ARCH_PPC) + ff_mpegvideoencdsp_init_ppc(c, avctx); + if (ARCH_X86) + ff_mpegvideoencdsp_init_x86(c, avctx); + if (ARCH_MIPS) + ff_mpegvideoencdsp_init_mips(c, avctx); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideoencdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideoencdsp.h new file mode 100644 index 0000000000..33f0282fcc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/mpegvideoencdsp.h @@ -0,0 +1,58 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_MPEGVIDEOENCDSP_H +#define AVCODEC_MPEGVIDEOENCDSP_H + +#include + +#include "avcodec.h" + +#define BASIS_SHIFT 16 +#define RECON_SHIFT 6 + +#define EDGE_TOP 1 +#define EDGE_BOTTOM 2 + +typedef struct MpegvideoEncDSPContext { + int (*try_8x8basis)(int16_t rem[64], int16_t weight[64], + int16_t basis[64], int scale); + void (*add_8x8basis)(int16_t rem[64], int16_t basis[64], int scale); + + int (*pix_sum)(uint8_t *pix, int line_size); + int (*pix_norm1)(uint8_t *pix, int line_size); + + void (*shrink[4])(uint8_t *dst, int dst_wrap, const uint8_t *src, + int src_wrap, int width, int height); + + void (*draw_edges)(uint8_t *buf, int wrap, int width, int height, + int w, int h, int sides); +} MpegvideoEncDSPContext; + +void ff_mpegvideoencdsp_init(MpegvideoEncDSPContext *c, + AVCodecContext *avctx); +void ff_mpegvideoencdsp_init_arm(MpegvideoEncDSPContext *c, + AVCodecContext *avctx); +void ff_mpegvideoencdsp_init_ppc(MpegvideoEncDSPContext *c, + AVCodecContext *avctx); +void ff_mpegvideoencdsp_init_x86(MpegvideoEncDSPContext *c, + AVCodecContext *avctx); +void ff_mpegvideoencdsp_init_mips(MpegvideoEncDSPContext *c, + AVCodecContext *avctx); + +#endif /* AVCODEC_MPEGVIDEOENCDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/null_bsf.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/null_bsf.c new file mode 100644 index 0000000000..24d26dfb1a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/null_bsf.c @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Null bitstream filter -- pass the input through unchanged. + */ + +#include "avcodec.h" +#include "bsf.h" + +static int null_filter(AVBSFContext *ctx, AVPacket *pkt) +{ + return ff_bsf_get_packet_ref(ctx, pkt); +} + +const AVBitStreamFilter ff_null_bsf = { + .name = "null", + .filter = null_filter, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/options.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/options.c new file mode 100644 index 0000000000..35e8ac9313 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/options.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Options definition for AVCodecContext. + */ + +#include "avcodec.h" +#include "internal.h" +#include "libavutil/avassert.h" +#include "libavutil/internal.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include + +FF_DISABLE_DEPRECATION_WARNINGS +#include "options_table.h" +FF_ENABLE_DEPRECATION_WARNINGS + +static const char* context_to_name(void* ptr) { + AVCodecContext *avc= ptr; + + if(avc && avc->codec && avc->codec->name) + return avc->codec->name; + else + return "NULL"; +} + +static void *codec_child_next(void *obj, void *prev) +{ + AVCodecContext *s = obj; + if (!prev && s->codec && s->codec->priv_class && s->priv_data) + return s->priv_data; + return NULL; +} + +static const AVClass *codec_child_class_next(const AVClass *prev) +{ + AVCodec *c = NULL; + + /* find the codec that corresponds to prev */ + while (prev && (c = av_codec_next(c))) + if (c->priv_class == prev) + break; + + /* find next codec with priv options */ + while (c = av_codec_next(c)) + if (c->priv_class) + return c->priv_class; + return NULL; +} + +static AVClassCategory get_category(void *ptr) +{ + AVCodecContext* avctx = ptr; + if(avctx->codec && avctx->codec->decode) return AV_CLASS_CATEGORY_DECODER; + else return AV_CLASS_CATEGORY_ENCODER; +} + +static const AVClass av_codec_context_class = { + .class_name = "AVCodecContext", + .item_name = context_to_name, + .option = avcodec_options, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(AVCodecContext, log_level_offset), + .child_next = codec_child_next, + .child_class_next = codec_child_class_next, + .category = AV_CLASS_CATEGORY_ENCODER, + .get_category = get_category, +}; + +static int init_context_defaults(AVCodecContext *s, const AVCodec *codec) +{ + int flags=0; + memset(s, 0, sizeof(AVCodecContext)); + + s->av_class = &av_codec_context_class; + + s->codec_type = codec ? codec->type : AVMEDIA_TYPE_UNKNOWN; + if (codec) { + s->codec = codec; + s->codec_id = codec->id; + } + + if(s->codec_type == AVMEDIA_TYPE_AUDIO) + flags= AV_OPT_FLAG_AUDIO_PARAM; + else if(s->codec_type == AVMEDIA_TYPE_VIDEO) + flags= AV_OPT_FLAG_VIDEO_PARAM; + else if(s->codec_type == AVMEDIA_TYPE_SUBTITLE) + flags= AV_OPT_FLAG_SUBTITLE_PARAM; + av_opt_set_defaults2(s, flags, flags); + + s->time_base = (AVRational){0,1}; + s->framerate = (AVRational){ 0, 1 }; + s->pkt_timebase = (AVRational){ 0, 1 }; + s->get_buffer2 = avcodec_default_get_buffer2; + s->get_format = avcodec_default_get_format; + s->execute = avcodec_default_execute; + s->execute2 = avcodec_default_execute2; + s->sample_aspect_ratio = (AVRational){0,1}; + s->pix_fmt = AV_PIX_FMT_NONE; + s->sw_pix_fmt = AV_PIX_FMT_NONE; + s->sample_fmt = AV_SAMPLE_FMT_NONE; + + s->reordered_opaque = AV_NOPTS_VALUE; + if(codec && codec->priv_data_size){ + if(!s->priv_data){ + s->priv_data= av_mallocz(codec->priv_data_size); + if (!s->priv_data) { + return AVERROR(ENOMEM); + } + } + if(codec->priv_class){ + *(const AVClass**)s->priv_data = codec->priv_class; + av_opt_set_defaults(s->priv_data); + } + } + if (codec && codec->defaults) { + int ret; + const AVCodecDefault *d = codec->defaults; + while (d->key) { + ret = av_opt_set(s, d->key, d->value, 0); + av_assert0(ret >= 0); + d++; + } + } + return 0; +} + +#if FF_API_GET_CONTEXT_DEFAULTS +int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec) +{ + return init_context_defaults(s, codec); +} +#endif + +AVCodecContext *avcodec_alloc_context3(const AVCodec *codec) +{ + AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext)); + + if (!avctx) + return NULL; + + if (init_context_defaults(avctx, codec) < 0) { + av_free(avctx); + return NULL; + } + + return avctx; +} + +void avcodec_free_context(AVCodecContext **pavctx) +{ + AVCodecContext *avctx = *pavctx; + + if (!avctx) + return; + + avcodec_close(avctx); + + av_freep(&avctx->extradata); + av_freep(&avctx->subtitle_header); + av_freep(&avctx->intra_matrix); + av_freep(&avctx->inter_matrix); + av_freep(&avctx->rc_override); + + av_freep(pavctx); +} + +#if FF_API_COPY_CONTEXT +static void copy_context_reset(AVCodecContext *avctx) +{ + int i; + + av_opt_free(avctx); +#if FF_API_CODED_FRAME +FF_DISABLE_DEPRECATION_WARNINGS + av_frame_free(&avctx->coded_frame); +FF_ENABLE_DEPRECATION_WARNINGS +#endif + av_freep(&avctx->rc_override); + av_freep(&avctx->intra_matrix); + av_freep(&avctx->inter_matrix); + av_freep(&avctx->extradata); + av_freep(&avctx->subtitle_header); + av_buffer_unref(&avctx->hw_frames_ctx); + av_buffer_unref(&avctx->hw_device_ctx); + for (i = 0; i < avctx->nb_coded_side_data; i++) + av_freep(&avctx->coded_side_data[i].data); + av_freep(&avctx->coded_side_data); + avctx->subtitle_header_size = 0; + avctx->nb_coded_side_data = 0; + avctx->extradata_size = 0; +} + +int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src) +{ + const AVCodec *orig_codec = dest->codec; + uint8_t *orig_priv_data = dest->priv_data; + + if (avcodec_is_open(dest)) { // check that the dest context is uninitialized + av_log(dest, AV_LOG_ERROR, + "Tried to copy AVCodecContext %p into already-initialized %p\n", + src, dest); + return AVERROR(EINVAL); + } + + copy_context_reset(dest); + + memcpy(dest, src, sizeof(*dest)); + av_opt_copy(dest, src); + + dest->priv_data = orig_priv_data; + dest->codec = orig_codec; + + if (orig_priv_data && src->codec && src->codec->priv_class && + dest->codec && dest->codec->priv_class) + av_opt_copy(orig_priv_data, src->priv_data); + + + /* set values specific to opened codecs back to their default state */ + dest->slice_offset = NULL; + dest->hwaccel = NULL; + dest->internal = NULL; +#if FF_API_CODED_FRAME +FF_DISABLE_DEPRECATION_WARNINGS + dest->coded_frame = NULL; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + /* reallocate values that should be allocated separately */ + dest->extradata = NULL; + dest->coded_side_data = NULL; + dest->intra_matrix = NULL; + dest->inter_matrix = NULL; + dest->rc_override = NULL; + dest->subtitle_header = NULL; + dest->hw_frames_ctx = NULL; + dest->hw_device_ctx = NULL; + dest->nb_coded_side_data = 0; + +#define alloc_and_copy_or_fail(obj, size, pad) \ + if (src->obj && size > 0) { \ + dest->obj = av_malloc(size + pad); \ + if (!dest->obj) \ + goto fail; \ + memcpy(dest->obj, src->obj, size); \ + if (pad) \ + memset(((uint8_t *) dest->obj) + size, 0, pad); \ + } + alloc_and_copy_or_fail(extradata, src->extradata_size, + AV_INPUT_BUFFER_PADDING_SIZE); + dest->extradata_size = src->extradata_size; + alloc_and_copy_or_fail(intra_matrix, 64 * sizeof(int16_t), 0); + alloc_and_copy_or_fail(inter_matrix, 64 * sizeof(int16_t), 0); + alloc_and_copy_or_fail(rc_override, src->rc_override_count * sizeof(*src->rc_override), 0); + alloc_and_copy_or_fail(subtitle_header, src->subtitle_header_size, 1); + av_assert0(dest->subtitle_header_size == src->subtitle_header_size); +#undef alloc_and_copy_or_fail + + if (src->hw_frames_ctx) { + dest->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx); + if (!dest->hw_frames_ctx) + goto fail; + } + + return 0; + +fail: + copy_context_reset(dest); + return AVERROR(ENOMEM); +} +#endif + +const AVClass *avcodec_get_class(void) +{ + return &av_codec_context_class; +} + +#define FOFFSET(x) offsetof(AVFrame,x) + +static const AVOption frame_options[]={ +{"best_effort_timestamp", "", FOFFSET(best_effort_timestamp), AV_OPT_TYPE_INT64, {.i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, 0}, +{"pkt_pos", "", FOFFSET(pkt_pos), AV_OPT_TYPE_INT64, {.i64 = -1 }, INT64_MIN, INT64_MAX, 0}, +{"pkt_size", "", FOFFSET(pkt_size), AV_OPT_TYPE_INT64, {.i64 = -1 }, INT64_MIN, INT64_MAX, 0}, +{"sample_aspect_ratio", "", FOFFSET(sample_aspect_ratio), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, 0, INT_MAX, 0}, +{"width", "", FOFFSET(width), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0}, +{"height", "", FOFFSET(height), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0}, +{"format", "", FOFFSET(format), AV_OPT_TYPE_INT, {.i64 = -1 }, 0, INT_MAX, 0}, +{"channel_layout", "", FOFFSET(channel_layout), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, 0}, +{"sample_rate", "", FOFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0}, +{NULL}, +}; + +static const AVClass av_frame_class = { + .class_name = "AVFrame", + .item_name = NULL, + .option = frame_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVClass *avcodec_get_frame_class(void) +{ + return &av_frame_class; +} + +#define SROFFSET(x) offsetof(AVSubtitleRect,x) + +static const AVOption subtitle_rect_options[]={ +{"x", "", SROFFSET(x), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0}, +{"y", "", SROFFSET(y), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0}, +{"w", "", SROFFSET(w), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0}, +{"h", "", SROFFSET(h), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0}, +{"type", "", SROFFSET(type), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, 0}, +{"flags", "", SROFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, 1, 0, "flags"}, +{"forced", "", SROFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, 1, 0}, +{NULL}, +}; + +static const AVClass av_subtitle_rect_class = { + .class_name = "AVSubtitleRect", + .item_name = NULL, + .option = subtitle_rect_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVClass *avcodec_get_subtitle_rect_class(void) +{ + return &av_subtitle_rect_class; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/options_table.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/options_table.h new file mode 100644 index 0000000000..4a266eca16 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/options_table.h @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPTIONS_TABLE_H +#define AVCODEC_OPTIONS_TABLE_H + +#include +#include +#include + +#include "libavutil/opt.h" +#include "avcodec.h" +#include "version.h" + +#define OFFSET(x) offsetof(AVCodecContext,x) +#define DEFAULT 0 //should be NAN but it does not work as it is not a constant in glibc as required by ANSI/ISO C +//these names are too long to be readable +#define V AV_OPT_FLAG_VIDEO_PARAM +#define A AV_OPT_FLAG_AUDIO_PARAM +#define S AV_OPT_FLAG_SUBTITLE_PARAM +#define E AV_OPT_FLAG_ENCODING_PARAM +#define D AV_OPT_FLAG_DECODING_PARAM + +#define AV_CODEC_DEFAULT_BITRATE 200*1000 + +static const AVOption avcodec_options[] = { +{"b", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT64, {.i64 = AV_CODEC_DEFAULT_BITRATE }, 0, INT64_MAX, A|V|E}, +{"ab", "set bitrate (in bits/s)", OFFSET(bit_rate), AV_OPT_TYPE_INT64, {.i64 = 128*1000 }, 0, INT_MAX, A|E}, +{"bt", "Set video bitrate tolerance (in bits/s). In 1-pass mode, bitrate tolerance specifies how far " + "ratecontrol is willing to deviate from the target average bitrate value. This is not related " + "to minimum/maximum bitrate. Lowering tolerance too much has an adverse effect on quality.", + OFFSET(bit_rate_tolerance), AV_OPT_TYPE_INT, {.i64 = AV_CODEC_DEFAULT_BITRATE*20 }, 1, INT_MAX, V|E}, +{"flags", NULL, OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, UINT_MAX, V|A|S|E|D, "flags"}, +{"unaligned", "allow decoders to produce unaligned output", 0, AV_OPT_TYPE_CONST, { .i64 = AV_CODEC_FLAG_UNALIGNED }, INT_MIN, INT_MAX, V | D, "flags" }, +{"mv4", "use four motion vectors per macroblock (MPEG-4)", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_4MV }, INT_MIN, INT_MAX, V|E, "flags"}, +{"qpel", "use 1/4-pel motion compensation", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_QPEL }, INT_MIN, INT_MAX, V|E, "flags"}, +{"loop", "use loop filter", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_LOOP_FILTER }, INT_MIN, INT_MAX, V|E, "flags"}, +{"qscale", "use fixed qscale", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_QSCALE }, INT_MIN, INT_MAX, 0, "flags"}, +{"pass1", "use internal 2-pass ratecontrol in first pass mode", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_PASS1 }, INT_MIN, INT_MAX, 0, "flags"}, +{"pass2", "use internal 2-pass ratecontrol in second pass mode", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_PASS2 }, INT_MIN, INT_MAX, 0, "flags"}, +{"gray", "only decode/encode grayscale", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_GRAY }, INT_MIN, INT_MAX, V|E|D, "flags"}, +{"psnr", "error[?] variables will be set during encoding", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_PSNR }, INT_MIN, INT_MAX, V|E, "flags"}, +{"truncated", "Input bitstream might be randomly truncated", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_TRUNCATED }, INT_MIN, INT_MAX, V|D, "flags"}, +{"ildct", "use interlaced DCT", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_INTERLACED_DCT }, INT_MIN, INT_MAX, V|E, "flags"}, +{"low_delay", "force low delay", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_LOW_DELAY }, INT_MIN, INT_MAX, V|D|E, "flags"}, +{"global_header", "place global headers in extradata instead of every keyframe", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_GLOBAL_HEADER }, INT_MIN, INT_MAX, V|A|E, "flags"}, +{"bitexact", "use only bitexact functions (except (I)DCT)", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_BITEXACT }, INT_MIN, INT_MAX, A|V|S|D|E, "flags"}, +{"aic", "H.263 advanced intra coding / MPEG-4 AC prediction", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_AC_PRED }, INT_MIN, INT_MAX, V|E, "flags"}, +{"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, "flags"}, +{"cgop", "closed GOP", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, "flags"}, +{"output_corrupt", "Output even potentially corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_OUTPUT_CORRUPT }, INT_MIN, INT_MAX, V|D, "flags"}, +{"drop_changed", "Drop frames whose parameters differ from first decoded frame", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_DROPCHANGED }, INT_MIN, INT_MAX, A|V|D, "flags"}, +{"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D, "flags2"}, +{"fast", "allow non-spec-compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, "flags2"}, +{"noout", "skip bitstream encoding", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_NO_OUTPUT }, INT_MIN, INT_MAX, V|E, "flags2"}, +{"ignorecrop", "ignore cropping information from sps", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_IGNORE_CROP }, INT_MIN, INT_MAX, V|D, "flags2"}, +{"local_header", "place global headers at every keyframe instead of in extradata", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_LOCAL_HEADER }, INT_MIN, INT_MAX, V|E, "flags2"}, +{"chunks", "Frame data might be split into multiple chunks", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_CHUNKS }, INT_MIN, INT_MAX, V|D, "flags2"}, +{"showall", "Show all frames before the first keyframe", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_SHOW_ALL }, INT_MIN, INT_MAX, V|D, "flags2"}, +{"export_mvs", "export motion vectors through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_EXPORT_MVS}, INT_MIN, INT_MAX, V|D, "flags2"}, +{"skip_manual", "do not skip samples and export skip information as frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_SKIP_MANUAL}, INT_MIN, INT_MAX, V|D, "flags2"}, +{"ass_ro_flush_noop", "do not reset ASS ReadOrder field on flush", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_RO_FLUSH_NOOP}, INT_MIN, INT_MAX, S|D, "flags2"}, +{"time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, INT_MAX}, +{"g", "set the group of picture (GOP) size", OFFSET(gop_size), AV_OPT_TYPE_INT, {.i64 = 12 }, INT_MIN, INT_MAX, V|E}, +{"ar", "set audio sampling rate (in Hz)", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, A|D|E}, +{"ac", "set number of audio channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, A|D|E}, +{"cutoff", "set cutoff bandwidth", OFFSET(cutoff), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, A|E}, +{"frame_size", NULL, OFFSET(frame_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, A|E}, +{"frame_number", NULL, OFFSET(frame_number), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"delay", NULL, OFFSET(delay), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"qcomp", "video quantizer scale compression (VBR). Constant of ratecontrol equation. " + "Recommended range for default rc_eq: 0.0-1.0", + OFFSET(qcompress), AV_OPT_TYPE_FLOAT, {.dbl = 0.5 }, -FLT_MAX, FLT_MAX, V|E}, +{"qblur", "video quantizer scale blur (VBR)", OFFSET(qblur), AV_OPT_TYPE_FLOAT, {.dbl = 0.5 }, -1, FLT_MAX, V|E}, +{"qmin", "minimum video quantizer scale (VBR)", OFFSET(qmin), AV_OPT_TYPE_INT, {.i64 = 2 }, -1, 69, V|E}, +{"qmax", "maximum video quantizer scale (VBR)", OFFSET(qmax), AV_OPT_TYPE_INT, {.i64 = 31 }, -1, 1024, V|E}, +{"qdiff", "maximum difference between the quantizer scales (VBR)", OFFSET(max_qdiff), AV_OPT_TYPE_INT, {.i64 = 3 }, INT_MIN, INT_MAX, V|E}, +{"bf", "set maximum number of B-frames between non-B-frames", OFFSET(max_b_frames), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, -1, INT_MAX, V|E}, +{"b_qfactor", "QP factor between P- and B-frames", OFFSET(b_quant_factor), AV_OPT_TYPE_FLOAT, {.dbl = 1.25 }, -FLT_MAX, FLT_MAX, V|E}, +#if FF_API_PRIVATE_OPT +{"b_strategy", "strategy to choose between I/P/B-frames", OFFSET(b_frame_strategy), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, V|E}, +{"ps", "RTP payload size in bytes", OFFSET(rtp_payload_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#endif +#if FF_API_STAT_BITS +{"mv_bits", NULL, OFFSET(mv_bits), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"header_bits", NULL, OFFSET(header_bits), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"i_tex_bits", NULL, OFFSET(i_tex_bits), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"p_tex_bits", NULL, OFFSET(p_tex_bits), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"i_count", NULL, OFFSET(i_count), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"p_count", NULL, OFFSET(p_count), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"skip_count", NULL, OFFSET(skip_count), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"misc_bits", NULL, OFFSET(misc_bits), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"frame_bits", NULL, OFFSET(frame_bits), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +#endif +{"codec_tag", NULL, OFFSET(codec_tag), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"bug", "work around not autodetected encoder bugs", OFFSET(workaround_bugs), AV_OPT_TYPE_FLAGS, {.i64 = FF_BUG_AUTODETECT }, INT_MIN, INT_MAX, V|D, "bug"}, +{"autodetect", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_AUTODETECT }, INT_MIN, INT_MAX, V|D, "bug"}, +{"xvid_ilace", "Xvid interlacing bug (autodetected if FOURCC == XVIX)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_XVID_ILACE }, INT_MIN, INT_MAX, V|D, "bug"}, +{"ump4", "(autodetected if FOURCC == UMP4)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_UMP4 }, INT_MIN, INT_MAX, V|D, "bug"}, +{"no_padding", "padding bug (autodetected)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_NO_PADDING }, INT_MIN, INT_MAX, V|D, "bug"}, +{"amv", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_AMV }, INT_MIN, INT_MAX, V|D, "bug"}, +{"qpel_chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_QPEL_CHROMA }, INT_MIN, INT_MAX, V|D, "bug"}, +{"std_qpel", "old standard qpel (autodetected per FOURCC/version)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_STD_QPEL }, INT_MIN, INT_MAX, V|D, "bug"}, +{"qpel_chroma2", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_QPEL_CHROMA2 }, INT_MIN, INT_MAX, V|D, "bug"}, +{"direct_blocksize", "direct-qpel-blocksize bug (autodetected per FOURCC/version)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_DIRECT_BLOCKSIZE }, INT_MIN, INT_MAX, V|D, "bug"}, +{"edge", "edge padding bug (autodetected per FOURCC/version)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_EDGE }, INT_MIN, INT_MAX, V|D, "bug"}, +{"hpel_chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_HPEL_CHROMA }, INT_MIN, INT_MAX, V|D, "bug"}, +{"dc_clip", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_DC_CLIP }, INT_MIN, INT_MAX, V|D, "bug"}, +{"ms", "work around various bugs in Microsoft's broken decoders", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_MS }, INT_MIN, INT_MAX, V|D, "bug"}, +{"trunc", "truncated frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_TRUNCATED}, INT_MIN, INT_MAX, V|D, "bug"}, +{"iedge", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_IEDGE }, INT_MIN, INT_MAX, V|D, "bug"}, +{"strict", "how strictly to follow the standards", OFFSET(strict_std_compliance), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, A|V|D|E, "strict"}, +{"very", "strictly conform to a older more strict version of the spec or reference software", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_VERY_STRICT }, INT_MIN, INT_MAX, A|V|D|E, "strict"}, +{"strict", "strictly conform to all the things in the spec no matter what the consequences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_STRICT }, INT_MIN, INT_MAX, A|V|D|E, "strict"}, +{"normal", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_NORMAL }, INT_MIN, INT_MAX, A|V|D|E, "strict"}, +{"unofficial", "allow unofficial extensions", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_UNOFFICIAL }, INT_MIN, INT_MAX, A|V|D|E, "strict"}, +{"experimental", "allow non-standardized experimental things", 0, AV_OPT_TYPE_CONST, {.i64 = FF_COMPLIANCE_EXPERIMENTAL }, INT_MIN, INT_MAX, A|V|D|E, "strict"}, +{"b_qoffset", "QP offset between P- and B-frames", OFFSET(b_quant_offset), AV_OPT_TYPE_FLOAT, {.dbl = 1.25 }, -FLT_MAX, FLT_MAX, V|E}, +{"err_detect", "set error detection flags", OFFSET(err_recognition), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, INT_MIN, INT_MAX, A|V|D, "err_detect"}, +{"crccheck", "verify embedded CRCs", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CRCCHECK }, INT_MIN, INT_MAX, A|V|D, "err_detect"}, +{"bitstream", "detect bitstream specification deviations", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BITSTREAM }, INT_MIN, INT_MAX, A|V|D, "err_detect"}, +{"buffer", "detect improper bitstream length", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_BUFFER }, INT_MIN, INT_MAX, A|V|D, "err_detect"}, +{"explode", "abort decoding on minor error detection", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_EXPLODE }, INT_MIN, INT_MAX, A|V|D, "err_detect"}, +{"ignore_err", "ignore errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_IGNORE_ERR }, INT_MIN, INT_MAX, A|V|D, "err_detect"}, +{"careful", "consider things that violate the spec, are fast to check and have not been seen in the wild as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_CAREFUL }, INT_MIN, INT_MAX, A|V|D, "err_detect"}, +{"compliant", "consider all spec non compliancies as errors", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_COMPLIANT }, INT_MIN, INT_MAX, A|V|D, "err_detect"}, +{"aggressive", "consider things that a sane encoder should not do as an error", 0, AV_OPT_TYPE_CONST, {.i64 = AV_EF_AGGRESSIVE }, INT_MIN, INT_MAX, A|V|D, "err_detect"}, +{"has_b_frames", NULL, OFFSET(has_b_frames), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX}, +{"block_align", NULL, OFFSET(block_align), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX}, +#if FF_API_PRIVATE_OPT +{"mpeg_quant", "use MPEG quantizers instead of H.263", OFFSET(mpeg_quant), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#endif +{"rc_override_count", NULL, OFFSET(rc_override_count), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"maxrate", "maximum bitrate (in bits/s). Used for VBV together with bufsize.", OFFSET(rc_max_rate), AV_OPT_TYPE_INT64, {.i64 = DEFAULT }, 0, INT_MAX, V|A|E}, +{"minrate", "minimum bitrate (in bits/s). Most useful in setting up a CBR encode. It is of little use otherwise.", + OFFSET(rc_min_rate), AV_OPT_TYPE_INT64, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E}, +{"bufsize", "set ratecontrol buffer size (in bits)", OFFSET(rc_buffer_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, A|V|E}, +{"i_qfactor", "QP factor between P- and I-frames", OFFSET(i_quant_factor), AV_OPT_TYPE_FLOAT, {.dbl = -0.8 }, -FLT_MAX, FLT_MAX, V|E}, +{"i_qoffset", "QP offset between P- and I-frames", OFFSET(i_quant_offset), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, -FLT_MAX, FLT_MAX, V|E}, +{"dct", "DCT algorithm", OFFSET(dct_algo), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, V|E, "dct"}, +{"auto", "autoselect a good one", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_AUTO }, INT_MIN, INT_MAX, V|E, "dct"}, +{"fastint", "fast integer", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_FASTINT }, INT_MIN, INT_MAX, V|E, "dct"}, +{"int", "accurate integer", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_INT }, INT_MIN, INT_MAX, V|E, "dct"}, +{"mmx", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_MMX }, INT_MIN, INT_MAX, V|E, "dct"}, +{"altivec", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_ALTIVEC }, INT_MIN, INT_MAX, V|E, "dct"}, +{"faan", "floating point AAN DCT", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_FAAN }, INT_MIN, INT_MAX, V|E, "dct"}, +{"lumi_mask", "compresses bright areas stronger than medium ones", OFFSET(lumi_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E}, +{"tcplx_mask", "temporal complexity masking", OFFSET(temporal_cplx_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E}, +{"scplx_mask", "spatial complexity masking", OFFSET(spatial_cplx_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E}, +{"p_mask", "inter masking", OFFSET(p_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E}, +{"dark_mask", "compresses dark areas stronger than medium ones", OFFSET(dark_masking), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, -FLT_MAX, FLT_MAX, V|E}, +{"idct", "select IDCT implementation", OFFSET(idct_algo), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, V|E|D, "idct"}, +{"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_AUTO }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"int", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_INT }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simple", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLE }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simplemmx", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEMMX }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"arm", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_ARM }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"altivec", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_ALTIVEC }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simplearm", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARM }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simplearmv5te", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARMV5TE }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simplearmv6", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARMV6 }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"simpleneon", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLENEON }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"xvid", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"xvidmmx", "deprecated, for compatibility only", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"faani", "floating point AAN IDCT", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_FAAN }, INT_MIN, INT_MAX, V|D|E, "idct"}, +{"simpleauto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEAUTO }, INT_MIN, INT_MAX, V|E|D, "idct"}, +{"slice_count", NULL, OFFSET(slice_count), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"ec", "set error concealment strategy", OFFSET(error_concealment), AV_OPT_TYPE_FLAGS, {.i64 = 3 }, INT_MIN, INT_MAX, V|D, "ec"}, +{"guess_mvs", "iterative motion vector (MV) search (slow)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_EC_GUESS_MVS }, INT_MIN, INT_MAX, V|D, "ec"}, +{"deblock", "use strong deblock filter for damaged MBs", 0, AV_OPT_TYPE_CONST, {.i64 = FF_EC_DEBLOCK }, INT_MIN, INT_MAX, V|D, "ec"}, +{"favor_inter", "favor predicting from the previous frame", 0, AV_OPT_TYPE_CONST, {.i64 = FF_EC_FAVOR_INTER }, INT_MIN, INT_MAX, V|D, "ec"}, +{"bits_per_coded_sample", NULL, OFFSET(bits_per_coded_sample), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX}, +#if FF_API_PRIVATE_OPT +{"pred", "prediction method", OFFSET(prediction_method), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "pred"}, +{"left", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PRED_LEFT }, INT_MIN, INT_MAX, V|E, "pred"}, +{"plane", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PRED_PLANE }, INT_MIN, INT_MAX, V|E, "pred"}, +{"median", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PRED_MEDIAN }, INT_MIN, INT_MAX, V|E, "pred"}, +#endif +{"aspect", "sample aspect ratio", OFFSET(sample_aspect_ratio), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, 10, V|E}, +{"sar", "sample aspect ratio", OFFSET(sample_aspect_ratio), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, 10, V|E}, +{"debug", "print specific debug info", OFFSET(debug), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, INT_MAX, V|A|S|E|D, "debug"}, +{"pict", "picture info", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_PICT_INFO }, INT_MIN, INT_MAX, V|D, "debug"}, +{"rc", "rate control", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_RC }, INT_MIN, INT_MAX, V|E, "debug"}, +{"bitstream", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_BITSTREAM }, INT_MIN, INT_MAX, V|D, "debug"}, +{"mb_type", "macroblock (MB) type", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_MB_TYPE }, INT_MIN, INT_MAX, V|D, "debug"}, +{"qp", "per-block quantization parameter (QP)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_QP }, INT_MIN, INT_MAX, V|D, "debug"}, +#if FF_API_DEBUG_MV +{"mv", "motion vector", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_MV }, INT_MIN, INT_MAX, V|D, "debug"}, +#endif +{"dct_coeff", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_DCT_COEFF }, INT_MIN, INT_MAX, V|D, "debug"}, +{"green_metadata", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_GREEN_MD }, INT_MIN, INT_MAX, V|D, "debug"}, +{"skip", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_SKIP }, INT_MIN, INT_MAX, V|D, "debug"}, +{"startcode", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_STARTCODE }, INT_MIN, INT_MAX, V|D, "debug"}, +{"er", "error recognition", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_ER }, INT_MIN, INT_MAX, V|D, "debug"}, +{"mmco", "memory management control operations (H.264)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_MMCO }, INT_MIN, INT_MAX, V|D, "debug"}, +{"bugs", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_BUGS }, INT_MIN, INT_MAX, V|D, "debug"}, +#if FF_API_DEBUG_MV +{"vis_qp", "visualize quantization parameter (QP), lower QP are tinted greener", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_QP }, INT_MIN, INT_MAX, V|D, "debug"}, +{"vis_mb_type", "visualize block types", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MB_TYPE }, INT_MIN, INT_MAX, V|D, "debug"}, +#endif +{"buffers", "picture buffer allocations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_BUFFERS }, INT_MIN, INT_MAX, V|D, "debug"}, +{"thread_ops", "threading operations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_THREADS }, INT_MIN, INT_MAX, V|A|D, "debug"}, +{"nomc", "skip motion compensation", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_NOMC }, INT_MIN, INT_MAX, V|A|D, "debug"}, +{"dia_size", "diamond type & size for motion estimation", OFFSET(dia_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +{"last_pred", "amount of motion predictors from the previous frame", OFFSET(last_predictor_count), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#if FF_API_PRIVATE_OPT +{"preme", "pre motion estimation", OFFSET(pre_me), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#endif +{"pre_dia_size", "diamond type & size for motion estimation pre-pass", OFFSET(pre_dia_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +{"subq", "sub-pel motion estimation quality", OFFSET(me_subpel_quality), AV_OPT_TYPE_INT, {.i64 = 8 }, INT_MIN, INT_MAX, V|E}, +{"me_range", "limit motion vectors range (1023 for DivX player)", OFFSET(me_range), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +{"global_quality", NULL, OFFSET(global_quality), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E}, +#if FF_API_CODER_TYPE +{"coder", NULL, OFFSET(coder_type), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "coder"}, +{"vlc", "variable length coder / Huffman coder", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CODER_TYPE_VLC }, INT_MIN, INT_MAX, V|E, "coder"}, +{"ac", "arithmetic coder", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CODER_TYPE_AC }, INT_MIN, INT_MAX, V|E, "coder"}, +{"raw", "raw (no encoding)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CODER_TYPE_RAW }, INT_MIN, INT_MAX, V|E, "coder"}, +{"rle", "run-length coder", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CODER_TYPE_RLE }, INT_MIN, INT_MAX, V|E, "coder"}, +#endif /* FF_API_CODER_TYPE */ +#if FF_API_PRIVATE_OPT +{"context", "context model", OFFSET(context_model), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#endif +{"slice_flags", NULL, OFFSET(slice_flags), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, +{"mbd", "macroblock decision algorithm (high quality mode)", OFFSET(mb_decision), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, 2, V|E, "mbd"}, +{"simple", "use mbcmp", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MB_DECISION_SIMPLE }, INT_MIN, INT_MAX, V|E, "mbd"}, +{"bits", "use fewest bits", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MB_DECISION_BITS }, INT_MIN, INT_MAX, V|E, "mbd"}, +{"rd", "use best rate distortion", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MB_DECISION_RD }, INT_MIN, INT_MAX, V|E, "mbd"}, +#if FF_API_PRIVATE_OPT +{"sc_threshold", "scene change threshold", OFFSET(scenechange_threshold), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#endif +#if FF_API_PRIVATE_OPT +{"nr", "noise reduction", OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#endif +{"rc_init_occupancy", "number of bits which should be loaded into the rc buffer before decoding starts", OFFSET(rc_initial_buffer_occupancy), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +{"threads", "set the number of threads", OFFSET(thread_count), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, INT_MAX, V|A|E|D, "threads"}, +{"auto", "autodetect a suitable number of threads to use", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, V|E|D, "threads"}, +{"dc", "intra_dc_precision", OFFSET(intra_dc_precision), AV_OPT_TYPE_INT, {.i64 = 0 }, -8, 16, V|E}, +{"nssew", "nsse weight", OFFSET(nsse_weight), AV_OPT_TYPE_INT, {.i64 = 8 }, INT_MIN, INT_MAX, V|E}, +{"skip_top", "number of macroblock rows at the top which are skipped", OFFSET(skip_top), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|D}, +{"skip_bottom", "number of macroblock rows at the bottom which are skipped", OFFSET(skip_bottom), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|D}, +{"profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT, {.i64 = FF_PROFILE_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, "profile"}, +{"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, "profile"}, +{"aac_main", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_AAC_MAIN }, INT_MIN, INT_MAX, A|E, "profile"}, +{"aac_low", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_AAC_LOW }, INT_MIN, INT_MAX, A|E, "profile"}, +{"aac_ssr", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_AAC_SSR }, INT_MIN, INT_MAX, A|E, "profile"}, +{"aac_ltp", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_AAC_LTP }, INT_MIN, INT_MAX, A|E, "profile"}, +{"aac_he", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_AAC_HE }, INT_MIN, INT_MAX, A|E, "profile"}, +{"aac_he_v2", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_AAC_HE_V2 }, INT_MIN, INT_MAX, A|E, "profile"}, +{"aac_ld", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_AAC_LD }, INT_MIN, INT_MAX, A|E, "profile"}, +{"aac_eld", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_AAC_ELD }, INT_MIN, INT_MAX, A|E, "profile"}, +{"mpeg2_aac_low", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG2_AAC_LOW }, INT_MIN, INT_MAX, A|E, "profile"}, +{"mpeg2_aac_he", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG2_AAC_HE }, INT_MIN, INT_MAX, A|E, "profile"}, +{"dts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_DTS }, INT_MIN, INT_MAX, A|E, "profile"}, +{"dts_es", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_DTS_ES }, INT_MIN, INT_MAX, A|E, "profile"}, +{"dts_96_24", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_DTS_96_24 }, INT_MIN, INT_MAX, A|E, "profile"}, +{"dts_hd_hra", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_DTS_HD_HRA }, INT_MIN, INT_MAX, A|E, "profile"}, +{"dts_hd_ma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_DTS_HD_MA }, INT_MIN, INT_MAX, A|E, "profile"}, +{"mpeg4_sp", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG4_SIMPLE }, INT_MIN, INT_MAX, V|E, "profile"}, +{"mpeg4_core", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG4_CORE }, INT_MIN, INT_MAX, V|E, "profile"}, +{"mpeg4_main", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG4_MAIN }, INT_MIN, INT_MAX, V|E, "profile"}, +{"mpeg4_asp", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG4_ADVANCED_SIMPLE }, INT_MIN, INT_MAX, V|E, "profile"}, +{"main10", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_HEVC_MAIN_10 }, INT_MIN, INT_MAX, V|E, "profile"}, +{"msbc", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_SBC_MSBC }, INT_MIN, INT_MAX, A|E, "profile"}, +{"level", NULL, OFFSET(level), AV_OPT_TYPE_INT, {.i64 = FF_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, "level"}, +{"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, "level"}, +{"lowres", "decode at 1= 1/2, 2=1/4, 3=1/8 resolutions", OFFSET(lowres), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|A|D}, +#if FF_API_PRIVATE_OPT +{"skip_threshold", "frame skip threshold", OFFSET(frame_skip_threshold), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +{"skip_factor", "frame skip factor", OFFSET(frame_skip_factor), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +{"skip_exp", "frame skip exponent", OFFSET(frame_skip_exp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +{"skipcmp", "frame skip compare function", OFFSET(frame_skip_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +#endif +{"cmp", "full-pel ME compare function", OFFSET(me_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"subcmp", "sub-pel ME compare function", OFFSET(me_sub_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"mbcmp", "macroblock compare function", OFFSET(mb_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"ildctcmp", "interlaced DCT compare function", OFFSET(ildct_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_VSAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"precmp", "pre motion estimation compare function", OFFSET(me_pre_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"sad", "sum of absolute differences, fast", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"sse", "sum of squared errors", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SSE }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"satd", "sum of absolute Hadamard transformed differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SATD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"dct", "sum of absolute DCT transformed differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"psnr", "sum of squared quantization errors (avoid, low quality)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_PSNR }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"bit", "number of bits needed for the block", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_BIT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"rd", "rate distortion optimal, slow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_RD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"zero", "0", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_ZERO }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"vsad", "sum of absolute vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"vsse", "sum of squared vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSSE }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"nsse", "noise preserving sum of squared differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_NSSE }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +#if CONFIG_SNOW_ENCODER +{"w53", "5/3 wavelet, only used in snow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_W53 }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"w97", "9/7 wavelet, only used in snow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_W97 }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +#endif +{"dctmax", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"msad", "sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"mblmin", "minimum macroblock Lagrange factor (VBR)", OFFSET(mb_lmin), AV_OPT_TYPE_INT, {.i64 = FF_QP2LAMBDA * 2 }, 1, FF_LAMBDA_MAX, V|E}, +{"mblmax", "maximum macroblock Lagrange factor (VBR)", OFFSET(mb_lmax), AV_OPT_TYPE_INT, {.i64 = FF_QP2LAMBDA * 31 }, 1, FF_LAMBDA_MAX, V|E}, +#if FF_API_PRIVATE_OPT +{"mepc", "motion estimation bitrate penalty compensation (1.0 = 256)", OFFSET(me_penalty_compensation), AV_OPT_TYPE_INT, {.i64 = 256 }, INT_MIN, INT_MAX, V|E}, +#endif +{"skip_loop_filter", "skip loop filtering process for the selected frames", OFFSET(skip_loop_filter), AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"}, +{"skip_idct" , "skip IDCT/dequantization for the selected frames", OFFSET(skip_idct), AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"}, +{"skip_frame" , "skip decoding for the selected frames", OFFSET(skip_frame), AV_OPT_TYPE_INT, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"}, +{"none" , "discard no frame", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONE }, INT_MIN, INT_MAX, V|D, "avdiscard"}, +{"default" , "discard useless frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_DEFAULT }, INT_MIN, INT_MAX, V|D, "avdiscard"}, +{"noref" , "discard all non-reference frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONREF }, INT_MIN, INT_MAX, V|D, "avdiscard"}, +{"bidir" , "discard all bidirectional frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_BIDIR }, INT_MIN, INT_MAX, V|D, "avdiscard"}, +{"nokey" , "discard all frames except keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONKEY }, INT_MIN, INT_MAX, V|D, "avdiscard"}, +{"nointra" , "discard all frames except I frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_NONINTRA}, INT_MIN, INT_MAX, V|D, "avdiscard"}, +{"all" , "discard all frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVDISCARD_ALL }, INT_MIN, INT_MAX, V|D, "avdiscard"}, +{"bidir_refine", "refine the two motion vectors used in bidirectional macroblocks", OFFSET(bidir_refine), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, 4, V|E}, +#if FF_API_PRIVATE_OPT +{"brd_scale", "downscale frames for dynamic B-frame decision", OFFSET(brd_scale), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, 10, V|E}, +#endif +{"keyint_min", "minimum interval between IDR-frames", OFFSET(keyint_min), AV_OPT_TYPE_INT, {.i64 = 25 }, INT_MIN, INT_MAX, V|E}, +{"refs", "reference frames to consider for motion compensation", OFFSET(refs), AV_OPT_TYPE_INT, {.i64 = 1 }, INT_MIN, INT_MAX, V|E}, +#if FF_API_PRIVATE_OPT +{"chromaoffset", "chroma QP offset from luma", OFFSET(chromaoffset), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#endif +{"trellis", "rate-distortion optimal quantization", OFFSET(trellis), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E}, +{"mv0_threshold", NULL, OFFSET(mv0_threshold), AV_OPT_TYPE_INT, {.i64 = 256 }, 0, INT_MAX, V|E}, +#if FF_API_PRIVATE_OPT +{"b_sensitivity", "adjust sensitivity of b_frame_strategy 1", OFFSET(b_sensitivity), AV_OPT_TYPE_INT, {.i64 = 40 }, 1, INT_MAX, V|E}, +#endif +{"compression_level", NULL, OFFSET(compression_level), AV_OPT_TYPE_INT, {.i64 = FF_COMPRESSION_DEFAULT }, INT_MIN, INT_MAX, V|A|E}, +#if FF_API_PRIVATE_OPT +{"min_prediction_order", NULL, OFFSET(min_prediction_order), AV_OPT_TYPE_INT, {.i64 = -1 }, INT_MIN, INT_MAX, A|E}, +{"max_prediction_order", NULL, OFFSET(max_prediction_order), AV_OPT_TYPE_INT, {.i64 = -1 }, INT_MIN, INT_MAX, A|E}, +{"timecode_frame_start", "GOP timecode frame start number, in non-drop-frame format", OFFSET(timecode_frame_start), AV_OPT_TYPE_INT64, {.i64 = -1 }, -1, INT64_MAX, V|E}, +#endif +{"bits_per_raw_sample", NULL, OFFSET(bits_per_raw_sample), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX}, +{"channel_layout", NULL, OFFSET(channel_layout), AV_OPT_TYPE_UINT64, {.i64 = DEFAULT }, 0, UINT64_MAX, A|E|D, "channel_layout"}, +{"request_channel_layout", NULL, OFFSET(request_channel_layout), AV_OPT_TYPE_UINT64, {.i64 = DEFAULT }, 0, UINT64_MAX, A|D, "request_channel_layout"}, +{"rc_max_vbv_use", NULL, OFFSET(rc_max_available_vbv_use), AV_OPT_TYPE_FLOAT, {.dbl = 0 }, 0.0, FLT_MAX, V|E}, +{"rc_min_vbv_use", NULL, OFFSET(rc_min_vbv_overflow_use), AV_OPT_TYPE_FLOAT, {.dbl = 3 }, 0.0, FLT_MAX, V|E}, +{"ticks_per_frame", NULL, OFFSET(ticks_per_frame), AV_OPT_TYPE_INT, {.i64 = 1 }, 1, INT_MAX, A|V|E|D}, +{"color_primaries", "color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64 = AVCOL_PRI_UNSPECIFIED }, 1, INT_MAX, V|E|D, "color_primaries_type"}, +{"bt709", "BT.709", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_BT709 }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"unknown", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"bt470m", "BT.470 M", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_BT470M }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"bt470bg", "BT.470 BG", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_BT470BG }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"smpte170m", "SMPTE 170 M", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_SMPTE170M }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"smpte240m", "SMPTE 240 M", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_SMPTE240M }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"film", "Film", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_FILM }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"bt2020", "BT.2020", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_BT2020 }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"smpte428", "SMPTE 428-1", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_SMPTE428 }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"smpte428_1", "SMPTE 428-1", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_SMPTE428 }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"smpte431", "SMPTE 431-2", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_SMPTE431 }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"smpte432", "SMPTE 422-1", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_SMPTE432 }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"jedec-p22", "JEDEC P22", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_JEDEC_P22 }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"unspecified", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "color_primaries_type"}, +{"color_trc", "color transfer characteristics", OFFSET(color_trc), AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_UNSPECIFIED }, 1, INT_MAX, V|E|D, "color_trc_type"}, +{"bt709", "BT.709", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT709 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"unknown", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"gamma22", "BT.470 M", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_GAMMA22 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"gamma28", "BT.470 BG", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_GAMMA28 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"smpte170m", "SMPTE 170 M", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_SMPTE170M }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"smpte240m", "SMPTE 240 M", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_SMPTE240M }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"linear", "Linear", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_LINEAR }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"log100", "Log", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_LOG }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"log316", "Log square root", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_LOG_SQRT }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"iec61966-2-4", "IEC 61966-2-4", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_IEC61966_2_4 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"bt1361e", "BT.1361", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT1361_ECG }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"iec61966-2-1", "IEC 61966-2-1", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_IEC61966_2_1 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"bt2020-10", "BT.2020 - 10 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT2020_10 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"bt2020-12", "BT.2020 - 12 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT2020_12 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"smpte2084", "SMPTE 2084", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_SMPTE2084 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"smpte428", "SMPTE 428-1", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_SMPTE428 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"arib-std-b67", "ARIB STD-B67", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_ARIB_STD_B67 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"unspecified", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"log", "Log", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_LOG }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"log_sqrt", "Log square root", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_LOG_SQRT }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"iec61966_2_4", "IEC 61966-2-4", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_IEC61966_2_4 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"bt1361", "BT.1361", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT1361_ECG }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"iec61966_2_1", "IEC 61966-2-1", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_IEC61966_2_1 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"bt2020_10bit", "BT.2020 - 10 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT2020_10 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"bt2020_12bit", "BT.2020 - 12 bit", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT2020_12 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"smpte428_1", "SMPTE 428-1", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_SMPTE428 }, INT_MIN, INT_MAX, V|E|D, "color_trc_type"}, +{"colorspace", "color space", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = AVCOL_SPC_UNSPECIFIED }, 0, INT_MAX, V|E|D, "colorspace_type"}, +{"rgb", "RGB", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_RGB }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"bt709", "BT.709", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT709 }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"unknown", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"fcc", "FCC", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_FCC }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"bt470bg", "BT.470 BG", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT470BG }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"smpte170m", "SMPTE 170 M", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_SMPTE170M }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"smpte240m", "SMPTE 240 M", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_SMPTE240M }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"ycgco", "YCGCO", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_YCGCO }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"bt2020nc", "BT.2020 NCL", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT2020_NCL }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"bt2020c", "BT.2020 CL", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT2020_CL }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"smpte2085", "SMPTE 2085", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_SMPTE2085 }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"unspecified", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"ycocg", "YCGCO", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_YCGCO }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"bt2020_ncl", "BT.2020 NCL", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT2020_NCL }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"bt2020_cl", "BT.2020 CL", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT2020_CL }, INT_MIN, INT_MAX, V|E|D, "colorspace_type"}, +{"color_range", "color range", OFFSET(color_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, INT_MAX, V|E|D, "color_range_type"}, +{"unknown", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "color_range_type"}, +{"tv", "MPEG (219*2^(n-8))", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG }, INT_MIN, INT_MAX, V|E|D, "color_range_type"}, +{"pc", "JPEG (2^n-1)", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG }, INT_MIN, INT_MAX, V|E|D, "color_range_type"}, +{"unspecified", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "color_range_type"}, +{"mpeg", "MPEG (219*2^(n-8))", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG }, INT_MIN, INT_MAX, V|E|D, "color_range_type"}, +{"jpeg", "JPEG (2^n-1)", 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG }, INT_MIN, INT_MAX, V|E|D, "color_range_type"}, +{"chroma_sample_location", "chroma sample location", OFFSET(chroma_sample_location), AV_OPT_TYPE_INT, {.i64 = AVCHROMA_LOC_UNSPECIFIED }, 0, INT_MAX, V|E|D, "chroma_sample_location_type"}, +{"unknown", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, +{"left", "Left", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_LEFT }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, +{"center", "Center", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_CENTER }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, +{"topleft", "Top-left", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_TOPLEFT }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, +{"top", "Top", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_TOP }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, +{"bottomleft", "Bottom-left", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_BOTTOMLEFT }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, +{"bottom", "Bottom", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_BOTTOM }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, +{"unspecified", "Unspecified", 0, AV_OPT_TYPE_CONST, {.i64 = AVCHROMA_LOC_UNSPECIFIED }, INT_MIN, INT_MAX, V|E|D, "chroma_sample_location_type"}, +{"log_level_offset", "set the log level offset", OFFSET(log_level_offset), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX }, +{"slices", "set the number of slices, used in parallelized encoding", OFFSET(slices), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|E}, +{"thread_type", "select multithreading type", OFFSET(thread_type), AV_OPT_TYPE_FLAGS, {.i64 = FF_THREAD_SLICE|FF_THREAD_FRAME }, 0, INT_MAX, V|A|E|D, "thread_type"}, +{"slice", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_THREAD_SLICE }, INT_MIN, INT_MAX, V|E|D, "thread_type"}, +{"frame", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_THREAD_FRAME }, INT_MIN, INT_MAX, V|E|D, "thread_type"}, +{"audio_service_type", "audio service type", OFFSET(audio_service_type), AV_OPT_TYPE_INT, {.i64 = AV_AUDIO_SERVICE_TYPE_MAIN }, 0, AV_AUDIO_SERVICE_TYPE_NB-1, A|E, "audio_service_type"}, +{"ma", "Main Audio Service", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_MAIN }, INT_MIN, INT_MAX, A|E, "audio_service_type"}, +{"ef", "Effects", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_EFFECTS }, INT_MIN, INT_MAX, A|E, "audio_service_type"}, +{"vi", "Visually Impaired", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED }, INT_MIN, INT_MAX, A|E, "audio_service_type"}, +{"hi", "Hearing Impaired", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED }, INT_MIN, INT_MAX, A|E, "audio_service_type"}, +{"di", "Dialogue", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_DIALOGUE }, INT_MIN, INT_MAX, A|E, "audio_service_type"}, +{"co", "Commentary", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_COMMENTARY }, INT_MIN, INT_MAX, A|E, "audio_service_type"}, +{"em", "Emergency", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_EMERGENCY }, INT_MIN, INT_MAX, A|E, "audio_service_type"}, +{"vo", "Voice Over", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_VOICE_OVER }, INT_MIN, INT_MAX, A|E, "audio_service_type"}, +{"ka", "Karaoke", 0, AV_OPT_TYPE_CONST, {.i64 = AV_AUDIO_SERVICE_TYPE_KARAOKE }, INT_MIN, INT_MAX, A|E, "audio_service_type"}, +{"request_sample_fmt", "sample format audio decoders should prefer", OFFSET(request_sample_fmt), AV_OPT_TYPE_SAMPLE_FMT, {.i64=AV_SAMPLE_FMT_NONE}, -1, INT_MAX, A|D, "request_sample_fmt"}, +{"pkt_timebase", NULL, OFFSET(pkt_timebase), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, 0, INT_MAX, 0}, +{"sub_charenc", "set input text subtitles character encoding", OFFSET(sub_charenc), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, S|D}, +{"sub_charenc_mode", "set input text subtitles character encoding mode", OFFSET(sub_charenc_mode), AV_OPT_TYPE_FLAGS, {.i64 = FF_SUB_CHARENC_MODE_AUTOMATIC}, -1, INT_MAX, S|D, "sub_charenc_mode"}, +{"do_nothing", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_DO_NOTHING}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"}, +{"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_AUTOMATIC}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"}, +{"pre_decoder", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_PRE_DECODER}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"}, +{"ignore", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_IGNORE}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"}, +#if FF_API_ASS_TIMING +{"sub_text_format", "set decoded text subtitle format", OFFSET(sub_text_format), AV_OPT_TYPE_INT, {.i64 = FF_SUB_TEXT_FMT_ASS_WITH_TIMINGS}, 0, 1, S|D, "sub_text_format"}, +#else +{"sub_text_format", "set decoded text subtitle format", OFFSET(sub_text_format), AV_OPT_TYPE_INT, {.i64 = FF_SUB_TEXT_FMT_ASS}, 0, 1, S|D, "sub_text_format"}, +#endif +{"ass", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_TEXT_FMT_ASS}, INT_MIN, INT_MAX, S|D, "sub_text_format"}, +#if FF_API_ASS_TIMING +{"ass_with_timings", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_TEXT_FMT_ASS_WITH_TIMINGS}, INT_MIN, INT_MAX, S|D, "sub_text_format"}, +#endif +{"refcounted_frames", NULL, OFFSET(refcounted_frames), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, A|V|D }, +#if FF_API_SIDEDATA_ONLY_PKT +{"side_data_only_packets", NULL, OFFSET(side_data_only_packets), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, A|V|E }, +#endif +{"apply_cropping", NULL, OFFSET(apply_cropping), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, V | D }, +{"skip_alpha", "Skip processing alpha", OFFSET(skip_alpha), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, V|D }, +{"field_order", "Field order", OFFSET(field_order), AV_OPT_TYPE_INT, {.i64 = AV_FIELD_UNKNOWN }, 0, 5, V|D|E, "field_order" }, +{"progressive", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_PROGRESSIVE }, 0, 0, V|D|E, "field_order" }, +{"tt", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_TT }, 0, 0, V|D|E, "field_order" }, +{"bb", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_BB }, 0, 0, V|D|E, "field_order" }, +{"tb", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_TB }, 0, 0, V|D|E, "field_order" }, +{"bt", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AV_FIELD_BT }, 0, 0, V|D|E, "field_order" }, +{"dump_separator", "set information dump field separator", OFFSET(dump_separator), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, A|V|S|D|E}, +{"codec_whitelist", "List of decoders that are allowed to be used", OFFSET(codec_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, A|V|S|D }, +{"pixel_format", "set pixel format", OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, {.i64=AV_PIX_FMT_NONE}, -1, INT_MAX, 0 }, +{"video_size", "set video size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str=NULL}, 0, INT_MAX, 0 }, +{"max_pixels", "Maximum number of pixels", OFFSET(max_pixels), AV_OPT_TYPE_INT64, {.i64 = INT_MAX }, 0, INT_MAX, A|V|S|D|E }, +{"hwaccel_flags", NULL, OFFSET(hwaccel_flags), AV_OPT_TYPE_FLAGS, {.i64 = AV_HWACCEL_FLAG_IGNORE_LEVEL }, 0, UINT_MAX, V|D, "hwaccel_flags"}, +{"ignore_level", "ignore level even if the codec level used is unknown or higher than the maximum supported level reported by the hardware driver", 0, AV_OPT_TYPE_CONST, { .i64 = AV_HWACCEL_FLAG_IGNORE_LEVEL }, INT_MIN, INT_MAX, V | D, "hwaccel_flags" }, +{"allow_high_depth", "allow to output YUV pixel formats with a different chroma sampling than 4:2:0 and/or other than 8 bits per component", 0, AV_OPT_TYPE_CONST, {.i64 = AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH }, INT_MIN, INT_MAX, V | D, "hwaccel_flags"}, +{"allow_profile_mismatch", "attempt to decode anyway if HW accelerated decoder's supported profiles do not exactly match the stream", 0, AV_OPT_TYPE_CONST, {.i64 = AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH }, INT_MIN, INT_MAX, V | D, "hwaccel_flags"}, +{"extra_hw_frames", "Number of extra hardware frames to allocate for the user", OFFSET(extra_hw_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, V|D }, +{"discard_damaged_percentage", "Percentage of damaged samples to discard a frame", OFFSET(discard_damaged_percentage), AV_OPT_TYPE_INT, {.i64 = 95 }, 0, 100, V|D }, +{NULL}, +}; + +#undef A +#undef V +#undef S +#undef E +#undef D +#undef DEFAULT +#undef OFFSET + +#endif /* AVCODEC_OPTIONS_TABLE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus.c new file mode 100644 index 0000000000..f74278a7e3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus.c @@ -0,0 +1,900 @@ +/* + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Opus decoder/parser shared code + */ + +#include + +#include "libavutil/error.h" +#include "libavutil/ffmath.h" + +#include "opus_celt.h" +#include "opustab.h" +#include "internal.h" +#include "vorbis.h" + +static const uint16_t opus_frame_duration[32] = { + 480, 960, 1920, 2880, + 480, 960, 1920, 2880, + 480, 960, 1920, 2880, + 480, 960, + 480, 960, + 120, 240, 480, 960, + 120, 240, 480, 960, + 120, 240, 480, 960, + 120, 240, 480, 960, +}; + +/** + * Read a 1- or 2-byte frame length + */ +static inline int xiph_lacing_16bit(const uint8_t **ptr, const uint8_t *end) +{ + int val; + + if (*ptr >= end) + return AVERROR_INVALIDDATA; + val = *(*ptr)++; + if (val >= 252) { + if (*ptr >= end) + return AVERROR_INVALIDDATA; + val += 4 * *(*ptr)++; + } + return val; +} + +/** + * Read a multi-byte length (used for code 3 packet padding size) + */ +static inline int xiph_lacing_full(const uint8_t **ptr, const uint8_t *end) +{ + int val = 0; + int next; + + while (1) { + if (*ptr >= end || val > INT_MAX - 254) + return AVERROR_INVALIDDATA; + next = *(*ptr)++; + val += next; + if (next < 255) + break; + else + val--; + } + return val; +} + +/** + * Parse Opus packet info from raw packet data + */ +int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size, + int self_delimiting) +{ + const uint8_t *ptr = buf; + const uint8_t *end = buf + buf_size; + int padding = 0; + int frame_bytes, i; + + if (buf_size < 1) + goto fail; + + /* TOC byte */ + i = *ptr++; + pkt->code = (i ) & 0x3; + pkt->stereo = (i >> 2) & 0x1; + pkt->config = (i >> 3) & 0x1F; + + /* code 2 and code 3 packets have at least 1 byte after the TOC */ + if (pkt->code >= 2 && buf_size < 2) + goto fail; + + switch (pkt->code) { + case 0: + /* 1 frame */ + pkt->frame_count = 1; + pkt->vbr = 0; + + if (self_delimiting) { + int len = xiph_lacing_16bit(&ptr, end); + if (len < 0 || len > end - ptr) + goto fail; + end = ptr + len; + buf_size = end - buf; + } + + frame_bytes = end - ptr; + if (frame_bytes > MAX_FRAME_SIZE) + goto fail; + pkt->frame_offset[0] = ptr - buf; + pkt->frame_size[0] = frame_bytes; + break; + case 1: + /* 2 frames, equal size */ + pkt->frame_count = 2; + pkt->vbr = 0; + + if (self_delimiting) { + int len = xiph_lacing_16bit(&ptr, end); + if (len < 0 || 2 * len > end - ptr) + goto fail; + end = ptr + 2 * len; + buf_size = end - buf; + } + + frame_bytes = end - ptr; + if (frame_bytes & 1 || frame_bytes >> 1 > MAX_FRAME_SIZE) + goto fail; + pkt->frame_offset[0] = ptr - buf; + pkt->frame_size[0] = frame_bytes >> 1; + pkt->frame_offset[1] = pkt->frame_offset[0] + pkt->frame_size[0]; + pkt->frame_size[1] = frame_bytes >> 1; + break; + case 2: + /* 2 frames, different sizes */ + pkt->frame_count = 2; + pkt->vbr = 1; + + /* read 1st frame size */ + frame_bytes = xiph_lacing_16bit(&ptr, end); + if (frame_bytes < 0) + goto fail; + + if (self_delimiting) { + int len = xiph_lacing_16bit(&ptr, end); + if (len < 0 || len + frame_bytes > end - ptr) + goto fail; + end = ptr + frame_bytes + len; + buf_size = end - buf; + } + + pkt->frame_offset[0] = ptr - buf; + pkt->frame_size[0] = frame_bytes; + + /* calculate 2nd frame size */ + frame_bytes = end - ptr - pkt->frame_size[0]; + if (frame_bytes < 0 || frame_bytes > MAX_FRAME_SIZE) + goto fail; + pkt->frame_offset[1] = pkt->frame_offset[0] + pkt->frame_size[0]; + pkt->frame_size[1] = frame_bytes; + break; + case 3: + /* 1 to 48 frames, can be different sizes */ + i = *ptr++; + pkt->frame_count = (i ) & 0x3F; + padding = (i >> 6) & 0x01; + pkt->vbr = (i >> 7) & 0x01; + + if (pkt->frame_count == 0 || pkt->frame_count > MAX_FRAMES) + goto fail; + + /* read padding size */ + if (padding) { + padding = xiph_lacing_full(&ptr, end); + if (padding < 0) + goto fail; + } + + /* read frame sizes */ + if (pkt->vbr) { + /* for VBR, all frames except the final one have their size coded + in the bitstream. the last frame size is implicit. */ + int total_bytes = 0; + for (i = 0; i < pkt->frame_count - 1; i++) { + frame_bytes = xiph_lacing_16bit(&ptr, end); + if (frame_bytes < 0) + goto fail; + pkt->frame_size[i] = frame_bytes; + total_bytes += frame_bytes; + } + + if (self_delimiting) { + int len = xiph_lacing_16bit(&ptr, end); + if (len < 0 || len + total_bytes + padding > end - ptr) + goto fail; + end = ptr + total_bytes + len + padding; + buf_size = end - buf; + } + + frame_bytes = end - ptr - padding; + if (total_bytes > frame_bytes) + goto fail; + pkt->frame_offset[0] = ptr - buf; + for (i = 1; i < pkt->frame_count; i++) + pkt->frame_offset[i] = pkt->frame_offset[i-1] + pkt->frame_size[i-1]; + pkt->frame_size[pkt->frame_count-1] = frame_bytes - total_bytes; + } else { + /* for CBR, the remaining packet bytes are divided evenly between + the frames */ + if (self_delimiting) { + frame_bytes = xiph_lacing_16bit(&ptr, end); + if (frame_bytes < 0 || pkt->frame_count * frame_bytes + padding > end - ptr) + goto fail; + end = ptr + pkt->frame_count * frame_bytes + padding; + buf_size = end - buf; + } else { + frame_bytes = end - ptr - padding; + if (frame_bytes % pkt->frame_count || + frame_bytes / pkt->frame_count > MAX_FRAME_SIZE) + goto fail; + frame_bytes /= pkt->frame_count; + } + + pkt->frame_offset[0] = ptr - buf; + pkt->frame_size[0] = frame_bytes; + for (i = 1; i < pkt->frame_count; i++) { + pkt->frame_offset[i] = pkt->frame_offset[i-1] + pkt->frame_size[i-1]; + pkt->frame_size[i] = frame_bytes; + } + } + } + + pkt->packet_size = buf_size; + pkt->data_size = pkt->packet_size - padding; + + /* total packet duration cannot be larger than 120ms */ + pkt->frame_duration = opus_frame_duration[pkt->config]; + if (pkt->frame_duration * pkt->frame_count > MAX_PACKET_DUR) + goto fail; + + /* set mode and bandwidth */ + if (pkt->config < 12) { + pkt->mode = OPUS_MODE_SILK; + pkt->bandwidth = pkt->config >> 2; + } else if (pkt->config < 16) { + pkt->mode = OPUS_MODE_HYBRID; + pkt->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND + (pkt->config >= 14); + } else { + pkt->mode = OPUS_MODE_CELT; + pkt->bandwidth = (pkt->config - 16) >> 2; + /* skip medium band */ + if (pkt->bandwidth) + pkt->bandwidth++; + } + + return 0; + +fail: + memset(pkt, 0, sizeof(*pkt)); + return AVERROR_INVALIDDATA; +} + +static int channel_reorder_vorbis(int nb_channels, int channel_idx) +{ + return ff_vorbis_channel_layout_offsets[nb_channels - 1][channel_idx]; +} + +static int channel_reorder_unknown(int nb_channels, int channel_idx) +{ + return channel_idx; +} + +av_cold int ff_opus_parse_extradata(AVCodecContext *avctx, + OpusContext *s) +{ + static const uint8_t default_channel_map[2] = { 0, 1 }; + + int (*channel_reorder)(int, int) = channel_reorder_unknown; + + const uint8_t *extradata, *channel_map; + int extradata_size; + int version, channels, map_type, streams, stereo_streams, i, j; + uint64_t layout; + + if (!avctx->extradata) { + if (avctx->channels > 2) { + av_log(avctx, AV_LOG_ERROR, + "Multichannel configuration without extradata.\n"); + return AVERROR(EINVAL); + } + extradata = opus_default_extradata; + extradata_size = sizeof(opus_default_extradata); + } else { + extradata = avctx->extradata; + extradata_size = avctx->extradata_size; + } + + if (extradata_size < 19) { + av_log(avctx, AV_LOG_ERROR, "Invalid extradata size: %d\n", + extradata_size); + return AVERROR_INVALIDDATA; + } + + version = extradata[8]; + if (version > 15) { + avpriv_request_sample(avctx, "Extradata version %d", version); + return AVERROR_PATCHWELCOME; + } + + avctx->delay = AV_RL16(extradata + 10); + if (avctx->internal) + avctx->internal->skip_samples = avctx->delay; + + channels = avctx->extradata ? extradata[9] : (avctx->channels == 1) ? 1 : 2; + if (!channels) { + av_log(avctx, AV_LOG_ERROR, "Zero channel count specified in the extradata\n"); + return AVERROR_INVALIDDATA; + } + + s->gain_i = AV_RL16(extradata + 16); + if (s->gain_i) + s->gain = ff_exp10(s->gain_i / (20.0 * 256)); + + map_type = extradata[18]; + if (!map_type) { + if (channels > 2) { + av_log(avctx, AV_LOG_ERROR, + "Channel mapping 0 is only specified for up to 2 channels\n"); + return AVERROR_INVALIDDATA; + } + layout = (channels == 1) ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; + streams = 1; + stereo_streams = channels - 1; + channel_map = default_channel_map; + } else if (map_type == 1 || map_type == 2 || map_type == 255) { + if (extradata_size < 21 + channels) { + av_log(avctx, AV_LOG_ERROR, "Invalid extradata size: %d\n", + extradata_size); + return AVERROR_INVALIDDATA; + } + + streams = extradata[19]; + stereo_streams = extradata[20]; + if (!streams || stereo_streams > streams || + streams + stereo_streams > 255) { + av_log(avctx, AV_LOG_ERROR, + "Invalid stream/stereo stream count: %d/%d\n", streams, stereo_streams); + return AVERROR_INVALIDDATA; + } + + if (map_type == 1) { + if (channels > 8) { + av_log(avctx, AV_LOG_ERROR, + "Channel mapping 1 is only specified for up to 8 channels\n"); + return AVERROR_INVALIDDATA; + } + layout = ff_vorbis_channel_layouts[channels - 1]; + channel_reorder = channel_reorder_vorbis; + } else if (map_type == 2) { + int ambisonic_order = ff_sqrt(channels) - 1; + if (channels != ((ambisonic_order + 1) * (ambisonic_order + 1)) && + channels != ((ambisonic_order + 1) * (ambisonic_order + 1) + 2)) { + av_log(avctx, AV_LOG_ERROR, + "Channel mapping 2 is only specified for channel counts" + " which can be written as (n + 1)^2 or (n + 1)^2 + 2" + " for nonnegative integer n\n"); + return AVERROR_INVALIDDATA; + } + if (channels > 227) { + av_log(avctx, AV_LOG_ERROR, "Too many channels\n"); + return AVERROR_INVALIDDATA; + } + layout = 0; + } else + layout = 0; + + channel_map = extradata + 21; + } else { + avpriv_request_sample(avctx, "Mapping type %d", map_type); + return AVERROR_PATCHWELCOME; + } + + s->channel_maps = av_mallocz_array(channels, sizeof(*s->channel_maps)); + if (!s->channel_maps) + return AVERROR(ENOMEM); + + for (i = 0; i < channels; i++) { + ChannelMap *map = &s->channel_maps[i]; + uint8_t idx = channel_map[channel_reorder(channels, i)]; + + if (idx == 255) { + map->silence = 1; + continue; + } else if (idx >= streams + stereo_streams) { + av_log(avctx, AV_LOG_ERROR, + "Invalid channel map for output channel %d: %d\n", i, idx); + av_freep(&s->channel_maps); + return AVERROR_INVALIDDATA; + } + + /* check that we did not see this index yet */ + map->copy = 0; + for (j = 0; j < i; j++) + if (channel_map[channel_reorder(channels, j)] == idx) { + map->copy = 1; + map->copy_idx = j; + break; + } + + if (idx < 2 * stereo_streams) { + map->stream_idx = idx / 2; + map->channel_idx = idx & 1; + } else { + map->stream_idx = idx - stereo_streams; + map->channel_idx = 0; + } + } + + avctx->channels = channels; + avctx->channel_layout = layout; + s->nb_streams = streams; + s->nb_stereo_streams = stereo_streams; + + return 0; +} + +void ff_celt_quant_bands(CeltFrame *f, OpusRangeCoder *rc) +{ + float lowband_scratch[8 * 22]; + float norm1[2 * 8 * 100]; + float *norm2 = norm1 + 8 * 100; + + int totalbits = (f->framebits << 3) - f->anticollapse_needed; + + int update_lowband = 1; + int lowband_offset = 0; + + int i, j; + + for (i = f->start_band; i < f->end_band; i++) { + uint32_t cm[2] = { (1 << f->blocks) - 1, (1 << f->blocks) - 1 }; + int band_offset = ff_celt_freq_bands[i] << f->size; + int band_size = ff_celt_freq_range[i] << f->size; + float *X = f->block[0].coeffs + band_offset; + float *Y = (f->channels == 2) ? f->block[1].coeffs + band_offset : NULL; + float *norm_loc1, *norm_loc2; + + int consumed = opus_rc_tell_frac(rc); + int effective_lowband = -1; + int b = 0; + + /* Compute how many bits we want to allocate to this band */ + if (i != f->start_band) + f->remaining -= consumed; + f->remaining2 = totalbits - consumed - 1; + if (i <= f->coded_bands - 1) { + int curr_balance = f->remaining / FFMIN(3, f->coded_bands-i); + b = av_clip_uintp2(FFMIN(f->remaining2 + 1, f->pulses[i] + curr_balance), 14); + } + + if ((ff_celt_freq_bands[i] - ff_celt_freq_range[i] >= ff_celt_freq_bands[f->start_band] || + i == f->start_band + 1) && (update_lowband || lowband_offset == 0)) + lowband_offset = i; + + if (i == f->start_band + 1) { + /* Special Hybrid Folding (RFC 8251 section 9). Copy the first band into + the second to ensure the second band never has to use the LCG. */ + int count = (ff_celt_freq_range[i] - ff_celt_freq_range[i-1]) << f->size; + + memcpy(&norm1[band_offset], &norm1[band_offset - count], count * sizeof(float)); + + if (f->channels == 2) + memcpy(&norm2[band_offset], &norm2[band_offset - count], count * sizeof(float)); + } + + /* Get a conservative estimate of the collapse_mask's for the bands we're + going to be folding from. */ + if (lowband_offset != 0 && (f->spread != CELT_SPREAD_AGGRESSIVE || + f->blocks > 1 || f->tf_change[i] < 0)) { + int foldstart, foldend; + + /* This ensures we never repeat spectral content within one band */ + effective_lowband = FFMAX(ff_celt_freq_bands[f->start_band], + ff_celt_freq_bands[lowband_offset] - ff_celt_freq_range[i]); + foldstart = lowband_offset; + while (ff_celt_freq_bands[--foldstart] > effective_lowband); + foldend = lowband_offset - 1; + while (++foldend < i && ff_celt_freq_bands[foldend] < effective_lowband + ff_celt_freq_range[i]); + + cm[0] = cm[1] = 0; + for (j = foldstart; j < foldend; j++) { + cm[0] |= f->block[0].collapse_masks[j]; + cm[1] |= f->block[f->channels - 1].collapse_masks[j]; + } + } + + if (f->dual_stereo && i == f->intensity_stereo) { + /* Switch off dual stereo to do intensity */ + f->dual_stereo = 0; + for (j = ff_celt_freq_bands[f->start_band] << f->size; j < band_offset; j++) + norm1[j] = (norm1[j] + norm2[j]) / 2; + } + + norm_loc1 = effective_lowband != -1 ? norm1 + (effective_lowband << f->size) : NULL; + norm_loc2 = effective_lowband != -1 ? norm2 + (effective_lowband << f->size) : NULL; + + if (f->dual_stereo) { + cm[0] = f->pvq->quant_band(f->pvq, f, rc, i, X, NULL, band_size, b >> 1, + f->blocks, norm_loc1, f->size, + norm1 + band_offset, 0, 1.0f, + lowband_scratch, cm[0]); + + cm[1] = f->pvq->quant_band(f->pvq, f, rc, i, Y, NULL, band_size, b >> 1, + f->blocks, norm_loc2, f->size, + norm2 + band_offset, 0, 1.0f, + lowband_scratch, cm[1]); + } else { + cm[0] = f->pvq->quant_band(f->pvq, f, rc, i, X, Y, band_size, b >> 0, + f->blocks, norm_loc1, f->size, + norm1 + band_offset, 0, 1.0f, + lowband_scratch, cm[0] | cm[1]); + cm[1] = cm[0]; + } + + f->block[0].collapse_masks[i] = (uint8_t)cm[0]; + f->block[f->channels - 1].collapse_masks[i] = (uint8_t)cm[1]; + f->remaining += f->pulses[i] + consumed; + + /* Update the folding position only as long as we have 1 bit/sample depth */ + update_lowband = (b > band_size << 3); + } +} + +#define NORMC(bits) ((bits) << (f->channels - 1) << f->size >> 2) + +void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode) +{ + int i, j, low, high, total, done, bandbits, remaining, tbits_8ths; + int skip_startband = f->start_band; + int skip_bit = 0; + int intensitystereo_bit = 0; + int dualstereo_bit = 0; + int dynalloc = 6; + int extrabits = 0; + + int boost[CELT_MAX_BANDS] = { 0 }; + int trim_offset[CELT_MAX_BANDS]; + int threshold[CELT_MAX_BANDS]; + int bits1[CELT_MAX_BANDS]; + int bits2[CELT_MAX_BANDS]; + + /* Spread */ + if (opus_rc_tell(rc) + 4 <= f->framebits) { + if (encode) + ff_opus_rc_enc_cdf(rc, f->spread, ff_celt_model_spread); + else + f->spread = ff_opus_rc_dec_cdf(rc, ff_celt_model_spread); + } else { + f->spread = CELT_SPREAD_NORMAL; + } + + /* Initialize static allocation caps */ + for (i = 0; i < CELT_MAX_BANDS; i++) + f->caps[i] = NORMC((ff_celt_static_caps[f->size][f->channels - 1][i] + 64) * ff_celt_freq_range[i]); + + /* Band boosts */ + tbits_8ths = f->framebits << 3; + for (i = f->start_band; i < f->end_band; i++) { + int quanta = ff_celt_freq_range[i] << (f->channels - 1) << f->size; + int b_dynalloc = dynalloc; + int boost_amount = f->alloc_boost[i]; + quanta = FFMIN(quanta << 3, FFMAX(6 << 3, quanta)); + + while (opus_rc_tell_frac(rc) + (b_dynalloc << 3) < tbits_8ths && boost[i] < f->caps[i]) { + int is_boost; + if (encode) { + is_boost = boost_amount--; + ff_opus_rc_enc_log(rc, is_boost, b_dynalloc); + } else { + is_boost = ff_opus_rc_dec_log(rc, b_dynalloc); + } + + if (!is_boost) + break; + + boost[i] += quanta; + tbits_8ths -= quanta; + + b_dynalloc = 1; + } + + if (boost[i]) + dynalloc = FFMAX(dynalloc - 1, 2); + } + + /* Allocation trim */ + if (opus_rc_tell_frac(rc) + (6 << 3) <= tbits_8ths) + if (encode) + ff_opus_rc_enc_cdf(rc, f->alloc_trim, ff_celt_model_alloc_trim); + else + f->alloc_trim = ff_opus_rc_dec_cdf(rc, ff_celt_model_alloc_trim); + + /* Anti-collapse bit reservation */ + tbits_8ths = (f->framebits << 3) - opus_rc_tell_frac(rc) - 1; + f->anticollapse_needed = 0; + if (f->transient && f->size >= 2 && tbits_8ths >= ((f->size + 2) << 3)) + f->anticollapse_needed = 1 << 3; + tbits_8ths -= f->anticollapse_needed; + + /* Band skip bit reservation */ + if (tbits_8ths >= 1 << 3) + skip_bit = 1 << 3; + tbits_8ths -= skip_bit; + + /* Intensity/dual stereo bit reservation */ + if (f->channels == 2) { + intensitystereo_bit = ff_celt_log2_frac[f->end_band - f->start_band]; + if (intensitystereo_bit <= tbits_8ths) { + tbits_8ths -= intensitystereo_bit; + if (tbits_8ths >= 1 << 3) { + dualstereo_bit = 1 << 3; + tbits_8ths -= 1 << 3; + } + } else { + intensitystereo_bit = 0; + } + } + + /* Trim offsets */ + for (i = f->start_band; i < f->end_band; i++) { + int trim = f->alloc_trim - 5 - f->size; + int band = ff_celt_freq_range[i] * (f->end_band - i - 1); + int duration = f->size + 3; + int scale = duration + f->channels - 1; + + /* PVQ minimum allocation threshold, below this value the band is + * skipped */ + threshold[i] = FFMAX(3 * ff_celt_freq_range[i] << duration >> 4, + f->channels << 3); + + trim_offset[i] = trim * (band << scale) >> 6; + + if (ff_celt_freq_range[i] << f->size == 1) + trim_offset[i] -= f->channels << 3; + } + + /* Bisection */ + low = 1; + high = CELT_VECTORS - 1; + while (low <= high) { + int center = (low + high) >> 1; + done = total = 0; + + for (i = f->end_band - 1; i >= f->start_band; i--) { + bandbits = NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[center][i]); + + if (bandbits) + bandbits = FFMAX(bandbits + trim_offset[i], 0); + bandbits += boost[i]; + + if (bandbits >= threshold[i] || done) { + done = 1; + total += FFMIN(bandbits, f->caps[i]); + } else if (bandbits >= f->channels << 3) { + total += f->channels << 3; + } + } + + if (total > tbits_8ths) + high = center - 1; + else + low = center + 1; + } + high = low--; + + /* Bisection */ + for (i = f->start_band; i < f->end_band; i++) { + bits1[i] = NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[low][i]); + bits2[i] = high >= CELT_VECTORS ? f->caps[i] : + NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[high][i]); + + if (bits1[i]) + bits1[i] = FFMAX(bits1[i] + trim_offset[i], 0); + if (bits2[i]) + bits2[i] = FFMAX(bits2[i] + trim_offset[i], 0); + + if (low) + bits1[i] += boost[i]; + bits2[i] += boost[i]; + + if (boost[i]) + skip_startband = i; + bits2[i] = FFMAX(bits2[i] - bits1[i], 0); + } + + /* Bisection */ + low = 0; + high = 1 << CELT_ALLOC_STEPS; + for (i = 0; i < CELT_ALLOC_STEPS; i++) { + int center = (low + high) >> 1; + done = total = 0; + + for (j = f->end_band - 1; j >= f->start_band; j--) { + bandbits = bits1[j] + (center * bits2[j] >> CELT_ALLOC_STEPS); + + if (bandbits >= threshold[j] || done) { + done = 1; + total += FFMIN(bandbits, f->caps[j]); + } else if (bandbits >= f->channels << 3) + total += f->channels << 3; + } + if (total > tbits_8ths) + high = center; + else + low = center; + } + + /* Bisection */ + done = total = 0; + for (i = f->end_band - 1; i >= f->start_band; i--) { + bandbits = bits1[i] + (low * bits2[i] >> CELT_ALLOC_STEPS); + + if (bandbits >= threshold[i] || done) + done = 1; + else + bandbits = (bandbits >= f->channels << 3) ? + f->channels << 3 : 0; + + bandbits = FFMIN(bandbits, f->caps[i]); + f->pulses[i] = bandbits; + total += bandbits; + } + + /* Band skipping */ + for (f->coded_bands = f->end_band; ; f->coded_bands--) { + int allocation; + j = f->coded_bands - 1; + + if (j == skip_startband) { + /* all remaining bands are not skipped */ + tbits_8ths += skip_bit; + break; + } + + /* determine the number of bits available for coding "do not skip" markers */ + remaining = tbits_8ths - total; + bandbits = remaining / (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]); + remaining -= bandbits * (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]); + allocation = f->pulses[j] + bandbits * ff_celt_freq_range[j]; + allocation += FFMAX(remaining - (ff_celt_freq_bands[j] - ff_celt_freq_bands[f->start_band]), 0); + + /* a "do not skip" marker is only coded if the allocation is + * above the chosen threshold */ + if (allocation >= FFMAX(threshold[j], (f->channels + 1) << 3)) { + int do_not_skip; + if (encode) { + do_not_skip = f->coded_bands <= f->skip_band_floor; + ff_opus_rc_enc_log(rc, do_not_skip, 1); + } else { + do_not_skip = ff_opus_rc_dec_log(rc, 1); + } + + if (do_not_skip) + break; + + total += 1 << 3; + allocation -= 1 << 3; + } + + /* the band is skipped, so reclaim its bits */ + total -= f->pulses[j]; + if (intensitystereo_bit) { + total -= intensitystereo_bit; + intensitystereo_bit = ff_celt_log2_frac[j - f->start_band]; + total += intensitystereo_bit; + } + + total += f->pulses[j] = (allocation >= f->channels << 3) ? f->channels << 3 : 0; + } + + /* IS start band */ + if (encode) { + if (intensitystereo_bit) { + f->intensity_stereo = FFMIN(f->intensity_stereo, f->coded_bands); + ff_opus_rc_enc_uint(rc, f->intensity_stereo, f->coded_bands + 1 - f->start_band); + } + } else { + f->intensity_stereo = f->dual_stereo = 0; + if (intensitystereo_bit) + f->intensity_stereo = f->start_band + ff_opus_rc_dec_uint(rc, f->coded_bands + 1 - f->start_band); + } + + /* DS flag */ + if (f->intensity_stereo <= f->start_band) + tbits_8ths += dualstereo_bit; /* no intensity stereo means no dual stereo */ + else if (dualstereo_bit) + if (encode) + ff_opus_rc_enc_log(rc, f->dual_stereo, 1); + else + f->dual_stereo = ff_opus_rc_dec_log(rc, 1); + + /* Supply the remaining bits in this frame to lower bands */ + remaining = tbits_8ths - total; + bandbits = remaining / (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]); + remaining -= bandbits * (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]); + for (i = f->start_band; i < f->coded_bands; i++) { + const int bits = FFMIN(remaining, ff_celt_freq_range[i]); + f->pulses[i] += bits + bandbits * ff_celt_freq_range[i]; + remaining -= bits; + } + + /* Finally determine the allocation */ + for (i = f->start_band; i < f->coded_bands; i++) { + int N = ff_celt_freq_range[i] << f->size; + int prev_extra = extrabits; + f->pulses[i] += extrabits; + + if (N > 1) { + int dof; /* degrees of freedom */ + int temp; /* dof * channels * log(dof) */ + int fine_bits; + int max_bits; + int offset; /* fine energy quantization offset, i.e. + * extra bits assigned over the standard + * totalbits/dof */ + + extrabits = FFMAX(f->pulses[i] - f->caps[i], 0); + f->pulses[i] -= extrabits; + + /* intensity stereo makes use of an extra degree of freedom */ + dof = N * f->channels + (f->channels == 2 && N > 2 && !f->dual_stereo && i < f->intensity_stereo); + temp = dof * (ff_celt_log_freq_range[i] + (f->size << 3)); + offset = (temp >> 1) - dof * CELT_FINE_OFFSET; + if (N == 2) /* dof=2 is the only case that doesn't fit the model */ + offset += dof << 1; + + /* grant an additional bias for the first and second pulses */ + if (f->pulses[i] + offset < 2 * (dof << 3)) + offset += temp >> 2; + else if (f->pulses[i] + offset < 3 * (dof << 3)) + offset += temp >> 3; + + fine_bits = (f->pulses[i] + offset + (dof << 2)) / (dof << 3); + max_bits = FFMIN((f->pulses[i] >> 3) >> (f->channels - 1), CELT_MAX_FINE_BITS); + max_bits = FFMAX(max_bits, 0); + f->fine_bits[i] = av_clip(fine_bits, 0, max_bits); + + /* If fine_bits was rounded down or capped, + * give priority for the final fine energy pass */ + f->fine_priority[i] = (f->fine_bits[i] * (dof << 3) >= f->pulses[i] + offset); + + /* the remaining bits are assigned to PVQ */ + f->pulses[i] -= f->fine_bits[i] << (f->channels - 1) << 3; + } else { + /* all bits go to fine energy except for the sign bit */ + extrabits = FFMAX(f->pulses[i] - (f->channels << 3), 0); + f->pulses[i] -= extrabits; + f->fine_bits[i] = 0; + f->fine_priority[i] = 1; + } + + /* hand back a limited number of extra fine energy bits to this band */ + if (extrabits > 0) { + int fineextra = FFMIN(extrabits >> (f->channels + 2), + CELT_MAX_FINE_BITS - f->fine_bits[i]); + f->fine_bits[i] += fineextra; + + fineextra <<= f->channels + 2; + f->fine_priority[i] = (fineextra >= extrabits - prev_extra); + extrabits -= fineextra; + } + } + f->remaining = extrabits; + + /* skipped bands dedicate all of their bits for fine energy */ + for (; i < f->end_band; i++) { + f->fine_bits[i] = f->pulses[i] >> (f->channels - 1) >> 3; + f->pulses[i] = 0; + f->fine_priority[i] = f->fine_bits[i] < 1; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus.h new file mode 100644 index 0000000000..63ecd0aff7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus.h @@ -0,0 +1,200 @@ +/* + * Opus decoder/demuxer common functions + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPUS_H +#define AVCODEC_OPUS_H + +#include + +#include "libavutil/audio_fifo.h" +#include "libavutil/float_dsp.h" +#include "libavutil/frame.h" + +#include "libswresample/swresample.h" + +#include "avcodec.h" +#include "opus_rc.h" + +#define MAX_FRAME_SIZE 1275 +#define MAX_FRAMES 48 +#define MAX_PACKET_DUR 5760 + +#define CELT_SHORT_BLOCKSIZE 120 +#define CELT_OVERLAP CELT_SHORT_BLOCKSIZE +#define CELT_MAX_LOG_BLOCKS 3 +#define CELT_MAX_FRAME_SIZE (CELT_SHORT_BLOCKSIZE * (1 << CELT_MAX_LOG_BLOCKS)) +#define CELT_MAX_BANDS 21 + +#define SILK_HISTORY 322 +#define SILK_MAX_LPC 16 + +#define ROUND_MULL(a,b,s) (((MUL64(a, b) >> ((s) - 1)) + 1) >> 1) +#define ROUND_MUL16(a,b) ((MUL16(a, b) + 16384) >> 15) + +#define OPUS_TS_HEADER 0x7FE0 // 0x3ff (11 bits) +#define OPUS_TS_MASK 0xFFE0 // top 11 bits + +static const uint8_t opus_default_extradata[30] = { + 'O', 'p', 'u', 's', 'H', 'e', 'a', 'd', + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +enum OpusMode { + OPUS_MODE_SILK, + OPUS_MODE_HYBRID, + OPUS_MODE_CELT, + + OPUS_MODE_NB +}; + +enum OpusBandwidth { + OPUS_BANDWIDTH_NARROWBAND, + OPUS_BANDWIDTH_MEDIUMBAND, + OPUS_BANDWIDTH_WIDEBAND, + OPUS_BANDWIDTH_SUPERWIDEBAND, + OPUS_BANDWIDTH_FULLBAND, + + OPUS_BANDWITH_NB +}; + +typedef struct SilkContext SilkContext; + +typedef struct CeltFrame CeltFrame; + +typedef struct OpusPacket { + int packet_size; /**< packet size */ + int data_size; /**< size of the useful data -- packet size - padding */ + int code; /**< packet code: specifies the frame layout */ + int stereo; /**< whether this packet is mono or stereo */ + int vbr; /**< vbr flag */ + int config; /**< configuration: tells the audio mode, + ** bandwidth, and frame duration */ + int frame_count; /**< frame count */ + int frame_offset[MAX_FRAMES]; /**< frame offsets */ + int frame_size[MAX_FRAMES]; /**< frame sizes */ + int frame_duration; /**< frame duration, in samples @ 48kHz */ + enum OpusMode mode; /**< mode */ + enum OpusBandwidth bandwidth; /**< bandwidth */ +} OpusPacket; + +typedef struct OpusStreamContext { + AVCodecContext *avctx; + int output_channels; + + OpusRangeCoder rc; + OpusRangeCoder redundancy_rc; + SilkContext *silk; + CeltFrame *celt; + AVFloatDSPContext *fdsp; + + float silk_buf[2][960]; + float *silk_output[2]; + DECLARE_ALIGNED(32, float, celt_buf)[2][960]; + float *celt_output[2]; + + DECLARE_ALIGNED(32, float, redundancy_buf)[2][960]; + float *redundancy_output[2]; + + /* data buffers for the final output data */ + float *out[2]; + int out_size; + + float *out_dummy; + int out_dummy_allocated_size; + + SwrContext *swr; + AVAudioFifo *celt_delay; + int silk_samplerate; + /* number of samples we still want to get from the resampler */ + int delayed_samples; + + OpusPacket packet; + + int redundancy_idx; +} OpusStreamContext; + +// a mapping between an opus stream and an output channel +typedef struct ChannelMap { + int stream_idx; + int channel_idx; + + // when a single decoded channel is mapped to multiple output channels, we + // write to the first output directly and copy from it to the others + // this field is set to 1 for those copied output channels + int copy; + // this is the index of the output channel to copy from + int copy_idx; + + // this channel is silent + int silence; +} ChannelMap; + +typedef struct OpusContext { + AVClass *av_class; + OpusStreamContext *streams; + int apply_phase_inv; + + /* current output buffers for each streams */ + float **out; + int *out_size; + /* Buffers for synchronizing the streams when they have different + * resampling delays */ + AVAudioFifo **sync_buffers; + /* number of decoded samples for each stream */ + int *decoded_samples; + + int nb_streams; + int nb_stereo_streams; + + AVFloatDSPContext *fdsp; + int16_t gain_i; + float gain; + + ChannelMap *channel_maps; +} OpusContext; + +int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size, + int self_delimited); + +int ff_opus_parse_extradata(AVCodecContext *avctx, OpusContext *s); + +int ff_silk_init(AVCodecContext *avctx, SilkContext **ps, int output_channels); +void ff_silk_free(SilkContext **ps); +void ff_silk_flush(SilkContext *s); + +/** + * Decode the LP layer of one Opus frame (which may correspond to several SILK + * frames). + */ +int ff_silk_decode_superframe(SilkContext *s, OpusRangeCoder *rc, + float *output[2], + enum OpusBandwidth bandwidth, int coded_channels, + int duration_ms); + +/* Encode or decode CELT bands */ +void ff_celt_quant_bands(CeltFrame *f, OpusRangeCoder *rc); + +/* Encode or decode CELT bitallocation */ +void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode); + +#endif /* AVCODEC_OPUS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_celt.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_celt.c new file mode 100644 index 0000000000..4655172b09 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_celt.c @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * Copyright (c) 2016 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Opus CELT decoder + */ + +#include "opus_celt.h" +#include "opustab.h" +#include "opus_pvq.h" + +/* Use the 2D z-transform to apply prediction in both the time domain (alpha) + * and the frequency domain (beta) */ +static void celt_decode_coarse_energy(CeltFrame *f, OpusRangeCoder *rc) +{ + int i, j; + float prev[2] = { 0 }; + float alpha = ff_celt_alpha_coef[f->size]; + float beta = ff_celt_beta_coef[f->size]; + const uint8_t *model = ff_celt_coarse_energy_dist[f->size][0]; + + /* intra frame */ + if (opus_rc_tell(rc) + 3 <= f->framebits && ff_opus_rc_dec_log(rc, 3)) { + alpha = 0.0f; + beta = 1.0f - (4915.0f/32768.0f); + model = ff_celt_coarse_energy_dist[f->size][1]; + } + + for (i = 0; i < CELT_MAX_BANDS; i++) { + for (j = 0; j < f->channels; j++) { + CeltBlock *block = &f->block[j]; + float value; + int available; + + if (i < f->start_band || i >= f->end_band) { + block->energy[i] = 0.0; + continue; + } + + available = f->framebits - opus_rc_tell(rc); + if (available >= 15) { + /* decode using a Laplace distribution */ + int k = FFMIN(i, 20) << 1; + value = ff_opus_rc_dec_laplace(rc, model[k] << 7, model[k+1] << 6); + } else if (available >= 2) { + int x = ff_opus_rc_dec_cdf(rc, ff_celt_model_energy_small); + value = (x>>1) ^ -(x&1); + } else if (available >= 1) { + value = -(float)ff_opus_rc_dec_log(rc, 1); + } else value = -1; + + block->energy[i] = FFMAX(-9.0f, block->energy[i]) * alpha + prev[j] + value; + prev[j] += beta * value; + } + } +} + +static void celt_decode_fine_energy(CeltFrame *f, OpusRangeCoder *rc) +{ + int i; + for (i = f->start_band; i < f->end_band; i++) { + int j; + if (!f->fine_bits[i]) + continue; + + for (j = 0; j < f->channels; j++) { + CeltBlock *block = &f->block[j]; + int q2; + float offset; + q2 = ff_opus_rc_get_raw(rc, f->fine_bits[i]); + offset = (q2 + 0.5f) * (1 << (14 - f->fine_bits[i])) / 16384.0f - 0.5f; + block->energy[i] += offset; + } + } +} + +static void celt_decode_final_energy(CeltFrame *f, OpusRangeCoder *rc) +{ + int priority, i, j; + int bits_left = f->framebits - opus_rc_tell(rc); + + for (priority = 0; priority < 2; priority++) { + for (i = f->start_band; i < f->end_band && bits_left >= f->channels; i++) { + if (f->fine_priority[i] != priority || f->fine_bits[i] >= CELT_MAX_FINE_BITS) + continue; + + for (j = 0; j < f->channels; j++) { + int q2; + float offset; + q2 = ff_opus_rc_get_raw(rc, 1); + offset = (q2 - 0.5f) * (1 << (14 - f->fine_bits[i] - 1)) / 16384.0f; + f->block[j].energy[i] += offset; + bits_left--; + } + } + } +} + +static void celt_decode_tf_changes(CeltFrame *f, OpusRangeCoder *rc) +{ + int i, diff = 0, tf_select = 0, tf_changed = 0, tf_select_bit; + int consumed, bits = f->transient ? 2 : 4; + + consumed = opus_rc_tell(rc); + tf_select_bit = (f->size != 0 && consumed+bits+1 <= f->framebits); + + for (i = f->start_band; i < f->end_band; i++) { + if (consumed+bits+tf_select_bit <= f->framebits) { + diff ^= ff_opus_rc_dec_log(rc, bits); + consumed = opus_rc_tell(rc); + tf_changed |= diff; + } + f->tf_change[i] = diff; + bits = f->transient ? 4 : 5; + } + + if (tf_select_bit && ff_celt_tf_select[f->size][f->transient][0][tf_changed] != + ff_celt_tf_select[f->size][f->transient][1][tf_changed]) + tf_select = ff_opus_rc_dec_log(rc, 1); + + for (i = f->start_band; i < f->end_band; i++) { + f->tf_change[i] = ff_celt_tf_select[f->size][f->transient][tf_select][f->tf_change[i]]; + } +} + +static void celt_denormalize(CeltFrame *f, CeltBlock *block, float *data) +{ + int i, j; + + for (i = f->start_band; i < f->end_band; i++) { + float *dst = data + (ff_celt_freq_bands[i] << f->size); + float log_norm = block->energy[i] + ff_celt_mean_energy[i]; + float norm = exp2f(FFMIN(log_norm, 32.0f)); + + for (j = 0; j < ff_celt_freq_range[i] << f->size; j++) + dst[j] *= norm; + } +} + +static void celt_postfilter_apply_transition(CeltBlock *block, float *data) +{ + const int T0 = block->pf_period_old; + const int T1 = block->pf_period; + + float g00, g01, g02; + float g10, g11, g12; + + float x0, x1, x2, x3, x4; + + int i; + + if (block->pf_gains[0] == 0.0 && + block->pf_gains_old[0] == 0.0) + return; + + g00 = block->pf_gains_old[0]; + g01 = block->pf_gains_old[1]; + g02 = block->pf_gains_old[2]; + g10 = block->pf_gains[0]; + g11 = block->pf_gains[1]; + g12 = block->pf_gains[2]; + + x1 = data[-T1 + 1]; + x2 = data[-T1]; + x3 = data[-T1 - 1]; + x4 = data[-T1 - 2]; + + for (i = 0; i < CELT_OVERLAP; i++) { + float w = ff_celt_window2[i]; + x0 = data[i - T1 + 2]; + + data[i] += (1.0 - w) * g00 * data[i - T0] + + (1.0 - w) * g01 * (data[i - T0 - 1] + data[i - T0 + 1]) + + (1.0 - w) * g02 * (data[i - T0 - 2] + data[i - T0 + 2]) + + w * g10 * x2 + + w * g11 * (x1 + x3) + + w * g12 * (x0 + x4); + x4 = x3; + x3 = x2; + x2 = x1; + x1 = x0; + } +} + +static void celt_postfilter(CeltFrame *f, CeltBlock *block) +{ + int len = f->blocksize * f->blocks; + const int filter_len = len - 2 * CELT_OVERLAP; + + celt_postfilter_apply_transition(block, block->buf + 1024); + + block->pf_period_old = block->pf_period; + memcpy(block->pf_gains_old, block->pf_gains, sizeof(block->pf_gains)); + + block->pf_period = block->pf_period_new; + memcpy(block->pf_gains, block->pf_gains_new, sizeof(block->pf_gains)); + + if (len > CELT_OVERLAP) { + celt_postfilter_apply_transition(block, block->buf + 1024 + CELT_OVERLAP); + + if (block->pf_gains[0] > FLT_EPSILON && filter_len > 0) + f->opusdsp.postfilter(block->buf + 1024 + 2 * CELT_OVERLAP, + block->pf_period, block->pf_gains, + filter_len); + + block->pf_period_old = block->pf_period; + memcpy(block->pf_gains_old, block->pf_gains, sizeof(block->pf_gains)); + } + + memmove(block->buf, block->buf + len, (1024 + CELT_OVERLAP / 2) * sizeof(float)); +} + +static int parse_postfilter(CeltFrame *f, OpusRangeCoder *rc, int consumed) +{ + int i; + + memset(f->block[0].pf_gains_new, 0, sizeof(f->block[0].pf_gains_new)); + memset(f->block[1].pf_gains_new, 0, sizeof(f->block[1].pf_gains_new)); + + if (f->start_band == 0 && consumed + 16 <= f->framebits) { + int has_postfilter = ff_opus_rc_dec_log(rc, 1); + if (has_postfilter) { + float gain; + int tapset, octave, period; + + octave = ff_opus_rc_dec_uint(rc, 6); + period = (16 << octave) + ff_opus_rc_get_raw(rc, 4 + octave) - 1; + gain = 0.09375f * (ff_opus_rc_get_raw(rc, 3) + 1); + tapset = (opus_rc_tell(rc) + 2 <= f->framebits) ? + ff_opus_rc_dec_cdf(rc, ff_celt_model_tapset) : 0; + + for (i = 0; i < 2; i++) { + CeltBlock *block = &f->block[i]; + + block->pf_period_new = FFMAX(period, CELT_POSTFILTER_MINPERIOD); + block->pf_gains_new[0] = gain * ff_celt_postfilter_taps[tapset][0]; + block->pf_gains_new[1] = gain * ff_celt_postfilter_taps[tapset][1]; + block->pf_gains_new[2] = gain * ff_celt_postfilter_taps[tapset][2]; + } + } + + consumed = opus_rc_tell(rc); + } + + return consumed; +} + +static void process_anticollapse(CeltFrame *f, CeltBlock *block, float *X) +{ + int i, j, k; + + for (i = f->start_band; i < f->end_band; i++) { + int renormalize = 0; + float *xptr; + float prev[2]; + float Ediff, r; + float thresh, sqrt_1; + int depth; + + /* depth in 1/8 bits */ + depth = (1 + f->pulses[i]) / (ff_celt_freq_range[i] << f->size); + thresh = exp2f(-1.0 - 0.125f * depth); + sqrt_1 = 1.0f / sqrtf(ff_celt_freq_range[i] << f->size); + + xptr = X + (ff_celt_freq_bands[i] << f->size); + + prev[0] = block->prev_energy[0][i]; + prev[1] = block->prev_energy[1][i]; + if (f->channels == 1) { + CeltBlock *block1 = &f->block[1]; + + prev[0] = FFMAX(prev[0], block1->prev_energy[0][i]); + prev[1] = FFMAX(prev[1], block1->prev_energy[1][i]); + } + Ediff = block->energy[i] - FFMIN(prev[0], prev[1]); + Ediff = FFMAX(0, Ediff); + + /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because + short blocks don't have the same energy as long */ + r = exp2f(1 - Ediff); + if (f->size == 3) + r *= M_SQRT2; + r = FFMIN(thresh, r) * sqrt_1; + for (k = 0; k < 1 << f->size; k++) { + /* Detect collapse */ + if (!(block->collapse_masks[i] & 1 << k)) { + /* Fill with noise */ + for (j = 0; j < ff_celt_freq_range[i]; j++) + xptr[(j << f->size) + k] = (celt_rng(f) & 0x8000) ? r : -r; + renormalize = 1; + } + } + + /* We just added some energy, so we need to renormalize */ + if (renormalize) + celt_renormalize_vector(xptr, ff_celt_freq_range[i] << f->size, 1.0f); + } +} + +int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, + float **output, int channels, int frame_size, + int start_band, int end_band) +{ + int i, j, downmix = 0; + int consumed; // bits of entropy consumed thus far for this frame + MDCT15Context *imdct; + + if (channels != 1 && channels != 2) { + av_log(f->avctx, AV_LOG_ERROR, "Invalid number of coded channels: %d\n", + channels); + return AVERROR_INVALIDDATA; + } + if (start_band < 0 || start_band > end_band || end_band > CELT_MAX_BANDS) { + av_log(f->avctx, AV_LOG_ERROR, "Invalid start/end band: %d %d\n", + start_band, end_band); + return AVERROR_INVALIDDATA; + } + + f->silence = 0; + f->transient = 0; + f->anticollapse = 0; + f->flushed = 0; + f->channels = channels; + f->start_band = start_band; + f->end_band = end_band; + f->framebits = rc->rb.bytes * 8; + + f->size = av_log2(frame_size / CELT_SHORT_BLOCKSIZE); + if (f->size > CELT_MAX_LOG_BLOCKS || + frame_size != CELT_SHORT_BLOCKSIZE * (1 << f->size)) { + av_log(f->avctx, AV_LOG_ERROR, "Invalid CELT frame size: %d\n", + frame_size); + return AVERROR_INVALIDDATA; + } + + if (!f->output_channels) + f->output_channels = channels; + + for (i = 0; i < f->channels; i++) { + memset(f->block[i].coeffs, 0, sizeof(f->block[i].coeffs)); + memset(f->block[i].collapse_masks, 0, sizeof(f->block[i].collapse_masks)); + } + + consumed = opus_rc_tell(rc); + + /* obtain silence flag */ + if (consumed >= f->framebits) + f->silence = 1; + else if (consumed == 1) + f->silence = ff_opus_rc_dec_log(rc, 15); + + + if (f->silence) { + consumed = f->framebits; + rc->total_bits += f->framebits - opus_rc_tell(rc); + } + + /* obtain post-filter options */ + consumed = parse_postfilter(f, rc, consumed); + + /* obtain transient flag */ + if (f->size != 0 && consumed+3 <= f->framebits) + f->transient = ff_opus_rc_dec_log(rc, 3); + + f->blocks = f->transient ? 1 << f->size : 1; + f->blocksize = frame_size / f->blocks; + + imdct = f->imdct[f->transient ? 0 : f->size]; + + if (channels == 1) { + for (i = 0; i < CELT_MAX_BANDS; i++) + f->block[0].energy[i] = FFMAX(f->block[0].energy[i], f->block[1].energy[i]); + } + + celt_decode_coarse_energy(f, rc); + celt_decode_tf_changes (f, rc); + ff_celt_bitalloc (f, rc, 0); + celt_decode_fine_energy (f, rc); + ff_celt_quant_bands (f, rc); + + if (f->anticollapse_needed) + f->anticollapse = ff_opus_rc_get_raw(rc, 1); + + celt_decode_final_energy(f, rc); + + /* apply anti-collapse processing and denormalization to + * each coded channel */ + for (i = 0; i < f->channels; i++) { + CeltBlock *block = &f->block[i]; + + if (f->anticollapse) + process_anticollapse(f, block, f->block[i].coeffs); + + celt_denormalize(f, block, f->block[i].coeffs); + } + + /* stereo -> mono downmix */ + if (f->output_channels < f->channels) { + f->dsp->vector_fmac_scalar(f->block[0].coeffs, f->block[1].coeffs, 1.0, FFALIGN(frame_size, 16)); + downmix = 1; + } else if (f->output_channels > f->channels) + memcpy(f->block[1].coeffs, f->block[0].coeffs, frame_size * sizeof(float)); + + if (f->silence) { + for (i = 0; i < 2; i++) { + CeltBlock *block = &f->block[i]; + + for (j = 0; j < FF_ARRAY_ELEMS(block->energy); j++) + block->energy[j] = CELT_ENERGY_SILENCE; + } + memset(f->block[0].coeffs, 0, sizeof(f->block[0].coeffs)); + memset(f->block[1].coeffs, 0, sizeof(f->block[1].coeffs)); + } + + /* transform and output for each output channel */ + for (i = 0; i < f->output_channels; i++) { + CeltBlock *block = &f->block[i]; + + /* iMDCT and overlap-add */ + for (j = 0; j < f->blocks; j++) { + float *dst = block->buf + 1024 + j * f->blocksize; + + imdct->imdct_half(imdct, dst + CELT_OVERLAP / 2, f->block[i].coeffs + j, + f->blocks); + f->dsp->vector_fmul_window(dst, dst, dst + CELT_OVERLAP / 2, + ff_celt_window, CELT_OVERLAP / 2); + } + + if (downmix) + f->dsp->vector_fmul_scalar(&block->buf[1024], &block->buf[1024], 0.5f, frame_size); + + /* postfilter */ + celt_postfilter(f, block); + + /* deemphasis */ + block->emph_coeff = f->opusdsp.deemphasis(output[i], + &block->buf[1024 - frame_size], + block->emph_coeff, frame_size); + } + + if (channels == 1) + memcpy(f->block[1].energy, f->block[0].energy, sizeof(f->block[0].energy)); + + for (i = 0; i < 2; i++ ) { + CeltBlock *block = &f->block[i]; + + if (!f->transient) { + memcpy(block->prev_energy[1], block->prev_energy[0], sizeof(block->prev_energy[0])); + memcpy(block->prev_energy[0], block->energy, sizeof(block->prev_energy[0])); + } else { + for (j = 0; j < CELT_MAX_BANDS; j++) + block->prev_energy[0][j] = FFMIN(block->prev_energy[0][j], block->energy[j]); + } + + for (j = 0; j < f->start_band; j++) { + block->prev_energy[0][j] = CELT_ENERGY_SILENCE; + block->energy[j] = 0.0; + } + for (j = f->end_band; j < CELT_MAX_BANDS; j++) { + block->prev_energy[0][j] = CELT_ENERGY_SILENCE; + block->energy[j] = 0.0; + } + } + + f->seed = rc->range; + + return 0; +} + +void ff_celt_flush(CeltFrame *f) +{ + int i, j; + + if (f->flushed) + return; + + for (i = 0; i < 2; i++) { + CeltBlock *block = &f->block[i]; + + for (j = 0; j < CELT_MAX_BANDS; j++) + block->prev_energy[0][j] = block->prev_energy[1][j] = CELT_ENERGY_SILENCE; + + memset(block->energy, 0, sizeof(block->energy)); + memset(block->buf, 0, sizeof(block->buf)); + + memset(block->pf_gains, 0, sizeof(block->pf_gains)); + memset(block->pf_gains_old, 0, sizeof(block->pf_gains_old)); + memset(block->pf_gains_new, 0, sizeof(block->pf_gains_new)); + + block->emph_coeff = 0.0; + } + f->seed = 0; + + f->flushed = 1; +} + +void ff_celt_free(CeltFrame **f) +{ + CeltFrame *frm = *f; + int i; + + if (!frm) + return; + + for (i = 0; i < FF_ARRAY_ELEMS(frm->imdct); i++) + ff_mdct15_uninit(&frm->imdct[i]); + + ff_celt_pvq_uninit(&frm->pvq); + + av_freep(&frm->dsp); + av_freep(f); +} + +int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels, + int apply_phase_inv) +{ + CeltFrame *frm; + int i, ret; + + if (output_channels != 1 && output_channels != 2) { + av_log(avctx, AV_LOG_ERROR, "Invalid number of output channels: %d\n", + output_channels); + return AVERROR(EINVAL); + } + + frm = av_mallocz(sizeof(*frm)); + if (!frm) + return AVERROR(ENOMEM); + + frm->avctx = avctx; + frm->output_channels = output_channels; + frm->apply_phase_inv = apply_phase_inv; + + for (i = 0; i < FF_ARRAY_ELEMS(frm->imdct); i++) + if ((ret = ff_mdct15_init(&frm->imdct[i], 1, i + 3, -1.0f/32768)) < 0) + goto fail; + + if ((ret = ff_celt_pvq_init(&frm->pvq, 0)) < 0) + goto fail; + + frm->dsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); + if (!frm->dsp) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ff_opus_dsp_init(&frm->opusdsp); + ff_celt_flush(frm); + + *f = frm; + + return 0; +fail: + ff_celt_free(&frm); + return ret; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_celt.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_celt.h new file mode 100644 index 0000000000..7c1c5316b9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_celt.h @@ -0,0 +1,171 @@ +/* + * Opus decoder/demuxer common functions + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * Copyright (c) 2016 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPUS_CELT_H +#define AVCODEC_OPUS_CELT_H + +#include + +#include "opus.h" +#include "opus_pvq.h" +#include "opusdsp.h" + +#include "mdct15.h" +#include "libavutil/float_dsp.h" +#include "libavutil/libm.h" + +#define CELT_VECTORS 11 +#define CELT_ALLOC_STEPS 6 +#define CELT_FINE_OFFSET 21 +#define CELT_MAX_FINE_BITS 8 +#define CELT_NORM_SCALE 16384 +#define CELT_QTHETA_OFFSET 4 +#define CELT_QTHETA_OFFSET_TWOPHASE 16 +#define CELT_POSTFILTER_MINPERIOD 15 +#define CELT_ENERGY_SILENCE (-28.0f) + +typedef struct CeltPVQ CeltPVQ; + +enum CeltSpread { + CELT_SPREAD_NONE, + CELT_SPREAD_LIGHT, + CELT_SPREAD_NORMAL, + CELT_SPREAD_AGGRESSIVE +}; + +enum CeltBlockSize { + CELT_BLOCK_120, + CELT_BLOCK_240, + CELT_BLOCK_480, + CELT_BLOCK_960, + + CELT_BLOCK_NB +}; + +typedef struct CeltBlock { + float energy[CELT_MAX_BANDS]; + float lin_energy[CELT_MAX_BANDS]; + float error_energy[CELT_MAX_BANDS]; + float prev_energy[2][CELT_MAX_BANDS]; + + uint8_t collapse_masks[CELT_MAX_BANDS]; + + /* buffer for mdct output + postfilter */ + DECLARE_ALIGNED(32, float, buf)[2048]; + DECLARE_ALIGNED(32, float, coeffs)[CELT_MAX_FRAME_SIZE]; + + /* Used by the encoder */ + DECLARE_ALIGNED(32, float, overlap)[FFALIGN(CELT_OVERLAP, 16)]; + DECLARE_ALIGNED(32, float, samples)[FFALIGN(CELT_MAX_FRAME_SIZE, 16)]; + + /* postfilter parameters */ + int pf_period_new; + float pf_gains_new[3]; + int pf_period; + float pf_gains[3]; + int pf_period_old; + float pf_gains_old[3]; + + float emph_coeff; +} CeltBlock; + +struct CeltFrame { + // constant values that do not change during context lifetime + AVCodecContext *avctx; + MDCT15Context *imdct[4]; + AVFloatDSPContext *dsp; + CeltBlock block[2]; + CeltPVQ *pvq; + OpusDSP opusdsp; + int channels; + int output_channels; + int apply_phase_inv; + + enum CeltBlockSize size; + int start_band; + int end_band; + int coded_bands; + int transient; + int pfilter; + int skip_band_floor; + int tf_select; + int alloc_trim; + int alloc_boost[CELT_MAX_BANDS]; + int blocks; /* number of iMDCT blocks in the frame, depends on transient */ + int blocksize; /* size of each block */ + int silence; /* Frame is filled with silence */ + int anticollapse_needed; /* Whether to expect an anticollapse bit */ + int anticollapse; /* Encoded anticollapse bit */ + int intensity_stereo; + int dual_stereo; + int flushed; + uint32_t seed; + enum CeltSpread spread; + + /* Encoder PF coeffs */ + int pf_octave; + int pf_period; + int pf_tapset; + float pf_gain; + + /* Bit allocation */ + int framebits; + int remaining; + int remaining2; + int caps [CELT_MAX_BANDS]; + int fine_bits [CELT_MAX_BANDS]; + int fine_priority[CELT_MAX_BANDS]; + int pulses [CELT_MAX_BANDS]; + int tf_change [CELT_MAX_BANDS]; +}; + +/* LCG for noise generation */ +static av_always_inline uint32_t celt_rng(CeltFrame *f) +{ + f->seed = 1664525 * f->seed + 1013904223; + return f->seed; +} + +static av_always_inline void celt_renormalize_vector(float *X, int N, float gain) +{ + int i; + float g = 1e-15f; + for (i = 0; i < N; i++) + g += X[i] * X[i]; + g = gain / sqrtf(g); + + for (i = 0; i < N; i++) + X[i] *= g; +} + +int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels, + int apply_phase_inv); + +void ff_celt_free(CeltFrame **f); + +void ff_celt_flush(CeltFrame *f); + +int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, float **output, + int coded_channels, int frame_size, int startband, int endband); + +#endif /* AVCODEC_OPUS_CELT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_pvq.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_pvq.c new file mode 100644 index 0000000000..9c21d67298 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_pvq.c @@ -0,0 +1,917 @@ +/* + * Copyright (c) 2007-2008 CSIRO + * Copyright (c) 2007-2009 Xiph.Org Foundation + * Copyright (c) 2008-2009 Gregory Maxwell + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * Copyright (c) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "opustab.h" +#include "opus_pvq.h" + +#define CELT_PVQ_U(n, k) (ff_celt_pvq_u_row[FFMIN(n, k)][FFMAX(n, k)]) +#define CELT_PVQ_V(n, k) (CELT_PVQ_U(n, k) + CELT_PVQ_U(n, (k) + 1)) + +static inline int16_t celt_cos(int16_t x) +{ + x = (MUL16(x, x) + 4096) >> 13; + x = (32767-x) + ROUND_MUL16(x, (-7651 + ROUND_MUL16(x, (8277 + ROUND_MUL16(-626, x))))); + return x + 1; +} + +static inline int celt_log2tan(int isin, int icos) +{ + int lc, ls; + lc = opus_ilog(icos); + ls = opus_ilog(isin); + icos <<= 15 - lc; + isin <<= 15 - ls; + return (ls << 11) - (lc << 11) + + ROUND_MUL16(isin, ROUND_MUL16(isin, -2597) + 7932) - + ROUND_MUL16(icos, ROUND_MUL16(icos, -2597) + 7932); +} + +static inline int celt_bits2pulses(const uint8_t *cache, int bits) +{ + // TODO: Find the size of cache and make it into an array in the parameters list + int i, low = 0, high; + + high = cache[0]; + bits--; + + for (i = 0; i < 6; i++) { + int center = (low + high + 1) >> 1; + if (cache[center] >= bits) + high = center; + else + low = center; + } + + return (bits - (low == 0 ? -1 : cache[low]) <= cache[high] - bits) ? low : high; +} + +static inline int celt_pulses2bits(const uint8_t *cache, int pulses) +{ + // TODO: Find the size of cache and make it into an array in the parameters list + return (pulses == 0) ? 0 : cache[pulses] + 1; +} + +static inline void celt_normalize_residual(const int * av_restrict iy, float * av_restrict X, + int N, float g) +{ + int i; + for (i = 0; i < N; i++) + X[i] = g * iy[i]; +} + +static void celt_exp_rotation_impl(float *X, uint32_t len, uint32_t stride, + float c, float s) +{ + float *Xptr; + int i; + + Xptr = X; + for (i = 0; i < len - stride; i++) { + float x1 = Xptr[0]; + float x2 = Xptr[stride]; + Xptr[stride] = c * x2 + s * x1; + *Xptr++ = c * x1 - s * x2; + } + + Xptr = &X[len - 2 * stride - 1]; + for (i = len - 2 * stride - 1; i >= 0; i--) { + float x1 = Xptr[0]; + float x2 = Xptr[stride]; + Xptr[stride] = c * x2 + s * x1; + *Xptr-- = c * x1 - s * x2; + } +} + +static inline void celt_exp_rotation(float *X, uint32_t len, + uint32_t stride, uint32_t K, + enum CeltSpread spread, const int encode) +{ + uint32_t stride2 = 0; + float c, s; + float gain, theta; + int i; + + if (2*K >= len || spread == CELT_SPREAD_NONE) + return; + + gain = (float)len / (len + (20 - 5*spread) * K); + theta = M_PI * gain * gain / 4; + + c = cosf(theta); + s = sinf(theta); + + if (len >= stride << 3) { + stride2 = 1; + /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding. + It's basically incrementing long as (stride2+0.5)^2 < len/stride. */ + while ((stride2 * stride2 + stride2) * stride + (stride >> 2) < len) + stride2++; + } + + len /= stride; + for (i = 0; i < stride; i++) { + if (encode) { + celt_exp_rotation_impl(X + i * len, len, 1, c, -s); + if (stride2) + celt_exp_rotation_impl(X + i * len, len, stride2, s, -c); + } else { + if (stride2) + celt_exp_rotation_impl(X + i * len, len, stride2, s, c); + celt_exp_rotation_impl(X + i * len, len, 1, c, s); + } + } +} + +static inline uint32_t celt_extract_collapse_mask(const int *iy, uint32_t N, uint32_t B) +{ + int i, j, N0 = N / B; + uint32_t collapse_mask = 0; + + if (B <= 1) + return 1; + + for (i = 0; i < B; i++) + for (j = 0; j < N0; j++) + collapse_mask |= (!!iy[i*N0+j]) << i; + return collapse_mask; +} + +static inline void celt_stereo_merge(float *X, float *Y, float mid, int N) +{ + int i; + float xp = 0, side = 0; + float E[2]; + float mid2; + float gain[2]; + + /* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */ + for (i = 0; i < N; i++) { + xp += X[i] * Y[i]; + side += Y[i] * Y[i]; + } + + /* Compensating for the mid normalization */ + xp *= mid; + mid2 = mid; + E[0] = mid2 * mid2 + side - 2 * xp; + E[1] = mid2 * mid2 + side + 2 * xp; + if (E[0] < 6e-4f || E[1] < 6e-4f) { + for (i = 0; i < N; i++) + Y[i] = X[i]; + return; + } + + gain[0] = 1.0f / sqrtf(E[0]); + gain[1] = 1.0f / sqrtf(E[1]); + + for (i = 0; i < N; i++) { + float value[2]; + /* Apply mid scaling (side is already scaled) */ + value[0] = mid * X[i]; + value[1] = Y[i]; + X[i] = gain[0] * (value[0] - value[1]); + Y[i] = gain[1] * (value[0] + value[1]); + } +} + +static void celt_interleave_hadamard(float *tmp, float *X, int N0, + int stride, int hadamard) +{ + int i, j, N = N0*stride; + const uint8_t *order = &ff_celt_hadamard_order[hadamard ? stride - 2 : 30]; + + for (i = 0; i < stride; i++) + for (j = 0; j < N0; j++) + tmp[j*stride+i] = X[order[i]*N0+j]; + + memcpy(X, tmp, N*sizeof(float)); +} + +static void celt_deinterleave_hadamard(float *tmp, float *X, int N0, + int stride, int hadamard) +{ + int i, j, N = N0*stride; + const uint8_t *order = &ff_celt_hadamard_order[hadamard ? stride - 2 : 30]; + + for (i = 0; i < stride; i++) + for (j = 0; j < N0; j++) + tmp[order[i]*N0+j] = X[j*stride+i]; + + memcpy(X, tmp, N*sizeof(float)); +} + +static void celt_haar1(float *X, int N0, int stride) +{ + int i, j; + N0 >>= 1; + for (i = 0; i < stride; i++) { + for (j = 0; j < N0; j++) { + float x0 = X[stride * (2 * j + 0) + i]; + float x1 = X[stride * (2 * j + 1) + i]; + X[stride * (2 * j + 0) + i] = (x0 + x1) * M_SQRT1_2; + X[stride * (2 * j + 1) + i] = (x0 - x1) * M_SQRT1_2; + } + } +} + +static inline int celt_compute_qn(int N, int b, int offset, int pulse_cap, + int stereo) +{ + int qn, qb; + int N2 = 2 * N - 1; + if (stereo && N == 2) + N2--; + + /* The upper limit ensures that in a stereo split with itheta==16384, we'll + * always have enough bits left over to code at least one pulse in the + * side; otherwise it would collapse, since it doesn't get folded. */ + qb = FFMIN3(b - pulse_cap - (4 << 3), (b + N2 * offset) / N2, 8 << 3); + qn = (qb < (1 << 3 >> 1)) ? 1 : ((ff_celt_qn_exp2[qb & 0x7] >> (14 - (qb >> 3))) + 1) >> 1 << 1; + return qn; +} + +/* Convert the quantized vector to an index */ +static inline uint32_t celt_icwrsi(uint32_t N, uint32_t K, const int *y) +{ + int i, idx = 0, sum = 0; + for (i = N - 1; i >= 0; i--) { + const uint32_t i_s = CELT_PVQ_U(N - i, sum + FFABS(y[i]) + 1); + idx += CELT_PVQ_U(N - i, sum) + (y[i] < 0)*i_s; + sum += FFABS(y[i]); + } + return idx; +} + +// this code was adapted from libopus +static inline uint64_t celt_cwrsi(uint32_t N, uint32_t K, uint32_t i, int *y) +{ + uint64_t norm = 0; + uint32_t q, p; + int s, val; + int k0; + + while (N > 2) { + /*Lots of pulses case:*/ + if (K >= N) { + const uint32_t *row = ff_celt_pvq_u_row[N]; + + /* Are the pulses in this dimension negative? */ + p = row[K + 1]; + s = -(i >= p); + i -= p & s; + + /*Count how many pulses were placed in this dimension.*/ + k0 = K; + q = row[N]; + if (q > i) { + K = N; + do { + p = ff_celt_pvq_u_row[--K][N]; + } while (p > i); + } else + for (p = row[K]; p > i; p = row[K]) + K--; + + i -= p; + val = (k0 - K + s) ^ s; + norm += val * val; + *y++ = val; + } else { /*Lots of dimensions case:*/ + /*Are there any pulses in this dimension at all?*/ + p = ff_celt_pvq_u_row[K ][N]; + q = ff_celt_pvq_u_row[K + 1][N]; + + if (p <= i && i < q) { + i -= p; + *y++ = 0; + } else { + /*Are the pulses in this dimension negative?*/ + s = -(i >= q); + i -= q & s; + + /*Count how many pulses were placed in this dimension.*/ + k0 = K; + do p = ff_celt_pvq_u_row[--K][N]; + while (p > i); + + i -= p; + val = (k0 - K + s) ^ s; + norm += val * val; + *y++ = val; + } + } + N--; + } + + /* N == 2 */ + p = 2 * K + 1; + s = -(i >= p); + i -= p & s; + k0 = K; + K = (i + 1) / 2; + + if (K) + i -= 2 * K - 1; + + val = (k0 - K + s) ^ s; + norm += val * val; + *y++ = val; + + /* N==1 */ + s = -i; + val = (K + s) ^ s; + norm += val * val; + *y = val; + + return norm; +} + +static inline void celt_encode_pulses(OpusRangeCoder *rc, int *y, uint32_t N, uint32_t K) +{ + ff_opus_rc_enc_uint(rc, celt_icwrsi(N, K, y), CELT_PVQ_V(N, K)); +} + +static inline float celt_decode_pulses(OpusRangeCoder *rc, int *y, uint32_t N, uint32_t K) +{ + const uint32_t idx = ff_opus_rc_dec_uint(rc, CELT_PVQ_V(N, K)); + return celt_cwrsi(N, K, idx, y); +} + +/* + * Faster than libopus's search, operates entirely in the signed domain. + * Slightly worse/better depending on N, K and the input vector. + */ +static float ppp_pvq_search_c(float *X, int *y, int K, int N) +{ + int i, y_norm = 0; + float res = 0.0f, xy_norm = 0.0f; + + for (i = 0; i < N; i++) + res += FFABS(X[i]); + + res = K/(res + FLT_EPSILON); + + for (i = 0; i < N; i++) { + y[i] = lrintf(res*X[i]); + y_norm += y[i]*y[i]; + xy_norm += y[i]*X[i]; + K -= FFABS(y[i]); + } + + while (K) { + int max_idx = 0, phase = FFSIGN(K); + float max_num = 0.0f; + float max_den = 1.0f; + y_norm += 1.0f; + + for (i = 0; i < N; i++) { + /* If the sum has been overshot and the best place has 0 pulses allocated + * to it, attempting to decrease it further will actually increase the + * sum. Prevent this by disregarding any 0 positions when decrementing. */ + const int ca = 1 ^ ((y[i] == 0) & (phase < 0)); + const int y_new = y_norm + 2*phase*FFABS(y[i]); + float xy_new = xy_norm + 1*phase*FFABS(X[i]); + xy_new = xy_new * xy_new; + if (ca && (max_den*xy_new) > (y_new*max_num)) { + max_den = y_new; + max_num = xy_new; + max_idx = i; + } + } + + K -= phase; + + phase *= FFSIGN(X[max_idx]); + xy_norm += 1*phase*X[max_idx]; + y_norm += 2*phase*y[max_idx]; + y[max_idx] += phase; + } + + return (float)y_norm; +} + +static uint32_t celt_alg_quant(OpusRangeCoder *rc, float *X, uint32_t N, uint32_t K, + enum CeltSpread spread, uint32_t blocks, float gain, + CeltPVQ *pvq) +{ + int *y = pvq->qcoeff; + + celt_exp_rotation(X, N, blocks, K, spread, 1); + gain /= sqrtf(pvq->pvq_search(X, y, K, N)); + celt_encode_pulses(rc, y, N, K); + celt_normalize_residual(y, X, N, gain); + celt_exp_rotation(X, N, blocks, K, spread, 0); + return celt_extract_collapse_mask(y, N, blocks); +} + +/** Decode pulse vector and combine the result with the pitch vector to produce + the final normalised signal in the current band. */ +static uint32_t celt_alg_unquant(OpusRangeCoder *rc, float *X, uint32_t N, uint32_t K, + enum CeltSpread spread, uint32_t blocks, float gain, + CeltPVQ *pvq) +{ + int *y = pvq->qcoeff; + + gain /= sqrtf(celt_decode_pulses(rc, y, N, K)); + celt_normalize_residual(y, X, N, gain); + celt_exp_rotation(X, N, blocks, K, spread, 0); + return celt_extract_collapse_mask(y, N, blocks); +} + +static int celt_calc_theta(const float *X, const float *Y, int coupling, int N) +{ + int i; + float e[2] = { 0.0f, 0.0f }; + if (coupling) { /* Coupling case */ + for (i = 0; i < N; i++) { + e[0] += (X[i] + Y[i])*(X[i] + Y[i]); + e[1] += (X[i] - Y[i])*(X[i] - Y[i]); + } + } else { + for (i = 0; i < N; i++) { + e[0] += X[i]*X[i]; + e[1] += Y[i]*Y[i]; + } + } + return lrintf(32768.0f*atan2f(sqrtf(e[1]), sqrtf(e[0]))/M_PI); +} + +static void celt_stereo_is_decouple(float *X, float *Y, float e_l, float e_r, int N) +{ + int i; + const float energy_n = 1.0f/(sqrtf(e_l*e_l + e_r*e_r) + FLT_EPSILON); + e_l *= energy_n; + e_r *= energy_n; + for (i = 0; i < N; i++) + X[i] = e_l*X[i] + e_r*Y[i]; +} + +static void celt_stereo_ms_decouple(float *X, float *Y, int N) +{ + int i; + for (i = 0; i < N; i++) { + const float Xret = X[i]; + X[i] = (X[i] + Y[i])*M_SQRT1_2; + Y[i] = (Y[i] - Xret)*M_SQRT1_2; + } +} + +static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, + OpusRangeCoder *rc, + const int band, float *X, + float *Y, int N, int b, + uint32_t blocks, float *lowband, + int duration, float *lowband_out, + int level, float gain, + float *lowband_scratch, + int fill, int quant) +{ + int i; + const uint8_t *cache; + int stereo = !!Y, split = stereo; + int imid = 0, iside = 0; + uint32_t N0 = N; + int N_B = N / blocks; + int N_B0 = N_B; + int B0 = blocks; + int time_divide = 0; + int recombine = 0; + int inv = 0; + float mid = 0, side = 0; + int longblocks = (B0 == 1); + uint32_t cm = 0; + + if (N == 1) { + float *x = X; + for (i = 0; i <= stereo; i++) { + int sign = 0; + if (f->remaining2 >= 1 << 3) { + if (quant) { + sign = x[0] < 0; + ff_opus_rc_put_raw(rc, sign, 1); + } else { + sign = ff_opus_rc_get_raw(rc, 1); + } + f->remaining2 -= 1 << 3; + } + x[0] = 1.0f - 2.0f*sign; + x = Y; + } + if (lowband_out) + lowband_out[0] = X[0]; + return 1; + } + + if (!stereo && level == 0) { + int tf_change = f->tf_change[band]; + int k; + if (tf_change > 0) + recombine = tf_change; + /* Band recombining to increase frequency resolution */ + + if (lowband && + (recombine || ((N_B & 1) == 0 && tf_change < 0) || B0 > 1)) { + for (i = 0; i < N; i++) + lowband_scratch[i] = lowband[i]; + lowband = lowband_scratch; + } + + for (k = 0; k < recombine; k++) { + if (quant || lowband) + celt_haar1(quant ? X : lowband, N >> k, 1 << k); + fill = ff_celt_bit_interleave[fill & 0xF] | ff_celt_bit_interleave[fill >> 4] << 2; + } + blocks >>= recombine; + N_B <<= recombine; + + /* Increasing the time resolution */ + while ((N_B & 1) == 0 && tf_change < 0) { + if (quant || lowband) + celt_haar1(quant ? X : lowband, N_B, blocks); + fill |= fill << blocks; + blocks <<= 1; + N_B >>= 1; + time_divide++; + tf_change++; + } + B0 = blocks; + N_B0 = N_B; + + /* Reorganize the samples in time order instead of frequency order */ + if (B0 > 1 && (quant || lowband)) + celt_deinterleave_hadamard(pvq->hadamard_tmp, quant ? X : lowband, + N_B >> recombine, B0 << recombine, + longblocks); + } + + /* If we need 1.5 more bit than we can produce, split the band in two. */ + cache = ff_celt_cache_bits + + ff_celt_cache_index[(duration + 1) * CELT_MAX_BANDS + band]; + if (!stereo && duration >= 0 && b > cache[cache[0]] + 12 && N > 2) { + N >>= 1; + Y = X + N; + split = 1; + duration -= 1; + if (blocks == 1) + fill = (fill & 1) | (fill << 1); + blocks = (blocks + 1) >> 1; + } + + if (split) { + int qn; + int itheta = quant ? celt_calc_theta(X, Y, stereo, N) : 0; + int mbits, sbits, delta; + int qalloc; + int pulse_cap; + int offset; + int orig_fill; + int tell; + + /* Decide on the resolution to give to the split parameter theta */ + pulse_cap = ff_celt_log_freq_range[band] + duration * 8; + offset = (pulse_cap >> 1) - (stereo && N == 2 ? CELT_QTHETA_OFFSET_TWOPHASE : + CELT_QTHETA_OFFSET); + qn = (stereo && band >= f->intensity_stereo) ? 1 : + celt_compute_qn(N, b, offset, pulse_cap, stereo); + tell = opus_rc_tell_frac(rc); + if (qn != 1) { + if (quant) + itheta = (itheta*qn + 8192) >> 14; + /* Entropy coding of the angle. We use a uniform pdf for the + * time split, a step for stereo, and a triangular one for the rest. */ + if (quant) { + if (stereo && N > 2) + ff_opus_rc_enc_uint_step(rc, itheta, qn / 2); + else if (stereo || B0 > 1) + ff_opus_rc_enc_uint(rc, itheta, qn + 1); + else + ff_opus_rc_enc_uint_tri(rc, itheta, qn); + itheta = itheta * 16384 / qn; + if (stereo) { + if (itheta == 0) + celt_stereo_is_decouple(X, Y, f->block[0].lin_energy[band], + f->block[1].lin_energy[band], N); + else + celt_stereo_ms_decouple(X, Y, N); + } + } else { + if (stereo && N > 2) + itheta = ff_opus_rc_dec_uint_step(rc, qn / 2); + else if (stereo || B0 > 1) + itheta = ff_opus_rc_dec_uint(rc, qn+1); + else + itheta = ff_opus_rc_dec_uint_tri(rc, qn); + itheta = itheta * 16384 / qn; + } + } else if (stereo) { + if (quant) { + inv = itheta > 8192; + if (inv) { + for (i = 0; i < N; i++) + Y[i] *= -1; + } + celt_stereo_is_decouple(X, Y, f->block[0].lin_energy[band], + f->block[1].lin_energy[band], N); + + if (b > 2 << 3 && f->remaining2 > 2 << 3) { + ff_opus_rc_enc_log(rc, inv, 2); + } else { + inv = 0; + } + } else { + inv = (b > 2 << 3 && f->remaining2 > 2 << 3) ? ff_opus_rc_dec_log(rc, 2) : 0; + inv = f->apply_phase_inv ? inv : 0; + } + itheta = 0; + } + qalloc = opus_rc_tell_frac(rc) - tell; + b -= qalloc; + + orig_fill = fill; + if (itheta == 0) { + imid = 32767; + iside = 0; + fill = av_mod_uintp2(fill, blocks); + delta = -16384; + } else if (itheta == 16384) { + imid = 0; + iside = 32767; + fill &= ((1 << blocks) - 1) << blocks; + delta = 16384; + } else { + imid = celt_cos(itheta); + iside = celt_cos(16384-itheta); + /* This is the mid vs side allocation that minimizes squared error + in that band. */ + delta = ROUND_MUL16((N - 1) << 7, celt_log2tan(iside, imid)); + } + + mid = imid / 32768.0f; + side = iside / 32768.0f; + + /* This is a special case for N=2 that only works for stereo and takes + advantage of the fact that mid and side are orthogonal to encode + the side with just one bit. */ + if (N == 2 && stereo) { + int c; + int sign = 0; + float tmp; + float *x2, *y2; + mbits = b; + /* Only need one bit for the side */ + sbits = (itheta != 0 && itheta != 16384) ? 1 << 3 : 0; + mbits -= sbits; + c = (itheta > 8192); + f->remaining2 -= qalloc+sbits; + + x2 = c ? Y : X; + y2 = c ? X : Y; + if (sbits) { + if (quant) { + sign = x2[0]*y2[1] - x2[1]*y2[0] < 0; + ff_opus_rc_put_raw(rc, sign, 1); + } else { + sign = ff_opus_rc_get_raw(rc, 1); + } + } + sign = 1 - 2 * sign; + /* We use orig_fill here because we want to fold the side, but if + itheta==16384, we'll have cleared the low bits of fill. */ + cm = pvq->quant_band(pvq, f, rc, band, x2, NULL, N, mbits, blocks, lowband, duration, + lowband_out, level, gain, lowband_scratch, orig_fill); + /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse), + and there's no need to worry about mixing with the other channel. */ + y2[0] = -sign * x2[1]; + y2[1] = sign * x2[0]; + X[0] *= mid; + X[1] *= mid; + Y[0] *= side; + Y[1] *= side; + tmp = X[0]; + X[0] = tmp - Y[0]; + Y[0] = tmp + Y[0]; + tmp = X[1]; + X[1] = tmp - Y[1]; + Y[1] = tmp + Y[1]; + } else { + /* "Normal" split code */ + float *next_lowband2 = NULL; + float *next_lowband_out1 = NULL; + int next_level = 0; + int rebalance; + uint32_t cmt; + + /* Give more bits to low-energy MDCTs than they would + * otherwise deserve */ + if (B0 > 1 && !stereo && (itheta & 0x3fff)) { + if (itheta > 8192) + /* Rough approximation for pre-echo masking */ + delta -= delta >> (4 - duration); + else + /* Corresponds to a forward-masking slope of + * 1.5 dB per 10 ms */ + delta = FFMIN(0, delta + (N << 3 >> (5 - duration))); + } + mbits = av_clip((b - delta) / 2, 0, b); + sbits = b - mbits; + f->remaining2 -= qalloc; + + if (lowband && !stereo) + next_lowband2 = lowband + N; /* >32-bit split case */ + + /* Only stereo needs to pass on lowband_out. + * Otherwise, it's handled at the end */ + if (stereo) + next_lowband_out1 = lowband_out; + else + next_level = level + 1; + + rebalance = f->remaining2; + if (mbits >= sbits) { + /* In stereo mode, we do not apply a scaling to the mid + * because we need the normalized mid for folding later */ + cm = pvq->quant_band(pvq, f, rc, band, X, NULL, N, mbits, blocks, + lowband, duration, next_lowband_out1, next_level, + stereo ? 1.0f : (gain * mid), lowband_scratch, fill); + rebalance = mbits - (rebalance - f->remaining2); + if (rebalance > 3 << 3 && itheta != 0) + sbits += rebalance - (3 << 3); + + /* For a stereo split, the high bits of fill are always zero, + * so no folding will be done to the side. */ + cmt = pvq->quant_band(pvq, f, rc, band, Y, NULL, N, sbits, blocks, + next_lowband2, duration, NULL, next_level, + gain * side, NULL, fill >> blocks); + cm |= cmt << ((B0 >> 1) & (stereo - 1)); + } else { + /* For a stereo split, the high bits of fill are always zero, + * so no folding will be done to the side. */ + cm = pvq->quant_band(pvq, f, rc, band, Y, NULL, N, sbits, blocks, + next_lowband2, duration, NULL, next_level, + gain * side, NULL, fill >> blocks); + cm <<= ((B0 >> 1) & (stereo - 1)); + rebalance = sbits - (rebalance - f->remaining2); + if (rebalance > 3 << 3 && itheta != 16384) + mbits += rebalance - (3 << 3); + + /* In stereo mode, we do not apply a scaling to the mid because + * we need the normalized mid for folding later */ + cm |= pvq->quant_band(pvq, f, rc, band, X, NULL, N, mbits, blocks, + lowband, duration, next_lowband_out1, next_level, + stereo ? 1.0f : (gain * mid), lowband_scratch, fill); + } + } + } else { + /* This is the basic no-split case */ + uint32_t q = celt_bits2pulses(cache, b); + uint32_t curr_bits = celt_pulses2bits(cache, q); + f->remaining2 -= curr_bits; + + /* Ensures we can never bust the budget */ + while (f->remaining2 < 0 && q > 0) { + f->remaining2 += curr_bits; + curr_bits = celt_pulses2bits(cache, --q); + f->remaining2 -= curr_bits; + } + + if (q != 0) { + /* Finally do the actual (de)quantization */ + if (quant) { + cm = celt_alg_quant(rc, X, N, (q < 8) ? q : (8 + (q & 7)) << ((q >> 3) - 1), + f->spread, blocks, gain, pvq); + } else { + cm = celt_alg_unquant(rc, X, N, (q < 8) ? q : (8 + (q & 7)) << ((q >> 3) - 1), + f->spread, blocks, gain, pvq); + } + } else { + /* If there's no pulse, fill the band anyway */ + uint32_t cm_mask = (1 << blocks) - 1; + fill &= cm_mask; + if (fill) { + if (!lowband) { + /* Noise */ + for (i = 0; i < N; i++) + X[i] = (((int32_t)celt_rng(f)) >> 20); + cm = cm_mask; + } else { + /* Folded spectrum */ + for (i = 0; i < N; i++) { + /* About 48 dB below the "normal" folding level */ + X[i] = lowband[i] + (((celt_rng(f)) & 0x8000) ? 1.0f / 256 : -1.0f / 256); + } + cm = fill; + } + celt_renormalize_vector(X, N, gain); + } else { + memset(X, 0, N*sizeof(float)); + } + } + } + + /* This code is used by the decoder and by the resynthesis-enabled encoder */ + if (stereo) { + if (N > 2) + celt_stereo_merge(X, Y, mid, N); + if (inv) { + for (i = 0; i < N; i++) + Y[i] *= -1; + } + } else if (level == 0) { + int k; + + /* Undo the sample reorganization going from time order to frequency order */ + if (B0 > 1) + celt_interleave_hadamard(pvq->hadamard_tmp, X, N_B >> recombine, + B0 << recombine, longblocks); + + /* Undo time-freq changes that we did earlier */ + N_B = N_B0; + blocks = B0; + for (k = 0; k < time_divide; k++) { + blocks >>= 1; + N_B <<= 1; + cm |= cm >> blocks; + celt_haar1(X, N_B, blocks); + } + + for (k = 0; k < recombine; k++) { + cm = ff_celt_bit_deinterleave[cm]; + celt_haar1(X, N0>>k, 1<pvq_search = ppp_pvq_search_c; + s->quant_band = encode ? pvq_encode_band : pvq_decode_band; + + if (CONFIG_OPUS_ENCODER && ARCH_X86) + ff_celt_pvq_init_x86(s); + + *pvq = s; + + return 0; +} + +void av_cold ff_celt_pvq_uninit(CeltPVQ **pvq) +{ + av_freep(pvq); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_pvq.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_pvq.h new file mode 100644 index 0000000000..52f9a4e6d4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_pvq.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * Copyright (c) 2016 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPUS_PVQ_H +#define AVCODEC_OPUS_PVQ_H + +#include "opus_celt.h" + +#define QUANT_FN(name) uint32_t (name)(struct CeltPVQ *pvq, CeltFrame *f, \ + OpusRangeCoder *rc, const int band, float *X, \ + float *Y, int N, int b, uint32_t blocks, \ + float *lowband, int duration, \ + float *lowband_out, int level, float gain, \ + float *lowband_scratch, int fill) + +struct CeltPVQ { + DECLARE_ALIGNED(32, int, qcoeff )[256]; + DECLARE_ALIGNED(32, float, hadamard_tmp)[256]; + + float (*pvq_search)(float *X, int *y, int K, int N); + QUANT_FN(*quant_band); +}; + +void ff_celt_pvq_init_x86(struct CeltPVQ *s); + +int ff_celt_pvq_init(struct CeltPVQ **pvq, int encode); +void ff_celt_pvq_uninit(struct CeltPVQ **pvq); + +#endif /* AVCODEC_OPUS_PVQ_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_rc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_rc.c new file mode 100644 index 0000000000..c432eb90c9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_rc.c @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * Copyright (c) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "opus_rc.h" + +#define OPUS_RC_BITS 32 +#define OPUS_RC_SYM 8 +#define OPUS_RC_CEIL ((1 << OPUS_RC_SYM) - 1) +#define OPUS_RC_TOP (1u << 31) +#define OPUS_RC_BOT (OPUS_RC_TOP >> OPUS_RC_SYM) +#define OPUS_RC_SHIFT (OPUS_RC_BITS - OPUS_RC_SYM - 1) + +static av_always_inline void opus_rc_enc_carryout(OpusRangeCoder *rc, int cbuf) +{ + const int cb = cbuf >> OPUS_RC_SYM, mb = (OPUS_RC_CEIL + cb) & OPUS_RC_CEIL; + if (cbuf == OPUS_RC_CEIL) { + rc->ext++; + return; + } + rc->rng_cur[0] = rc->rem + cb; + rc->rng_cur += (rc->rem >= 0); + for (; rc->ext > 0; rc->ext--) + *rc->rng_cur++ = mb; + av_assert0(rc->rng_cur < rc->rb.position); + rc->rem = cbuf & OPUS_RC_CEIL; /* Propagate */ +} + +static av_always_inline void opus_rc_dec_normalize(OpusRangeCoder *rc) +{ + while (rc->range <= OPUS_RC_BOT) { + rc->value = ((rc->value << OPUS_RC_SYM) | (get_bits(&rc->gb, OPUS_RC_SYM) ^ OPUS_RC_CEIL)) & (OPUS_RC_TOP - 1); + rc->range <<= OPUS_RC_SYM; + rc->total_bits += OPUS_RC_SYM; + } +} + +static av_always_inline void opus_rc_enc_normalize(OpusRangeCoder *rc) +{ + while (rc->range <= OPUS_RC_BOT) { + opus_rc_enc_carryout(rc, rc->value >> OPUS_RC_SHIFT); + rc->value = (rc->value << OPUS_RC_SYM) & (OPUS_RC_TOP - 1); + rc->range <<= OPUS_RC_SYM; + rc->total_bits += OPUS_RC_SYM; + } +} + +static av_always_inline void opus_rc_dec_update(OpusRangeCoder *rc, uint32_t scale, + uint32_t low, uint32_t high, + uint32_t total) +{ + rc->value -= scale * (total - high); + rc->range = low ? scale * (high - low) + : rc->range - scale * (total - high); + opus_rc_dec_normalize(rc); +} + +/* Main encoding function, this needs to go fast */ +static av_always_inline void opus_rc_enc_update(OpusRangeCoder *rc, uint32_t b, uint32_t p, + uint32_t p_tot, const int ptwo) +{ + uint32_t rscaled, cnd = !!b; + if (ptwo) /* Whole function is inlined so hopefully branch is optimized out */ + rscaled = rc->range >> ff_log2(p_tot); + else + rscaled = rc->range/p_tot; + rc->value += cnd*(rc->range - rscaled*(p_tot - b)); + rc->range = (!cnd)*(rc->range - rscaled*(p_tot - p)) + cnd*rscaled*(p - b); + opus_rc_enc_normalize(rc); +} + +uint32_t ff_opus_rc_dec_cdf(OpusRangeCoder *rc, const uint16_t *cdf) +{ + unsigned int k, scale, total, symbol, low, high; + + total = *cdf++; + + scale = rc->range / total; + symbol = rc->value / scale + 1; + symbol = total - FFMIN(symbol, total); + + for (k = 0; cdf[k] <= symbol; k++); + high = cdf[k]; + low = k ? cdf[k-1] : 0; + + opus_rc_dec_update(rc, scale, low, high, total); + + return k; +} + +void ff_opus_rc_enc_cdf(OpusRangeCoder *rc, int val, const uint16_t *cdf) +{ + opus_rc_enc_update(rc, (!!val)*cdf[val], cdf[val + 1], cdf[0], 1); +} + +uint32_t ff_opus_rc_dec_log(OpusRangeCoder *rc, uint32_t bits) +{ + uint32_t k, scale; + scale = rc->range >> bits; // in this case, scale = symbol + + if (rc->value >= scale) { + rc->value -= scale; + rc->range -= scale; + k = 0; + } else { + rc->range = scale; + k = 1; + } + opus_rc_dec_normalize(rc); + return k; +} + +void ff_opus_rc_enc_log(OpusRangeCoder *rc, int val, uint32_t bits) +{ + bits = (1 << bits) - 1; + opus_rc_enc_update(rc, (!!val)*bits, bits + !!val, bits + 1, 1); +} + +/** + * CELT: read 1-25 raw bits at the end of the frame, backwards byte-wise + */ +uint32_t ff_opus_rc_get_raw(OpusRangeCoder *rc, uint32_t count) +{ + uint32_t value = 0; + + while (rc->rb.bytes && rc->rb.cachelen < count) { + rc->rb.cacheval |= *--rc->rb.position << rc->rb.cachelen; + rc->rb.cachelen += 8; + rc->rb.bytes--; + } + + value = av_mod_uintp2(rc->rb.cacheval, count); + rc->rb.cacheval >>= count; + rc->rb.cachelen -= count; + rc->total_bits += count; + + return value; +} + +/** + * CELT: write 0 - 31 bits to the rawbits buffer + */ +void ff_opus_rc_put_raw(OpusRangeCoder *rc, uint32_t val, uint32_t count) +{ + const int to_write = FFMIN(32 - rc->rb.cachelen, count); + + rc->total_bits += count; + rc->rb.cacheval |= av_mod_uintp2(val, to_write) << rc->rb.cachelen; + rc->rb.cachelen = (rc->rb.cachelen + to_write) % 32; + + if (!rc->rb.cachelen && count) { + AV_WB32((uint8_t *)rc->rb.position, rc->rb.cacheval); + rc->rb.bytes += 4; + rc->rb.position -= 4; + rc->rb.cachelen = count - to_write; + rc->rb.cacheval = av_mod_uintp2(val >> to_write, rc->rb.cachelen); + av_assert0(rc->rng_cur < rc->rb.position); + } +} + +/** + * CELT: read a uniform distribution + */ +uint32_t ff_opus_rc_dec_uint(OpusRangeCoder *rc, uint32_t size) +{ + uint32_t bits, k, scale, total; + + bits = opus_ilog(size - 1); + total = (bits > 8) ? ((size - 1) >> (bits - 8)) + 1 : size; + + scale = rc->range / total; + k = rc->value / scale + 1; + k = total - FFMIN(k, total); + opus_rc_dec_update(rc, scale, k, k + 1, total); + + if (bits > 8) { + k = k << (bits - 8) | ff_opus_rc_get_raw(rc, bits - 8); + return FFMIN(k, size - 1); + } else + return k; +} + +/** + * CELT: write a uniformly distributed integer + */ +void ff_opus_rc_enc_uint(OpusRangeCoder *rc, uint32_t val, uint32_t size) +{ + const int ps = FFMAX(opus_ilog(size - 1) - 8, 0); + opus_rc_enc_update(rc, val >> ps, (val >> ps) + 1, ((size - 1) >> ps) + 1, 0); + ff_opus_rc_put_raw(rc, val, ps); +} + +uint32_t ff_opus_rc_dec_uint_step(OpusRangeCoder *rc, int k0) +{ + /* Use a probability of 3 up to itheta=8192 and then use 1 after */ + uint32_t k, scale, symbol, total = (k0+1)*3 + k0; + scale = rc->range / total; + symbol = rc->value / scale + 1; + symbol = total - FFMIN(symbol, total); + + k = (symbol < (k0+1)*3) ? symbol/3 : symbol - (k0+1)*2; + + opus_rc_dec_update(rc, scale, (k <= k0) ? 3*(k+0) : (k-1-k0) + 3*(k0+1), + (k <= k0) ? 3*(k+1) : (k-0-k0) + 3*(k0+1), total); + return k; +} + +void ff_opus_rc_enc_uint_step(OpusRangeCoder *rc, uint32_t val, int k0) +{ + const uint32_t a = val <= k0, b = 2*a + 1; + k0 = (k0 + 1) << 1; + val = b*(val + k0) - 3*a*k0; + opus_rc_enc_update(rc, val, val + b, (k0 << 1) - 1, 0); +} + +uint32_t ff_opus_rc_dec_uint_tri(OpusRangeCoder *rc, int qn) +{ + uint32_t k, scale, symbol, total, low, center; + + total = ((qn>>1) + 1) * ((qn>>1) + 1); + scale = rc->range / total; + center = rc->value / scale + 1; + center = total - FFMIN(center, total); + + if (center < total >> 1) { + k = (ff_sqrt(8 * center + 1) - 1) >> 1; + low = k * (k + 1) >> 1; + symbol = k + 1; + } else { + k = (2*(qn + 1) - ff_sqrt(8*(total - center - 1) + 1)) >> 1; + low = total - ((qn + 1 - k) * (qn + 2 - k) >> 1); + symbol = qn + 1 - k; + } + + opus_rc_dec_update(rc, scale, low, low + symbol, total); + + return k; +} + +void ff_opus_rc_enc_uint_tri(OpusRangeCoder *rc, uint32_t k, int qn) +{ + uint32_t symbol, low, total; + + total = ((qn>>1) + 1) * ((qn>>1) + 1); + + if (k <= qn >> 1) { + low = k * (k + 1) >> 1; + symbol = k + 1; + } else { + low = total - ((qn + 1 - k) * (qn + 2 - k) >> 1); + symbol = qn + 1 - k; + } + + opus_rc_enc_update(rc, low, low + symbol, total, 0); +} + +int ff_opus_rc_dec_laplace(OpusRangeCoder *rc, uint32_t symbol, int decay) +{ + /* extends the range coder to model a Laplace distribution */ + int value = 0; + uint32_t scale, low = 0, center; + + scale = rc->range >> 15; + center = rc->value / scale + 1; + center = (1 << 15) - FFMIN(center, 1 << 15); + + if (center >= symbol) { + value++; + low = symbol; + symbol = 1 + ((32768 - 32 - symbol) * (16384-decay) >> 15); + + while (symbol > 1 && center >= low + 2 * symbol) { + value++; + symbol *= 2; + low += symbol; + symbol = (((symbol - 2) * decay) >> 15) + 1; + } + + if (symbol <= 1) { + int distance = (center - low) >> 1; + value += distance; + low += 2 * distance; + } + + if (center < low + symbol) + value *= -1; + else + low += symbol; + } + + opus_rc_dec_update(rc, scale, low, FFMIN(low + symbol, 32768), 32768); + + return value; +} + +void ff_opus_rc_enc_laplace(OpusRangeCoder *rc, int *value, uint32_t symbol, int decay) +{ + uint32_t low = symbol; + int i = 1, val = FFABS(*value), pos = *value > 0; + if (!val) { + opus_rc_enc_update(rc, 0, symbol, 1 << 15, 1); + return; + } + symbol = ((32768 - 32 - symbol)*(16384 - decay)) >> 15; + for (; i < val && symbol; i++) { + low += (symbol << 1) + 2; + symbol = (symbol*decay) >> 14; + } + if (symbol) { + low += (++symbol)*pos; + } else { + const int distance = FFMIN(val - i, (((32768 - low) - !pos) >> 1) - 1); + low += pos + (distance << 1); + symbol = FFMIN(1, 32768 - low); + *value = FFSIGN(*value)*(distance + i); + } + opus_rc_enc_update(rc, low, low + symbol, 1 << 15, 1); +} + +int ff_opus_rc_dec_init(OpusRangeCoder *rc, const uint8_t *data, int size) +{ + int ret = init_get_bits8(&rc->gb, data, size); + if (ret < 0) + return ret; + + rc->range = 128; + rc->value = 127 - get_bits(&rc->gb, 7); + rc->total_bits = 9; + opus_rc_dec_normalize(rc); + + return 0; +} + +void ff_opus_rc_dec_raw_init(OpusRangeCoder *rc, const uint8_t *rightend, uint32_t bytes) +{ + rc->rb.position = rightend; + rc->rb.bytes = bytes; + rc->rb.cachelen = 0; + rc->rb.cacheval = 0; +} + +void ff_opus_rc_enc_end(OpusRangeCoder *rc, uint8_t *dst, int size) +{ + int rng_bytes, bits = OPUS_RC_BITS - opus_ilog(rc->range); + uint32_t mask = (OPUS_RC_TOP - 1) >> bits; + uint32_t end = (rc->value + mask) & ~mask; + + if ((end | mask) >= rc->value + rc->range) { + bits++; + mask >>= 1; + end = (rc->value + mask) & ~mask; + } + + /* Finish what's left */ + while (bits > 0) { + opus_rc_enc_carryout(rc, end >> OPUS_RC_SHIFT); + end = (end << OPUS_RC_SYM) & (OPUS_RC_TOP - 1); + bits -= OPUS_RC_SYM; + } + + /* Flush out anything left or marked */ + if (rc->rem >= 0 || rc->ext > 0) + opus_rc_enc_carryout(rc, 0); + + rng_bytes = rc->rng_cur - rc->buf; + memcpy(dst, rc->buf, rng_bytes); + + rc->waste = size*8 - (rc->rb.bytes*8 + rc->rb.cachelen) - rng_bytes*8; + + /* Put the rawbits part, if any */ + if (rc->rb.bytes || rc->rb.cachelen) { + int i, lap; + uint8_t *rb_src, *rb_dst; + ff_opus_rc_put_raw(rc, 0, 32 - rc->rb.cachelen); + rb_src = rc->buf + OPUS_MAX_PACKET_SIZE + 12 - rc->rb.bytes; + rb_dst = dst + FFMAX(size - rc->rb.bytes, 0); + lap = &dst[rng_bytes] - rb_dst; + for (i = 0; i < lap; i++) + rb_dst[i] |= rb_src[i]; + memcpy(&rb_dst[lap], &rb_src[lap], FFMAX(rc->rb.bytes - lap, 0)); + } +} + +void ff_opus_rc_enc_init(OpusRangeCoder *rc) +{ + rc->value = 0; + rc->range = OPUS_RC_TOP; + rc->total_bits = OPUS_RC_BITS + 1; + rc->rem = -1; + rc->ext = 0; + rc->rng_cur = rc->buf; + ff_opus_rc_dec_raw_init(rc, rc->buf + OPUS_MAX_PACKET_SIZE + 8, 0); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_rc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_rc.h new file mode 100644 index 0000000000..627f83229e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opus_rc.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * Copyright (c) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPUS_RC_H +#define AVCODEC_OPUS_RC_H + +#include +#include "get_bits.h" + +#define OPUS_MAX_PACKET_SIZE 1275 + +#define opus_ilog(i) (av_log2(i) + !!(i)) + +typedef struct RawBitsContext { + const uint8_t *position; + uint32_t bytes; + uint32_t cachelen; + uint32_t cacheval; +} RawBitsContext; + +typedef struct OpusRangeCoder { + GetBitContext gb; + RawBitsContext rb; + uint32_t range; + uint32_t value; + uint32_t total_bits; + + /* Encoder */ + uint8_t buf[OPUS_MAX_PACKET_SIZE + 12]; /* memcpy vs (memmove + overreading) */ + uint8_t *rng_cur; /* Current range coded byte */ + int ext; /* Awaiting propagation */ + int rem; /* Carryout flag */ + + /* Encoding stats */ + int waste; +} OpusRangeCoder; + +/** + * CELT: estimate bits of entropy that have thus far been consumed for the + * current CELT frame, to integer and fractional (1/8th bit) precision + */ +static av_always_inline uint32_t opus_rc_tell(const OpusRangeCoder *rc) +{ + return rc->total_bits - av_log2(rc->range) - 1; +} + +static av_always_inline uint32_t opus_rc_tell_frac(const OpusRangeCoder *rc) +{ + uint32_t i, total_bits, rcbuffer, range; + + total_bits = rc->total_bits << 3; + rcbuffer = av_log2(rc->range) + 1; + range = rc->range >> (rcbuffer-16); + + for (i = 0; i < 3; i++) { + int bit; + range = range * range >> 15; + bit = range >> 16; + rcbuffer = rcbuffer << 1 | bit; + range >>= bit; + } + + return total_bits - rcbuffer; +} + +uint32_t ff_opus_rc_dec_cdf(OpusRangeCoder *rc, const uint16_t *cdf); +void ff_opus_rc_enc_cdf(OpusRangeCoder *rc, int val, const uint16_t *cdf); + +uint32_t ff_opus_rc_dec_log(OpusRangeCoder *rc, uint32_t bits); +void ff_opus_rc_enc_log(OpusRangeCoder *rc, int val, uint32_t bits); + +uint32_t ff_opus_rc_dec_uint_step(OpusRangeCoder *rc, int k0); +void ff_opus_rc_enc_uint_step(OpusRangeCoder *rc, uint32_t val, int k0); + +uint32_t ff_opus_rc_dec_uint_tri(OpusRangeCoder *rc, int qn); +void ff_opus_rc_enc_uint_tri(OpusRangeCoder *rc, uint32_t k, int qn); + +uint32_t ff_opus_rc_dec_uint(OpusRangeCoder *rc, uint32_t size); +void ff_opus_rc_enc_uint(OpusRangeCoder *rc, uint32_t val, uint32_t size); + +uint32_t ff_opus_rc_get_raw(OpusRangeCoder *rc, uint32_t count); +void ff_opus_rc_put_raw(OpusRangeCoder *rc, uint32_t val, uint32_t count); + +int ff_opus_rc_dec_laplace(OpusRangeCoder *rc, uint32_t symbol, int decay); +void ff_opus_rc_enc_laplace(OpusRangeCoder *rc, int *value, uint32_t symbol, int decay); + +int ff_opus_rc_dec_init(OpusRangeCoder *rc, const uint8_t *data, int size); +void ff_opus_rc_dec_raw_init(OpusRangeCoder *rc, const uint8_t *rightend, uint32_t bytes); + +void ff_opus_rc_enc_end(OpusRangeCoder *rc, uint8_t *dst, int size); +void ff_opus_rc_enc_init(OpusRangeCoder *rc); + +#define OPUS_RC_CHECKPOINT_UPDATE(rc) \ + rc_rollback_bits = opus_rc_tell_frac(rc); \ + rc_rollback_ctx = *rc + +#define OPUS_RC_CHECKPOINT_SPAWN(rc) \ + uint32_t rc_rollback_bits = opus_rc_tell_frac(rc); \ + OpusRangeCoder rc_rollback_ctx = *rc \ + +#define OPUS_RC_CHECKPOINT_BITS(rc) \ + (opus_rc_tell_frac(rc) - rc_rollback_bits) + +#define OPUS_RC_CHECKPOINT_ROLLBACK(rc) \ + memcpy(rc, &rc_rollback_ctx, sizeof(OpusRangeCoder)); \ + +#endif /* AVCODEC_OPUS_RC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusdsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusdsp.c new file mode 100644 index 0000000000..0e179c98c9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusdsp.c @@ -0,0 +1,67 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "opusdsp.h" + +static void postfilter_c(float *data, int period, float *gains, int len) +{ + const float g0 = gains[0]; + const float g1 = gains[1]; + const float g2 = gains[2]; + + float x4 = data[-period - 2]; + float x3 = data[-period - 1]; + float x2 = data[-period + 0]; + float x1 = data[-period + 1]; + + for (int i = 0; i < len; i++) { + float x0 = data[i - period + 2]; + data[i] += g0 * x2 + + g1 * (x1 + x3) + + g2 * (x0 + x4); + x4 = x3; + x3 = x2; + x2 = x1; + x1 = x0; + } +} + +static float deemphasis_c(float *y, float *x, float coeff, int len) +{ + float state = coeff; + + for (int i = 0; i < len; i++) { + const float tmp = x[i] + state; + state = tmp * CELT_EMPH_COEFF; + y[i] = tmp; + } + + return state; +} + +av_cold void ff_opus_dsp_init(OpusDSP *ctx) +{ + ctx->postfilter = postfilter_c; + ctx->deemphasis = deemphasis_c; + + if (ARCH_X86) + ff_opus_dsp_init_x86(ctx); + + if (ARCH_AARCH64) + ff_opus_dsp_init_aarch64(ctx); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusdsp.h new file mode 100644 index 0000000000..ee3186dd44 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusdsp.h @@ -0,0 +1,36 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPUSDSP_H +#define AVCODEC_OPUSDSP_H + +#include "libavutil/common.h" + +#define CELT_EMPH_COEFF 0.8500061035f + +typedef struct OpusDSP { + void (*postfilter)(float *data, int period, float *gains, int len); + float (*deemphasis)(float *out, float *in, float coeff, int len); +} OpusDSP; + +void ff_opus_dsp_init(OpusDSP *ctx); + +void ff_opus_dsp_init_x86(OpusDSP *ctx); +void ff_opus_dsp_init_aarch64(OpusDSP *ctx); + +#endif /* AVCODEC_OPUSDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc.c new file mode 100644 index 0000000000..3c08ebcf69 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc.c @@ -0,0 +1,738 @@ +/* + * Opus encoder + * Copyright (c) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "opusenc.h" +#include "opus_pvq.h" +#include "opusenc_psy.h" +#include "opustab.h" + +#include "libavutil/float_dsp.h" +#include "libavutil/opt.h" +#include "internal.h" +#include "bytestream.h" +#include "audio_frame_queue.h" + +typedef struct OpusEncContext { + AVClass *av_class; + OpusEncOptions options; + OpusPsyContext psyctx; + AVCodecContext *avctx; + AudioFrameQueue afq; + AVFloatDSPContext *dsp; + MDCT15Context *mdct[CELT_BLOCK_NB]; + CeltPVQ *pvq; + struct FFBufQueue bufqueue; + + uint8_t enc_id[64]; + int enc_id_bits; + + OpusPacketInfo packet; + + int channels; + + CeltFrame *frame; + OpusRangeCoder *rc; + + /* Actual energy the decoder will have */ + float last_quantized_energy[OPUS_MAX_CHANNELS][CELT_MAX_BANDS]; + + DECLARE_ALIGNED(32, float, scratch)[2048]; +} OpusEncContext; + +static void opus_write_extradata(AVCodecContext *avctx) +{ + uint8_t *bs = avctx->extradata; + + bytestream_put_buffer(&bs, "OpusHead", 8); + bytestream_put_byte (&bs, 0x1); + bytestream_put_byte (&bs, avctx->channels); + bytestream_put_le16 (&bs, avctx->initial_padding); + bytestream_put_le32 (&bs, avctx->sample_rate); + bytestream_put_le16 (&bs, 0x0); + bytestream_put_byte (&bs, 0x0); /* Default layout */ +} + +static int opus_gen_toc(OpusEncContext *s, uint8_t *toc, int *size, int *fsize_needed) +{ + int tmp = 0x0, extended_toc = 0; + static const int toc_cfg[][OPUS_MODE_NB][OPUS_BANDWITH_NB] = { + /* Silk Hybrid Celt Layer */ + /* NB MB WB SWB FB NB MB WB SWB FB NB MB WB SWB FB Bandwidth */ + { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 17, 0, 21, 25, 29 } }, /* 2.5 ms */ + { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, { 18, 0, 22, 26, 30 } }, /* 5 ms */ + { { 1, 5, 9, 0, 0 }, { 0, 0, 0, 13, 15 }, { 19, 0, 23, 27, 31 } }, /* 10 ms */ + { { 2, 6, 10, 0, 0 }, { 0, 0, 0, 14, 16 }, { 20, 0, 24, 28, 32 } }, /* 20 ms */ + { { 3, 7, 11, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }, /* 40 ms */ + { { 4, 8, 12, 0, 0 }, { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }, /* 60 ms */ + }; + int cfg = toc_cfg[s->packet.framesize][s->packet.mode][s->packet.bandwidth]; + *fsize_needed = 0; + if (!cfg) + return 1; + if (s->packet.frames == 2) { /* 2 packets */ + if (s->frame[0].framebits == s->frame[1].framebits) { /* same size */ + tmp = 0x1; + } else { /* different size */ + tmp = 0x2; + *fsize_needed = 1; /* put frame sizes in the packet */ + } + } else if (s->packet.frames > 2) { + tmp = 0x3; + extended_toc = 1; + } + tmp |= (s->channels > 1) << 2; /* Stereo or mono */ + tmp |= (cfg - 1) << 3; /* codec configuration */ + *toc++ = tmp; + if (extended_toc) { + for (int i = 0; i < (s->packet.frames - 1); i++) + *fsize_needed |= (s->frame[i].framebits != s->frame[i + 1].framebits); + tmp = (*fsize_needed) << 7; /* vbr flag */ + tmp |= (0) << 6; /* padding flag */ + tmp |= s->packet.frames; + *toc++ = tmp; + } + *size = 1 + extended_toc; + return 0; +} + +static void celt_frame_setup_input(OpusEncContext *s, CeltFrame *f) +{ + AVFrame *cur = NULL; + const int subframesize = s->avctx->frame_size; + int subframes = OPUS_BLOCK_SIZE(s->packet.framesize) / subframesize; + + cur = ff_bufqueue_get(&s->bufqueue); + + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *b = &f->block[ch]; + const void *input = cur->extended_data[ch]; + size_t bps = av_get_bytes_per_sample(cur->format); + memcpy(b->overlap, input, bps*cur->nb_samples); + } + + av_frame_free(&cur); + + for (int sf = 0; sf < subframes; sf++) { + if (sf != (subframes - 1)) + cur = ff_bufqueue_get(&s->bufqueue); + else + cur = ff_bufqueue_peek(&s->bufqueue, 0); + + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *b = &f->block[ch]; + const void *input = cur->extended_data[ch]; + const size_t bps = av_get_bytes_per_sample(cur->format); + const size_t left = (subframesize - cur->nb_samples)*bps; + const size_t len = FFMIN(subframesize, cur->nb_samples)*bps; + memcpy(&b->samples[sf*subframesize], input, len); + memset(&b->samples[cur->nb_samples], 0, left); + } + + /* Last frame isn't popped off and freed yet - we need it for overlap */ + if (sf != (subframes - 1)) + av_frame_free(&cur); + } +} + +/* Apply the pre emphasis filter */ +static void celt_apply_preemph_filter(OpusEncContext *s, CeltFrame *f) +{ + const int subframesize = s->avctx->frame_size; + const int subframes = OPUS_BLOCK_SIZE(s->packet.framesize) / subframesize; + + /* Filter overlap */ + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *b = &f->block[ch]; + float m = b->emph_coeff; + for (int i = 0; i < CELT_OVERLAP; i++) { + float sample = b->overlap[i]; + b->overlap[i] = sample - m; + m = sample * CELT_EMPH_COEFF; + } + b->emph_coeff = m; + } + + /* Filter the samples but do not update the last subframe's coeff - overlap ^^^ */ + for (int sf = 0; sf < subframes; sf++) { + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *b = &f->block[ch]; + float m = b->emph_coeff; + for (int i = 0; i < subframesize; i++) { + float sample = b->samples[sf*subframesize + i]; + b->samples[sf*subframesize + i] = sample - m; + m = sample * CELT_EMPH_COEFF; + } + if (sf != (subframes - 1)) + b->emph_coeff = m; + } + } +} + +/* Create the window and do the mdct */ +static void celt_frame_mdct(OpusEncContext *s, CeltFrame *f) +{ + float *win = s->scratch, *temp = s->scratch + 1920; + + if (f->transient) { + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *b = &f->block[ch]; + float *src1 = b->overlap; + for (int t = 0; t < f->blocks; t++) { + float *src2 = &b->samples[CELT_OVERLAP*t]; + s->dsp->vector_fmul(win, src1, ff_celt_window, 128); + s->dsp->vector_fmul_reverse(&win[CELT_OVERLAP], src2, + ff_celt_window - 8, 128); + src1 = src2; + s->mdct[0]->mdct(s->mdct[0], b->coeffs + t, win, f->blocks); + } + } + } else { + int blk_len = OPUS_BLOCK_SIZE(f->size), wlen = OPUS_BLOCK_SIZE(f->size + 1); + int rwin = blk_len - CELT_OVERLAP, lap_dst = (wlen - blk_len - CELT_OVERLAP) >> 1; + memset(win, 0, wlen*sizeof(float)); + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *b = &f->block[ch]; + + /* Overlap */ + s->dsp->vector_fmul(temp, b->overlap, ff_celt_window, 128); + memcpy(win + lap_dst, temp, CELT_OVERLAP*sizeof(float)); + + /* Samples, flat top window */ + memcpy(&win[lap_dst + CELT_OVERLAP], b->samples, rwin*sizeof(float)); + + /* Samples, windowed */ + s->dsp->vector_fmul_reverse(temp, b->samples + rwin, + ff_celt_window - 8, 128); + memcpy(win + lap_dst + blk_len, temp, CELT_OVERLAP*sizeof(float)); + + s->mdct[f->size]->mdct(s->mdct[f->size], b->coeffs, win, 1); + } + } + + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *block = &f->block[ch]; + for (int i = 0; i < CELT_MAX_BANDS; i++) { + float ener = 0.0f; + int band_offset = ff_celt_freq_bands[i] << f->size; + int band_size = ff_celt_freq_range[i] << f->size; + float *coeffs = &block->coeffs[band_offset]; + + for (int j = 0; j < band_size; j++) + ener += coeffs[j]*coeffs[j]; + + block->lin_energy[i] = sqrtf(ener) + FLT_EPSILON; + ener = 1.0f/block->lin_energy[i]; + + for (int j = 0; j < band_size; j++) + coeffs[j] *= ener; + + block->energy[i] = log2f(block->lin_energy[i]) - ff_celt_mean_energy[i]; + + /* CELT_ENERGY_SILENCE is what the decoder uses and its not -infinity */ + block->energy[i] = FFMAX(block->energy[i], CELT_ENERGY_SILENCE); + } + } +} + +static void celt_enc_tf(CeltFrame *f, OpusRangeCoder *rc) +{ + int tf_select = 0, diff = 0, tf_changed = 0, tf_select_needed; + int bits = f->transient ? 2 : 4; + + tf_select_needed = ((f->size && (opus_rc_tell(rc) + bits + 1) <= f->framebits)); + + for (int i = f->start_band; i < f->end_band; i++) { + if ((opus_rc_tell(rc) + bits + tf_select_needed) <= f->framebits) { + const int tbit = (diff ^ 1) == f->tf_change[i]; + ff_opus_rc_enc_log(rc, tbit, bits); + diff ^= tbit; + tf_changed |= diff; + } + bits = f->transient ? 4 : 5; + } + + if (tf_select_needed && ff_celt_tf_select[f->size][f->transient][0][tf_changed] != + ff_celt_tf_select[f->size][f->transient][1][tf_changed]) { + ff_opus_rc_enc_log(rc, f->tf_select, 1); + tf_select = f->tf_select; + } + + for (int i = f->start_band; i < f->end_band; i++) + f->tf_change[i] = ff_celt_tf_select[f->size][f->transient][tf_select][f->tf_change[i]]; +} + +static void celt_enc_quant_pfilter(OpusRangeCoder *rc, CeltFrame *f) +{ + float gain = f->pf_gain; + int txval, octave = f->pf_octave, period = f->pf_period, tapset = f->pf_tapset; + + ff_opus_rc_enc_log(rc, f->pfilter, 1); + if (!f->pfilter) + return; + + /* Octave */ + txval = FFMIN(octave, 6); + ff_opus_rc_enc_uint(rc, txval, 6); + octave = txval; + /* Period */ + txval = av_clip(period - (16 << octave) + 1, 0, (1 << (4 + octave)) - 1); + ff_opus_rc_put_raw(rc, period, 4 + octave); + period = txval + (16 << octave) - 1; + /* Gain */ + txval = FFMIN(((int)(gain / 0.09375f)) - 1, 7); + ff_opus_rc_put_raw(rc, txval, 3); + gain = 0.09375f * (txval + 1); + /* Tapset */ + if ((opus_rc_tell(rc) + 2) <= f->framebits) + ff_opus_rc_enc_cdf(rc, tapset, ff_celt_model_tapset); + else + tapset = 0; + /* Finally create the coeffs */ + for (int i = 0; i < 2; i++) { + CeltBlock *block = &f->block[i]; + + block->pf_period_new = FFMAX(period, CELT_POSTFILTER_MINPERIOD); + block->pf_gains_new[0] = gain * ff_celt_postfilter_taps[tapset][0]; + block->pf_gains_new[1] = gain * ff_celt_postfilter_taps[tapset][1]; + block->pf_gains_new[2] = gain * ff_celt_postfilter_taps[tapset][2]; + } +} + +static void exp_quant_coarse(OpusRangeCoder *rc, CeltFrame *f, + float last_energy[][CELT_MAX_BANDS], int intra) +{ + float alpha, beta, prev[2] = { 0, 0 }; + const uint8_t *pmod = ff_celt_coarse_energy_dist[f->size][intra]; + + /* Inter is really just differential coding */ + if (opus_rc_tell(rc) + 3 <= f->framebits) + ff_opus_rc_enc_log(rc, intra, 3); + else + intra = 0; + + if (intra) { + alpha = 0.0f; + beta = 1.0f - (4915.0f/32768.0f); + } else { + alpha = ff_celt_alpha_coef[f->size]; + beta = ff_celt_beta_coef[f->size]; + } + + for (int i = f->start_band; i < f->end_band; i++) { + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *block = &f->block[ch]; + const int left = f->framebits - opus_rc_tell(rc); + const float last = FFMAX(-9.0f, last_energy[ch][i]); + float diff = block->energy[i] - prev[ch] - last*alpha; + int q_en = lrintf(diff); + if (left >= 15) { + ff_opus_rc_enc_laplace(rc, &q_en, pmod[i << 1] << 7, pmod[(i << 1) + 1] << 6); + } else if (left >= 2) { + q_en = av_clip(q_en, -1, 1); + ff_opus_rc_enc_cdf(rc, 2*q_en + 3*(q_en < 0), ff_celt_model_energy_small); + } else if (left >= 1) { + q_en = av_clip(q_en, -1, 0); + ff_opus_rc_enc_log(rc, (q_en & 1), 1); + } else q_en = -1; + + block->error_energy[i] = q_en - diff; + prev[ch] += beta * q_en; + } + } +} + +static void celt_quant_coarse(CeltFrame *f, OpusRangeCoder *rc, + float last_energy[][CELT_MAX_BANDS]) +{ + uint32_t inter, intra; + OPUS_RC_CHECKPOINT_SPAWN(rc); + + exp_quant_coarse(rc, f, last_energy, 1); + intra = OPUS_RC_CHECKPOINT_BITS(rc); + + OPUS_RC_CHECKPOINT_ROLLBACK(rc); + + exp_quant_coarse(rc, f, last_energy, 0); + inter = OPUS_RC_CHECKPOINT_BITS(rc); + + if (inter > intra) { /* Unlikely */ + OPUS_RC_CHECKPOINT_ROLLBACK(rc); + exp_quant_coarse(rc, f, last_energy, 1); + } +} + +static void celt_quant_fine(CeltFrame *f, OpusRangeCoder *rc) +{ + for (int i = f->start_band; i < f->end_band; i++) { + if (!f->fine_bits[i]) + continue; + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *block = &f->block[ch]; + int quant, lim = (1 << f->fine_bits[i]); + float offset, diff = 0.5f - block->error_energy[i]; + quant = av_clip(floor(diff*lim), 0, lim - 1); + ff_opus_rc_put_raw(rc, quant, f->fine_bits[i]); + offset = 0.5f - ((quant + 0.5f) * (1 << (14 - f->fine_bits[i])) / 16384.0f); + block->error_energy[i] -= offset; + } + } +} + +static void celt_quant_final(OpusEncContext *s, OpusRangeCoder *rc, CeltFrame *f) +{ + for (int priority = 0; priority < 2; priority++) { + for (int i = f->start_band; i < f->end_band && (f->framebits - opus_rc_tell(rc)) >= f->channels; i++) { + if (f->fine_priority[i] != priority || f->fine_bits[i] >= CELT_MAX_FINE_BITS) + continue; + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *block = &f->block[ch]; + const float err = block->error_energy[i]; + const float offset = 0.5f * (1 << (14 - f->fine_bits[i] - 1)) / 16384.0f; + const int sign = FFABS(err + offset) < FFABS(err - offset); + ff_opus_rc_put_raw(rc, sign, 1); + block->error_energy[i] -= offset*(1 - 2*sign); + } + } + } +} + +static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc, + CeltFrame *f, int index) +{ + ff_opus_rc_enc_init(rc); + + ff_opus_psy_celt_frame_init(&s->psyctx, f, index); + + celt_frame_setup_input(s, f); + + if (f->silence) { + if (f->framebits >= 16) + ff_opus_rc_enc_log(rc, 1, 15); /* Silence (if using explicit singalling) */ + for (int ch = 0; ch < s->channels; ch++) + memset(s->last_quantized_energy[ch], 0.0f, sizeof(float)*CELT_MAX_BANDS); + return; + } + + /* Filters */ + celt_apply_preemph_filter(s, f); + if (f->pfilter) { + ff_opus_rc_enc_log(rc, 0, 15); + celt_enc_quant_pfilter(rc, f); + } + + /* Transform */ + celt_frame_mdct(s, f); + + /* Need to handle transient/non-transient switches at any point during analysis */ + while (ff_opus_psy_celt_frame_process(&s->psyctx, f, index)) + celt_frame_mdct(s, f); + + ff_opus_rc_enc_init(rc); + + /* Silence */ + ff_opus_rc_enc_log(rc, 0, 15); + + /* Pitch filter */ + if (!f->start_band && opus_rc_tell(rc) + 16 <= f->framebits) + celt_enc_quant_pfilter(rc, f); + + /* Transient flag */ + if (f->size && opus_rc_tell(rc) + 3 <= f->framebits) + ff_opus_rc_enc_log(rc, f->transient, 3); + + /* Main encoding */ + celt_quant_coarse (f, rc, s->last_quantized_energy); + celt_enc_tf (f, rc); + ff_celt_bitalloc (f, rc, 1); + celt_quant_fine (f, rc); + ff_celt_quant_bands(f, rc); + + /* Anticollapse bit */ + if (f->anticollapse_needed) + ff_opus_rc_put_raw(rc, f->anticollapse, 1); + + /* Final per-band energy adjustments from leftover bits */ + celt_quant_final(s, rc, f); + + for (int ch = 0; ch < f->channels; ch++) { + CeltBlock *block = &f->block[ch]; + for (int i = 0; i < CELT_MAX_BANDS; i++) + s->last_quantized_energy[ch][i] = block->energy[i] + block->error_energy[i]; + } +} + +static inline int write_opuslacing(uint8_t *dst, int v) +{ + dst[0] = FFMIN(v - FFALIGN(v - 255, 4), v); + dst[1] = v - dst[0] >> 2; + return 1 + (v >= 252); +} + +static void opus_packet_assembler(OpusEncContext *s, AVPacket *avpkt) +{ + int offset, fsize_needed; + + /* Write toc */ + opus_gen_toc(s, avpkt->data, &offset, &fsize_needed); + + /* Frame sizes if needed */ + if (fsize_needed) { + for (int i = 0; i < s->packet.frames - 1; i++) { + offset += write_opuslacing(avpkt->data + offset, + s->frame[i].framebits >> 3); + } + } + + /* Packets */ + for (int i = 0; i < s->packet.frames; i++) { + ff_opus_rc_enc_end(&s->rc[i], avpkt->data + offset, + s->frame[i].framebits >> 3); + offset += s->frame[i].framebits >> 3; + } + + avpkt->size = offset; +} + +/* Used as overlap for the first frame and padding for the last encoded packet */ +static AVFrame *spawn_empty_frame(OpusEncContext *s) +{ + AVFrame *f = av_frame_alloc(); + if (!f) + return NULL; + f->format = s->avctx->sample_fmt; + f->nb_samples = s->avctx->frame_size; + f->channel_layout = s->avctx->channel_layout; + if (av_frame_get_buffer(f, 4)) { + av_frame_free(&f); + return NULL; + } + for (int i = 0; i < s->channels; i++) { + size_t bps = av_get_bytes_per_sample(f->format); + memset(f->extended_data[i], 0, bps*f->nb_samples); + } + return f; +} + +static int opus_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + OpusEncContext *s = avctx->priv_data; + int ret, frame_size, alloc_size = 0; + + if (frame) { /* Add new frame to queue */ + if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) + return ret; + ff_bufqueue_add(avctx, &s->bufqueue, av_frame_clone(frame)); + } else { + ff_opus_psy_signal_eof(&s->psyctx); + if (!s->afq.remaining_samples || !avctx->frame_number) + return 0; /* We've been flushed and there's nothing left to encode */ + } + + /* Run the psychoacoustic system */ + if (ff_opus_psy_process(&s->psyctx, &s->packet)) + return 0; + + frame_size = OPUS_BLOCK_SIZE(s->packet.framesize); + + if (!frame) { + /* This can go negative, that's not a problem, we only pad if positive */ + int pad_empty = s->packet.frames*(frame_size/s->avctx->frame_size) - s->bufqueue.available + 1; + /* Pad with empty 2.5 ms frames to whatever framesize was decided, + * this should only happen at the very last flush frame. The frames + * allocated here will be freed (because they have no other references) + * after they get used by celt_frame_setup_input() */ + for (int i = 0; i < pad_empty; i++) { + AVFrame *empty = spawn_empty_frame(s); + if (!empty) + return AVERROR(ENOMEM); + ff_bufqueue_add(avctx, &s->bufqueue, empty); + } + } + + for (int i = 0; i < s->packet.frames; i++) { + celt_encode_frame(s, &s->rc[i], &s->frame[i], i); + alloc_size += s->frame[i].framebits >> 3; + } + + /* Worst case toc + the frame lengths if needed */ + alloc_size += 2 + s->packet.frames*2; + + if ((ret = ff_alloc_packet2(avctx, avpkt, alloc_size, 0)) < 0) + return ret; + + /* Assemble packet */ + opus_packet_assembler(s, avpkt); + + /* Update the psychoacoustic system */ + ff_opus_psy_postencode_update(&s->psyctx, s->frame, s->rc); + + /* Remove samples from queue and skip if needed */ + ff_af_queue_remove(&s->afq, s->packet.frames*frame_size, &avpkt->pts, &avpkt->duration); + if (s->packet.frames*frame_size > avpkt->duration) { + uint8_t *side = av_packet_new_side_data(avpkt, AV_PKT_DATA_SKIP_SAMPLES, 10); + if (!side) + return AVERROR(ENOMEM); + AV_WL32(&side[4], s->packet.frames*frame_size - avpkt->duration + 120); + } + + *got_packet_ptr = 1; + + return 0; +} + +static av_cold int opus_encode_end(AVCodecContext *avctx) +{ + OpusEncContext *s = avctx->priv_data; + + for (int i = 0; i < CELT_BLOCK_NB; i++) + ff_mdct15_uninit(&s->mdct[i]); + + ff_celt_pvq_uninit(&s->pvq); + av_freep(&s->dsp); + av_freep(&s->frame); + av_freep(&s->rc); + ff_af_queue_close(&s->afq); + ff_opus_psy_end(&s->psyctx); + ff_bufqueue_discard_all(&s->bufqueue); + av_freep(&avctx->extradata); + + return 0; +} + +static av_cold int opus_encode_init(AVCodecContext *avctx) +{ + int ret, max_frames; + OpusEncContext *s = avctx->priv_data; + + s->avctx = avctx; + s->channels = avctx->channels; + + /* Opus allows us to change the framesize on each packet (and each packet may + * have multiple frames in it) but we can't change the codec's frame size on + * runtime, so fix it to the lowest possible number of samples and use a queue + * to accumulate AVFrames until we have enough to encode whatever the encoder + * decides is the best */ + avctx->frame_size = 120; + /* Initial padding will change if SILK is ever supported */ + avctx->initial_padding = 120; + + if (!avctx->bit_rate) { + int coupled = ff_opus_default_coupled_streams[s->channels - 1]; + avctx->bit_rate = coupled*(96000) + (s->channels - coupled*2)*(48000); + } else if (avctx->bit_rate < 6000 || avctx->bit_rate > 255000 * s->channels) { + int64_t clipped_rate = av_clip(avctx->bit_rate, 6000, 255000 * s->channels); + av_log(avctx, AV_LOG_ERROR, "Unsupported bitrate %"PRId64" kbps, clipping to %"PRId64" kbps\n", + avctx->bit_rate/1000, clipped_rate/1000); + avctx->bit_rate = clipped_rate; + } + + /* Extradata */ + avctx->extradata_size = 19; + avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) + return AVERROR(ENOMEM); + opus_write_extradata(avctx); + + ff_af_queue_init(avctx, &s->afq); + + if ((ret = ff_celt_pvq_init(&s->pvq, 1)) < 0) + return ret; + + if (!(s->dsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT))) + return AVERROR(ENOMEM); + + /* I have no idea why a base scaling factor of 68 works, could be the twiddles */ + for (int i = 0; i < CELT_BLOCK_NB; i++) + if ((ret = ff_mdct15_init(&s->mdct[i], 0, i + 3, 68 << (CELT_BLOCK_NB - 1 - i)))) + return AVERROR(ENOMEM); + + /* Zero out previous energy (matters for inter first frame) */ + for (int ch = 0; ch < s->channels; ch++) + memset(s->last_quantized_energy[ch], 0.0f, sizeof(float)*CELT_MAX_BANDS); + + /* Allocate an empty frame to use as overlap for the first frame of audio */ + ff_bufqueue_add(avctx, &s->bufqueue, spawn_empty_frame(s)); + if (!ff_bufqueue_peek(&s->bufqueue, 0)) + return AVERROR(ENOMEM); + + if ((ret = ff_opus_psy_init(&s->psyctx, s->avctx, &s->bufqueue, &s->options))) + return ret; + + /* Frame structs and range coder buffers */ + max_frames = ceilf(FFMIN(s->options.max_delay_ms, 120.0f)/2.5f); + s->frame = av_malloc(max_frames*sizeof(CeltFrame)); + if (!s->frame) + return AVERROR(ENOMEM); + s->rc = av_malloc(max_frames*sizeof(OpusRangeCoder)); + if (!s->rc) + return AVERROR(ENOMEM); + + for (int i = 0; i < max_frames; i++) { + s->frame[i].dsp = s->dsp; + s->frame[i].avctx = s->avctx; + s->frame[i].seed = 0; + s->frame[i].pvq = s->pvq; + s->frame[i].apply_phase_inv = 1; + s->frame[i].block[0].emph_coeff = s->frame[i].block[1].emph_coeff = 0.0f; + } + + return 0; +} + +#define OPUSENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM +static const AVOption opusenc_options[] = { + { "opus_delay", "Maximum delay in milliseconds", offsetof(OpusEncContext, options.max_delay_ms), AV_OPT_TYPE_FLOAT, { .dbl = OPUS_MAX_LOOKAHEAD }, 2.5f, OPUS_MAX_LOOKAHEAD, OPUSENC_FLAGS, "max_delay_ms" }, + { NULL }, +}; + +static const AVClass opusenc_class = { + .class_name = "Opus encoder", + .item_name = av_default_item_name, + .option = opusenc_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVCodecDefault opusenc_defaults[] = { + { "b", "0" }, + { "compression_level", "10" }, + { NULL }, +}; + +AVCodec ff_opus_encoder = { + .name = "opus", + .long_name = NULL_IF_CONFIG_SMALL("Opus"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_OPUS, + .defaults = opusenc_defaults, + .priv_class = &opusenc_class, + .priv_data_size = sizeof(OpusEncContext), + .init = opus_encode_init, + .encode2 = opus_encode_frame, + .close = opus_encode_end, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .capabilities = AV_CODEC_CAP_EXPERIMENTAL | AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY, + .supported_samplerates = (const int []){ 48000, 0 }, + .channel_layouts = (const uint64_t []){ AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, 0 }, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_NONE }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc.h new file mode 100644 index 0000000000..b9162ebec6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc.h @@ -0,0 +1,54 @@ +/* + * Opus encoder + * Copyright (c) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPUSENC_H +#define AVCODEC_OPUSENC_H + +#include "internal.h" +#include "opus_celt.h" + +/* Determines the maximum delay the psychoacoustic system will use for lookahead */ +#define FF_BUFQUEUE_SIZE 145 +#include "libavfilter/bufferqueue.h" + +#define OPUS_MAX_LOOKAHEAD ((FF_BUFQUEUE_SIZE - 1)*2.5f) + +#define OPUS_MAX_CHANNELS 2 + +/* 120 ms / 2.5 ms = 48 frames (extremely improbable, but the encoder'll work) */ +#define OPUS_MAX_FRAMES_PER_PACKET 48 + +#define OPUS_BLOCK_SIZE(x) (2 * 15 * (1 << ((x) + 2))) + +#define OPUS_SAMPLES_TO_BLOCK_SIZE(x) (ff_log2((x) / (2 * 15)) - 2) + +typedef struct OpusEncOptions { + float max_delay_ms; +} OpusEncOptions; + +typedef struct OpusPacketInfo { + enum OpusMode mode; + enum OpusBandwidth bandwidth; + int framesize; + int frames; +} OpusPacketInfo; + +#endif /* AVCODEC_OPUSENC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_psy.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_psy.c new file mode 100644 index 0000000000..5a50db942f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_psy.c @@ -0,0 +1,612 @@ +/* + * Opus encoder + * Copyright (c) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "opusenc_psy.h" +#include "opus_pvq.h" +#include "opustab.h" +#include "mdct15.h" +#include "libavutil/qsort.h" + +static float pvq_band_cost(CeltPVQ *pvq, CeltFrame *f, OpusRangeCoder *rc, int band, + float *bits, float lambda) +{ + int i, b = 0; + uint32_t cm[2] = { (1 << f->blocks) - 1, (1 << f->blocks) - 1 }; + const int band_size = ff_celt_freq_range[band] << f->size; + float buf[176 * 2], lowband_scratch[176], norm1[176], norm2[176]; + float dist, cost, err_x = 0.0f, err_y = 0.0f; + float *X = buf; + float *X_orig = f->block[0].coeffs + (ff_celt_freq_bands[band] << f->size); + float *Y = (f->channels == 2) ? &buf[176] : NULL; + float *Y_orig = f->block[1].coeffs + (ff_celt_freq_bands[band] << f->size); + OPUS_RC_CHECKPOINT_SPAWN(rc); + + memcpy(X, X_orig, band_size*sizeof(float)); + if (Y) + memcpy(Y, Y_orig, band_size*sizeof(float)); + + f->remaining2 = ((f->framebits << 3) - f->anticollapse_needed) - opus_rc_tell_frac(rc) - 1; + if (band <= f->coded_bands - 1) { + int curr_balance = f->remaining / FFMIN(3, f->coded_bands - band); + b = av_clip_uintp2(FFMIN(f->remaining2 + 1, f->pulses[band] + curr_balance), 14); + } + + if (f->dual_stereo) { + pvq->quant_band(pvq, f, rc, band, X, NULL, band_size, b / 2, f->blocks, NULL, + f->size, norm1, 0, 1.0f, lowband_scratch, cm[0]); + + pvq->quant_band(pvq, f, rc, band, Y, NULL, band_size, b / 2, f->blocks, NULL, + f->size, norm2, 0, 1.0f, lowband_scratch, cm[1]); + } else { + pvq->quant_band(pvq, f, rc, band, X, Y, band_size, b, f->blocks, NULL, f->size, + norm1, 0, 1.0f, lowband_scratch, cm[0] | cm[1]); + } + + for (i = 0; i < band_size; i++) { + err_x += (X[i] - X_orig[i])*(X[i] - X_orig[i]); + if (Y) + err_y += (Y[i] - Y_orig[i])*(Y[i] - Y_orig[i]); + } + + dist = sqrtf(err_x) + sqrtf(err_y); + cost = OPUS_RC_CHECKPOINT_BITS(rc)/8.0f; + *bits += cost; + + OPUS_RC_CHECKPOINT_ROLLBACK(rc); + + return lambda*dist*cost; +} + +/* Populate metrics without taking into consideration neighbouring steps */ +static void step_collect_psy_metrics(OpusPsyContext *s, int index) +{ + int silence = 0, ch, i, j; + OpusPsyStep *st = s->steps[index]; + + st->index = index; + + for (ch = 0; ch < s->avctx->channels; ch++) { + const int lap_size = (1 << s->bsize_analysis); + for (i = 1; i <= FFMIN(lap_size, index); i++) { + const int offset = i*120; + AVFrame *cur = ff_bufqueue_peek(s->bufqueue, index - i); + memcpy(&s->scratch[offset], cur->extended_data[ch], cur->nb_samples*sizeof(float)); + } + for (i = 0; i < lap_size; i++) { + const int offset = i*120 + lap_size; + AVFrame *cur = ff_bufqueue_peek(s->bufqueue, index + i); + memcpy(&s->scratch[offset], cur->extended_data[ch], cur->nb_samples*sizeof(float)); + } + + s->dsp->vector_fmul(s->scratch, s->scratch, s->window[s->bsize_analysis], + (OPUS_BLOCK_SIZE(s->bsize_analysis) << 1)); + + s->mdct[s->bsize_analysis]->mdct(s->mdct[s->bsize_analysis], st->coeffs[ch], s->scratch, 1); + + for (i = 0; i < CELT_MAX_BANDS; i++) + st->bands[ch][i] = &st->coeffs[ch][ff_celt_freq_bands[i] << s->bsize_analysis]; + } + + for (ch = 0; ch < s->avctx->channels; ch++) { + for (i = 0; i < CELT_MAX_BANDS; i++) { + float avg_c_s, energy = 0.0f, dist_dev = 0.0f; + const int range = ff_celt_freq_range[i] << s->bsize_analysis; + const float *coeffs = st->bands[ch][i]; + for (j = 0; j < range; j++) + energy += coeffs[j]*coeffs[j]; + + st->energy[ch][i] += sqrtf(energy); + silence |= !!st->energy[ch][i]; + avg_c_s = energy / range; + + for (j = 0; j < range; j++) { + const float c_s = coeffs[j]*coeffs[j]; + dist_dev += (avg_c_s - c_s)*(avg_c_s - c_s); + } + + st->tone[ch][i] += sqrtf(dist_dev); + } + } + + st->silence = !silence; + + if (s->avctx->channels > 1) { + for (i = 0; i < CELT_MAX_BANDS; i++) { + float incompat = 0.0f; + const float *coeffs1 = st->bands[0][i]; + const float *coeffs2 = st->bands[1][i]; + const int range = ff_celt_freq_range[i] << s->bsize_analysis; + for (j = 0; j < range; j++) + incompat += (coeffs1[j] - coeffs2[j])*(coeffs1[j] - coeffs2[j]); + st->stereo[i] = sqrtf(incompat); + } + } + + for (ch = 0; ch < s->avctx->channels; ch++) { + for (i = 0; i < CELT_MAX_BANDS; i++) { + OpusBandExcitation *ex = &s->ex[ch][i]; + float bp_e = bessel_filter(&s->bfilter_lo[ch][i], st->energy[ch][i]); + bp_e = bessel_filter(&s->bfilter_hi[ch][i], bp_e); + bp_e *= bp_e; + if (bp_e > ex->excitation) { + st->change_amp[ch][i] = bp_e - ex->excitation; + st->total_change += st->change_amp[ch][i]; + ex->excitation = ex->excitation_init = bp_e; + ex->excitation_dist = 0.0f; + } + if (ex->excitation > 0.0f) { + ex->excitation -= av_clipf((1/expf(ex->excitation_dist)), ex->excitation_init/20, ex->excitation_init/1.09); + ex->excitation = FFMAX(ex->excitation, 0.0f); + ex->excitation_dist += 1.0f; + } + } + } +} + +static void search_for_change_points(OpusPsyContext *s, float tgt_change, + int offset_s, int offset_e, int resolution, + int level) +{ + int i; + float c_change = 0.0f; + if ((offset_e - offset_s) <= resolution) + return; + for (i = offset_s; i < offset_e; i++) { + c_change += s->steps[i]->total_change; + if (c_change > tgt_change) + break; + } + if (i == offset_e) + return; + search_for_change_points(s, tgt_change / 2.0f, offset_s, i + 0, resolution, level + 1); + s->inflection_points[s->inflection_points_count++] = i; + search_for_change_points(s, tgt_change / 2.0f, i + 1, offset_e, resolution, level + 1); +} + +static int flush_silent_frames(OpusPsyContext *s) +{ + int fsize, silent_frames; + + for (silent_frames = 0; silent_frames < s->buffered_steps; silent_frames++) + if (!s->steps[silent_frames]->silence) + break; + if (--silent_frames < 0) + return 0; + + for (fsize = CELT_BLOCK_960; fsize > CELT_BLOCK_120; fsize--) { + if ((1 << fsize) > silent_frames) + continue; + s->p.frames = FFMIN(silent_frames / (1 << fsize), 48 >> fsize); + s->p.framesize = fsize; + return 1; + } + + return 0; +} + +/* Main function which decides frame size and frames per current packet */ +static void psy_output_groups(OpusPsyContext *s) +{ + int max_delay_samples = (s->options->max_delay_ms*s->avctx->sample_rate)/1000; + int max_bsize = FFMIN(OPUS_SAMPLES_TO_BLOCK_SIZE(max_delay_samples), CELT_BLOCK_960); + + /* These don't change for now */ + s->p.mode = OPUS_MODE_CELT; + s->p.bandwidth = OPUS_BANDWIDTH_FULLBAND; + + /* Flush silent frames ASAP */ + if (s->steps[0]->silence && flush_silent_frames(s)) + return; + + s->p.framesize = FFMIN(max_bsize, CELT_BLOCK_960); + s->p.frames = 1; +} + +int ff_opus_psy_process(OpusPsyContext *s, OpusPacketInfo *p) +{ + int i; + float total_energy_change = 0.0f; + + if (s->buffered_steps < s->max_steps && !s->eof) { + const int awin = (1 << s->bsize_analysis); + if (++s->steps_to_process >= awin) { + step_collect_psy_metrics(s, s->buffered_steps - awin + 1); + s->steps_to_process = 0; + } + if ((++s->buffered_steps) < s->max_steps) + return 1; + } + + for (i = 0; i < s->buffered_steps; i++) + total_energy_change += s->steps[i]->total_change; + + search_for_change_points(s, total_energy_change / 2.0f, 0, + s->buffered_steps, 1, 0); + + psy_output_groups(s); + + p->frames = s->p.frames; + p->framesize = s->p.framesize; + p->mode = s->p.mode; + p->bandwidth = s->p.bandwidth; + + return 0; +} + +void ff_opus_psy_celt_frame_init(OpusPsyContext *s, CeltFrame *f, int index) +{ + int i, neighbouring_points = 0, start_offset = 0; + int radius = (1 << s->p.framesize), step_offset = radius*index; + int silence = 1; + + f->start_band = (s->p.mode == OPUS_MODE_HYBRID) ? 17 : 0; + f->end_band = ff_celt_band_end[s->p.bandwidth]; + f->channels = s->avctx->channels; + f->size = s->p.framesize; + + for (i = 0; i < (1 << f->size); i++) + silence &= s->steps[index*(1 << f->size) + i]->silence; + + f->silence = silence; + if (f->silence) { + f->framebits = 0; /* Otherwise the silence flag eats up 16(!) bits */ + return; + } + + for (i = 0; i < s->inflection_points_count; i++) { + if (s->inflection_points[i] >= step_offset) { + start_offset = i; + break; + } + } + + for (i = start_offset; i < FFMIN(radius, s->inflection_points_count - start_offset); i++) { + if (s->inflection_points[i] < (step_offset + radius)) { + neighbouring_points++; + } + } + + /* Transient flagging */ + f->transient = neighbouring_points > 0; + f->blocks = f->transient ? OPUS_BLOCK_SIZE(s->p.framesize)/CELT_OVERLAP : 1; + + /* Some sane defaults */ + f->pfilter = 0; + f->pf_gain = 0.5f; + f->pf_octave = 2; + f->pf_period = 1; + f->pf_tapset = 2; + + /* More sane defaults */ + f->tf_select = 0; + f->anticollapse = 1; + f->alloc_trim = 5; + f->skip_band_floor = f->end_band; + f->intensity_stereo = f->end_band; + f->dual_stereo = 0; + f->spread = CELT_SPREAD_NORMAL; + memset(f->tf_change, 0, sizeof(int)*CELT_MAX_BANDS); + memset(f->alloc_boost, 0, sizeof(int)*CELT_MAX_BANDS); +} + +static void celt_gauge_psy_weight(OpusPsyContext *s, OpusPsyStep **start, + CeltFrame *f_out) +{ + int i, f, ch; + int frame_size = OPUS_BLOCK_SIZE(s->p.framesize); + float rate, frame_bits = 0; + + /* Used for the global ROTATE flag */ + float tonal = 0.0f; + + /* Pseudo-weights */ + float band_score[CELT_MAX_BANDS] = { 0 }; + float max_score = 1.0f; + + /* Pass one - one loop around each band, computing unquant stuff */ + for (i = 0; i < CELT_MAX_BANDS; i++) { + float weight = 0.0f; + float tonal_contrib = 0.0f; + for (f = 0; f < (1 << s->p.framesize); f++) { + weight = start[f]->stereo[i]; + for (ch = 0; ch < s->avctx->channels; ch++) { + weight += start[f]->change_amp[ch][i] + start[f]->tone[ch][i] + start[f]->energy[ch][i]; + tonal_contrib += start[f]->tone[ch][i]; + } + } + tonal += tonal_contrib; + band_score[i] = weight; + } + + tonal /= (float)CELT_MAX_BANDS; + + for (i = 0; i < CELT_MAX_BANDS; i++) { + if (band_score[i] > max_score) + max_score = band_score[i]; + } + + for (i = 0; i < CELT_MAX_BANDS; i++) { + f_out->alloc_boost[i] = (int)((band_score[i]/max_score)*3.0f); + frame_bits += band_score[i]*8.0f; + } + + tonal /= 1333136.0f; + f_out->spread = av_clip_uintp2(lrintf(tonal), 2); + + rate = ((float)s->avctx->bit_rate) + frame_bits*frame_size*16; + rate *= s->lambda; + rate /= s->avctx->sample_rate/frame_size; + + f_out->framebits = lrintf(rate); + f_out->framebits = FFMIN(f_out->framebits, OPUS_MAX_PACKET_SIZE*8); + f_out->framebits = FFALIGN(f_out->framebits, 8); +} + +static int bands_dist(OpusPsyContext *s, CeltFrame *f, float *total_dist) +{ + int i, tdist = 0.0f; + OpusRangeCoder dump; + + ff_opus_rc_enc_init(&dump); + ff_celt_bitalloc(f, &dump, 1); + + for (i = 0; i < CELT_MAX_BANDS; i++) { + float bits = 0.0f; + float dist = pvq_band_cost(f->pvq, f, &dump, i, &bits, s->lambda); + tdist += dist; + } + + *total_dist = tdist; + + return 0; +} + +static void celt_search_for_dual_stereo(OpusPsyContext *s, CeltFrame *f) +{ + float td1, td2; + f->dual_stereo = 0; + + if (s->avctx->channels < 2) + return; + + bands_dist(s, f, &td1); + f->dual_stereo = 1; + bands_dist(s, f, &td2); + + f->dual_stereo = td2 < td1; + s->dual_stereo_used += td2 < td1; +} + +static void celt_search_for_intensity(OpusPsyContext *s, CeltFrame *f) +{ + int i, best_band = CELT_MAX_BANDS - 1; + float dist, best_dist = FLT_MAX; + /* TODO: fix, make some heuristic up here using the lambda value */ + float end_band = 0; + + if (s->avctx->channels < 2) + return; + + for (i = f->end_band; i >= end_band; i--) { + f->intensity_stereo = i; + bands_dist(s, f, &dist); + if (best_dist > dist) { + best_dist = dist; + best_band = i; + } + } + + f->intensity_stereo = best_band; + s->avg_is_band = (s->avg_is_band + f->intensity_stereo)/2.0f; +} + +static int celt_search_for_tf(OpusPsyContext *s, OpusPsyStep **start, CeltFrame *f) +{ + int i, j, k, cway, config[2][CELT_MAX_BANDS] = { { 0 } }; + float score[2] = { 0 }; + + for (cway = 0; cway < 2; cway++) { + int mag[2]; + int base = f->transient ? 120 : 960; + + for (i = 0; i < 2; i++) { + int c = ff_celt_tf_select[f->size][f->transient][cway][i]; + mag[i] = c < 0 ? base >> FFABS(c) : base << FFABS(c); + } + + for (i = 0; i < CELT_MAX_BANDS; i++) { + float iscore0 = 0.0f; + float iscore1 = 0.0f; + for (j = 0; j < (1 << f->size); j++) { + for (k = 0; k < s->avctx->channels; k++) { + iscore0 += start[j]->tone[k][i]*start[j]->change_amp[k][i]/mag[0]; + iscore1 += start[j]->tone[k][i]*start[j]->change_amp[k][i]/mag[1]; + } + } + config[cway][i] = FFABS(iscore0 - 1.0f) < FFABS(iscore1 - 1.0f); + score[cway] += config[cway][i] ? iscore1 : iscore0; + } + } + + f->tf_select = score[0] < score[1]; + memcpy(f->tf_change, config[f->tf_select], sizeof(int)*CELT_MAX_BANDS); + + return 0; +} + +int ff_opus_psy_celt_frame_process(OpusPsyContext *s, CeltFrame *f, int index) +{ + int start_transient_flag = f->transient; + OpusPsyStep **start = &s->steps[index * (1 << s->p.framesize)]; + + if (f->silence) + return 0; + + celt_gauge_psy_weight(s, start, f); + celt_search_for_intensity(s, f); + celt_search_for_dual_stereo(s, f); + celt_search_for_tf(s, start, f); + + if (f->transient != start_transient_flag) { + f->blocks = f->transient ? OPUS_BLOCK_SIZE(s->p.framesize)/CELT_OVERLAP : 1; + s->redo_analysis = 1; + return 1; + } + + s->redo_analysis = 0; + + return 0; +} + +void ff_opus_psy_postencode_update(OpusPsyContext *s, CeltFrame *f, OpusRangeCoder *rc) +{ + int i, frame_size = OPUS_BLOCK_SIZE(s->p.framesize); + int steps_out = s->p.frames*(frame_size/120); + void *tmp[FF_BUFQUEUE_SIZE]; + float ideal_fbits; + + for (i = 0; i < steps_out; i++) + memset(s->steps[i], 0, sizeof(OpusPsyStep)); + + for (i = 0; i < s->max_steps; i++) + tmp[i] = s->steps[i]; + + for (i = 0; i < s->max_steps; i++) { + const int i_new = i - steps_out; + s->steps[i_new < 0 ? s->max_steps + i_new : i_new] = tmp[i]; + } + + for (i = steps_out; i < s->buffered_steps; i++) + s->steps[i]->index -= steps_out; + + ideal_fbits = s->avctx->bit_rate/(s->avctx->sample_rate/frame_size); + + for (i = 0; i < s->p.frames; i++) { + s->avg_is_band += f[i].intensity_stereo; + s->lambda *= ideal_fbits / f[i].framebits; + } + + s->avg_is_band /= (s->p.frames + 1); + + s->cs_num = 0; + s->steps_to_process = 0; + s->buffered_steps -= steps_out; + s->total_packets_out += s->p.frames; + s->inflection_points_count = 0; +} + +av_cold int ff_opus_psy_init(OpusPsyContext *s, AVCodecContext *avctx, + struct FFBufQueue *bufqueue, OpusEncOptions *options) +{ + int i, ch, ret; + + s->redo_analysis = 0; + s->lambda = 1.0f; + s->options = options; + s->avctx = avctx; + s->bufqueue = bufqueue; + s->max_steps = ceilf(s->options->max_delay_ms/2.5f); + s->bsize_analysis = CELT_BLOCK_960; + s->avg_is_band = CELT_MAX_BANDS - 1; + s->inflection_points_count = 0; + + s->inflection_points = av_mallocz(sizeof(*s->inflection_points)*s->max_steps); + if (!s->inflection_points) { + ret = AVERROR(ENOMEM); + goto fail; + } + + s->dsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); + if (!s->dsp) { + ret = AVERROR(ENOMEM); + goto fail; + } + + for (ch = 0; ch < s->avctx->channels; ch++) { + for (i = 0; i < CELT_MAX_BANDS; i++) { + bessel_init(&s->bfilter_hi[ch][i], 1.0f, 19.0f, 100.0f, 1); + bessel_init(&s->bfilter_lo[ch][i], 1.0f, 20.0f, 100.0f, 0); + } + } + + for (i = 0; i < s->max_steps; i++) { + s->steps[i] = av_mallocz(sizeof(OpusPsyStep)); + if (!s->steps[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + for (i = 0; i < CELT_BLOCK_NB; i++) { + float tmp; + const int len = OPUS_BLOCK_SIZE(i); + s->window[i] = av_malloc(2*len*sizeof(float)); + if (!s->window[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + generate_window_func(s->window[i], 2*len, WFUNC_SINE, &tmp); + if ((ret = ff_mdct15_init(&s->mdct[i], 0, i + 3, 68 << (CELT_BLOCK_NB - 1 - i)))) + goto fail; + } + + return 0; + +fail: + av_freep(&s->inflection_points); + av_freep(&s->dsp); + + for (i = 0; i < CELT_BLOCK_NB; i++) { + ff_mdct15_uninit(&s->mdct[i]); + av_freep(&s->window[i]); + } + + for (i = 0; i < s->max_steps; i++) + av_freep(&s->steps[i]); + + return ret; +} + +void ff_opus_psy_signal_eof(OpusPsyContext *s) +{ + s->eof = 1; +} + +av_cold int ff_opus_psy_end(OpusPsyContext *s) +{ + int i; + + av_freep(&s->inflection_points); + av_freep(&s->dsp); + + for (i = 0; i < CELT_BLOCK_NB; i++) { + ff_mdct15_uninit(&s->mdct[i]); + av_freep(&s->window[i]); + } + + for (i = 0; i < s->max_steps; i++) + av_freep(&s->steps[i]); + + av_log(s->avctx, AV_LOG_INFO, "Average Intensity Stereo band: %0.1f\n", s->avg_is_band); + av_log(s->avctx, AV_LOG_INFO, "Dual Stereo used: %0.2f%%\n", ((float)s->dual_stereo_used/s->total_packets_out)*100.0f); + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_psy.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_psy.h new file mode 100644 index 0000000000..b91e4f1b8b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_psy.h @@ -0,0 +1,104 @@ +/* + * Opus encoder + * Copyright (c) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPUSENC_PSY_H +#define AVCODEC_OPUSENC_PSY_H + +#include "opusenc.h" +#include "opusenc_utils.h" +#include "libavfilter/window_func.h" + +/* Each step is 2.5ms */ +typedef struct OpusPsyStep { + int index; /* Current index */ + int silence; + float energy[OPUS_MAX_CHANNELS][CELT_MAX_BANDS]; /* Masking effects included */ + float tone[OPUS_MAX_CHANNELS][CELT_MAX_BANDS]; /* Tonality */ + float stereo[CELT_MAX_BANDS]; /* IS/MS compatibility */ + float change_amp[OPUS_MAX_CHANNELS][CELT_MAX_BANDS]; /* Jump over last frame */ + float total_change; /* Total change */ + + float *bands[OPUS_MAX_CHANNELS][CELT_MAX_BANDS]; + float coeffs[OPUS_MAX_CHANNELS][OPUS_BLOCK_SIZE(CELT_BLOCK_960)]; +} OpusPsyStep; + +typedef struct OpusBandExcitation { + float excitation; + float excitation_dist; + float excitation_init; +} OpusBandExcitation; + +typedef struct PsyChain { + int start; + int end; +} PsyChain; + +typedef struct OpusPsyContext { + AVCodecContext *avctx; + AVFloatDSPContext *dsp; + struct FFBufQueue *bufqueue; + OpusEncOptions *options; + + PsyChain cs[128]; + int cs_num; + + OpusBandExcitation ex[OPUS_MAX_CHANNELS][CELT_MAX_BANDS]; + FFBesselFilter bfilter_lo[OPUS_MAX_CHANNELS][CELT_MAX_BANDS]; + FFBesselFilter bfilter_hi[OPUS_MAX_CHANNELS][CELT_MAX_BANDS]; + + OpusPsyStep *steps[FF_BUFQUEUE_SIZE + 1]; + int max_steps; + + float *window[CELT_BLOCK_NB]; + MDCT15Context *mdct[CELT_BLOCK_NB]; + int bsize_analysis; + + DECLARE_ALIGNED(32, float, scratch)[2048]; + + /* Stats */ + float rc_waste; + float avg_is_band; + int64_t dual_stereo_used; + int64_t total_packets_out; + + /* State */ + FFBesselFilter lambda_lp; + OpusPacketInfo p; + int redo_analysis; + int buffered_steps; + int steps_to_process; + int eof; + float lambda; + int *inflection_points; + int inflection_points_count; +} OpusPsyContext; + +int ff_opus_psy_process (OpusPsyContext *s, OpusPacketInfo *p); +void ff_opus_psy_celt_frame_init (OpusPsyContext *s, CeltFrame *f, int index); +int ff_opus_psy_celt_frame_process(OpusPsyContext *s, CeltFrame *f, int index); +void ff_opus_psy_postencode_update (OpusPsyContext *s, CeltFrame *f, OpusRangeCoder *rc); + +int ff_opus_psy_init(OpusPsyContext *s, AVCodecContext *avctx, + struct FFBufQueue *bufqueue, OpusEncOptions *options); +void ff_opus_psy_signal_eof(OpusPsyContext *s); +int ff_opus_psy_end(OpusPsyContext *s); + +#endif /* AVCODEC_OPUSENC_PSY_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_utils.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_utils.h new file mode 100644 index 0000000000..be82e13767 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opusenc_utils.h @@ -0,0 +1,87 @@ +/* + * Opus encoder + * Copyright (c) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPUSENC_UTILS_H +#define AVCODEC_OPUSENC_UTILS_H + +#include "opus.h" + +typedef struct FFBesselFilter { + float a[3]; + float b[2]; + float x[3]; + float y[3]; +} FFBesselFilter; + +/* Fills the coefficients, returns 1 if filter will be unstable */ +static inline int bessel_reinit(FFBesselFilter *s, float n, float f0, float fs, + int highpass) +{ + int unstable; + float c, cfreq, w0, k1, k2; + + if (!highpass) { + c = (1.0f/sqrtf(sqrtf(pow(2.0f, 1.0f/n) - 3.0f/4.0f) - 0.5f))/sqrtf(3.0f); + cfreq = c*f0/fs; + unstable = (cfreq <= 0.0f || cfreq >= 1.0f/4.0f); + } else { + c = sqrtf(3.0f)*sqrtf(sqrtf(pow(2.0f, 1.0f/n) - 3.0f/4.0f) - 0.5f); + cfreq = 0.5f - c*f0/fs; + unstable = (cfreq <= 3.0f/8.0f || cfreq >= 1.0f/2.0f); + } + + w0 = tanf(M_PI*cfreq); + k1 = 3.0f * w0; + k2 = 3.0f * w0; + + s->a[0] = k2/(1.0f + k1 + k2); + s->a[1] = 2.0f * s->a[0]; + s->a[2] = s->a[0]; + s->b[0] = 2.0f * s->a[0] * (1.0f/k2 - 1.0f); + s->b[1] = 1.0f - (s->a[0] + s->a[1] + s->a[2] + s->b[0]); + + if (highpass) { + s->a[1] *= -1; + s->b[0] *= -1; + } + + return unstable; +} + +static inline int bessel_init(FFBesselFilter *s, float n, float f0, float fs, + int highpass) +{ + memset(s, 0, sizeof(FFBesselFilter)); + return bessel_reinit(s, n, f0, fs, highpass); +} + +static inline float bessel_filter(FFBesselFilter *s, float x) +{ + s->x[2] = s->x[1]; + s->x[1] = s->x[0]; + s->x[0] = x; + s->y[2] = s->y[1]; + s->y[1] = s->y[0]; + s->y[0] = s->a[0]*s->x[0] + s->a[1]*s->x[1] + s->a[2]*s->x[2] + s->b[0]*s->y[1] + s->b[1]*s->y[2]; + return s->y[0]; +} + +#endif /* AVCODEC_OPUSENC_UTILS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opustab.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opustab.c new file mode 100644 index 0000000000..fb340e07e8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opustab.c @@ -0,0 +1,1158 @@ +/* + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * Copyright (c) 2016 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "opustab.h" + +const uint8_t ff_opus_default_coupled_streams[] = { 0, 1, 1, 2, 2, 2, 2, 3 }; + +const uint8_t ff_celt_band_end[] = { 13, 17, 17, 19, 21 }; + +const uint16_t ff_silk_model_stereo_s1[] = { + 256, 7, 9, 10, 11, 12, 22, 46, 54, 55, 56, 59, 82, 174, 197, 200, + 201, 202, 210, 234, 244, 245, 246, 247, 249, 256 +}; + +const uint16_t ff_silk_model_stereo_s2[] = {256, 85, 171, 256}; + +const uint16_t ff_silk_model_stereo_s3[] = {256, 51, 102, 154, 205, 256}; + +const uint16_t ff_silk_model_mid_only[] = {256, 192, 256}; + +const uint16_t ff_silk_model_frame_type_inactive[] = {256, 26, 256}; + +const uint16_t ff_silk_model_frame_type_active[] = {256, 24, 98, 246, 256}; + +const uint16_t ff_silk_model_gain_highbits[3][9] = { + {256, 32, 144, 212, 241, 253, 254, 255, 256}, + {256, 2, 19, 64, 124, 186, 233, 252, 256}, + {256, 1, 4, 30, 101, 195, 245, 254, 256} +}; + +const uint16_t ff_silk_model_gain_lowbits[] = {256, 32, 64, 96, 128, 160, 192, 224, 256}; + +const uint16_t ff_silk_model_gain_delta[] = { + 256, 6, 11, 22, 53, 185, 206, 214, 218, 221, 223, 225, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256 +}; +const uint16_t ff_silk_model_lsf_s1[2][2][33] = { + { + { // NB or MB, unvoiced + 256, 44, 78, 108, 127, 148, 160, 171, 174, 177, 179, 195, 197, 199, 200, 205, + 207, 208, 211, 214, 215, 216, 218, 220, 222, 225, 226, 235, 244, 246, 253, 255, 256 + }, { // NB or MB, voiced + 256, 1, 11, 12, 20, 23, 31, 39, 53, 66, 80, 81, 95, 107, 120, 131, + 142, 154, 165, 175, 185, 196, 204, 213, 221, 228, 236, 237, 238, 244, 245, 251, 256 + } + }, { + { // WB, unvoiced + 256, 31, 52, 55, 72, 73, 81, 98, 102, 103, 121, 137, 141, 143, 146, 147, + 157, 158, 161, 177, 188, 204, 206, 208, 211, 213, 224, 225, 229, 238, 246, 253, 256 + }, { // WB, voiced + 256, 1, 5, 21, 26, 44, 55, 60, 74, 89, 90, 93, 105, 118, 132, 146, + 152, 166, 178, 180, 186, 187, 199, 211, 222, 232, 235, 245, 250, 251, 252, 253, 256 + } + } +}; + +const uint16_t ff_silk_model_lsf_s2[32][10] = { + // NB, MB + { 256, 1, 2, 3, 18, 242, 253, 254, 255, 256 }, + { 256, 1, 2, 4, 38, 221, 253, 254, 255, 256 }, + { 256, 1, 2, 6, 48, 197, 252, 254, 255, 256 }, + { 256, 1, 2, 10, 62, 185, 246, 254, 255, 256 }, + { 256, 1, 4, 20, 73, 174, 248, 254, 255, 256 }, + { 256, 1, 4, 21, 76, 166, 239, 254, 255, 256 }, + { 256, 1, 8, 32, 85, 159, 226, 252, 255, 256 }, + { 256, 1, 2, 20, 83, 161, 219, 249, 255, 256 }, + + // WB + { 256, 1, 2, 3, 12, 244, 253, 254, 255, 256 }, + { 256, 1, 2, 4, 32, 218, 253, 254, 255, 256 }, + { 256, 1, 2, 5, 47, 199, 252, 254, 255, 256 }, + { 256, 1, 2, 12, 61, 187, 252, 254, 255, 256 }, + { 256, 1, 5, 24, 72, 172, 249, 254, 255, 256 }, + { 256, 1, 2, 16, 70, 170, 242, 254, 255, 256 }, + { 256, 1, 2, 17, 78, 165, 226, 251, 255, 256 }, + { 256, 1, 8, 29, 79, 156, 237, 254, 255, 256 } +}; + +const uint16_t ff_silk_model_lsf_s2_ext[] = { 256, 156, 216, 240, 249, 253, 255, 256 }; + +const uint16_t ff_silk_model_lsf_interpolation_offset[] = { 256, 13, 35, 64, 75, 256 }; + +const uint16_t ff_silk_model_pitch_highbits[] = { + 256, 3, 6, 12, 23, 44, 74, 106, 125, 136, 146, 158, 171, 184, 196, 207, + 216, 224, 231, 237, 241, 243, 245, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256 +}; + +const uint16_t ff_silk_model_pitch_lowbits_nb[] = { 256, 64, 128, 192, 256 }; + +const uint16_t ff_silk_model_pitch_lowbits_mb[] = { 256, 43, 85, 128, 171, 213, 256 }; + +const uint16_t ff_silk_model_pitch_lowbits_wb[] = { 256, 32, 64, 96, 128, 160, 192, 224, 256 }; + +const uint16_t ff_silk_model_pitch_delta[] = { + 256, 46, 48, 50, 53, 57, 63, 73, 88, 114, 152, 182, 204, 219, 229, 236, + 242, 246, 250, 252, 254, 256 +}; + +const uint16_t ff_silk_model_pitch_contour_nb10ms[] = { 256, 143, 193, 256 }; + +const uint16_t ff_silk_model_pitch_contour_nb20ms[] = { + 256, 68, 80, 101, 118, 137, 159, 189, 213, 230, 246, 256 +}; + +const uint16_t ff_silk_model_pitch_contour_mbwb10ms[] = { + 256, 91, 137, 176, 195, 209, 221, 229, 236, 242, 247, 252, 256 +}; + +const uint16_t ff_silk_model_pitch_contour_mbwb20ms[] = { + 256, 33, 55, 73, 89, 104, 118, 132, 145, 158, 168, 177, 186, 194, 200, 206, + 212, 217, 221, 225, 229, 232, 235, 238, 240, 242, 244, 246, 248, 250, 252, 253, + 254, 255, 256 +}; + +const uint16_t ff_silk_model_ltp_filter[] = { 256, 77, 157, 256 }; + +const uint16_t ff_silk_model_ltp_filter0_sel[] = { + 256, 185, 200, 213, 226, 235, 244, 250, 256 +}; + +const uint16_t ff_silk_model_ltp_filter1_sel[] = { + 256, 57, 91, 112, 132, 147, 160, 172, 185, 195, 205, 214, 224, 233, 241, 248, 256 +}; + +const uint16_t ff_silk_model_ltp_filter2_sel[] = { + 256, 15, 31, 45, 57, 69, 81, 92, 103, 114, 124, 133, 142, 151, 160, 168, + 176, 184, 192, 199, 206, 212, 218, 223, 227, 232, 236, 240, 244, 247, 251, 254, 256 +}; + +const uint16_t ff_silk_model_ltp_scale_index[] = { 256, 128, 192, 256 }; + +const uint16_t ff_silk_model_lcg_seed[] = { 256, 64, 128, 192, 256 }; + +const uint16_t ff_silk_model_exc_rate[2][10] = { + { 256, 15, 66, 78, 124, 169, 182, 215, 242, 256 }, // unvoiced + { 256, 33, 63, 99, 116, 150, 199, 217, 238, 256 } // voiced +}; + +const uint16_t ff_silk_model_pulse_count[11][19] = { + { 256, 131, 205, 230, 238, 241, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256 }, + { 256, 58, 151, 211, 234, 241, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256 }, + { 256, 43, 94, 140, 173, 197, 213, 224, 232, + 238, 241, 244, 247, 249, 250, 251, 253, 254, 256 }, + { 256, 17, 69, 140, 197, 228, 240, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256 }, + { 256, 6, 27, 68, 121, 170, 205, 226, 237, + 243, 246, 248, 250, 251, 252, 253, 254, 255, 256 }, + { 256, 7, 21, 43, 71, 100, 128, 153, 173, + 190, 203, 214, 223, 230, 235, 239, 243, 246, 256 }, + { 256, 2, 7, 21, 50, 92, 138, 179, 210, + 229, 240, 246, 249, 251, 252, 253, 254, 255, 256 }, + { 256, 1, 3, 7, 17, 36, 65, 100, 137, + 171, 199, 219, 233, 241, 246, 250, 252, 254, 256 }, + { 256, 1, 3, 5, 10, 19, 33, 53, 77, + 104, 132, 158, 181, 201, 216, 227, 235, 241, 256 }, + { 256, 1, 2, 3, 9, 36, 94, 150, 189, + 214, 228, 238, 244, 247, 250, 252, 253, 254, 256 }, + { 256, 2, 3, 9, 36, 94, 150, 189, 214, + 228, 238, 244, 247, 250, 252, 253, 254, 256, 256 } +}; + +const uint16_t ff_silk_model_pulse_location[4][168] = { + { + 256, 126, 256, + 256, 56, 198, 256, + 256, 25, 126, 230, 256, + 256, 12, 72, 180, 244, 256, + 256, 7, 42, 126, 213, 250, 256, + 256, 4, 24, 83, 169, 232, 253, 256, + 256, 3, 15, 53, 125, 200, 242, 254, 256, + 256, 2, 10, 35, 89, 162, 221, 248, 255, 256, + 256, 2, 7, 24, 63, 126, 191, 233, 251, 255, 256, + 256, 1, 5, 17, 45, 94, 157, 211, 241, 252, 255, 256, + 256, 1, 5, 13, 33, 70, 125, 182, 223, 245, 253, 255, 256, + 256, 1, 4, 11, 26, 54, 98, 151, 199, 232, 248, 254, 255, 256, + 256, 1, 3, 9, 21, 42, 77, 124, 172, 212, 237, 249, 254, 255, 256, + 256, 1, 2, 6, 16, 33, 60, 97, 144, 187, 220, 241, 250, 254, 255, 256, + 256, 1, 2, 3, 11, 25, 47, 80, 120, 163, 201, 229, 245, 253, 254, 255, 256, + 256, 1, 2, 3, 4, 17, 35, 62, 98, 139, 180, 214, 238, 252, 253, 254, 255, 256 + },{ + 256, 127, 256, + 256, 53, 202, 256, + 256, 22, 127, 233, 256, + 256, 11, 72, 183, 246, 256, + 256, 6, 41, 127, 215, 251, 256, + 256, 4, 24, 83, 170, 232, 253, 256, + 256, 3, 16, 56, 127, 200, 241, 254, 256, + 256, 3, 12, 39, 92, 162, 218, 246, 255, 256, + 256, 3, 11, 30, 67, 124, 185, 229, 249, 255, 256, + 256, 3, 10, 25, 53, 97, 151, 200, 233, 250, 255, 256, + 256, 1, 8, 21, 43, 77, 123, 171, 209, 237, 251, 255, 256, + 256, 1, 2, 13, 35, 62, 97, 139, 186, 219, 244, 254, 255, 256, + 256, 1, 2, 8, 22, 48, 85, 128, 171, 208, 234, 248, 254, 255, 256, + 256, 1, 2, 6, 16, 36, 67, 107, 149, 189, 220, 240, 250, 254, 255, 256, + 256, 1, 2, 5, 13, 29, 55, 90, 128, 166, 201, 227, 243, 251, 254, 255, 256, + 256, 1, 2, 4, 10, 22, 43, 73, 109, 147, 183, 213, 234, 246, 252, 254, 255, 256 + },{ + 256, 127, 256, + 256, 49, 206, 256, + 256, 20, 127, 236, 256, + 256, 11, 71, 184, 246, 256, + 256, 7, 43, 127, 214, 250, 256, + 256, 6, 30, 87, 169, 229, 252, 256, + 256, 5, 23, 62, 126, 194, 236, 252, 256, + 256, 6, 20, 49, 96, 157, 209, 239, 253, 256, + 256, 1, 16, 39, 74, 125, 175, 215, 245, 255, 256, + 256, 1, 2, 23, 55, 97, 149, 195, 236, 254, 255, 256, + 256, 1, 7, 23, 50, 86, 128, 170, 206, 233, 249, 255, 256, + 256, 1, 6, 18, 39, 70, 108, 148, 186, 217, 238, 250, 255, 256, + 256, 1, 4, 13, 30, 56, 90, 128, 166, 200, 226, 243, 252, 255, 256, + 256, 1, 4, 11, 25, 47, 76, 110, 146, 180, 209, 231, 245, 252, 255, 256, + 256, 1, 3, 8, 19, 37, 62, 93, 128, 163, 194, 219, 237, 248, 253, 255, 256, + 256, 1, 2, 6, 15, 30, 51, 79, 111, 145, 177, 205, 226, 241, 250, 254, 255, 256 + },{ + 256, 128, 256, + 256, 42, 214, 256, + 256, 21, 128, 235, 256, + 256, 12, 72, 184, 245, 256, + 256, 8, 42, 128, 214, 249, 256, + 256, 8, 31, 86, 176, 231, 251, 256, + 256, 5, 20, 58, 130, 202, 238, 253, 256, + 256, 6, 18, 45, 97, 174, 221, 241, 251, 256, + 256, 6, 25, 53, 88, 128, 168, 203, 231, 250, 256, + 256, 4, 18, 40, 71, 108, 148, 185, 216, 238, 252, 256, + 256, 3, 13, 31, 57, 90, 128, 166, 199, 225, 243, 253, 256, + 256, 2, 10, 23, 44, 73, 109, 147, 183, 212, 233, 246, 254, 256, + 256, 1, 6, 16, 33, 58, 90, 128, 166, 198, 223, 240, 250, 255, 256, + 256, 1, 5, 12, 25, 46, 75, 110, 146, 181, 210, 231, 244, 251, 255, 256, + 256, 1, 3, 8, 18, 35, 60, 92, 128, 164, 196, 221, 238, 248, 253, 255, 256, + 256, 1, 3, 7, 14, 27, 48, 76, 110, 146, 180, 208, 229, 242, 249, 253, 255, 256 + } +}; + +const uint16_t ff_silk_model_excitation_lsb[] = {256, 136, 256}; + +const uint16_t ff_silk_model_excitation_sign[3][2][7][3] = { + { // Inactive + { // Low offset + {256, 2, 256}, + {256, 207, 256}, + {256, 189, 256}, + {256, 179, 256}, + {256, 174, 256}, + {256, 163, 256}, + {256, 157, 256} + }, { // High offset + {256, 58, 256}, + {256, 245, 256}, + {256, 238, 256}, + {256, 232, 256}, + {256, 225, 256}, + {256, 220, 256}, + {256, 211, 256} + } + }, { // Unvoiced + { // Low offset + {256, 1, 256}, + {256, 210, 256}, + {256, 190, 256}, + {256, 178, 256}, + {256, 169, 256}, + {256, 162, 256}, + {256, 152, 256} + }, { // High offset + {256, 48, 256}, + {256, 242, 256}, + {256, 235, 256}, + {256, 224, 256}, + {256, 214, 256}, + {256, 205, 256}, + {256, 190, 256} + } + }, { // Voiced + { // Low offset + {256, 1, 256}, + {256, 162, 256}, + {256, 152, 256}, + {256, 147, 256}, + {256, 144, 256}, + {256, 141, 256}, + {256, 138, 256} + }, { // High offset + {256, 8, 256}, + {256, 203, 256}, + {256, 187, 256}, + {256, 176, 256}, + {256, 168, 256}, + {256, 161, 256}, + {256, 154, 256} + } + } +}; + +const int16_t ff_silk_stereo_weights[] = { + -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, + 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732 +}; + +const uint8_t ff_silk_lsf_s2_model_sel_nbmb[32][10] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 3, 1, 2, 2, 1, 2, 1, 1, 1 }, + { 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 2, 2, 2, 2, 1, 2, 1, 1, 1 }, + { 2, 3, 3, 3, 3, 2, 2, 2, 2, 2 }, + { 0, 5, 3, 3, 2, 2, 2, 2, 1, 1 }, + { 0, 2, 2, 2, 2, 2, 2, 2, 2, 1 }, + { 2, 3, 6, 4, 4, 4, 5, 4, 5, 5 }, + { 2, 4, 5, 5, 4, 5, 4, 6, 4, 4 }, + { 2, 4, 4, 7, 4, 5, 4, 5, 5, 4 }, + { 4, 3, 3, 3, 2, 3, 2, 2, 2, 2 }, + { 1, 5, 5, 6, 4, 5, 4, 5, 5, 5 }, + { 2, 7, 4, 6, 5, 5, 5, 5, 5, 5 }, + { 2, 7, 5, 5, 5, 5, 5, 6, 5, 4 }, + { 3, 3, 5, 4, 4, 5, 4, 5, 4, 4 }, + { 2, 3, 3, 5, 5, 4, 4, 4, 4, 4 }, + { 2, 4, 4, 6, 4, 5, 4, 5, 5, 5 }, + { 2, 5, 4, 6, 5, 5, 5, 4, 5, 4 }, + { 2, 7, 4, 5, 4, 5, 4, 5, 5, 5 }, + { 2, 5, 4, 6, 7, 6, 5, 6, 5, 4 }, + { 3, 6, 7, 4, 6, 5, 5, 6, 4, 5 }, + { 2, 7, 6, 4, 4, 4, 5, 4, 5, 5 }, + { 4, 5, 5, 4, 6, 6, 5, 6, 5, 4 }, + { 2, 5, 5, 6, 5, 6, 4, 6, 4, 4 }, + { 4, 5, 5, 5, 3, 7, 4, 5, 5, 4 }, + { 2, 3, 4, 5, 5, 6, 4, 5, 5, 4 }, + { 2, 3, 2, 3, 3, 4, 2, 3, 3, 3 }, + { 1, 1, 2, 2, 2, 2, 2, 3, 2, 2 }, + { 4, 5, 5, 6, 6, 6, 5, 6, 4, 5 }, + { 3, 5, 5, 4, 4, 4, 4, 3, 3, 2 }, + { 2, 5, 3, 7, 5, 5, 4, 4, 5, 4 }, + { 4, 4, 5, 4, 5, 6, 5, 6, 5, 4 } +}; + +const uint8_t ff_silk_lsf_s2_model_sel_wb[32][16] = { + { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, + { 10, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 9, 9, 9, 8, 11 }, + { 10, 13, 13, 11, 15, 12, 12, 13, 10, 13, 12, 13, 13, 12, 11, 11 }, + { 8, 10, 9, 10, 10, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 9 }, + { 8, 14, 13, 12, 14, 12, 15, 13, 12, 12, 12, 13, 13, 12, 12, 11 }, + { 8, 11, 13, 13, 12, 11, 11, 13, 11, 11, 11, 11, 11, 11, 10, 12 }, + { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, + { 8, 10, 14, 11, 15, 10, 13, 11, 12, 13, 13, 12, 11, 11, 10, 11 }, + { 8, 14, 10, 14, 14, 12, 13, 12, 14, 13, 12, 12, 13, 11, 11, 11 }, + { 10, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, + { 8, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9 }, + { 10, 10, 11, 12, 13, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 11 }, + { 10, 10, 11, 11, 12, 11, 11, 11, 11, 11, 11, 11, 11, 10, 9, 11 }, + { 11, 12, 12, 12, 14, 12, 12, 13, 11, 13, 12, 12, 13, 12, 11, 12 }, + { 8, 14, 12, 13, 12, 15, 13, 10, 14, 13, 15, 12, 12, 11, 13, 11 }, + { 8, 9, 8, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 9, 8 }, + { 9, 14, 13, 15, 13, 12, 13, 11, 12, 13, 12, 12, 12, 11, 11, 12 }, + { 9, 11, 11, 12, 12, 11, 11, 13, 10, 11, 11, 13, 13, 13, 11, 12 }, + { 10, 11, 11, 10, 10, 10, 11, 10, 9, 10, 9, 10, 9, 9, 9, 12 }, + { 8, 10, 11, 13, 11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 8 }, + { 11, 12, 11, 13, 11, 11, 10, 10, 9, 9, 9, 9, 9, 10, 10, 12 }, + { 10, 14, 11, 15, 15, 12, 13, 12, 13, 11, 13, 11, 11, 10, 11, 11 }, + { 10, 11, 13, 14, 14, 11, 13, 11, 12, 12, 11, 11, 11, 11, 10, 12 }, + { 9, 11, 11, 12, 12, 12, 12, 11, 13, 13, 13, 11, 9, 9, 9, 9 }, + { 10, 13, 11, 14, 14, 12, 15, 12, 12, 13, 11, 12, 12, 11, 11, 11 }, + { 8, 14, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }, + { 8, 14, 14, 11, 13, 10, 13, 13, 11, 12, 12, 15, 15, 12, 12, 12 }, + { 11, 11, 15, 11, 13, 12, 11, 11, 11, 10, 10, 11, 11, 11, 10, 11 }, + { 8, 8, 9, 8, 8, 8, 10, 9, 10, 9, 9, 10, 10, 10, 9, 9 }, + { 8, 11, 10, 13, 11, 11, 10, 11, 10, 9, 8, 8, 9, 8, 8, 9 }, + { 11, 13, 13, 12, 15, 13, 11, 11, 10, 11, 10, 10, 9, 8, 9, 8 }, + { 10, 11, 13, 11, 12, 11, 11, 11, 10, 9, 10, 14, 12, 8, 8, 8 } +}; + +const uint8_t ff_silk_lsf_pred_weights_nbmb[2][9] = { + {179, 138, 140, 148, 151, 149, 153, 151, 163}, + {116, 67, 82, 59, 92, 72, 100, 89, 92} +}; + +const uint8_t ff_silk_lsf_pred_weights_wb[2][15] = { + {175, 148, 160, 176, 178, 173, 174, 164, 177, 174, 196, 182, 198, 192, 182}, + { 68, 62, 66, 60, 72, 117, 85, 90, 118, 136, 151, 142, 160, 142, 155} +}; + +const uint8_t ff_silk_lsf_weight_sel_nbmb[32][9] = { + { 0, 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 1, 1, 0, 0, 0, 0, 1, 0 }, + { 0, 1, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 1, 1, 0, 0, 0, 1, 0 }, + { 0, 1, 1, 0, 0, 1, 1, 0, 0 }, + { 0, 0, 1, 1, 0, 1, 0, 1, 1 }, + { 0, 0, 1, 1, 0, 0, 1, 1, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1, 0, 1, 1, 1, 1, 1, 0 }, + { 0, 1, 0, 1, 1, 1, 1, 1, 0 }, + { 0, 1, 1, 1, 1, 1, 1, 1, 0 }, + { 1, 0, 1, 1, 0, 1, 1, 1, 1 }, + { 0, 1, 1, 1, 1, 1, 0, 1, 0 }, + { 0, 0, 1, 1, 0, 1, 0, 1, 0 }, + { 0, 0, 1, 1, 1, 0, 1, 1, 1 }, + { 0, 1, 1, 0, 0, 1, 1, 1, 0 }, + { 0, 0, 0, 1, 1, 1, 0, 1, 0 }, + { 0, 1, 1, 0, 0, 1, 0, 1, 0 }, + { 0, 1, 1, 0, 0, 0, 1, 1, 0 }, + { 0, 0, 0, 0, 0, 1, 1, 1, 1 }, + { 0, 0, 1, 1, 0, 0, 0, 1, 1 }, + { 0, 0, 0, 1, 0, 1, 1, 1, 1 }, + { 0, 1, 1, 1, 1, 1, 1, 1, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 0, 1, 1, 0, 1, 0 }, + { 1, 0, 0, 1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 1, 1, 0, 1, 0, 1 }, + { 1, 0, 1, 1, 0, 1, 1, 1, 1 } +}; + +const uint8_t ff_silk_lsf_weight_sel_wb[32][15] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, + { 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0 }, + { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0 }, + { 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1 }, + { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0 }, + { 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0 }, + { 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0 }, + { 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 }, + { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0 }, + { 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0 }, + { 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0 }, + { 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0 }, + { 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0 }, + { 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1 }, + { 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, + { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0 } +}; + +const uint8_t ff_silk_lsf_codebook_nbmb[32][10] = { + { 12, 35, 60, 83, 108, 132, 157, 180, 206, 228 }, + { 15, 32, 55, 77, 101, 125, 151, 175, 201, 225 }, + { 19, 42, 66, 89, 114, 137, 162, 184, 209, 230 }, + { 12, 25, 50, 72, 97, 120, 147, 172, 200, 223 }, + { 26, 44, 69, 90, 114, 135, 159, 180, 205, 225 }, + { 13, 22, 53, 80, 106, 130, 156, 180, 205, 228 }, + { 15, 25, 44, 64, 90, 115, 142, 168, 196, 222 }, + { 19, 24, 62, 82, 100, 120, 145, 168, 190, 214 }, + { 22, 31, 50, 79, 103, 120, 151, 170, 203, 227 }, + { 21, 29, 45, 65, 106, 124, 150, 171, 196, 224 }, + { 30, 49, 75, 97, 121, 142, 165, 186, 209, 229 }, + { 19, 25, 52, 70, 93, 116, 143, 166, 192, 219 }, + { 26, 34, 62, 75, 97, 118, 145, 167, 194, 217 }, + { 25, 33, 56, 70, 91, 113, 143, 165, 196, 223 }, + { 21, 34, 51, 72, 97, 117, 145, 171, 196, 222 }, + { 20, 29, 50, 67, 90, 117, 144, 168, 197, 221 }, + { 22, 31, 48, 66, 95, 117, 146, 168, 196, 222 }, + { 24, 33, 51, 77, 116, 134, 158, 180, 200, 224 }, + { 21, 28, 70, 87, 106, 124, 149, 170, 194, 217 }, + { 26, 33, 53, 64, 83, 117, 152, 173, 204, 225 }, + { 27, 34, 65, 95, 108, 129, 155, 174, 210, 225 }, + { 20, 26, 72, 99, 113, 131, 154, 176, 200, 219 }, + { 34, 43, 61, 78, 93, 114, 155, 177, 205, 229 }, + { 23, 29, 54, 97, 124, 138, 163, 179, 209, 229 }, + { 30, 38, 56, 89, 118, 129, 158, 178, 200, 231 }, + { 21, 29, 49, 63, 85, 111, 142, 163, 193, 222 }, + { 27, 48, 77, 103, 133, 158, 179, 196, 215, 232 }, + { 29, 47, 74, 99, 124, 151, 176, 198, 220, 237 }, + { 33, 42, 61, 76, 93, 121, 155, 174, 207, 225 }, + { 29, 53, 87, 112, 136, 154, 170, 188, 208, 227 }, + { 24, 30, 52, 84, 131, 150, 166, 186, 203, 229 }, + { 37, 48, 64, 84, 104, 118, 156, 177, 201, 230 } +}; + +const uint8_t ff_silk_lsf_codebook_wb[32][16] = { + { 7, 23, 38, 54, 69, 85, 100, 116, 131, 147, 162, 178, 193, 208, 223, 239 }, + { 13, 25, 41, 55, 69, 83, 98, 112, 127, 142, 157, 171, 187, 203, 220, 236 }, + { 15, 21, 34, 51, 61, 78, 92, 106, 126, 136, 152, 167, 185, 205, 225, 240 }, + { 10, 21, 36, 50, 63, 79, 95, 110, 126, 141, 157, 173, 189, 205, 221, 237 }, + { 17, 20, 37, 51, 59, 78, 89, 107, 123, 134, 150, 164, 184, 205, 224, 240 }, + { 10, 15, 32, 51, 67, 81, 96, 112, 129, 142, 158, 173, 189, 204, 220, 236 }, + { 8, 21, 37, 51, 65, 79, 98, 113, 126, 138, 155, 168, 179, 192, 209, 218 }, + { 12, 15, 34, 55, 63, 78, 87, 108, 118, 131, 148, 167, 185, 203, 219, 236 }, + { 16, 19, 32, 36, 56, 79, 91, 108, 118, 136, 154, 171, 186, 204, 220, 237 }, + { 11, 28, 43, 58, 74, 89, 105, 120, 135, 150, 165, 180, 196, 211, 226, 241 }, + { 6, 16, 33, 46, 60, 75, 92, 107, 123, 137, 156, 169, 185, 199, 214, 225 }, + { 11, 19, 30, 44, 57, 74, 89, 105, 121, 135, 152, 169, 186, 202, 218, 234 }, + { 12, 19, 29, 46, 57, 71, 88, 100, 120, 132, 148, 165, 182, 199, 216, 233 }, + { 17, 23, 35, 46, 56, 77, 92, 106, 123, 134, 152, 167, 185, 204, 222, 237 }, + { 14, 17, 45, 53, 63, 75, 89, 107, 115, 132, 151, 171, 188, 206, 221, 240 }, + { 9, 16, 29, 40, 56, 71, 88, 103, 119, 137, 154, 171, 189, 205, 222, 237 }, + { 16, 19, 36, 48, 57, 76, 87, 105, 118, 132, 150, 167, 185, 202, 218, 236 }, + { 12, 17, 29, 54, 71, 81, 94, 104, 126, 136, 149, 164, 182, 201, 221, 237 }, + { 15, 28, 47, 62, 79, 97, 115, 129, 142, 155, 168, 180, 194, 208, 223, 238 }, + { 8, 14, 30, 45, 62, 78, 94, 111, 127, 143, 159, 175, 192, 207, 223, 239 }, + { 17, 30, 49, 62, 79, 92, 107, 119, 132, 145, 160, 174, 190, 204, 220, 235 }, + { 14, 19, 36, 45, 61, 76, 91, 108, 121, 138, 154, 172, 189, 205, 222, 238 }, + { 12, 18, 31, 45, 60, 76, 91, 107, 123, 138, 154, 171, 187, 204, 221, 236 }, + { 13, 17, 31, 43, 53, 70, 83, 103, 114, 131, 149, 167, 185, 203, 220, 237 }, + { 17, 22, 35, 42, 58, 78, 93, 110, 125, 139, 155, 170, 188, 206, 224, 240 }, + { 8, 15, 34, 50, 67, 83, 99, 115, 131, 146, 162, 178, 193, 209, 224, 239 }, + { 13, 16, 41, 66, 73, 86, 95, 111, 128, 137, 150, 163, 183, 206, 225, 241 }, + { 17, 25, 37, 52, 63, 75, 92, 102, 119, 132, 144, 160, 175, 191, 212, 231 }, + { 19, 31, 49, 65, 83, 100, 117, 133, 147, 161, 174, 187, 200, 213, 227, 242 }, + { 18, 31, 52, 68, 88, 103, 117, 126, 138, 149, 163, 177, 192, 207, 223, 239 }, + { 16, 29, 47, 61, 76, 90, 106, 119, 133, 147, 161, 176, 193, 209, 224, 240 }, + { 15, 21, 35, 50, 61, 73, 86, 97, 110, 119, 129, 141, 175, 198, 218, 237 } +}; + +const uint16_t ff_silk_lsf_min_spacing_nbmb[] = { + 250, 3, 6, 3, 3, 3, 4, 3, 3, 3, 461 +}; + +const uint16_t ff_silk_lsf_min_spacing_wb[] = { + 100, 3, 40, 3, 3, 3, 5, 14, 14, 10, 11, 3, 8, 9, 7, 3, 347 +}; + +const uint8_t ff_silk_lsf_ordering_nbmb[] = { + 0, 9, 6, 3, 4, 5, 8, 1, 2, 7 +}; + +const uint8_t ff_silk_lsf_ordering_wb[] = { + 0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1 +}; + +const int16_t ff_silk_cosine[] = { /* (0.12) */ + 4096, 4095, 4091, 4085, + 4076, 4065, 4052, 4036, + 4017, 3997, 3973, 3948, + 3920, 3889, 3857, 3822, + 3784, 3745, 3703, 3659, + 3613, 3564, 3513, 3461, + 3406, 3349, 3290, 3229, + 3166, 3102, 3035, 2967, + 2896, 2824, 2751, 2676, + 2599, 2520, 2440, 2359, + 2276, 2191, 2106, 2019, + 1931, 1842, 1751, 1660, + 1568, 1474, 1380, 1285, + 1189, 1093, 995, 897, + 799, 700, 601, 501, + 401, 301, 201, 101, + 0, -101, -201, -301, + -401, -501, -601, -700, + -799, -897, -995, -1093, + -1189, -1285, -1380, -1474, + -1568, -1660, -1751, -1842, + -1931, -2019, -2106, -2191, + -2276, -2359, -2440, -2520, + -2599, -2676, -2751, -2824, + -2896, -2967, -3035, -3102, + -3166, -3229, -3290, -3349, + -3406, -3461, -3513, -3564, + -3613, -3659, -3703, -3745, + -3784, -3822, -3857, -3889, + -3920, -3948, -3973, -3997, + -4017, -4036, -4052, -4065, + -4076, -4085, -4091, -4095, + -4096 +}; + +const uint16_t ff_silk_pitch_scale[] = { 4, 6, 8}; + +const uint16_t ff_silk_pitch_min_lag[] = { 16, 24, 32}; + +const uint16_t ff_silk_pitch_max_lag[] = {144, 216, 288}; + +const int8_t ff_silk_pitch_offset_nb10ms[3][2] = { + { 0, 0}, + { 1, 0}, + { 0, 1} +}; + +const int8_t ff_silk_pitch_offset_nb20ms[11][4] = { + { 0, 0, 0, 0}, + { 2, 1, 0, -1}, + {-1, 0, 1, 2}, + {-1, 0, 0, 1}, + {-1, 0, 0, 0}, + { 0, 0, 0, 1}, + { 0, 0, 1, 1}, + { 1, 1, 0, 0}, + { 1, 0, 0, 0}, + { 0, 0, 0, -1}, + { 1, 0, 0, -1} +}; + +const int8_t ff_silk_pitch_offset_mbwb10ms[12][2] = { + { 0, 0}, + { 0, 1}, + { 1, 0}, + {-1, 1}, + { 1, -1}, + {-1, 2}, + { 2, -1}, + {-2, 2}, + { 2, -2}, + {-2, 3}, + { 3, -2}, + {-3, 3} +}; + +const int8_t ff_silk_pitch_offset_mbwb20ms[34][4] = { + { 0, 0, 0, 0}, + { 0, 0, 1, 1}, + { 1, 1, 0, 0}, + {-1, 0, 0, 0}, + { 0, 0, 0, 1}, + { 1, 0, 0, 0}, + {-1, 0, 0, 1}, + { 0, 0, 0, -1}, + {-1, 0, 1, 2}, + { 1, 0, 0, -1}, + {-2, -1, 1, 2}, + { 2, 1, 0, -1}, + {-2, 0, 0, 2}, + {-2, 0, 1, 3}, + { 2, 1, -1, -2}, + {-3, -1, 1, 3}, + { 2, 0, 0, -2}, + { 3, 1, 0, -2}, + {-3, -1, 2, 4}, + {-4, -1, 1, 4}, + { 3, 1, -1, -3}, + {-4, -1, 2, 5}, + { 4, 2, -1, -3}, + { 4, 1, -1, -4}, + {-5, -1, 2, 6}, + { 5, 2, -1, -4}, + {-6, -2, 2, 6}, + {-5, -2, 2, 5}, + { 6, 2, -1, -5}, + {-7, -2, 3, 8}, + { 6, 2, -2, -6}, + { 5, 2, -2, -5}, + { 8, 3, -2, -7}, + {-9, -3, 3, 9} +}; + +const int8_t ff_silk_ltp_filter0_taps[8][5] = { + { 4, 6, 24, 7, 5}, + { 0, 0, 2, 0, 0}, + { 12, 28, 41, 13, -4}, + { -9, 15, 42, 25, 14}, + { 1, -2, 62, 41, -9}, + {-10, 37, 65, -4, 3}, + { -6, 4, 66, 7, -8}, + { 16, 14, 38, -3, 33} +}; + +const int8_t ff_silk_ltp_filter1_taps[16][5] = { + { 13, 22, 39, 23, 12}, + { -1, 36, 64, 27, -6}, + { -7, 10, 55, 43, 17}, + { 1, 1, 8, 1, 1}, + { 6, -11, 74, 53, -9}, + {-12, 55, 76, -12, 8}, + { -3, 3, 93, 27, -4}, + { 26, 39, 59, 3, -8}, + { 2, 0, 77, 11, 9}, + { -8, 22, 44, -6, 7}, + { 40, 9, 26, 3, 9}, + { -7, 20, 101, -7, 4}, + { 3, -8, 42, 26, 0}, + {-15, 33, 68, 2, 23}, + { -2, 55, 46, -2, 15}, + { 3, -1, 21, 16, 41} +}; + +const int8_t ff_silk_ltp_filter2_taps[32][5] = { + { -6, 27, 61, 39, 5}, + {-11, 42, 88, 4, 1}, + { -2, 60, 65, 6, -4}, + { -1, -5, 73, 56, 1}, + { -9, 19, 94, 29, -9}, + { 0, 12, 99, 6, 4}, + { 8, -19, 102, 46, -13}, + { 3, 2, 13, 3, 2}, + { 9, -21, 84, 72, -18}, + {-11, 46, 104, -22, 8}, + { 18, 38, 48, 23, 0}, + {-16, 70, 83, -21, 11}, + { 5, -11, 117, 22, -8}, + { -6, 23, 117, -12, 3}, + { 3, -8, 95, 28, 4}, + {-10, 15, 77, 60, -15}, + { -1, 4, 124, 2, -4}, + { 3, 38, 84, 24, -25}, + { 2, 13, 42, 13, 31}, + { 21, -4, 56, 46, -1}, + { -1, 35, 79, -13, 19}, + { -7, 65, 88, -9, -14}, + { 20, 4, 81, 49, -29}, + { 20, 0, 75, 3, -17}, + { 5, -9, 44, 92, -8}, + { 1, -3, 22, 69, 31}, + { -6, 95, 41, -12, 5}, + { 39, 67, 16, -4, 1}, + { 0, -6, 120, 55, -36}, + {-13, 44, 122, 4, -24}, + { 81, 5, 11, 3, 7}, + { 2, 0, 9, 10, 88} +}; + +const uint16_t ff_silk_ltp_scale_factor[] = {15565, 12288, 8192}; + +const uint8_t ff_silk_shell_blocks[3][2] = { + { 5, 10}, // NB + { 8, 15}, // MB + {10, 20} // WB +}; + +const uint8_t ff_silk_quant_offset[2][2] = { /* (0.23) */ + {25, 60}, // Inactive or Unvoiced + { 8, 25} // Voiced +}; + +const int ff_silk_stereo_interp_len[3] = { + 64, 96, 128 +}; + +const uint16_t ff_celt_model_tapset[] = { 4, 2, 3, 4 }; + +const uint16_t ff_celt_model_spread[] = { 32, 7, 9, 30, 32 }; + +const uint16_t ff_celt_model_alloc_trim[] = { + 128, 2, 4, 9, 19, 41, 87, 109, 119, 124, 126, 128 +}; + +const uint16_t ff_celt_model_energy_small[] = { 4, 2, 3, 4 }; + +const uint8_t ff_celt_freq_bands[] = { /* in steps of 200Hz */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100 +}; + +const uint8_t ff_celt_freq_range[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 6, 6, 8, 12, 18, 22 +}; + +const uint8_t ff_celt_log_freq_range[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36 +}; + +/* Positive - increased freqeuency resolution (only possible on transients) + * Negative - increased time resolution */ +const int8_t ff_celt_tf_select[4][2][2][2] = { + /* OFF ON Transient frame */ + /* OFF ON OFF ON TF select flag */ + /* OFF ON OFF ON OFF ON OFF ON TF change flag */ + { { { 0, -1 }, { 0, -1 } }, { { 0, -1 }, { 0, -1 } } }, /* 120 */ + { { { 0, -1 }, { 0, -2 } }, { { 1, 0 }, { 1, -1 } } }, /* 240 */ + { { { 0, -2 }, { 0, -3 } }, { { 2, 0 }, { 1, -1 } } }, /* 480 */ + { { { 0, -2 }, { 0, -3 } }, { { 3, 0 }, { 1, -1 } } } /* 960 */ +}; + +const float ff_celt_mean_energy[] = { + 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f, + 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f, + 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f, + 4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f, + 3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f +}; + +const float ff_celt_alpha_coef[] = { + 29440.0f/32768.0f, 26112.0f/32768.0f, 21248.0f/32768.0f, 16384.0f/32768.0f +}; + +const float ff_celt_beta_coef[] = { + 1.0f - (30147.0f/32768.0f), 1.0f - (22282.0f/32768.0f), 1.0f - (12124.0f/32768.0f), 1.0f - (6554.0f/32768.0f), +}; + +const uint8_t ff_celt_coarse_energy_dist[4][2][42] = { + { + { // 120-sample inter + 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, + 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, + 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11 + }, { // 120-sample intra + 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, + 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, + 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50 + } + }, { + { // 240-sample inter + 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, + 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, + 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9 + }, { // 240-sample intra + 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, + 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, + 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45 + } + }, { + { // 480-sample inter + 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, + 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, + 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10 + }, { // 480-sample intra + 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, + 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, + 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42 + } + }, { + { // 960-sample inter + 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, + 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, + 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15 + }, { // 960-sample intra + 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, + 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, + 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40 + } + } +}; + +const uint8_t ff_celt_static_alloc[11][21] = { /* 1/32 bit/sample */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 110, 100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0 }, + { 118, 110, 103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15, 4, 0, 0, 0, 0 }, + { 126, 119, 112, 104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0 }, + { 134, 127, 120, 114, 103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10, 1 }, + { 144, 137, 130, 124, 113, 107, 101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1 }, + { 152, 145, 138, 132, 123, 117, 111, 105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1 }, + { 162, 155, 148, 142, 133, 127, 121, 115, 108, 102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1 }, + { 172, 165, 158, 152, 143, 137, 131, 125, 118, 112, 106, 100, 94, 87, 81, 75, 69, 63, 56, 45, 20 }, + { 200, 200, 200, 200, 200, 200, 200, 200, 198, 193, 188, 183, 178, 173, 168, 163, 158, 153, 148, 129, 104 } +}; + +const uint8_t ff_celt_static_caps[4][2][21] = { + { // 120-sample + {224, 224, 224, 224, 224, 224, 224, 224, 160, 160, + 160, 160, 185, 185, 185, 178, 178, 168, 134, 61, 37}, + {224, 224, 224, 224, 224, 224, 224, 224, 240, 240, + 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40}, + }, { // 240-sample + {160, 160, 160, 160, 160, 160, 160, 160, 185, 185, + 185, 185, 193, 193, 193, 183, 183, 172, 138, 64, 38}, + {240, 240, 240, 240, 240, 240, 240, 240, 207, 207, + 207, 207, 204, 204, 204, 193, 193, 180, 143, 66, 40}, + }, { // 480-sample + {185, 185, 185, 185, 185, 185, 185, 185, 193, 193, + 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39}, + {207, 207, 207, 207, 207, 207, 207, 207, 204, 204, + 204, 204, 201, 201, 201, 188, 188, 176, 141, 66, 40}, + }, { // 960-sample + {193, 193, 193, 193, 193, 193, 193, 193, 193, 193, + 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39}, + {204, 204, 204, 204, 204, 204, 204, 204, 201, 201, + 201, 201, 198, 198, 198, 187, 187, 175, 140, 66, 40} + } +}; + +const uint8_t ff_celt_cache_bits[392] = { + 40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, + 31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, + 51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, + 66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, + 64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, + 94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, + 124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, + 97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, + 142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, + 28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, + 153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, + 229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, + 166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, + 86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, + 25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, + 185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, + 110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, + 74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, + 163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, + 228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, + 90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, + 87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, + 106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, + 224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, + 182, 234 +}; + +const int16_t ff_celt_cache_index[105] = { + -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, + 82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, + 41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, + 41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, + 318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, + 305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, + 240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; + +const uint8_t ff_celt_log2_frac[] = { + 0, 8, 13, 16, 19, 21, 23, 24, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 34, 35, 36, 36, 37, 37 +}; + +const uint8_t ff_celt_bit_interleave[] = { + 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3 +}; + +const uint8_t ff_celt_bit_deinterleave[] = { + 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, + 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF +}; + +const uint8_t ff_celt_hadamard_order[] = { + 1, 0, + 3, 0, 2, 1, + 7, 0, 4, 3, 6, 1, 5, 2, + 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; + +const uint16_t ff_celt_qn_exp2[] = { + 16384, 17866, 19483, 21247, 23170, 25267, 27554, 30048 +}; + +const uint32_t ff_celt_pvq_u[1272] = { + /* N = 0, K = 0...176 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* N = 1, K = 1...176 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* N = 2, K = 2...176 */ + 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, + 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, + 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, + 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, + 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, + 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, + 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, + 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, + 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, + 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323, + 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, + /* N = 3, K = 3...176 */ + 13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613, + 685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861, + 1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, 3121, 3281, 3445, 3613, 3785, + 3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385, + 6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661, + 9941, 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961, + 13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745, + 17113, 17485, 17861, 18241, 18625, 19013, 19405, 19801, 20201, 20605, 21013, + 21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765, + 26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001, + 31501, 32005, 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721, + 37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925, + 43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, 48361, 48985, 49613, + 50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785, + 57461, 58141, 58825, 59513, 60205, 60901, 61601, + /* N = 4, K = 4...176 */ + 63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017, + 7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775, + 30913, 34279, 37881, 41727, 45825, 50183, 54809, 59711, 64897, 70375, 76153, + 82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193, + 161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575, + 267033, 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217, + 410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951, + 597057, 620775, 645113, 670079, 695681, 721927, 748825, 776383, 804609, + 833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023, + 1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407, + 1436025, 1478463, 1521729, 1565831, 1610777, 1656575, 1703233, 1750759, + 1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175, + 2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751, + 2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583, + 3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767, + 3858425, 3940223, 4023169, 4107271, 4192537, 4278975, 4366593, 4455399, + 4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575, + 5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391, + 6154617, 6266175, 6379073, 6493319, 6608921, 6725887, 6844225, 6963943, + 7085049, 7207551, + /* N = 5, K = 5...176 */ + 321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041, + 50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401, + 330409, 383041, 441729, 506921, 579081, 658689, 746241, 842249, 947241, + 1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241, + 2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801, + 4695809, 5071041, 5468329, 5888521, 6332481, 6801089, 7295241, 7815849, + 8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849, + 13850241, 14689089, 15565481, 16480521, 17435329, 18431041, 19468809, + 20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881, + 29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641, + 40914369, 42794761, 44739241, 46749249, 48826241, 50971689, 53187081, + 55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609, + 73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049, + 95872041, 99421961, 103069569, 106816641, 110664969, 114616361, 118672641, + 122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041, + 155123009, 160208001, 165417001, 170752009, 176215041, 181808129, 187533321, + 193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969, + 238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889, + 290705281, 298835721, 307135529, 315607041, 324252609, 333074601, 342075401, + 351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241, + 420810249, 431530241, 442453761, 453583369, 464921641, 476471169, 488234561, + 500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929, + 590359041, 604167209, 618216201, 632508801, + /* N = 6, K = 6...96 (technically V(109,5) fits in 32 bits, but that can't be + achieved by splitting an Opus band) */ + 1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047, + 335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409, + 2908411, 3522221, 4235671, 5060441, 6009091, 7095093, 8332863, 9737793, + 11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455, + 29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189, + 64696159, 71789409, 79491819, 87841821, 96879431, 106646281, 117185651, + 128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185, + 235074115, 254801525, 275831935, 298228865, 322057867, 347386557, 374284647, + 402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229, + 655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283, + 1020274013, 1083597703, 1150027593, 1219676595, 1292660325, 1369097135, + 1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187, + 2011371957, 2120032959, + /* N = 7, K = 7...54 (technically V(60,6) fits in 32 bits, but that can't be + achieved by splitting an Opus band) */ + 8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777, + 1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233, + 19665841, 24957661, 31388293, 39146185, 48442297, 59511829, 72616013, + 88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805, + 292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433, + 793950709, 904317037, 1027188385, 1163673953, 1314955181, 1482288821, + 1667010073, 1870535785, 2094367717, + /* N = 8, K = 8...37 (technically V(40,7) fits in 32 bits, but that can't be + achieved by splitting an Opus band) */ + 48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767, + 9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017, + 104692735, 139703809, 184327311, 240673265, 311207743, 398796225, 506750351, + 638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615, + 2229491905, + /* N = 9, K = 9...28 (technically V(29,8) fits in 32 bits, but that can't be + achieved by splitting an Opus band) */ + 265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777, + 39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145, + 628496897, 872893441, 1196924561, 1621925137, 2173806145, + /* N = 10, K = 10...24 */ + 1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073, + 254831667, 413442773, 654862247, 1014889769, 1541911931, 2300409629, + 3375210671, + /* N = 11, K = 11...19 (technically V(20,10) fits in 32 bits, but that can't be + achieved by splitting an Opus band) */ + 8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585, + 948062325, 1616336765, + /* N = 12, K = 12...18 */ + 45046719, 103274625, 224298231, 464387817, 921406335, 1759885185, + 3248227095, + /* N = 13, K = 13...16 */ + 251595969, 579168825, 1267854873, 2653649025, + /* N = 14, K = 14 */ + 1409933619 +}; + +const float ff_celt_postfilter_taps[3][3] = { + { 0.3066406250f, 0.2170410156f, 0.1296386719f }, + { 0.4638671875f, 0.2680664062f, 0.0 }, + { 0.7998046875f, 0.1000976562f, 0.0 } +}; + +DECLARE_ALIGNED(32, static const float, ff_celt_window_padded)[136] = { + 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, + 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, + 6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f, + 0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f, + 0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f, + 0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f, + 0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f, + 0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f, + 0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f, + 0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f, + 0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f, + 0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f, + 0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f, + 0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f, + 0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f, + 0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f, + 0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f, + 0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f, + 0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f, + 0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f, + 0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f, + 0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f, + 0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f, + 0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f, + 0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f, + 0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.00000000f, + 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, + 1.00000000f, 1.00000000f, 1.00000000f, +}; + +const float *ff_celt_window = &ff_celt_window_padded[8]; + +/* square of the window, used for the postfilter */ +const float ff_celt_window2[120] = { + 4.5275357e-09f, 3.66647e-07f, 2.82777e-06f, 1.08557e-05f, 2.96371e-05f, 6.60594e-05f, + 0.000128686f, 0.000227727f, 0.000374999f, 0.000583881f, 0.000869266f, 0.0012475f, + 0.0017363f, 0.00235471f, 0.00312299f, 0.00406253f, 0.00519576f, 0.00654601f, + 0.00813743f, 0.00999482f, 0.0121435f, 0.0146093f, 0.017418f, 0.0205957f, 0.0241684f, + 0.0281615f, 0.0326003f, 0.0375092f, 0.0429118f, 0.0488308f, 0.0552873f, 0.0623012f, + 0.0698908f, 0.0780723f, 0.0868601f, 0.0962664f, 0.106301f, 0.11697f, 0.12828f, + 0.140231f, 0.152822f, 0.166049f, 0.179905f, 0.194379f, 0.209457f, 0.225123f, 0.241356f, + 0.258133f, 0.275428f, 0.293212f, 0.311453f, 0.330116f, 0.349163f, 0.368556f, 0.388253f, + 0.40821f, 0.428382f, 0.448723f, 0.469185f, 0.48972f, 0.51028f, 0.530815f, 0.551277f, + 0.571618f, 0.59179f, 0.611747f, 0.631444f, 0.650837f, 0.669884f, 0.688547f, 0.706788f, + 0.724572f, 0.741867f, 0.758644f, 0.774877f, 0.790543f, 0.805621f, 0.820095f, 0.833951f, + 0.847178f, 0.859769f, 0.87172f, 0.88303f, 0.893699f, 0.903734f, 0.91314f, 0.921928f, + 0.930109f, 0.937699f, 0.944713f, 0.951169f, 0.957088f, 0.962491f, 0.9674f, 0.971838f, + 0.975832f, 0.979404f, 0.982582f, 0.985391f, 0.987857f, 0.990005f, 0.991863f, 0.993454f, + 0.994804f, 0.995937f, 0.996877f, 0.997645f, 0.998264f, 0.998753f, 0.999131f, 0.999416f, + 0.999625f, 0.999772f, 0.999871f, 0.999934f, 0.99997f, 0.999989f, 0.999997f, 0.99999964f, 1.0f, +}; + +const uint32_t * const ff_celt_pvq_u_row[15] = { + ff_celt_pvq_u + 0, ff_celt_pvq_u + 176, ff_celt_pvq_u + 351, + ff_celt_pvq_u + 525, ff_celt_pvq_u + 698, ff_celt_pvq_u + 870, + ff_celt_pvq_u + 1041, ff_celt_pvq_u + 1131, ff_celt_pvq_u + 1178, + ff_celt_pvq_u + 1207, ff_celt_pvq_u + 1226, ff_celt_pvq_u + 1240, + ff_celt_pvq_u + 1248, ff_celt_pvq_u + 1254, ff_celt_pvq_u + 1257 +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opustab.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opustab.h new file mode 100644 index 0000000000..bce5a42830 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/opustab.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2012 Andrew D'Addesio + * Copyright (c) 2013-2014 Mozilla Corporation + * Copyright (c) 2016 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPUSTAB_H +#define AVCODEC_OPUSTAB_H + +#include "libavutil/mem.h" + +#include + +extern const uint8_t ff_celt_band_end[]; + +extern const uint8_t ff_opus_default_coupled_streams[]; + +extern const uint16_t ff_silk_model_stereo_s1[]; +extern const uint16_t ff_silk_model_stereo_s2[]; +extern const uint16_t ff_silk_model_stereo_s3[]; +extern const uint16_t ff_silk_model_mid_only[]; + +extern const uint16_t ff_silk_model_frame_type_inactive[]; +extern const uint16_t ff_silk_model_frame_type_active[]; + +extern const uint16_t ff_silk_model_gain_highbits[3][9]; +extern const uint16_t ff_silk_model_gain_lowbits[]; +extern const uint16_t ff_silk_model_gain_delta[]; + +extern const uint16_t ff_silk_model_lsf_s1[2][2][33]; +extern const uint16_t ff_silk_model_lsf_s2[32][10]; +extern const uint16_t ff_silk_model_lsf_s2_ext[]; +extern const uint16_t ff_silk_model_lsf_interpolation_offset[]; + +extern const uint16_t ff_silk_model_pitch_highbits[]; +extern const uint16_t ff_silk_model_pitch_lowbits_nb[]; +extern const uint16_t ff_silk_model_pitch_lowbits_mb[]; +extern const uint16_t ff_silk_model_pitch_lowbits_wb[]; +extern const uint16_t ff_silk_model_pitch_delta[]; +extern const uint16_t ff_silk_model_pitch_contour_nb10ms[]; +extern const uint16_t ff_silk_model_pitch_contour_nb20ms[]; +extern const uint16_t ff_silk_model_pitch_contour_mbwb10ms[]; +extern const uint16_t ff_silk_model_pitch_contour_mbwb20ms[]; + +extern const uint16_t ff_silk_model_ltp_filter[]; +extern const uint16_t ff_silk_model_ltp_filter0_sel[]; +extern const uint16_t ff_silk_model_ltp_filter1_sel[]; +extern const uint16_t ff_silk_model_ltp_filter2_sel[]; +extern const uint16_t ff_silk_model_ltp_scale_index[]; + +extern const uint16_t ff_silk_model_lcg_seed[]; + +extern const uint16_t ff_silk_model_exc_rate[2][10]; + +extern const uint16_t ff_silk_model_pulse_count[11][19]; +extern const uint16_t ff_silk_model_pulse_location[4][168]; + +extern const uint16_t ff_silk_model_excitation_lsb[]; +extern const uint16_t ff_silk_model_excitation_sign[3][2][7][3]; + +extern const int16_t ff_silk_stereo_weights[]; + +extern const uint8_t ff_silk_lsf_s2_model_sel_nbmb[32][10]; +extern const uint8_t ff_silk_lsf_s2_model_sel_wb[32][16]; + +extern const uint8_t ff_silk_lsf_pred_weights_nbmb[2][9]; +extern const uint8_t ff_silk_lsf_pred_weights_wb[2][15]; + +extern const uint8_t ff_silk_lsf_weight_sel_nbmb[32][9]; +extern const uint8_t ff_silk_lsf_weight_sel_wb[32][15]; + +extern const uint8_t ff_silk_lsf_codebook_nbmb[32][10]; +extern const uint8_t ff_silk_lsf_codebook_wb[32][16]; + +extern const uint16_t ff_silk_lsf_min_spacing_nbmb[]; +extern const uint16_t ff_silk_lsf_min_spacing_wb[]; + +extern const uint8_t ff_silk_lsf_ordering_nbmb[]; +extern const uint8_t ff_silk_lsf_ordering_wb[]; + +extern const int16_t ff_silk_cosine[]; + +extern const uint16_t ff_silk_pitch_scale[]; +extern const uint16_t ff_silk_pitch_min_lag[]; +extern const uint16_t ff_silk_pitch_max_lag[]; + +extern const int8_t ff_silk_pitch_offset_nb10ms[3][2]; +extern const int8_t ff_silk_pitch_offset_nb20ms[11][4]; +extern const int8_t ff_silk_pitch_offset_mbwb10ms[12][2]; +extern const int8_t ff_silk_pitch_offset_mbwb20ms[34][4]; + +extern const int8_t ff_silk_ltp_filter0_taps[8][5]; +extern const int8_t ff_silk_ltp_filter1_taps[16][5]; +extern const int8_t ff_silk_ltp_filter2_taps[32][5]; + +extern const uint16_t ff_silk_ltp_scale_factor[]; + +extern const uint8_t ff_silk_shell_blocks[3][2]; + +extern const uint8_t ff_silk_quant_offset[2][2]; + +extern const int ff_silk_stereo_interp_len[3]; + +extern const uint16_t ff_celt_model_tapset[]; +extern const uint16_t ff_celt_model_spread[]; +extern const uint16_t ff_celt_model_alloc_trim[]; +extern const uint16_t ff_celt_model_energy_small[]; + +extern const uint8_t ff_celt_freq_bands[]; +extern const uint8_t ff_celt_freq_range[]; +extern const uint8_t ff_celt_log_freq_range[]; + +extern const int8_t ff_celt_tf_select[4][2][2][2]; + +extern const float ff_celt_mean_energy[]; + +extern const float ff_celt_alpha_coef[]; +extern const float ff_celt_beta_coef[]; + +extern const uint8_t ff_celt_coarse_energy_dist[4][2][42]; + +extern const uint8_t ff_celt_static_alloc[11][21]; +extern const uint8_t ff_celt_static_caps[4][2][21]; + +extern const uint8_t ff_celt_cache_bits[392]; +extern const int16_t ff_celt_cache_index[105]; + +extern const uint8_t ff_celt_log2_frac[]; + +extern const uint8_t ff_celt_bit_interleave[]; +extern const uint8_t ff_celt_bit_deinterleave[]; + +extern const uint8_t ff_celt_hadamard_order[]; + +extern const uint16_t ff_celt_qn_exp2[]; +extern const uint32_t ff_celt_pvq_u[1272]; + +extern const float ff_celt_postfilter_taps[3][3]; + +extern const float ff_celt_window2[120]; +extern const float *ff_celt_window; + +extern const uint32_t * const ff_celt_pvq_u_row[15]; + +#endif /* AVCODEC_OPUSTAB_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser.c new file mode 100644 index 0000000000..3e19810a94 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser.c @@ -0,0 +1,334 @@ +/* + * Audio and Video frame extraction + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/internal.h" +#include "libavutil/mem.h" + +#include "internal.h" +#include "parser.h" + +AVCodecParserContext *av_parser_init(int codec_id) +{ + AVCodecParserContext *s = NULL; + const AVCodecParser *parser; + void *i = 0; + int ret; + + if (codec_id == AV_CODEC_ID_NONE) + return NULL; + + while ((parser = av_parser_iterate(&i))) { + if (parser->codec_ids[0] == codec_id || + parser->codec_ids[1] == codec_id || + parser->codec_ids[2] == codec_id || + parser->codec_ids[3] == codec_id || + parser->codec_ids[4] == codec_id) + goto found; + } + return NULL; + +found: + s = av_mallocz(sizeof(AVCodecParserContext)); + if (!s) + goto err_out; + s->parser = (AVCodecParser*)parser; + s->priv_data = av_mallocz(parser->priv_data_size); + if (!s->priv_data) + goto err_out; + s->fetch_timestamp=1; + s->pict_type = AV_PICTURE_TYPE_I; + if (parser->parser_init) { + ret = parser->parser_init(s); + if (ret != 0) + goto err_out; + } + s->key_frame = -1; +#if FF_API_CONVERGENCE_DURATION +FF_DISABLE_DEPRECATION_WARNINGS + s->convergence_duration = 0; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + s->dts_sync_point = INT_MIN; + s->dts_ref_dts_delta = INT_MIN; + s->pts_dts_delta = INT_MIN; + s->format = -1; + + return s; + +err_out: + if (s) + av_freep(&s->priv_data); + av_free(s); + return NULL; +} + +void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove, int fuzzy) +{ + int i; + + if (!fuzzy) { + s->dts = + s->pts = AV_NOPTS_VALUE; + s->pos = -1; + s->offset = 0; + } + for (i = 0; i < AV_PARSER_PTS_NB; i++) { + if (s->cur_offset + off >= s->cur_frame_offset[i] && + (s->frame_offset < s->cur_frame_offset[i] || + (!s->frame_offset && !s->next_frame_offset)) && // first field/frame + // check disabled since MPEG-TS does not send complete PES packets + /*s->next_frame_offset + off <*/ s->cur_frame_end[i]){ + + if (!fuzzy || s->cur_frame_dts[i] != AV_NOPTS_VALUE) { + s->dts = s->cur_frame_dts[i]; + s->pts = s->cur_frame_pts[i]; + s->pos = s->cur_frame_pos[i]; + s->offset = s->next_frame_offset - s->cur_frame_offset[i]; + } + if (remove) + s->cur_frame_offset[i] = INT64_MAX; + if (s->cur_offset + off < s->cur_frame_end[i]) + break; + } + } +} + +int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, + int64_t pts, int64_t dts, int64_t pos) +{ + int index, i; + uint8_t dummy_buf[AV_INPUT_BUFFER_PADDING_SIZE]; + + av_assert1(avctx->codec_id != AV_CODEC_ID_NONE); + + /* Parsers only work for the specified codec ids. */ + av_assert1(avctx->codec_id == s->parser->codec_ids[0] || + avctx->codec_id == s->parser->codec_ids[1] || + avctx->codec_id == s->parser->codec_ids[2] || + avctx->codec_id == s->parser->codec_ids[3] || + avctx->codec_id == s->parser->codec_ids[4]); + + if (!(s->flags & PARSER_FLAG_FETCHED_OFFSET)) { + s->next_frame_offset = + s->cur_offset = pos; + s->flags |= PARSER_FLAG_FETCHED_OFFSET; + } + + if (buf_size == 0) { + /* padding is always necessary even if EOF, so we add it here */ + memset(dummy_buf, 0, sizeof(dummy_buf)); + buf = dummy_buf; + } else if (s->cur_offset + buf_size != s->cur_frame_end[s->cur_frame_start_index]) { /* skip remainder packets */ + /* add a new packet descriptor */ + i = (s->cur_frame_start_index + 1) & (AV_PARSER_PTS_NB - 1); + s->cur_frame_start_index = i; + s->cur_frame_offset[i] = s->cur_offset; + s->cur_frame_end[i] = s->cur_offset + buf_size; + s->cur_frame_pts[i] = pts; + s->cur_frame_dts[i] = dts; + s->cur_frame_pos[i] = pos; + } + + if (s->fetch_timestamp) { + s->fetch_timestamp = 0; + s->last_pts = s->pts; + s->last_dts = s->dts; + s->last_pos = s->pos; + ff_fetch_timestamp(s, 0, 0, 0); + } + /* WARNING: the returned index can be negative */ + index = s->parser->parser_parse(s, avctx, (const uint8_t **) poutbuf, + poutbuf_size, buf, buf_size); + av_assert0(index > -0x20000000); // The API does not allow returning AVERROR codes +#define FILL(name) if(s->name > 0 && avctx->name <= 0) avctx->name = s->name + if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + FILL(field_order); + } + + /* update the file pointer */ + if (*poutbuf_size) { + /* fill the data for the current frame */ + s->frame_offset = s->next_frame_offset; + + /* offset of the next frame */ + s->next_frame_offset = s->cur_offset + index; + s->fetch_timestamp = 1; + } + if (index < 0) + index = 0; + s->cur_offset += index; + return index; +} + +int av_parser_change(AVCodecParserContext *s, AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe) +{ + if (s && s->parser->split) { + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER || + avctx->flags2 & AV_CODEC_FLAG2_LOCAL_HEADER) { + int i = s->parser->split(avctx, buf, buf_size); + buf += i; + buf_size -= i; + } + } + + /* cast to avoid warning about discarding qualifiers */ + *poutbuf = (uint8_t *) buf; + *poutbuf_size = buf_size; + if (avctx->extradata) { + if (keyframe && (avctx->flags2 & AV_CODEC_FLAG2_LOCAL_HEADER)) { + int size = buf_size + avctx->extradata_size; + + *poutbuf_size = size; + *poutbuf = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!*poutbuf) + return AVERROR(ENOMEM); + + memcpy(*poutbuf, avctx->extradata, avctx->extradata_size); + memcpy(*poutbuf + avctx->extradata_size, buf, + buf_size + AV_INPUT_BUFFER_PADDING_SIZE); + return 1; + } + } + + return 0; +} + +void av_parser_close(AVCodecParserContext *s) +{ + if (s) { + if (s->parser->parser_close) + s->parser->parser_close(s); + av_freep(&s->priv_data); + av_free(s); + } +} + +int ff_combine_frame(ParseContext *pc, int next, + const uint8_t **buf, int *buf_size) +{ + if (pc->overread) { + ff_dlog(NULL, "overread %d, state:%"PRIX32" next:%d index:%d o_index:%d\n", + pc->overread, pc->state, next, pc->index, pc->overread_index); + ff_dlog(NULL, "%X %X %X %X\n", + (*buf)[0], (*buf)[1], (*buf)[2], (*buf)[3]); + } + + /* Copy overread bytes from last frame into buffer. */ + for (; pc->overread > 0; pc->overread--) + pc->buffer[pc->index++] = pc->buffer[pc->overread_index++]; + + if (next > *buf_size) + return AVERROR(EINVAL); + + /* flush remaining if EOF */ + if (!*buf_size && next == END_NOT_FOUND) + next = 0; + + pc->last_index = pc->index; + + /* copy into buffer end return */ + if (next == END_NOT_FOUND) { + void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, + *buf_size + pc->index + + AV_INPUT_BUFFER_PADDING_SIZE); + + if (!new_buffer) { + av_log(NULL, AV_LOG_ERROR, "Failed to reallocate parser buffer to %d\n", *buf_size + pc->index + AV_INPUT_BUFFER_PADDING_SIZE); + pc->index = 0; + return AVERROR(ENOMEM); + } + pc->buffer = new_buffer; + memcpy(&pc->buffer[pc->index], *buf, *buf_size); + pc->index += *buf_size; + return -1; + } + + av_assert0(next >= 0 || pc->buffer); + + *buf_size = + pc->overread_index = pc->index + next; + + /* append to buffer */ + if (pc->index) { + void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size, + next + pc->index + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!new_buffer) { + av_log(NULL, AV_LOG_ERROR, "Failed to reallocate parser buffer to %d\n", next + pc->index + AV_INPUT_BUFFER_PADDING_SIZE); + pc->overread_index = + pc->index = 0; + return AVERROR(ENOMEM); + } + pc->buffer = new_buffer; + if (next > -AV_INPUT_BUFFER_PADDING_SIZE) + memcpy(&pc->buffer[pc->index], *buf, + next + AV_INPUT_BUFFER_PADDING_SIZE); + pc->index = 0; + *buf = pc->buffer; + } + + /* store overread bytes */ + for (; next < 0; next++) { + pc->state = pc->state << 8 | pc->buffer[pc->last_index + next]; + pc->state64 = pc->state64 << 8 | pc->buffer[pc->last_index + next]; + pc->overread++; + } + + if (pc->overread) { + ff_dlog(NULL, "overread %d, state:%"PRIX32" next:%d index:%d o_index:%d\n", + pc->overread, pc->state, next, pc->index, pc->overread_index); + ff_dlog(NULL, "%X %X %X %X\n", + (*buf)[0], (*buf)[1], (*buf)[2], (*buf)[3]); + } + + return 0; +} + +void ff_parse_close(AVCodecParserContext *s) +{ + ParseContext *pc = s->priv_data; + + av_freep(&pc->buffer); +} + +int ff_mpeg4video_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size) +{ + uint32_t state = -1; + const uint8_t *ptr = buf, *end = buf + buf_size; + + while (ptr < end) { + ptr = avpriv_find_start_code(ptr, end, &state); + if (state == 0x1B3 || state == 0x1B6) + return ptr - 4 - buf; + } + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser.h new file mode 100644 index 0000000000..ef35547e9b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser.h @@ -0,0 +1,60 @@ +/* + * AVCodecParser prototypes and definitions + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_PARSER_H +#define AVCODEC_PARSER_H + +#include "avcodec.h" + +typedef struct ParseContext{ + uint8_t *buffer; + int index; + int last_index; + unsigned int buffer_size; + uint32_t state; ///< contains the last few bytes in MSB order + int frame_start_found; + int overread; ///< the number of bytes which where irreversibly read from the next frame + int overread_index; ///< the index into ParseContext.buffer of the overread bytes + uint64_t state64; ///< contains the last 8 bytes in MSB order +} ParseContext; + +#define END_NOT_FOUND (-100) + +/** + * Combine the (truncated) bitstream to a complete frame. + * @return -1 if no complete frame could be created, + * AVERROR(ENOMEM) if there was a memory allocation error + */ +int ff_combine_frame(ParseContext *pc, int next, const uint8_t **buf, int *buf_size); +int ff_mpeg4video_split(AVCodecContext *avctx, const uint8_t *buf, + int buf_size); +void ff_parse_close(AVCodecParserContext *s); + +/** + * Fetch timestamps for a specific byte within the current access unit. + * @param off byte position within the access unit + * @param remove Found timestamps will be removed if set to 1, kept if set to 0. + * @param fuzzy Only use found value if it is more informative than what we already have + */ +void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove, int fuzzy); + +#endif /* AVCODEC_PARSER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser_list.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser_list.c new file mode 100644 index 0000000000..6539d07a62 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parser_list.c @@ -0,0 +1,3 @@ +static const AVCodecParser * const parser_list[] = { + &ff_aac_latm_parser, + NULL }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parsers.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parsers.c new file mode 100644 index 0000000000..33a71de8a0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/parsers.c @@ -0,0 +1,110 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/thread.h" + +#include "avcodec.h" + +extern AVCodecParser ff_aac_parser; +extern AVCodecParser ff_aac_latm_parser; +extern AVCodecParser ff_ac3_parser; +extern AVCodecParser ff_adx_parser; +extern AVCodecParser ff_av1_parser; +extern AVCodecParser ff_avs2_parser; +extern AVCodecParser ff_bmp_parser; +extern AVCodecParser ff_cavsvideo_parser; +extern AVCodecParser ff_cook_parser; +extern AVCodecParser ff_dca_parser; +extern AVCodecParser ff_dirac_parser; +extern AVCodecParser ff_dnxhd_parser; +extern AVCodecParser ff_dpx_parser; +extern AVCodecParser ff_dvaudio_parser; +extern AVCodecParser ff_dvbsub_parser; +extern AVCodecParser ff_dvdsub_parser; +extern AVCodecParser ff_dvd_nav_parser; +extern AVCodecParser ff_flac_parser; +extern AVCodecParser ff_g723_1_parser; +extern AVCodecParser ff_g729_parser; +extern AVCodecParser ff_gif_parser; +extern AVCodecParser ff_gsm_parser; +extern AVCodecParser ff_h261_parser; +extern AVCodecParser ff_h263_parser; +extern AVCodecParser ff_h264_parser; +extern AVCodecParser ff_hevc_parser; +extern AVCodecParser ff_mjpeg_parser; +extern AVCodecParser ff_mlp_parser; +extern AVCodecParser ff_mpeg4video_parser; +extern AVCodecParser ff_mpegaudio_parser; +extern AVCodecParser ff_mpegvideo_parser; +extern AVCodecParser ff_opus_parser; +extern AVCodecParser ff_png_parser; +extern AVCodecParser ff_pnm_parser; +extern AVCodecParser ff_rv30_parser; +extern AVCodecParser ff_rv40_parser; +extern AVCodecParser ff_sbc_parser; +extern AVCodecParser ff_sipr_parser; +extern AVCodecParser ff_tak_parser; +extern AVCodecParser ff_vc1_parser; +extern AVCodecParser ff_vorbis_parser; +extern AVCodecParser ff_vp3_parser; +extern AVCodecParser ff_vp8_parser; +extern AVCodecParser ff_vp9_parser; +extern AVCodecParser ff_xma_parser; + +#include "libavcodec/parser_list.c" + +static AVOnce av_parser_next_init = AV_ONCE_INIT; + +static void av_parser_init_next(void) +{ + AVCodecParser *prev = NULL, *p; + int i = 0; + while ((p = (AVCodecParser*)parser_list[i++])) { + if (prev) + prev->next = p; + prev = p; + } +} + +AVCodecParser *av_parser_next(const AVCodecParser *p) +{ + ff_thread_once(&av_parser_next_init, av_parser_init_next); + + if (p) + return p->next; + else + return (AVCodecParser*)parser_list[0]; +} + +const AVCodecParser *av_parser_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVCodecParser *p = parser_list[i]; + + if (p) + *opaque = (void*)(i + 1); + + return p; +} + +void av_register_codec_parser(AVCodecParser *parser) +{ + ff_thread_once(&av_parser_next_init, av_parser_init_next); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pixblockdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pixblockdsp.h new file mode 100644 index 0000000000..e036700ff0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pixblockdsp.h @@ -0,0 +1,55 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_PIXBLOCKDSP_H +#define AVCODEC_PIXBLOCKDSP_H + +#include + +#include "config.h" + +#include "avcodec.h" + +typedef struct PixblockDSPContext { + void (*get_pixels)(int16_t *av_restrict block /* align 16 */, + const uint8_t *pixels /* align 8 */, + ptrdiff_t stride); + void (*diff_pixels)(int16_t *av_restrict block /* align 16 */, + const uint8_t *s1 /* align 8 */, + const uint8_t *s2 /* align 8 */, + ptrdiff_t stride); + void (*diff_pixels_unaligned)(int16_t *av_restrict block /* align 16 */, + const uint8_t *s1, + const uint8_t *s2, + ptrdiff_t stride); + +} PixblockDSPContext; + +void ff_pixblockdsp_init(PixblockDSPContext *c, AVCodecContext *avctx); +void ff_pixblockdsp_init_alpha(PixblockDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); +void ff_pixblockdsp_init_arm(PixblockDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); +void ff_pixblockdsp_init_ppc(PixblockDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); +void ff_pixblockdsp_init_x86(PixblockDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); +void ff_pixblockdsp_init_mips(PixblockDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth); + +#endif /* AVCODEC_PIXBLOCKDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/profiles.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/profiles.c new file mode 100644 index 0000000000..eaf0d68d32 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/profiles.c @@ -0,0 +1,179 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "avcodec.h" +#include "profiles.h" + +#if !CONFIG_SMALL + +const AVProfile ff_aac_profiles[] = { + { FF_PROFILE_AAC_LOW, "LC" }, + { FF_PROFILE_AAC_HE, "HE-AAC" }, + { FF_PROFILE_AAC_HE_V2, "HE-AACv2" }, + { FF_PROFILE_AAC_LD, "LD" }, + { FF_PROFILE_AAC_ELD, "ELD" }, + { FF_PROFILE_AAC_MAIN, "Main" }, + { FF_PROFILE_AAC_SSR, "SSR" }, + { FF_PROFILE_AAC_LTP, "LTP" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_dca_profiles[] = { + { FF_PROFILE_DTS, "DTS" }, + { FF_PROFILE_DTS_ES, "DTS-ES" }, + { FF_PROFILE_DTS_96_24, "DTS 96/24" }, + { FF_PROFILE_DTS_HD_HRA, "DTS-HD HRA" }, + { FF_PROFILE_DTS_HD_MA, "DTS-HD MA" }, + { FF_PROFILE_DTS_EXPRESS, "DTS Express" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_dnxhd_profiles[] = { + { FF_PROFILE_DNXHD, "DNXHD"}, + { FF_PROFILE_DNXHR_LB, "DNXHR LB"}, + { FF_PROFILE_DNXHR_SQ, "DNXHR SQ"}, + { FF_PROFILE_DNXHR_HQ, "DNXHR HQ" }, + { FF_PROFILE_DNXHR_HQX, "DNXHR HQX"}, + { FF_PROFILE_DNXHR_444, "DNXHR 444"}, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_h264_profiles[] = { + { FF_PROFILE_H264_BASELINE, "Baseline" }, + { FF_PROFILE_H264_CONSTRAINED_BASELINE, "Constrained Baseline" }, + { FF_PROFILE_H264_MAIN, "Main" }, + { FF_PROFILE_H264_EXTENDED, "Extended" }, + { FF_PROFILE_H264_HIGH, "High" }, + { FF_PROFILE_H264_HIGH_10, "High 10" }, + { FF_PROFILE_H264_HIGH_10_INTRA, "High 10 Intra" }, + { FF_PROFILE_H264_HIGH_422, "High 4:2:2" }, + { FF_PROFILE_H264_HIGH_422_INTRA, "High 4:2:2 Intra" }, + { FF_PROFILE_H264_HIGH_444, "High 4:4:4" }, + { FF_PROFILE_H264_HIGH_444_PREDICTIVE, "High 4:4:4 Predictive" }, + { FF_PROFILE_H264_HIGH_444_INTRA, "High 4:4:4 Intra" }, + { FF_PROFILE_H264_CAVLC_444, "CAVLC 4:4:4" }, + { FF_PROFILE_H264_MULTIVIEW_HIGH, "Multiview High" }, + { FF_PROFILE_H264_STEREO_HIGH, "Stereo High" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_hevc_profiles[] = { + { FF_PROFILE_HEVC_MAIN, "Main" }, + { FF_PROFILE_HEVC_MAIN_10, "Main 10" }, + { FF_PROFILE_HEVC_MAIN_STILL_PICTURE, "Main Still Picture" }, + { FF_PROFILE_HEVC_REXT, "Rext" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_jpeg2000_profiles[] = { + { FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0, "JPEG 2000 codestream restriction 0" }, + { FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1, "JPEG 2000 codestream restriction 1" }, + { FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION, "JPEG 2000 no codestream restrictions" }, + { FF_PROFILE_JPEG2000_DCINEMA_2K, "JPEG 2000 digital cinema 2K" }, + { FF_PROFILE_JPEG2000_DCINEMA_4K, "JPEG 2000 digital cinema 4K" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_mpeg2_video_profiles[] = { + { FF_PROFILE_MPEG2_422, "4:2:2" }, + { FF_PROFILE_MPEG2_HIGH, "High" }, + { FF_PROFILE_MPEG2_SS, "Spatially Scalable" }, + { FF_PROFILE_MPEG2_SNR_SCALABLE, "SNR Scalable" }, + { FF_PROFILE_MPEG2_MAIN, "Main" }, + { FF_PROFILE_MPEG2_SIMPLE, "Simple" }, + { FF_PROFILE_RESERVED, "Reserved" }, + { FF_PROFILE_RESERVED, "Reserved" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_mpeg4_video_profiles[] = { + { FF_PROFILE_MPEG4_SIMPLE, "Simple Profile" }, + { FF_PROFILE_MPEG4_SIMPLE_SCALABLE, "Simple Scalable Profile" }, + { FF_PROFILE_MPEG4_CORE, "Core Profile" }, + { FF_PROFILE_MPEG4_MAIN, "Main Profile" }, + { FF_PROFILE_MPEG4_N_BIT, "N-bit Profile" }, + { FF_PROFILE_MPEG4_SCALABLE_TEXTURE, "Scalable Texture Profile" }, + { FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION, "Simple Face Animation Profile" }, + { FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE, "Basic Animated Texture Profile" }, + { FF_PROFILE_MPEG4_HYBRID, "Hybrid Profile" }, + { FF_PROFILE_MPEG4_ADVANCED_REAL_TIME, "Advanced Real Time Simple Profile" }, + { FF_PROFILE_MPEG4_CORE_SCALABLE, "Code Scalable Profile" }, + { FF_PROFILE_MPEG4_ADVANCED_CODING, "Advanced Coding Profile" }, + { FF_PROFILE_MPEG4_ADVANCED_CORE, "Advanced Core Profile" }, + { FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE, "Advanced Scalable Texture Profile" }, + { FF_PROFILE_MPEG4_SIMPLE_STUDIO, "Simple Studio Profile" }, + { FF_PROFILE_MPEG4_ADVANCED_SIMPLE, "Advanced Simple Profile" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_vc1_profiles[] = { + { FF_PROFILE_VC1_SIMPLE, "Simple" }, + { FF_PROFILE_VC1_MAIN, "Main" }, + { FF_PROFILE_VC1_COMPLEX, "Complex" }, + { FF_PROFILE_VC1_ADVANCED, "Advanced" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_vp9_profiles[] = { + { FF_PROFILE_VP9_0, "Profile 0" }, + { FF_PROFILE_VP9_1, "Profile 1" }, + { FF_PROFILE_VP9_2, "Profile 2" }, + { FF_PROFILE_VP9_3, "Profile 3" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_av1_profiles[] = { + { FF_PROFILE_AV1_MAIN, "Main" }, + { FF_PROFILE_AV1_HIGH, "High" }, + { FF_PROFILE_AV1_PROFESSIONAL, "Professional" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_sbc_profiles[] = { + { FF_PROFILE_SBC_MSBC, "mSBC" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_prores_profiles[] = { + { FF_PROFILE_PRORES_PROXY, "Proxy" }, + { FF_PROFILE_PRORES_LT, "LT" }, + { FF_PROFILE_PRORES_STANDARD, "Standard" }, + { FF_PROFILE_PRORES_HQ, "HQ" }, + { FF_PROFILE_PRORES_4444, "4444" }, + { FF_PROFILE_PRORES_XQ, "XQ" }, + { FF_PROFILE_UNKNOWN } +}; + +const AVProfile ff_mjpeg_profiles[] = { + { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, "Baseline" }, + { FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT, "Sequential" }, + { FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT, "Progressive" }, + { FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS, "Lossless" }, + { FF_PROFILE_MJPEG_JPEG_LS, "JPEG LS" }, + { FF_PROFILE_UNKNOWN } +}; + +const AVProfile ff_arib_caption_profiles[] = { + { FF_PROFILE_ARIB_PROFILE_A, "Profile A" }, + { FF_PROFILE_ARIB_PROFILE_C, "Profile C" }, + { FF_PROFILE_UNKNOWN } +}; + +#endif /* !CONFIG_SMALL */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/profiles.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/profiles.h new file mode 100644 index 0000000000..a53b67e7f2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/profiles.h @@ -0,0 +1,40 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_PROFILES_H +#define AVCODEC_PROFILES_H + +#include "avcodec.h" + +extern const AVProfile ff_aac_profiles[]; +extern const AVProfile ff_dca_profiles[]; +extern const AVProfile ff_dnxhd_profiles[]; +extern const AVProfile ff_h264_profiles[]; +extern const AVProfile ff_hevc_profiles[]; +extern const AVProfile ff_jpeg2000_profiles[]; +extern const AVProfile ff_mpeg2_video_profiles[]; +extern const AVProfile ff_mpeg4_video_profiles[]; +extern const AVProfile ff_vc1_profiles[]; +extern const AVProfile ff_vp9_profiles[]; +extern const AVProfile ff_av1_profiles[]; +extern const AVProfile ff_sbc_profiles[]; +extern const AVProfile ff_prores_profiles[]; +extern const AVProfile ff_mjpeg_profiles[]; +extern const AVProfile ff_arib_caption_profiles[]; + +#endif /* AVCODEC_PROFILES_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/psymodel.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/psymodel.c new file mode 100644 index 0000000000..2b5f111fbe --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/psymodel.c @@ -0,0 +1,161 @@ +/* + * audio encoder psychoacoustic model + * Copyright (C) 2008 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "avcodec.h" +#include "psymodel.h" +#include "iirfilter.h" +#include "libavutil/mem.h" + +extern const FFPsyModel ff_aac_psy_model; + +av_cold int ff_psy_init(FFPsyContext *ctx, AVCodecContext *avctx, int num_lens, + const uint8_t **bands, const int* num_bands, + int num_groups, const uint8_t *group_map) +{ + int i, j, k = 0; + + ctx->avctx = avctx; + ctx->ch = av_mallocz_array(sizeof(ctx->ch[0]), avctx->channels * 2); + ctx->group = av_mallocz_array(sizeof(ctx->group[0]), num_groups); + ctx->bands = av_malloc_array (sizeof(ctx->bands[0]), num_lens); + ctx->num_bands = av_malloc_array (sizeof(ctx->num_bands[0]), num_lens); + ctx->cutoff = avctx->cutoff; + + if (!ctx->ch || !ctx->group || !ctx->bands || !ctx->num_bands) { + ff_psy_end(ctx); + return AVERROR(ENOMEM); + } + + memcpy(ctx->bands, bands, sizeof(ctx->bands[0]) * num_lens); + memcpy(ctx->num_bands, num_bands, sizeof(ctx->num_bands[0]) * num_lens); + + /* assign channels to groups (with virtual channels for coupling) */ + for (i = 0; i < num_groups; i++) { + /* NOTE: Add 1 to handle the AAC chan_config without modification. + * This has the side effect of allowing an array of 0s to map + * to one channel per group. + */ + ctx->group[i].num_ch = group_map[i] + 1; + for (j = 0; j < ctx->group[i].num_ch * 2; j++) + ctx->group[i].ch[j] = &ctx->ch[k++]; + } + + switch (ctx->avctx->codec_id) { + case AV_CODEC_ID_AAC: + ctx->model = &ff_aac_psy_model; + break; + } + if (ctx->model->init) + return ctx->model->init(ctx); + return 0; +} + +FFPsyChannelGroup *ff_psy_find_group(FFPsyContext *ctx, int channel) +{ + int i = 0, ch = 0; + + while (ch <= channel) + ch += ctx->group[i++].num_ch; + + return &ctx->group[i-1]; +} + +av_cold void ff_psy_end(FFPsyContext *ctx) +{ + if (ctx->model && ctx->model->end) + ctx->model->end(ctx); + av_freep(&ctx->bands); + av_freep(&ctx->num_bands); + av_freep(&ctx->group); + av_freep(&ctx->ch); +} + +typedef struct FFPsyPreprocessContext{ + AVCodecContext *avctx; + float stereo_att; + struct FFIIRFilterCoeffs *fcoeffs; + struct FFIIRFilterState **fstate; + struct FFIIRFilterContext fiir; +}FFPsyPreprocessContext; + +#define FILT_ORDER 4 + +av_cold struct FFPsyPreprocessContext* ff_psy_preprocess_init(AVCodecContext *avctx) +{ + FFPsyPreprocessContext *ctx; + int i; + float cutoff_coeff = 0; + ctx = av_mallocz(sizeof(FFPsyPreprocessContext)); + if (!ctx) + return NULL; + ctx->avctx = avctx; + + /* AAC has its own LP method */ + if (avctx->codec_id != AV_CODEC_ID_AAC) { + if (avctx->cutoff > 0) + cutoff_coeff = 2.0 * avctx->cutoff / avctx->sample_rate; + + if (cutoff_coeff && cutoff_coeff < 0.98) + ctx->fcoeffs = ff_iir_filter_init_coeffs(avctx, FF_FILTER_TYPE_BUTTERWORTH, + FF_FILTER_MODE_LOWPASS, FILT_ORDER, + cutoff_coeff, 0.0, 0.0); + if (ctx->fcoeffs) { + ctx->fstate = av_mallocz_array(sizeof(ctx->fstate[0]), avctx->channels); + if (!ctx->fstate) { + av_free(ctx->fcoeffs); + av_free(ctx); + return NULL; + } + for (i = 0; i < avctx->channels; i++) + ctx->fstate[i] = ff_iir_filter_init_state(FILT_ORDER); + } + } + + ff_iir_filter_init(&ctx->fiir); + + return ctx; +} + +void ff_psy_preprocess(struct FFPsyPreprocessContext *ctx, float **audio, int channels) +{ + int ch; + int frame_size = ctx->avctx->frame_size; + FFIIRFilterContext *iir = &ctx->fiir; + + if (ctx->fstate) { + for (ch = 0; ch < channels; ch++) + iir->filter_flt(ctx->fcoeffs, ctx->fstate[ch], frame_size, + &audio[ch][frame_size], 1, &audio[ch][frame_size], 1); + } +} + +av_cold void ff_psy_preprocess_end(struct FFPsyPreprocessContext *ctx) +{ + int i; + ff_iir_filter_free_coeffsp(&ctx->fcoeffs); + if (ctx->fstate) + for (i = 0; i < ctx->avctx->channels; i++) + ff_iir_filter_free_statep(&ctx->fstate[i]); + av_freep(&ctx->fstate); + av_free(ctx); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/psymodel.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/psymodel.h new file mode 100644 index 0000000000..e5f917d495 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/psymodel.h @@ -0,0 +1,204 @@ +/* + * audio encoder psychoacoustic model + * Copyright (C) 2008 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_PSYMODEL_H +#define AVCODEC_PSYMODEL_H + +#include "avcodec.h" + +/** maximum possible number of bands */ +#define PSY_MAX_BANDS 128 +/** maximum number of channels */ +#define PSY_MAX_CHANS 20 + +/* cutoff for VBR is purposely increased, since LP filtering actually + * hinders VBR performance rather than the opposite + */ +#define AAC_CUTOFF_FROM_BITRATE(bit_rate,channels,sample_rate) (bit_rate ? FFMIN3(FFMIN3( \ + FFMAX(bit_rate/channels/5, bit_rate/channels*15/32 - 5500), \ + 3000 + bit_rate/channels/4, \ + 12000 + bit_rate/channels/16), \ + 22000, \ + sample_rate / 2): (sample_rate / 2)) +#define AAC_CUTOFF(s) ( \ + (s->flags & AV_CODEC_FLAG_QSCALE) \ + ? s->sample_rate / 2 \ + : AAC_CUTOFF_FROM_BITRATE(s->bit_rate, s->channels, s->sample_rate) \ +) + +/** + * single band psychoacoustic information + */ +typedef struct FFPsyBand { + int bits; + float energy; + float threshold; + float spread; /* Energy spread over the band */ +} FFPsyBand; + +/** + * single channel psychoacoustic information + */ +typedef struct FFPsyChannel { + FFPsyBand psy_bands[PSY_MAX_BANDS]; ///< channel bands information + float entropy; ///< total PE for this channel +} FFPsyChannel; + +/** + * psychoacoustic information for an arbitrary group of channels + */ +typedef struct FFPsyChannelGroup { + FFPsyChannel *ch[PSY_MAX_CHANS]; ///< pointers to the individual channels in the group + uint8_t num_ch; ///< number of channels in this group + uint8_t coupling[PSY_MAX_BANDS]; ///< allow coupling for this band in the group +} FFPsyChannelGroup; + +/** + * windowing related information + */ +typedef struct FFPsyWindowInfo { + int window_type[3]; ///< window type (short/long/transitional, etc.) - current, previous and next + int window_shape; ///< window shape (sine/KBD/whatever) + int num_windows; ///< number of windows in a frame + int grouping[8]; ///< window grouping (for e.g. AAC) + float clipping[8]; ///< maximum absolute normalized intensity in the given window for clip avoidance + int *window_sizes; ///< sequence of window sizes inside one frame (for eg. WMA) +} FFPsyWindowInfo; + +/** + * context used by psychoacoustic model + */ +typedef struct FFPsyContext { + AVCodecContext *avctx; ///< encoder context + const struct FFPsyModel *model; ///< encoder-specific model functions + + FFPsyChannel *ch; ///< single channel information + FFPsyChannelGroup *group; ///< channel group information + int num_groups; ///< number of channel groups + int cutoff; ///< lowpass frequency cutoff for analysis + + uint8_t **bands; ///< scalefactor band sizes for possible frame sizes + int *num_bands; ///< number of scalefactor bands for possible frame sizes + int num_lens; ///< number of scalefactor band sets + + struct { + int size; ///< size of the bitresevoir in bits + int bits; ///< number of bits used in the bitresevoir + int alloc; ///< number of bits allocated by the psy, or -1 if no allocation was done + } bitres; + + void* model_priv_data; ///< psychoacoustic model implementation private data +} FFPsyContext; + +/** + * codec-specific psychoacoustic model implementation + */ +typedef struct FFPsyModel { + const char *name; + int (*init) (FFPsyContext *apc); + + /** + * Suggest window sequence for channel. + * + * @param ctx model context + * @param audio samples for the current frame + * @param la lookahead samples (NULL when unavailable) + * @param channel number of channel element to analyze + * @param prev_type previous window type + * + * @return suggested window information in a structure + */ + FFPsyWindowInfo (*window)(FFPsyContext *ctx, const float *audio, const float *la, int channel, int prev_type); + + /** + * Perform psychoacoustic analysis and set band info (threshold, energy) for a group of channels. + * + * @param ctx model context + * @param channel channel number of the first channel in the group to perform analysis on + * @param coeffs array of pointers to the transformed coefficients + * @param wi window information for the channels in the group + */ + void (*analyze)(FFPsyContext *ctx, int channel, const float **coeffs, const FFPsyWindowInfo *wi); + + void (*end) (FFPsyContext *apc); +} FFPsyModel; + +/** + * Initialize psychoacoustic model. + * + * @param ctx model context + * @param avctx codec context + * @param num_lens number of possible frame lengths + * @param bands scalefactor band lengths for all frame lengths + * @param num_bands number of scalefactor bands for all frame lengths + * @param num_groups number of channel groups + * @param group_map array with # of channels in group - 1, for each group + * + * @return zero if successful, a negative value if not + */ +int ff_psy_init(FFPsyContext *ctx, AVCodecContext *avctx, int num_lens, + const uint8_t **bands, const int *num_bands, + int num_groups, const uint8_t *group_map); + +/** + * Determine what group a channel belongs to. + * + * @param ctx psymodel context + * @param channel channel to locate the group for + * + * @return pointer to the FFPsyChannelGroup this channel belongs to + */ +FFPsyChannelGroup *ff_psy_find_group(FFPsyContext *ctx, int channel); + +/** + * Cleanup model context at the end. + * + * @param ctx model context + */ +void ff_psy_end(FFPsyContext *ctx); + + +/************************************************************************** + * Audio preprocessing stuff. * + * This should be moved into some audio filter eventually. * + **************************************************************************/ +struct FFPsyPreprocessContext; + +/** + * psychoacoustic model audio preprocessing initialization + */ +struct FFPsyPreprocessContext *ff_psy_preprocess_init(AVCodecContext *avctx); + +/** + * Preprocess several channel in audio frame in order to compress it better. + * + * @param ctx preprocessing context + * @param audio samples to be filtered (in place) + * @param channels number of channel to preprocess + */ +void ff_psy_preprocess(struct FFPsyPreprocessContext *ctx, float **audio, int channels); + +/** + * Cleanup audio preprocessing module. + */ +void ff_psy_preprocess_end(struct FFPsyPreprocessContext *ctx); + +#endif /* AVCODEC_PSYMODEL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread.c new file mode 100644 index 0000000000..572471586d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2004 Roman Shaposhnik + * Copyright (c) 2008 Alexander Strange (astrange@ithinksw.com) + * + * Many thanks to Steven M. Schultz for providing clever ideas and + * to Michael Niedermayer for writing initial + * implementation. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Multithreading support functions + * @see doc/multithreading.txt + */ + +#include "avcodec.h" +#include "internal.h" +#include "pthread_internal.h" +#include "thread.h" + +/** + * Set the threading algorithms used. + * + * Threading requires more than one thread. + * Frame threading requires entire frames to be passed to the codec, + * and introduces extra decoding delay, so is incompatible with low_delay. + * + * @param avctx The context. + */ +static void validate_thread_parameters(AVCodecContext *avctx) +{ + int frame_threading_supported = (avctx->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS) + && !(avctx->flags & AV_CODEC_FLAG_TRUNCATED) + && !(avctx->flags & AV_CODEC_FLAG_LOW_DELAY) + && !(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS); + if (avctx->thread_count == 1) { + avctx->active_thread_type = 0; + } else if (frame_threading_supported && (avctx->thread_type & FF_THREAD_FRAME)) { + avctx->active_thread_type = FF_THREAD_FRAME; + } else if (avctx->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS && + avctx->thread_type & FF_THREAD_SLICE) { + avctx->active_thread_type = FF_THREAD_SLICE; + } else if (!(avctx->codec->capabilities & AV_CODEC_CAP_AUTO_THREADS)) { + avctx->thread_count = 1; + avctx->active_thread_type = 0; + } + + if (avctx->thread_count > MAX_AUTO_THREADS) + av_log(avctx, AV_LOG_WARNING, + "Application has requested %d threads. Using a thread count greater than %d is not recommended.\n", + avctx->thread_count, MAX_AUTO_THREADS); +} + +int ff_thread_init(AVCodecContext *avctx) +{ + validate_thread_parameters(avctx); + + if (avctx->active_thread_type&FF_THREAD_SLICE) + return ff_slice_thread_init(avctx); + else if (avctx->active_thread_type&FF_THREAD_FRAME) + return ff_frame_thread_init(avctx); + + return 0; +} + +void ff_thread_free(AVCodecContext *avctx) +{ + if (avctx->active_thread_type&FF_THREAD_FRAME) + ff_frame_thread_free(avctx, avctx->thread_count); + else + ff_slice_thread_free(avctx); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_frame.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_frame.c new file mode 100644 index 0000000000..36ac0ac1e5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_frame.c @@ -0,0 +1,1013 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Frame multithreading support functions + * @see doc/multithreading.txt + */ + +#include "config.h" + +#include +#include + +#include "avcodec.h" +#include "hwaccel.h" +#include "internal.h" +#include "pthread_internal.h" +#include "thread.h" +#include "version.h" + +#include "libavutil/avassert.h" +#include "libavutil/buffer.h" +#include "libavutil/common.h" +#include "libavutil/cpu.h" +#include "libavutil/frame.h" +#include "libavutil/internal.h" +#include "libavutil/log.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/thread.h" + +enum { + ///< Set when the thread is awaiting a packet. + STATE_INPUT_READY, + ///< Set before the codec has called ff_thread_finish_setup(). + STATE_SETTING_UP, + /** + * Set when the codec calls get_buffer(). + * State is returned to STATE_SETTING_UP afterwards. + */ + STATE_GET_BUFFER, + /** + * Set when the codec calls get_format(). + * State is returned to STATE_SETTING_UP afterwards. + */ + STATE_GET_FORMAT, + ///< Set after the codec has called ff_thread_finish_setup(). + STATE_SETUP_FINISHED, +}; + +/** + * Context used by codec threads and stored in their AVCodecInternal thread_ctx. + */ +typedef struct PerThreadContext { + struct FrameThreadContext *parent; + + pthread_t thread; + int thread_init; + pthread_cond_t input_cond; ///< Used to wait for a new packet from the main thread. + pthread_cond_t progress_cond; ///< Used by child threads to wait for progress to change. + pthread_cond_t output_cond; ///< Used by the main thread to wait for frames to finish. + + pthread_mutex_t mutex; ///< Mutex used to protect the contents of the PerThreadContext. + pthread_mutex_t progress_mutex; ///< Mutex used to protect frame progress values and progress_cond. + + AVCodecContext *avctx; ///< Context used to decode packets passed to this thread. + + AVPacket avpkt; ///< Input packet (for decoding) or output (for encoding). + + AVFrame *frame; ///< Output frame (for decoding) or input (for encoding). + int got_frame; ///< The output of got_picture_ptr from the last avcodec_decode_video() call. + int result; ///< The result of the last codec decode/encode() call. + + atomic_int state; + + /** + * Array of frames passed to ff_thread_release_buffer(). + * Frames are released after all threads referencing them are finished. + */ + AVFrame *released_buffers; + int num_released_buffers; + int released_buffers_allocated; + + AVFrame *requested_frame; ///< AVFrame the codec passed to get_buffer() + int requested_flags; ///< flags passed to get_buffer() for requested_frame + + const enum AVPixelFormat *available_formats; ///< Format array for get_format() + enum AVPixelFormat result_format; ///< get_format() result + + int die; ///< Set when the thread should exit. + + int hwaccel_serializing; + int async_serializing; + + atomic_int debug_threads; ///< Set if the FF_DEBUG_THREADS option is set. +} PerThreadContext; + +/** + * Context stored in the client AVCodecInternal thread_ctx. + */ +typedef struct FrameThreadContext { + PerThreadContext *threads; ///< The contexts for each thread. + PerThreadContext *prev_thread; ///< The last thread submit_packet() was called on. + + pthread_mutex_t buffer_mutex; ///< Mutex used to protect get/release_buffer(). + /** + * This lock is used for ensuring threads run in serial when hwaccel + * is used. + */ + pthread_mutex_t hwaccel_mutex; + pthread_mutex_t async_mutex; + pthread_cond_t async_cond; + int async_lock; + + int next_decoding; ///< The next context to submit a packet to. + int next_finished; ///< The next context to return output from. + + int delaying; /**< + * Set for the first N packets, where N is the number of threads. + * While it is set, ff_thread_en/decode_frame won't return any results. + */ +} FrameThreadContext; + +#define THREAD_SAFE_CALLBACKS(avctx) \ +((avctx)->thread_safe_callbacks || (avctx)->get_buffer2 == avcodec_default_get_buffer2) + +static void async_lock(FrameThreadContext *fctx) +{ + pthread_mutex_lock(&fctx->async_mutex); + while (fctx->async_lock) + pthread_cond_wait(&fctx->async_cond, &fctx->async_mutex); + fctx->async_lock = 1; + pthread_mutex_unlock(&fctx->async_mutex); +} + +static void async_unlock(FrameThreadContext *fctx) +{ + pthread_mutex_lock(&fctx->async_mutex); + av_assert0(fctx->async_lock); + fctx->async_lock = 0; + pthread_cond_broadcast(&fctx->async_cond); + pthread_mutex_unlock(&fctx->async_mutex); +} + +/** + * Codec worker thread. + * + * Automatically calls ff_thread_finish_setup() if the codec does + * not provide an update_thread_context method, or if the codec returns + * before calling it. + */ +static attribute_align_arg void *frame_worker_thread(void *arg) +{ + PerThreadContext *p = arg; + AVCodecContext *avctx = p->avctx; + const AVCodec *codec = avctx->codec; + + pthread_mutex_lock(&p->mutex); + while (1) { + while (atomic_load(&p->state) == STATE_INPUT_READY && !p->die) + pthread_cond_wait(&p->input_cond, &p->mutex); + + if (p->die) break; + + if (!codec->update_thread_context && THREAD_SAFE_CALLBACKS(avctx)) + ff_thread_finish_setup(avctx); + + /* If a decoder supports hwaccel, then it must call ff_get_format(). + * Since that call must happen before ff_thread_finish_setup(), the + * decoder is required to implement update_thread_context() and call + * ff_thread_finish_setup() manually. Therefore the above + * ff_thread_finish_setup() call did not happen and hwaccel_serializing + * cannot be true here. */ + av_assert0(!p->hwaccel_serializing); + + /* if the previous thread uses hwaccel then we take the lock to ensure + * the threads don't run concurrently */ + if (avctx->hwaccel) { + pthread_mutex_lock(&p->parent->hwaccel_mutex); + p->hwaccel_serializing = 1; + } + + av_frame_unref(p->frame); + p->got_frame = 0; + p->result = codec->decode(avctx, p->frame, &p->got_frame, &p->avpkt); + + if ((p->result < 0 || !p->got_frame) && p->frame->buf[0]) { + if (avctx->internal->allocate_progress) + av_log(avctx, AV_LOG_ERROR, "A frame threaded decoder did not " + "free the frame on failure. This is a bug, please report it.\n"); + av_frame_unref(p->frame); + } + + if (atomic_load(&p->state) == STATE_SETTING_UP) + ff_thread_finish_setup(avctx); + + if (p->hwaccel_serializing) { + p->hwaccel_serializing = 0; + pthread_mutex_unlock(&p->parent->hwaccel_mutex); + } + + if (p->async_serializing) { + p->async_serializing = 0; + + async_unlock(p->parent); + } + + pthread_mutex_lock(&p->progress_mutex); + + atomic_store(&p->state, STATE_INPUT_READY); + + pthread_cond_broadcast(&p->progress_cond); + pthread_cond_signal(&p->output_cond); + pthread_mutex_unlock(&p->progress_mutex); + } + pthread_mutex_unlock(&p->mutex); + + return NULL; +} + +/** + * Update the next thread's AVCodecContext with values from the reference thread's context. + * + * @param dst The destination context. + * @param src The source context. + * @param for_user 0 if the destination is a codec thread, 1 if the destination is the user's thread + * @return 0 on success, negative error code on failure + */ +static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, int for_user) +{ + int err = 0; + + if (dst != src && (for_user || !(src->codec_descriptor->props & AV_CODEC_PROP_INTRA_ONLY))) { + dst->time_base = src->time_base; + dst->framerate = src->framerate; + dst->width = src->width; + dst->height = src->height; + dst->pix_fmt = src->pix_fmt; + dst->sw_pix_fmt = src->sw_pix_fmt; + + dst->coded_width = src->coded_width; + dst->coded_height = src->coded_height; + + dst->has_b_frames = src->has_b_frames; + dst->idct_algo = src->idct_algo; + + dst->bits_per_coded_sample = src->bits_per_coded_sample; + dst->sample_aspect_ratio = src->sample_aspect_ratio; + + dst->profile = src->profile; + dst->level = src->level; + + dst->bits_per_raw_sample = src->bits_per_raw_sample; + dst->ticks_per_frame = src->ticks_per_frame; + dst->color_primaries = src->color_primaries; + + dst->color_trc = src->color_trc; + dst->colorspace = src->colorspace; + dst->color_range = src->color_range; + dst->chroma_sample_location = src->chroma_sample_location; + + dst->hwaccel = src->hwaccel; + dst->hwaccel_context = src->hwaccel_context; + + dst->channels = src->channels; + dst->sample_rate = src->sample_rate; + dst->sample_fmt = src->sample_fmt; + dst->channel_layout = src->channel_layout; + dst->internal->hwaccel_priv_data = src->internal->hwaccel_priv_data; + + if (!!dst->hw_frames_ctx != !!src->hw_frames_ctx || + (dst->hw_frames_ctx && dst->hw_frames_ctx->data != src->hw_frames_ctx->data)) { + av_buffer_unref(&dst->hw_frames_ctx); + + if (src->hw_frames_ctx) { + dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx); + if (!dst->hw_frames_ctx) + return AVERROR(ENOMEM); + } + } + + dst->hwaccel_flags = src->hwaccel_flags; + } + + if (for_user) { + dst->delay = src->thread_count - 1; +#if FF_API_CODED_FRAME +FF_DISABLE_DEPRECATION_WARNINGS + dst->coded_frame = src->coded_frame; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + } else { + if (dst->codec->update_thread_context) + err = dst->codec->update_thread_context(dst, src); + } + + return err; +} + +/** + * Update the next thread's AVCodecContext with values set by the user. + * + * @param dst The destination context. + * @param src The source context. + * @return 0 on success, negative error code on failure + */ +static int update_context_from_user(AVCodecContext *dst, AVCodecContext *src) +{ +#define copy_fields(s, e) memcpy(&dst->s, &src->s, (char*)&dst->e - (char*)&dst->s); + dst->flags = src->flags; + + dst->draw_horiz_band= src->draw_horiz_band; + dst->get_buffer2 = src->get_buffer2; + + dst->opaque = src->opaque; + dst->debug = src->debug; + dst->debug_mv = src->debug_mv; + + dst->slice_flags = src->slice_flags; + dst->flags2 = src->flags2; + + copy_fields(skip_loop_filter, subtitle_header); + + dst->frame_number = src->frame_number; + dst->reordered_opaque = src->reordered_opaque; + dst->thread_safe_callbacks = src->thread_safe_callbacks; + + if (src->slice_count && src->slice_offset) { + if (dst->slice_count < src->slice_count) { + int err = av_reallocp_array(&dst->slice_offset, src->slice_count, + sizeof(*dst->slice_offset)); + if (err < 0) + return err; + } + memcpy(dst->slice_offset, src->slice_offset, + src->slice_count * sizeof(*dst->slice_offset)); + } + dst->slice_count = src->slice_count; + return 0; +#undef copy_fields +} + +/// Releases the buffers that this decoding thread was the last user of. +static void release_delayed_buffers(PerThreadContext *p) +{ + FrameThreadContext *fctx = p->parent; + + while (p->num_released_buffers > 0) { + AVFrame *f; + + pthread_mutex_lock(&fctx->buffer_mutex); + + // fix extended data in case the caller screwed it up + av_assert0(p->avctx->codec_type == AVMEDIA_TYPE_VIDEO || + p->avctx->codec_type == AVMEDIA_TYPE_AUDIO); + f = &p->released_buffers[--p->num_released_buffers]; + f->extended_data = f->data; + av_frame_unref(f); + + pthread_mutex_unlock(&fctx->buffer_mutex); + } +} + +static int submit_packet(PerThreadContext *p, AVCodecContext *user_avctx, + AVPacket *avpkt) +{ + FrameThreadContext *fctx = p->parent; + PerThreadContext *prev_thread = fctx->prev_thread; + const AVCodec *codec = p->avctx->codec; + int ret; + + if (!avpkt->size && !(codec->capabilities & AV_CODEC_CAP_DELAY)) + return 0; + + pthread_mutex_lock(&p->mutex); + + ret = update_context_from_user(p->avctx, user_avctx); + if (ret) { + pthread_mutex_unlock(&p->mutex); + return ret; + } + atomic_store_explicit(&p->debug_threads, + (p->avctx->debug & FF_DEBUG_THREADS) != 0, + memory_order_relaxed); + + release_delayed_buffers(p); + + if (prev_thread) { + int err; + if (atomic_load(&prev_thread->state) == STATE_SETTING_UP) { + pthread_mutex_lock(&prev_thread->progress_mutex); + while (atomic_load(&prev_thread->state) == STATE_SETTING_UP) + pthread_cond_wait(&prev_thread->progress_cond, &prev_thread->progress_mutex); + pthread_mutex_unlock(&prev_thread->progress_mutex); + } + + err = update_context_from_thread(p->avctx, prev_thread->avctx, 0); + if (err) { + pthread_mutex_unlock(&p->mutex); + return err; + } + } + + av_packet_unref(&p->avpkt); + ret = av_packet_ref(&p->avpkt, avpkt); + if (ret < 0) { + pthread_mutex_unlock(&p->mutex); + av_log(p->avctx, AV_LOG_ERROR, "av_packet_ref() failed in submit_packet()\n"); + return ret; + } + + atomic_store(&p->state, STATE_SETTING_UP); + pthread_cond_signal(&p->input_cond); + pthread_mutex_unlock(&p->mutex); + + /* + * If the client doesn't have a thread-safe get_buffer(), + * then decoding threads call back to the main thread, + * and it calls back to the client here. + */ + + if (!p->avctx->thread_safe_callbacks && ( + p->avctx->get_format != avcodec_default_get_format || + p->avctx->get_buffer2 != avcodec_default_get_buffer2)) { + while (atomic_load(&p->state) != STATE_SETUP_FINISHED && atomic_load(&p->state) != STATE_INPUT_READY) { + int call_done = 1; + pthread_mutex_lock(&p->progress_mutex); + while (atomic_load(&p->state) == STATE_SETTING_UP) + pthread_cond_wait(&p->progress_cond, &p->progress_mutex); + + switch (atomic_load_explicit(&p->state, memory_order_acquire)) { + case STATE_GET_BUFFER: + p->result = ff_get_buffer(p->avctx, p->requested_frame, p->requested_flags); + break; + case STATE_GET_FORMAT: + p->result_format = ff_get_format(p->avctx, p->available_formats); + break; + default: + call_done = 0; + break; + } + if (call_done) { + atomic_store(&p->state, STATE_SETTING_UP); + pthread_cond_signal(&p->progress_cond); + } + pthread_mutex_unlock(&p->progress_mutex); + } + } + + fctx->prev_thread = p; + fctx->next_decoding++; + + return 0; +} + +int ff_thread_decode_frame(AVCodecContext *avctx, + AVFrame *picture, int *got_picture_ptr, + AVPacket *avpkt) +{ + FrameThreadContext *fctx = avctx->internal->thread_ctx; + int finished = fctx->next_finished; + PerThreadContext *p; + int err; + + /* release the async lock, permitting blocked hwaccel threads to + * go forward while we are in this function */ + async_unlock(fctx); + + /* + * Submit a packet to the next decoding thread. + */ + + p = &fctx->threads[fctx->next_decoding]; + err = submit_packet(p, avctx, avpkt); + if (err) + goto finish; + + /* + * If we're still receiving the initial packets, don't return a frame. + */ + + if (fctx->next_decoding > (avctx->thread_count-1-(avctx->codec_id == AV_CODEC_ID_FFV1))) + fctx->delaying = 0; + + if (fctx->delaying) { + *got_picture_ptr=0; + if (avpkt->size) { + err = avpkt->size; + goto finish; + } + } + + /* + * Return the next available frame from the oldest thread. + * If we're at the end of the stream, then we have to skip threads that + * didn't output a frame/error, because we don't want to accidentally signal + * EOF (avpkt->size == 0 && *got_picture_ptr == 0 && err >= 0). + */ + + do { + p = &fctx->threads[finished++]; + + if (atomic_load(&p->state) != STATE_INPUT_READY) { + pthread_mutex_lock(&p->progress_mutex); + while (atomic_load_explicit(&p->state, memory_order_relaxed) != STATE_INPUT_READY) + pthread_cond_wait(&p->output_cond, &p->progress_mutex); + pthread_mutex_unlock(&p->progress_mutex); + } + + av_frame_move_ref(picture, p->frame); + *got_picture_ptr = p->got_frame; + picture->pkt_dts = p->avpkt.dts; + err = p->result; + + /* + * A later call with avkpt->size == 0 may loop over all threads, + * including this one, searching for a frame/error to return before being + * stopped by the "finished != fctx->next_finished" condition. + * Make sure we don't mistakenly return the same frame/error again. + */ + p->got_frame = 0; + p->result = 0; + + if (finished >= avctx->thread_count) finished = 0; + } while (!avpkt->size && !*got_picture_ptr && err >= 0 && finished != fctx->next_finished); + + update_context_from_thread(avctx, p->avctx, 1); + + if (fctx->next_decoding >= avctx->thread_count) fctx->next_decoding = 0; + + fctx->next_finished = finished; + + /* return the size of the consumed packet if no error occurred */ + if (err >= 0) + err = avpkt->size; +finish: + async_lock(fctx); + return err; +} + +void ff_thread_report_progress(ThreadFrame *f, int n, int field) +{ + PerThreadContext *p; + atomic_int *progress = f->progress ? (atomic_int*)f->progress->data : NULL; + + if (!progress || + atomic_load_explicit(&progress[field], memory_order_relaxed) >= n) + return; + + p = f->owner[field]->internal->thread_ctx; + + if (atomic_load_explicit(&p->debug_threads, memory_order_relaxed)) + av_log(f->owner[field], AV_LOG_DEBUG, + "%p finished %d field %d\n", progress, n, field); + + pthread_mutex_lock(&p->progress_mutex); + + atomic_store_explicit(&progress[field], n, memory_order_release); + + pthread_cond_broadcast(&p->progress_cond); + pthread_mutex_unlock(&p->progress_mutex); +} + +void ff_thread_await_progress(ThreadFrame *f, int n, int field) +{ + PerThreadContext *p; + atomic_int *progress = f->progress ? (atomic_int*)f->progress->data : NULL; + + if (!progress || + atomic_load_explicit(&progress[field], memory_order_acquire) >= n) + return; + + p = f->owner[field]->internal->thread_ctx; + + if (atomic_load_explicit(&p->debug_threads, memory_order_relaxed)) + av_log(f->owner[field], AV_LOG_DEBUG, + "thread awaiting %d field %d from %p\n", n, field, progress); + + pthread_mutex_lock(&p->progress_mutex); + while (atomic_load_explicit(&progress[field], memory_order_relaxed) < n) + pthread_cond_wait(&p->progress_cond, &p->progress_mutex); + pthread_mutex_unlock(&p->progress_mutex); +} + +void ff_thread_finish_setup(AVCodecContext *avctx) { + PerThreadContext *p = avctx->internal->thread_ctx; + + if (!(avctx->active_thread_type&FF_THREAD_FRAME)) return; + + if (avctx->hwaccel && !p->hwaccel_serializing) { + pthread_mutex_lock(&p->parent->hwaccel_mutex); + p->hwaccel_serializing = 1; + } + + /* this assumes that no hwaccel calls happen before ff_thread_finish_setup() */ + if (avctx->hwaccel && + !(avctx->hwaccel->caps_internal & HWACCEL_CAP_ASYNC_SAFE)) { + p->async_serializing = 1; + + async_lock(p->parent); + } + + pthread_mutex_lock(&p->progress_mutex); + if(atomic_load(&p->state) == STATE_SETUP_FINISHED){ + av_log(avctx, AV_LOG_WARNING, "Multiple ff_thread_finish_setup() calls\n"); + } + + atomic_store(&p->state, STATE_SETUP_FINISHED); + + pthread_cond_broadcast(&p->progress_cond); + pthread_mutex_unlock(&p->progress_mutex); +} + +/// Waits for all threads to finish. +static void park_frame_worker_threads(FrameThreadContext *fctx, int thread_count) +{ + int i; + + async_unlock(fctx); + + for (i = 0; i < thread_count; i++) { + PerThreadContext *p = &fctx->threads[i]; + + if (atomic_load(&p->state) != STATE_INPUT_READY) { + pthread_mutex_lock(&p->progress_mutex); + while (atomic_load(&p->state) != STATE_INPUT_READY) + pthread_cond_wait(&p->output_cond, &p->progress_mutex); + pthread_mutex_unlock(&p->progress_mutex); + } + p->got_frame = 0; + } + + async_lock(fctx); +} + +void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) +{ + FrameThreadContext *fctx = avctx->internal->thread_ctx; + const AVCodec *codec = avctx->codec; + int i; + + park_frame_worker_threads(fctx, thread_count); + + if (fctx->prev_thread && fctx->prev_thread != fctx->threads) + if (update_context_from_thread(fctx->threads->avctx, fctx->prev_thread->avctx, 0) < 0) { + av_log(avctx, AV_LOG_ERROR, "Final thread update failed\n"); + fctx->prev_thread->avctx->internal->is_copy = fctx->threads->avctx->internal->is_copy; + fctx->threads->avctx->internal->is_copy = 1; + } + + for (i = 0; i < thread_count; i++) { + PerThreadContext *p = &fctx->threads[i]; + + pthread_mutex_lock(&p->mutex); + p->die = 1; + pthread_cond_signal(&p->input_cond); + pthread_mutex_unlock(&p->mutex); + + if (p->thread_init) + pthread_join(p->thread, NULL); + p->thread_init=0; + + if (codec->close && p->avctx) + codec->close(p->avctx); + + release_delayed_buffers(p); + av_frame_free(&p->frame); + } + + for (i = 0; i < thread_count; i++) { + PerThreadContext *p = &fctx->threads[i]; + + pthread_mutex_destroy(&p->mutex); + pthread_mutex_destroy(&p->progress_mutex); + pthread_cond_destroy(&p->input_cond); + pthread_cond_destroy(&p->progress_cond); + pthread_cond_destroy(&p->output_cond); + av_packet_unref(&p->avpkt); + av_freep(&p->released_buffers); + + if (i && p->avctx) { + av_freep(&p->avctx->priv_data); + av_freep(&p->avctx->slice_offset); + } + + if (p->avctx) { + av_freep(&p->avctx->internal); + av_buffer_unref(&p->avctx->hw_frames_ctx); + } + + av_freep(&p->avctx); + } + + av_freep(&fctx->threads); + pthread_mutex_destroy(&fctx->buffer_mutex); + pthread_mutex_destroy(&fctx->hwaccel_mutex); + pthread_mutex_destroy(&fctx->async_mutex); + pthread_cond_destroy(&fctx->async_cond); + + av_freep(&avctx->internal->thread_ctx); + + if (avctx->priv_data && avctx->codec && avctx->codec->priv_class) + av_opt_free(avctx->priv_data); + avctx->codec = NULL; +} + +int ff_frame_thread_init(AVCodecContext *avctx) +{ + int thread_count = avctx->thread_count; + const AVCodec *codec = avctx->codec; + AVCodecContext *src = avctx; + FrameThreadContext *fctx; + int i, err = 0; + + if (!thread_count) { + int nb_cpus = av_cpu_count(); +#if FF_API_DEBUG_MV + if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || avctx->debug_mv) + nb_cpus = 1; +#endif + // use number of cores + 1 as thread count if there is more than one + if (nb_cpus > 1) + thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS); + else + thread_count = avctx->thread_count = 1; + } + + if (thread_count <= 1) { + avctx->active_thread_type = 0; + return 0; + } + + avctx->internal->thread_ctx = fctx = av_mallocz(sizeof(FrameThreadContext)); + if (!fctx) + return AVERROR(ENOMEM); + + fctx->threads = av_mallocz_array(thread_count, sizeof(PerThreadContext)); + if (!fctx->threads) { + av_freep(&avctx->internal->thread_ctx); + return AVERROR(ENOMEM); + } + + pthread_mutex_init(&fctx->buffer_mutex, NULL); + pthread_mutex_init(&fctx->hwaccel_mutex, NULL); + pthread_mutex_init(&fctx->async_mutex, NULL); + pthread_cond_init(&fctx->async_cond, NULL); + + fctx->async_lock = 1; + fctx->delaying = 1; + + for (i = 0; i < thread_count; i++) { + AVCodecContext *copy = av_malloc(sizeof(AVCodecContext)); + PerThreadContext *p = &fctx->threads[i]; + + pthread_mutex_init(&p->mutex, NULL); + pthread_mutex_init(&p->progress_mutex, NULL); + pthread_cond_init(&p->input_cond, NULL); + pthread_cond_init(&p->progress_cond, NULL); + pthread_cond_init(&p->output_cond, NULL); + + p->frame = av_frame_alloc(); + if (!p->frame) { + av_freep(©); + err = AVERROR(ENOMEM); + goto error; + } + + p->parent = fctx; + p->avctx = copy; + + if (!copy) { + err = AVERROR(ENOMEM); + goto error; + } + + *copy = *src; + + copy->internal = av_malloc(sizeof(AVCodecInternal)); + if (!copy->internal) { + copy->priv_data = NULL; + err = AVERROR(ENOMEM); + goto error; + } + *copy->internal = *src->internal; + copy->internal->thread_ctx = p; + copy->internal->last_pkt_props = &p->avpkt; + + if (!i) { + src = copy; + + if (codec->init) + err = codec->init(copy); + + update_context_from_thread(avctx, copy, 1); + } else { + copy->priv_data = av_malloc(codec->priv_data_size); + if (!copy->priv_data) { + err = AVERROR(ENOMEM); + goto error; + } + memcpy(copy->priv_data, src->priv_data, codec->priv_data_size); + copy->internal->is_copy = 1; + + if (codec->init_thread_copy) + err = codec->init_thread_copy(copy); + } + + if (err) goto error; + + atomic_init(&p->debug_threads, (copy->debug & FF_DEBUG_THREADS) != 0); + + err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p)); + p->thread_init= !err; + if(!p->thread_init) + goto error; + } + + return 0; + +error: + ff_frame_thread_free(avctx, i+1); + + return err; +} + +void ff_thread_flush(AVCodecContext *avctx) +{ + int i; + FrameThreadContext *fctx = avctx->internal->thread_ctx; + + if (!fctx) return; + + park_frame_worker_threads(fctx, avctx->thread_count); + if (fctx->prev_thread) { + if (fctx->prev_thread != &fctx->threads[0]) + update_context_from_thread(fctx->threads[0].avctx, fctx->prev_thread->avctx, 0); + } + + fctx->next_decoding = fctx->next_finished = 0; + fctx->delaying = 1; + fctx->prev_thread = NULL; + for (i = 0; i < avctx->thread_count; i++) { + PerThreadContext *p = &fctx->threads[i]; + // Make sure decode flush calls with size=0 won't return old frames + p->got_frame = 0; + av_frame_unref(p->frame); + p->result = 0; + + release_delayed_buffers(p); + + if (avctx->codec->flush) + avctx->codec->flush(p->avctx); + } +} + +int ff_thread_can_start_frame(AVCodecContext *avctx) +{ + PerThreadContext *p = avctx->internal->thread_ctx; + if ((avctx->active_thread_type&FF_THREAD_FRAME) && atomic_load(&p->state) != STATE_SETTING_UP && + (avctx->codec->update_thread_context || !THREAD_SAFE_CALLBACKS(avctx))) { + return 0; + } + return 1; +} + +static int thread_get_buffer_internal(AVCodecContext *avctx, ThreadFrame *f, int flags) +{ + PerThreadContext *p = avctx->internal->thread_ctx; + int err; + + f->owner[0] = f->owner[1] = avctx; + + if (!(avctx->active_thread_type & FF_THREAD_FRAME)) + return ff_get_buffer(avctx, f->f, flags); + + if (atomic_load(&p->state) != STATE_SETTING_UP && + (avctx->codec->update_thread_context || !THREAD_SAFE_CALLBACKS(avctx))) { + av_log(avctx, AV_LOG_ERROR, "get_buffer() cannot be called after ff_thread_finish_setup()\n"); + return -1; + } + + if (avctx->internal->allocate_progress) { + atomic_int *progress; + f->progress = av_buffer_alloc(2 * sizeof(*progress)); + if (!f->progress) { + return AVERROR(ENOMEM); + } + progress = (atomic_int*)f->progress->data; + + atomic_init(&progress[0], -1); + atomic_init(&progress[1], -1); + } + + pthread_mutex_lock(&p->parent->buffer_mutex); + if (THREAD_SAFE_CALLBACKS(avctx)) { + err = ff_get_buffer(avctx, f->f, flags); + } else { + pthread_mutex_lock(&p->progress_mutex); + p->requested_frame = f->f; + p->requested_flags = flags; + atomic_store_explicit(&p->state, STATE_GET_BUFFER, memory_order_release); + pthread_cond_broadcast(&p->progress_cond); + + while (atomic_load(&p->state) != STATE_SETTING_UP) + pthread_cond_wait(&p->progress_cond, &p->progress_mutex); + + err = p->result; + + pthread_mutex_unlock(&p->progress_mutex); + + } + if (!THREAD_SAFE_CALLBACKS(avctx) && !avctx->codec->update_thread_context) + ff_thread_finish_setup(avctx); + if (err) + av_buffer_unref(&f->progress); + + pthread_mutex_unlock(&p->parent->buffer_mutex); + + return err; +} + +enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) +{ + enum AVPixelFormat res; + PerThreadContext *p = avctx->internal->thread_ctx; + if (!(avctx->active_thread_type & FF_THREAD_FRAME) || avctx->thread_safe_callbacks || + avctx->get_format == avcodec_default_get_format) + return ff_get_format(avctx, fmt); + if (atomic_load(&p->state) != STATE_SETTING_UP) { + av_log(avctx, AV_LOG_ERROR, "get_format() cannot be called after ff_thread_finish_setup()\n"); + return -1; + } + pthread_mutex_lock(&p->progress_mutex); + p->available_formats = fmt; + atomic_store(&p->state, STATE_GET_FORMAT); + pthread_cond_broadcast(&p->progress_cond); + + while (atomic_load(&p->state) != STATE_SETTING_UP) + pthread_cond_wait(&p->progress_cond, &p->progress_mutex); + + res = p->result_format; + + pthread_mutex_unlock(&p->progress_mutex); + + return res; +} + +int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) +{ + int ret = thread_get_buffer_internal(avctx, f, flags); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "thread_get_buffer() failed\n"); + return ret; +} + +void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f) +{ + PerThreadContext *p = avctx->internal->thread_ctx; + FrameThreadContext *fctx; + AVFrame *dst, *tmp; + int can_direct_free = !(avctx->active_thread_type & FF_THREAD_FRAME) || + THREAD_SAFE_CALLBACKS(avctx); + + if (!f->f || !f->f->buf[0]) + return; + + if (avctx->debug & FF_DEBUG_BUFFERS) + av_log(avctx, AV_LOG_DEBUG, "thread_release_buffer called on pic %p\n", f); + + av_buffer_unref(&f->progress); + f->owner[0] = f->owner[1] = NULL; + + if (can_direct_free) { + av_frame_unref(f->f); + return; + } + + fctx = p->parent; + pthread_mutex_lock(&fctx->buffer_mutex); + + if (p->num_released_buffers + 1 >= INT_MAX / sizeof(*p->released_buffers)) + goto fail; + tmp = av_fast_realloc(p->released_buffers, &p->released_buffers_allocated, + (p->num_released_buffers + 1) * + sizeof(*p->released_buffers)); + if (!tmp) + goto fail; + p->released_buffers = tmp; + + dst = &p->released_buffers[p->num_released_buffers]; + av_frame_move_ref(dst, f->f); + + p->num_released_buffers++; + +fail: + pthread_mutex_unlock(&fctx->buffer_mutex); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_internal.h new file mode 100644 index 0000000000..d2115cbbaf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_internal.h @@ -0,0 +1,34 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_PTHREAD_INTERNAL_H +#define AVCODEC_PTHREAD_INTERNAL_H + +#include "avcodec.h" + +/* H.264 slice threading seems to be buggy with more than 16 threads, + * limit the number of threads to 16 for automatic detection */ +#define MAX_AUTO_THREADS 16 + +int ff_slice_thread_init(AVCodecContext *avctx); +void ff_slice_thread_free(AVCodecContext *avctx); + +int ff_frame_thread_init(AVCodecContext *avctx); +void ff_frame_thread_free(AVCodecContext *avctx, int thread_count); + +#endif // AVCODEC_PTHREAD_INTERNAL_H diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_slice.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_slice.c new file mode 100644 index 0000000000..77cfe3c9f6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/pthread_slice.c @@ -0,0 +1,242 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Slice multithreading support functions + * @see doc/multithreading.txt + */ + +#include "config.h" + +#include "avcodec.h" +#include "internal.h" +#include "pthread_internal.h" +#include "thread.h" + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/cpu.h" +#include "libavutil/mem.h" +#include "libavutil/thread.h" +#include "libavutil/slicethread.h" + +typedef int (action_func)(AVCodecContext *c, void *arg); +typedef int (action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr); +typedef int (main_func)(AVCodecContext *c); + +typedef struct SliceThreadContext { + AVSliceThread *thread; + action_func *func; + action_func2 *func2; + main_func *mainfunc; + void *args; + int *rets; + int job_size; + + int *entries; + int entries_count; + int thread_count; + pthread_cond_t *progress_cond; + pthread_mutex_t *progress_mutex; +} SliceThreadContext; + +static void main_function(void *priv) { + AVCodecContext *avctx = priv; + SliceThreadContext *c = avctx->internal->thread_ctx; + c->mainfunc(avctx); +} + +static void worker_func(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads) +{ + AVCodecContext *avctx = priv; + SliceThreadContext *c = avctx->internal->thread_ctx; + int ret; + + ret = c->func ? c->func(avctx, (char *)c->args + c->job_size * jobnr) + : c->func2(avctx, c->args, jobnr, threadnr); + if (c->rets) + c->rets[jobnr] = ret; +} + +void ff_slice_thread_free(AVCodecContext *avctx) +{ + SliceThreadContext *c = avctx->internal->thread_ctx; + int i; + + avpriv_slicethread_free(&c->thread); + + for (i = 0; i < c->thread_count; i++) { + pthread_mutex_destroy(&c->progress_mutex[i]); + pthread_cond_destroy(&c->progress_cond[i]); + } + + av_freep(&c->entries); + av_freep(&c->progress_mutex); + av_freep(&c->progress_cond); + av_freep(&avctx->internal->thread_ctx); +} + +static int thread_execute(AVCodecContext *avctx, action_func* func, void *arg, int *ret, int job_count, int job_size) +{ + SliceThreadContext *c = avctx->internal->thread_ctx; + + if (!(avctx->active_thread_type&FF_THREAD_SLICE) || avctx->thread_count <= 1) + return avcodec_default_execute(avctx, func, arg, ret, job_count, job_size); + + if (job_count <= 0) + return 0; + + c->job_size = job_size; + c->args = arg; + c->func = func; + c->rets = ret; + + avpriv_slicethread_execute(c->thread, job_count, !!c->mainfunc ); + return 0; +} + +static int thread_execute2(AVCodecContext *avctx, action_func2* func2, void *arg, int *ret, int job_count) +{ + SliceThreadContext *c = avctx->internal->thread_ctx; + c->func2 = func2; + return thread_execute(avctx, NULL, arg, ret, job_count, 0); +} + +int ff_slice_thread_execute_with_mainfunc(AVCodecContext *avctx, action_func2* func2, main_func *mainfunc, void *arg, int *ret, int job_count) +{ + SliceThreadContext *c = avctx->internal->thread_ctx; + c->func2 = func2; + c->mainfunc = mainfunc; + return thread_execute(avctx, NULL, arg, ret, job_count, 0); +} + +int ff_slice_thread_init(AVCodecContext *avctx) +{ + SliceThreadContext *c; + int thread_count = avctx->thread_count; + static void (*mainfunc)(void *); + + // We cannot do this in the encoder init as the threads are created before + if (av_codec_is_encoder(avctx->codec) && + avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && + avctx->height > 2800) + thread_count = avctx->thread_count = 1; + + if (!thread_count) { + int nb_cpus = av_cpu_count(); + if (avctx->height) + nb_cpus = FFMIN(nb_cpus, (avctx->height+15)/16); + // use number of cores + 1 as thread count if there is more than one + if (nb_cpus > 1) + thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS); + else + thread_count = avctx->thread_count = 1; + } + + if (thread_count <= 1) { + avctx->active_thread_type = 0; + return 0; + } + + avctx->internal->thread_ctx = c = av_mallocz(sizeof(*c)); + mainfunc = avctx->codec->caps_internal & FF_CODEC_CAP_SLICE_THREAD_HAS_MF ? &main_function : NULL; + if (!c || (thread_count = avpriv_slicethread_create(&c->thread, avctx, worker_func, mainfunc, thread_count)) <= 1) { + if (c) + avpriv_slicethread_free(&c->thread); + av_freep(&avctx->internal->thread_ctx); + avctx->thread_count = 1; + avctx->active_thread_type = 0; + return 0; + } + avctx->thread_count = thread_count; + + avctx->execute = thread_execute; + avctx->execute2 = thread_execute2; + return 0; +} + +void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n) +{ + SliceThreadContext *p = avctx->internal->thread_ctx; + int *entries = p->entries; + + pthread_mutex_lock(&p->progress_mutex[thread]); + entries[field] +=n; + pthread_cond_signal(&p->progress_cond[thread]); + pthread_mutex_unlock(&p->progress_mutex[thread]); +} + +void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift) +{ + SliceThreadContext *p = avctx->internal->thread_ctx; + int *entries = p->entries; + + if (!entries || !field) return; + + thread = thread ? thread - 1 : p->thread_count - 1; + + pthread_mutex_lock(&p->progress_mutex[thread]); + while ((entries[field - 1] - entries[field]) < shift){ + pthread_cond_wait(&p->progress_cond[thread], &p->progress_mutex[thread]); + } + pthread_mutex_unlock(&p->progress_mutex[thread]); +} + +int ff_alloc_entries(AVCodecContext *avctx, int count) +{ + int i; + + if (avctx->active_thread_type & FF_THREAD_SLICE) { + SliceThreadContext *p = avctx->internal->thread_ctx; + + if (p->entries) { + av_assert0(p->thread_count == avctx->thread_count); + av_freep(&p->entries); + } + + p->thread_count = avctx->thread_count; + p->entries = av_mallocz_array(count, sizeof(int)); + + if (!p->progress_mutex) { + p->progress_mutex = av_malloc_array(p->thread_count, sizeof(pthread_mutex_t)); + p->progress_cond = av_malloc_array(p->thread_count, sizeof(pthread_cond_t)); + } + + if (!p->entries || !p->progress_mutex || !p->progress_cond) { + av_freep(&p->entries); + av_freep(&p->progress_mutex); + av_freep(&p->progress_cond); + return AVERROR(ENOMEM); + } + p->entries_count = count; + + for (i = 0; i < p->thread_count; i++) { + pthread_mutex_init(&p->progress_mutex[i], NULL); + pthread_cond_init(&p->progress_cond[i], NULL); + } + } + + return 0; +} + +void ff_reset_entries(AVCodecContext *avctx) +{ + SliceThreadContext *p = avctx->internal->thread_ctx; + memset(p->entries, 0, p->entries_count * sizeof(int)); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/put_bits.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/put_bits.h new file mode 100644 index 0000000000..1ceb1cc766 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/put_bits.h @@ -0,0 +1,365 @@ +/* + * copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * bitstream writer API + */ + +#ifndef AVCODEC_PUT_BITS_H +#define AVCODEC_PUT_BITS_H + +#include +#include + +#include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" + +typedef struct PutBitContext { + uint32_t bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; + int size_in_bits; +} PutBitContext; + +/** + * Initialize the PutBitContext s. + * + * @param buffer the buffer where to put bits + * @param buffer_size the size in bytes of buffer + */ +static inline void init_put_bits(PutBitContext *s, uint8_t *buffer, + int buffer_size) +{ + if (buffer_size < 0) { + buffer_size = 0; + buffer = NULL; + } + + s->size_in_bits = 8 * buffer_size; + s->buf = buffer; + s->buf_end = s->buf + buffer_size; + s->buf_ptr = s->buf; + s->bit_left = 32; + s->bit_buf = 0; +} + +/** + * Rebase the bit writer onto a reallocated buffer. + * + * @param buffer the buffer where to put bits + * @param buffer_size the size in bytes of buffer, + * must be larger than the previous size + */ +static inline void rebase_put_bits(PutBitContext *s, uint8_t *buffer, + int buffer_size) +{ + av_assert0(8*buffer_size > s->size_in_bits); + + s->buf_end = buffer + buffer_size; + s->buf_ptr = buffer + (s->buf_ptr - s->buf); + s->buf = buffer; + s->size_in_bits = 8 * buffer_size; +} + +/** + * @return the total number of bits written to the bitstream. + */ +static inline int put_bits_count(PutBitContext *s) +{ + return (s->buf_ptr - s->buf) * 8 + 32 - s->bit_left; +} + +/** + * @return the number of bits available in the bitstream. + */ +static inline int put_bits_left(PutBitContext* s) +{ + return (s->buf_end - s->buf_ptr) * 8 - 32 + s->bit_left; +} + +/** + * Pad the end of the output stream with zeros. + */ +static inline void flush_put_bits(PutBitContext *s) +{ +#ifndef BITSTREAM_WRITER_LE + if (s->bit_left < 32) + s->bit_buf <<= s->bit_left; +#endif + while (s->bit_left < 32) { + av_assert0(s->buf_ptr < s->buf_end); +#ifdef BITSTREAM_WRITER_LE + *s->buf_ptr++ = s->bit_buf; + s->bit_buf >>= 8; +#else + *s->buf_ptr++ = s->bit_buf >> 24; + s->bit_buf <<= 8; +#endif + s->bit_left += 8; + } + s->bit_left = 32; + s->bit_buf = 0; +} + +static inline void flush_put_bits_le(PutBitContext *s) +{ + while (s->bit_left < 32) { + av_assert0(s->buf_ptr < s->buf_end); + *s->buf_ptr++ = s->bit_buf; + s->bit_buf >>= 8; + s->bit_left += 8; + } + s->bit_left = 32; + s->bit_buf = 0; +} + +#ifdef BITSTREAM_WRITER_LE +#define avpriv_align_put_bits align_put_bits_unsupported_here +#define avpriv_put_string ff_put_string_unsupported_here +#define avpriv_copy_bits avpriv_copy_bits_unsupported_here +#else +/** + * Pad the bitstream with zeros up to the next byte boundary. + */ +void avpriv_align_put_bits(PutBitContext *s); + +/** + * Put the string string in the bitstream. + * + * @param terminate_string 0-terminates the written string if value is 1 + */ +void avpriv_put_string(PutBitContext *pb, const char *string, + int terminate_string); + +/** + * Copy the content of src to the bitstream. + * + * @param length the number of bits of src to copy + */ +void avpriv_copy_bits(PutBitContext *pb, const uint8_t *src, int length); +#endif + +/** + * Write up to 31 bits into a bitstream. + * Use put_bits32 to write 32 bits. + */ +static inline void put_bits(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + + av_assert2(n <= 31 && value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + /* XXX: optimize */ +#ifdef BITSTREAM_WRITER_LE + bit_buf |= value << (32 - bit_left); + if (n >= bit_left) { + if (3 < s->buf_end - s->buf_ptr) { + AV_WL32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + } else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = value >> bit_left; + bit_left += 32; + } + bit_left -= n; +#else + if (n < bit_left) { + bit_buf = (bit_buf << n) | value; + bit_left -= n; + } else { + bit_buf <<= bit_left; + bit_buf |= value >> (n - bit_left); + if (3 < s->buf_end - s->buf_ptr) { + AV_WB32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + } else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_left += 32 - n; + bit_buf = value; + } +#endif + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +static inline void put_bits_le(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + + av_assert2(n <= 31 && value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + bit_buf |= value << (32 - bit_left); + if (n >= bit_left) { + if (3 < s->buf_end - s->buf_ptr) { + AV_WL32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + } else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = value >> bit_left; + bit_left += 32; + } + bit_left -= n; + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +static inline void put_sbits(PutBitContext *pb, int n, int32_t value) +{ + av_assert2(n >= 0 && n <= 31); + + put_bits(pb, n, av_mod_uintp2(value, n)); +} + +/** + * Write exactly 32 bits into a bitstream. + */ +static void av_unused put_bits32(PutBitContext *s, uint32_t value) +{ + unsigned int bit_buf; + int bit_left; + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + +#ifdef BITSTREAM_WRITER_LE + bit_buf |= value << (32 - bit_left); + if (3 < s->buf_end - s->buf_ptr) { + AV_WL32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + } else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = (uint64_t)value >> bit_left; +#else + bit_buf = (uint64_t)bit_buf << bit_left; + bit_buf |= value >> (32 - bit_left); + if (3 < s->buf_end - s->buf_ptr) { + AV_WB32(s->buf_ptr, bit_buf); + s->buf_ptr += 4; + } else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = value; +#endif + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +/** + * Write up to 64 bits into a bitstream. + */ +static inline void put_bits64(PutBitContext *s, int n, uint64_t value) +{ + av_assert2((n == 64) || (n < 64 && value < (UINT64_C(1) << n))); + + if (n < 32) + put_bits(s, n, value); + else if (n == 32) + put_bits32(s, value); + else if (n < 64) { + uint32_t lo = value & 0xffffffff; + uint32_t hi = value >> 32; +#ifdef BITSTREAM_WRITER_LE + put_bits32(s, lo); + put_bits(s, n - 32, hi); +#else + put_bits(s, n - 32, hi); + put_bits32(s, lo); +#endif + } else { + uint32_t lo = value & 0xffffffff; + uint32_t hi = value >> 32; +#ifdef BITSTREAM_WRITER_LE + put_bits32(s, lo); + put_bits32(s, hi); +#else + put_bits32(s, hi); + put_bits32(s, lo); +#endif + + } +} + +/** + * Return the pointer to the byte where the bitstream writer will put + * the next bit. + */ +static inline uint8_t *put_bits_ptr(PutBitContext *s) +{ + return s->buf_ptr; +} + +/** + * Skip the given number of bytes. + * PutBitContext must be flushed & aligned to a byte boundary before calling this. + */ +static inline void skip_put_bytes(PutBitContext *s, int n) +{ + av_assert2((put_bits_count(s) & 7) == 0); + av_assert2(s->bit_left == 32); + av_assert0(n <= s->buf_end - s->buf_ptr); + s->buf_ptr += n; +} + +/** + * Skip the given number of bits. + * Must only be used if the actual values in the bitstream do not matter. + * If n is 0 the behavior is undefined. + */ +static inline void skip_put_bits(PutBitContext *s, int n) +{ + s->bit_left -= n; + s->buf_ptr -= 4 * (s->bit_left >> 5); + s->bit_left &= 31; +} + +/** + * Change the end of the buffer. + * + * @param size the new size in bytes of the buffer where to put bits + */ +static inline void set_put_bits_buffer_size(PutBitContext *s, int size) +{ + av_assert0(size <= INT_MAX/8 - 32); + s->buf_end = s->buf + size; + s->size_in_bits = 8*size; +} + +#endif /* AVCODEC_PUT_BITS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qpeldsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qpeldsp.c new file mode 100644 index 0000000000..6e52b33657 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qpeldsp.c @@ -0,0 +1,816 @@ +/* + * quarterpel DSP functions + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * quarterpel DSP functions + */ + +#include +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "copy_block.h" +#include "qpeldsp.h" +#include "diracdsp.h" + +#define BIT_DEPTH 8 +#include "hpel_template.c" +#include "pel_template.c" +#include "qpel_template.c" + +#define QPEL_MC(r, OPNAME, RND, OP) \ +static void OPNAME ## mpeg4_qpel8_h_lowpass(uint8_t *dst, const uint8_t *src, \ + int dstStride, int srcStride, \ + int h) \ +{ \ + const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; \ + int i; \ + \ + for (i = 0; i < h; i++) { \ + OP(dst[0], (src[0] + src[1]) * 20 - (src[0] + src[2]) * 6 + (src[1] + src[3]) * 3 - (src[2] + src[4])); \ + OP(dst[1], (src[1] + src[2]) * 20 - (src[0] + src[3]) * 6 + (src[0] + src[4]) * 3 - (src[1] + src[5])); \ + OP(dst[2], (src[2] + src[3]) * 20 - (src[1] + src[4]) * 6 + (src[0] + src[5]) * 3 - (src[0] + src[6])); \ + OP(dst[3], (src[3] + src[4]) * 20 - (src[2] + src[5]) * 6 + (src[1] + src[6]) * 3 - (src[0] + src[7])); \ + OP(dst[4], (src[4] + src[5]) * 20 - (src[3] + src[6]) * 6 + (src[2] + src[7]) * 3 - (src[1] + src[8])); \ + OP(dst[5], (src[5] + src[6]) * 20 - (src[4] + src[7]) * 6 + (src[3] + src[8]) * 3 - (src[2] + src[8])); \ + OP(dst[6], (src[6] + src[7]) * 20 - (src[5] + src[8]) * 6 + (src[4] + src[8]) * 3 - (src[3] + src[7])); \ + OP(dst[7], (src[7] + src[8]) * 20 - (src[6] + src[8]) * 6 + (src[5] + src[7]) * 3 - (src[4] + src[6])); \ + dst += dstStride; \ + src += srcStride; \ + } \ +} \ + \ +static void OPNAME ## mpeg4_qpel8_v_lowpass(uint8_t *dst, const uint8_t *src, \ + int dstStride, int srcStride) \ +{ \ + const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; \ + const int w = 8; \ + int i; \ + \ + for (i = 0; i < w; i++) { \ + const int src0 = src[0 * srcStride]; \ + const int src1 = src[1 * srcStride]; \ + const int src2 = src[2 * srcStride]; \ + const int src3 = src[3 * srcStride]; \ + const int src4 = src[4 * srcStride]; \ + const int src5 = src[5 * srcStride]; \ + const int src6 = src[6 * srcStride]; \ + const int src7 = src[7 * srcStride]; \ + const int src8 = src[8 * srcStride]; \ + OP(dst[0 * dstStride], (src0 + src1) * 20 - (src0 + src2) * 6 + (src1 + src3) * 3 - (src2 + src4)); \ + OP(dst[1 * dstStride], (src1 + src2) * 20 - (src0 + src3) * 6 + (src0 + src4) * 3 - (src1 + src5)); \ + OP(dst[2 * dstStride], (src2 + src3) * 20 - (src1 + src4) * 6 + (src0 + src5) * 3 - (src0 + src6)); \ + OP(dst[3 * dstStride], (src3 + src4) * 20 - (src2 + src5) * 6 + (src1 + src6) * 3 - (src0 + src7)); \ + OP(dst[4 * dstStride], (src4 + src5) * 20 - (src3 + src6) * 6 + (src2 + src7) * 3 - (src1 + src8)); \ + OP(dst[5 * dstStride], (src5 + src6) * 20 - (src4 + src7) * 6 + (src3 + src8) * 3 - (src2 + src8)); \ + OP(dst[6 * dstStride], (src6 + src7) * 20 - (src5 + src8) * 6 + (src4 + src8) * 3 - (src3 + src7)); \ + OP(dst[7 * dstStride], (src7 + src8) * 20 - (src6 + src8) * 6 + (src5 + src7) * 3 - (src4 + src6)); \ + dst++; \ + src++; \ + } \ +} \ + \ +static void OPNAME ## mpeg4_qpel16_h_lowpass(uint8_t *dst, \ + const uint8_t *src, \ + int dstStride, int srcStride, \ + int h) \ +{ \ + const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; \ + int i; \ + \ + for (i = 0; i < h; i++) { \ + OP(dst[0], (src[0] + src[1]) * 20 - (src[0] + src[2]) * 6 + (src[1] + src[3]) * 3 - (src[2] + src[4])); \ + OP(dst[1], (src[1] + src[2]) * 20 - (src[0] + src[3]) * 6 + (src[0] + src[4]) * 3 - (src[1] + src[5])); \ + OP(dst[2], (src[2] + src[3]) * 20 - (src[1] + src[4]) * 6 + (src[0] + src[5]) * 3 - (src[0] + src[6])); \ + OP(dst[3], (src[3] + src[4]) * 20 - (src[2] + src[5]) * 6 + (src[1] + src[6]) * 3 - (src[0] + src[7])); \ + OP(dst[4], (src[4] + src[5]) * 20 - (src[3] + src[6]) * 6 + (src[2] + src[7]) * 3 - (src[1] + src[8])); \ + OP(dst[5], (src[5] + src[6]) * 20 - (src[4] + src[7]) * 6 + (src[3] + src[8]) * 3 - (src[2] + src[9])); \ + OP(dst[6], (src[6] + src[7]) * 20 - (src[5] + src[8]) * 6 + (src[4] + src[9]) * 3 - (src[3] + src[10])); \ + OP(dst[7], (src[7] + src[8]) * 20 - (src[6] + src[9]) * 6 + (src[5] + src[10]) * 3 - (src[4] + src[11])); \ + OP(dst[8], (src[8] + src[9]) * 20 - (src[7] + src[10]) * 6 + (src[6] + src[11]) * 3 - (src[5] + src[12])); \ + OP(dst[9], (src[9] + src[10]) * 20 - (src[8] + src[11]) * 6 + (src[7] + src[12]) * 3 - (src[6] + src[13])); \ + OP(dst[10], (src[10] + src[11]) * 20 - (src[9] + src[12]) * 6 + (src[8] + src[13]) * 3 - (src[7] + src[14])); \ + OP(dst[11], (src[11] + src[12]) * 20 - (src[10] + src[13]) * 6 + (src[9] + src[14]) * 3 - (src[8] + src[15])); \ + OP(dst[12], (src[12] + src[13]) * 20 - (src[11] + src[14]) * 6 + (src[10] + src[15]) * 3 - (src[9] + src[16])); \ + OP(dst[13], (src[13] + src[14]) * 20 - (src[12] + src[15]) * 6 + (src[11] + src[16]) * 3 - (src[10] + src[16])); \ + OP(dst[14], (src[14] + src[15]) * 20 - (src[13] + src[16]) * 6 + (src[12] + src[16]) * 3 - (src[11] + src[15])); \ + OP(dst[15], (src[15] + src[16]) * 20 - (src[14] + src[16]) * 6 + (src[13] + src[15]) * 3 - (src[12] + src[14])); \ + dst += dstStride; \ + src += srcStride; \ + } \ +} \ + \ +static void OPNAME ## mpeg4_qpel16_v_lowpass(uint8_t *dst, \ + const uint8_t *src, \ + int dstStride, int srcStride) \ +{ \ + const uint8_t *cm = ff_crop_tab + MAX_NEG_CROP; \ + const int w = 16; \ + int i; \ + \ + for (i = 0; i < w; i++) { \ + const int src0 = src[0 * srcStride]; \ + const int src1 = src[1 * srcStride]; \ + const int src2 = src[2 * srcStride]; \ + const int src3 = src[3 * srcStride]; \ + const int src4 = src[4 * srcStride]; \ + const int src5 = src[5 * srcStride]; \ + const int src6 = src[6 * srcStride]; \ + const int src7 = src[7 * srcStride]; \ + const int src8 = src[8 * srcStride]; \ + const int src9 = src[9 * srcStride]; \ + const int src10 = src[10 * srcStride]; \ + const int src11 = src[11 * srcStride]; \ + const int src12 = src[12 * srcStride]; \ + const int src13 = src[13 * srcStride]; \ + const int src14 = src[14 * srcStride]; \ + const int src15 = src[15 * srcStride]; \ + const int src16 = src[16 * srcStride]; \ + OP(dst[0 * dstStride], (src0 + src1) * 20 - (src0 + src2) * 6 + (src1 + src3) * 3 - (src2 + src4)); \ + OP(dst[1 * dstStride], (src1 + src2) * 20 - (src0 + src3) * 6 + (src0 + src4) * 3 - (src1 + src5)); \ + OP(dst[2 * dstStride], (src2 + src3) * 20 - (src1 + src4) * 6 + (src0 + src5) * 3 - (src0 + src6)); \ + OP(dst[3 * dstStride], (src3 + src4) * 20 - (src2 + src5) * 6 + (src1 + src6) * 3 - (src0 + src7)); \ + OP(dst[4 * dstStride], (src4 + src5) * 20 - (src3 + src6) * 6 + (src2 + src7) * 3 - (src1 + src8)); \ + OP(dst[5 * dstStride], (src5 + src6) * 20 - (src4 + src7) * 6 + (src3 + src8) * 3 - (src2 + src9)); \ + OP(dst[6 * dstStride], (src6 + src7) * 20 - (src5 + src8) * 6 + (src4 + src9) * 3 - (src3 + src10)); \ + OP(dst[7 * dstStride], (src7 + src8) * 20 - (src6 + src9) * 6 + (src5 + src10) * 3 - (src4 + src11)); \ + OP(dst[8 * dstStride], (src8 + src9) * 20 - (src7 + src10) * 6 + (src6 + src11) * 3 - (src5 + src12)); \ + OP(dst[9 * dstStride], (src9 + src10) * 20 - (src8 + src11) * 6 + (src7 + src12) * 3 - (src6 + src13)); \ + OP(dst[10 * dstStride], (src10 + src11) * 20 - (src9 + src12) * 6 + (src8 + src13) * 3 - (src7 + src14)); \ + OP(dst[11 * dstStride], (src11 + src12) * 20 - (src10 + src13) * 6 + (src9 + src14) * 3 - (src8 + src15)); \ + OP(dst[12 * dstStride], (src12 + src13) * 20 - (src11 + src14) * 6 + (src10 + src15) * 3 - (src9 + src16)); \ + OP(dst[13 * dstStride], (src13 + src14) * 20 - (src12 + src15) * 6 + (src11 + src16) * 3 - (src10 + src16)); \ + OP(dst[14 * dstStride], (src14 + src15) * 20 - (src13 + src16) * 6 + (src12 + src16) * 3 - (src11 + src15)); \ + OP(dst[15 * dstStride], (src15 + src16) * 20 - (src14 + src16) * 6 + (src13 + src15) * 3 - (src12 + src14)); \ + dst++; \ + src++; \ + } \ +} \ + \ +static void OPNAME ## qpel8_mc10_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t half[64]; \ + \ + put ## RND ## mpeg4_qpel8_h_lowpass(half, src, 8, stride, 8); \ + OPNAME ## pixels8_l2_8(dst, src, half, stride, stride, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc20_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + OPNAME ## mpeg4_qpel8_h_lowpass(dst, src, stride, stride, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc30_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t half[64]; \ + \ + put ## RND ## mpeg4_qpel8_h_lowpass(half, src, 8, stride, 8); \ + OPNAME ## pixels8_l2_8(dst, src + 1, half, stride, stride, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc01_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t half[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(half, full, 8, 16); \ + OPNAME ## pixels8_l2_8(dst, full, half, stride, 16, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc02_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + OPNAME ## mpeg4_qpel8_v_lowpass(dst, full, stride, 16); \ +} \ + \ +static void OPNAME ## qpel8_mc03_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t half[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(half, full, 8, 16); \ + OPNAME ## pixels8_l2_8(dst, full + 16, half, stride, 16, 8, 8); \ +} \ + \ +void ff_ ## OPNAME ## qpel8_mc11_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + uint8_t halfV[64]; \ + uint8_t halfHV[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfV, full, 8, 16); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l4_8(dst, full, halfH, halfV, halfHV, \ + stride, 16, 8, 8, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc11_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + uint8_t halfHV[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## pixels8_l2_8(halfH, halfH, full, 8, 8, 16, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l2_8(dst, halfH, halfHV, stride, 8, 8, 8); \ +} \ + \ +void ff_ ## OPNAME ## qpel8_mc31_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + uint8_t halfV[64]; \ + uint8_t halfHV[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfV, full + 1, 8, 16); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l4_8(dst, full + 1, halfH, halfV, halfHV, \ + stride, 16, 8, 8, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc31_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + uint8_t halfHV[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## pixels8_l2_8(halfH, halfH, full + 1, 8, 8, 16, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l2_8(dst, halfH, halfHV, stride, 8, 8, 8); \ +} \ + \ +void ff_ ## OPNAME ## qpel8_mc13_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + uint8_t halfV[64]; \ + uint8_t halfHV[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfV, full, 8, 16); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l4_8(dst, full + 16, halfH + 8, halfV, halfHV, \ + stride, 16, 8, 8, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc13_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + uint8_t halfHV[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## pixels8_l2_8(halfH, halfH, full, 8, 8, 16, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l2_8(dst, halfH + 8, halfHV, stride, 8, 8, 8); \ +} \ + \ +void ff_ ## OPNAME ## qpel8_mc33_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + uint8_t halfV[64]; \ + uint8_t halfHV[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfV, full + 1, 8, 16); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l4_8(dst, full + 17, halfH + 8, halfV, halfHV, \ + stride, 16, 8, 8, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc33_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + uint8_t halfHV[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## pixels8_l2_8(halfH, halfH, full + 1, 8, 8, 16, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l2_8(dst, halfH + 8, halfHV, stride, 8, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc21_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t halfH[72]; \ + uint8_t halfHV[64]; \ + \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, src, 8, stride, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l2_8(dst, halfH, halfHV, stride, 8, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc23_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t halfH[72]; \ + uint8_t halfHV[64]; \ + \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, src, 8, stride, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l2_8(dst, halfH + 8, halfHV, stride, 8, 8, 8); \ +} \ + \ +void ff_ ## OPNAME ## qpel8_mc12_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + uint8_t halfV[64]; \ + uint8_t halfHV[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfV, full, 8, 16); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l2_8(dst, halfV, halfHV, stride, 8, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc12_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## pixels8_l2_8(halfH, halfH, full, 8, 8, 16, 9); \ + OPNAME ## mpeg4_qpel8_v_lowpass(dst, halfH, stride, 8); \ +} \ + \ +void ff_ ## OPNAME ## qpel8_mc32_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + uint8_t halfV[64]; \ + uint8_t halfHV[64]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfV, full + 1, 8, 16); \ + put ## RND ## mpeg4_qpel8_v_lowpass(halfHV, halfH, 8, 8); \ + OPNAME ## pixels8_l2_8(dst, halfV, halfHV, stride, 8, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc32_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[16 * 9]; \ + uint8_t halfH[72]; \ + \ + copy_block9(full, src, 16, stride, 9); \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, full, 8, 16, 9); \ + put ## RND ## pixels8_l2_8(halfH, halfH, full + 1, 8, 8, 16, 9); \ + OPNAME ## mpeg4_qpel8_v_lowpass(dst, halfH, stride, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc22_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t halfH[72]; \ + \ + put ## RND ## mpeg4_qpel8_h_lowpass(halfH, src, 8, stride, 9); \ + OPNAME ## mpeg4_qpel8_v_lowpass(dst, halfH, stride, 8); \ +} \ + \ +static void OPNAME ## qpel16_mc10_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t half[256]; \ + \ + put ## RND ## mpeg4_qpel16_h_lowpass(half, src, 16, stride, 16); \ + OPNAME ## pixels16_l2_8(dst, src, half, stride, stride, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc20_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + OPNAME ## mpeg4_qpel16_h_lowpass(dst, src, stride, stride, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc30_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t half[256]; \ + \ + put ## RND ## mpeg4_qpel16_h_lowpass(half, src, 16, stride, 16); \ + OPNAME ## pixels16_l2_8(dst, src + 1, half, stride, stride, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc01_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t half[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(half, full, 16, 24); \ + OPNAME ## pixels16_l2_8(dst, full, half, stride, 24, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc02_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + OPNAME ## mpeg4_qpel16_v_lowpass(dst, full, stride, 24); \ +} \ + \ +static void OPNAME ## qpel16_mc03_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t half[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(half, full, 16, 24); \ + OPNAME ## pixels16_l2_8(dst, full + 24, half, stride, 24, 16, 16); \ +} \ + \ +void ff_ ## OPNAME ## qpel16_mc11_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + uint8_t halfV[256]; \ + uint8_t halfHV[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfV, full, 16, 24); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l4_8(dst, full, halfH, halfV, halfHV, \ + stride, 24, 16, 16, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc11_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + uint8_t halfHV[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## pixels16_l2_8(halfH, halfH, full, 16, 16, 24, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l2_8(dst, halfH, halfHV, stride, 16, 16, 16); \ +} \ + \ +void ff_ ## OPNAME ## qpel16_mc31_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + uint8_t halfV[256]; \ + uint8_t halfHV[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfV, full + 1, 16, 24); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l4_8(dst, full + 1, halfH, halfV, halfHV, \ + stride, 24, 16, 16, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc31_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + uint8_t halfHV[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## pixels16_l2_8(halfH, halfH, full + 1, 16, 16, 24, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l2_8(dst, halfH, halfHV, stride, 16, 16, 16); \ +} \ + \ +void ff_ ## OPNAME ## qpel16_mc13_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + uint8_t halfV[256]; \ + uint8_t halfHV[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfV, full, 16, 24); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l4_8(dst, full + 24, halfH + 16, halfV, halfHV, \ + stride, 24, 16, 16, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc13_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + uint8_t halfHV[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## pixels16_l2_8(halfH, halfH, full, 16, 16, 24, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l2_8(dst, halfH + 16, halfHV, stride, 16, 16, 16); \ +} \ + \ +void ff_ ## OPNAME ## qpel16_mc33_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + uint8_t halfV[256]; \ + uint8_t halfHV[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfV, full + 1, 16, 24); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l4_8(dst, full + 25, halfH + 16, halfV, halfHV, \ + stride, 24, 16, 16, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc33_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + uint8_t halfHV[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## pixels16_l2_8(halfH, halfH, full + 1, 16, 16, 24, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l2_8(dst, halfH + 16, halfHV, stride, 16, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc21_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t halfH[272]; \ + uint8_t halfHV[256]; \ + \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, src, 16, stride, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l2_8(dst, halfH, halfHV, stride, 16, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc23_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t halfH[272]; \ + uint8_t halfHV[256]; \ + \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, src, 16, stride, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l2_8(dst, halfH + 16, halfHV, stride, 16, 16, 16); \ +} \ + \ +void ff_ ## OPNAME ## qpel16_mc12_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + uint8_t halfV[256]; \ + uint8_t halfHV[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfV, full, 16, 24); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l2_8(dst, halfV, halfHV, stride, 16, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc12_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## pixels16_l2_8(halfH, halfH, full, 16, 16, 24, 17); \ + OPNAME ## mpeg4_qpel16_v_lowpass(dst, halfH, stride, 16); \ +} \ + \ +void ff_ ## OPNAME ## qpel16_mc32_old_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + uint8_t halfV[256]; \ + uint8_t halfHV[256]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfV, full + 1, 16, 24); \ + put ## RND ## mpeg4_qpel16_v_lowpass(halfHV, halfH, 16, 16); \ + OPNAME ## pixels16_l2_8(dst, halfV, halfHV, stride, 16, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc32_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t full[24 * 17]; \ + uint8_t halfH[272]; \ + \ + copy_block17(full, src, 24, stride, 17); \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, full, 16, 24, 17); \ + put ## RND ## pixels16_l2_8(halfH, halfH, full + 1, 16, 16, 24, 17); \ + OPNAME ## mpeg4_qpel16_v_lowpass(dst, halfH, stride, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc22_c(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint8_t halfH[272]; \ + \ + put ## RND ## mpeg4_qpel16_h_lowpass(halfH, src, 16, stride, 17); \ + OPNAME ## mpeg4_qpel16_v_lowpass(dst, halfH, stride, 16); \ +} + +#define op_avg(a, b) a = (((a) + cm[((b) + 16) >> 5] + 1) >> 1) +#define op_put(a, b) a = cm[((b) + 16) >> 5] +#define op_put_no_rnd(a, b) a = cm[((b) + 15) >> 5] + +QPEL_MC(0, put_, _, op_put) +QPEL_MC(1, put_no_rnd_, _no_rnd_, op_put_no_rnd) +QPEL_MC(0, avg_, _, op_avg) + +#undef op_avg +#undef op_put +#undef op_put_no_rnd + +void ff_put_pixels8x8_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + put_pixels8_8_c(dst, src, stride, 8); +} + +void ff_avg_pixels8x8_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + avg_pixels8_8_c(dst, src, stride, 8); +} + +void ff_put_pixels16x16_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + put_pixels16_8_c(dst, src, stride, 16); +} + +void ff_avg_pixels16x16_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) +{ + avg_pixels16_8_c(dst, src, stride, 16); +} + +#define put_qpel8_mc00_c ff_put_pixels8x8_c +#define avg_qpel8_mc00_c ff_avg_pixels8x8_c +#define put_qpel16_mc00_c ff_put_pixels16x16_c +#define avg_qpel16_mc00_c ff_avg_pixels16x16_c +#define put_no_rnd_qpel8_mc00_c ff_put_pixels8x8_c +#define put_no_rnd_qpel16_mc00_c ff_put_pixels16x16_c + +void ff_put_pixels8_l2_8(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + int dst_stride, int src_stride1, int src_stride2, + int h) +{ + put_pixels8_l2_8(dst, src1, src2, dst_stride, src_stride1, src_stride2, h); + +} + +#if CONFIG_DIRAC_DECODER +#define DIRAC_MC(OPNAME)\ +void ff_ ## OPNAME ## _dirac_pixels8_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + OPNAME ## _pixels8_8_c(dst, src[0], stride, h);\ +}\ +void ff_ ## OPNAME ## _dirac_pixels16_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + OPNAME ## _pixels16_8_c(dst, src[0], stride, h);\ +}\ +void ff_ ## OPNAME ## _dirac_pixels32_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + OPNAME ## _pixels16_8_c(dst , src[0] , stride, h);\ + OPNAME ## _pixels16_8_c(dst+16, src[0]+16, stride, h);\ +}\ +void ff_ ## OPNAME ## _dirac_pixels8_l2_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + OPNAME ## _pixels8_l2_8(dst, src[0], src[1], stride, stride, stride, h);\ +}\ +void ff_ ## OPNAME ## _dirac_pixels16_l2_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + OPNAME ## _pixels16_l2_8(dst, src[0], src[1], stride, stride, stride, h);\ +}\ +void ff_ ## OPNAME ## _dirac_pixels32_l2_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + OPNAME ## _pixels16_l2_8(dst , src[0] , src[1] , stride, stride, stride, h);\ + OPNAME ## _pixels16_l2_8(dst+16, src[0]+16, src[1]+16, stride, stride, stride, h);\ +}\ +void ff_ ## OPNAME ## _dirac_pixels8_l4_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + OPNAME ## _pixels8_l4_8(dst, src[0], src[1], src[2], src[3], stride, stride, stride, stride, stride, h);\ +}\ +void ff_ ## OPNAME ## _dirac_pixels16_l4_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + OPNAME ## _pixels16_l4_8(dst, src[0], src[1], src[2], src[3], stride, stride, stride, stride, stride, h);\ +}\ +void ff_ ## OPNAME ## _dirac_pixels32_l4_c(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + OPNAME ## _pixels16_l4_8(dst , src[0] , src[1] , src[2] , src[3] , stride, stride, stride, stride, stride, h);\ + OPNAME ## _pixels16_l4_8(dst+16, src[0]+16, src[1]+16, src[2]+16, src[3]+16, stride, stride, stride, stride, stride, h);\ +} +DIRAC_MC(put) +DIRAC_MC(avg) +#endif + +av_cold void ff_qpeldsp_init(QpelDSPContext *c) +{ +#define dspfunc(PFX, IDX, NUM) \ + c->PFX ## _pixels_tab[IDX][0] = PFX ## NUM ## _mc00_c; \ + c->PFX ## _pixels_tab[IDX][1] = PFX ## NUM ## _mc10_c; \ + c->PFX ## _pixels_tab[IDX][2] = PFX ## NUM ## _mc20_c; \ + c->PFX ## _pixels_tab[IDX][3] = PFX ## NUM ## _mc30_c; \ + c->PFX ## _pixels_tab[IDX][4] = PFX ## NUM ## _mc01_c; \ + c->PFX ## _pixels_tab[IDX][5] = PFX ## NUM ## _mc11_c; \ + c->PFX ## _pixels_tab[IDX][6] = PFX ## NUM ## _mc21_c; \ + c->PFX ## _pixels_tab[IDX][7] = PFX ## NUM ## _mc31_c; \ + c->PFX ## _pixels_tab[IDX][8] = PFX ## NUM ## _mc02_c; \ + c->PFX ## _pixels_tab[IDX][9] = PFX ## NUM ## _mc12_c; \ + c->PFX ## _pixels_tab[IDX][10] = PFX ## NUM ## _mc22_c; \ + c->PFX ## _pixels_tab[IDX][11] = PFX ## NUM ## _mc32_c; \ + c->PFX ## _pixels_tab[IDX][12] = PFX ## NUM ## _mc03_c; \ + c->PFX ## _pixels_tab[IDX][13] = PFX ## NUM ## _mc13_c; \ + c->PFX ## _pixels_tab[IDX][14] = PFX ## NUM ## _mc23_c; \ + c->PFX ## _pixels_tab[IDX][15] = PFX ## NUM ## _mc33_c + + dspfunc(put_qpel, 0, 16); + dspfunc(put_qpel, 1, 8); + + dspfunc(put_no_rnd_qpel, 0, 16); + dspfunc(put_no_rnd_qpel, 1, 8); + + dspfunc(avg_qpel, 0, 16); + dspfunc(avg_qpel, 1, 8); + + if (ARCH_X86) + ff_qpeldsp_init_x86(c); + if (ARCH_MIPS) + ff_qpeldsp_init_mips(c); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qpeldsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qpeldsp.h new file mode 100644 index 0000000000..91019eda9c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qpeldsp.h @@ -0,0 +1,83 @@ +/* + * quarterpel DSP functions + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * quarterpel DSP functions + */ + +#ifndef AVCODEC_QPELDSP_H +#define AVCODEC_QPELDSP_H + +#include +#include + +void ff_put_pixels8x8_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_pixels8x8_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_put_pixels16x16_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); +void ff_avg_pixels16x16_c(uint8_t *dst, const uint8_t *src, ptrdiff_t stride); + +void ff_put_pixels8_l2_8(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + int dst_stride, int src_stride1, int src_stride2, + int h); + +#define DEF_OLD_QPEL(name) \ +void ff_put_ ## name(uint8_t *dst /* align width (8 or 16) */, \ + const uint8_t *src /* align 1 */, \ + ptrdiff_t stride); \ +void ff_put_no_rnd_ ## name(uint8_t *dst /* align width (8 or 16) */, \ + const uint8_t *src /* align 1 */, \ + ptrdiff_t stride); \ +void ff_avg_ ## name(uint8_t *dst /* align width (8 or 16) */, \ + const uint8_t *src /* align 1 */, \ + ptrdiff_t stride); + +DEF_OLD_QPEL(qpel16_mc11_old_c) +DEF_OLD_QPEL(qpel16_mc31_old_c) +DEF_OLD_QPEL(qpel16_mc12_old_c) +DEF_OLD_QPEL(qpel16_mc32_old_c) +DEF_OLD_QPEL(qpel16_mc13_old_c) +DEF_OLD_QPEL(qpel16_mc33_old_c) +DEF_OLD_QPEL(qpel8_mc11_old_c) +DEF_OLD_QPEL(qpel8_mc31_old_c) +DEF_OLD_QPEL(qpel8_mc12_old_c) +DEF_OLD_QPEL(qpel8_mc32_old_c) +DEF_OLD_QPEL(qpel8_mc13_old_c) +DEF_OLD_QPEL(qpel8_mc33_old_c) + +typedef void (*qpel_mc_func)(uint8_t *dst /* align width (8 or 16) */, + const uint8_t *src /* align 1 */, + ptrdiff_t stride); + +/** + * quarterpel DSP context + */ +typedef struct QpelDSPContext { + qpel_mc_func put_qpel_pixels_tab[2][16]; + qpel_mc_func avg_qpel_pixels_tab[2][16]; + qpel_mc_func put_no_rnd_qpel_pixels_tab[2][16]; +} QpelDSPContext; + +void ff_qpeldsp_init(QpelDSPContext *c); + +void ff_qpeldsp_init_x86(QpelDSPContext *c); +void ff_qpeldsp_init_mips(QpelDSPContext *c); + +#endif /* AVCODEC_QPELDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qsv.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qsv.h new file mode 100644 index 0000000000..b77158ec26 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qsv.h @@ -0,0 +1,107 @@ +/* + * Intel MediaSDK QSV public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_QSV_H +#define AVCODEC_QSV_H + +#include + +#include "libavutil/buffer.h" + +/** + * This struct is used for communicating QSV parameters between libavcodec and + * the caller. It is managed by the caller and must be assigned to + * AVCodecContext.hwaccel_context. + * - decoding: hwaccel_context must be set on return from the get_format() + * callback + * - encoding: hwaccel_context must be set before avcodec_open2() + */ +typedef struct AVQSVContext { + /** + * If non-NULL, the session to use for encoding or decoding. + * Otherwise, libavcodec will try to create an internal session. + */ + mfxSession session; + + /** + * The IO pattern to use. + */ + int iopattern; + + /** + * Extra buffers to pass to encoder or decoder initialization. + */ + mfxExtBuffer **ext_buffers; + int nb_ext_buffers; + + /** + * Encoding only. If this field is set to non-zero by the caller, libavcodec + * will create an mfxExtOpaqueSurfaceAlloc extended buffer and pass it to + * the encoder initialization. This only makes sense if iopattern is also + * set to MFX_IOPATTERN_IN_OPAQUE_MEMORY. + * + * The number of allocated opaque surfaces will be the sum of the number + * required by the encoder and the user-provided value nb_opaque_surfaces. + * The array of the opaque surfaces will be exported to the caller through + * the opaque_surfaces field. + */ + int opaque_alloc; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. Before + * calling avcodec_open2(), the caller should set this field to the number + * of extra opaque surfaces to allocate beyond what is required by the + * encoder. + * + * On return from avcodec_open2(), this field will be set by libavcodec to + * the total number of allocated opaque surfaces. + */ + int nb_opaque_surfaces; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. On return + * from avcodec_open2(), this field will be used by libavcodec to export the + * array of the allocated opaque surfaces to the caller, so they can be + * passed to other parts of the pipeline. + * + * The buffer reference exported here is owned and managed by libavcodec, + * the callers should make their own reference with av_buffer_ref() and free + * it with av_buffer_unref() when it is no longer needed. + * + * The buffer data is an nb_opaque_surfaces-sized array of mfxFrameSurface1. + */ + AVBufferRef *opaque_surfaces; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. On return + * from avcodec_open2(), this field will be set to the surface type used in + * the opaque allocation request. + */ + int opaque_alloc_type; +} AVQSVContext; + +/** + * Allocate a new context. + * + * It must be freed by the caller with av_free(). + */ +AVQSVContext *av_qsv_alloc_context(void); + +#endif /* AVCODEC_QSV_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qsv_api.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qsv_api.c new file mode 100644 index 0000000000..327ff7d813 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/qsv_api.c @@ -0,0 +1,42 @@ +/* + * Intel MediaSDK QSV public API functions + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include + +#include "libavutil/mem.h" + +#if CONFIG_QSV +#include "qsv.h" + +AVQSVContext *av_qsv_alloc_context(void) +{ + return av_mallocz(sizeof(AVQSVContext)); +} +#else + +struct AVQSVContext *av_qsv_alloc_context(void); + +struct AVQSVContext *av_qsv_alloc_context(void) +{ + return NULL; +} +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ratecontrol.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ratecontrol.c new file mode 100644 index 0000000000..49d169ba25 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ratecontrol.c @@ -0,0 +1,1028 @@ +/* + * Rate control for video encoders + * + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Rate control for video encoders. + */ + +#include "libavutil/attributes.h" +#include "libavutil/internal.h" + +#include "avcodec.h" +#include "internal.h" +#include "ratecontrol.h" +#include "mpegutils.h" +#include "mpegvideo.h" +#include "libavutil/eval.h" + +void ff_write_pass1_stats(MpegEncContext *s) +{ + snprintf(s->avctx->stats_out, 256, + "in:%d out:%d type:%d q:%d itex:%d ptex:%d mv:%d misc:%d " + "fcode:%d bcode:%d mc-var:%"PRId64" var:%"PRId64" icount:%d skipcount:%d hbits:%d;\n", + s->current_picture_ptr->f->display_picture_number, + s->current_picture_ptr->f->coded_picture_number, + s->pict_type, + s->current_picture.f->quality, + s->i_tex_bits, + s->p_tex_bits, + s->mv_bits, + s->misc_bits, + s->f_code, + s->b_code, + s->current_picture.mc_mb_var_sum, + s->current_picture.mb_var_sum, + s->i_count, s->skip_count, + s->header_bits); +} + +static double get_fps(AVCodecContext *avctx) +{ + return 1.0 / av_q2d(avctx->time_base) / FFMAX(avctx->ticks_per_frame, 1); +} + +static inline double qp2bits(RateControlEntry *rce, double qp) +{ + if (qp <= 0.0) { + av_log(NULL, AV_LOG_ERROR, "qp<=0.0\n"); + } + return rce->qscale * (double)(rce->i_tex_bits + rce->p_tex_bits + 1) / qp; +} + +static inline double bits2qp(RateControlEntry *rce, double bits) +{ + if (bits < 0.9) { + av_log(NULL, AV_LOG_ERROR, "bits<0.9\n"); + } + return rce->qscale * (double)(rce->i_tex_bits + rce->p_tex_bits + 1) / bits; +} + +static double get_diff_limited_q(MpegEncContext *s, RateControlEntry *rce, double q) +{ + RateControlContext *rcc = &s->rc_context; + AVCodecContext *a = s->avctx; + const int pict_type = rce->new_pict_type; + const double last_p_q = rcc->last_qscale_for[AV_PICTURE_TYPE_P]; + const double last_non_b_q = rcc->last_qscale_for[rcc->last_non_b_pict_type]; + + if (pict_type == AV_PICTURE_TYPE_I && + (a->i_quant_factor > 0.0 || rcc->last_non_b_pict_type == AV_PICTURE_TYPE_P)) + q = last_p_q * FFABS(a->i_quant_factor) + a->i_quant_offset; + else if (pict_type == AV_PICTURE_TYPE_B && + a->b_quant_factor > 0.0) + q = last_non_b_q * a->b_quant_factor + a->b_quant_offset; + if (q < 1) + q = 1; + + /* last qscale / qdiff stuff */ + if (rcc->last_non_b_pict_type == pict_type || pict_type != AV_PICTURE_TYPE_I) { + double last_q = rcc->last_qscale_for[pict_type]; + const int maxdiff = FF_QP2LAMBDA * a->max_qdiff; + + if (q > last_q + maxdiff) + q = last_q + maxdiff; + else if (q < last_q - maxdiff) + q = last_q - maxdiff; + } + + rcc->last_qscale_for[pict_type] = q; // Note we cannot do that after blurring + + if (pict_type != AV_PICTURE_TYPE_B) + rcc->last_non_b_pict_type = pict_type; + + return q; +} + +/** + * Get the qmin & qmax for pict_type. + */ +static void get_qminmax(int *qmin_ret, int *qmax_ret, MpegEncContext *s, int pict_type) +{ + int qmin = s->lmin; + int qmax = s->lmax; + + av_assert0(qmin <= qmax); + + switch (pict_type) { + case AV_PICTURE_TYPE_B: + qmin = (int)(qmin * FFABS(s->avctx->b_quant_factor) + s->avctx->b_quant_offset + 0.5); + qmax = (int)(qmax * FFABS(s->avctx->b_quant_factor) + s->avctx->b_quant_offset + 0.5); + break; + case AV_PICTURE_TYPE_I: + qmin = (int)(qmin * FFABS(s->avctx->i_quant_factor) + s->avctx->i_quant_offset + 0.5); + qmax = (int)(qmax * FFABS(s->avctx->i_quant_factor) + s->avctx->i_quant_offset + 0.5); + break; + } + + qmin = av_clip(qmin, 1, FF_LAMBDA_MAX); + qmax = av_clip(qmax, 1, FF_LAMBDA_MAX); + + if (qmax < qmin) + qmax = qmin; + + *qmin_ret = qmin; + *qmax_ret = qmax; +} + +static double modify_qscale(MpegEncContext *s, RateControlEntry *rce, + double q, int frame_num) +{ + RateControlContext *rcc = &s->rc_context; + const double buffer_size = s->avctx->rc_buffer_size; + const double fps = get_fps(s->avctx); + const double min_rate = s->avctx->rc_min_rate / fps; + const double max_rate = s->avctx->rc_max_rate / fps; + const int pict_type = rce->new_pict_type; + int qmin, qmax; + + get_qminmax(&qmin, &qmax, s, pict_type); + + /* modulation */ + if (s->rc_qmod_freq && + frame_num % s->rc_qmod_freq == 0 && + pict_type == AV_PICTURE_TYPE_P) + q *= s->rc_qmod_amp; + + /* buffer overflow/underflow protection */ + if (buffer_size) { + double expected_size = rcc->buffer_index; + double q_limit; + + if (min_rate) { + double d = 2 * (buffer_size - expected_size) / buffer_size; + if (d > 1.0) + d = 1.0; + else if (d < 0.0001) + d = 0.0001; + q *= pow(d, 1.0 / s->rc_buffer_aggressivity); + + q_limit = bits2qp(rce, + FFMAX((min_rate - buffer_size + rcc->buffer_index) * + s->avctx->rc_min_vbv_overflow_use, 1)); + + if (q > q_limit) { + if (s->avctx->debug & FF_DEBUG_RC) + av_log(s->avctx, AV_LOG_DEBUG, + "limiting QP %f -> %f\n", q, q_limit); + q = q_limit; + } + } + + if (max_rate) { + double d = 2 * expected_size / buffer_size; + if (d > 1.0) + d = 1.0; + else if (d < 0.0001) + d = 0.0001; + q /= pow(d, 1.0 / s->rc_buffer_aggressivity); + + q_limit = bits2qp(rce, + FFMAX(rcc->buffer_index * + s->avctx->rc_max_available_vbv_use, + 1)); + if (q < q_limit) { + if (s->avctx->debug & FF_DEBUG_RC) + av_log(s->avctx, AV_LOG_DEBUG, + "limiting QP %f -> %f\n", q, q_limit); + q = q_limit; + } + } + } + ff_dlog(s, "q:%f max:%f min:%f size:%f index:%f agr:%f\n", + q, max_rate, min_rate, buffer_size, rcc->buffer_index, + s->rc_buffer_aggressivity); + if (s->rc_qsquish == 0.0 || qmin == qmax) { + if (q < qmin) + q = qmin; + else if (q > qmax) + q = qmax; + } else { + double min2 = log(qmin); + double max2 = log(qmax); + + q = log(q); + q = (q - min2) / (max2 - min2) - 0.5; + q *= -4.0; + q = 1.0 / (1.0 + exp(q)); + q = q * (max2 - min2) + min2; + + q = exp(q); + } + + return q; +} + +/** + * Modify the bitrate curve from pass1 for one frame. + */ +static double get_qscale(MpegEncContext *s, RateControlEntry *rce, + double rate_factor, int frame_num) +{ + RateControlContext *rcc = &s->rc_context; + AVCodecContext *a = s->avctx; + const int pict_type = rce->new_pict_type; + const double mb_num = s->mb_num; + double q, bits; + int i; + + double const_values[] = { + M_PI, + M_E, + rce->i_tex_bits * rce->qscale, + rce->p_tex_bits * rce->qscale, + (rce->i_tex_bits + rce->p_tex_bits) * (double)rce->qscale, + rce->mv_bits / mb_num, + rce->pict_type == AV_PICTURE_TYPE_B ? (rce->f_code + rce->b_code) * 0.5 : rce->f_code, + rce->i_count / mb_num, + rce->mc_mb_var_sum / mb_num, + rce->mb_var_sum / mb_num, + rce->pict_type == AV_PICTURE_TYPE_I, + rce->pict_type == AV_PICTURE_TYPE_P, + rce->pict_type == AV_PICTURE_TYPE_B, + rcc->qscale_sum[pict_type] / (double)rcc->frame_count[pict_type], + a->qcompress, + rcc->i_cplx_sum[AV_PICTURE_TYPE_I] / (double)rcc->frame_count[AV_PICTURE_TYPE_I], + rcc->i_cplx_sum[AV_PICTURE_TYPE_P] / (double)rcc->frame_count[AV_PICTURE_TYPE_P], + rcc->p_cplx_sum[AV_PICTURE_TYPE_P] / (double)rcc->frame_count[AV_PICTURE_TYPE_P], + rcc->p_cplx_sum[AV_PICTURE_TYPE_B] / (double)rcc->frame_count[AV_PICTURE_TYPE_B], + (rcc->i_cplx_sum[pict_type] + rcc->p_cplx_sum[pict_type]) / (double)rcc->frame_count[pict_type], + 0 + }; + + bits = av_expr_eval(rcc->rc_eq_eval, const_values, rce); + if (isnan(bits)) { + av_log(s->avctx, AV_LOG_ERROR, "Error evaluating rc_eq \"%s\"\n", s->rc_eq); + return -1; + } + + rcc->pass1_rc_eq_output_sum += bits; + bits *= rate_factor; + if (bits < 0.0) + bits = 0.0; + bits += 1.0; // avoid 1/0 issues + + /* user override */ + for (i = 0; i < s->avctx->rc_override_count; i++) { + RcOverride *rco = s->avctx->rc_override; + if (rco[i].start_frame > frame_num) + continue; + if (rco[i].end_frame < frame_num) + continue; + + if (rco[i].qscale) + bits = qp2bits(rce, rco[i].qscale); // FIXME move at end to really force it? + else + bits *= rco[i].quality_factor; + } + + q = bits2qp(rce, bits); + + /* I/B difference */ + if (pict_type == AV_PICTURE_TYPE_I && s->avctx->i_quant_factor < 0.0) + q = -q * s->avctx->i_quant_factor + s->avctx->i_quant_offset; + else if (pict_type == AV_PICTURE_TYPE_B && s->avctx->b_quant_factor < 0.0) + q = -q * s->avctx->b_quant_factor + s->avctx->b_quant_offset; + if (q < 1) + q = 1; + + return q; +} + +static int init_pass2(MpegEncContext *s) +{ + RateControlContext *rcc = &s->rc_context; + AVCodecContext *a = s->avctx; + int i, toobig; + double fps = get_fps(s->avctx); + double complexity[5] = { 0 }; // approximate bits at quant=1 + uint64_t const_bits[5] = { 0 }; // quantizer independent bits + uint64_t all_const_bits; + uint64_t all_available_bits = (uint64_t)(s->bit_rate * + (double)rcc->num_entries / fps); + double rate_factor = 0; + double step; + const int filter_size = (int)(a->qblur * 4) | 1; + double expected_bits = 0; // init to silence gcc warning + double *qscale, *blurred_qscale, qscale_sum; + + /* find complexity & const_bits & decide the pict_types */ + for (i = 0; i < rcc->num_entries; i++) { + RateControlEntry *rce = &rcc->entry[i]; + + rce->new_pict_type = rce->pict_type; + rcc->i_cplx_sum[rce->pict_type] += rce->i_tex_bits * rce->qscale; + rcc->p_cplx_sum[rce->pict_type] += rce->p_tex_bits * rce->qscale; + rcc->mv_bits_sum[rce->pict_type] += rce->mv_bits; + rcc->frame_count[rce->pict_type]++; + + complexity[rce->new_pict_type] += (rce->i_tex_bits + rce->p_tex_bits) * + (double)rce->qscale; + const_bits[rce->new_pict_type] += rce->mv_bits + rce->misc_bits; + } + + all_const_bits = const_bits[AV_PICTURE_TYPE_I] + + const_bits[AV_PICTURE_TYPE_P] + + const_bits[AV_PICTURE_TYPE_B]; + + if (all_available_bits < all_const_bits) { + av_log(s->avctx, AV_LOG_ERROR, "requested bitrate is too low\n"); + return -1; + } + + qscale = av_malloc_array(rcc->num_entries, sizeof(double)); + blurred_qscale = av_malloc_array(rcc->num_entries, sizeof(double)); + if (!qscale || !blurred_qscale) { + av_free(qscale); + av_free(blurred_qscale); + return AVERROR(ENOMEM); + } + toobig = 0; + + for (step = 256 * 256; step > 0.0000001; step *= 0.5) { + expected_bits = 0; + rate_factor += step; + + rcc->buffer_index = s->avctx->rc_buffer_size / 2; + + /* find qscale */ + for (i = 0; i < rcc->num_entries; i++) { + RateControlEntry *rce = &rcc->entry[i]; + + qscale[i] = get_qscale(s, &rcc->entry[i], rate_factor, i); + rcc->last_qscale_for[rce->pict_type] = qscale[i]; + } + av_assert0(filter_size % 2 == 1); + + /* fixed I/B QP relative to P mode */ + for (i = FFMAX(0, rcc->num_entries - 300); i < rcc->num_entries; i++) { + RateControlEntry *rce = &rcc->entry[i]; + + qscale[i] = get_diff_limited_q(s, rce, qscale[i]); + } + + for (i = rcc->num_entries - 1; i >= 0; i--) { + RateControlEntry *rce = &rcc->entry[i]; + + qscale[i] = get_diff_limited_q(s, rce, qscale[i]); + } + + /* smooth curve */ + for (i = 0; i < rcc->num_entries; i++) { + RateControlEntry *rce = &rcc->entry[i]; + const int pict_type = rce->new_pict_type; + int j; + double q = 0.0, sum = 0.0; + + for (j = 0; j < filter_size; j++) { + int index = i + j - filter_size / 2; + double d = index - i; + double coeff = a->qblur == 0 ? 1.0 : exp(-d * d / (a->qblur * a->qblur)); + + if (index < 0 || index >= rcc->num_entries) + continue; + if (pict_type != rcc->entry[index].new_pict_type) + continue; + q += qscale[index] * coeff; + sum += coeff; + } + blurred_qscale[i] = q / sum; + } + + /* find expected bits */ + for (i = 0; i < rcc->num_entries; i++) { + RateControlEntry *rce = &rcc->entry[i]; + double bits; + + rce->new_qscale = modify_qscale(s, rce, blurred_qscale[i], i); + + bits = qp2bits(rce, rce->new_qscale) + rce->mv_bits + rce->misc_bits; + bits += 8 * ff_vbv_update(s, bits); + + rce->expected_bits = expected_bits; + expected_bits += bits; + } + + ff_dlog(s->avctx, + "expected_bits: %f all_available_bits: %d rate_factor: %f\n", + expected_bits, (int)all_available_bits, rate_factor); + if (expected_bits > all_available_bits) { + rate_factor -= step; + ++toobig; + } + } + av_free(qscale); + av_free(blurred_qscale); + + /* check bitrate calculations and print info */ + qscale_sum = 0.0; + for (i = 0; i < rcc->num_entries; i++) { + ff_dlog(s, "[lavc rc] entry[%d].new_qscale = %.3f qp = %.3f\n", + i, + rcc->entry[i].new_qscale, + rcc->entry[i].new_qscale / FF_QP2LAMBDA); + qscale_sum += av_clip(rcc->entry[i].new_qscale / FF_QP2LAMBDA, + s->avctx->qmin, s->avctx->qmax); + } + av_assert0(toobig <= 40); + av_log(s->avctx, AV_LOG_DEBUG, + "[lavc rc] requested bitrate: %"PRId64" bps expected bitrate: %"PRId64" bps\n", + s->bit_rate, + (int64_t)(expected_bits / ((double)all_available_bits / s->bit_rate))); + av_log(s->avctx, AV_LOG_DEBUG, + "[lavc rc] estimated target average qp: %.3f\n", + (float)qscale_sum / rcc->num_entries); + if (toobig == 0) { + av_log(s->avctx, AV_LOG_INFO, + "[lavc rc] Using all of requested bitrate is not " + "necessary for this video with these parameters.\n"); + } else if (toobig == 40) { + av_log(s->avctx, AV_LOG_ERROR, + "[lavc rc] Error: bitrate too low for this video " + "with these parameters.\n"); + return -1; + } else if (fabs(expected_bits / all_available_bits - 1.0) > 0.01) { + av_log(s->avctx, AV_LOG_ERROR, + "[lavc rc] Error: 2pass curve failed to converge\n"); + return -1; + } + + return 0; +} + +av_cold int ff_rate_control_init(MpegEncContext *s) +{ + RateControlContext *rcc = &s->rc_context; + int i, res; + static const char * const const_names[] = { + "PI", + "E", + "iTex", + "pTex", + "tex", + "mv", + "fCode", + "iCount", + "mcVar", + "var", + "isI", + "isP", + "isB", + "avgQP", + "qComp", + "avgIITex", + "avgPITex", + "avgPPTex", + "avgBPTex", + "avgTex", + NULL + }; + static double (* const func1[])(void *, double) = { + (double (*)(void *, double)) bits2qp, + (double (*)(void *, double)) qp2bits, + NULL + }; + static const char * const func1_names[] = { + "bits2qp", + "qp2bits", + NULL + }; + emms_c(); + + if (!s->avctx->rc_max_available_vbv_use && s->avctx->rc_buffer_size) { + if (s->avctx->rc_max_rate) { + s->avctx->rc_max_available_vbv_use = av_clipf(s->avctx->rc_max_rate/(s->avctx->rc_buffer_size*get_fps(s->avctx)), 1.0/3, 1.0); + } else + s->avctx->rc_max_available_vbv_use = 1.0; + } + + res = av_expr_parse(&rcc->rc_eq_eval, + s->rc_eq ? s->rc_eq : "tex^qComp", + const_names, func1_names, func1, + NULL, NULL, 0, s->avctx); + if (res < 0) { + av_log(s->avctx, AV_LOG_ERROR, "Error parsing rc_eq \"%s\"\n", s->rc_eq); + return res; + } + + for (i = 0; i < 5; i++) { + rcc->pred[i].coeff = FF_QP2LAMBDA * 7.0; + rcc->pred[i].count = 1.0; + rcc->pred[i].decay = 0.4; + + rcc->i_cplx_sum [i] = + rcc->p_cplx_sum [i] = + rcc->mv_bits_sum[i] = + rcc->qscale_sum [i] = + rcc->frame_count[i] = 1; // 1 is better because of 1/0 and such + + rcc->last_qscale_for[i] = FF_QP2LAMBDA * 5; + } + rcc->buffer_index = s->avctx->rc_initial_buffer_occupancy; + if (!rcc->buffer_index) + rcc->buffer_index = s->avctx->rc_buffer_size * 3 / 4; + + if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { + int i; + char *p; + + /* find number of pics */ + p = s->avctx->stats_in; + for (i = -1; p; i++) + p = strchr(p + 1, ';'); + i += s->max_b_frames; + if (i <= 0 || i >= INT_MAX / sizeof(RateControlEntry)) + return -1; + rcc->entry = av_mallocz(i * sizeof(RateControlEntry)); + if (!rcc->entry) + return AVERROR(ENOMEM); + rcc->num_entries = i; + + /* init all to skipped P-frames + * (with B-frames we might have a not encoded frame at the end FIXME) */ + for (i = 0; i < rcc->num_entries; i++) { + RateControlEntry *rce = &rcc->entry[i]; + + rce->pict_type = rce->new_pict_type = AV_PICTURE_TYPE_P; + rce->qscale = rce->new_qscale = FF_QP2LAMBDA * 2; + rce->misc_bits = s->mb_num + 10; + rce->mb_var_sum = s->mb_num * 100; + } + + /* read stats */ + p = s->avctx->stats_in; + for (i = 0; i < rcc->num_entries - s->max_b_frames; i++) { + RateControlEntry *rce; + int picture_number; + int e; + char *next; + + next = strchr(p, ';'); + if (next) { + (*next) = 0; // sscanf is unbelievably slow on looong strings // FIXME copy / do not write + next++; + } + e = sscanf(p, " in:%d ", &picture_number); + + av_assert0(picture_number >= 0); + av_assert0(picture_number < rcc->num_entries); + rce = &rcc->entry[picture_number]; + + e += sscanf(p, " in:%*d out:%*d type:%d q:%f itex:%d ptex:%d mv:%d misc:%d fcode:%d bcode:%d mc-var:%"SCNd64" var:%"SCNd64" icount:%d skipcount:%d hbits:%d", + &rce->pict_type, &rce->qscale, &rce->i_tex_bits, &rce->p_tex_bits, + &rce->mv_bits, &rce->misc_bits, + &rce->f_code, &rce->b_code, + &rce->mc_mb_var_sum, &rce->mb_var_sum, + &rce->i_count, &rce->skip_count, &rce->header_bits); + if (e != 14) { + av_log(s->avctx, AV_LOG_ERROR, + "statistics are damaged at line %d, parser out=%d\n", + i, e); + return -1; + } + + p = next; + } + + if (init_pass2(s) < 0) { + ff_rate_control_uninit(s); + return -1; + } + } + + if (!(s->avctx->flags & AV_CODEC_FLAG_PASS2)) { + rcc->short_term_qsum = 0.001; + rcc->short_term_qcount = 0.001; + + rcc->pass1_rc_eq_output_sum = 0.001; + rcc->pass1_wanted_bits = 0.001; + + if (s->avctx->qblur > 1.0) { + av_log(s->avctx, AV_LOG_ERROR, "qblur too large\n"); + return -1; + } + /* init stuff with the user specified complexity */ + if (s->rc_initial_cplx) { + for (i = 0; i < 60 * 30; i++) { + double bits = s->rc_initial_cplx * (i / 10000.0 + 1.0) * s->mb_num; + RateControlEntry rce; + + if (i % ((s->gop_size + 3) / 4) == 0) + rce.pict_type = AV_PICTURE_TYPE_I; + else if (i % (s->max_b_frames + 1)) + rce.pict_type = AV_PICTURE_TYPE_B; + else + rce.pict_type = AV_PICTURE_TYPE_P; + + rce.new_pict_type = rce.pict_type; + rce.mc_mb_var_sum = bits * s->mb_num / 100000; + rce.mb_var_sum = s->mb_num; + + rce.qscale = FF_QP2LAMBDA * 2; + rce.f_code = 2; + rce.b_code = 1; + rce.misc_bits = 1; + + if (s->pict_type == AV_PICTURE_TYPE_I) { + rce.i_count = s->mb_num; + rce.i_tex_bits = bits; + rce.p_tex_bits = 0; + rce.mv_bits = 0; + } else { + rce.i_count = 0; // FIXME we do know this approx + rce.i_tex_bits = 0; + rce.p_tex_bits = bits * 0.9; + rce.mv_bits = bits * 0.1; + } + rcc->i_cplx_sum[rce.pict_type] += rce.i_tex_bits * rce.qscale; + rcc->p_cplx_sum[rce.pict_type] += rce.p_tex_bits * rce.qscale; + rcc->mv_bits_sum[rce.pict_type] += rce.mv_bits; + rcc->frame_count[rce.pict_type]++; + + get_qscale(s, &rce, rcc->pass1_wanted_bits / rcc->pass1_rc_eq_output_sum, i); + + // FIXME misbehaves a little for variable fps + rcc->pass1_wanted_bits += s->bit_rate / get_fps(s->avctx); + } + } + } + + return 0; +} + +av_cold void ff_rate_control_uninit(MpegEncContext *s) +{ + RateControlContext *rcc = &s->rc_context; + emms_c(); + + av_expr_free(rcc->rc_eq_eval); + av_freep(&rcc->entry); +} + +int ff_vbv_update(MpegEncContext *s, int frame_size) +{ + RateControlContext *rcc = &s->rc_context; + const double fps = get_fps(s->avctx); + const int buffer_size = s->avctx->rc_buffer_size; + const double min_rate = s->avctx->rc_min_rate / fps; + const double max_rate = s->avctx->rc_max_rate / fps; + + ff_dlog(s, "%d %f %d %f %f\n", + buffer_size, rcc->buffer_index, frame_size, min_rate, max_rate); + + if (buffer_size) { + int left; + + rcc->buffer_index -= frame_size; + if (rcc->buffer_index < 0) { + av_log(s->avctx, AV_LOG_ERROR, "rc buffer underflow\n"); + if (frame_size > max_rate && s->qscale == s->avctx->qmax) { + av_log(s->avctx, AV_LOG_ERROR, "max bitrate possibly too small or try trellis with large lmax or increase qmax\n"); + } + rcc->buffer_index = 0; + } + + left = buffer_size - rcc->buffer_index - 1; + rcc->buffer_index += av_clip(left, min_rate, max_rate); + + if (rcc->buffer_index > buffer_size) { + int stuffing = ceil((rcc->buffer_index - buffer_size) / 8); + + if (stuffing < 4 && s->codec_id == AV_CODEC_ID_MPEG4) + stuffing = 4; + rcc->buffer_index -= 8 * stuffing; + + if (s->avctx->debug & FF_DEBUG_RC) + av_log(s->avctx, AV_LOG_DEBUG, "stuffing %d bytes\n", stuffing); + + return stuffing; + } + } + return 0; +} + +static double predict_size(Predictor *p, double q, double var) +{ + return p->coeff * var / (q * p->count); +} + +static void update_predictor(Predictor *p, double q, double var, double size) +{ + double new_coeff = size * q / (var + 1); + if (var < 10) + return; + + p->count *= p->decay; + p->coeff *= p->decay; + p->count++; + p->coeff += new_coeff; +} + +static void adaptive_quantization(MpegEncContext *s, double q) +{ + int i; + const float lumi_masking = s->avctx->lumi_masking / (128.0 * 128.0); + const float dark_masking = s->avctx->dark_masking / (128.0 * 128.0); + const float temp_cplx_masking = s->avctx->temporal_cplx_masking; + const float spatial_cplx_masking = s->avctx->spatial_cplx_masking; + const float p_masking = s->avctx->p_masking; + const float border_masking = s->border_masking; + float bits_sum = 0.0; + float cplx_sum = 0.0; + float *cplx_tab = s->cplx_tab; + float *bits_tab = s->bits_tab; + const int qmin = s->avctx->mb_lmin; + const int qmax = s->avctx->mb_lmax; + Picture *const pic = &s->current_picture; + const int mb_width = s->mb_width; + const int mb_height = s->mb_height; + + for (i = 0; i < s->mb_num; i++) { + const int mb_xy = s->mb_index2xy[i]; + float temp_cplx = sqrt(pic->mc_mb_var[mb_xy]); // FIXME merge in pow() + float spat_cplx = sqrt(pic->mb_var[mb_xy]); + const int lumi = pic->mb_mean[mb_xy]; + float bits, cplx, factor; + int mb_x = mb_xy % s->mb_stride; + int mb_y = mb_xy / s->mb_stride; + int mb_distance; + float mb_factor = 0.0; + if (spat_cplx < 4) + spat_cplx = 4; // FIXME fine-tune + if (temp_cplx < 4) + temp_cplx = 4; // FIXME fine-tune + + if ((s->mb_type[mb_xy] & CANDIDATE_MB_TYPE_INTRA)) { // FIXME hq mode + cplx = spat_cplx; + factor = 1.0 + p_masking; + } else { + cplx = temp_cplx; + factor = pow(temp_cplx, -temp_cplx_masking); + } + factor *= pow(spat_cplx, -spatial_cplx_masking); + + if (lumi > 127) + factor *= (1.0 - (lumi - 128) * (lumi - 128) * lumi_masking); + else + factor *= (1.0 - (lumi - 128) * (lumi - 128) * dark_masking); + + if (mb_x < mb_width / 5) { + mb_distance = mb_width / 5 - mb_x; + mb_factor = (float)mb_distance / (float)(mb_width / 5); + } else if (mb_x > 4 * mb_width / 5) { + mb_distance = mb_x - 4 * mb_width / 5; + mb_factor = (float)mb_distance / (float)(mb_width / 5); + } + if (mb_y < mb_height / 5) { + mb_distance = mb_height / 5 - mb_y; + mb_factor = FFMAX(mb_factor, + (float)mb_distance / (float)(mb_height / 5)); + } else if (mb_y > 4 * mb_height / 5) { + mb_distance = mb_y - 4 * mb_height / 5; + mb_factor = FFMAX(mb_factor, + (float)mb_distance / (float)(mb_height / 5)); + } + + factor *= 1.0 - border_masking * mb_factor; + + if (factor < 0.00001) + factor = 0.00001; + + bits = cplx * factor; + cplx_sum += cplx; + bits_sum += bits; + cplx_tab[i] = cplx; + bits_tab[i] = bits; + } + + /* handle qmin/qmax clipping */ + if (s->mpv_flags & FF_MPV_FLAG_NAQ) { + float factor = bits_sum / cplx_sum; + for (i = 0; i < s->mb_num; i++) { + float newq = q * cplx_tab[i] / bits_tab[i]; + newq *= factor; + + if (newq > qmax) { + bits_sum -= bits_tab[i]; + cplx_sum -= cplx_tab[i] * q / qmax; + } else if (newq < qmin) { + bits_sum -= bits_tab[i]; + cplx_sum -= cplx_tab[i] * q / qmin; + } + } + if (bits_sum < 0.001) + bits_sum = 0.001; + if (cplx_sum < 0.001) + cplx_sum = 0.001; + } + + for (i = 0; i < s->mb_num; i++) { + const int mb_xy = s->mb_index2xy[i]; + float newq = q * cplx_tab[i] / bits_tab[i]; + int intq; + + if (s->mpv_flags & FF_MPV_FLAG_NAQ) { + newq *= bits_sum / cplx_sum; + } + + intq = (int)(newq + 0.5); + + if (intq > qmax) + intq = qmax; + else if (intq < qmin) + intq = qmin; + s->lambda_table[mb_xy] = intq; + } +} + +void ff_get_2pass_fcode(MpegEncContext *s) +{ + RateControlContext *rcc = &s->rc_context; + RateControlEntry *rce = &rcc->entry[s->picture_number]; + + s->f_code = rce->f_code; + s->b_code = rce->b_code; +} + +// FIXME rd or at least approx for dquant + +float ff_rate_estimate_qscale(MpegEncContext *s, int dry_run) +{ + float q; + int qmin, qmax; + float br_compensation; + double diff; + double short_term_q; + double fps; + int picture_number = s->picture_number; + int64_t wanted_bits; + RateControlContext *rcc = &s->rc_context; + AVCodecContext *a = s->avctx; + RateControlEntry local_rce, *rce; + double bits; + double rate_factor; + int64_t var; + const int pict_type = s->pict_type; + Picture * const pic = &s->current_picture; + emms_c(); + + get_qminmax(&qmin, &qmax, s, pict_type); + + fps = get_fps(s->avctx); + /* update predictors */ + if (picture_number > 2 && !dry_run) { + const int64_t last_var = + s->last_pict_type == AV_PICTURE_TYPE_I ? rcc->last_mb_var_sum + : rcc->last_mc_mb_var_sum; + av_assert1(s->frame_bits >= s->stuffing_bits); + update_predictor(&rcc->pred[s->last_pict_type], + rcc->last_qscale, + sqrt(last_var), + s->frame_bits - s->stuffing_bits); + } + + if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { + av_assert0(picture_number >= 0); + if (picture_number >= rcc->num_entries) { + av_log(s, AV_LOG_ERROR, "Input is longer than 2-pass log file\n"); + return -1; + } + rce = &rcc->entry[picture_number]; + wanted_bits = rce->expected_bits; + } else { + Picture *dts_pic; + rce = &local_rce; + + /* FIXME add a dts field to AVFrame and ensure it is set and use it + * here instead of reordering but the reordering is simpler for now + * until H.264 B-pyramid must be handled. */ + if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) + dts_pic = s->current_picture_ptr; + else + dts_pic = s->last_picture_ptr; + + if (!dts_pic || dts_pic->f->pts == AV_NOPTS_VALUE) + wanted_bits = (uint64_t)(s->bit_rate * (double)picture_number / fps); + else + wanted_bits = (uint64_t)(s->bit_rate * (double)dts_pic->f->pts / fps); + } + + diff = s->total_bits - wanted_bits; + br_compensation = (a->bit_rate_tolerance - diff) / a->bit_rate_tolerance; + if (br_compensation <= 0.0) + br_compensation = 0.001; + + var = pict_type == AV_PICTURE_TYPE_I ? pic->mb_var_sum : pic->mc_mb_var_sum; + + short_term_q = 0; /* avoid warning */ + if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { + if (pict_type != AV_PICTURE_TYPE_I) + av_assert0(pict_type == rce->new_pict_type); + + q = rce->new_qscale / br_compensation; + ff_dlog(s, "%f %f %f last:%d var:%"PRId64" type:%d//\n", q, rce->new_qscale, + br_compensation, s->frame_bits, var, pict_type); + } else { + rce->pict_type = + rce->new_pict_type = pict_type; + rce->mc_mb_var_sum = pic->mc_mb_var_sum; + rce->mb_var_sum = pic->mb_var_sum; + rce->qscale = FF_QP2LAMBDA * 2; + rce->f_code = s->f_code; + rce->b_code = s->b_code; + rce->misc_bits = 1; + + bits = predict_size(&rcc->pred[pict_type], rce->qscale, sqrt(var)); + if (pict_type == AV_PICTURE_TYPE_I) { + rce->i_count = s->mb_num; + rce->i_tex_bits = bits; + rce->p_tex_bits = 0; + rce->mv_bits = 0; + } else { + rce->i_count = 0; // FIXME we do know this approx + rce->i_tex_bits = 0; + rce->p_tex_bits = bits * 0.9; + rce->mv_bits = bits * 0.1; + } + rcc->i_cplx_sum[pict_type] += rce->i_tex_bits * rce->qscale; + rcc->p_cplx_sum[pict_type] += rce->p_tex_bits * rce->qscale; + rcc->mv_bits_sum[pict_type] += rce->mv_bits; + rcc->frame_count[pict_type]++; + + rate_factor = rcc->pass1_wanted_bits / + rcc->pass1_rc_eq_output_sum * br_compensation; + + q = get_qscale(s, rce, rate_factor, picture_number); + if (q < 0) + return -1; + + av_assert0(q > 0.0); + q = get_diff_limited_q(s, rce, q); + av_assert0(q > 0.0); + + // FIXME type dependent blur like in 2-pass + if (pict_type == AV_PICTURE_TYPE_P || s->intra_only) { + rcc->short_term_qsum *= a->qblur; + rcc->short_term_qcount *= a->qblur; + + rcc->short_term_qsum += q; + rcc->short_term_qcount++; + q = short_term_q = rcc->short_term_qsum / rcc->short_term_qcount; + } + av_assert0(q > 0.0); + + q = modify_qscale(s, rce, q, picture_number); + + rcc->pass1_wanted_bits += s->bit_rate / fps; + + av_assert0(q > 0.0); + } + + if (s->avctx->debug & FF_DEBUG_RC) { + av_log(s->avctx, AV_LOG_DEBUG, + "%c qp:%d<%2.1f<%d %d want:%d total:%d comp:%f st_q:%2.2f " + "size:%d var:%"PRId64"/%"PRId64" br:%"PRId64" fps:%d\n", + av_get_picture_type_char(pict_type), + qmin, q, qmax, picture_number, + (int)wanted_bits / 1000, (int)s->total_bits / 1000, + br_compensation, short_term_q, s->frame_bits, + pic->mb_var_sum, pic->mc_mb_var_sum, + s->bit_rate / 1000, (int)fps); + } + + if (q < qmin) + q = qmin; + else if (q > qmax) + q = qmax; + + if (s->adaptive_quant) + adaptive_quantization(s, q); + else + q = (int)(q + 0.5); + + if (!dry_run) { + rcc->last_qscale = q; + rcc->last_mc_mb_var_sum = pic->mc_mb_var_sum; + rcc->last_mb_var_sum = pic->mb_var_sum; + } + return q; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ratecontrol.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ratecontrol.h new file mode 100644 index 0000000000..2a7aaec644 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/ratecontrol.h @@ -0,0 +1,99 @@ +/* + * Ratecontrol + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_RATECONTROL_H +#define AVCODEC_RATECONTROL_H + +/** + * @file + * ratecontrol header. + */ + +#include +#include +#include "libavutil/eval.h" + +typedef struct Predictor{ + double coeff; + double count; + double decay; +} Predictor; + +typedef struct RateControlEntry{ + int pict_type; + float qscale; + int mv_bits; + int i_tex_bits; + int p_tex_bits; + int misc_bits; + int header_bits; + uint64_t expected_bits; + int new_pict_type; + float new_qscale; + int64_t mc_mb_var_sum; + int64_t mb_var_sum; + int i_count; + int skip_count; + int f_code; + int b_code; +}RateControlEntry; + +/** + * rate control context. + */ +typedef struct RateControlContext{ + int num_entries; ///< number of RateControlEntries + RateControlEntry *entry; + double buffer_index; ///< amount of bits in the video/audio buffer + Predictor pred[5]; + double short_term_qsum; ///< sum of recent qscales + double short_term_qcount; ///< count of recent qscales + double pass1_rc_eq_output_sum;///< sum of the output of the rc equation, this is used for normalization + double pass1_wanted_bits; ///< bits which should have been output by the pass1 code (including complexity init) + double last_qscale; + double last_qscale_for[5]; ///< last qscale for a specific pict type, used for max_diff & ipb factor stuff + int64_t last_mc_mb_var_sum; + int64_t last_mb_var_sum; + uint64_t i_cplx_sum[5]; + uint64_t p_cplx_sum[5]; + uint64_t mv_bits_sum[5]; + uint64_t qscale_sum[5]; + int frame_count[5]; + int last_non_b_pict_type; + + void *non_lavc_opaque; ///< context for non lavc rc code (for example xvid) + float dry_run_qscale; ///< for xvid rc + int last_picture_number; ///< for xvid rc + AVExpr * rc_eq_eval; +}RateControlContext; + +struct MpegEncContext; + +/* rate control */ +int ff_rate_control_init(struct MpegEncContext *s); +float ff_rate_estimate_qscale(struct MpegEncContext *s, int dry_run); +void ff_write_pass1_stats(struct MpegEncContext *s); +void ff_rate_control_uninit(struct MpegEncContext *s); +int ff_vbv_update(struct MpegEncContext *s, int frame_size); +void ff_get_2pass_fcode(struct MpegEncContext *s); + +#endif /* AVCODEC_RATECONTROL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/raw.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/raw.c new file mode 100644 index 0000000000..b6fb91c1c6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/raw.c @@ -0,0 +1,338 @@ +/* + * Raw Video Codec + * Copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Raw Video Codec + */ + +#include "avcodec.h" +#include "raw.h" +#include "libavutil/common.h" + +const PixelFormatTag ff_raw_pix_fmt_tags[] = { + { AV_PIX_FMT_YUV420P, MKTAG('I', '4', '2', '0') }, /* Planar formats */ + { AV_PIX_FMT_YUV420P, MKTAG('I', 'Y', 'U', 'V') }, + { AV_PIX_FMT_YUV420P, MKTAG('y', 'v', '1', '2') }, + { AV_PIX_FMT_YUV420P, MKTAG('Y', 'V', '1', '2') }, + { AV_PIX_FMT_YUV410P, MKTAG('Y', 'U', 'V', '9') }, + { AV_PIX_FMT_YUV410P, MKTAG('Y', 'V', 'U', '9') }, + { AV_PIX_FMT_YUV411P, MKTAG('Y', '4', '1', 'B') }, + { AV_PIX_FMT_YUV422P, MKTAG('Y', '4', '2', 'B') }, + { AV_PIX_FMT_YUV422P, MKTAG('P', '4', '2', '2') }, + { AV_PIX_FMT_YUV422P, MKTAG('Y', 'V', '1', '6') }, + /* yuvjXXX formats are deprecated hacks specific to libav*, + they are identical to yuvXXX */ + { AV_PIX_FMT_YUVJ420P, MKTAG('I', '4', '2', '0') }, /* Planar formats */ + { AV_PIX_FMT_YUVJ420P, MKTAG('I', 'Y', 'U', 'V') }, + { AV_PIX_FMT_YUVJ420P, MKTAG('Y', 'V', '1', '2') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('Y', '4', '2', 'B') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('P', '4', '2', '2') }, + { AV_PIX_FMT_GRAY8, MKTAG('Y', '8', '0', '0') }, + { AV_PIX_FMT_GRAY8, MKTAG('Y', '8', ' ', ' ') }, + + { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'Y', '2') }, /* Packed formats */ + { AV_PIX_FMT_YUYV422, MKTAG('Y', '4', '2', '2') }, + { AV_PIX_FMT_YUYV422, MKTAG('V', '4', '2', '2') }, + { AV_PIX_FMT_YUYV422, MKTAG('V', 'Y', 'U', 'Y') }, + { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'N', 'V') }, + { AV_PIX_FMT_YUYV422, MKTAG('Y', 'U', 'Y', 'V') }, + { AV_PIX_FMT_YVYU422, MKTAG('Y', 'V', 'Y', 'U') }, /* Philips */ + { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'V', 'Y') }, + { AV_PIX_FMT_UYVY422, MKTAG('H', 'D', 'Y', 'C') }, + { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'N', 'V') }, + { AV_PIX_FMT_UYVY422, MKTAG('U', 'Y', 'N', 'Y') }, + { AV_PIX_FMT_UYVY422, MKTAG('u', 'y', 'v', '1') }, + { AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', '1') }, + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'R', 'n') }, /* Avid AVI Codec 1:1 */ + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', '1', 'x') }, /* Avid 1:1x */ + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'u', 'p') }, + { AV_PIX_FMT_UYVY422, MKTAG('V', 'D', 'T', 'Z') }, /* SoftLab-NSK VideoTizer */ + { AV_PIX_FMT_UYVY422, MKTAG('a', 'u', 'v', '2') }, + { AV_PIX_FMT_UYVY422, MKTAG('c', 'y', 'u', 'v') }, /* CYUV is also Creative YUV */ + { AV_PIX_FMT_UYYVYY411, MKTAG('Y', '4', '1', '1') }, + { AV_PIX_FMT_GRAY8, MKTAG('G', 'R', 'E', 'Y') }, + { AV_PIX_FMT_NV12, MKTAG('N', 'V', '1', '2') }, + { AV_PIX_FMT_NV21, MKTAG('N', 'V', '2', '1') }, + + /* nut */ + { AV_PIX_FMT_RGB555LE, MKTAG('R', 'G', 'B', 15) }, + { AV_PIX_FMT_BGR555LE, MKTAG('B', 'G', 'R', 15) }, + { AV_PIX_FMT_RGB565LE, MKTAG('R', 'G', 'B', 16) }, + { AV_PIX_FMT_BGR565LE, MKTAG('B', 'G', 'R', 16) }, + { AV_PIX_FMT_RGB555BE, MKTAG(15 , 'B', 'G', 'R') }, + { AV_PIX_FMT_BGR555BE, MKTAG(15 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGB565BE, MKTAG(16 , 'B', 'G', 'R') }, + { AV_PIX_FMT_BGR565BE, MKTAG(16 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGB444LE, MKTAG('R', 'G', 'B', 12) }, + { AV_PIX_FMT_BGR444LE, MKTAG('B', 'G', 'R', 12) }, + { AV_PIX_FMT_RGB444BE, MKTAG(12 , 'B', 'G', 'R') }, + { AV_PIX_FMT_BGR444BE, MKTAG(12 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGBA64LE, MKTAG('R', 'B', 'A', 64 ) }, + { AV_PIX_FMT_BGRA64LE, MKTAG('B', 'R', 'A', 64 ) }, + { AV_PIX_FMT_RGBA64BE, MKTAG(64 , 'R', 'B', 'A') }, + { AV_PIX_FMT_BGRA64BE, MKTAG(64 , 'B', 'R', 'A') }, + { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') }, + { AV_PIX_FMT_RGB0, MKTAG('R', 'G', 'B', 0 ) }, + { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') }, + { AV_PIX_FMT_BGR0, MKTAG('B', 'G', 'R', 0 ) }, + { AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') }, + { AV_PIX_FMT_0BGR, MKTAG( 0 , 'B', 'G', 'R') }, + { AV_PIX_FMT_ARGB, MKTAG('A', 'R', 'G', 'B') }, + { AV_PIX_FMT_0RGB, MKTAG( 0 , 'R', 'G', 'B') }, + { AV_PIX_FMT_RGB24, MKTAG('R', 'G', 'B', 24 ) }, + { AV_PIX_FMT_BGR24, MKTAG('B', 'G', 'R', 24 ) }, + { AV_PIX_FMT_YUV411P, MKTAG('4', '1', '1', 'P') }, + { AV_PIX_FMT_YUV422P, MKTAG('4', '2', '2', 'P') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('4', '2', '2', 'P') }, + { AV_PIX_FMT_YUV440P, MKTAG('4', '4', '0', 'P') }, + { AV_PIX_FMT_YUVJ440P, MKTAG('4', '4', '0', 'P') }, + { AV_PIX_FMT_YUV444P, MKTAG('4', '4', '4', 'P') }, + { AV_PIX_FMT_YUVJ444P, MKTAG('4', '4', '4', 'P') }, + { AV_PIX_FMT_MONOWHITE,MKTAG('B', '1', 'W', '0') }, + { AV_PIX_FMT_MONOBLACK,MKTAG('B', '0', 'W', '1') }, + { AV_PIX_FMT_BGR8, MKTAG('B', 'G', 'R', 8 ) }, + { AV_PIX_FMT_RGB8, MKTAG('R', 'G', 'B', 8 ) }, + { AV_PIX_FMT_BGR4, MKTAG('B', 'G', 'R', 4 ) }, + { AV_PIX_FMT_RGB4, MKTAG('R', 'G', 'B', 4 ) }, + { AV_PIX_FMT_RGB4_BYTE,MKTAG('B', '4', 'B', 'Y') }, + { AV_PIX_FMT_BGR4_BYTE,MKTAG('R', '4', 'B', 'Y') }, + { AV_PIX_FMT_RGB48LE, MKTAG('R', 'G', 'B', 48 ) }, + { AV_PIX_FMT_RGB48BE, MKTAG( 48, 'R', 'G', 'B') }, + { AV_PIX_FMT_BGR48LE, MKTAG('B', 'G', 'R', 48 ) }, + { AV_PIX_FMT_BGR48BE, MKTAG( 48, 'B', 'G', 'R') }, + { AV_PIX_FMT_GRAY9LE, MKTAG('Y', '1', 0 , 9 ) }, + { AV_PIX_FMT_GRAY9BE, MKTAG( 9 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY10LE, MKTAG('Y', '1', 0 , 10 ) }, + { AV_PIX_FMT_GRAY10BE, MKTAG(10 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY12LE, MKTAG('Y', '1', 0 , 12 ) }, + { AV_PIX_FMT_GRAY12BE, MKTAG(12 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY14LE, MKTAG('Y', '1', 0 , 14 ) }, + { AV_PIX_FMT_GRAY14BE, MKTAG(14 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY16LE, MKTAG('Y', '1', 0 , 16 ) }, + { AV_PIX_FMT_GRAY16BE, MKTAG(16 , 0 , '1', 'Y') }, + { AV_PIX_FMT_YUV420P9LE, MKTAG('Y', '3', 11 , 9 ) }, + { AV_PIX_FMT_YUV420P9BE, MKTAG( 9 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P9LE, MKTAG('Y', '3', 10 , 9 ) }, + { AV_PIX_FMT_YUV422P9BE, MKTAG( 9 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P9LE, MKTAG('Y', '3', 0 , 9 ) }, + { AV_PIX_FMT_YUV444P9BE, MKTAG( 9 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P10LE, MKTAG('Y', '3', 11 , 10 ) }, + { AV_PIX_FMT_YUV420P10BE, MKTAG(10 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P10LE, MKTAG('Y', '3', 10 , 10 ) }, + { AV_PIX_FMT_YUV422P10BE, MKTAG(10 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P10LE, MKTAG('Y', '3', 0 , 10 ) }, + { AV_PIX_FMT_YUV444P10BE, MKTAG(10 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P12LE, MKTAG('Y', '3', 11 , 12 ) }, + { AV_PIX_FMT_YUV420P12BE, MKTAG(12 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P12LE, MKTAG('Y', '3', 10 , 12 ) }, + { AV_PIX_FMT_YUV422P12BE, MKTAG(12 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P12LE, MKTAG('Y', '3', 0 , 12 ) }, + { AV_PIX_FMT_YUV444P12BE, MKTAG(12 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P14LE, MKTAG('Y', '3', 11 , 14 ) }, + { AV_PIX_FMT_YUV420P14BE, MKTAG(14 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P14LE, MKTAG('Y', '3', 10 , 14 ) }, + { AV_PIX_FMT_YUV422P14BE, MKTAG(14 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P14LE, MKTAG('Y', '3', 0 , 14 ) }, + { AV_PIX_FMT_YUV444P14BE, MKTAG(14 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUV420P16LE, MKTAG('Y', '3', 11 , 16 ) }, + { AV_PIX_FMT_YUV420P16BE, MKTAG(16 , 11 , '3', 'Y') }, + { AV_PIX_FMT_YUV422P16LE, MKTAG('Y', '3', 10 , 16 ) }, + { AV_PIX_FMT_YUV422P16BE, MKTAG(16 , 10 , '3', 'Y') }, + { AV_PIX_FMT_YUV444P16LE, MKTAG('Y', '3', 0 , 16 ) }, + { AV_PIX_FMT_YUV444P16BE, MKTAG(16 , 0 , '3', 'Y') }, + { AV_PIX_FMT_YUVA420P, MKTAG('Y', '4', 11 , 8 ) }, + { AV_PIX_FMT_YUVA422P, MKTAG('Y', '4', 10 , 8 ) }, + { AV_PIX_FMT_YUVA444P, MKTAG('Y', '4', 0 , 8 ) }, + { AV_PIX_FMT_YA8, MKTAG('Y', '2', 0 , 8 ) }, + { AV_PIX_FMT_PAL8, MKTAG('P', 'A', 'L', 8 ) }, + + { AV_PIX_FMT_YUVA420P9LE, MKTAG('Y', '4', 11 , 9 ) }, + { AV_PIX_FMT_YUVA420P9BE, MKTAG( 9 , 11 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P9LE, MKTAG('Y', '4', 10 , 9 ) }, + { AV_PIX_FMT_YUVA422P9BE, MKTAG( 9 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P9LE, MKTAG('Y', '4', 0 , 9 ) }, + { AV_PIX_FMT_YUVA444P9BE, MKTAG( 9 , 0 , '4', 'Y') }, + { AV_PIX_FMT_YUVA420P10LE, MKTAG('Y', '4', 11 , 10 ) }, + { AV_PIX_FMT_YUVA420P10BE, MKTAG(10 , 11 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P10LE, MKTAG('Y', '4', 10 , 10 ) }, + { AV_PIX_FMT_YUVA422P10BE, MKTAG(10 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P10LE, MKTAG('Y', '4', 0 , 10 ) }, + { AV_PIX_FMT_YUVA444P10BE, MKTAG(10 , 0 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P12LE, MKTAG('Y', '4', 10 , 12 ) }, + { AV_PIX_FMT_YUVA422P12BE, MKTAG(12 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P12LE, MKTAG('Y', '4', 0 , 12 ) }, + { AV_PIX_FMT_YUVA444P12BE, MKTAG(12 , 0 , '4', 'Y') }, + { AV_PIX_FMT_YUVA420P16LE, MKTAG('Y', '4', 11 , 16 ) }, + { AV_PIX_FMT_YUVA420P16BE, MKTAG(16 , 11 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P16LE, MKTAG('Y', '4', 10 , 16 ) }, + { AV_PIX_FMT_YUVA422P16BE, MKTAG(16 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P16LE, MKTAG('Y', '4', 0 , 16 ) }, + { AV_PIX_FMT_YUVA444P16BE, MKTAG(16 , 0 , '4', 'Y') }, + + { AV_PIX_FMT_GBRP, MKTAG('G', '3', 00 , 8 ) }, + { AV_PIX_FMT_GBRP9LE, MKTAG('G', '3', 00 , 9 ) }, + { AV_PIX_FMT_GBRP9BE, MKTAG( 9 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP10LE, MKTAG('G', '3', 00 , 10 ) }, + { AV_PIX_FMT_GBRP10BE, MKTAG(10 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP12LE, MKTAG('G', '3', 00 , 12 ) }, + { AV_PIX_FMT_GBRP12BE, MKTAG(12 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP14LE, MKTAG('G', '3', 00 , 14 ) }, + { AV_PIX_FMT_GBRP14BE, MKTAG(14 , 00 , '3', 'G') }, + { AV_PIX_FMT_GBRP16LE, MKTAG('G', '3', 00 , 16 ) }, + { AV_PIX_FMT_GBRP16BE, MKTAG(16 , 00 , '3', 'G') }, + + { AV_PIX_FMT_GBRAP, MKTAG('G', '4', 00 , 8 ) }, + { AV_PIX_FMT_GBRAP10LE, MKTAG('G', '4', 00 , 10 ) }, + { AV_PIX_FMT_GBRAP10BE, MKTAG(10 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAP12LE, MKTAG('G', '4', 00 , 12 ) }, + { AV_PIX_FMT_GBRAP12BE, MKTAG(12 , 00 , '4', 'G') }, + { AV_PIX_FMT_GBRAP16LE, MKTAG('G', '4', 00 , 16 ) }, + { AV_PIX_FMT_GBRAP16BE, MKTAG(16 , 00 , '4', 'G') }, + + { AV_PIX_FMT_XYZ12LE, MKTAG('X', 'Y', 'Z' , 36 ) }, + { AV_PIX_FMT_XYZ12BE, MKTAG(36 , 'Z' , 'Y', 'X') }, + + { AV_PIX_FMT_BAYER_BGGR8, MKTAG(0xBA, 'B', 'G', 8 ) }, + { AV_PIX_FMT_BAYER_BGGR16LE, MKTAG(0xBA, 'B', 'G', 16 ) }, + { AV_PIX_FMT_BAYER_BGGR16BE, MKTAG(16 , 'G', 'B', 0xBA) }, + { AV_PIX_FMT_BAYER_RGGB8, MKTAG(0xBA, 'R', 'G', 8 ) }, + { AV_PIX_FMT_BAYER_RGGB16LE, MKTAG(0xBA, 'R', 'G', 16 ) }, + { AV_PIX_FMT_BAYER_RGGB16BE, MKTAG(16 , 'G', 'R', 0xBA) }, + { AV_PIX_FMT_BAYER_GBRG8, MKTAG(0xBA, 'G', 'B', 8 ) }, + { AV_PIX_FMT_BAYER_GBRG16LE, MKTAG(0xBA, 'G', 'B', 16 ) }, + { AV_PIX_FMT_BAYER_GBRG16BE, MKTAG(16, 'B', 'G', 0xBA) }, + { AV_PIX_FMT_BAYER_GRBG8, MKTAG(0xBA, 'G', 'R', 8 ) }, + { AV_PIX_FMT_BAYER_GRBG16LE, MKTAG(0xBA, 'G', 'R', 16 ) }, + { AV_PIX_FMT_BAYER_GRBG16BE, MKTAG(16, 'R', 'G', 0xBA) }, + + /* quicktime */ + { AV_PIX_FMT_YUV420P, MKTAG('R', '4', '2', '0') }, /* Radius DV YUV PAL */ + { AV_PIX_FMT_YUV411P, MKTAG('R', '4', '1', '1') }, /* Radius DV YUV NTSC */ + { AV_PIX_FMT_UYVY422, MKTAG('2', 'v', 'u', 'y') }, + { AV_PIX_FMT_UYVY422, MKTAG('2', 'V', 'u', 'y') }, + { AV_PIX_FMT_UYVY422, MKTAG('A', 'V', 'U', 'I') }, /* FIXME merge both fields */ + { AV_PIX_FMT_UYVY422, MKTAG('b', 'x', 'y', 'v') }, + { AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', '2') }, + { AV_PIX_FMT_YUYV422, MKTAG('y', 'u', 'v', 's') }, + { AV_PIX_FMT_YUYV422, MKTAG('D', 'V', 'O', 'O') }, /* Digital Voodoo SD 8 Bit */ + { AV_PIX_FMT_RGB555LE,MKTAG('L', '5', '5', '5') }, + { AV_PIX_FMT_RGB565LE,MKTAG('L', '5', '6', '5') }, + { AV_PIX_FMT_RGB565BE,MKTAG('B', '5', '6', '5') }, + { AV_PIX_FMT_BGR24, MKTAG('2', '4', 'B', 'G') }, + { AV_PIX_FMT_BGR24, MKTAG('b', 'x', 'b', 'g') }, + { AV_PIX_FMT_BGRA, MKTAG('B', 'G', 'R', 'A') }, + { AV_PIX_FMT_RGBA, MKTAG('R', 'G', 'B', 'A') }, + { AV_PIX_FMT_RGB24, MKTAG('b', 'x', 'r', 'g') }, + { AV_PIX_FMT_ABGR, MKTAG('A', 'B', 'G', 'R') }, + { AV_PIX_FMT_GRAY16BE,MKTAG('b', '1', '6', 'g') }, + { AV_PIX_FMT_RGB48BE, MKTAG('b', '4', '8', 'r') }, + { AV_PIX_FMT_RGBA64BE,MKTAG('b', '6', '4', 'a') }, + + /* vlc */ + { AV_PIX_FMT_YUV410P, MKTAG('I', '4', '1', '0') }, + { AV_PIX_FMT_YUV411P, MKTAG('I', '4', '1', '1') }, + { AV_PIX_FMT_YUV422P, MKTAG('I', '4', '2', '2') }, + { AV_PIX_FMT_YUV440P, MKTAG('I', '4', '4', '0') }, + { AV_PIX_FMT_YUV444P, MKTAG('I', '4', '4', '4') }, + { AV_PIX_FMT_YUVJ420P, MKTAG('J', '4', '2', '0') }, + { AV_PIX_FMT_YUVJ422P, MKTAG('J', '4', '2', '2') }, + { AV_PIX_FMT_YUVJ440P, MKTAG('J', '4', '4', '0') }, + { AV_PIX_FMT_YUVJ444P, MKTAG('J', '4', '4', '4') }, + { AV_PIX_FMT_YUVA444P, MKTAG('Y', 'U', 'V', 'A') }, + { AV_PIX_FMT_YUVA420P, MKTAG('I', '4', '0', 'A') }, + { AV_PIX_FMT_YUVA422P, MKTAG('I', '4', '2', 'A') }, + { AV_PIX_FMT_RGB8, MKTAG('R', 'G', 'B', '2') }, + { AV_PIX_FMT_RGB555LE, MKTAG('R', 'V', '1', '5') }, + { AV_PIX_FMT_RGB565LE, MKTAG('R', 'V', '1', '6') }, + { AV_PIX_FMT_BGR24, MKTAG('R', 'V', '2', '4') }, + { AV_PIX_FMT_BGR0, MKTAG('R', 'V', '3', '2') }, + { AV_PIX_FMT_RGBA, MKTAG('A', 'V', '3', '2') }, + { AV_PIX_FMT_YUV420P9LE, MKTAG('I', '0', '9', 'L') }, + { AV_PIX_FMT_YUV420P9BE, MKTAG('I', '0', '9', 'B') }, + { AV_PIX_FMT_YUV422P9LE, MKTAG('I', '2', '9', 'L') }, + { AV_PIX_FMT_YUV422P9BE, MKTAG('I', '2', '9', 'B') }, + { AV_PIX_FMT_YUV444P9LE, MKTAG('I', '4', '9', 'L') }, + { AV_PIX_FMT_YUV444P9BE, MKTAG('I', '4', '9', 'B') }, + { AV_PIX_FMT_YUV420P10LE, MKTAG('I', '0', 'A', 'L') }, + { AV_PIX_FMT_YUV420P10BE, MKTAG('I', '0', 'A', 'B') }, + { AV_PIX_FMT_YUV422P10LE, MKTAG('I', '2', 'A', 'L') }, + { AV_PIX_FMT_YUV422P10BE, MKTAG('I', '2', 'A', 'B') }, + { AV_PIX_FMT_YUV444P10LE, MKTAG('I', '4', 'A', 'L') }, + { AV_PIX_FMT_YUV444P10BE, MKTAG('I', '4', 'A', 'B') }, + { AV_PIX_FMT_YUV420P12LE, MKTAG('I', '0', 'C', 'L') }, + { AV_PIX_FMT_YUV420P12BE, MKTAG('I', '0', 'C', 'B') }, + { AV_PIX_FMT_YUV422P12LE, MKTAG('I', '2', 'C', 'L') }, + { AV_PIX_FMT_YUV422P12BE, MKTAG('I', '2', 'C', 'B') }, + { AV_PIX_FMT_YUV444P12LE, MKTAG('I', '4', 'C', 'L') }, + { AV_PIX_FMT_YUV444P12BE, MKTAG('I', '4', 'C', 'B') }, + { AV_PIX_FMT_YUV420P16LE, MKTAG('I', '0', 'F', 'L') }, + { AV_PIX_FMT_YUV420P16BE, MKTAG('I', '0', 'F', 'B') }, + { AV_PIX_FMT_YUV444P16LE, MKTAG('I', '4', 'F', 'L') }, + { AV_PIX_FMT_YUV444P16BE, MKTAG('I', '4', 'F', 'B') }, + + /* special */ + { AV_PIX_FMT_RGB565LE,MKTAG( 3 , 0 , 0 , 0 ) }, /* flipped RGB565LE */ + { AV_PIX_FMT_YUV444P, MKTAG('Y', 'V', '2', '4') }, /* YUV444P, swapped UV */ + + { AV_PIX_FMT_NONE, 0 }, +}; + +const struct PixelFormatTag *avpriv_get_raw_pix_fmt_tags(void) +{ + return ff_raw_pix_fmt_tags; +} + +unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat fmt) +{ + const PixelFormatTag *tags = ff_raw_pix_fmt_tags; + while (tags->pix_fmt >= 0) { + if (tags->pix_fmt == fmt) + return tags->fourcc; + tags++; + } + return 0; +} + +const PixelFormatTag avpriv_pix_fmt_bps_avi[] = { + { AV_PIX_FMT_PAL8, 1 }, + { AV_PIX_FMT_PAL8, 2 }, + { AV_PIX_FMT_PAL8, 4 }, + { AV_PIX_FMT_PAL8, 8 }, + { AV_PIX_FMT_RGB444LE, 12 }, + { AV_PIX_FMT_RGB555LE, 15 }, + { AV_PIX_FMT_RGB555LE, 16 }, + { AV_PIX_FMT_BGR24, 24 }, + { AV_PIX_FMT_BGRA, 32 }, + { AV_PIX_FMT_NONE, 0 }, +}; + +const PixelFormatTag avpriv_pix_fmt_bps_mov[] = { + { AV_PIX_FMT_PAL8, 1 }, + { AV_PIX_FMT_PAL8, 2 }, + { AV_PIX_FMT_PAL8, 4 }, + { AV_PIX_FMT_PAL8, 8 }, + { AV_PIX_FMT_RGB555BE, 16 }, + { AV_PIX_FMT_RGB24, 24 }, + { AV_PIX_FMT_ARGB, 32 }, + { AV_PIX_FMT_PAL8, 33 }, + { AV_PIX_FMT_NONE, 0 }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/raw.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/raw.h new file mode 100644 index 0000000000..28a27b1f9e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/raw.h @@ -0,0 +1,48 @@ +/* + * Raw Video Codec + * Copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Raw Video Codec + */ + +#ifndef AVCODEC_RAW_H +#define AVCODEC_RAW_H + +#include "avcodec.h" +#include "internal.h" +#include "libavutil/internal.h" + +typedef struct PixelFormatTag { + enum AVPixelFormat pix_fmt; + unsigned int fourcc; +} PixelFormatTag; + +extern const PixelFormatTag ff_raw_pix_fmt_tags[]; // exposed through avpriv_get_raw_pix_fmt_tags() + +const struct PixelFormatTag *avpriv_get_raw_pix_fmt_tags(void); + +enum AVPixelFormat avpriv_find_pix_fmt(const PixelFormatTag *tags, unsigned int fourcc); + +extern av_export_avcodec const PixelFormatTag avpriv_pix_fmt_bps_avi[]; +extern av_export_avcodec const PixelFormatTag avpriv_pix_fmt_bps_mov[]; + +#endif /* AVCODEC_RAW_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rdft.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rdft.h new file mode 100644 index 0000000000..ffafca7f24 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rdft.h @@ -0,0 +1,52 @@ +/* + * (I)RDFT transforms + * Copyright (c) 2009 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined(AVCODEC_RDFT_H) && (!defined(FFT_FLOAT) || FFT_FLOAT) +#define AVCODEC_RDFT_H + +#include "config.h" +#include "fft.h" + +struct RDFTContext { + int nbits; + int inverse; + int sign_convention; + + /* pre/post rotation tables */ + const FFTSample *tcos; + const FFTSample *tsin; + int negative_sin; + FFTContext fft; + void (*rdft_calc)(struct RDFTContext *s, FFTSample *z); +}; + +/** + * Set up a real FFT. + * @param nbits log2 of the length of the input array + * @param trans the type of transform + */ +int ff_rdft_init(RDFTContext *s, int nbits, enum RDFTransformType trans); +void ff_rdft_end(RDFTContext *s); + +void ff_rdft_init_arm(RDFTContext *s); + + +#endif /* AVCODEC_RDFT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rl.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rl.c new file mode 100644 index 0000000000..6eac306b88 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rl.c @@ -0,0 +1,147 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/mem.h" + +#include "rl.h" + +void ff_rl_free(RLTable *rl) +{ + int i; + + for (i = 0; i < 2; i++) { + av_freep(&rl->max_run[i]); + av_freep(&rl->max_level[i]); + av_freep(&rl->index_run[i]); + } +} + +av_cold int ff_rl_init(RLTable *rl, + uint8_t static_store[2][2 * MAX_RUN + MAX_LEVEL + 3]) +{ + int8_t max_level[MAX_RUN + 1], max_run[MAX_LEVEL + 1]; + uint8_t index_run[MAX_RUN + 1]; + int last, run, level, start, end, i; + + /* If table is static, we can quit if rl->max_level[0] is not NULL */ + if (static_store && rl->max_level[0]) + return 0; + + /* compute max_level[], max_run[] and index_run[] */ + for (last = 0; last < 2; last++) { + if (last == 0) { + start = 0; + end = rl->last; + } else { + start = rl->last; + end = rl->n; + } + + memset(max_level, 0, MAX_RUN + 1); + memset(max_run, 0, MAX_LEVEL + 1); + memset(index_run, rl->n, MAX_RUN + 1); + for (i = start; i < end; i++) { + run = rl->table_run[i]; + level = rl->table_level[i]; + if (index_run[run] == rl->n) + index_run[run] = i; + if (level > max_level[run]) + max_level[run] = level; + if (run > max_run[level]) + max_run[level] = run; + } + if (static_store) + rl->max_level[last] = static_store[last]; + else { + rl->max_level[last] = av_malloc(MAX_RUN + 1); + if (!rl->max_level[last]) + goto fail; + } + memcpy(rl->max_level[last], max_level, MAX_RUN + 1); + if (static_store) + rl->max_run[last] = static_store[last] + MAX_RUN + 1; + else { + rl->max_run[last] = av_malloc(MAX_LEVEL + 1); + if (!rl->max_run[last]) + goto fail; + } + memcpy(rl->max_run[last], max_run, MAX_LEVEL + 1); + if (static_store) + rl->index_run[last] = static_store[last] + MAX_RUN + MAX_LEVEL + 2; + else { + rl->index_run[last] = av_malloc(MAX_RUN + 1); + if (!rl->index_run[last]) + goto fail; + } + memcpy(rl->index_run[last], index_run, MAX_RUN + 1); + } + return 0; + +fail: + ff_rl_free(rl); + return AVERROR(ENOMEM); +} + +av_cold void ff_rl_init_vlc(RLTable *rl, unsigned static_size) +{ + int i, q; + VLC_TYPE table[1500][2] = {{0}}; + VLC vlc = { .table = table, .table_allocated = static_size }; + av_assert0(static_size <= FF_ARRAY_ELEMS(table)); + init_vlc(&vlc, 9, rl->n + 1, &rl->table_vlc[0][1], 4, 2, &rl->table_vlc[0][0], 4, 2, INIT_VLC_USE_NEW_STATIC); + + for (q = 0; q < 32; q++) { + int qmul = q * 2; + int qadd = (q - 1) | 1; + + if (q == 0) { + qmul = 1; + qadd = 0; + } + for (i = 0; i < vlc.table_size; i++) { + int code = vlc.table[i][0]; + int len = vlc.table[i][1]; + int level, run; + + if (len == 0) { // illegal code + run = 66; + level = MAX_LEVEL; + } else if (len < 0) { // more bits needed + run = 0; + level = code; + } else { + if (code == rl->n) { // esc + run = 66; + level = 0; + } else { + run = rl->table_run[code] + 1; + level = rl->table_level[code] * qmul + qadd; + if (code >= rl->last) run += 192; + } + } + rl->rl_vlc[q][i].len = len; + rl->rl_vlc[q][i].level = level; + rl->rl_vlc[q][i].run = run; + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rl.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rl.h new file mode 100644 index 0000000000..9a767bc5fd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rl.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000-2002 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * rl header. + */ + +#ifndef AVCODEC_RL_H +#define AVCODEC_RL_H + +#include + +#include "vlc.h" + +/* run length table */ +#define MAX_RUN 64 +#define MAX_LEVEL 64 + +/** RLTable. */ +typedef struct RLTable { + int n; ///< number of entries of table_vlc minus 1 + int last; ///< number of values for last = 0 + const uint16_t (*table_vlc)[2]; + const int8_t *table_run; + const int8_t *table_level; + uint8_t *index_run[2]; ///< encoding only + int8_t *max_level[2]; ///< encoding & decoding + int8_t *max_run[2]; ///< encoding & decoding + RL_VLC_ELEM *rl_vlc[32]; ///< decoding only +} RLTable; + +/** + * @param static_store static uint8_t array[2][2*MAX_RUN + MAX_LEVEL + 3] which will hold + * the level and run tables, if this is NULL av_malloc() will be used + */ +int ff_rl_init(RLTable *rl, uint8_t static_store[2][2*MAX_RUN + MAX_LEVEL + 3]); +void ff_rl_init_vlc(RLTable *rl, unsigned static_size); + +/** + * Free the contents of a dynamically allocated table. + */ +void ff_rl_free(RLTable *rl); + +#define INIT_VLC_RL(rl, static_size)\ +{\ + int q;\ + static RL_VLC_ELEM rl_vlc_table[32][static_size];\ +\ + if(!rl.rl_vlc[0]){\ + for(q=0; q<32; q++)\ + rl.rl_vlc[q]= rl_vlc_table[q];\ +\ + ff_rl_init_vlc(&rl, static_size);\ + }\ +} + +static inline int get_rl_index(const RLTable *rl, int last, int run, int level) +{ + int index; + index = rl->index_run[last][run]; + if (index >= rl->n) + return rl->n; + if (level > rl->max_level[last][run]) + return rl->n; + return index + level - 1; +} + +#endif /* AVCODEC_RL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rle.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rle.h new file mode 100644 index 0000000000..a92edf7a26 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/rle.h @@ -0,0 +1,51 @@ +/* + * RLE encoder + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_RLE_H +#define AVCODEC_RLE_H + +#include + +/** + * Count up to 127 consecutive pixels which are either all the same or + * all differ from the previous and next pixels. + * @param start Pointer to the first pixel + * @param len Maximum number of pixels + * @param bpp Bytes per pixel + * @param same 1 if searching for identical pixel values, 0 for differing + * @return Number of matching consecutive pixels found + */ +int ff_rle_count_pixels(const uint8_t *start, int len, int bpp, int same); + +/** + * RLE compress the row, with maximum size of out_size. + * Value before repeated bytes is (count ^ xor_rep) + add_rep. + * Value before raw bytes is (count ^ xor_raw) + add_raw. + * @param outbuf Output buffer + * @param out_size Maximum output size + * @param inbuf Input buffer + * @param bpp Bytes per pixel + * @param w Image width + * @return Size of output in bytes, or -1 if larger than out_size + */ +int ff_rle_encode(uint8_t *outbuf, int out_size, const uint8_t *inbuf, int bpp, + int w, int add_rep, int xor_rep, int add_raw, int xor_raw); + +#endif /* AVCODEC_RLE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbr.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbr.h new file mode 100644 index 0000000000..eb7d1aec09 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbr.h @@ -0,0 +1,217 @@ +/* + * Spectral Band Replication definitions and structures + * Copyright (c) 2008-2009 Robert Swain ( rob opendot cl ) + * Copyright (c) 2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Spectral Band Replication definitions and structures + * @author Robert Swain ( rob opendot cl ) + */ + +#ifndef AVCODEC_SBR_H +#define AVCODEC_SBR_H + +#include +#include "fft.h" +#include "aacps.h" +#include "sbrdsp.h" + +typedef struct AACContext AACContext; + +/** + * Spectral Band Replication header - spectrum parameters that invoke a reset if they differ from the previous header. + */ +typedef struct SpectrumParameters { + uint8_t bs_start_freq; + uint8_t bs_stop_freq; + uint8_t bs_xover_band; + + /** + * @name Variables associated with bs_header_extra_1 + * @{ + */ + uint8_t bs_freq_scale; + uint8_t bs_alter_scale; + uint8_t bs_noise_bands; + /** @} */ +} SpectrumParameters; + +#define SBR_SYNTHESIS_BUF_SIZE ((1280-128)*2) + +/** + * Spectral Band Replication per channel data + */ +typedef struct SBRData { + /** + * @name Main bitstream data variables + * @{ + */ + unsigned bs_frame_class; + unsigned bs_add_harmonic_flag; + AAC_SIGNE bs_num_env; + uint8_t bs_freq_res[7]; + AAC_SIGNE bs_num_noise; + uint8_t bs_df_env[5]; + uint8_t bs_df_noise[2]; + uint8_t bs_invf_mode[2][5]; + uint8_t bs_add_harmonic[48]; + unsigned bs_amp_res; + /** @} */ + + /** + * @name State variables + * @{ + */ + DECLARE_ALIGNED(32, INTFLOAT, synthesis_filterbank_samples)[SBR_SYNTHESIS_BUF_SIZE]; + DECLARE_ALIGNED(32, INTFLOAT, analysis_filterbank_samples) [1312]; + int synthesis_filterbank_samples_offset; + ///l_APrev and l_A + int e_a[2]; + ///Chirp factors + INTFLOAT bw_array[5]; + ///QMF values of the original signal + INTFLOAT W[2][32][32][2]; + ///QMF output of the HF adjustor + int Ypos; + DECLARE_ALIGNED(16, INTFLOAT, Y)[2][38][64][2]; + DECLARE_ALIGNED(16, AAC_FLOAT, g_temp)[42][48]; + AAC_FLOAT q_temp[42][48]; + uint8_t s_indexmapped[8][48]; + ///Envelope scalefactors + uint8_t env_facs_q[6][48]; + AAC_FLOAT env_facs[6][48]; + ///Noise scalefactors + uint8_t noise_facs_q[3][5]; + AAC_FLOAT noise_facs[3][5]; + ///Envelope time borders + uint8_t t_env[8]; + ///Envelope time border of the last envelope of the previous frame + uint8_t t_env_num_env_old; + ///Noise time borders + uint8_t t_q[3]; + unsigned f_indexnoise; + unsigned f_indexsine; + /** @} */ +} SBRData; + +typedef struct SpectralBandReplication SpectralBandReplication; + +/** + * aacsbr functions pointers + */ +typedef struct AACSBRContext { + int (*sbr_lf_gen)(AACContext *ac, SpectralBandReplication *sbr, + INTFLOAT X_low[32][40][2], const INTFLOAT W[2][32][32][2], + int buf_idx); + void (*sbr_hf_assemble)(INTFLOAT Y1[38][64][2], + const INTFLOAT X_high[64][40][2], + SpectralBandReplication *sbr, SBRData *ch_data, + const int e_a[2]); + int (*sbr_x_gen)(SpectralBandReplication *sbr, INTFLOAT X[2][38][64], + const INTFLOAT Y0[38][64][2], const INTFLOAT Y1[38][64][2], + const INTFLOAT X_low[32][40][2], int ch); + void (*sbr_hf_inverse_filter)(SBRDSPContext *dsp, + INTFLOAT (*alpha0)[2], INTFLOAT (*alpha1)[2], + const INTFLOAT X_low[32][40][2], int k0); +} AACSBRContext; + +/** + * Spectral Band Replication + */ +struct SpectralBandReplication { + int sample_rate; + int start; + int ready_for_dequant; + int id_aac; + int reset; + SpectrumParameters spectrum_params; + int bs_amp_res_header; + /** + * @name Variables associated with bs_header_extra_2 + * @{ + */ + unsigned bs_limiter_bands; + unsigned bs_limiter_gains; + unsigned bs_interpol_freq; + unsigned bs_smoothing_mode; + /** @} */ + unsigned bs_coupling; + AAC_SIGNE k[5]; ///< k0, k1, k2 + ///kx', and kx respectively, kx is the first QMF subband where SBR is used. + ///kx' is its value from the previous frame + AAC_SIGNE kx[2]; + ///M' and M respectively, M is the number of QMF subbands that use SBR. + AAC_SIGNE m[2]; + unsigned kx_and_m_pushed; + ///The number of frequency bands in f_master + AAC_SIGNE n_master; + SBRData data[2]; + PSContext ps; + ///N_Low and N_High respectively, the number of frequency bands for low and high resolution + AAC_SIGNE n[2]; + ///Number of noise floor bands + AAC_SIGNE n_q; + ///Number of limiter bands + AAC_SIGNE n_lim; + ///The master QMF frequency grouping + uint16_t f_master[49]; + ///Frequency borders for low resolution SBR + uint16_t f_tablelow[25]; + ///Frequency borders for high resolution SBR + uint16_t f_tablehigh[49]; + ///Frequency borders for noise floors + uint16_t f_tablenoise[6]; + ///Frequency borders for the limiter + uint16_t f_tablelim[30]; + AAC_SIGNE num_patches; + uint8_t patch_num_subbands[6]; + uint8_t patch_start_subband[6]; + ///QMF low frequency input to the HF generator + DECLARE_ALIGNED(16, INTFLOAT, X_low)[32][40][2]; + ///QMF output of the HF generator + DECLARE_ALIGNED(16, INTFLOAT, X_high)[64][40][2]; + ///QMF values of the reconstructed signal + DECLARE_ALIGNED(16, INTFLOAT, X)[2][2][38][64]; + ///Zeroth coefficient used to filter the subband signals + DECLARE_ALIGNED(16, INTFLOAT, alpha0)[64][2]; + ///First coefficient used to filter the subband signals + DECLARE_ALIGNED(16, INTFLOAT, alpha1)[64][2]; + ///Dequantized envelope scalefactors, remapped + AAC_FLOAT e_origmapped[7][48]; + ///Dequantized noise scalefactors, remapped + AAC_FLOAT q_mapped[7][48]; + ///Sinusoidal presence, remapped + uint8_t s_mapped[7][48]; + ///Estimated envelope + AAC_FLOAT e_curr[7][48]; + ///Amplitude adjusted noise scalefactors + AAC_FLOAT q_m[7][48]; + ///Sinusoidal levels + AAC_FLOAT s_m[7][48]; + AAC_FLOAT gain[7][48]; + DECLARE_ALIGNED(32, INTFLOAT, qmf_filter_scratch)[5][64]; + FFTContext mdct_ana; + FFTContext mdct; + SBRDSPContext dsp; + AACSBRContext c; +}; + +#endif /* AVCODEC_SBR_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.asm new file mode 100644 index 0000000000..62bbe512ec --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.asm @@ -0,0 +1,548 @@ +;****************************************************************************** +;* AAC Spectral Band Replication decoding functions +;* Copyright (C) 2012 Christophe Gisquet +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA +; mask equivalent for multiply by -1.0 1.0 +ps_mask times 2 dd 1<<31, 0 +ps_mask2 times 2 dd 0, 1<<31 +ps_mask3 dd 0, 0, 0, 1<<31 +ps_noise0 times 2 dd 1.0, 0.0, +ps_noise2 times 2 dd -1.0, 0.0 +ps_noise13 dd 0.0, 1.0, 0.0, -1.0 + dd 0.0, -1.0, 0.0, 1.0 + dd 0.0, 1.0, 0.0, -1.0 +cextern sbr_noise_table +cextern ps_neg + +SECTION .text + +INIT_XMM sse +cglobal sbr_sum_square, 2, 3, 6 + mov r2d, r1d + xorps m0, m0 + xorps m1, m1 + sar r2, 3 + jz .prepare +.loop: + movu m2, [r0 + 0] + movu m3, [r0 + 16] + movu m4, [r0 + 32] + movu m5, [r0 + 48] + mulps m2, m2 + mulps m3, m3 + mulps m4, m4 + mulps m5, m5 + addps m0, m2 + addps m1, m3 + addps m0, m4 + addps m1, m5 + add r0, 64 + dec r2 + jnz .loop +.prepare: + and r1, 7 + sar r1, 1 + jz .end +; len is a multiple of 2, thus there are at least 4 elements to process +.endloop: + movu m2, [r0] + add r0, 16 + mulps m2, m2 + dec r1 + addps m0, m2 + jnz .endloop +.end: + addps m0, m1 + movhlps m2, m0 + addps m0, m2 + movss m1, m0 + shufps m0, m0, 1 + addss m0, m1 +%if ARCH_X86_64 == 0 + movss r0m, m0 + fld dword r0m +%endif + RET + +%define STEP 40*4*2 +cglobal sbr_hf_g_filt, 5, 6, 5 + lea r1, [r1 + 8*r4] ; offset by ixh elements into X_high + mov r5, r3 + and r3, 0xFC + lea r2, [r2 + r3*4] + lea r0, [r0 + r3*8] + neg r3 + jz .loop1 +.loop4: + movlps m0, [r2 + 4*r3 + 0] + movlps m1, [r2 + 4*r3 + 8] + movlps m2, [r1 + 0*STEP] + movlps m3, [r1 + 2*STEP] + movhps m2, [r1 + 1*STEP] + movhps m3, [r1 + 3*STEP] + unpcklps m0, m0 + unpcklps m1, m1 + mulps m0, m2 + mulps m1, m3 + movu [r0 + 8*r3 + 0], m0 + movu [r0 + 8*r3 + 16], m1 + add r1, 4*STEP + add r3, 4 + jnz .loop4 + and r5, 3 ; number of single element loops + jz .end +.loop1: ; element 0 and 1 can be computed at the same time + movss m0, [r2] + movlps m2, [r1] + unpcklps m0, m0 + mulps m2, m0 + movlps [r0], m2 + add r0, 8 + add r2, 4 + add r1, STEP + dec r5 + jnz .loop1 +.end: + RET + +; void ff_sbr_hf_gen_sse(float (*X_high)[2], const float (*X_low)[2], +; const float alpha0[2], const float alpha1[2], +; float bw, int start, int end) +; +cglobal sbr_hf_gen, 4,4,8, X_high, X_low, alpha0, alpha1, BW, S, E + ; load alpha factors +%define bw m0 +%if ARCH_X86_64 == 0 || WIN64 + movss bw, BWm +%endif + movlps m2, [alpha1q] + movlps m1, [alpha0q] + shufps bw, bw, 0 + mulps m2, bw ; (a1[0] a1[1])*bw + mulps m1, bw ; (a0[0] a0[1])*bw = (a2 a3) + mulps m2, bw ; (a1[0] a1[1])*bw*bw = (a0 a1) + mova m3, m1 + mova m4, m2 + + ; Set pointers +%if ARCH_X86_64 == 0 || WIN64 + ; start and end 6th and 7th args on stack + mov r2d, Sm + mov r3d, Em + DEFINE_ARGS X_high, X_low, start, end +%else +; BW does not actually occupy a register, so shift by 1 + DEFINE_ARGS X_high, X_low, alpha0, alpha1, start, end + movsxd startq, startd + movsxd endq, endd +%endif + sub startq, endq ; neg num of loops + lea X_highq, [X_highq + endq*2*4] + lea X_lowq, [X_lowq + endq*2*4 - 2*2*4] + shl startq, 3 ; offset from num loops + + mova m0, [X_lowq + startq] + shufps m3, m3, q1111 + shufps m4, m4, q1111 + xorps m3, [ps_mask] + shufps m1, m1, q0000 + shufps m2, m2, q0000 + xorps m4, [ps_mask] +.loop2: + movu m7, [X_lowq + startq + 8] ; BbCc + mova m6, m0 + mova m5, m7 + shufps m0, m0, q2301 ; aAbB + shufps m7, m7, q2301 ; bBcC + mulps m0, m4 + mulps m7, m3 + mulps m6, m2 + mulps m5, m1 + addps m7, m0 + mova m0, [X_lowq + startq + 16] ; CcDd + addps m7, m0 + addps m6, m5 + addps m7, m6 + mova [X_highq + startq], m7 + add startq, 16 + jnz .loop2 + RET + +cglobal sbr_sum64x5, 1,2,4,z + lea r1q, [zq+ 256] +.loop: + mova m0, [zq+ 0] + mova m2, [zq+ 16] + mova m1, [zq+ 256] + mova m3, [zq+ 272] + addps m0, [zq+ 512] + addps m2, [zq+ 528] + addps m1, [zq+ 768] + addps m3, [zq+ 784] + addps m0, [zq+1024] + addps m2, [zq+1040] + addps m0, m1 + addps m2, m3 + mova [zq], m0 + mova [zq+16], m2 + add zq, 32 + cmp zq, r1q + jne .loop + REP_RET + +INIT_XMM sse +cglobal sbr_qmf_post_shuffle, 2,3,4,W,z + lea r2q, [zq + (64-4)*4] + mova m3, [ps_neg] +.loop: + mova m1, [zq] + xorps m0, m3, [r2q] + shufps m0, m0, m0, q0123 + unpcklps m2, m0, m1 + unpckhps m0, m0, m1 + mova [Wq + 0], m2 + mova [Wq + 16], m0 + add Wq, 32 + sub r2q, 16 + add zq, 16 + cmp zq, r2q + jl .loop + REP_RET + +INIT_XMM sse +cglobal sbr_neg_odd_64, 1,2,4,z + lea r1q, [zq+256] +.loop: + mova m0, [zq+ 0] + mova m1, [zq+16] + mova m2, [zq+32] + mova m3, [zq+48] + xorps m0, [ps_mask2] + xorps m1, [ps_mask2] + xorps m2, [ps_mask2] + xorps m3, [ps_mask2] + mova [zq+ 0], m0 + mova [zq+16], m1 + mova [zq+32], m2 + mova [zq+48], m3 + add zq, 64 + cmp zq, r1q + jne .loop + REP_RET + +; void ff_sbr_qmf_deint_bfly_sse2(float *v, const float *src0, const float *src1) +%macro SBR_QMF_DEINT_BFLY 0 +cglobal sbr_qmf_deint_bfly, 3,5,8, v,src0,src1,vrev,c + mov cq, 64*4-2*mmsize + lea vrevq, [vq + 64*4] +.loop: + mova m0, [src0q+cq] + mova m1, [src1q] + mova m4, [src0q+cq+mmsize] + mova m5, [src1q+mmsize] +%if cpuflag(sse2) + pshufd m2, m0, q0123 + pshufd m3, m1, q0123 + pshufd m6, m4, q0123 + pshufd m7, m5, q0123 +%else + shufps m2, m0, m0, q0123 + shufps m3, m1, m1, q0123 + shufps m6, m4, m4, q0123 + shufps m7, m5, m5, q0123 +%endif + addps m5, m2 + subps m0, m7 + addps m1, m6 + subps m4, m3 + mova [vrevq], m1 + mova [vrevq+mmsize], m5 + mova [vq+cq], m0 + mova [vq+cq+mmsize], m4 + add src1q, 2*mmsize + add vrevq, 2*mmsize + sub cq, 2*mmsize + jge .loop + REP_RET +%endmacro + +INIT_XMM sse +SBR_QMF_DEINT_BFLY + +INIT_XMM sse2 +SBR_QMF_DEINT_BFLY + +INIT_XMM sse2 +cglobal sbr_qmf_pre_shuffle, 1,4,6,z +%define OFFSET (32*4-2*mmsize) + mov r3q, OFFSET + lea r1q, [zq + (32+1)*4] + lea r2q, [zq + 64*4] + mova m5, [ps_neg] +.loop: + movu m0, [r1q] + movu m2, [r1q + mmsize] + movu m1, [zq + r3q + 4 + mmsize] + movu m3, [zq + r3q + 4] + + pxor m2, m5 + pxor m0, m5 + pshufd m2, m2, q0123 + pshufd m0, m0, q0123 + SBUTTERFLY dq, 2, 3, 4 + SBUTTERFLY dq, 0, 1, 4 + mova [r2q + 2*r3q + 0*mmsize], m2 + mova [r2q + 2*r3q + 1*mmsize], m3 + mova [r2q + 2*r3q + 2*mmsize], m0 + mova [r2q + 2*r3q + 3*mmsize], m1 + add r1q, 2*mmsize + sub r3q, 2*mmsize + jge .loop + movq m2, [zq] + movq [r2q], m2 + REP_RET + +%ifdef PIC +%define NREGS 1 +%if UNIX64 +%define NOISE_TABLE r6q ; r5q is m_max +%else +%define NOISE_TABLE r5q +%endif +%else +%define NREGS 0 +%define NOISE_TABLE sbr_noise_table +%endif + +%macro LOAD_NST 1 +%ifdef PIC + lea NOISE_TABLE, [%1] + mova m0, [kxq + NOISE_TABLE] +%else + mova m0, [kxq + %1] +%endif +%endmacro + +INIT_XMM sse2 +; sbr_hf_apply_noise_0(float (*Y)[2], const float *s_m, +; const float *q_filt, int noise, +; int kx, int m_max) +cglobal sbr_hf_apply_noise_0, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max + mova m0, [ps_noise0] + jmp apply_noise_main + +; sbr_hf_apply_noise_1(float (*Y)[2], const float *s_m, +; const float *q_filt, int noise, +; int kx, int m_max) +cglobal sbr_hf_apply_noise_1, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max + and kxq, 1 + shl kxq, 4 + LOAD_NST ps_noise13 + jmp apply_noise_main + +; sbr_hf_apply_noise_2(float (*Y)[2], const float *s_m, +; const float *q_filt, int noise, +; int kx, int m_max) +cglobal sbr_hf_apply_noise_2, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max + mova m0, [ps_noise2] + jmp apply_noise_main + +; sbr_hf_apply_noise_3(float (*Y)[2], const float *s_m, +; const float *q_filt, int noise, +; int kx, int m_max) +cglobal sbr_hf_apply_noise_3, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max + and kxq, 1 + shl kxq, 4 + LOAD_NST ps_noise13+16 + +apply_noise_main: +%if ARCH_X86_64 == 0 || WIN64 + mov kxd, m_maxm + DEFINE_ARGS Y, s_m, q_filt, noise, count +%else + DEFINE_ARGS Y, s_m, q_filt, noise, kx, count +%endif + movsxdifnidn noiseq, noised + dec noiseq + shl countd, 2 +%ifdef PIC + lea NOISE_TABLE, [sbr_noise_table] +%endif + lea Yq, [Yq + 2*countq] + add s_mq, countq + add q_filtq, countq + shl noiseq, 3 + pxor m5, m5 + neg countq +.loop: + mova m1, [q_filtq + countq] + movu m3, [noiseq + NOISE_TABLE + 1*mmsize] + movu m4, [noiseq + NOISE_TABLE + 2*mmsize] + add noiseq, 2*mmsize + and noiseq, 0x1ff<<3 + punpckhdq m2, m1, m1 + punpckldq m1, m1 + mulps m1, m3 ; m2 = q_filt[m] * ff_sbr_noise_table[noise] + mulps m2, m4 ; m2 = q_filt[m] * ff_sbr_noise_table[noise] + mova m3, [s_mq + countq] + ; TODO: replace by a vpermd in AVX2 + punpckhdq m4, m3, m3 + punpckldq m3, m3 + pcmpeqd m6, m3, m5 ; m6 == 0 + pcmpeqd m7, m4, m5 ; m7 == 0 + mulps m3, m0 ; s_m[m] * phi_sign + mulps m4, m0 ; s_m[m] * phi_sign + pand m1, m6 + pand m2, m7 + movu m6, [Yq + 2*countq] + movu m7, [Yq + 2*countq + mmsize] + addps m3, m1 + addps m4, m2 + addps m6, m3 + addps m7, m4 + movu [Yq + 2*countq], m6 + movu [Yq + 2*countq + mmsize], m7 + add countq, mmsize + jl .loop + RET + +INIT_XMM sse +cglobal sbr_qmf_deint_neg, 2,4,4,v,src,vrev,c +%define COUNT 32*4 +%define OFFSET 32*4 + mov cq, -COUNT + lea vrevq, [vq + OFFSET + COUNT] + add vq, OFFSET-mmsize + add srcq, 2*COUNT + mova m3, [ps_neg] +.loop: + mova m0, [srcq + 2*cq + 0*mmsize] + mova m1, [srcq + 2*cq + 1*mmsize] + shufps m2, m0, m1, q2020 + shufps m1, m0, q1313 + xorps m2, m3 + mova [vq], m1 + mova [vrevq + cq], m2 + sub vq, mmsize + add cq, mmsize + jl .loop + REP_RET + +%macro SBR_AUTOCORRELATE 0 +cglobal sbr_autocorrelate, 2,3,8,32, x, phi, cnt + mov cntq, 37*8 + add xq, cntq + neg cntq + +%if cpuflag(sse3) +%define MOVH movsd + movddup m5, [xq+cntq] +%else +%define MOVH movlps + movlps m5, [xq+cntq] + movlhps m5, m5 +%endif + MOVH m7, [xq+cntq+8 ] + MOVH m1, [xq+cntq+16] + shufps m7, m7, q0110 + shufps m1, m1, q0110 + mulps m3, m5, m7 ; x[0][0] * x[1][0], x[0][1] * x[1][1], x[0][0] * x[1][1], x[0][1] * x[1][0] + mulps m4, m5, m5 ; x[0][0] * x[0][0], x[0][1] * x[0][1]; + mulps m5, m1 ; real_sum2 = x[0][0] * x[2][0], x[0][1] * x[2][1]; imag_sum2 = x[0][0] * x[2][1], x[0][1] * x[2][0] + movaps [rsp ], m3 + movaps [rsp+16], m4 + add cntq, 8 + + MOVH m2, [xq+cntq+16] + movlhps m7, m7 + shufps m2, m2, q0110 + mulps m6, m7, m1 ; real_sum1 = x[1][0] * x[2][0], x[1][1] * x[2][1]; imag_sum1 += x[1][0] * x[2][1], x[1][1] * x[2][0] + mulps m4, m7, m2 + mulps m7, m7 ; real_sum0 = x[1][0] * x[1][0], x[1][1] * x[1][1]; + addps m5, m4 ; real_sum2 += x[1][0] * x[3][0], x[1][1] * x[3][1]; imag_sum2 += x[1][0] * x[3][1], x[1][1] * x[3][0] + +align 16 +.loop: + add cntq, 8 + MOVH m0, [xq+cntq+16] + movlhps m1, m1 + shufps m0, m0, q0110 + mulps m3, m1, m2 + mulps m4, m1, m0 + mulps m1, m1 + addps m6, m3 ; real_sum1 += x[i][0] * x[i + 1][0], x[i][1] * x[i + 1][1]; imag_sum1 += x[i][0] * x[i + 1][1], x[i][1] * x[i + 1][0]; + addps m5, m4 ; real_sum2 += x[i][0] * x[i + 2][0], x[i][1] * x[i + 2][1]; imag_sum2 += x[i][0] * x[i + 2][1], x[i][1] * x[i + 2][0]; + addps m7, m1 ; real_sum0 += x[i][0] * x[i][0], x[i][1] * x[i][1]; + add cntq, 8 + MOVH m1, [xq+cntq+16] + movlhps m2, m2 + shufps m1, m1, q0110 + mulps m3, m2, m0 + mulps m4, m2, m1 + mulps m2, m2 + addps m6, m3 ; real_sum1 += x[i][0] * x[i + 1][0], x[i][1] * x[i + 1][1]; imag_sum1 += x[i][0] * x[i + 1][1], x[i][1] * x[i + 1][0]; + addps m5, m4 ; real_sum2 += x[i][0] * x[i + 2][0], x[i][1] * x[i + 2][1]; imag_sum2 += x[i][0] * x[i + 2][1], x[i][1] * x[i + 2][0]; + addps m7, m2 ; real_sum0 += x[i][0] * x[i][0], x[i][1] * x[i][1]; + add cntq, 8 + MOVH m2, [xq+cntq+16] + movlhps m0, m0 + shufps m2, m2, q0110 + mulps m3, m0, m1 + mulps m4, m0, m2 + mulps m0, m0 + addps m6, m3 ; real_sum1 += x[i][0] * x[i + 1][0], x[i][1] * x[i + 1][1]; imag_sum1 += x[i][0] * x[i + 1][1], x[i][1] * x[i + 1][0]; + addps m5, m4 ; real_sum2 += x[i][0] * x[i + 2][0], x[i][1] * x[i + 2][1]; imag_sum2 += x[i][0] * x[i + 2][1], x[i][1] * x[i + 2][0]; + addps m7, m0 ; real_sum0 += x[i][0] * x[i][0], x[i][1] * x[i][1]; + jl .loop + + movlhps m1, m1 + mulps m2, m1 + mulps m1, m1 + addps m2, m6 ; real_sum1 + x[38][0] * x[39][0], x[38][1] * x[39][1]; imag_sum1 + x[38][0] * x[39][1], x[38][1] * x[39][0]; + addps m1, m7 ; real_sum0 + x[38][0] * x[38][0], x[38][1] * x[38][1]; + addps m6, [rsp ] ; real_sum1 + x[ 0][0] * x[ 1][0], x[ 0][1] * x[ 1][1]; imag_sum1 + x[ 0][0] * x[ 1][1], x[ 0][1] * x[ 1][0]; + addps m7, [rsp+16] ; real_sum0 + x[ 0][0] * x[ 0][0], x[ 0][1] * x[ 0][1]; + + xorps m2, [ps_mask3] + xorps m5, [ps_mask3] + xorps m6, [ps_mask3] + HADDPS m2, m5, m3 + HADDPS m7, m6, m4 +%if cpuflag(sse3) + movshdup m0, m1 +%else + movss m0, m1 + shufps m1, m1, q0001 +%endif + addss m1, m0 + movaps [phiq ], m2 + movhps [phiq+0x18], m7 + movss [phiq+0x28], m7 + movss [phiq+0x10], m1 + RET +%endmacro + +INIT_XMM sse +SBR_AUTOCORRELATE +INIT_XMM sse3 +SBR_AUTOCORRELATE diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.c new file mode 100644 index 0000000000..a93b5f9c13 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.c @@ -0,0 +1,225 @@ +/* + * AAC Spectral Band Replication decoding functions + * Copyright (c) 2008-2009 Robert Swain ( rob opendot cl ) + * Copyright (c) 2009-2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 0 + +#include "aac.h" +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/intfloat.h" +#include "sbrdsp.h" + +static float sbr_sum_square_c(float (*x)[2], int n) +{ + float sum0 = 0.0f, sum1 = 0.0f; + int i; + + for (i = 0; i < n; i += 2) + { + sum0 += x[i + 0][0] * x[i + 0][0]; + sum1 += x[i + 0][1] * x[i + 0][1]; + sum0 += x[i + 1][0] * x[i + 1][0]; + sum1 += x[i + 1][1] * x[i + 1][1]; + } + + return sum0 + sum1; +} + +static void sbr_neg_odd_64_c(float *x) +{ + union av_intfloat32 *xi = (union av_intfloat32*) x; + int i; + for (i = 1; i < 64; i += 4) { + xi[i + 0].i ^= 1U << 31; + xi[i + 2].i ^= 1U << 31; + } +} + +static void sbr_qmf_pre_shuffle_c(float *z) +{ + union av_intfloat32 *zi = (union av_intfloat32*) z; + int k; + zi[64].i = zi[0].i; + zi[65].i = zi[1].i; + for (k = 1; k < 31; k += 2) { + zi[64 + 2 * k + 0].i = zi[64 - k].i ^ (1U << 31); + zi[64 + 2 * k + 1].i = zi[ k + 1].i; + zi[64 + 2 * k + 2].i = zi[63 - k].i ^ (1U << 31); + zi[64 + 2 * k + 3].i = zi[ k + 2].i; + } + + zi[64 + 2 * 31 + 0].i = zi[64 - 31].i ^ (1U << 31); + zi[64 + 2 * 31 + 1].i = zi[31 + 1].i; +} + +static void sbr_qmf_post_shuffle_c(float W[32][2], const float *z) +{ + const union av_intfloat32 *zi = (const union av_intfloat32*) z; + union av_intfloat32 *Wi = (union av_intfloat32*) W; + int k; + for (k = 0; k < 32; k += 2) { + Wi[2 * k + 0].i = zi[63 - k].i ^ (1U << 31); + Wi[2 * k + 1].i = zi[ k + 0].i; + Wi[2 * k + 2].i = zi[62 - k].i ^ (1U << 31); + Wi[2 * k + 3].i = zi[ k + 1].i; + } +} + +static void sbr_qmf_deint_neg_c(float *v, const float *src) +{ + const union av_intfloat32 *si = (const union av_intfloat32*)src; + union av_intfloat32 *vi = (union av_intfloat32*)v; + int i; + for (i = 0; i < 32; i++) { + vi[ i].i = si[63 - 2 * i ].i; + vi[63 - i].i = si[63 - 2 * i - 1].i ^ (1U << 31); + } +} + +#if 0 + /* This code is slower because it multiplies memory accesses. + * It is left for educational purposes and because it may offer + * a better reference for writing arch-specific DSP functions. */ +static av_always_inline void autocorrelate(const float x[40][2], + float phi[3][2][2], int lag) +{ + int i; + float real_sum = 0.0f; + float imag_sum = 0.0f; + if (lag) { + for (i = 1; i < 38; i++) { + real_sum += x[i][0] * x[i+lag][0] + x[i][1] * x[i+lag][1]; + imag_sum += x[i][0] * x[i+lag][1] - x[i][1] * x[i+lag][0]; + } + phi[2-lag][1][0] = real_sum + x[ 0][0] * x[lag][0] + x[ 0][1] * x[lag][1]; + phi[2-lag][1][1] = imag_sum + x[ 0][0] * x[lag][1] - x[ 0][1] * x[lag][0]; + if (lag == 1) { + phi[0][0][0] = real_sum + x[38][0] * x[39][0] + x[38][1] * x[39][1]; + phi[0][0][1] = imag_sum + x[38][0] * x[39][1] - x[38][1] * x[39][0]; + } + } else { + for (i = 1; i < 38; i++) { + real_sum += x[i][0] * x[i][0] + x[i][1] * x[i][1]; + } + phi[2][1][0] = real_sum + x[ 0][0] * x[ 0][0] + x[ 0][1] * x[ 0][1]; + phi[1][0][0] = real_sum + x[38][0] * x[38][0] + x[38][1] * x[38][1]; + } +} + +static void sbr_autocorrelate_c(const float x[40][2], float phi[3][2][2]) +{ + autocorrelate(x, phi, 0); + autocorrelate(x, phi, 1); + autocorrelate(x, phi, 2); +} +#else +static void sbr_autocorrelate_c(const float x[40][2], float phi[3][2][2]) +{ + float real_sum2 = x[0][0] * x[2][0] + x[0][1] * x[2][1]; + float imag_sum2 = x[0][0] * x[2][1] - x[0][1] * x[2][0]; + float real_sum1 = 0.0f, imag_sum1 = 0.0f, real_sum0 = 0.0f; + int i; + for (i = 1; i < 38; i++) { + real_sum0 += x[i][0] * x[i ][0] + x[i][1] * x[i ][1]; + real_sum1 += x[i][0] * x[i + 1][0] + x[i][1] * x[i + 1][1]; + imag_sum1 += x[i][0] * x[i + 1][1] - x[i][1] * x[i + 1][0]; + real_sum2 += x[i][0] * x[i + 2][0] + x[i][1] * x[i + 2][1]; + imag_sum2 += x[i][0] * x[i + 2][1] - x[i][1] * x[i + 2][0]; + } + phi[2 - 2][1][0] = real_sum2; + phi[2 - 2][1][1] = imag_sum2; + phi[2 ][1][0] = real_sum0 + x[ 0][0] * x[ 0][0] + x[ 0][1] * x[ 0][1]; + phi[1 ][0][0] = real_sum0 + x[38][0] * x[38][0] + x[38][1] * x[38][1]; + phi[2 - 1][1][0] = real_sum1 + x[ 0][0] * x[ 1][0] + x[ 0][1] * x[ 1][1]; + phi[2 - 1][1][1] = imag_sum1 + x[ 0][0] * x[ 1][1] - x[ 0][1] * x[ 1][0]; + phi[0 ][0][0] = real_sum1 + x[38][0] * x[39][0] + x[38][1] * x[39][1]; + phi[0 ][0][1] = imag_sum1 + x[38][0] * x[39][1] - x[38][1] * x[39][0]; +} +#endif + +static void sbr_hf_gen_c(float (*X_high)[2], const float (*X_low)[2], + const float alpha0[2], const float alpha1[2], + float bw, int start, int end) +{ + float alpha[4]; + int i; + + alpha[0] = alpha1[0] * bw * bw; + alpha[1] = alpha1[1] * bw * bw; + alpha[2] = alpha0[0] * bw; + alpha[3] = alpha0[1] * bw; + + for (i = start; i < end; i++) { + X_high[i][0] = + X_low[i - 2][0] * alpha[0] - + X_low[i - 2][1] * alpha[1] + + X_low[i - 1][0] * alpha[2] - + X_low[i - 1][1] * alpha[3] + + X_low[i][0]; + X_high[i][1] = + X_low[i - 2][1] * alpha[0] + + X_low[i - 2][0] * alpha[1] + + X_low[i - 1][1] * alpha[2] + + X_low[i - 1][0] * alpha[3] + + X_low[i][1]; + } +} + +static void sbr_hf_g_filt_c(float (*Y)[2], const float (*X_high)[40][2], + const float *g_filt, int m_max, intptr_t ixh) +{ + int m; + + for (m = 0; m < m_max; m++) { + Y[m][0] = X_high[m][ixh][0] * g_filt[m]; + Y[m][1] = X_high[m][ixh][1] * g_filt[m]; + } +} + +static av_always_inline void sbr_hf_apply_noise(float (*Y)[2], + const float *s_m, + const float *q_filt, + int noise, + float phi_sign0, + float phi_sign1, + int m_max) +{ + int m; + + for (m = 0; m < m_max; m++) { + float y0 = Y[m][0]; + float y1 = Y[m][1]; + noise = (noise + 1) & 0x1ff; + if (s_m[m]) { + y0 += s_m[m] * phi_sign0; + y1 += s_m[m] * phi_sign1; + } else { + y0 += q_filt[m] * ff_sbr_noise_table[noise][0]; + y1 += q_filt[m] * ff_sbr_noise_table[noise][1]; + } + Y[m][0] = y0; + Y[m][1] = y1; + phi_sign1 = -phi_sign1; + } +} + +#include "sbrdsp_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.h new file mode 100644 index 0000000000..e6fd76d8ed --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_SBRDSP_H +#define AVCODEC_SBRDSP_H + +#include +#include "aac_defines.h" +#include "libavutil/softfloat.h" + +typedef struct SBRDSPContext { + void (*sum64x5)(INTFLOAT *z); + AAC_FLOAT (*sum_square)(INTFLOAT (*x)[2], int n); + void (*neg_odd_64)(INTFLOAT *x); + void (*qmf_pre_shuffle)(INTFLOAT *z); + void (*qmf_post_shuffle)(INTFLOAT W[32][2], const INTFLOAT *z); + void (*qmf_deint_neg)(INTFLOAT *v, const INTFLOAT *src); + void (*qmf_deint_bfly)(INTFLOAT *v, const INTFLOAT *src0, const INTFLOAT *src1); + void (*autocorrelate)(const INTFLOAT x[40][2], AAC_FLOAT phi[3][2][2]); + void (*hf_gen)(INTFLOAT (*X_high)[2], const INTFLOAT (*X_low)[2], + const INTFLOAT alpha0[2], const INTFLOAT alpha1[2], + INTFLOAT bw, int start, int end); + void (*hf_g_filt)(INTFLOAT (*Y)[2], const INTFLOAT (*X_high)[40][2], + const AAC_FLOAT *g_filt, int m_max, intptr_t ixh); + void (*hf_apply_noise[4])(INTFLOAT (*Y)[2], const AAC_FLOAT *s_m, + const AAC_FLOAT *q_filt, int noise, + int kx, int m_max); +} SBRDSPContext; + +extern const INTFLOAT AAC_RENAME(ff_sbr_noise_table)[][2]; + +void AAC_RENAME(ff_sbrdsp_init)(SBRDSPContext *s); +void ff_sbrdsp_init_arm(SBRDSPContext *s); +void ff_sbrdsp_init_aarch64(SBRDSPContext *s); +void ff_sbrdsp_init_x86(SBRDSPContext *s); +void ff_sbrdsp_init_mips(SBRDSPContext *s); + +#endif /* AVCODEC_SBRDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_fixed.c new file mode 100644 index 0000000000..91fa664c08 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_fixed.c @@ -0,0 +1,315 @@ +/* + * AAC Spectral Band Replication decoding functions + * Copyright (c) 2008-2009 Robert Swain ( rob opendot cl ) + * Copyright (c) 2009-2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Note: Rounding-to-nearest used unless otherwise stated + * + */ + +#define USE_FIXED 1 + +#include "aac.h" +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/intfloat.h" +#include "sbrdsp.h" + +static SoftFloat sbr_sum_square_c(int (*x)[2], int n) +{ + SoftFloat ret; + uint64_t accu = 0, round; + uint64_t accu0 = 0, accu1 = 0, accu2 = 0, accu3 = 0; + int i, nz, nz0; + unsigned u; + + nz = 0; + for (i = 0; i < n; i += 2) { + accu0 += (int64_t)x[i + 0][0] * x[i + 0][0]; + accu1 += (int64_t)x[i + 0][1] * x[i + 0][1]; + accu2 += (int64_t)x[i + 1][0] * x[i + 1][0]; + accu3 += (int64_t)x[i + 1][1] * x[i + 1][1]; + if ((accu0|accu1|accu2|accu3) > UINT64_MAX - INT32_MIN*(int64_t)INT32_MIN || i+2>=n) { + accu0 >>= nz; + accu1 >>= nz; + accu2 >>= nz; + accu3 >>= nz; + while ((accu0|accu1|accu2|accu3) > (UINT64_MAX - accu) >> 2) { + accu0 >>= 1; + accu1 >>= 1; + accu2 >>= 1; + accu3 >>= 1; + accu >>= 1; + nz ++; + } + accu += accu0 + accu1 + accu2 + accu3; + accu0 = accu1 = accu2 = accu3 = 0; + } + } + + nz0 = 15 - nz; + + u = accu >> 32; + if (u) { + nz = 33; + while (u < 0x80000000U) { + u <<= 1; + nz--; + } + } else + nz = 1; + + round = 1ULL << (nz-1); + u = ((accu + round) >> nz); + u >>= 1; + ret = av_int2sf(u, nz0 - nz); + + return ret; +} + +static void sbr_neg_odd_64_c(int *x) +{ + int i; + for (i = 1; i < 64; i += 2) + x[i] = -x[i]; +} + +static void sbr_qmf_pre_shuffle_c(int *z) +{ + int k; + z[64] = z[0]; + z[65] = z[1]; + for (k = 1; k < 32; k++) { + z[64+2*k ] = -z[64 - k]; + z[64+2*k+1] = z[ k + 1]; + } +} + +static void sbr_qmf_post_shuffle_c(int W[32][2], const int *z) +{ + int k; + for (k = 0; k < 32; k++) { + W[k][0] = -z[63-k]; + W[k][1] = z[k]; + } +} + +static void sbr_qmf_deint_neg_c(int *v, const int *src) +{ + int i; + for (i = 0; i < 32; i++) { + v[ i] = ( src[63 - 2*i ] + 0x10) >> 5; + v[63 - i] = (-src[63 - 2*i - 1] + 0x10) >> 5; + } +} + +static av_always_inline SoftFloat autocorr_calc(int64_t accu) +{ + int nz, mant, expo; + unsigned round; + int i = (int)(accu >> 32); + if (i == 0) { + nz = 1; + } else { + nz = 0; + while (FFABS(i) < 0x40000000) { + i *= 2; + nz++; + } + nz = 32-nz; + } + + round = 1U << (nz-1); + mant = (int)((accu + round) >> nz); + mant = (mant + 0x40LL)>>7; + mant *= 64; + expo = nz + 15; + return av_int2sf(mant, 30 - expo); +} + +static av_always_inline void autocorrelate(const int x[40][2], SoftFloat phi[3][2][2], int lag) +{ + int i; + int64_t real_sum, imag_sum; + int64_t accu_re = 0, accu_im = 0; + + if (lag) { + for (i = 1; i < 38; i++) { + accu_re += (uint64_t)x[i][0] * x[i+lag][0]; + accu_re += (uint64_t)x[i][1] * x[i+lag][1]; + accu_im += (uint64_t)x[i][0] * x[i+lag][1]; + accu_im -= (uint64_t)x[i][1] * x[i+lag][0]; + } + + real_sum = accu_re; + imag_sum = accu_im; + + accu_re += (uint64_t)x[ 0][0] * x[lag][0]; + accu_re += (uint64_t)x[ 0][1] * x[lag][1]; + accu_im += (uint64_t)x[ 0][0] * x[lag][1]; + accu_im -= (uint64_t)x[ 0][1] * x[lag][0]; + + phi[2-lag][1][0] = autocorr_calc(accu_re); + phi[2-lag][1][1] = autocorr_calc(accu_im); + + if (lag == 1) { + accu_re = real_sum; + accu_im = imag_sum; + accu_re += (uint64_t)x[38][0] * x[39][0]; + accu_re += (uint64_t)x[38][1] * x[39][1]; + accu_im += (uint64_t)x[38][0] * x[39][1]; + accu_im -= (uint64_t)x[38][1] * x[39][0]; + + phi[0][0][0] = autocorr_calc(accu_re); + phi[0][0][1] = autocorr_calc(accu_im); + } + } else { + for (i = 1; i < 38; i++) { + accu_re += (uint64_t)x[i][0] * x[i][0]; + accu_re += (uint64_t)x[i][1] * x[i][1]; + } + real_sum = accu_re; + accu_re += (uint64_t)x[ 0][0] * x[ 0][0]; + accu_re += (uint64_t)x[ 0][1] * x[ 0][1]; + + phi[2][1][0] = autocorr_calc(accu_re); + + accu_re = real_sum; + accu_re += (uint64_t)x[38][0] * x[38][0]; + accu_re += (uint64_t)x[38][1] * x[38][1]; + + phi[1][0][0] = autocorr_calc(accu_re); + } +} + +static void sbr_autocorrelate_c(const int x[40][2], SoftFloat phi[3][2][2]) +{ + autocorrelate(x, phi, 0); + autocorrelate(x, phi, 1); + autocorrelate(x, phi, 2); +} + +static void sbr_hf_gen_c(int (*X_high)[2], const int (*X_low)[2], + const int alpha0[2], const int alpha1[2], + int bw, int start, int end) +{ + int alpha[4]; + int i; + int64_t accu; + + accu = (int64_t)alpha0[0] * bw; + alpha[2] = (int)((accu + 0x40000000) >> 31); + accu = (int64_t)alpha0[1] * bw; + alpha[3] = (int)((accu + 0x40000000) >> 31); + accu = (int64_t)bw * bw; + bw = (int)((accu + 0x40000000) >> 31); + accu = (int64_t)alpha1[0] * bw; + alpha[0] = (int)((accu + 0x40000000) >> 31); + accu = (int64_t)alpha1[1] * bw; + alpha[1] = (int)((accu + 0x40000000) >> 31); + + for (i = start; i < end; i++) { + accu = (int64_t)X_low[i][0] * 0x20000000; + accu += (int64_t)X_low[i - 2][0] * alpha[0]; + accu -= (int64_t)X_low[i - 2][1] * alpha[1]; + accu += (int64_t)X_low[i - 1][0] * alpha[2]; + accu -= (int64_t)X_low[i - 1][1] * alpha[3]; + X_high[i][0] = (int)((accu + 0x10000000) >> 29); + + accu = (int64_t)X_low[i][1] * 0x20000000; + accu += (int64_t)X_low[i - 2][1] * alpha[0]; + accu += (int64_t)X_low[i - 2][0] * alpha[1]; + accu += (int64_t)X_low[i - 1][1] * alpha[2]; + accu += (int64_t)X_low[i - 1][0] * alpha[3]; + X_high[i][1] = (int)((accu + 0x10000000) >> 29); + } +} + +static void sbr_hf_g_filt_c(int (*Y)[2], const int (*X_high)[40][2], + const SoftFloat *g_filt, int m_max, intptr_t ixh) +{ + int m; + int64_t accu; + + for (m = 0; m < m_max; m++) { + if (22 - g_filt[m].exp < 61) { + int64_t r = 1LL << (22-g_filt[m].exp); + accu = (int64_t)X_high[m][ixh][0] * ((g_filt[m].mant + 0x40)>>7); + Y[m][0] = (int)((accu + r) >> (23-g_filt[m].exp)); + + accu = (int64_t)X_high[m][ixh][1] * ((g_filt[m].mant + 0x40)>>7); + Y[m][1] = (int)((accu + r) >> (23-g_filt[m].exp)); + } + } +} + +static av_always_inline int sbr_hf_apply_noise(int (*Y)[2], + const SoftFloat *s_m, + const SoftFloat *q_filt, + int noise, + int phi_sign0, + int phi_sign1, + int m_max) +{ + int m; + + for (m = 0; m < m_max; m++) { + unsigned y0 = Y[m][0]; + unsigned y1 = Y[m][1]; + noise = (noise + 1) & 0x1ff; + if (s_m[m].mant) { + int shift, round; + + shift = 22 - s_m[m].exp; + if (shift < 1) { + av_log(NULL, AV_LOG_ERROR, "Overflow in sbr_hf_apply_noise, shift=%d\n", shift); + return AVERROR(ERANGE); + } else if (shift < 30) { + round = 1 << (shift-1); + y0 += (s_m[m].mant * phi_sign0 + round) >> shift; + y1 += (s_m[m].mant * phi_sign1 + round) >> shift; + } + } else { + int shift, round, tmp; + int64_t accu; + + shift = 22 - q_filt[m].exp; + if (shift < 1) { + av_log(NULL, AV_LOG_ERROR, "Overflow in sbr_hf_apply_noise, shift=%d\n", shift); + return AVERROR(ERANGE); + } else if (shift < 30) { + round = 1 << (shift-1); + + accu = (int64_t)q_filt[m].mant * ff_sbr_noise_table_fixed[noise][0]; + tmp = (int)((accu + 0x40000000) >> 31); + y0 += (tmp + round) >> shift; + + accu = (int64_t)q_filt[m].mant * ff_sbr_noise_table_fixed[noise][1]; + tmp = (int)((accu + 0x40000000) >> 31); + y1 += (tmp + round) >> shift; + } + } + Y[m][0] = y0; + Y[m][1] = y1; + phi_sign1 = -phi_sign1; + } + return 0; +} + +#include "sbrdsp_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_init.c new file mode 100644 index 0000000000..6911a1a515 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_init.c @@ -0,0 +1,87 @@ +/* + * AAC Spectral Band Replication decoding functions + * Copyright (c) 2012 Christophe Gisquet + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/sbrdsp.h" + +float ff_sbr_sum_square_sse(float (*x)[2], int n); +void ff_sbr_sum64x5_sse(float *z); +void ff_sbr_hf_g_filt_sse(float (*Y)[2], const float (*X_high)[40][2], + const float *g_filt, int m_max, intptr_t ixh); +void ff_sbr_hf_gen_sse(float (*X_high)[2], const float (*X_low)[2], + const float alpha0[2], const float alpha1[2], + float bw, int start, int end); +void ff_sbr_neg_odd_64_sse(float *z); +void ff_sbr_qmf_post_shuffle_sse(float W[32][2], const float *z); +void ff_sbr_qmf_deint_bfly_sse(float *v, const float *src0, const float *src1); +void ff_sbr_qmf_deint_bfly_sse2(float *v, const float *src0, const float *src1); +void ff_sbr_qmf_pre_shuffle_sse2(float *z); + +void ff_sbr_hf_apply_noise_0_sse2(float (*Y)[2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); +void ff_sbr_hf_apply_noise_1_sse2(float (*Y)[2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); +void ff_sbr_hf_apply_noise_2_sse2(float (*Y)[2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); +void ff_sbr_hf_apply_noise_3_sse2(float (*Y)[2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); + +void ff_sbr_qmf_deint_neg_sse(float *v, const float *src); + +void ff_sbr_autocorrelate_sse (const float x[40][2], float phi[3][2][2]); +void ff_sbr_autocorrelate_sse3(const float x[40][2], float phi[3][2][2]); + +av_cold void ff_sbrdsp_init_x86(SBRDSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE(cpu_flags)) { + s->neg_odd_64 = ff_sbr_neg_odd_64_sse; + s->sum_square = ff_sbr_sum_square_sse; + s->sum64x5 = ff_sbr_sum64x5_sse; + s->hf_g_filt = ff_sbr_hf_g_filt_sse; + s->hf_gen = ff_sbr_hf_gen_sse; + s->qmf_post_shuffle = ff_sbr_qmf_post_shuffle_sse; + s->qmf_deint_bfly = ff_sbr_qmf_deint_bfly_sse; + s->qmf_deint_neg = ff_sbr_qmf_deint_neg_sse; + s->autocorrelate = ff_sbr_autocorrelate_sse; + } + + if (EXTERNAL_SSE2(cpu_flags)) { + s->qmf_deint_bfly = ff_sbr_qmf_deint_bfly_sse2; + s->qmf_pre_shuffle = ff_sbr_qmf_pre_shuffle_sse2; + s->hf_apply_noise[0] = ff_sbr_hf_apply_noise_0_sse2; + s->hf_apply_noise[1] = ff_sbr_hf_apply_noise_1_sse2; + s->hf_apply_noise[2] = ff_sbr_hf_apply_noise_2_sse2; + s->hf_apply_noise[3] = ff_sbr_hf_apply_noise_3_sse2; + } + + if (EXTERNAL_SSE3(cpu_flags)) { + s->autocorrelate = ff_sbr_autocorrelate_sse3; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_template.c new file mode 100644 index 0000000000..37a3365b97 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sbrdsp_template.c @@ -0,0 +1,104 @@ +/* + * AAC Spectral Band Replication decoding functions + * Copyright (c) 2008-2009 Robert Swain ( rob opendot cl ) + * Copyright (c) 2009-2010 Alex Converse + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static void sbr_sum64x5_c(INTFLOAT *z) +{ + int k; + for (k = 0; k < 64; k++) { + INTFLOAT f = z[k] + z[k + 64] + z[k + 128] + z[k + 192] + z[k + 256]; + z[k] = f; + } +} + +static void sbr_qmf_deint_bfly_c(INTFLOAT *v, const INTFLOAT *src0, const INTFLOAT *src1) +{ + int i; + for (i = 0; i < 64; i++) { +#if USE_FIXED + v[ i] = (int)(0x10U + src0[i] - src1[63 - i]) >> 5; + v[127 - i] = (int)(0x10U + src0[i] + src1[63 - i]) >> 5; +#else + v[ i] = src0[i] - src1[63 - i]; + v[127 - i] = src0[i] + src1[63 - i]; +#endif + } +} + +static void sbr_hf_apply_noise_0(INTFLOAT (*Y)[2], const AAC_FLOAT *s_m, + const AAC_FLOAT *q_filt, int noise, + int kx, int m_max) +{ + sbr_hf_apply_noise(Y, s_m, q_filt, noise, (INTFLOAT)1.0, (INTFLOAT)0.0, m_max); +} + +static void sbr_hf_apply_noise_1(INTFLOAT (*Y)[2], const AAC_FLOAT *s_m, + const AAC_FLOAT *q_filt, int noise, + int kx, int m_max) +{ + INTFLOAT phi_sign = 1 - 2 * (kx & 1); + sbr_hf_apply_noise(Y, s_m, q_filt, noise, (INTFLOAT)0.0, phi_sign, m_max); +} + +static void sbr_hf_apply_noise_2(INTFLOAT (*Y)[2], const AAC_FLOAT *s_m, + const AAC_FLOAT *q_filt, int noise, + int kx, int m_max) +{ + sbr_hf_apply_noise(Y, s_m, q_filt, noise, (INTFLOAT)-1.0, (INTFLOAT)0.0, m_max); +} + +static void sbr_hf_apply_noise_3(INTFLOAT (*Y)[2], const AAC_FLOAT *s_m, + const AAC_FLOAT *q_filt, int noise, + int kx, int m_max) +{ + INTFLOAT phi_sign = 1 - 2 * (kx & 1); + sbr_hf_apply_noise(Y, s_m, q_filt, noise, (INTFLOAT)0.0, -phi_sign, m_max); +} + +av_cold void AAC_RENAME(ff_sbrdsp_init)(SBRDSPContext *s) +{ + s->sum64x5 = sbr_sum64x5_c; + s->sum_square = sbr_sum_square_c; + s->neg_odd_64 = sbr_neg_odd_64_c; + s->qmf_pre_shuffle = sbr_qmf_pre_shuffle_c; + s->qmf_post_shuffle = sbr_qmf_post_shuffle_c; + s->qmf_deint_neg = sbr_qmf_deint_neg_c; + s->qmf_deint_bfly = sbr_qmf_deint_bfly_c; + s->autocorrelate = sbr_autocorrelate_c; + s->hf_gen = sbr_hf_gen_c; + s->hf_g_filt = sbr_hf_g_filt_c; + + s->hf_apply_noise[0] = sbr_hf_apply_noise_0; + s->hf_apply_noise[1] = sbr_hf_apply_noise_1; + s->hf_apply_noise[2] = sbr_hf_apply_noise_2; + s->hf_apply_noise[3] = sbr_hf_apply_noise_3; + +#if !USE_FIXED + if (ARCH_ARM) + ff_sbrdsp_init_arm(s); + if (ARCH_AARCH64) + ff_sbrdsp_init_aarch64(s); + if (ARCH_X86) + ff_sbrdsp_init_x86(s); + if (ARCH_MIPS) + ff_sbrdsp_init_mips(s); +#endif /* !USE_FIXED */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin.c new file mode 100644 index 0000000000..4532dc7354 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin.c @@ -0,0 +1,21 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 0 +#include "sinewin.h" +#include "sinewin_tablegen.h" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin.h new file mode 100644 index 0000000000..329e9bb5be --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008 Robert Swain + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_SINEWIN_H +#define AVCODEC_SINEWIN_H + +#include "config.h" +#include "libavutil/mem.h" +#include "libavcodec/aac_defines.h" + +#if CONFIG_HARDCODED_TABLES +# define SINETABLE_CONST const +#else +# define SINETABLE_CONST +#endif + +#ifndef USE_FIXED +#define USE_FIXED 0 +#endif + +#define SINETABLE(size) \ + SINETABLE_CONST DECLARE_ALIGNED(32, INTFLOAT, AAC_RENAME(ff_sine_##size))[size] + +#define SINETABLE120960(size) \ + DECLARE_ALIGNED(32, INTFLOAT, AAC_RENAME(ff_sine_##size))[size] + +/** + * Generate a sine window. + * @param window pointer to half window + * @param n size of half window + */ +void AAC_RENAME(ff_sine_window_init)(INTFLOAT *window, int n); + +/** + * initialize the specified entry of ff_sine_windows + */ +void AAC_RENAME(ff_init_ff_sine_windows)(int index); + +extern SINETABLE( 32); +extern SINETABLE( 64); +extern SINETABLE120960(120); +extern SINETABLE( 128); +extern SINETABLE( 256); +extern SINETABLE( 512); +extern SINETABLE120960(960); +extern SINETABLE(1024); +extern SINETABLE(2048); +extern SINETABLE(4096); +extern SINETABLE(8192); + +extern SINETABLE_CONST INTFLOAT * const AAC_RENAME(ff_sine_windows)[16]; + +#endif /* AVCODEC_SINEWIN_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_fixed.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_fixed.c new file mode 100644 index 0000000000..27ead29e8e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_fixed.c @@ -0,0 +1,21 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 1 +#include "sinewin.h" +#include "sinewin_tablegen.h" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_tablegen.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_tablegen.c new file mode 100644 index 0000000000..dd602668ee --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_tablegen.c @@ -0,0 +1,24 @@ +/* + * Generate a header file for hardcoded sine windows + * + * Copyright (c) 2009 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define USE_FIXED 0 +#include "sinewin_tablegen_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_tablegen.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_tablegen.h new file mode 100644 index 0000000000..dc52234ed0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/sinewin_tablegen.h @@ -0,0 +1,83 @@ +/* + * Header file for hardcoded sine windows + * + * Copyright (c) 2009 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_SINEWIN_TABLEGEN_H +#define AVCODEC_SINEWIN_TABLEGEN_H + +#include +// do not use libavutil/libm.h since this is compiled both +// for the host and the target and config.h is only valid for the target +#include +#include "libavcodec/aac_defines.h" +#include "libavutil/attributes.h" +#include "libavutil/common.h" + +#if !USE_FIXED +SINETABLE120960(120); +SINETABLE120960(960); +#endif +#if !CONFIG_HARDCODED_TABLES +SINETABLE( 32); +SINETABLE( 64); +SINETABLE( 128); +SINETABLE( 256); +SINETABLE( 512); +SINETABLE(1024); +SINETABLE(2048); +SINETABLE(4096); +SINETABLE(8192); +#else +#if USE_FIXED +#include "libavcodec/sinewin_fixed_tables.h" +#else +#include "libavcodec/sinewin_tables.h" +#endif +#endif + +#if USE_FIXED +#define SIN_FIX(a) (int)floor((a) * 0x80000000 + 0.5) +#else +#define SIN_FIX(a) a +#endif + +SINETABLE_CONST INTFLOAT * const AAC_RENAME(ff_sine_windows)[] = { + NULL, NULL, NULL, NULL, NULL, // unused + AAC_RENAME(ff_sine_32) , AAC_RENAME(ff_sine_64), AAC_RENAME(ff_sine_128), + AAC_RENAME(ff_sine_256), AAC_RENAME(ff_sine_512), AAC_RENAME(ff_sine_1024), + AAC_RENAME(ff_sine_2048), AAC_RENAME(ff_sine_4096), AAC_RENAME(ff_sine_8192), +}; + +// Generate a sine window. +av_cold void AAC_RENAME(ff_sine_window_init)(INTFLOAT *window, int n) { + int i; + for(i = 0; i < n; i++) + window[i] = SIN_FIX(sinf((i + 0.5) * (M_PI / (2.0 * n)))); +} + +av_cold void AAC_RENAME(ff_init_ff_sine_windows)(int index) { + assert(index >= 0 && index < FF_ARRAY_ELEMS(AAC_RENAME(ff_sine_windows))); +#if !CONFIG_HARDCODED_TABLES + AAC_RENAME(ff_sine_window_init)(AAC_RENAME(ff_sine_windows)[index], 1 << index); +#endif +} + +#endif /* AVCODEC_SINEWIN_TABLEGEN_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/thread.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/thread.h new file mode 100644 index 0000000000..540135fbc9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/thread.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2008 Alexander Strange + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Multithreading support functions + * @author Alexander Strange + */ + +#ifndef AVCODEC_THREAD_H +#define AVCODEC_THREAD_H + +#include "libavutil/buffer.h" + +#include "avcodec.h" + +typedef struct ThreadFrame { + AVFrame *f; + AVCodecContext *owner[2]; + // progress->data is an array of 2 ints holding progress for top/bottom + // fields + AVBufferRef *progress; +} ThreadFrame; + +/** + * Wait for decoding threads to finish and reset internal state. + * Called by avcodec_flush_buffers(). + * + * @param avctx The context. + */ +void ff_thread_flush(AVCodecContext *avctx); + +/** + * Submit a new frame to a decoding thread. + * Returns the next available frame in picture. *got_picture_ptr + * will be 0 if none is available. + * The return value on success is the size of the consumed packet for + * compatibility with avcodec_decode_video2(). This means the decoder + * has to consume the full packet. + * + * Parameters are the same as avcodec_decode_video2(). + */ +int ff_thread_decode_frame(AVCodecContext *avctx, AVFrame *picture, + int *got_picture_ptr, AVPacket *avpkt); + +/** + * If the codec defines update_thread_context(), call this + * when they are ready for the next thread to start decoding + * the next frame. After calling it, do not change any variables + * read by the update_thread_context() method, or call ff_thread_get_buffer(). + * + * @param avctx The context. + */ +void ff_thread_finish_setup(AVCodecContext *avctx); + +/** + * Notify later decoding threads when part of their reference picture is ready. + * Call this when some part of the picture is finished decoding. + * Later calls with lower values of progress have no effect. + * + * @param f The picture being decoded. + * @param progress Value, in arbitrary units, of how much of the picture has decoded. + * @param field The field being decoded, for field-picture codecs. + * 0 for top field or frame pictures, 1 for bottom field. + */ +void ff_thread_report_progress(ThreadFrame *f, int progress, int field); + +/** + * Wait for earlier decoding threads to finish reference pictures. + * Call this before accessing some part of a picture, with a given + * value for progress, and it will return after the responsible decoding + * thread calls ff_thread_report_progress() with the same or + * higher value for progress. + * + * @param f The picture being referenced. + * @param progress Value, in arbitrary units, to wait for. + * @param field The field being referenced, for field-picture codecs. + * 0 for top field or frame pictures, 1 for bottom field. + */ +void ff_thread_await_progress(ThreadFrame *f, int progress, int field); + +/** + * Wrapper around get_format() for frame-multithreaded codecs. + * Call this function instead of avctx->get_format(). + * Cannot be called after the codec has called ff_thread_finish_setup(). + * + * @param avctx The current context. + * @param fmt The list of available formats. + */ +enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt); + +/** + * Wrapper around get_buffer() for frame-multithreaded codecs. + * Call this function instead of ff_get_buffer(f). + * Cannot be called after the codec has called ff_thread_finish_setup(). + * + * @param avctx The current context. + * @param f The frame to write into. + */ +int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags); + +/** + * Wrapper around release_buffer() frame-for multithreaded codecs. + * Call this function instead of avctx->release_buffer(f). + * The AVFrame will be copied and the actual release_buffer() call + * will be performed later. The contents of data pointed to by the + * AVFrame should not be changed until ff_thread_get_buffer() is called + * on it. + * + * @param avctx The current context. + * @param f The picture being released. + */ +void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f); + +int ff_thread_ref_frame(ThreadFrame *dst, ThreadFrame *src); + +int ff_thread_init(AVCodecContext *s); +int ff_slice_thread_execute_with_mainfunc(AVCodecContext *avctx, + int (*action_func2)(AVCodecContext *c, void *arg, int jobnr, int threadnr), + int (*main_func)(AVCodecContext *c), void *arg, int *ret, int job_count); +void ff_thread_free(AVCodecContext *s); +int ff_alloc_entries(AVCodecContext *avctx, int count); +void ff_reset_entries(AVCodecContext *avctx); +void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n); +void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift); + +#endif /* AVCODEC_THREAD_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/utils.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/utils.c new file mode 100644 index 0000000000..a6a646636d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/utils.c @@ -0,0 +1,2234 @@ +/* + * utils for libavcodec + * Copyright (c) 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * utils. + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/bprint.h" +#include "libavutil/channel_layout.h" +#include "libavutil/crc.h" +#include "libavutil/frame.h" +#include "libavutil/hwcontext.h" +#include "libavutil/internal.h" +#include "libavutil/mathematics.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixdesc.h" +#include "libavutil/imgutils.h" +#include "libavutil/samplefmt.h" +#include "libavutil/dict.h" +#include "libavutil/thread.h" +#include "avcodec.h" +#include "decode.h" +#include "hwaccel.h" +#include "libavutil/opt.h" +#include "mpegvideo.h" +#include "thread.h" +#include "frame_thread_encoder.h" +#include "internal.h" +#include "raw.h" +#include "bytestream.h" +#include "version.h" +#include +#include +#include +#include +#include +#if CONFIG_ICONV +# include +#endif + +#include "libavutil/ffversion.h" +const char av_codec_ffversion[] = "FFmpeg version " FFMPEG_VERSION; + +static AVMutex codec_mutex = AV_MUTEX_INITIALIZER; + +void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size) +{ + uint8_t **p = ptr; + if (min_size > SIZE_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { + av_freep(p); + *size = 0; + return; + } + if (!ff_fast_malloc(p, size, min_size + AV_INPUT_BUFFER_PADDING_SIZE, 1)) + memset(*p + min_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); +} + +void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size) +{ + uint8_t **p = ptr; + if (min_size > SIZE_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { + av_freep(p); + *size = 0; + return; + } + if (!ff_fast_malloc(p, size, min_size + AV_INPUT_BUFFER_PADDING_SIZE, 1)) + memset(*p, 0, min_size + AV_INPUT_BUFFER_PADDING_SIZE); +} + +int av_codec_is_encoder(const AVCodec *codec) +{ + return codec && (codec->encode_sub || codec->encode2 ||codec->send_frame); +} + +int av_codec_is_decoder(const AVCodec *codec) +{ + return codec && (codec->decode || codec->receive_frame); +} + +int ff_set_dimensions(AVCodecContext *s, int width, int height) +{ + int ret = av_image_check_size2(width, height, s->max_pixels, AV_PIX_FMT_NONE, 0, s); + + if (ret < 0) + width = height = 0; + + s->coded_width = width; + s->coded_height = height; + s->width = AV_CEIL_RSHIFT(width, s->lowres); + s->height = AV_CEIL_RSHIFT(height, s->lowres); + + return ret; +} + +int ff_set_sar(AVCodecContext *avctx, AVRational sar) +{ + int ret = av_image_check_sar(avctx->width, avctx->height, sar); + + if (ret < 0) { + av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %d/%d\n", + sar.num, sar.den); + avctx->sample_aspect_ratio = (AVRational){ 0, 1 }; + return ret; + } else { + avctx->sample_aspect_ratio = sar; + } + return 0; +} + +int ff_side_data_update_matrix_encoding(AVFrame *frame, + enum AVMatrixEncoding matrix_encoding) +{ + AVFrameSideData *side_data; + enum AVMatrixEncoding *data; + + side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_MATRIXENCODING); + if (!side_data) + side_data = av_frame_new_side_data(frame, AV_FRAME_DATA_MATRIXENCODING, + sizeof(enum AVMatrixEncoding)); + + if (!side_data) + return AVERROR(ENOMEM); + + data = (enum AVMatrixEncoding*)side_data->data; + *data = matrix_encoding; + + return 0; +} + +void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, + int linesize_align[AV_NUM_DATA_POINTERS]) +{ + int i; + int w_align = 1; + int h_align = 1; + AVPixFmtDescriptor const *desc = av_pix_fmt_desc_get(s->pix_fmt); + + if (desc) { + w_align = 1 << desc->log2_chroma_w; + h_align = 1 << desc->log2_chroma_h; + } + + switch (s->pix_fmt) { + case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUYV422: + case AV_PIX_FMT_YVYU422: + case AV_PIX_FMT_UYVY422: + case AV_PIX_FMT_YUV422P: + case AV_PIX_FMT_YUV440P: + case AV_PIX_FMT_YUV444P: + case AV_PIX_FMT_GBRP: + case AV_PIX_FMT_GBRAP: + case AV_PIX_FMT_GRAY8: + case AV_PIX_FMT_GRAY16BE: + case AV_PIX_FMT_GRAY16LE: + case AV_PIX_FMT_YUVJ420P: + case AV_PIX_FMT_YUVJ422P: + case AV_PIX_FMT_YUVJ440P: + case AV_PIX_FMT_YUVJ444P: + case AV_PIX_FMT_YUVA420P: + case AV_PIX_FMT_YUVA422P: + case AV_PIX_FMT_YUVA444P: + case AV_PIX_FMT_YUV420P9LE: + case AV_PIX_FMT_YUV420P9BE: + case AV_PIX_FMT_YUV420P10LE: + case AV_PIX_FMT_YUV420P10BE: + case AV_PIX_FMT_YUV420P12LE: + case AV_PIX_FMT_YUV420P12BE: + case AV_PIX_FMT_YUV420P14LE: + case AV_PIX_FMT_YUV420P14BE: + case AV_PIX_FMT_YUV420P16LE: + case AV_PIX_FMT_YUV420P16BE: + case AV_PIX_FMT_YUVA420P9LE: + case AV_PIX_FMT_YUVA420P9BE: + case AV_PIX_FMT_YUVA420P10LE: + case AV_PIX_FMT_YUVA420P10BE: + case AV_PIX_FMT_YUVA420P16LE: + case AV_PIX_FMT_YUVA420P16BE: + case AV_PIX_FMT_YUV422P9LE: + case AV_PIX_FMT_YUV422P9BE: + case AV_PIX_FMT_YUV422P10LE: + case AV_PIX_FMT_YUV422P10BE: + case AV_PIX_FMT_YUV422P12LE: + case AV_PIX_FMT_YUV422P12BE: + case AV_PIX_FMT_YUV422P14LE: + case AV_PIX_FMT_YUV422P14BE: + case AV_PIX_FMT_YUV422P16LE: + case AV_PIX_FMT_YUV422P16BE: + case AV_PIX_FMT_YUVA422P9LE: + case AV_PIX_FMT_YUVA422P9BE: + case AV_PIX_FMT_YUVA422P10LE: + case AV_PIX_FMT_YUVA422P10BE: + case AV_PIX_FMT_YUVA422P12LE: + case AV_PIX_FMT_YUVA422P12BE: + case AV_PIX_FMT_YUVA422P16LE: + case AV_PIX_FMT_YUVA422P16BE: + case AV_PIX_FMT_YUV440P10LE: + case AV_PIX_FMT_YUV440P10BE: + case AV_PIX_FMT_YUV440P12LE: + case AV_PIX_FMT_YUV440P12BE: + case AV_PIX_FMT_YUV444P9LE: + case AV_PIX_FMT_YUV444P9BE: + case AV_PIX_FMT_YUV444P10LE: + case AV_PIX_FMT_YUV444P10BE: + case AV_PIX_FMT_YUV444P12LE: + case AV_PIX_FMT_YUV444P12BE: + case AV_PIX_FMT_YUV444P14LE: + case AV_PIX_FMT_YUV444P14BE: + case AV_PIX_FMT_YUV444P16LE: + case AV_PIX_FMT_YUV444P16BE: + case AV_PIX_FMT_YUVA444P9LE: + case AV_PIX_FMT_YUVA444P9BE: + case AV_PIX_FMT_YUVA444P10LE: + case AV_PIX_FMT_YUVA444P10BE: + case AV_PIX_FMT_YUVA444P12LE: + case AV_PIX_FMT_YUVA444P12BE: + case AV_PIX_FMT_YUVA444P16LE: + case AV_PIX_FMT_YUVA444P16BE: + case AV_PIX_FMT_GBRP9LE: + case AV_PIX_FMT_GBRP9BE: + case AV_PIX_FMT_GBRP10LE: + case AV_PIX_FMT_GBRP10BE: + case AV_PIX_FMT_GBRP12LE: + case AV_PIX_FMT_GBRP12BE: + case AV_PIX_FMT_GBRP14LE: + case AV_PIX_FMT_GBRP14BE: + case AV_PIX_FMT_GBRP16LE: + case AV_PIX_FMT_GBRP16BE: + case AV_PIX_FMT_GBRAP12LE: + case AV_PIX_FMT_GBRAP12BE: + case AV_PIX_FMT_GBRAP16LE: + case AV_PIX_FMT_GBRAP16BE: + w_align = 16; //FIXME assume 16 pixel per macroblock + h_align = 16 * 2; // interlaced needs 2 macroblocks height + break; + case AV_PIX_FMT_YUV411P: + case AV_PIX_FMT_YUVJ411P: + case AV_PIX_FMT_UYYVYY411: + w_align = 32; + h_align = 16 * 2; + break; + case AV_PIX_FMT_YUV410P: + if (s->codec_id == AV_CODEC_ID_SVQ1) { + w_align = 64; + h_align = 64; + } + break; + case AV_PIX_FMT_RGB555: + if (s->codec_id == AV_CODEC_ID_RPZA) { + w_align = 4; + h_align = 4; + } + if (s->codec_id == AV_CODEC_ID_INTERPLAY_VIDEO) { + w_align = 8; + h_align = 8; + } + break; + case AV_PIX_FMT_PAL8: + case AV_PIX_FMT_BGR8: + case AV_PIX_FMT_RGB8: + if (s->codec_id == AV_CODEC_ID_SMC || + s->codec_id == AV_CODEC_ID_CINEPAK) { + w_align = 4; + h_align = 4; + } + if (s->codec_id == AV_CODEC_ID_JV || + s->codec_id == AV_CODEC_ID_INTERPLAY_VIDEO) { + w_align = 8; + h_align = 8; + } + break; + case AV_PIX_FMT_BGR24: + if ((s->codec_id == AV_CODEC_ID_MSZH) || + (s->codec_id == AV_CODEC_ID_ZLIB)) { + w_align = 4; + h_align = 4; + } + break; + case AV_PIX_FMT_RGB24: + if (s->codec_id == AV_CODEC_ID_CINEPAK) { + w_align = 4; + h_align = 4; + } + break; + default: + break; + } + + if (s->codec_id == AV_CODEC_ID_IFF_ILBM) { + w_align = FFMAX(w_align, 8); + } + + *width = FFALIGN(*width, w_align); + *height = FFALIGN(*height, h_align); + if (s->codec_id == AV_CODEC_ID_H264 || s->lowres || + s->codec_id == AV_CODEC_ID_VP5 || s->codec_id == AV_CODEC_ID_VP6 || + s->codec_id == AV_CODEC_ID_VP6F || s->codec_id == AV_CODEC_ID_VP6A + ) { + // some of the optimized chroma MC reads one line too much + // which is also done in mpeg decoders with lowres > 0 + *height += 2; + + // H.264 uses edge emulation for out of frame motion vectors, for this + // it requires a temporary area large enough to hold a 21x21 block, + // increasing witdth ensure that the temporary area is large enough, + // the next rounded up width is 32 + *width = FFMAX(*width, 32); + } + + for (i = 0; i < 4; i++) + linesize_align[i] = STRIDE_ALIGN; +} + +void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->pix_fmt); + int chroma_shift = desc->log2_chroma_w; + int linesize_align[AV_NUM_DATA_POINTERS]; + int align; + + avcodec_align_dimensions2(s, width, height, linesize_align); + align = FFMAX(linesize_align[0], linesize_align[3]); + linesize_align[1] <<= chroma_shift; + linesize_align[2] <<= chroma_shift; + align = FFMAX3(align, linesize_align[1], linesize_align[2]); + *width = FFALIGN(*width, align); +} + +int avcodec_enum_to_chroma_pos(int *xpos, int *ypos, enum AVChromaLocation pos) +{ + if (pos <= AVCHROMA_LOC_UNSPECIFIED || pos >= AVCHROMA_LOC_NB) + return AVERROR(EINVAL); + pos--; + + *xpos = (pos&1) * 128; + *ypos = ((pos>>1)^(pos<4)) * 128; + + return 0; +} + +enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos) +{ + int pos, xout, yout; + + for (pos = AVCHROMA_LOC_UNSPECIFIED + 1; pos < AVCHROMA_LOC_NB; pos++) { + if (avcodec_enum_to_chroma_pos(&xout, &yout, pos) == 0 && xout == xpos && yout == ypos) + return pos; + } + return AVCHROMA_LOC_UNSPECIFIED; +} + +int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels, + enum AVSampleFormat sample_fmt, const uint8_t *buf, + int buf_size, int align) +{ + int ch, planar, needed_size, ret = 0; + + needed_size = av_samples_get_buffer_size(NULL, nb_channels, + frame->nb_samples, sample_fmt, + align); + if (buf_size < needed_size) + return AVERROR(EINVAL); + + planar = av_sample_fmt_is_planar(sample_fmt); + if (planar && nb_channels > AV_NUM_DATA_POINTERS) { + if (!(frame->extended_data = av_mallocz_array(nb_channels, + sizeof(*frame->extended_data)))) + return AVERROR(ENOMEM); + } else { + frame->extended_data = frame->data; + } + + if ((ret = av_samples_fill_arrays(frame->extended_data, &frame->linesize[0], + (uint8_t *)(intptr_t)buf, nb_channels, frame->nb_samples, + sample_fmt, align)) < 0) { + if (frame->extended_data != frame->data) + av_freep(&frame->extended_data); + return ret; + } + if (frame->extended_data != frame->data) { + for (ch = 0; ch < AV_NUM_DATA_POINTERS; ch++) + frame->data[ch] = frame->extended_data[ch]; + } + + return ret; +} + +void ff_color_frame(AVFrame *frame, const int c[4]) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int p, y, x; + + av_assert0(desc->flags & AV_PIX_FMT_FLAG_PLANAR); + + for (p = 0; pnb_components; p++) { + uint8_t *dst = frame->data[p]; + int is_chroma = p == 1 || p == 2; + int bytes = is_chroma ? AV_CEIL_RSHIFT(frame->width, desc->log2_chroma_w) : frame->width; + int height = is_chroma ? AV_CEIL_RSHIFT(frame->height, desc->log2_chroma_h) : frame->height; + for (y = 0; y < height; y++) { + if (desc->comp[0].depth >= 9) { + for (x = 0; xlinesize[p]; + } + } +} + +int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2), void *arg, int *ret, int count, int size) +{ + int i; + + for (i = 0; i < count; i++) { + int r = func(c, (char *)arg + i * size); + if (ret) + ret[i] = r; + } + emms_c(); + return 0; +} + +int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int jobnr, int threadnr), void *arg, int *ret, int count) +{ + int i; + + for (i = 0; i < count; i++) { + int r = func(c, arg, i, 0); + if (ret) + ret[i] = r; + } + emms_c(); + return 0; +} + +enum AVPixelFormat avpriv_find_pix_fmt(const PixelFormatTag *tags, + unsigned int fourcc) +{ + while (tags->pix_fmt >= 0) { + if (tags->fourcc == fourcc) + return tags->pix_fmt; + tags++; + } + return AV_PIX_FMT_NONE; +} + +#if FF_API_CODEC_GET_SET +MAKE_ACCESSORS(AVCodecContext, codec, AVRational, pkt_timebase) +MAKE_ACCESSORS(AVCodecContext, codec, const AVCodecDescriptor *, codec_descriptor) +MAKE_ACCESSORS(AVCodecContext, codec, int, lowres) +MAKE_ACCESSORS(AVCodecContext, codec, int, seek_preroll) +MAKE_ACCESSORS(AVCodecContext, codec, uint16_t*, chroma_intra_matrix) + +unsigned av_codec_get_codec_properties(const AVCodecContext *codec) +{ + return codec->properties; +} + +int av_codec_get_max_lowres(const AVCodec *codec) +{ + return codec->max_lowres; +} +#endif + +int avpriv_codec_get_cap_skip_frame_fill_param(const AVCodec *codec){ + return !!(codec->caps_internal & FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM); +} + +static int64_t get_bit_rate(AVCodecContext *ctx) +{ + int64_t bit_rate; + int bits_per_sample; + + switch (ctx->codec_type) { + case AVMEDIA_TYPE_VIDEO: + case AVMEDIA_TYPE_DATA: + case AVMEDIA_TYPE_SUBTITLE: + case AVMEDIA_TYPE_ATTACHMENT: + bit_rate = ctx->bit_rate; + break; + case AVMEDIA_TYPE_AUDIO: + bits_per_sample = av_get_bits_per_sample(ctx->codec_id); + bit_rate = bits_per_sample ? ctx->sample_rate * (int64_t)ctx->channels * bits_per_sample : ctx->bit_rate; + break; + default: + bit_rate = 0; + break; + } + return bit_rate; +} + + +static void ff_lock_avcodec(AVCodecContext *log_ctx, const AVCodec *codec) +{ + if (!(codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE) && codec->init) + ff_mutex_lock(&codec_mutex); +} + +static void ff_unlock_avcodec(const AVCodec *codec) +{ + if (!(codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE) && codec->init) + ff_mutex_unlock(&codec_mutex); +} + +int attribute_align_arg ff_codec_open2_recursive(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options) +{ + int ret = 0; + + ff_unlock_avcodec(codec); + + ret = avcodec_open2(avctx, codec, options); + + ff_lock_avcodec(avctx, codec); + return ret; +} + +int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options) +{ + int ret = 0; + int codec_init_ok = 0; + AVDictionary *tmp = NULL; + const AVPixFmtDescriptor *pixdesc; + + if (avcodec_is_open(avctx)) + return 0; + + if ((!codec && !avctx->codec)) { + av_log(avctx, AV_LOG_ERROR, "No codec provided to avcodec_open2()\n"); + return AVERROR(EINVAL); + } + if ((codec && avctx->codec && codec != avctx->codec)) { + av_log(avctx, AV_LOG_ERROR, "This AVCodecContext was allocated for %s, " + "but %s passed to avcodec_open2()\n", avctx->codec->name, codec->name); + return AVERROR(EINVAL); + } + if (!codec) + codec = avctx->codec; + + if (avctx->extradata_size < 0 || avctx->extradata_size >= FF_MAX_EXTRADATA_SIZE) + return AVERROR(EINVAL); + + if (options) + av_dict_copy(&tmp, *options, 0); + + ff_lock_avcodec(avctx, codec); + + avctx->internal = av_mallocz(sizeof(*avctx->internal)); + if (!avctx->internal) { + ret = AVERROR(ENOMEM); + goto end; + } + + avctx->internal->pool = av_mallocz(sizeof(*avctx->internal->pool)); + if (!avctx->internal->pool) { + ret = AVERROR(ENOMEM); + goto free_and_end; + } + + avctx->internal->to_free = av_frame_alloc(); + if (!avctx->internal->to_free) { + ret = AVERROR(ENOMEM); + goto free_and_end; + } + + avctx->internal->compat_decode_frame = av_frame_alloc(); + if (!avctx->internal->compat_decode_frame) { + ret = AVERROR(ENOMEM); + goto free_and_end; + } + + avctx->internal->buffer_frame = av_frame_alloc(); + if (!avctx->internal->buffer_frame) { + ret = AVERROR(ENOMEM); + goto free_and_end; + } + + avctx->internal->buffer_pkt = av_packet_alloc(); + if (!avctx->internal->buffer_pkt) { + ret = AVERROR(ENOMEM); + goto free_and_end; + } + + avctx->internal->ds.in_pkt = av_packet_alloc(); + if (!avctx->internal->ds.in_pkt) { + ret = AVERROR(ENOMEM); + goto free_and_end; + } + + avctx->internal->last_pkt_props = av_packet_alloc(); + if (!avctx->internal->last_pkt_props) { + ret = AVERROR(ENOMEM); + goto free_and_end; + } + + avctx->internal->skip_samples_multiplier = 1; + + if (codec->priv_data_size > 0) { + if (!avctx->priv_data) { + avctx->priv_data = av_mallocz(codec->priv_data_size); + if (!avctx->priv_data) { + ret = AVERROR(ENOMEM); + goto end; + } + if (codec->priv_class) { + *(const AVClass **)avctx->priv_data = codec->priv_class; + av_opt_set_defaults(avctx->priv_data); + } + } + if (codec->priv_class && (ret = av_opt_set_dict(avctx->priv_data, &tmp)) < 0) + goto free_and_end; + } else { + avctx->priv_data = NULL; + } + if ((ret = av_opt_set_dict(avctx, &tmp)) < 0) + goto free_and_end; + + if (avctx->codec_whitelist && av_match_list(codec->name, avctx->codec_whitelist, ',') <= 0) { + av_log(avctx, AV_LOG_ERROR, "Codec (%s) not on whitelist \'%s\'\n", codec->name, avctx->codec_whitelist); + ret = AVERROR(EINVAL); + goto free_and_end; + } + + // only call ff_set_dimensions() for non H.264/VP6F/DXV codecs so as not to overwrite previously setup dimensions + if (!(avctx->coded_width && avctx->coded_height && avctx->width && avctx->height && + (avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_VP6F || avctx->codec_id == AV_CODEC_ID_DXV))) { + if (avctx->coded_width && avctx->coded_height) + ret = ff_set_dimensions(avctx, avctx->coded_width, avctx->coded_height); + else if (avctx->width && avctx->height) + ret = ff_set_dimensions(avctx, avctx->width, avctx->height); + if (ret < 0) + goto free_and_end; + } + + if ((avctx->coded_width || avctx->coded_height || avctx->width || avctx->height) + && ( av_image_check_size2(avctx->coded_width, avctx->coded_height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0 + || av_image_check_size2(avctx->width, avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0)) { + av_log(avctx, AV_LOG_WARNING, "Ignoring invalid width/height values\n"); + ff_set_dimensions(avctx, 0, 0); + } + + if (avctx->width > 0 && avctx->height > 0) { + if (av_image_check_sar(avctx->width, avctx->height, + avctx->sample_aspect_ratio) < 0) { + av_log(avctx, AV_LOG_WARNING, "ignoring invalid SAR: %u/%u\n", + avctx->sample_aspect_ratio.num, + avctx->sample_aspect_ratio.den); + avctx->sample_aspect_ratio = (AVRational){ 0, 1 }; + } + } + + /* if the decoder init function was already called previously, + * free the already allocated subtitle_header before overwriting it */ + if (av_codec_is_decoder(codec)) + av_freep(&avctx->subtitle_header); + + if (avctx->channels > FF_SANE_NB_CHANNELS) { + av_log(avctx, AV_LOG_ERROR, "Too many channels: %d\n", avctx->channels); + ret = AVERROR(EINVAL); + goto free_and_end; + } + + avctx->codec = codec; + if ((avctx->codec_type == AVMEDIA_TYPE_UNKNOWN || avctx->codec_type == codec->type) && + avctx->codec_id == AV_CODEC_ID_NONE) { + avctx->codec_type = codec->type; + avctx->codec_id = codec->id; + } + if (avctx->codec_id != codec->id || (avctx->codec_type != codec->type + && avctx->codec_type != AVMEDIA_TYPE_ATTACHMENT)) { + av_log(avctx, AV_LOG_ERROR, "Codec type or id mismatches\n"); + ret = AVERROR(EINVAL); + goto free_and_end; + } + avctx->frame_number = 0; + avctx->codec_descriptor = avcodec_descriptor_get(avctx->codec_id); + + if ((avctx->codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) && + avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + const char *codec_string = av_codec_is_encoder(codec) ? "encoder" : "decoder"; + AVCodec *codec2; + av_log(avctx, AV_LOG_ERROR, + "The %s '%s' is experimental but experimental codecs are not enabled, " + "add '-strict %d' if you want to use it.\n", + codec_string, codec->name, FF_COMPLIANCE_EXPERIMENTAL); + codec2 = av_codec_is_encoder(codec) ? avcodec_find_encoder(codec->id) : avcodec_find_decoder(codec->id); + if (!(codec2->capabilities & AV_CODEC_CAP_EXPERIMENTAL)) + av_log(avctx, AV_LOG_ERROR, "Alternatively use the non experimental %s '%s'.\n", + codec_string, codec2->name); + ret = AVERROR_EXPERIMENTAL; + goto free_and_end; + } + + if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && + (!avctx->time_base.num || !avctx->time_base.den)) { + avctx->time_base.num = 1; + avctx->time_base.den = avctx->sample_rate; + } + + if (!HAVE_THREADS) + av_log(avctx, AV_LOG_WARNING, "Warning: not compiled with thread support, using thread emulation\n"); + + if (CONFIG_FRAME_THREAD_ENCODER && av_codec_is_encoder(avctx->codec)) { + ff_unlock_avcodec(codec); //we will instantiate a few encoders thus kick the counter to prevent false detection of a problem + ret = ff_frame_thread_encoder_init(avctx, options ? *options : NULL); + ff_lock_avcodec(avctx, codec); + if (ret < 0) + goto free_and_end; + } + + if (av_codec_is_decoder(avctx->codec)) { + ret = ff_decode_bsfs_init(avctx); + if (ret < 0) + goto free_and_end; + } + + if (HAVE_THREADS + && !(avctx->internal->frame_thread_encoder && (avctx->active_thread_type&FF_THREAD_FRAME))) { + ret = ff_thread_init(avctx); + if (ret < 0) { + goto free_and_end; + } + } + if (!HAVE_THREADS && !(codec->capabilities & AV_CODEC_CAP_AUTO_THREADS)) + avctx->thread_count = 1; + + if (avctx->codec->max_lowres < avctx->lowres || avctx->lowres < 0) { + av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n", + avctx->codec->max_lowres); + avctx->lowres = avctx->codec->max_lowres; + } + + if (av_codec_is_encoder(avctx->codec)) { + int i; +#if FF_API_CODED_FRAME +FF_DISABLE_DEPRECATION_WARNINGS + avctx->coded_frame = av_frame_alloc(); + if (!avctx->coded_frame) { + ret = AVERROR(ENOMEM); + goto free_and_end; + } +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + if (avctx->time_base.num <= 0 || avctx->time_base.den <= 0) { + av_log(avctx, AV_LOG_ERROR, "The encoder timebase is not set.\n"); + ret = AVERROR(EINVAL); + goto free_and_end; + } + + if (avctx->codec->sample_fmts) { + for (i = 0; avctx->codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++) { + if (avctx->sample_fmt == avctx->codec->sample_fmts[i]) + break; + if (avctx->channels == 1 && + av_get_planar_sample_fmt(avctx->sample_fmt) == + av_get_planar_sample_fmt(avctx->codec->sample_fmts[i])) { + avctx->sample_fmt = avctx->codec->sample_fmts[i]; + break; + } + } + if (avctx->codec->sample_fmts[i] == AV_SAMPLE_FMT_NONE) { + char buf[128]; + snprintf(buf, sizeof(buf), "%d", avctx->sample_fmt); + av_log(avctx, AV_LOG_ERROR, "Specified sample format %s is invalid or not supported\n", + (char *)av_x_if_null(av_get_sample_fmt_name(avctx->sample_fmt), buf)); + ret = AVERROR(EINVAL); + goto free_and_end; + } + } + if (avctx->codec->pix_fmts) { + for (i = 0; avctx->codec->pix_fmts[i] != AV_PIX_FMT_NONE; i++) + if (avctx->pix_fmt == avctx->codec->pix_fmts[i]) + break; + if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_NONE + && !((avctx->codec_id == AV_CODEC_ID_MJPEG || avctx->codec_id == AV_CODEC_ID_LJPEG) + && avctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) { + char buf[128]; + snprintf(buf, sizeof(buf), "%d", avctx->pix_fmt); + av_log(avctx, AV_LOG_ERROR, "Specified pixel format %s is invalid or not supported\n", + (char *)av_x_if_null(av_get_pix_fmt_name(avctx->pix_fmt), buf)); + ret = AVERROR(EINVAL); + goto free_and_end; + } + if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ420P || + avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ411P || + avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ422P || + avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ440P || + avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ444P) + avctx->color_range = AVCOL_RANGE_JPEG; + } + if (avctx->codec->supported_samplerates) { + for (i = 0; avctx->codec->supported_samplerates[i] != 0; i++) + if (avctx->sample_rate == avctx->codec->supported_samplerates[i]) + break; + if (avctx->codec->supported_samplerates[i] == 0) { + av_log(avctx, AV_LOG_ERROR, "Specified sample rate %d is not supported\n", + avctx->sample_rate); + ret = AVERROR(EINVAL); + goto free_and_end; + } + } + if (avctx->sample_rate < 0) { + av_log(avctx, AV_LOG_ERROR, "Specified sample rate %d is not supported\n", + avctx->sample_rate); + ret = AVERROR(EINVAL); + goto free_and_end; + } + if (avctx->codec->channel_layouts) { + if (!avctx->channel_layout) { + av_log(avctx, AV_LOG_WARNING, "Channel layout not specified\n"); + } else { + for (i = 0; avctx->codec->channel_layouts[i] != 0; i++) + if (avctx->channel_layout == avctx->codec->channel_layouts[i]) + break; + if (avctx->codec->channel_layouts[i] == 0) { + char buf[512]; + av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout); + av_log(avctx, AV_LOG_ERROR, "Specified channel layout '%s' is not supported\n", buf); + ret = AVERROR(EINVAL); + goto free_and_end; + } + } + } + if (avctx->channel_layout && avctx->channels) { + int channels = av_get_channel_layout_nb_channels(avctx->channel_layout); + if (channels != avctx->channels) { + char buf[512]; + av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout); + av_log(avctx, AV_LOG_ERROR, + "Channel layout '%s' with %d channels does not match number of specified channels %d\n", + buf, channels, avctx->channels); + ret = AVERROR(EINVAL); + goto free_and_end; + } + } else if (avctx->channel_layout) { + avctx->channels = av_get_channel_layout_nb_channels(avctx->channel_layout); + } + if (avctx->channels < 0) { + av_log(avctx, AV_LOG_ERROR, "Specified number of channels %d is not supported\n", + avctx->channels); + ret = AVERROR(EINVAL); + goto free_and_end; + } + if(avctx->codec_type == AVMEDIA_TYPE_VIDEO) { + pixdesc = av_pix_fmt_desc_get(avctx->pix_fmt); + if ( avctx->bits_per_raw_sample < 0 + || (avctx->bits_per_raw_sample > 8 && pixdesc->comp[0].depth <= 8)) { + av_log(avctx, AV_LOG_WARNING, "Specified bit depth %d not possible with the specified pixel formats depth %d\n", + avctx->bits_per_raw_sample, pixdesc->comp[0].depth); + avctx->bits_per_raw_sample = pixdesc->comp[0].depth; + } + if (avctx->width <= 0 || avctx->height <= 0) { + av_log(avctx, AV_LOG_ERROR, "dimensions not set\n"); + ret = AVERROR(EINVAL); + goto free_and_end; + } + } + if ( (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO) + && avctx->bit_rate>0 && avctx->bit_rate<1000) { + av_log(avctx, AV_LOG_WARNING, "Bitrate %"PRId64" is extremely low, maybe you mean %"PRId64"k\n", avctx->bit_rate, avctx->bit_rate); + } + + if (!avctx->rc_initial_buffer_occupancy) + avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size * 3LL / 4; + + if (avctx->ticks_per_frame && avctx->time_base.num && + avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) { + av_log(avctx, AV_LOG_ERROR, + "ticks_per_frame %d too large for the timebase %d/%d.", + avctx->ticks_per_frame, + avctx->time_base.num, + avctx->time_base.den); + goto free_and_end; + } + + if (avctx->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + if (frames_ctx->format != avctx->pix_fmt) { + av_log(avctx, AV_LOG_ERROR, + "Mismatching AVCodecContext.pix_fmt and AVHWFramesContext.format\n"); + ret = AVERROR(EINVAL); + goto free_and_end; + } + if (avctx->sw_pix_fmt != AV_PIX_FMT_NONE && + avctx->sw_pix_fmt != frames_ctx->sw_format) { + av_log(avctx, AV_LOG_ERROR, + "Mismatching AVCodecContext.sw_pix_fmt (%s) " + "and AVHWFramesContext.sw_format (%s)\n", + av_get_pix_fmt_name(avctx->sw_pix_fmt), + av_get_pix_fmt_name(frames_ctx->sw_format)); + ret = AVERROR(EINVAL); + goto free_and_end; + } + avctx->sw_pix_fmt = frames_ctx->sw_format; + } + } + + avctx->pts_correction_num_faulty_pts = + avctx->pts_correction_num_faulty_dts = 0; + avctx->pts_correction_last_pts = + avctx->pts_correction_last_dts = INT64_MIN; + + if ( !CONFIG_GRAY && avctx->flags & AV_CODEC_FLAG_GRAY + && avctx->codec_descriptor->type == AVMEDIA_TYPE_VIDEO) + av_log(avctx, AV_LOG_WARNING, + "gray decoding requested but not enabled at configuration time\n"); + + if ( avctx->codec->init && (!(avctx->active_thread_type&FF_THREAD_FRAME) + || avctx->internal->frame_thread_encoder)) { + ret = avctx->codec->init(avctx); + if (ret < 0) { + goto free_and_end; + } + codec_init_ok = 1; + } + + ret=0; + + if (av_codec_is_decoder(avctx->codec)) { + if (!avctx->bit_rate) + avctx->bit_rate = get_bit_rate(avctx); + /* validate channel layout from the decoder */ + if (avctx->channel_layout) { + int channels = av_get_channel_layout_nb_channels(avctx->channel_layout); + if (!avctx->channels) + avctx->channels = channels; + else if (channels != avctx->channels) { + char buf[512]; + av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout); + av_log(avctx, AV_LOG_WARNING, + "Channel layout '%s' with %d channels does not match specified number of channels %d: " + "ignoring specified channel layout\n", + buf, channels, avctx->channels); + avctx->channel_layout = 0; + } + } + if (avctx->channels && avctx->channels < 0 || + avctx->channels > FF_SANE_NB_CHANNELS) { + ret = AVERROR(EINVAL); + goto free_and_end; + } + if (avctx->bits_per_coded_sample < 0) { + ret = AVERROR(EINVAL); + goto free_and_end; + } + if (avctx->sub_charenc) { + if (avctx->codec_type != AVMEDIA_TYPE_SUBTITLE) { + av_log(avctx, AV_LOG_ERROR, "Character encoding is only " + "supported with subtitles codecs\n"); + ret = AVERROR(EINVAL); + goto free_and_end; + } else if (avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB) { + av_log(avctx, AV_LOG_WARNING, "Codec '%s' is bitmap-based, " + "subtitles character encoding will be ignored\n", + avctx->codec_descriptor->name); + avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_DO_NOTHING; + } else { + /* input character encoding is set for a text based subtitle + * codec at this point */ + if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_AUTOMATIC) + avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_PRE_DECODER; + + if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_PRE_DECODER) { +#if CONFIG_ICONV + iconv_t cd = iconv_open("UTF-8", avctx->sub_charenc); + if (cd == (iconv_t)-1) { + ret = AVERROR(errno); + av_log(avctx, AV_LOG_ERROR, "Unable to open iconv context " + "with input character encoding \"%s\"\n", avctx->sub_charenc); + goto free_and_end; + } + iconv_close(cd); +#else + av_log(avctx, AV_LOG_ERROR, "Character encoding subtitles " + "conversion needs a libavcodec built with iconv support " + "for this codec\n"); + ret = AVERROR(ENOSYS); + goto free_and_end; +#endif + } + } + } + +#if FF_API_AVCTX_TIMEBASE + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1})); +#endif + } + if (codec->priv_data_size > 0 && avctx->priv_data && codec->priv_class) { + av_assert0(*(const AVClass **)avctx->priv_data == codec->priv_class); + } + +end: + ff_unlock_avcodec(codec); + if (options) { + av_dict_free(options); + *options = tmp; + } + + return ret; +free_and_end: + if (avctx->codec && avctx->codec->close && + (codec_init_ok || + (avctx->codec->caps_internal & FF_CODEC_CAP_INIT_CLEANUP))) + avctx->codec->close(avctx); + + if (codec->priv_class && codec->priv_data_size) + av_opt_free(avctx->priv_data); + av_opt_free(avctx); + +#if FF_API_CODED_FRAME +FF_DISABLE_DEPRECATION_WARNINGS + av_frame_free(&avctx->coded_frame); +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + av_dict_free(&tmp); + av_freep(&avctx->priv_data); + av_freep(&avctx->subtitle_header); + if (avctx->internal) { + av_frame_free(&avctx->internal->to_free); + av_frame_free(&avctx->internal->compat_decode_frame); + av_frame_free(&avctx->internal->buffer_frame); + av_packet_free(&avctx->internal->buffer_pkt); + av_packet_free(&avctx->internal->last_pkt_props); + + av_packet_free(&avctx->internal->ds.in_pkt); + ff_decode_bsfs_uninit(avctx); + + av_freep(&avctx->internal->pool); + } + av_freep(&avctx->internal); + avctx->codec = NULL; + goto end; +} + +void avsubtitle_free(AVSubtitle *sub) +{ + int i; + + for (i = 0; i < sub->num_rects; i++) { + av_freep(&sub->rects[i]->data[0]); + av_freep(&sub->rects[i]->data[1]); + av_freep(&sub->rects[i]->data[2]); + av_freep(&sub->rects[i]->data[3]); + av_freep(&sub->rects[i]->text); + av_freep(&sub->rects[i]->ass); + av_freep(&sub->rects[i]); + } + + av_freep(&sub->rects); + + memset(sub, 0, sizeof(*sub)); +} + +av_cold int avcodec_close(AVCodecContext *avctx) +{ + int i; + + if (!avctx) + return 0; + + if (avcodec_is_open(avctx)) { + FramePool *pool = avctx->internal->pool; + if (CONFIG_FRAME_THREAD_ENCODER && + avctx->internal->frame_thread_encoder && avctx->thread_count > 1) { + ff_frame_thread_encoder_free(avctx); + } + if (HAVE_THREADS && avctx->internal->thread_ctx) + ff_thread_free(avctx); + if (avctx->codec && avctx->codec->close) + avctx->codec->close(avctx); + avctx->internal->byte_buffer_size = 0; + av_freep(&avctx->internal->byte_buffer); + av_frame_free(&avctx->internal->to_free); + av_frame_free(&avctx->internal->compat_decode_frame); + av_frame_free(&avctx->internal->buffer_frame); + av_packet_free(&avctx->internal->buffer_pkt); + av_packet_free(&avctx->internal->last_pkt_props); + + av_packet_free(&avctx->internal->ds.in_pkt); + + for (i = 0; i < FF_ARRAY_ELEMS(pool->pools); i++) + av_buffer_pool_uninit(&pool->pools[i]); + av_freep(&avctx->internal->pool); + + if (avctx->hwaccel && avctx->hwaccel->uninit) + avctx->hwaccel->uninit(avctx); + av_freep(&avctx->internal->hwaccel_priv_data); + + ff_decode_bsfs_uninit(avctx); + + av_freep(&avctx->internal); + } + + for (i = 0; i < avctx->nb_coded_side_data; i++) + av_freep(&avctx->coded_side_data[i].data); + av_freep(&avctx->coded_side_data); + avctx->nb_coded_side_data = 0; + + av_buffer_unref(&avctx->hw_frames_ctx); + av_buffer_unref(&avctx->hw_device_ctx); + + if (avctx->priv_data && avctx->codec && avctx->codec->priv_class) + av_opt_free(avctx->priv_data); + av_opt_free(avctx); + av_freep(&avctx->priv_data); + if (av_codec_is_encoder(avctx->codec)) { + av_freep(&avctx->extradata); +#if FF_API_CODED_FRAME +FF_DISABLE_DEPRECATION_WARNINGS + av_frame_free(&avctx->coded_frame); +FF_ENABLE_DEPRECATION_WARNINGS +#endif + } + avctx->codec = NULL; + avctx->active_thread_type = 0; + + return 0; +} + +const char *avcodec_get_name(enum AVCodecID id) +{ + const AVCodecDescriptor *cd; + AVCodec *codec; + + if (id == AV_CODEC_ID_NONE) + return "none"; + cd = avcodec_descriptor_get(id); + if (cd) + return cd->name; + av_log(NULL, AV_LOG_WARNING, "Codec 0x%x is not in the full list.\n", id); + codec = avcodec_find_decoder(id); + if (codec) + return codec->name; + codec = avcodec_find_encoder(id); + if (codec) + return codec->name; + return "unknown_codec"; +} + +size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_tag) +{ + int i, len, ret = 0; + +#define TAG_PRINT(x) \ + (((x) >= '0' && (x) <= '9') || \ + ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z') || \ + ((x) == '.' || (x) == ' ' || (x) == '-' || (x) == '_')) + + for (i = 0; i < 4; i++) { + len = snprintf(buf, buf_size, + TAG_PRINT(codec_tag & 0xFF) ? "%c" : "[%d]", codec_tag & 0xFF); + buf += len; + buf_size = buf_size > len ? buf_size - len : 0; + ret += len; + codec_tag >>= 8; + } + return ret; +} + +void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode) +{ + const char *codec_type; + const char *codec_name; + const char *profile = NULL; + int64_t bitrate; + int new_line = 0; + AVRational display_aspect_ratio; + const char *separator = enc->dump_separator ? (const char *)enc->dump_separator : ", "; + + if (!buf || buf_size <= 0) + return; + codec_type = av_get_media_type_string(enc->codec_type); + codec_name = avcodec_get_name(enc->codec_id); + profile = avcodec_profile_name(enc->codec_id, enc->profile); + + snprintf(buf, buf_size, "%s: %s", codec_type ? codec_type : "unknown", + codec_name); + buf[0] ^= 'a' ^ 'A'; /* first letter in uppercase */ + + if (enc->codec && strcmp(enc->codec->name, codec_name)) + snprintf(buf + strlen(buf), buf_size - strlen(buf), " (%s)", enc->codec->name); + + if (profile) + snprintf(buf + strlen(buf), buf_size - strlen(buf), " (%s)", profile); + if ( enc->codec_type == AVMEDIA_TYPE_VIDEO + && av_log_get_level() >= AV_LOG_VERBOSE + && enc->refs) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", %d reference frame%s", + enc->refs, enc->refs > 1 ? "s" : ""); + + if (enc->codec_tag) + snprintf(buf + strlen(buf), buf_size - strlen(buf), " (%s / 0x%04X)", + av_fourcc2str(enc->codec_tag), enc->codec_tag); + + switch (enc->codec_type) { + case AVMEDIA_TYPE_VIDEO: + { + char detail[256] = "("; + + av_strlcat(buf, separator, buf_size); + + snprintf(buf + strlen(buf), buf_size - strlen(buf), + "%s", enc->pix_fmt == AV_PIX_FMT_NONE ? "none" : + av_get_pix_fmt_name(enc->pix_fmt)); + if (enc->bits_per_raw_sample && enc->pix_fmt != AV_PIX_FMT_NONE && + enc->bits_per_raw_sample < av_pix_fmt_desc_get(enc->pix_fmt)->comp[0].depth) + av_strlcatf(detail, sizeof(detail), "%d bpc, ", enc->bits_per_raw_sample); + if (enc->color_range != AVCOL_RANGE_UNSPECIFIED) + av_strlcatf(detail, sizeof(detail), "%s, ", + av_color_range_name(enc->color_range)); + + if (enc->colorspace != AVCOL_SPC_UNSPECIFIED || + enc->color_primaries != AVCOL_PRI_UNSPECIFIED || + enc->color_trc != AVCOL_TRC_UNSPECIFIED) { + if (enc->colorspace != (int)enc->color_primaries || + enc->colorspace != (int)enc->color_trc) { + new_line = 1; + av_strlcatf(detail, sizeof(detail), "%s/%s/%s, ", + av_color_space_name(enc->colorspace), + av_color_primaries_name(enc->color_primaries), + av_color_transfer_name(enc->color_trc)); + } else + av_strlcatf(detail, sizeof(detail), "%s, ", + av_get_colorspace_name(enc->colorspace)); + } + + if (enc->field_order != AV_FIELD_UNKNOWN) { + const char *field_order = "progressive"; + if (enc->field_order == AV_FIELD_TT) + field_order = "top first"; + else if (enc->field_order == AV_FIELD_BB) + field_order = "bottom first"; + else if (enc->field_order == AV_FIELD_TB) + field_order = "top coded first (swapped)"; + else if (enc->field_order == AV_FIELD_BT) + field_order = "bottom coded first (swapped)"; + + av_strlcatf(detail, sizeof(detail), "%s, ", field_order); + } + + if (av_log_get_level() >= AV_LOG_VERBOSE && + enc->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) + av_strlcatf(detail, sizeof(detail), "%s, ", + av_chroma_location_name(enc->chroma_sample_location)); + + if (strlen(detail) > 1) { + detail[strlen(detail) - 2] = 0; + av_strlcatf(buf, buf_size, "%s)", detail); + } + } + + if (enc->width) { + av_strlcat(buf, new_line ? separator : ", ", buf_size); + + snprintf(buf + strlen(buf), buf_size - strlen(buf), + "%dx%d", + enc->width, enc->height); + + if (av_log_get_level() >= AV_LOG_VERBOSE && + (enc->width != enc->coded_width || + enc->height != enc->coded_height)) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + " (%dx%d)", enc->coded_width, enc->coded_height); + + if (enc->sample_aspect_ratio.num) { + av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den, + enc->width * (int64_t)enc->sample_aspect_ratio.num, + enc->height * (int64_t)enc->sample_aspect_ratio.den, + 1024 * 1024); + snprintf(buf + strlen(buf), buf_size - strlen(buf), + " [SAR %d:%d DAR %d:%d]", + enc->sample_aspect_ratio.num, enc->sample_aspect_ratio.den, + display_aspect_ratio.num, display_aspect_ratio.den); + } + if (av_log_get_level() >= AV_LOG_DEBUG) { + int g = av_gcd(enc->time_base.num, enc->time_base.den); + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", %d/%d", + enc->time_base.num / g, enc->time_base.den / g); + } + } + if (encode) { + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", q=%d-%d", enc->qmin, enc->qmax); + } else { + if (enc->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", Closed Captions"); + if (enc->properties & FF_CODEC_PROPERTY_LOSSLESS) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", lossless"); + } + break; + case AVMEDIA_TYPE_AUDIO: + av_strlcat(buf, separator, buf_size); + + if (enc->sample_rate) { + snprintf(buf + strlen(buf), buf_size - strlen(buf), + "%d Hz, ", enc->sample_rate); + } + av_get_channel_layout_string(buf + strlen(buf), buf_size - strlen(buf), enc->channels, enc->channel_layout); + if (enc->sample_fmt != AV_SAMPLE_FMT_NONE) { + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", %s", av_get_sample_fmt_name(enc->sample_fmt)); + } + if ( enc->bits_per_raw_sample > 0 + && enc->bits_per_raw_sample != av_get_bytes_per_sample(enc->sample_fmt) * 8) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + " (%d bit)", enc->bits_per_raw_sample); + if (av_log_get_level() >= AV_LOG_VERBOSE) { + if (enc->initial_padding) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", delay %d", enc->initial_padding); + if (enc->trailing_padding) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", padding %d", enc->trailing_padding); + } + break; + case AVMEDIA_TYPE_DATA: + if (av_log_get_level() >= AV_LOG_DEBUG) { + int g = av_gcd(enc->time_base.num, enc->time_base.den); + if (g) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", %d/%d", + enc->time_base.num / g, enc->time_base.den / g); + } + break; + case AVMEDIA_TYPE_SUBTITLE: + if (enc->width) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", %dx%d", enc->width, enc->height); + break; + default: + return; + } + if (encode) { + if (enc->flags & AV_CODEC_FLAG_PASS1) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", pass 1"); + if (enc->flags & AV_CODEC_FLAG_PASS2) + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", pass 2"); + } + bitrate = get_bit_rate(enc); + if (bitrate != 0) { + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", %"PRId64" kb/s", bitrate / 1000); + } else if (enc->rc_max_rate > 0) { + snprintf(buf + strlen(buf), buf_size - strlen(buf), + ", max. %"PRId64" kb/s", enc->rc_max_rate / 1000); + } +} + +const char *av_get_profile_name(const AVCodec *codec, int profile) +{ + const AVProfile *p; + if (profile == FF_PROFILE_UNKNOWN || !codec->profiles) + return NULL; + + for (p = codec->profiles; p->profile != FF_PROFILE_UNKNOWN; p++) + if (p->profile == profile) + return p->name; + + return NULL; +} + +const char *avcodec_profile_name(enum AVCodecID codec_id, int profile) +{ + const AVCodecDescriptor *desc = avcodec_descriptor_get(codec_id); + const AVProfile *p; + + if (profile == FF_PROFILE_UNKNOWN || !desc || !desc->profiles) + return NULL; + + for (p = desc->profiles; p->profile != FF_PROFILE_UNKNOWN; p++) + if (p->profile == profile) + return p->name; + + return NULL; +} + +unsigned avcodec_version(void) +{ + av_assert0(AV_CODEC_ID_PCM_S8_PLANAR==65563); + av_assert0(AV_CODEC_ID_ADPCM_G722==69660); + av_assert0(AV_CODEC_ID_SRT==94216); + av_assert0(LIBAVCODEC_VERSION_MICRO >= 100); + + return LIBAVCODEC_VERSION_INT; +} + +const char *avcodec_configuration(void) +{ + return FFMPEG_CONFIGURATION; +} + +const char *avcodec_license(void) +{ +#define LICENSE_PREFIX "libavcodec license: " + return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; +} + +int av_get_exact_bits_per_sample(enum AVCodecID codec_id) +{ + switch (codec_id) { + case AV_CODEC_ID_8SVX_EXP: + case AV_CODEC_ID_8SVX_FIB: + case AV_CODEC_ID_ADPCM_CT: + case AV_CODEC_ID_ADPCM_IMA_APC: + case AV_CODEC_ID_ADPCM_IMA_EA_SEAD: + case AV_CODEC_ID_ADPCM_IMA_OKI: + case AV_CODEC_ID_ADPCM_IMA_WS: + case AV_CODEC_ID_ADPCM_G722: + case AV_CODEC_ID_ADPCM_YAMAHA: + case AV_CODEC_ID_ADPCM_AICA: + return 4; + case AV_CODEC_ID_DSD_LSBF: + case AV_CODEC_ID_DSD_MSBF: + case AV_CODEC_ID_DSD_LSBF_PLANAR: + case AV_CODEC_ID_DSD_MSBF_PLANAR: + case AV_CODEC_ID_PCM_ALAW: + case AV_CODEC_ID_PCM_MULAW: + case AV_CODEC_ID_PCM_VIDC: + case AV_CODEC_ID_PCM_S8: + case AV_CODEC_ID_PCM_S8_PLANAR: + case AV_CODEC_ID_PCM_U8: + case AV_CODEC_ID_PCM_ZORK: + case AV_CODEC_ID_SDX2_DPCM: + return 8; + case AV_CODEC_ID_PCM_S16BE: + case AV_CODEC_ID_PCM_S16BE_PLANAR: + case AV_CODEC_ID_PCM_S16LE: + case AV_CODEC_ID_PCM_S16LE_PLANAR: + case AV_CODEC_ID_PCM_U16BE: + case AV_CODEC_ID_PCM_U16LE: + return 16; + case AV_CODEC_ID_PCM_S24DAUD: + case AV_CODEC_ID_PCM_S24BE: + case AV_CODEC_ID_PCM_S24LE: + case AV_CODEC_ID_PCM_S24LE_PLANAR: + case AV_CODEC_ID_PCM_U24BE: + case AV_CODEC_ID_PCM_U24LE: + return 24; + case AV_CODEC_ID_PCM_S32BE: + case AV_CODEC_ID_PCM_S32LE: + case AV_CODEC_ID_PCM_S32LE_PLANAR: + case AV_CODEC_ID_PCM_U32BE: + case AV_CODEC_ID_PCM_U32LE: + case AV_CODEC_ID_PCM_F32BE: + case AV_CODEC_ID_PCM_F32LE: + case AV_CODEC_ID_PCM_F24LE: + case AV_CODEC_ID_PCM_F16LE: + return 32; + case AV_CODEC_ID_PCM_F64BE: + case AV_CODEC_ID_PCM_F64LE: + case AV_CODEC_ID_PCM_S64BE: + case AV_CODEC_ID_PCM_S64LE: + return 64; + default: + return 0; + } +} + +enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be) +{ + static const enum AVCodecID map[AV_SAMPLE_FMT_NB][2] = { + [AV_SAMPLE_FMT_U8 ] = { AV_CODEC_ID_PCM_U8, AV_CODEC_ID_PCM_U8 }, + [AV_SAMPLE_FMT_S16 ] = { AV_CODEC_ID_PCM_S16LE, AV_CODEC_ID_PCM_S16BE }, + [AV_SAMPLE_FMT_S32 ] = { AV_CODEC_ID_PCM_S32LE, AV_CODEC_ID_PCM_S32BE }, + [AV_SAMPLE_FMT_FLT ] = { AV_CODEC_ID_PCM_F32LE, AV_CODEC_ID_PCM_F32BE }, + [AV_SAMPLE_FMT_DBL ] = { AV_CODEC_ID_PCM_F64LE, AV_CODEC_ID_PCM_F64BE }, + [AV_SAMPLE_FMT_U8P ] = { AV_CODEC_ID_PCM_U8, AV_CODEC_ID_PCM_U8 }, + [AV_SAMPLE_FMT_S16P] = { AV_CODEC_ID_PCM_S16LE, AV_CODEC_ID_PCM_S16BE }, + [AV_SAMPLE_FMT_S32P] = { AV_CODEC_ID_PCM_S32LE, AV_CODEC_ID_PCM_S32BE }, + [AV_SAMPLE_FMT_S64P] = { AV_CODEC_ID_PCM_S64LE, AV_CODEC_ID_PCM_S64BE }, + [AV_SAMPLE_FMT_FLTP] = { AV_CODEC_ID_PCM_F32LE, AV_CODEC_ID_PCM_F32BE }, + [AV_SAMPLE_FMT_DBLP] = { AV_CODEC_ID_PCM_F64LE, AV_CODEC_ID_PCM_F64BE }, + }; + if (fmt < 0 || fmt >= AV_SAMPLE_FMT_NB) + return AV_CODEC_ID_NONE; + if (be < 0 || be > 1) + be = AV_NE(1, 0); + return map[fmt][be]; +} + +int av_get_bits_per_sample(enum AVCodecID codec_id) +{ + switch (codec_id) { + case AV_CODEC_ID_ADPCM_SBPRO_2: + return 2; + case AV_CODEC_ID_ADPCM_SBPRO_3: + return 3; + case AV_CODEC_ID_ADPCM_SBPRO_4: + case AV_CODEC_ID_ADPCM_IMA_WAV: + case AV_CODEC_ID_ADPCM_IMA_QT: + case AV_CODEC_ID_ADPCM_SWF: + case AV_CODEC_ID_ADPCM_MS: + return 4; + default: + return av_get_exact_bits_per_sample(codec_id); + } +} + +static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, + uint32_t tag, int bits_per_coded_sample, int64_t bitrate, + uint8_t * extradata, int frame_size, int frame_bytes) +{ + int bps = av_get_exact_bits_per_sample(id); + int framecount = (ba > 0 && frame_bytes / ba > 0) ? frame_bytes / ba : 1; + + /* codecs with an exact constant bits per sample */ + if (bps > 0 && ch > 0 && frame_bytes > 0 && ch < 32768 && bps < 32768) + return (frame_bytes * 8LL) / (bps * ch); + bps = bits_per_coded_sample; + + /* codecs with a fixed packet duration */ + switch (id) { + case AV_CODEC_ID_ADPCM_ADX: return 32; + case AV_CODEC_ID_ADPCM_IMA_QT: return 64; + case AV_CODEC_ID_ADPCM_EA_XAS: return 128; + case AV_CODEC_ID_AMR_NB: + case AV_CODEC_ID_EVRC: + case AV_CODEC_ID_GSM: + case AV_CODEC_ID_QCELP: + case AV_CODEC_ID_RA_288: return 160; + case AV_CODEC_ID_AMR_WB: + case AV_CODEC_ID_GSM_MS: return 320; + case AV_CODEC_ID_MP1: return 384; + case AV_CODEC_ID_ATRAC1: return 512; + case AV_CODEC_ID_ATRAC9: + case AV_CODEC_ID_ATRAC3: return 1024 * framecount; + case AV_CODEC_ID_ATRAC3P: return 2048; + case AV_CODEC_ID_MP2: + case AV_CODEC_ID_MUSEPACK7: return 1152; + case AV_CODEC_ID_AC3: return 1536; + } + + if (sr > 0) { + /* calc from sample rate */ + if (id == AV_CODEC_ID_TTA) + return 256 * sr / 245; + else if (id == AV_CODEC_ID_DST) + return 588 * sr / 44100; + + if (ch > 0) { + /* calc from sample rate and channels */ + if (id == AV_CODEC_ID_BINKAUDIO_DCT) + return (480 << (sr / 22050)) / ch; + } + + if (id == AV_CODEC_ID_MP3) + return sr <= 24000 ? 576 : 1152; + } + + if (ba > 0) { + /* calc from block_align */ + if (id == AV_CODEC_ID_SIPR) { + switch (ba) { + case 20: return 160; + case 19: return 144; + case 29: return 288; + case 37: return 480; + } + } else if (id == AV_CODEC_ID_ILBC) { + switch (ba) { + case 38: return 160; + case 50: return 240; + } + } + } + + if (frame_bytes > 0) { + /* calc from frame_bytes only */ + if (id == AV_CODEC_ID_TRUESPEECH) + return 240 * (frame_bytes / 32); + if (id == AV_CODEC_ID_NELLYMOSER) + return 256 * (frame_bytes / 64); + if (id == AV_CODEC_ID_RA_144) + return 160 * (frame_bytes / 20); + + if (bps > 0) { + /* calc from frame_bytes and bits_per_coded_sample */ + if (id == AV_CODEC_ID_ADPCM_G726 || id == AV_CODEC_ID_ADPCM_G726LE) + return frame_bytes * 8 / bps; + } + + if (ch > 0 && ch < INT_MAX/16) { + /* calc from frame_bytes and channels */ + switch (id) { + case AV_CODEC_ID_ADPCM_AFC: + return frame_bytes / (9 * ch) * 16; + case AV_CODEC_ID_ADPCM_PSX: + case AV_CODEC_ID_ADPCM_DTK: + return frame_bytes / (16 * ch) * 28; + case AV_CODEC_ID_ADPCM_4XM: + case AV_CODEC_ID_ADPCM_IMA_DAT4: + case AV_CODEC_ID_ADPCM_IMA_ISS: + return (frame_bytes - 4 * ch) * 2 / ch; + case AV_CODEC_ID_ADPCM_IMA_SMJPEG: + return (frame_bytes - 4) * 2 / ch; + case AV_CODEC_ID_ADPCM_IMA_AMV: + return (frame_bytes - 8) * 2 / ch; + case AV_CODEC_ID_ADPCM_THP: + case AV_CODEC_ID_ADPCM_THP_LE: + if (extradata) + return frame_bytes * 14 / (8 * ch); + break; + case AV_CODEC_ID_ADPCM_XA: + return (frame_bytes / 128) * 224 / ch; + case AV_CODEC_ID_INTERPLAY_DPCM: + return (frame_bytes - 6 - ch) / ch; + case AV_CODEC_ID_ROQ_DPCM: + return (frame_bytes - 8) / ch; + case AV_CODEC_ID_XAN_DPCM: + return (frame_bytes - 2 * ch) / ch; + case AV_CODEC_ID_MACE3: + return 3 * frame_bytes / ch; + case AV_CODEC_ID_MACE6: + return 6 * frame_bytes / ch; + case AV_CODEC_ID_PCM_LXF: + return 2 * (frame_bytes / (5 * ch)); + case AV_CODEC_ID_IAC: + case AV_CODEC_ID_IMC: + return 4 * frame_bytes / ch; + } + + if (tag) { + /* calc from frame_bytes, channels, and codec_tag */ + if (id == AV_CODEC_ID_SOL_DPCM) { + if (tag == 3) + return frame_bytes / ch; + else + return frame_bytes * 2 / ch; + } + } + + if (ba > 0) { + /* calc from frame_bytes, channels, and block_align */ + int blocks = frame_bytes / ba; + switch (id) { + case AV_CODEC_ID_ADPCM_IMA_WAV: + if (bps < 2 || bps > 5) + return 0; + return blocks * (1 + (ba - 4 * ch) / (bps * ch) * 8); + case AV_CODEC_ID_ADPCM_IMA_DK3: + return blocks * (((ba - 16) * 2 / 3 * 4) / ch); + case AV_CODEC_ID_ADPCM_IMA_DK4: + return blocks * (1 + (ba - 4 * ch) * 2 / ch); + case AV_CODEC_ID_ADPCM_IMA_RAD: + return blocks * ((ba - 4 * ch) * 2 / ch); + case AV_CODEC_ID_ADPCM_MS: + return blocks * (2 + (ba - 7 * ch) * 2 / ch); + case AV_CODEC_ID_ADPCM_MTAF: + return blocks * (ba - 16) * 2 / ch; + } + } + + if (bps > 0) { + /* calc from frame_bytes, channels, and bits_per_coded_sample */ + switch (id) { + case AV_CODEC_ID_PCM_DVD: + if(bps<4 || frame_bytes<3) + return 0; + return 2 * ((frame_bytes - 3) / ((bps * 2 / 8) * ch)); + case AV_CODEC_ID_PCM_BLURAY: + if(bps<4 || frame_bytes<4) + return 0; + return (frame_bytes - 4) / ((FFALIGN(ch, 2) * bps) / 8); + case AV_CODEC_ID_S302M: + return 2 * (frame_bytes / ((bps + 4) / 4)) / ch; + } + } + } + } + + /* Fall back on using frame_size */ + if (frame_size > 1 && frame_bytes) + return frame_size; + + //For WMA we currently have no other means to calculate duration thus we + //do it here by assuming CBR, which is true for all known cases. + if (bitrate > 0 && frame_bytes > 0 && sr > 0 && ba > 1) { + if (id == AV_CODEC_ID_WMAV1 || id == AV_CODEC_ID_WMAV2) + return (frame_bytes * 8LL * sr) / bitrate; + } + + return 0; +} + +int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) +{ + return get_audio_frame_duration(avctx->codec_id, avctx->sample_rate, + avctx->channels, avctx->block_align, + avctx->codec_tag, avctx->bits_per_coded_sample, + avctx->bit_rate, avctx->extradata, avctx->frame_size, + frame_bytes); +} + +int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes) +{ + return get_audio_frame_duration(par->codec_id, par->sample_rate, + par->channels, par->block_align, + par->codec_tag, par->bits_per_coded_sample, + par->bit_rate, par->extradata, par->frame_size, + frame_bytes); +} + +#if !HAVE_THREADS +int ff_thread_init(AVCodecContext *s) +{ + return -1; +} + +#endif + +unsigned int av_xiphlacing(unsigned char *s, unsigned int v) +{ + unsigned int n = 0; + + while (v >= 0xff) { + *s++ = 0xff; + v -= 0xff; + n++; + } + *s = v; + n++; + return n; +} + +int ff_match_2uint16(const uint16_t(*tab)[2], int size, int a, int b) +{ + int i; + for (i = 0; i < size && !(tab[i][0] == a && tab[i][1] == b); i++) ; + return i; +} + +const AVCodecHWConfig *avcodec_get_hw_config(const AVCodec *codec, int index) +{ + int i; + if (!codec->hw_configs || index < 0) + return NULL; + for (i = 0; i <= index; i++) + if (!codec->hw_configs[i]) + return NULL; + return &codec->hw_configs[index]->public; +} + +#if FF_API_USER_VISIBLE_AVHWACCEL +AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel) +{ + return NULL; +} + +void av_register_hwaccel(AVHWAccel *hwaccel) +{ +} +#endif + +#if FF_API_LOCKMGR +int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)) +{ + return 0; +} +#endif + +unsigned int avpriv_toupper4(unsigned int x) +{ + return av_toupper(x & 0xFF) + + (av_toupper((x >> 8) & 0xFF) << 8) + + (av_toupper((x >> 16) & 0xFF) << 16) + +((unsigned)av_toupper((x >> 24) & 0xFF) << 24); +} + +int ff_thread_ref_frame(ThreadFrame *dst, ThreadFrame *src) +{ + int ret; + + dst->owner[0] = src->owner[0]; + dst->owner[1] = src->owner[1]; + + ret = av_frame_ref(dst->f, src->f); + if (ret < 0) + return ret; + + av_assert0(!dst->progress); + + if (src->progress && + !(dst->progress = av_buffer_ref(src->progress))) { + ff_thread_release_buffer(dst->owner[0], dst); + return AVERROR(ENOMEM); + } + + return 0; +} + +#if !HAVE_THREADS + +enum AVPixelFormat ff_thread_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) +{ + return ff_get_format(avctx, fmt); +} + +int ff_thread_get_buffer(AVCodecContext *avctx, ThreadFrame *f, int flags) +{ + f->owner[0] = f->owner[1] = avctx; + return ff_get_buffer(avctx, f->f, flags); +} + +void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f) +{ + if (f->f) + av_frame_unref(f->f); +} + +void ff_thread_finish_setup(AVCodecContext *avctx) +{ +} + +void ff_thread_report_progress(ThreadFrame *f, int progress, int field) +{ +} + +void ff_thread_await_progress(ThreadFrame *f, int progress, int field) +{ +} + +int ff_thread_can_start_frame(AVCodecContext *avctx) +{ + return 1; +} + +int ff_alloc_entries(AVCodecContext *avctx, int count) +{ + return 0; +} + +void ff_reset_entries(AVCodecContext *avctx) +{ +} + +void ff_thread_await_progress2(AVCodecContext *avctx, int field, int thread, int shift) +{ +} + +void ff_thread_report_progress2(AVCodecContext *avctx, int field, int thread, int n) +{ +} + +#endif + +int avcodec_is_open(AVCodecContext *s) +{ + return !!s->internal; +} + +int avpriv_bprint_to_extradata(AVCodecContext *avctx, struct AVBPrint *buf) +{ + int ret; + char *str; + + ret = av_bprint_finalize(buf, &str); + if (ret < 0) + return ret; + if (!av_bprint_is_complete(buf)) { + av_free(str); + return AVERROR(ENOMEM); + } + + avctx->extradata = str; + /* Note: the string is NUL terminated (so extradata can be read as a + * string), but the ending character is not accounted in the size (in + * binary formats you are likely not supposed to mux that character). When + * extradata is copied, it is also padded with AV_INPUT_BUFFER_PADDING_SIZE + * zeros. */ + avctx->extradata_size = buf->len; + return 0; +} + +const uint8_t *avpriv_find_start_code(const uint8_t *av_restrict p, + const uint8_t *end, + uint32_t *av_restrict state) +{ + int i; + + av_assert0(p <= end); + if (p >= end) + return end; + + for (i = 0; i < 3; i++) { + uint32_t tmp = *state << 8; + *state = tmp + *(p++); + if (tmp == 0x100 || p == end) + return p; + } + + while (p < end) { + if (p[-1] > 1 ) p += 3; + else if (p[-2] ) p += 2; + else if (p[-3]|(p[-1]-1)) p++; + else { + p++; + break; + } + } + + p = FFMIN(p, end) - 4; + *state = AV_RB32(p); + + return p + 4; +} + +AVCPBProperties *av_cpb_properties_alloc(size_t *size) +{ + AVCPBProperties *props = av_mallocz(sizeof(AVCPBProperties)); + if (!props) + return NULL; + + if (size) + *size = sizeof(*props); + + props->vbv_delay = UINT64_MAX; + + return props; +} + +AVCPBProperties *ff_add_cpb_side_data(AVCodecContext *avctx) +{ + AVPacketSideData *tmp; + AVCPBProperties *props; + size_t size; + + props = av_cpb_properties_alloc(&size); + if (!props) + return NULL; + + tmp = av_realloc_array(avctx->coded_side_data, avctx->nb_coded_side_data + 1, sizeof(*tmp)); + if (!tmp) { + av_freep(&props); + return NULL; + } + + avctx->coded_side_data = tmp; + avctx->nb_coded_side_data++; + + avctx->coded_side_data[avctx->nb_coded_side_data - 1].type = AV_PKT_DATA_CPB_PROPERTIES; + avctx->coded_side_data[avctx->nb_coded_side_data - 1].data = (uint8_t*)props; + avctx->coded_side_data[avctx->nb_coded_side_data - 1].size = size; + + return props; +} + +static void codec_parameters_reset(AVCodecParameters *par) +{ + av_freep(&par->extradata); + + memset(par, 0, sizeof(*par)); + + par->codec_type = AVMEDIA_TYPE_UNKNOWN; + par->codec_id = AV_CODEC_ID_NONE; + par->format = -1; + par->field_order = AV_FIELD_UNKNOWN; + par->color_range = AVCOL_RANGE_UNSPECIFIED; + par->color_primaries = AVCOL_PRI_UNSPECIFIED; + par->color_trc = AVCOL_TRC_UNSPECIFIED; + par->color_space = AVCOL_SPC_UNSPECIFIED; + par->chroma_location = AVCHROMA_LOC_UNSPECIFIED; + par->sample_aspect_ratio = (AVRational){ 0, 1 }; + par->profile = FF_PROFILE_UNKNOWN; + par->level = FF_LEVEL_UNKNOWN; +} + +AVCodecParameters *avcodec_parameters_alloc(void) +{ + AVCodecParameters *par = av_mallocz(sizeof(*par)); + + if (!par) + return NULL; + codec_parameters_reset(par); + return par; +} + +void avcodec_parameters_free(AVCodecParameters **ppar) +{ + AVCodecParameters *par = *ppar; + + if (!par) + return; + codec_parameters_reset(par); + + av_freep(ppar); +} + +int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src) +{ + codec_parameters_reset(dst); + memcpy(dst, src, sizeof(*dst)); + + dst->extradata = NULL; + dst->extradata_size = 0; + if (src->extradata) { + dst->extradata = av_mallocz(src->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!dst->extradata) + return AVERROR(ENOMEM); + memcpy(dst->extradata, src->extradata, src->extradata_size); + dst->extradata_size = src->extradata_size; + } + + return 0; +} + +int avcodec_parameters_from_context(AVCodecParameters *par, + const AVCodecContext *codec) +{ + codec_parameters_reset(par); + + par->codec_type = codec->codec_type; + par->codec_id = codec->codec_id; + par->codec_tag = codec->codec_tag; + + par->bit_rate = codec->bit_rate; + par->bits_per_coded_sample = codec->bits_per_coded_sample; + par->bits_per_raw_sample = codec->bits_per_raw_sample; + par->profile = codec->profile; + par->level = codec->level; + + switch (par->codec_type) { + case AVMEDIA_TYPE_VIDEO: + par->format = codec->pix_fmt; + par->width = codec->width; + par->height = codec->height; + par->field_order = codec->field_order; + par->color_range = codec->color_range; + par->color_primaries = codec->color_primaries; + par->color_trc = codec->color_trc; + par->color_space = codec->colorspace; + par->chroma_location = codec->chroma_sample_location; + par->sample_aspect_ratio = codec->sample_aspect_ratio; + par->video_delay = codec->has_b_frames; + break; + case AVMEDIA_TYPE_AUDIO: + par->format = codec->sample_fmt; + par->channel_layout = codec->channel_layout; + par->channels = codec->channels; + par->sample_rate = codec->sample_rate; + par->block_align = codec->block_align; + par->frame_size = codec->frame_size; + par->initial_padding = codec->initial_padding; + par->trailing_padding = codec->trailing_padding; + par->seek_preroll = codec->seek_preroll; + break; + case AVMEDIA_TYPE_SUBTITLE: + par->width = codec->width; + par->height = codec->height; + break; + } + + if (codec->extradata) { + par->extradata = av_mallocz(codec->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!par->extradata) + return AVERROR(ENOMEM); + memcpy(par->extradata, codec->extradata, codec->extradata_size); + par->extradata_size = codec->extradata_size; + } + + return 0; +} + +int avcodec_parameters_to_context(AVCodecContext *codec, + const AVCodecParameters *par) +{ + codec->codec_type = par->codec_type; + codec->codec_id = par->codec_id; + codec->codec_tag = par->codec_tag; + + codec->bit_rate = par->bit_rate; + codec->bits_per_coded_sample = par->bits_per_coded_sample; + codec->bits_per_raw_sample = par->bits_per_raw_sample; + codec->profile = par->profile; + codec->level = par->level; + + switch (par->codec_type) { + case AVMEDIA_TYPE_VIDEO: + codec->pix_fmt = par->format; + codec->width = par->width; + codec->height = par->height; + codec->field_order = par->field_order; + codec->color_range = par->color_range; + codec->color_primaries = par->color_primaries; + codec->color_trc = par->color_trc; + codec->colorspace = par->color_space; + codec->chroma_sample_location = par->chroma_location; + codec->sample_aspect_ratio = par->sample_aspect_ratio; + codec->has_b_frames = par->video_delay; + break; + case AVMEDIA_TYPE_AUDIO: + codec->sample_fmt = par->format; + codec->channel_layout = par->channel_layout; + codec->channels = par->channels; + codec->sample_rate = par->sample_rate; + codec->block_align = par->block_align; + codec->frame_size = par->frame_size; + codec->delay = + codec->initial_padding = par->initial_padding; + codec->trailing_padding = par->trailing_padding; + codec->seek_preroll = par->seek_preroll; + break; + case AVMEDIA_TYPE_SUBTITLE: + codec->width = par->width; + codec->height = par->height; + break; + } + + if (par->extradata) { + av_freep(&codec->extradata); + codec->extradata = av_mallocz(par->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!codec->extradata) + return AVERROR(ENOMEM); + memcpy(codec->extradata, par->extradata, par->extradata_size); + codec->extradata_size = par->extradata_size; + } + + return 0; +} + +int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len, + void **data, size_t *sei_size) +{ + AVFrameSideData *side_data = NULL; + uint8_t *sei_data; + + if (frame) + side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_A53_CC); + + if (!side_data) { + *data = NULL; + return 0; + } + + *sei_size = side_data->size + 11; + *data = av_mallocz(*sei_size + prefix_len); + if (!*data) + return AVERROR(ENOMEM); + sei_data = (uint8_t*)*data + prefix_len; + + // country code + sei_data[0] = 181; + sei_data[1] = 0; + sei_data[2] = 49; + + /** + * 'GA94' is standard in North America for ATSC, but hard coding + * this style may not be the right thing to do -- other formats + * do exist. This information is not available in the side_data + * so we are going with this right now. + */ + AV_WL32(sei_data + 3, MKTAG('G', 'A', '9', '4')); + sei_data[7] = 3; + sei_data[8] = ((side_data->size/3) & 0x1f) | 0x40; + sei_data[9] = 0; + + memcpy(sei_data + 10, side_data->data, side_data->size); + + sei_data[side_data->size+10] = 255; + + return 0; +} + +int64_t ff_guess_coded_bitrate(AVCodecContext *avctx) +{ + AVRational framerate = avctx->framerate; + int bits_per_coded_sample = avctx->bits_per_coded_sample; + int64_t bitrate; + + if (!(framerate.num && framerate.den)) + framerate = av_inv_q(avctx->time_base); + if (!(framerate.num && framerate.den)) + return 0; + + if (!bits_per_coded_sample) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); + bits_per_coded_sample = av_get_bits_per_pixel(desc); + } + bitrate = (int64_t)bits_per_coded_sample * avctx->width * avctx->height * + framerate.num / framerate.den; + + return bitrate; +} + +int ff_int_from_list_or_default(void *ctx, const char * val_name, int val, + const int * array_valid_values, int default_value) +{ + int i = 0, ref_val; + + while (1) { + ref_val = array_valid_values[i]; + if (ref_val == INT_MAX) + break; + if (val == ref_val) + return val; + i++; + } + /* val is not a valid value */ + av_log(ctx, AV_LOG_DEBUG, + "%s %d are not supported. Set to default value : %d\n", val_name, val, default_value); + return default_value; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vaapi.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vaapi.h new file mode 100644 index 0000000000..2cf7da5889 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vaapi.h @@ -0,0 +1,86 @@ +/* + * Video Acceleration API (shared data between FFmpeg and the video player) + * HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1 + * + * Copyright (C) 2008-2009 Splitted-Desktop Systems + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VAAPI_H +#define AVCODEC_VAAPI_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vaapi + * Public libavcodec VA API header. + */ + +#include +#include "libavutil/attributes.h" +#include "version.h" + +#if FF_API_STRUCT_VAAPI_CONTEXT + +/** + * @defgroup lavc_codec_hwaccel_vaapi VA API Decoding + * @ingroup lavc_codec_hwaccel + * @{ + */ + +/** + * This structure is used to share data between the FFmpeg library and + * the client video application. + * This shall be zero-allocated and available as + * AVCodecContext.hwaccel_context. All user members can be set once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + * + * Deprecated: use AVCodecContext.hw_frames_ctx instead. + */ +struct attribute_deprecated vaapi_context { + /** + * Window system dependent data + * + * - encoding: unused + * - decoding: Set by user + */ + void *display; + + /** + * Configuration ID + * + * - encoding: unused + * - decoding: Set by user + */ + uint32_t config_id; + + /** + * Context ID (video decode pipeline) + * + * - encoding: unused + * - decoding: Set by user + */ + uint32_t context_id; +}; + +/* @} */ + +#endif /* FF_API_STRUCT_VAAPI_CONTEXT */ + +#endif /* AVCODEC_VAAPI_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vdpau.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vdpau.h new file mode 100644 index 0000000000..4d99943369 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vdpau.h @@ -0,0 +1,176 @@ +/* + * The Video Decode and Presentation API for UNIX (VDPAU) is used for + * hardware-accelerated decoding of MPEG-1/2, H.264 and VC-1. + * + * Copyright (C) 2008 NVIDIA + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VDPAU_H +#define AVCODEC_VDPAU_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vdpau + * Public libavcodec VDPAU header. + */ + + +/** + * @defgroup lavc_codec_hwaccel_vdpau VDPAU Decoder and Renderer + * @ingroup lavc_codec_hwaccel + * + * VDPAU hardware acceleration has two modules + * - VDPAU decoding + * - VDPAU presentation + * + * The VDPAU decoding module parses all headers using FFmpeg + * parsing mechanisms and uses VDPAU for the actual decoding. + * + * As per the current implementation, the actual decoding + * and rendering (API calls) are done as part of the VDPAU + * presentation (vo_vdpau.c) module. + * + * @{ + */ + +#include + +#include "libavutil/avconfig.h" +#include "libavutil/attributes.h" + +#include "avcodec.h" +#include "version.h" + +struct AVCodecContext; +struct AVFrame; + +typedef int (*AVVDPAU_Render2)(struct AVCodecContext *, struct AVFrame *, + const VdpPictureInfo *, uint32_t, + const VdpBitstreamBuffer *); + +/** + * This structure is used to share data between the libavcodec library and + * the client video application. + * The user shall allocate the structure via the av_alloc_vdpau_hwaccel + * function and make it available as + * AVCodecContext.hwaccel_context. Members can be set by the user once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + * + * The size of this structure is not a part of the public ABI and must not + * be used outside of libavcodec. Use av_vdpau_alloc_context() to allocate an + * AVVDPAUContext. + */ +typedef struct AVVDPAUContext { + /** + * VDPAU decoder handle + * + * Set by user. + */ + VdpDecoder decoder; + + /** + * VDPAU decoder render callback + * + * Set by the user. + */ + VdpDecoderRender *render; + + AVVDPAU_Render2 render2; +} AVVDPAUContext; + +/** + * @brief allocation function for AVVDPAUContext + * + * Allows extending the struct without breaking API/ABI + */ +AVVDPAUContext *av_alloc_vdpaucontext(void); + +AVVDPAU_Render2 av_vdpau_hwaccel_get_render2(const AVVDPAUContext *); +void av_vdpau_hwaccel_set_render2(AVVDPAUContext *, AVVDPAU_Render2); + +/** + * Associate a VDPAU device with a codec context for hardware acceleration. + * This function is meant to be called from the get_format() codec callback, + * or earlier. It can also be called after avcodec_flush_buffers() to change + * the underlying VDPAU device mid-stream (e.g. to recover from non-transparent + * display preemption). + * + * @note get_format() must return AV_PIX_FMT_VDPAU if this function completes + * successfully. + * + * @param avctx decoding context whose get_format() callback is invoked + * @param device VDPAU device handle to use for hardware acceleration + * @param get_proc_address VDPAU device driver + * @param flags zero of more OR'd AV_HWACCEL_FLAG_* flags + * + * @return 0 on success, an AVERROR code on failure. + */ +int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device, + VdpGetProcAddress *get_proc_address, unsigned flags); + +/** + * Gets the parameters to create an adequate VDPAU video surface for the codec + * context using VDPAU hardware decoding acceleration. + * + * @note Behavior is undefined if the context was not successfully bound to a + * VDPAU device using av_vdpau_bind_context(). + * + * @param avctx the codec context being used for decoding the stream + * @param type storage space for the VDPAU video surface chroma type + * (or NULL to ignore) + * @param width storage space for the VDPAU video surface pixel width + * (or NULL to ignore) + * @param height storage space for the VDPAU video surface pixel height + * (or NULL to ignore) + * + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_vdpau_get_surface_parameters(AVCodecContext *avctx, VdpChromaType *type, + uint32_t *width, uint32_t *height); + +/** + * Allocate an AVVDPAUContext. + * + * @return Newly-allocated AVVDPAUContext or NULL on failure. + */ +AVVDPAUContext *av_vdpau_alloc_context(void); + +#if FF_API_VDPAU_PROFILE +/** + * Get a decoder profile that should be used for initializing a VDPAU decoder. + * Should be called from the AVCodecContext.get_format() callback. + * + * @deprecated Use av_vdpau_bind_context() instead. + * + * @param avctx the codec context being used for decoding the stream + * @param profile a pointer into which the result will be written on success. + * The contents of profile are undefined if this function returns + * an error. + * + * @return 0 on success (non-negative), a negative AVERROR on failure. + */ +attribute_deprecated +int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile); +#endif + +/* @}*/ + +#endif /* AVCODEC_VDPAU_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/version.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/version.h new file mode 100644 index 0000000000..3331d47300 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/version.h @@ -0,0 +1,140 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VERSION_H +#define AVCODEC_VERSION_H + +/** + * @file + * @ingroup libavc + * Libavcodec version macros. + */ + +#include "libavutil/version.h" + +#define LIBAVCODEC_VERSION_MAJOR 58 +#define LIBAVCODEC_VERSION_MINOR 54 +#define LIBAVCODEC_VERSION_MICRO 100 + +#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT + +#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @note, when bumping the major version it is recommended to manually + * disable each FF_API_* in its own commit instead of disabling them all + * at once through the bump. This improves the git bisect-ability of the change. + */ + +#ifndef FF_API_LOWRES +#define FF_API_LOWRES (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_DEBUG_MV +#define FF_API_DEBUG_MV (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AVCTX_TIMEBASE +#define FF_API_AVCTX_TIMEBASE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_CODED_FRAME +#define FF_API_CODED_FRAME (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_SIDEDATA_ONLY_PKT +#define FF_API_SIDEDATA_ONLY_PKT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_VDPAU_PROFILE +#define FF_API_VDPAU_PROFILE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_CONVERGENCE_DURATION +#define FF_API_CONVERGENCE_DURATION (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_AVPICTURE +#define FF_API_AVPICTURE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_AVPACKET_OLD_API +#define FF_API_AVPACKET_OLD_API (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_RTP_CALLBACK +#define FF_API_RTP_CALLBACK (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_VBV_DELAY +#define FF_API_VBV_DELAY (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_CODER_TYPE +#define FF_API_CODER_TYPE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_STAT_BITS +#define FF_API_STAT_BITS (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_PRIVATE_OPT +#define FF_API_PRIVATE_OPT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_ASS_TIMING +#define FF_API_ASS_TIMING (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_OLD_BSF +#define FF_API_OLD_BSF (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_COPY_CONTEXT +#define FF_API_COPY_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_GET_CONTEXT_DEFAULTS +#define FF_API_GET_CONTEXT_DEFAULTS (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_NVENC_OLD_NAME +#define FF_API_NVENC_OLD_NAME (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_STRUCT_VAAPI_CONTEXT +#define FF_API_STRUCT_VAAPI_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_MERGE_SD_API +#define FF_API_MERGE_SD_API (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_TAG_STRING +#define FF_API_TAG_STRING (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_GETCHROMA +#define FF_API_GETCHROMA (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_CODEC_GET_SET +#define FF_API_CODEC_GET_SET (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_USER_VISIBLE_AVHWACCEL +#define FF_API_USER_VISIBLE_AVHWACCEL (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_LOCKMGR +#define FF_API_LOCKMGR (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_NEXT +#define FF_API_NEXT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_UNSANITIZED_BITRATES +#define FF_API_UNSANITIZED_BITRATES (LIBAVCODEC_VERSION_MAJOR < 59) +#endif + + +#endif /* AVCODEC_VERSION_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videodsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videodsp.c new file mode 100644 index 0000000000..ce9e9eb143 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videodsp.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "videodsp.h" + +#define BIT_DEPTH 8 +#include "videodsp_template.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 16 +#include "videodsp_template.c" +#undef BIT_DEPTH + +static void just_return(uint8_t *buf, ptrdiff_t stride, int h) +{ +} + +av_cold void ff_videodsp_init(VideoDSPContext *ctx, int bpc) +{ + ctx->prefetch = just_return; + if (bpc <= 8) { + ctx->emulated_edge_mc = ff_emulated_edge_mc_8; + } else { + ctx->emulated_edge_mc = ff_emulated_edge_mc_16; + } + + if (ARCH_AARCH64) + ff_videodsp_init_aarch64(ctx, bpc); + if (ARCH_ARM) + ff_videodsp_init_arm(ctx, bpc); + if (ARCH_PPC) + ff_videodsp_init_ppc(ctx, bpc); + if (ARCH_X86) + ff_videodsp_init_x86(ctx, bpc); + if (ARCH_MIPS) + ff_videodsp_init_mips(ctx, bpc); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videodsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videodsp.h new file mode 100644 index 0000000000..c0545f22b0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videodsp.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2012 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Core video DSP helper functions + */ + +#ifndef AVCODEC_VIDEODSP_H +#define AVCODEC_VIDEODSP_H + +#include +#include + +#define EMULATED_EDGE(depth) \ +void ff_emulated_edge_mc_ ## depth(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t dst_stride, ptrdiff_t src_stride, \ + int block_w, int block_h,\ + int src_x, int src_y, int w, int h); + +EMULATED_EDGE(8) +EMULATED_EDGE(16) + +typedef struct VideoDSPContext { + /** + * Copy a rectangular area of samples to a temporary buffer and replicate + * the border samples. + * + * @param dst destination buffer + * @param dst_stride number of bytes between 2 vertically adjacent samples + * in destination buffer + * @param src source buffer + * @param dst_linesize number of bytes between 2 vertically adjacent + * samples in the destination buffer + * @param src_linesize number of bytes between 2 vertically adjacent + * samples in both the source buffer + * @param block_w width of block + * @param block_h height of block + * @param src_x x coordinate of the top left sample of the block in the + * source buffer + * @param src_y y coordinate of the top left sample of the block in the + * source buffer + * @param w width of the source buffer + * @param h height of the source buffer + */ + void (*emulated_edge_mc)(uint8_t *dst, const uint8_t *src, + ptrdiff_t dst_linesize, + ptrdiff_t src_linesize, + int block_w, int block_h, + int src_x, int src_y, int w, int h); + + /** + * Prefetch memory into cache (if supported by hardware). + * + * @param buf pointer to buffer to prefetch memory from + * @param stride distance between two lines of buf (in bytes) + * @param h number of lines to prefetch + */ + void (*prefetch)(uint8_t *buf, ptrdiff_t stride, int h); +} VideoDSPContext; + +void ff_videodsp_init(VideoDSPContext *ctx, int bpc); + +/* for internal use only (i.e. called by ff_videodsp_init() */ +void ff_videodsp_init_aarch64(VideoDSPContext *ctx, int bpc); +void ff_videodsp_init_arm(VideoDSPContext *ctx, int bpc); +void ff_videodsp_init_ppc(VideoDSPContext *ctx, int bpc); +void ff_videodsp_init_x86(VideoDSPContext *ctx, int bpc); +void ff_videodsp_init_mips(VideoDSPContext *ctx, int bpc); + +#endif /* AVCODEC_VIDEODSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videotoolbox.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videotoolbox.h new file mode 100644 index 0000000000..af2db0d580 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/videotoolbox.h @@ -0,0 +1,127 @@ +/* + * Videotoolbox hardware acceleration + * + * copyright (c) 2012 Sebastien Zwickert + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VIDEOTOOLBOX_H +#define AVCODEC_VIDEOTOOLBOX_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_videotoolbox + * Public libavcodec Videotoolbox header. + */ + +#include + +#define Picture QuickdrawPicture +#include +#undef Picture + +#include "libavcodec/avcodec.h" + +/** + * This struct holds all the information that needs to be passed + * between the caller and libavcodec for initializing Videotoolbox decoding. + * Its size is not a part of the public ABI, it must be allocated with + * av_videotoolbox_alloc_context() and freed with av_free(). + */ +typedef struct AVVideotoolboxContext { + /** + * Videotoolbox decompression session object. + * Created and freed the caller. + */ + VTDecompressionSessionRef session; + + /** + * The output callback that must be passed to the session. + * Set by av_videottoolbox_default_init() + */ + VTDecompressionOutputCallback output_callback; + + /** + * CVPixelBuffer Format Type that Videotoolbox will use for decoded frames. + * set by the caller. If this is set to 0, then no specific format is + * requested from the decoder, and its native format is output. + */ + OSType cv_pix_fmt_type; + + /** + * CoreMedia Format Description that Videotoolbox will use to create the decompression session. + * Set by the caller. + */ + CMVideoFormatDescriptionRef cm_fmt_desc; + + /** + * CoreMedia codec type that Videotoolbox will use to create the decompression session. + * Set by the caller. + */ + int cm_codec_type; +} AVVideotoolboxContext; + +/** + * Allocate and initialize a Videotoolbox context. + * + * This function should be called from the get_format() callback when the caller + * selects the AV_PIX_FMT_VIDETOOLBOX format. The caller must then create + * the decoder object (using the output callback provided by libavcodec) that + * will be used for Videotoolbox-accelerated decoding. + * + * When decoding with Videotoolbox is finished, the caller must destroy the decoder + * object and free the Videotoolbox context using av_free(). + * + * @return the newly allocated context or NULL on failure + */ +AVVideotoolboxContext *av_videotoolbox_alloc_context(void); + +/** + * This is a convenience function that creates and sets up the Videotoolbox context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_videotoolbox_default_init(AVCodecContext *avctx); + +/** + * This is a convenience function that creates and sets up the Videotoolbox context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * @param vtctx the Videotoolbox context to use + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext *vtctx); + +/** + * This function must be called to free the Videotoolbox context initialized with + * av_videotoolbox_default_init(). + * + * @param avctx the corresponding codec context + */ +void av_videotoolbox_default_free(AVCodecContext *avctx); + +/** + * @} + */ + +#endif /* AVCODEC_VIDEOTOOLBOX_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vlc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vlc.h new file mode 100644 index 0000000000..42ccddf3fc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vlc.h @@ -0,0 +1,81 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VLC_H +#define AVCODEC_VLC_H + +#include + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; ///< code, bits + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +#define init_vlc(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + flags) \ + ff_init_vlc_sparse(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + NULL, 0, 0, flags) + +int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags); +void ff_free_vlc(VLC *vlc); + +#define INIT_VLC_LE 2 +#define INIT_VLC_USE_NEW_STATIC 4 + +#define INIT_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, h, i, j, static_size) \ + do { \ + static VLC_TYPE table[static_size][2]; \ + (vlc)->table = table; \ + (vlc)->table_allocated = static_size; \ + ff_init_vlc_sparse(vlc, bits, a, b, c, d, e, f, g, h, i, j, \ + INIT_VLC_USE_NEW_STATIC); \ + } while (0) + +#define INIT_LE_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, h, i, j, static_size) \ + do { \ + static VLC_TYPE table[static_size][2]; \ + (vlc)->table = table; \ + (vlc)->table_allocated = static_size; \ + ff_init_vlc_sparse(vlc, bits, a, b, c, d, e, f, g, h, i, j, \ + INIT_VLC_USE_NEW_STATIC | INIT_VLC_LE); \ + } while (0) + +#define INIT_VLC_STATIC(vlc, bits, a, b, c, d, e, f, g, static_size) \ + INIT_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, NULL, 0, 0, static_size) + +#define INIT_LE_VLC_STATIC(vlc, bits, a, b, c, d, e, f, g, static_size) \ + INIT_LE_VLC_SPARSE_STATIC(vlc, bits, a, b, c, d, e, f, g, NULL, 0, 0, static_size) + +#endif /* AVCODEC_VLC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis.c new file mode 100644 index 0000000000..cca2aa7c63 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis.c @@ -0,0 +1,218 @@ +/** + * @file + * Common code for Vorbis I encoder and decoder + * @author Denes Balatoni ( dbalatoni programozo hu ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Common code for Vorbis I encoder and decoder + * @author Denes Balatoni ( dbalatoni programozo hu ) + */ + +#include "libavutil/common.h" + +#include "avcodec.h" +#include "vorbis.h" + + +/* Helper functions */ + +// x^(1/n) +unsigned int ff_vorbis_nth_root(unsigned int x, unsigned int n) +{ + unsigned int ret = 0, i, j; + + do { + ++ret; + for (i = 0, j = ret; i < n - 1; i++) + j *= ret; + } while (j <= x); + + return ret - 1; +} + +// Generate vlc codes from vorbis huffman code lengths + +// the two bits[p] > 32 checks should be redundant, all calling code should +// already ensure that, but since it allows overwriting the stack it seems +// reasonable to check redundantly. +int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num) +{ + uint32_t exit_at_level[33] = { 404 }; + unsigned i, j, p, code; + + for (p = 0; (p < num) && (bits[p] == 0); ++p) + ; + if (p == num) + return 0; + + codes[p] = 0; + if (bits[p] > 32) + return AVERROR_INVALIDDATA; + for (i = 0; i < bits[p]; ++i) + exit_at_level[i+1] = 1u << i; + + ++p; + + for (i = p; (i < num) && (bits[i] == 0); ++i) + ; + if (i == num) + return 0; + + for (; p < num; ++p) { + if (bits[p] > 32) + return AVERROR_INVALIDDATA; + if (bits[p] == 0) + continue; + // find corresponding exit(node which the tree can grow further from) + for (i = bits[p]; i > 0; --i) + if (exit_at_level[i]) + break; + if (!i) // overspecified tree + return AVERROR_INVALIDDATA; + code = exit_at_level[i]; + exit_at_level[i] = 0; + // construct code (append 0s to end) and introduce new exits + for (j = i + 1 ;j <= bits[p]; ++j) + exit_at_level[j] = code + (1u << (j - 1)); + codes[p] = code; + } + + //no exits should be left (underspecified tree - ie. unused valid vlcs - not allowed by SPEC) + for (p = 1; p < 33; p++) + if (exit_at_level[p]) + return AVERROR_INVALIDDATA; + + return 0; +} + +int ff_vorbis_ready_floor1_list(AVCodecContext *avctx, + vorbis_floor1_entry *list, int values) +{ + int i; + list[0].sort = 0; + list[1].sort = 1; + for (i = 2; i < values; i++) { + int j; + list[i].low = 0; + list[i].high = 1; + list[i].sort = i; + for (j = 2; j < i; j++) { + int tmp = list[j].x; + if (tmp < list[i].x) { + if (tmp > list[list[i].low].x) + list[i].low = j; + } else { + if (tmp < list[list[i].high].x) + list[i].high = j; + } + } + } + for (i = 0; i < values - 1; i++) { + int j; + for (j = i + 1; j < values; j++) { + if (list[i].x == list[j].x) { + av_log(avctx, AV_LOG_ERROR, + "Duplicate value found in floor 1 X coordinates\n"); + return AVERROR_INVALIDDATA; + } + if (list[list[i].sort].x > list[list[j].sort].x) { + int tmp = list[i].sort; + list[i].sort = list[j].sort; + list[j].sort = tmp; + } + } + } + return 0; +} + +static inline void render_line_unrolled(intptr_t x, int y, int x1, + intptr_t sy, int ady, int adx, + float *buf) +{ + int err = -adx; + x -= x1 - 1; + buf += x1 - 1; + while (++x < 0) { + err += ady; + if (err >= 0) { + err += ady - adx; + y += sy; + buf[x++] = ff_vorbis_floor1_inverse_db_table[av_clip_uint8(y)]; + } + buf[x] = ff_vorbis_floor1_inverse_db_table[av_clip_uint8(y)]; + } + if (x <= 0) { + if (err + ady >= 0) + y += sy; + buf[x] = ff_vorbis_floor1_inverse_db_table[av_clip_uint8(y)]; + } +} + +static void render_line(int x0, int y0, int x1, int y1, float *buf) +{ + int dy = y1 - y0; + int adx = x1 - x0; + int ady = FFABS(dy); + int sy = dy < 0 ? -1 : 1; + buf[x0] = ff_vorbis_floor1_inverse_db_table[av_clip_uint8(y0)]; + if (ady*2 <= adx) { // optimized common case + render_line_unrolled(x0, y0, x1, sy, ady, adx, buf); + } else { + int base = dy / adx; + int x = x0; + int y = y0; + int err = -adx; + ady -= FFABS(base) * adx; + while (++x < x1) { + y += base; + err += ady; + if (err >= 0) { + err -= adx; + y += sy; + } + buf[x] = ff_vorbis_floor1_inverse_db_table[av_clip_uint8(y)]; + } + } +} + +void ff_vorbis_floor1_render_list(vorbis_floor1_entry * list, int values, + uint16_t *y_list, int *flag, + int multiplier, float *out, int samples) +{ + int lx, ly, i; + lx = 0; + ly = y_list[0] * multiplier; + for (i = 1; i < values; i++) { + int pos = list[i].sort; + if (flag[pos]) { + int x1 = list[pos].x; + int y1 = y_list[pos] * multiplier; + if (lx < samples) + render_line(lx, ly, FFMIN(x1,samples), y1, out); + lx = x1; + ly = y1; + } + if (lx >= samples) + break; + } + if (lx < samples) + render_line(lx, ly, samples, ly, out); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis.h new file mode 100644 index 0000000000..98dd14f9d4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis.h @@ -0,0 +1,50 @@ +/* + * copyright (c) 2006 Oded Shimon + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VORBIS_H +#define AVCODEC_VORBIS_H + +#include "avcodec.h" + +extern const float ff_vorbis_floor1_inverse_db_table[256]; +extern const float * const ff_vorbis_vwin[8]; +extern const uint8_t ff_vorbis_channel_layout_offsets[8][8]; +extern const uint8_t ff_vorbis_encoding_channel_layout_offsets[8][8]; +extern const uint64_t ff_vorbis_channel_layouts[9]; + +typedef struct vorbis_floor1_entry { + uint16_t x; + uint16_t sort; + uint16_t low; + uint16_t high; +} vorbis_floor1_entry; + +int ff_vorbis_ready_floor1_list(AVCodecContext *avctx, + vorbis_floor1_entry *list, int values); +unsigned int ff_vorbis_nth_root(unsigned int x, unsigned int n); // x^(1/n) +int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num); +void ff_vorbis_floor1_render_list(vorbis_floor1_entry * list, int values, + uint16_t *y_list, int *flag, + int multiplier, float * out, int samples); +void ff_vorbis_inverse_coupling(float *mag, float *ang, intptr_t blocksize); + +#define ilog(i) av_log2(2*(i)) + +#endif /* AVCODEC_VORBIS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_data.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_data.c new file mode 100644 index 0000000000..063a075ce0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_data.c @@ -0,0 +1,2193 @@ +/* + * copyright (c) 2005 Denes Balatoni ( dbalatoni programozo hu ) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/channel_layout.h" +#include "libavutil/mem.h" +#include "vorbis.h" + +const uint8_t ff_vorbis_channel_layout_offsets[8][8] = { + { 0 }, + { 0, 1 }, + { 0, 2, 1 }, + { 0, 1, 2, 3 }, + { 0, 2, 1, 3, 4 }, + { 0, 2, 1, 5, 3, 4 }, + { 0, 2, 1, 6, 5, 3, 4 }, + { 0, 2, 1, 7, 5, 6, 3, 4 }, +}; + +const uint8_t ff_vorbis_encoding_channel_layout_offsets[8][8] = { + { 0 }, + { 0, 1 }, + { 0, 2, 1 }, + { 0, 1, 2, 3 }, + { 0, 2, 1, 3, 4 }, + { 0, 2, 1, 4, 5, 3 }, + { 0, 2, 1, 5, 6, 4, 3 }, + { 0, 2, 1, 6, 7, 4, 5, 3 }, +}; + +const uint64_t ff_vorbis_channel_layouts[9] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_QUAD, + AV_CH_LAYOUT_5POINT0_BACK, + AV_CH_LAYOUT_5POINT1_BACK, + AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER, + AV_CH_LAYOUT_7POINT1, + 0 +}; + +DECLARE_ALIGNED(16, static const float, vwin64)[32] = { + 0.0009460463F, 0.0085006468F, 0.0235352254F, 0.0458950567F, + 0.0753351908F, 0.1115073077F, 0.1539457973F, 0.2020557475F, + 0.2551056759F, 0.3122276645F, 0.3724270287F, 0.4346027792F, + 0.4975789974F, 0.5601459521F, 0.6211085051F, 0.6793382689F, + 0.7338252629F, 0.7837245849F, 0.8283939355F, 0.8674186656F, + 0.9006222429F, 0.9280614787F, 0.9500073081F, 0.9669131782F, + 0.9793740220F, 0.9880792941F, 0.9937636139F, 0.9971582668F, + 0.9989462667F, 0.9997230082F, 0.9999638688F, 0.9999995525F, +}; + +DECLARE_ALIGNED(16, static const float, vwin128)[64] = { + 0.0002365472F, 0.0021280687F, 0.0059065254F, 0.0115626550F, + 0.0190823442F, 0.0284463735F, 0.0396300935F, 0.0526030430F, + 0.0673285281F, 0.0837631763F, 0.1018564887F, 0.1215504095F, + 0.1427789367F, 0.1654677960F, 0.1895342001F, 0.2148867160F, + 0.2414252576F, 0.2690412240F, 0.2976177952F, 0.3270303960F, + 0.3571473350F, 0.3878306189F, 0.4189369387F, 0.4503188188F, + 0.4818259135F, 0.5133064334F, 0.5446086751F, 0.5755826278F, + 0.6060816248F, 0.6359640047F, 0.6650947483F, 0.6933470543F, + 0.7206038179F, 0.7467589810F, 0.7717187213F, 0.7954024542F, + 0.8177436264F, 0.8386902831F, 0.8582053981F, 0.8762669622F, + 0.8928678298F, 0.9080153310F, 0.9217306608F, 0.9340480615F, + 0.9450138200F, 0.9546851041F, 0.9631286621F, 0.9704194171F, + 0.9766389810F, 0.9818741197F, 0.9862151938F, 0.9897546035F, + 0.9925852598F, 0.9947991032F, 0.9964856900F, 0.9977308602F, + 0.9986155015F, 0.9992144193F, 0.9995953200F, 0.9998179155F, + 0.9999331503F, 0.9999825563F, 0.9999977357F, 0.9999999720F, +}; + +DECLARE_ALIGNED(16, static const float, vwin256)[128] = { + 0.0000591390F, 0.0005321979F, 0.0014780301F, 0.0028960636F, + 0.0047854363F, 0.0071449926F, 0.0099732775F, 0.0132685298F, + 0.0170286741F, 0.0212513119F, 0.0259337111F, 0.0310727950F, + 0.0366651302F, 0.0427069140F, 0.0491939614F, 0.0561216907F, + 0.0634851102F, 0.0712788035F, 0.0794969160F, 0.0881331402F, + 0.0971807028F, 0.1066323515F, 0.1164803426F, 0.1267164297F, + 0.1373318534F, 0.1483173323F, 0.1596630553F, 0.1713586755F, + 0.1833933062F, 0.1957555184F, 0.2084333404F, 0.2214142599F, + 0.2346852280F, 0.2482326664F, 0.2620424757F, 0.2761000481F, + 0.2903902813F, 0.3048975959F, 0.3196059553F, 0.3344988887F, + 0.3495595160F, 0.3647705766F, 0.3801144597F, 0.3955732382F, + 0.4111287047F, 0.4267624093F, 0.4424557009F, 0.4581897696F, + 0.4739456913F, 0.4897044744F, 0.5054471075F, 0.5211546088F, + 0.5368080763F, 0.5523887395F, 0.5678780103F, 0.5832575361F, + 0.5985092508F, 0.6136154277F, 0.6285587300F, 0.6433222619F, + 0.6578896175F, 0.6722449294F, 0.6863729144F, 0.7002589187F, + 0.7138889597F, 0.7272497662F, 0.7403288154F, 0.7531143679F, + 0.7655954985F, 0.7777621249F, 0.7896050322F, 0.8011158947F, + 0.8122872932F, 0.8231127294F, 0.8335866365F, 0.8437043850F, + 0.8534622861F, 0.8628575905F, 0.8718884835F, 0.8805540765F, + 0.8888543947F, 0.8967903616F, 0.9043637797F, 0.9115773078F, + 0.9184344360F, 0.9249394562F, 0.9310974312F, 0.9369141608F, + 0.9423961446F, 0.9475505439F, 0.9523851406F, 0.9569082947F, + 0.9611289005F, 0.9650563408F, 0.9687004405F, 0.9720714191F, + 0.9751798427F, 0.9780365753F, 0.9806527301F, 0.9830396204F, + 0.9852087111F, 0.9871715701F, 0.9889398207F, 0.9905250941F, + 0.9919389832F, 0.9931929973F, 0.9942985174F, 0.9952667537F, + 0.9961087037F, 0.9968351119F, 0.9974564312F, 0.9979827858F, + 0.9984239359F, 0.9987892441F, 0.9990876435F, 0.9993276081F, + 0.9995171241F, 0.9996636648F, 0.9997741654F, 0.9998550016F, + 0.9999119692F, 0.9999502656F, 0.9999744742F, 0.9999885497F, + 0.9999958064F, 0.9999989077F, 0.9999998584F, 0.9999999983F, +}; + +DECLARE_ALIGNED(16, static const float, vwin512)[256] = { + 0.0000147849F, 0.0001330607F, 0.0003695946F, 0.0007243509F, + 0.0011972759F, 0.0017882983F, 0.0024973285F, 0.0033242588F, + 0.0042689632F, 0.0053312973F, 0.0065110982F, 0.0078081841F, + 0.0092223540F, 0.0107533880F, 0.0124010466F, 0.0141650703F, + 0.0160451800F, 0.0180410758F, 0.0201524373F, 0.0223789233F, + 0.0247201710F, 0.0271757958F, 0.0297453914F, 0.0324285286F, + 0.0352247556F, 0.0381335972F, 0.0411545545F, 0.0442871045F, + 0.0475306997F, 0.0508847676F, 0.0543487103F, 0.0579219038F, + 0.0616036982F, 0.0653934164F, 0.0692903546F, 0.0732937809F, + 0.0774029356F, 0.0816170305F, 0.0859352485F, 0.0903567428F, + 0.0948806375F, 0.0995060259F, 0.1042319712F, 0.1090575056F, + 0.1139816300F, 0.1190033137F, 0.1241214941F, 0.1293350764F, + 0.1346429333F, 0.1400439046F, 0.1455367974F, 0.1511203852F, + 0.1567934083F, 0.1625545735F, 0.1684025537F, 0.1743359881F, + 0.1803534820F, 0.1864536069F, 0.1926349000F, 0.1988958650F, + 0.2052349715F, 0.2116506555F, 0.2181413191F, 0.2247053313F, + 0.2313410275F, 0.2380467105F, 0.2448206500F, 0.2516610835F, + 0.2585662164F, 0.2655342226F, 0.2725632448F, 0.2796513950F, + 0.2867967551F, 0.2939973773F, 0.3012512852F, 0.3085564739F, + 0.3159109111F, 0.3233125375F, 0.3307592680F, 0.3382489922F, + 0.3457795756F, 0.3533488602F, 0.3609546657F, 0.3685947904F, + 0.3762670121F, 0.3839690896F, 0.3916987634F, 0.3994537572F, + 0.4072317788F, 0.4150305215F, 0.4228476653F, 0.4306808783F, + 0.4385278181F, 0.4463861329F, 0.4542534630F, 0.4621274424F, + 0.4700057001F, 0.4778858615F, 0.4857655502F, 0.4936423891F, + 0.5015140023F, 0.5093780165F, 0.5172320626F, 0.5250737772F, + 0.5329008043F, 0.5407107971F, 0.5485014192F, 0.5562703465F, + 0.5640152688F, 0.5717338914F, 0.5794239366F, 0.5870831457F, + 0.5947092801F, 0.6023001235F, 0.6098534829F, 0.6173671907F, + 0.6248391059F, 0.6322671161F, 0.6396491384F, 0.6469831217F, + 0.6542670475F, 0.6614989319F, 0.6686768267F, 0.6757988210F, + 0.6828630426F, 0.6898676592F, 0.6968108799F, 0.7036909564F, + 0.7105061843F, 0.7172549043F, 0.7239355032F, 0.7305464154F, + 0.7370861235F, 0.7435531598F, 0.7499461068F, 0.7562635986F, + 0.7625043214F, 0.7686670148F, 0.7747504721F, 0.7807535410F, + 0.7866751247F, 0.7925141825F, 0.7982697296F, 0.8039408387F, + 0.8095266395F, 0.8150263196F, 0.8204391248F, 0.8257643590F, + 0.8310013848F, 0.8361496236F, 0.8412085555F, 0.8461777194F, + 0.8510567129F, 0.8558451924F, 0.8605428730F, 0.8651495278F, + 0.8696649882F, 0.8740891432F, 0.8784219392F, 0.8826633797F, + 0.8868135244F, 0.8908724888F, 0.8948404441F, 0.8987176157F, + 0.9025042831F, 0.9062007791F, 0.9098074886F, 0.9133248482F, + 0.9167533451F, 0.9200935163F, 0.9233459472F, 0.9265112712F, + 0.9295901680F, 0.9325833632F, 0.9354916263F, 0.9383157705F, + 0.9410566504F, 0.9437151618F, 0.9462922398F, 0.9487888576F, + 0.9512060252F, 0.9535447882F, 0.9558062262F, 0.9579914516F, + 0.9601016078F, 0.9621378683F, 0.9641014348F, 0.9659935361F, + 0.9678154261F, 0.9695683830F, 0.9712537071F, 0.9728727198F, + 0.9744267618F, 0.9759171916F, 0.9773453842F, 0.9787127293F, + 0.9800206298F, 0.9812705006F, 0.9824637665F, 0.9836018613F, + 0.9846862258F, 0.9857183066F, 0.9866995544F, 0.9876314227F, + 0.9885153662F, 0.9893528393F, 0.9901452948F, 0.9908941823F, + 0.9916009470F, 0.9922670279F, 0.9928938570F, 0.9934828574F, + 0.9940354423F, 0.9945530133F, 0.9950369595F, 0.9954886562F, + 0.9959094633F, 0.9963007242F, 0.9966637649F, 0.9969998925F, + 0.9973103939F, 0.9975965351F, 0.9978595598F, 0.9981006885F, + 0.9983211172F, 0.9985220166F, 0.9987045311F, 0.9988697776F, + 0.9990188449F, 0.9991527924F, 0.9992726499F, 0.9993794157F, + 0.9994740570F, 0.9995575079F, 0.9996306699F, 0.9996944099F, + 0.9997495605F, 0.9997969190F, 0.9998372465F, 0.9998712678F, + 0.9998996704F, 0.9999231041F, 0.9999421807F, 0.9999574732F, + 0.9999695157F, 0.9999788026F, 0.9999857885F, 0.9999908879F, + 0.9999944746F, 0.9999968817F, 0.9999984010F, 0.9999992833F, + 0.9999997377F, 0.9999999317F, 0.9999999911F, 0.9999999999F, +}; + +DECLARE_ALIGNED(16, static const float, vwin1024)[512] = { + 0.0000036962F, 0.0000332659F, 0.0000924041F, 0.0001811086F, + 0.0002993761F, 0.0004472021F, 0.0006245811F, 0.0008315063F, + 0.0010679699F, 0.0013339631F, 0.0016294757F, 0.0019544965F, + 0.0023090133F, 0.0026930125F, 0.0031064797F, 0.0035493989F, + 0.0040217533F, 0.0045235250F, 0.0050546946F, 0.0056152418F, + 0.0062051451F, 0.0068243817F, 0.0074729278F, 0.0081507582F, + 0.0088578466F, 0.0095941655F, 0.0103596863F, 0.0111543789F, + 0.0119782122F, 0.0128311538F, 0.0137131701F, 0.0146242260F, + 0.0155642855F, 0.0165333111F, 0.0175312640F, 0.0185581042F, + 0.0196137903F, 0.0206982797F, 0.0218115284F, 0.0229534910F, + 0.0241241208F, 0.0253233698F, 0.0265511886F, 0.0278075263F, + 0.0290923308F, 0.0304055484F, 0.0317471241F, 0.0331170013F, + 0.0345151222F, 0.0359414274F, 0.0373958560F, 0.0388783456F, + 0.0403888325F, 0.0419272511F, 0.0434935347F, 0.0450876148F, + 0.0467094213F, 0.0483588828F, 0.0500359261F, 0.0517404765F, + 0.0534724575F, 0.0552317913F, 0.0570183983F, 0.0588321971F, + 0.0606731048F, 0.0625410369F, 0.0644359070F, 0.0663576272F, + 0.0683061077F, 0.0702812571F, 0.0722829821F, 0.0743111878F, + 0.0763657775F, 0.0784466526F, 0.0805537129F, 0.0826868561F, + 0.0848459782F, 0.0870309736F, 0.0892417345F, 0.0914781514F, + 0.0937401128F, 0.0960275056F, 0.0983402145F, 0.1006781223F, + 0.1030411101F, 0.1054290568F, 0.1078418397F, 0.1102793336F, + 0.1127414119F, 0.1152279457F, 0.1177388042F, 0.1202738544F, + 0.1228329618F, 0.1254159892F, 0.1280227980F, 0.1306532471F, + 0.1333071937F, 0.1359844927F, 0.1386849970F, 0.1414085575F, + 0.1441550230F, 0.1469242403F, 0.1497160539F, 0.1525303063F, + 0.1553668381F, 0.1582254875F, 0.1611060909F, 0.1640084822F, + 0.1669324936F, 0.1698779549F, 0.1728446939F, 0.1758325362F, + 0.1788413055F, 0.1818708232F, 0.1849209084F, 0.1879913785F, + 0.1910820485F, 0.1941927312F, 0.1973232376F, 0.2004733764F, + 0.2036429541F, 0.2068317752F, 0.2100396421F, 0.2132663552F, + 0.2165117125F, 0.2197755102F, 0.2230575422F, 0.2263576007F, + 0.2296754753F, 0.2330109540F, 0.2363638225F, 0.2397338646F, + 0.2431208619F, 0.2465245941F, 0.2499448389F, 0.2533813719F, + 0.2568339669F, 0.2603023956F, 0.2637864277F, 0.2672858312F, + 0.2708003718F, 0.2743298135F, 0.2778739186F, 0.2814324472F, + 0.2850051576F, 0.2885918065F, 0.2921921485F, 0.2958059366F, + 0.2994329219F, 0.3030728538F, 0.3067254799F, 0.3103905462F, + 0.3140677969F, 0.3177569747F, 0.3214578205F, 0.3251700736F, + 0.3288934718F, 0.3326277513F, 0.3363726468F, 0.3401278914F, + 0.3438932168F, 0.3476683533F, 0.3514530297F, 0.3552469734F, + 0.3590499106F, 0.3628615659F, 0.3666816630F, 0.3705099239F, + 0.3743460698F, 0.3781898204F, 0.3820408945F, 0.3858990095F, + 0.3897638820F, 0.3936352274F, 0.3975127601F, 0.4013961936F, + 0.4052852405F, 0.4091796123F, 0.4130790198F, 0.4169831732F, + 0.4208917815F, 0.4248045534F, 0.4287211965F, 0.4326414181F, + 0.4365649248F, 0.4404914225F, 0.4444206167F, 0.4483522125F, + 0.4522859146F, 0.4562214270F, 0.4601584538F, 0.4640966984F, + 0.4680358644F, 0.4719756548F, 0.4759157726F, 0.4798559209F, + 0.4837958024F, 0.4877351199F, 0.4916735765F, 0.4956108751F, + 0.4995467188F, 0.5034808109F, 0.5074128550F, 0.5113425550F, + 0.5152696149F, 0.5191937395F, 0.5231146336F, 0.5270320028F, + 0.5309455530F, 0.5348549910F, 0.5387600239F, 0.5426603597F, + 0.5465557070F, 0.5504457754F, 0.5543302752F, 0.5582089175F, + 0.5620814145F, 0.5659474793F, 0.5698068262F, 0.5736591704F, + 0.5775042283F, 0.5813417176F, 0.5851713571F, 0.5889928670F, + 0.5928059689F, 0.5966103856F, 0.6004058415F, 0.6041920626F, + 0.6079687761F, 0.6117357113F, 0.6154925986F, 0.6192391705F, + 0.6229751612F, 0.6267003064F, 0.6304143441F, 0.6341170137F, + 0.6378080569F, 0.6414872173F, 0.6451542405F, 0.6488088741F, + 0.6524508681F, 0.6560799742F, 0.6596959469F, 0.6632985424F, + 0.6668875197F, 0.6704626398F, 0.6740236662F, 0.6775703649F, + 0.6811025043F, 0.6846198554F, 0.6881221916F, 0.6916092892F, + 0.6950809269F, 0.6985368861F, 0.7019769510F, 0.7054009085F, + 0.7088085484F, 0.7121996632F, 0.7155740484F, 0.7189315023F, + 0.7222718263F, 0.7255948245F, 0.7289003043F, 0.7321880760F, + 0.7354579530F, 0.7387097518F, 0.7419432921F, 0.7451583966F, + 0.7483548915F, 0.7515326059F, 0.7546913723F, 0.7578310265F, + 0.7609514077F, 0.7640523581F, 0.7671337237F, 0.7701953535F, + 0.7732371001F, 0.7762588195F, 0.7792603711F, 0.7822416178F, + 0.7852024259F, 0.7881426654F, 0.7910622097F, 0.7939609356F, + 0.7968387237F, 0.7996954579F, 0.8025310261F, 0.8053453193F, + 0.8081382324F, 0.8109096638F, 0.8136595156F, 0.8163876936F, + 0.8190941071F, 0.8217786690F, 0.8244412960F, 0.8270819086F, + 0.8297004305F, 0.8322967896F, 0.8348709171F, 0.8374227481F, + 0.8399522213F, 0.8424592789F, 0.8449438672F, 0.8474059356F, + 0.8498454378F, 0.8522623306F, 0.8546565748F, 0.8570281348F, + 0.8593769787F, 0.8617030779F, 0.8640064080F, 0.8662869477F, + 0.8685446796F, 0.8707795899F, 0.8729916682F, 0.8751809079F, + 0.8773473059F, 0.8794908626F, 0.8816115819F, 0.8837094713F, + 0.8857845418F, 0.8878368079F, 0.8898662874F, 0.8918730019F, + 0.8938569760F, 0.8958182380F, 0.8977568194F, 0.8996727552F, + 0.9015660837F, 0.9034368465F, 0.9052850885F, 0.9071108577F, + 0.9089142057F, 0.9106951869F, 0.9124538591F, 0.9141902832F, + 0.9159045233F, 0.9175966464F, 0.9192667228F, 0.9209148257F, + 0.9225410313F, 0.9241454187F, 0.9257280701F, 0.9272890704F, + 0.9288285075F, 0.9303464720F, 0.9318430576F, 0.9333183603F, + 0.9347724792F, 0.9362055158F, 0.9376175745F, 0.9390087622F, + 0.9403791881F, 0.9417289644F, 0.9430582055F, 0.9443670283F, + 0.9456555521F, 0.9469238986F, 0.9481721917F, 0.9494005577F, + 0.9506091252F, 0.9517980248F, 0.9529673894F, 0.9541173540F, + 0.9552480557F, 0.9563596334F, 0.9574522282F, 0.9585259830F, + 0.9595810428F, 0.9606175542F, 0.9616356656F, 0.9626355274F, + 0.9636172915F, 0.9645811114F, 0.9655271425F, 0.9664555414F, + 0.9673664664F, 0.9682600774F, 0.9691365355F, 0.9699960034F, + 0.9708386448F, 0.9716646250F, 0.9724741103F, 0.9732672685F, + 0.9740442683F, 0.9748052795F, 0.9755504729F, 0.9762800205F, + 0.9769940950F, 0.9776928703F, 0.9783765210F, 0.9790452223F, + 0.9796991504F, 0.9803384823F, 0.9809633954F, 0.9815740679F, + 0.9821706784F, 0.9827534063F, 0.9833224312F, 0.9838779332F, + 0.9844200928F, 0.9849490910F, 0.9854651087F, 0.9859683274F, + 0.9864589286F, 0.9869370940F, 0.9874030054F, 0.9878568447F, + 0.9882987937F, 0.9887290343F, 0.9891477481F, 0.9895551169F, + 0.9899513220F, 0.9903365446F, 0.9907109658F, 0.9910747662F, + 0.9914281260F, 0.9917712252F, 0.9921042433F, 0.9924273593F, + 0.9927407516F, 0.9930445982F, 0.9933390763F, 0.9936243626F, + 0.9939006331F, 0.9941680631F, 0.9944268269F, 0.9946770982F, + 0.9949190498F, 0.9951528537F, 0.9953786808F, 0.9955967011F, + 0.9958070836F, 0.9960099963F, 0.9962056061F, 0.9963940787F, + 0.9965755786F, 0.9967502693F, 0.9969183129F, 0.9970798704F, + 0.9972351013F, 0.9973841640F, 0.9975272151F, 0.9976644103F, + 0.9977959036F, 0.9979218476F, 0.9980423932F, 0.9981576901F, + 0.9982678862F, 0.9983731278F, 0.9984735596F, 0.9985693247F, + 0.9986605645F, 0.9987474186F, 0.9988300248F, 0.9989085193F, + 0.9989830364F, 0.9990537085F, 0.9991206662F, 0.9991840382F, + 0.9992439513F, 0.9993005303F, 0.9993538982F, 0.9994041757F, + 0.9994514817F, 0.9994959330F, 0.9995376444F, 0.9995767286F, + 0.9996132960F, 0.9996474550F, 0.9996793121F, 0.9997089710F, + 0.9997365339F, 0.9997621003F, 0.9997857677F, 0.9998076311F, + 0.9998277836F, 0.9998463156F, 0.9998633155F, 0.9998788692F, + 0.9998930603F, 0.9999059701F, 0.9999176774F, 0.9999282586F, + 0.9999377880F, 0.9999463370F, 0.9999539749F, 0.9999607685F, + 0.9999667820F, 0.9999720773F, 0.9999767136F, 0.9999807479F, + 0.9999842344F, 0.9999872249F, 0.9999897688F, 0.9999919127F, + 0.9999937009F, 0.9999951749F, 0.9999963738F, 0.9999973342F, + 0.9999980900F, 0.9999986724F, 0.9999991103F, 0.9999994297F, + 0.9999996543F, 0.9999998049F, 0.9999999000F, 0.9999999552F, + 0.9999999836F, 0.9999999957F, 0.9999999994F, 1.0000000000F, +}; + +DECLARE_ALIGNED(16, static const float, vwin2048)[1024] = { + 0.0000009241F, 0.0000083165F, 0.0000231014F, 0.0000452785F, + 0.0000748476F, 0.0001118085F, 0.0001561608F, 0.0002079041F, + 0.0002670379F, 0.0003335617F, 0.0004074748F, 0.0004887765F, + 0.0005774661F, 0.0006735427F, 0.0007770054F, 0.0008878533F, + 0.0010060853F, 0.0011317002F, 0.0012646969F, 0.0014050742F, + 0.0015528307F, 0.0017079650F, 0.0018704756F, 0.0020403610F, + 0.0022176196F, 0.0024022497F, 0.0025942495F, 0.0027936173F, + 0.0030003511F, 0.0032144490F, 0.0034359088F, 0.0036647286F, + 0.0039009061F, 0.0041444391F, 0.0043953253F, 0.0046535621F, + 0.0049191472F, 0.0051920781F, 0.0054723520F, 0.0057599664F, + 0.0060549184F, 0.0063572052F, 0.0066668239F, 0.0069837715F, + 0.0073080449F, 0.0076396410F, 0.0079785566F, 0.0083247884F, + 0.0086783330F, 0.0090391871F, 0.0094073470F, 0.0097828092F, + 0.0101655700F, 0.0105556258F, 0.0109529726F, 0.0113576065F, + 0.0117695237F, 0.0121887200F, 0.0126151913F, 0.0130489335F, + 0.0134899422F, 0.0139382130F, 0.0143937415F, 0.0148565233F, + 0.0153265536F, 0.0158038279F, 0.0162883413F, 0.0167800889F, + 0.0172790660F, 0.0177852675F, 0.0182986882F, 0.0188193231F, + 0.0193471668F, 0.0198822141F, 0.0204244594F, 0.0209738974F, + 0.0215305225F, 0.0220943289F, 0.0226653109F, 0.0232434627F, + 0.0238287784F, 0.0244212519F, 0.0250208772F, 0.0256276481F, + 0.0262415582F, 0.0268626014F, 0.0274907711F, 0.0281260608F, + 0.0287684638F, 0.0294179736F, 0.0300745833F, 0.0307382859F, + 0.0314090747F, 0.0320869424F, 0.0327718819F, 0.0334638860F, + 0.0341629474F, 0.0348690586F, 0.0355822122F, 0.0363024004F, + 0.0370296157F, 0.0377638502F, 0.0385050960F, 0.0392533451F, + 0.0400085896F, 0.0407708211F, 0.0415400315F, 0.0423162123F, + 0.0430993552F, 0.0438894515F, 0.0446864926F, 0.0454904698F, + 0.0463013742F, 0.0471191969F, 0.0479439288F, 0.0487755607F, + 0.0496140836F, 0.0504594879F, 0.0513117642F, 0.0521709031F, + 0.0530368949F, 0.0539097297F, 0.0547893979F, 0.0556758894F, + 0.0565691941F, 0.0574693019F, 0.0583762026F, 0.0592898858F, + 0.0602103410F, 0.0611375576F, 0.0620715250F, 0.0630122324F, + 0.0639596688F, 0.0649138234F, 0.0658746848F, 0.0668422421F, + 0.0678164838F, 0.0687973985F, 0.0697849746F, 0.0707792005F, + 0.0717800645F, 0.0727875547F, 0.0738016591F, 0.0748223656F, + 0.0758496620F, 0.0768835359F, 0.0779239751F, 0.0789709668F, + 0.0800244985F, 0.0810845574F, 0.0821511306F, 0.0832242052F, + 0.0843037679F, 0.0853898056F, 0.0864823050F, 0.0875812525F, + 0.0886866347F, 0.0897984378F, 0.0909166480F, 0.0920412513F, + 0.0931722338F, 0.0943095813F, 0.0954532795F, 0.0966033140F, + 0.0977596702F, 0.0989223336F, 0.1000912894F, 0.1012665227F, + 0.1024480185F, 0.1036357616F, 0.1048297369F, 0.1060299290F, + 0.1072363224F, 0.1084489014F, 0.1096676504F, 0.1108925534F, + 0.1121235946F, 0.1133607577F, 0.1146040267F, 0.1158533850F, + 0.1171088163F, 0.1183703040F, 0.1196378312F, 0.1209113812F, + 0.1221909370F, 0.1234764815F, 0.1247679974F, 0.1260654674F, + 0.1273688740F, 0.1286781995F, 0.1299934263F, 0.1313145365F, + 0.1326415121F, 0.1339743349F, 0.1353129866F, 0.1366574490F, + 0.1380077035F, 0.1393637315F, 0.1407255141F, 0.1420930325F, + 0.1434662677F, 0.1448452004F, 0.1462298115F, 0.1476200814F, + 0.1490159906F, 0.1504175195F, 0.1518246482F, 0.1532373569F, + 0.1546556253F, 0.1560794333F, 0.1575087606F, 0.1589435866F, + 0.1603838909F, 0.1618296526F, 0.1632808509F, 0.1647374648F, + 0.1661994731F, 0.1676668546F, 0.1691395880F, 0.1706176516F, + 0.1721010238F, 0.1735896829F, 0.1750836068F, 0.1765827736F, + 0.1780871610F, 0.1795967468F, 0.1811115084F, 0.1826314234F, + 0.1841564689F, 0.1856866221F, 0.1872218600F, 0.1887621595F, + 0.1903074974F, 0.1918578503F, 0.1934131947F, 0.1949735068F, + 0.1965387630F, 0.1981089393F, 0.1996840117F, 0.2012639560F, + 0.2028487479F, 0.2044383630F, 0.2060327766F, 0.2076319642F, + 0.2092359007F, 0.2108445614F, 0.2124579211F, 0.2140759545F, + 0.2156986364F, 0.2173259411F, 0.2189578432F, 0.2205943168F, + 0.2222353361F, 0.2238808751F, 0.2255309076F, 0.2271854073F, + 0.2288443480F, 0.2305077030F, 0.2321754457F, 0.2338475493F, + 0.2355239869F, 0.2372047315F, 0.2388897560F, 0.2405790329F, + 0.2422725350F, 0.2439702347F, 0.2456721043F, 0.2473781159F, + 0.2490882418F, 0.2508024539F, 0.2525207240F, 0.2542430237F, + 0.2559693248F, 0.2576995986F, 0.2594338166F, 0.2611719498F, + 0.2629139695F, 0.2646598466F, 0.2664095520F, 0.2681630564F, + 0.2699203304F, 0.2716813445F, 0.2734460691F, 0.2752144744F, + 0.2769865307F, 0.2787622079F, 0.2805414760F, 0.2823243047F, + 0.2841106637F, 0.2859005227F, 0.2876938509F, 0.2894906179F, + 0.2912907928F, 0.2930943447F, 0.2949012426F, 0.2967114554F, + 0.2985249520F, 0.3003417009F, 0.3021616708F, 0.3039848301F, + 0.3058111471F, 0.3076405901F, 0.3094731273F, 0.3113087266F, + 0.3131473560F, 0.3149889833F, 0.3168335762F, 0.3186811024F, + 0.3205315294F, 0.3223848245F, 0.3242409552F, 0.3260998886F, + 0.3279615918F, 0.3298260319F, 0.3316931758F, 0.3335629903F, + 0.3354354423F, 0.3373104982F, 0.3391881247F, 0.3410682882F, + 0.3429509551F, 0.3448360917F, 0.3467236642F, 0.3486136387F, + 0.3505059811F, 0.3524006575F, 0.3542976336F, 0.3561968753F, + 0.3580983482F, 0.3600020179F, 0.3619078499F, 0.3638158096F, + 0.3657258625F, 0.3676379737F, 0.3695521086F, 0.3714682321F, + 0.3733863094F, 0.3753063055F, 0.3772281852F, 0.3791519134F, + 0.3810774548F, 0.3830047742F, 0.3849338362F, 0.3868646053F, + 0.3887970459F, 0.3907311227F, 0.3926667998F, 0.3946040417F, + 0.3965428125F, 0.3984830765F, 0.4004247978F, 0.4023679403F, + 0.4043124683F, 0.4062583455F, 0.4082055359F, 0.4101540034F, + 0.4121037117F, 0.4140546246F, 0.4160067058F, 0.4179599190F, + 0.4199142277F, 0.4218695956F, 0.4238259861F, 0.4257833627F, + 0.4277416888F, 0.4297009279F, 0.4316610433F, 0.4336219983F, + 0.4355837562F, 0.4375462803F, 0.4395095337F, 0.4414734797F, + 0.4434380815F, 0.4454033021F, 0.4473691046F, 0.4493354521F, + 0.4513023078F, 0.4532696345F, 0.4552373954F, 0.4572055533F, + 0.4591740713F, 0.4611429123F, 0.4631120393F, 0.4650814151F, + 0.4670510028F, 0.4690207650F, 0.4709906649F, 0.4729606651F, + 0.4749307287F, 0.4769008185F, 0.4788708972F, 0.4808409279F, + 0.4828108732F, 0.4847806962F, 0.4867503597F, 0.4887198264F, + 0.4906890593F, 0.4926580213F, 0.4946266753F, 0.4965949840F, + 0.4985629105F, 0.5005304176F, 0.5024974683F, 0.5044640255F, + 0.5064300522F, 0.5083955114F, 0.5103603659F, 0.5123245790F, + 0.5142881136F, 0.5162509328F, 0.5182129997F, 0.5201742774F, + 0.5221347290F, 0.5240943178F, 0.5260530070F, 0.5280107598F, + 0.5299675395F, 0.5319233095F, 0.5338780330F, 0.5358316736F, + 0.5377841946F, 0.5397355596F, 0.5416857320F, 0.5436346755F, + 0.5455823538F, 0.5475287304F, 0.5494737691F, 0.5514174337F, + 0.5533596881F, 0.5553004962F, 0.5572398218F, 0.5591776291F, + 0.5611138821F, 0.5630485449F, 0.5649815818F, 0.5669129570F, + 0.5688426349F, 0.5707705799F, 0.5726967564F, 0.5746211290F, + 0.5765436624F, 0.5784643212F, 0.5803830702F, 0.5822998743F, + 0.5842146984F, 0.5861275076F, 0.5880382669F, 0.5899469416F, + 0.5918534968F, 0.5937578981F, 0.5956601107F, 0.5975601004F, + 0.5994578326F, 0.6013532732F, 0.6032463880F, 0.6051371429F, + 0.6070255039F, 0.6089114372F, 0.6107949090F, 0.6126758856F, + 0.6145543334F, 0.6164302191F, 0.6183035092F, 0.6201741706F, + 0.6220421700F, 0.6239074745F, 0.6257700513F, 0.6276298674F, + 0.6294868903F, 0.6313410873F, 0.6331924262F, 0.6350408745F, + 0.6368864001F, 0.6387289710F, 0.6405685552F, 0.6424051209F, + 0.6442386364F, 0.6460690702F, 0.6478963910F, 0.6497205673F, + 0.6515415682F, 0.6533593625F, 0.6551739194F, 0.6569852082F, + 0.6587931984F, 0.6605978593F, 0.6623991609F, 0.6641970728F, + 0.6659915652F, 0.6677826081F, 0.6695701718F, 0.6713542268F, + 0.6731347437F, 0.6749116932F, 0.6766850461F, 0.6784547736F, + 0.6802208469F, 0.6819832374F, 0.6837419164F, 0.6854968559F, + 0.6872480275F, 0.6889954034F, 0.6907389556F, 0.6924786566F, + 0.6942144788F, 0.6959463950F, 0.6976743780F, 0.6993984008F, + 0.7011184365F, 0.7028344587F, 0.7045464407F, 0.7062543564F, + 0.7079581796F, 0.7096578844F, 0.7113534450F, 0.7130448359F, + 0.7147320316F, 0.7164150070F, 0.7180937371F, 0.7197681970F, + 0.7214383620F, 0.7231042077F, 0.7247657098F, 0.7264228443F, + 0.7280755871F, 0.7297239147F, 0.7313678035F, 0.7330072301F, + 0.7346421715F, 0.7362726046F, 0.7378985069F, 0.7395198556F, + 0.7411366285F, 0.7427488034F, 0.7443563584F, 0.7459592717F, + 0.7475575218F, 0.7491510873F, 0.7507399471F, 0.7523240803F, + 0.7539034661F, 0.7554780839F, 0.7570479136F, 0.7586129349F, + 0.7601731279F, 0.7617284730F, 0.7632789506F, 0.7648245416F, + 0.7663652267F, 0.7679009872F, 0.7694318044F, 0.7709576599F, + 0.7724785354F, 0.7739944130F, 0.7755052749F, 0.7770111035F, + 0.7785118815F, 0.7800075916F, 0.7814982170F, 0.7829837410F, + 0.7844641472F, 0.7859394191F, 0.7874095408F, 0.7888744965F, + 0.7903342706F, 0.7917888476F, 0.7932382124F, 0.7946823501F, + 0.7961212460F, 0.7975548855F, 0.7989832544F, 0.8004063386F, + 0.8018241244F, 0.8032365981F, 0.8046437463F, 0.8060455560F, + 0.8074420141F, 0.8088331080F, 0.8102188253F, 0.8115991536F, + 0.8129740810F, 0.8143435957F, 0.8157076861F, 0.8170663409F, + 0.8184195489F, 0.8197672994F, 0.8211095817F, 0.8224463853F, + 0.8237777001F, 0.8251035161F, 0.8264238235F, 0.8277386129F, + 0.8290478750F, 0.8303516008F, 0.8316497814F, 0.8329424083F, + 0.8342294731F, 0.8355109677F, 0.8367868841F, 0.8380572148F, + 0.8393219523F, 0.8405810893F, 0.8418346190F, 0.8430825345F, + 0.8443248294F, 0.8455614974F, 0.8467925323F, 0.8480179285F, + 0.8492376802F, 0.8504517822F, 0.8516602292F, 0.8528630164F, + 0.8540601391F, 0.8552515928F, 0.8564373733F, 0.8576174766F, + 0.8587918990F, 0.8599606368F, 0.8611236868F, 0.8622810460F, + 0.8634327113F, 0.8645786802F, 0.8657189504F, 0.8668535195F, + 0.8679823857F, 0.8691055472F, 0.8702230025F, 0.8713347503F, + 0.8724407896F, 0.8735411194F, 0.8746357394F, 0.8757246489F, + 0.8768078479F, 0.8778853364F, 0.8789571146F, 0.8800231832F, + 0.8810835427F, 0.8821381942F, 0.8831871387F, 0.8842303777F, + 0.8852679127F, 0.8862997456F, 0.8873258784F, 0.8883463132F, + 0.8893610527F, 0.8903700994F, 0.8913734562F, 0.8923711263F, + 0.8933631129F, 0.8943494196F, 0.8953300500F, 0.8963050083F, + 0.8972742985F, 0.8982379249F, 0.8991958922F, 0.9001482052F, + 0.9010948688F, 0.9020358883F, 0.9029712690F, 0.9039010165F, + 0.9048251367F, 0.9057436357F, 0.9066565195F, 0.9075637946F, + 0.9084654678F, 0.9093615456F, 0.9102520353F, 0.9111369440F, + 0.9120162792F, 0.9128900484F, 0.9137582595F, 0.9146209204F, + 0.9154780394F, 0.9163296248F, 0.9171756853F, 0.9180162296F, + 0.9188512667F, 0.9196808057F, 0.9205048559F, 0.9213234270F, + 0.9221365285F, 0.9229441704F, 0.9237463629F, 0.9245431160F, + 0.9253344404F, 0.9261203465F, 0.9269008453F, 0.9276759477F, + 0.9284456648F, 0.9292100080F, 0.9299689889F, 0.9307226190F, + 0.9314709103F, 0.9322138747F, 0.9329515245F, 0.9336838721F, + 0.9344109300F, 0.9351327108F, 0.9358492275F, 0.9365604931F, + 0.9372665208F, 0.9379673239F, 0.9386629160F, 0.9393533107F, + 0.9400385220F, 0.9407185637F, 0.9413934501F, 0.9420631954F, + 0.9427278141F, 0.9433873208F, 0.9440417304F, 0.9446910576F, + 0.9453353176F, 0.9459745255F, 0.9466086968F, 0.9472378469F, + 0.9478619915F, 0.9484811463F, 0.9490953274F, 0.9497045506F, + 0.9503088323F, 0.9509081888F, 0.9515026365F, 0.9520921921F, + 0.9526768723F, 0.9532566940F, 0.9538316742F, 0.9544018300F, + 0.9549671786F, 0.9555277375F, 0.9560835241F, 0.9566345562F, + 0.9571808513F, 0.9577224275F, 0.9582593027F, 0.9587914949F, + 0.9593190225F, 0.9598419038F, 0.9603601571F, 0.9608738012F, + 0.9613828546F, 0.9618873361F, 0.9623872646F, 0.9628826591F, + 0.9633735388F, 0.9638599227F, 0.9643418303F, 0.9648192808F, + 0.9652922939F, 0.9657608890F, 0.9662250860F, 0.9666849046F, + 0.9671403646F, 0.9675914861F, 0.9680382891F, 0.9684807937F, + 0.9689190202F, 0.9693529890F, 0.9697827203F, 0.9702082347F, + 0.9706295529F, 0.9710466953F, 0.9714596828F, 0.9718685362F, + 0.9722732762F, 0.9726739240F, 0.9730705005F, 0.9734630267F, + 0.9738515239F, 0.9742360134F, 0.9746165163F, 0.9749930540F, + 0.9753656481F, 0.9757343198F, 0.9760990909F, 0.9764599829F, + 0.9768170175F, 0.9771702164F, 0.9775196013F, 0.9778651941F, + 0.9782070167F, 0.9785450909F, 0.9788794388F, 0.9792100824F, + 0.9795370437F, 0.9798603449F, 0.9801800080F, 0.9804960554F, + 0.9808085092F, 0.9811173916F, 0.9814227251F, 0.9817245318F, + 0.9820228343F, 0.9823176549F, 0.9826090160F, 0.9828969402F, + 0.9831814498F, 0.9834625674F, 0.9837403156F, 0.9840147169F, + 0.9842857939F, 0.9845535692F, 0.9848180654F, 0.9850793052F, + 0.9853373113F, 0.9855921062F, 0.9858437127F, 0.9860921535F, + 0.9863374512F, 0.9865796287F, 0.9868187085F, 0.9870547136F, + 0.9872876664F, 0.9875175899F, 0.9877445067F, 0.9879684396F, + 0.9881894112F, 0.9884074444F, 0.9886225619F, 0.9888347863F, + 0.9890441404F, 0.9892506468F, 0.9894543284F, 0.9896552077F, + 0.9898533074F, 0.9900486502F, 0.9902412587F, 0.9904311555F, + 0.9906183633F, 0.9908029045F, 0.9909848019F, 0.9911640779F, + 0.9913407550F, 0.9915148557F, 0.9916864025F, 0.9918554179F, + 0.9920219241F, 0.9921859437F, 0.9923474989F, 0.9925066120F, + 0.9926633054F, 0.9928176012F, 0.9929695218F, 0.9931190891F, + 0.9932663254F, 0.9934112527F, 0.9935538932F, 0.9936942686F, + 0.9938324012F, 0.9939683126F, 0.9941020248F, 0.9942335597F, + 0.9943629388F, 0.9944901841F, 0.9946153170F, 0.9947383593F, + 0.9948593325F, 0.9949782579F, 0.9950951572F, 0.9952100516F, + 0.9953229625F, 0.9954339111F, 0.9955429186F, 0.9956500062F, + 0.9957551948F, 0.9958585056F, 0.9959599593F, 0.9960595769F, + 0.9961573792F, 0.9962533869F, 0.9963476206F, 0.9964401009F, + 0.9965308483F, 0.9966198833F, 0.9967072261F, 0.9967928971F, + 0.9968769164F, 0.9969593041F, 0.9970400804F, 0.9971192651F, + 0.9971968781F, 0.9972729391F, 0.9973474680F, 0.9974204842F, + 0.9974920074F, 0.9975620569F, 0.9976306521F, 0.9976978122F, + 0.9977635565F, 0.9978279039F, 0.9978908736F, 0.9979524842F, + 0.9980127547F, 0.9980717037F, 0.9981293499F, 0.9981857116F, + 0.9982408073F, 0.9982946554F, 0.9983472739F, 0.9983986810F, + 0.9984488947F, 0.9984979328F, 0.9985458132F, 0.9985925534F, + 0.9986381711F, 0.9986826838F, 0.9987261086F, 0.9987684630F, + 0.9988097640F, 0.9988500286F, 0.9988892738F, 0.9989275163F, + 0.9989647727F, 0.9990010597F, 0.9990363938F, 0.9990707911F, + 0.9991042679F, 0.9991368404F, 0.9991685244F, 0.9991993358F, + 0.9992292905F, 0.9992584038F, 0.9992866914F, 0.9993141686F, + 0.9993408506F, 0.9993667526F, 0.9993918895F, 0.9994162761F, + 0.9994399273F, 0.9994628576F, 0.9994850815F, 0.9995066133F, + 0.9995274672F, 0.9995476574F, 0.9995671978F, 0.9995861021F, + 0.9996043841F, 0.9996220573F, 0.9996391352F, 0.9996556310F, + 0.9996715579F, 0.9996869288F, 0.9997017568F, 0.9997160543F, + 0.9997298342F, 0.9997431088F, 0.9997558905F, 0.9997681914F, + 0.9997800236F, 0.9997913990F, 0.9998023292F, 0.9998128261F, + 0.9998229009F, 0.9998325650F, 0.9998418296F, 0.9998507058F, + 0.9998592044F, 0.9998673362F, 0.9998751117F, 0.9998825415F, + 0.9998896358F, 0.9998964047F, 0.9999028584F, 0.9999090066F, + 0.9999148590F, 0.9999204253F, 0.9999257148F, 0.9999307368F, + 0.9999355003F, 0.9999400144F, 0.9999442878F, 0.9999483293F, + 0.9999521472F, 0.9999557499F, 0.9999591457F, 0.9999623426F, + 0.9999653483F, 0.9999681708F, 0.9999708175F, 0.9999732959F, + 0.9999756132F, 0.9999777765F, 0.9999797928F, 0.9999816688F, + 0.9999834113F, 0.9999850266F, 0.9999865211F, 0.9999879009F, + 0.9999891721F, 0.9999903405F, 0.9999914118F, 0.9999923914F, + 0.9999932849F, 0.9999940972F, 0.9999948336F, 0.9999954989F, + 0.9999960978F, 0.9999966349F, 0.9999971146F, 0.9999975411F, + 0.9999979185F, 0.9999982507F, 0.9999985414F, 0.9999987944F, + 0.9999990129F, 0.9999992003F, 0.9999993596F, 0.9999994939F, + 0.9999996059F, 0.9999996981F, 0.9999997732F, 0.9999998333F, + 0.9999998805F, 0.9999999170F, 0.9999999444F, 0.9999999643F, + 0.9999999784F, 0.9999999878F, 0.9999999937F, 0.9999999972F, + 0.9999999990F, 0.9999999997F, 1.0000000000F, 1.0000000000F, +}; + +DECLARE_ALIGNED(16, static const float, vwin4096)[2048] = { + 0.0000002310F, 0.0000020791F, 0.0000057754F, 0.0000113197F, + 0.0000187121F, 0.0000279526F, 0.0000390412F, 0.0000519777F, + 0.0000667623F, 0.0000833949F, 0.0001018753F, 0.0001222036F, + 0.0001443798F, 0.0001684037F, 0.0001942754F, 0.0002219947F, + 0.0002515616F, 0.0002829761F, 0.0003162380F, 0.0003513472F, + 0.0003883038F, 0.0004271076F, 0.0004677584F, 0.0005102563F, + 0.0005546011F, 0.0006007928F, 0.0006488311F, 0.0006987160F, + 0.0007504474F, 0.0008040251F, 0.0008594490F, 0.0009167191F, + 0.0009758351F, 0.0010367969F, 0.0010996044F, 0.0011642574F, + 0.0012307558F, 0.0012990994F, 0.0013692880F, 0.0014413216F, + 0.0015151998F, 0.0015909226F, 0.0016684898F, 0.0017479011F, + 0.0018291565F, 0.0019122556F, 0.0019971983F, 0.0020839845F, + 0.0021726138F, 0.0022630861F, 0.0023554012F, 0.0024495588F, + 0.0025455588F, 0.0026434008F, 0.0027430847F, 0.0028446103F, + 0.0029479772F, 0.0030531853F, 0.0031602342F, 0.0032691238F, + 0.0033798538F, 0.0034924239F, 0.0036068338F, 0.0037230833F, + 0.0038411721F, 0.0039610999F, 0.0040828664F, 0.0042064714F, + 0.0043319145F, 0.0044591954F, 0.0045883139F, 0.0047192696F, + 0.0048520622F, 0.0049866914F, 0.0051231569F, 0.0052614583F, + 0.0054015953F, 0.0055435676F, 0.0056873748F, 0.0058330166F, + 0.0059804926F, 0.0061298026F, 0.0062809460F, 0.0064339226F, + 0.0065887320F, 0.0067453738F, 0.0069038476F, 0.0070641531F, + 0.0072262899F, 0.0073902575F, 0.0075560556F, 0.0077236838F, + 0.0078931417F, 0.0080644288F, 0.0082375447F, 0.0084124891F, + 0.0085892615F, 0.0087678614F, 0.0089482885F, 0.0091305422F, + 0.0093146223F, 0.0095005281F, 0.0096882592F, 0.0098778153F, + 0.0100691958F, 0.0102624002F, 0.0104574281F, 0.0106542791F, + 0.0108529525F, 0.0110534480F, 0.0112557651F, 0.0114599032F, + 0.0116658618F, 0.0118736405F, 0.0120832387F, 0.0122946560F, + 0.0125078917F, 0.0127229454F, 0.0129398166F, 0.0131585046F, + 0.0133790090F, 0.0136013292F, 0.0138254647F, 0.0140514149F, + 0.0142791792F, 0.0145087572F, 0.0147401481F, 0.0149733515F, + 0.0152083667F, 0.0154451932F, 0.0156838304F, 0.0159242777F, + 0.0161665345F, 0.0164106001F, 0.0166564741F, 0.0169041557F, + 0.0171536443F, 0.0174049393F, 0.0176580401F, 0.0179129461F, + 0.0181696565F, 0.0184281708F, 0.0186884883F, 0.0189506084F, + 0.0192145303F, 0.0194802535F, 0.0197477772F, 0.0200171008F, + 0.0202882236F, 0.0205611449F, 0.0208358639F, 0.0211123801F, + 0.0213906927F, 0.0216708011F, 0.0219527043F, 0.0222364019F, + 0.0225218930F, 0.0228091769F, 0.0230982529F, 0.0233891203F, + 0.0236817782F, 0.0239762259F, 0.0242724628F, 0.0245704880F, + 0.0248703007F, 0.0251719002F, 0.0254752858F, 0.0257804565F, + 0.0260874117F, 0.0263961506F, 0.0267066722F, 0.0270189760F, + 0.0273330609F, 0.0276489263F, 0.0279665712F, 0.0282859949F, + 0.0286071966F, 0.0289301753F, 0.0292549303F, 0.0295814607F, + 0.0299097656F, 0.0302398442F, 0.0305716957F, 0.0309053191F, + 0.0312407135F, 0.0315778782F, 0.0319168122F, 0.0322575145F, + 0.0325999844F, 0.0329442209F, 0.0332902231F, 0.0336379900F, + 0.0339875208F, 0.0343388146F, 0.0346918703F, 0.0350466871F, + 0.0354032640F, 0.0357616000F, 0.0361216943F, 0.0364835458F, + 0.0368471535F, 0.0372125166F, 0.0375796339F, 0.0379485046F, + 0.0383191276F, 0.0386915020F, 0.0390656267F, 0.0394415008F, + 0.0398191231F, 0.0401984927F, 0.0405796086F, 0.0409624698F, + 0.0413470751F, 0.0417334235F, 0.0421215141F, 0.0425113457F, + 0.0429029172F, 0.0432962277F, 0.0436912760F, 0.0440880610F, + 0.0444865817F, 0.0448868370F, 0.0452888257F, 0.0456925468F, + 0.0460979992F, 0.0465051816F, 0.0469140931F, 0.0473247325F, + 0.0477370986F, 0.0481511902F, 0.0485670064F, 0.0489845458F, + 0.0494038074F, 0.0498247899F, 0.0502474922F, 0.0506719131F, + 0.0510980514F, 0.0515259060F, 0.0519554756F, 0.0523867590F, + 0.0528197550F, 0.0532544624F, 0.0536908800F, 0.0541290066F, + 0.0545688408F, 0.0550103815F, 0.0554536274F, 0.0558985772F, + 0.0563452297F, 0.0567935837F, 0.0572436377F, 0.0576953907F, + 0.0581488412F, 0.0586039880F, 0.0590608297F, 0.0595193651F, + 0.0599795929F, 0.0604415117F, 0.0609051202F, 0.0613704170F, + 0.0618374009F, 0.0623060704F, 0.0627764243F, 0.0632484611F, + 0.0637221795F, 0.0641975781F, 0.0646746555F, 0.0651534104F, + 0.0656338413F, 0.0661159469F, 0.0665997257F, 0.0670851763F, + 0.0675722973F, 0.0680610873F, 0.0685515448F, 0.0690436684F, + 0.0695374567F, 0.0700329081F, 0.0705300213F, 0.0710287947F, + 0.0715292269F, 0.0720313163F, 0.0725350616F, 0.0730404612F, + 0.0735475136F, 0.0740562172F, 0.0745665707F, 0.0750785723F, + 0.0755922207F, 0.0761075143F, 0.0766244515F, 0.0771430307F, + 0.0776632505F, 0.0781851092F, 0.0787086052F, 0.0792337371F, + 0.0797605032F, 0.0802889018F, 0.0808189315F, 0.0813505905F, + 0.0818838773F, 0.0824187903F, 0.0829553277F, 0.0834934881F, + 0.0840332697F, 0.0845746708F, 0.0851176899F, 0.0856623252F, + 0.0862085751F, 0.0867564379F, 0.0873059119F, 0.0878569954F, + 0.0884096867F, 0.0889639840F, 0.0895198858F, 0.0900773902F, + 0.0906364955F, 0.0911972000F, 0.0917595019F, 0.0923233995F, + 0.0928888909F, 0.0934559745F, 0.0940246485F, 0.0945949110F, + 0.0951667604F, 0.0957401946F, 0.0963152121F, 0.0968918109F, + 0.0974699893F, 0.0980497454F, 0.0986310773F, 0.0992139832F, + 0.0997984614F, 0.1003845098F, 0.1009721267F, 0.1015613101F, + 0.1021520582F, 0.1027443692F, 0.1033382410F, 0.1039336718F, + 0.1045306597F, 0.1051292027F, 0.1057292990F, 0.1063309466F, + 0.1069341435F, 0.1075388878F, 0.1081451776F, 0.1087530108F, + 0.1093623856F, 0.1099732998F, 0.1105857516F, 0.1111997389F, + 0.1118152597F, 0.1124323121F, 0.1130508939F, 0.1136710032F, + 0.1142926379F, 0.1149157960F, 0.1155404755F, 0.1161666742F, + 0.1167943901F, 0.1174236211F, 0.1180543652F, 0.1186866202F, + 0.1193203841F, 0.1199556548F, 0.1205924300F, 0.1212307078F, + 0.1218704860F, 0.1225117624F, 0.1231545349F, 0.1237988013F, + 0.1244445596F, 0.1250918074F, 0.1257405427F, 0.1263907632F, + 0.1270424667F, 0.1276956512F, 0.1283503142F, 0.1290064537F, + 0.1296640674F, 0.1303231530F, 0.1309837084F, 0.1316457312F, + 0.1323092193F, 0.1329741703F, 0.1336405820F, 0.1343084520F, + 0.1349777782F, 0.1356485582F, 0.1363207897F, 0.1369944704F, + 0.1376695979F, 0.1383461700F, 0.1390241842F, 0.1397036384F, + 0.1403845300F, 0.1410668567F, 0.1417506162F, 0.1424358061F, + 0.1431224240F, 0.1438104674F, 0.1444999341F, 0.1451908216F, + 0.1458831274F, 0.1465768492F, 0.1472719844F, 0.1479685308F, + 0.1486664857F, 0.1493658468F, 0.1500666115F, 0.1507687775F, + 0.1514723422F, 0.1521773031F, 0.1528836577F, 0.1535914035F, + 0.1543005380F, 0.1550110587F, 0.1557229631F, 0.1564362485F, + 0.1571509124F, 0.1578669524F, 0.1585843657F, 0.1593031499F, + 0.1600233024F, 0.1607448205F, 0.1614677017F, 0.1621919433F, + 0.1629175428F, 0.1636444975F, 0.1643728047F, 0.1651024619F, + 0.1658334665F, 0.1665658156F, 0.1672995067F, 0.1680345371F, + 0.1687709041F, 0.1695086050F, 0.1702476372F, 0.1709879978F, + 0.1717296843F, 0.1724726938F, 0.1732170237F, 0.1739626711F, + 0.1747096335F, 0.1754579079F, 0.1762074916F, 0.1769583819F, + 0.1777105760F, 0.1784640710F, 0.1792188642F, 0.1799749529F, + 0.1807323340F, 0.1814910049F, 0.1822509628F, 0.1830122046F, + 0.1837747277F, 0.1845385292F, 0.1853036062F, 0.1860699558F, + 0.1868375751F, 0.1876064613F, 0.1883766114F, 0.1891480226F, + 0.1899206919F, 0.1906946164F, 0.1914697932F, 0.1922462194F, + 0.1930238919F, 0.1938028079F, 0.1945829643F, 0.1953643583F, + 0.1961469868F, 0.1969308468F, 0.1977159353F, 0.1985022494F, + 0.1992897859F, 0.2000785420F, 0.2008685145F, 0.2016597005F, + 0.2024520968F, 0.2032457005F, 0.2040405084F, 0.2048365175F, + 0.2056337247F, 0.2064321269F, 0.2072317211F, 0.2080325041F, + 0.2088344727F, 0.2096376240F, 0.2104419547F, 0.2112474618F, + 0.2120541420F, 0.2128619923F, 0.2136710094F, 0.2144811902F, + 0.2152925315F, 0.2161050301F, 0.2169186829F, 0.2177334866F, + 0.2185494381F, 0.2193665340F, 0.2201847712F, 0.2210041465F, + 0.2218246565F, 0.2226462981F, 0.2234690680F, 0.2242929629F, + 0.2251179796F, 0.2259441147F, 0.2267713650F, 0.2275997272F, + 0.2284291979F, 0.2292597739F, 0.2300914518F, 0.2309242283F, + 0.2317581001F, 0.2325930638F, 0.2334291160F, 0.2342662534F, + 0.2351044727F, 0.2359437703F, 0.2367841431F, 0.2376255875F, + 0.2384681001F, 0.2393116776F, 0.2401563165F, 0.2410020134F, + 0.2418487649F, 0.2426965675F, 0.2435454178F, 0.2443953122F, + 0.2452462474F, 0.2460982199F, 0.2469512262F, 0.2478052628F, + 0.2486603262F, 0.2495164129F, 0.2503735194F, 0.2512316421F, + 0.2520907776F, 0.2529509222F, 0.2538120726F, 0.2546742250F, + 0.2555373760F, 0.2564015219F, 0.2572666593F, 0.2581327845F, + 0.2589998939F, 0.2598679840F, 0.2607370510F, 0.2616070916F, + 0.2624781019F, 0.2633500783F, 0.2642230173F, 0.2650969152F, + 0.2659717684F, 0.2668475731F, 0.2677243257F, 0.2686020226F, + 0.2694806601F, 0.2703602344F, 0.2712407419F, 0.2721221789F, + 0.2730045417F, 0.2738878265F, 0.2747720297F, 0.2756571474F, + 0.2765431760F, 0.2774301117F, 0.2783179508F, 0.2792066895F, + 0.2800963240F, 0.2809868505F, 0.2818782654F, 0.2827705647F, + 0.2836637447F, 0.2845578016F, 0.2854527315F, 0.2863485307F, + 0.2872451953F, 0.2881427215F, 0.2890411055F, 0.2899403433F, + 0.2908404312F, 0.2917413654F, 0.2926431418F, 0.2935457567F, + 0.2944492061F, 0.2953534863F, 0.2962585932F, 0.2971645230F, + 0.2980712717F, 0.2989788356F, 0.2998872105F, 0.3007963927F, + 0.3017063781F, 0.3026171629F, 0.3035287430F, 0.3044411145F, + 0.3053542736F, 0.3062682161F, 0.3071829381F, 0.3080984356F, + 0.3090147047F, 0.3099317413F, 0.3108495414F, 0.3117681011F, + 0.3126874163F, 0.3136074830F, 0.3145282972F, 0.3154498548F, + 0.3163721517F, 0.3172951841F, 0.3182189477F, 0.3191434385F, + 0.3200686525F, 0.3209945856F, 0.3219212336F, 0.3228485927F, + 0.3237766585F, 0.3247054271F, 0.3256348943F, 0.3265650560F, + 0.3274959081F, 0.3284274465F, 0.3293596671F, 0.3302925657F, + 0.3312261382F, 0.3321603804F, 0.3330952882F, 0.3340308574F, + 0.3349670838F, 0.3359039634F, 0.3368414919F, 0.3377796651F, + 0.3387184789F, 0.3396579290F, 0.3405980113F, 0.3415387216F, + 0.3424800556F, 0.3434220091F, 0.3443645779F, 0.3453077578F, + 0.3462515446F, 0.3471959340F, 0.3481409217F, 0.3490865036F, + 0.3500326754F, 0.3509794328F, 0.3519267715F, 0.3528746873F, + 0.3538231759F, 0.3547722330F, 0.3557218544F, 0.3566720357F, + 0.3576227727F, 0.3585740610F, 0.3595258964F, 0.3604782745F, + 0.3614311910F, 0.3623846417F, 0.3633386221F, 0.3642931280F, + 0.3652481549F, 0.3662036987F, 0.3671597548F, 0.3681163191F, + 0.3690733870F, 0.3700309544F, 0.3709890167F, 0.3719475696F, + 0.3729066089F, 0.3738661299F, 0.3748261285F, 0.3757866002F, + 0.3767475406F, 0.3777089453F, 0.3786708100F, 0.3796331302F, + 0.3805959014F, 0.3815591194F, 0.3825227796F, 0.3834868777F, + 0.3844514093F, 0.3854163698F, 0.3863817549F, 0.3873475601F, + 0.3883137810F, 0.3892804131F, 0.3902474521F, 0.3912148933F, + 0.3921827325F, 0.3931509650F, 0.3941195865F, 0.3950885925F, + 0.3960579785F, 0.3970277400F, 0.3979978725F, 0.3989683716F, + 0.3999392328F, 0.4009104516F, 0.4018820234F, 0.4028539438F, + 0.4038262084F, 0.4047988125F, 0.4057717516F, 0.4067450214F, + 0.4077186172F, 0.4086925345F, 0.4096667688F, 0.4106413155F, + 0.4116161703F, 0.4125913284F, 0.4135667854F, 0.4145425368F, + 0.4155185780F, 0.4164949044F, 0.4174715116F, 0.4184483949F, + 0.4194255498F, 0.4204029718F, 0.4213806563F, 0.4223585987F, + 0.4233367946F, 0.4243152392F, 0.4252939281F, 0.4262728566F, + 0.4272520202F, 0.4282314144F, 0.4292110345F, 0.4301908760F, + 0.4311709343F, 0.4321512047F, 0.4331316828F, 0.4341123639F, + 0.4350932435F, 0.4360743168F, 0.4370555794F, 0.4380370267F, + 0.4390186540F, 0.4400004567F, 0.4409824303F, 0.4419645701F, + 0.4429468716F, 0.4439293300F, 0.4449119409F, 0.4458946996F, + 0.4468776014F, 0.4478606418F, 0.4488438162F, 0.4498271199F, + 0.4508105483F, 0.4517940967F, 0.4527777607F, 0.4537615355F, + 0.4547454165F, 0.4557293991F, 0.4567134786F, 0.4576976505F, + 0.4586819101F, 0.4596662527F, 0.4606506738F, 0.4616351687F, + 0.4626197328F, 0.4636043614F, 0.4645890499F, 0.4655737936F, + 0.4665585880F, 0.4675434284F, 0.4685283101F, 0.4695132286F, + 0.4704981791F, 0.4714831570F, 0.4724681577F, 0.4734531766F, + 0.4744382089F, 0.4754232501F, 0.4764082956F, 0.4773933406F, + 0.4783783806F, 0.4793634108F, 0.4803484267F, 0.4813334237F, + 0.4823183969F, 0.4833033419F, 0.4842882540F, 0.4852731285F, + 0.4862579608F, 0.4872427462F, 0.4882274802F, 0.4892121580F, + 0.4901967751F, 0.4911813267F, 0.4921658083F, 0.4931502151F, + 0.4941345427F, 0.4951187863F, 0.4961029412F, 0.4970870029F, + 0.4980709667F, 0.4990548280F, 0.5000385822F, 0.5010222245F, + 0.5020057505F, 0.5029891553F, 0.5039724345F, 0.5049555834F, + 0.5059385973F, 0.5069214716F, 0.5079042018F, 0.5088867831F, + 0.5098692110F, 0.5108514808F, 0.5118335879F, 0.5128155277F, + 0.5137972956F, 0.5147788869F, 0.5157602971F, 0.5167415215F, + 0.5177225555F, 0.5187033945F, 0.5196840339F, 0.5206644692F, + 0.5216446956F, 0.5226247086F, 0.5236045035F, 0.5245840759F, + 0.5255634211F, 0.5265425344F, 0.5275214114F, 0.5285000474F, + 0.5294784378F, 0.5304565781F, 0.5314344637F, 0.5324120899F, + 0.5333894522F, 0.5343665461F, 0.5353433670F, 0.5363199102F, + 0.5372961713F, 0.5382721457F, 0.5392478287F, 0.5402232159F, + 0.5411983027F, 0.5421730845F, 0.5431475569F, 0.5441217151F, + 0.5450955548F, 0.5460690714F, 0.5470422602F, 0.5480151169F, + 0.5489876368F, 0.5499598155F, 0.5509316484F, 0.5519031310F, + 0.5528742587F, 0.5538450271F, 0.5548154317F, 0.5557854680F, + 0.5567551314F, 0.5577244174F, 0.5586933216F, 0.5596618395F, + 0.5606299665F, 0.5615976983F, 0.5625650302F, 0.5635319580F, + 0.5644984770F, 0.5654645828F, 0.5664302709F, 0.5673955370F, + 0.5683603765F, 0.5693247850F, 0.5702887580F, 0.5712522912F, + 0.5722153800F, 0.5731780200F, 0.5741402069F, 0.5751019362F, + 0.5760632034F, 0.5770240042F, 0.5779843341F, 0.5789441889F, + 0.5799035639F, 0.5808624549F, 0.5818208575F, 0.5827787673F, + 0.5837361800F, 0.5846930910F, 0.5856494961F, 0.5866053910F, + 0.5875607712F, 0.5885156324F, 0.5894699703F, 0.5904237804F, + 0.5913770586F, 0.5923298004F, 0.5932820016F, 0.5942336578F, + 0.5951847646F, 0.5961353179F, 0.5970853132F, 0.5980347464F, + 0.5989836131F, 0.5999319090F, 0.6008796298F, 0.6018267713F, + 0.6027733292F, 0.6037192993F, 0.6046646773F, 0.6056094589F, + 0.6065536400F, 0.6074972162F, 0.6084401833F, 0.6093825372F, + 0.6103242736F, 0.6112653884F, 0.6122058772F, 0.6131457359F, + 0.6140849604F, 0.6150235464F, 0.6159614897F, 0.6168987862F, + 0.6178354318F, 0.6187714223F, 0.6197067535F, 0.6206414213F, + 0.6215754215F, 0.6225087501F, 0.6234414028F, 0.6243733757F, + 0.6253046646F, 0.6262352654F, 0.6271651739F, 0.6280943862F, + 0.6290228982F, 0.6299507057F, 0.6308778048F, 0.6318041913F, + 0.6327298612F, 0.6336548105F, 0.6345790352F, 0.6355025312F, + 0.6364252945F, 0.6373473211F, 0.6382686070F, 0.6391891483F, + 0.6401089409F, 0.6410279808F, 0.6419462642F, 0.6428637869F, + 0.6437805452F, 0.6446965350F, 0.6456117524F, 0.6465261935F, + 0.6474398544F, 0.6483527311F, 0.6492648197F, 0.6501761165F, + 0.6510866174F, 0.6519963186F, 0.6529052162F, 0.6538133064F, + 0.6547205854F, 0.6556270492F, 0.6565326941F, 0.6574375162F, + 0.6583415117F, 0.6592446769F, 0.6601470079F, 0.6610485009F, + 0.6619491521F, 0.6628489578F, 0.6637479143F, 0.6646460177F, + 0.6655432643F, 0.6664396505F, 0.6673351724F, 0.6682298264F, + 0.6691236087F, 0.6700165157F, 0.6709085436F, 0.6717996889F, + 0.6726899478F, 0.6735793167F, 0.6744677918F, 0.6753553697F, + 0.6762420466F, 0.6771278190F, 0.6780126832F, 0.6788966357F, + 0.6797796728F, 0.6806617909F, 0.6815429866F, 0.6824232562F, + 0.6833025961F, 0.6841810030F, 0.6850584731F, 0.6859350031F, + 0.6868105894F, 0.6876852284F, 0.6885589168F, 0.6894316510F, + 0.6903034275F, 0.6911742430F, 0.6920440939F, 0.6929129769F, + 0.6937808884F, 0.6946478251F, 0.6955137837F, 0.6963787606F, + 0.6972427525F, 0.6981057560F, 0.6989677678F, 0.6998287845F, + 0.7006888028F, 0.7015478194F, 0.7024058309F, 0.7032628340F, + 0.7041188254F, 0.7049738019F, 0.7058277601F, 0.7066806969F, + 0.7075326089F, 0.7083834929F, 0.7092333457F, 0.7100821640F, + 0.7109299447F, 0.7117766846F, 0.7126223804F, 0.7134670291F, + 0.7143106273F, 0.7151531721F, 0.7159946602F, 0.7168350885F, + 0.7176744539F, 0.7185127534F, 0.7193499837F, 0.7201861418F, + 0.7210212247F, 0.7218552293F, 0.7226881526F, 0.7235199914F, + 0.7243507428F, 0.7251804039F, 0.7260089715F, 0.7268364426F, + 0.7276628144F, 0.7284880839F, 0.7293122481F, 0.7301353040F, + 0.7309572487F, 0.7317780794F, 0.7325977930F, 0.7334163868F, + 0.7342338579F, 0.7350502033F, 0.7358654202F, 0.7366795059F, + 0.7374924573F, 0.7383042718F, 0.7391149465F, 0.7399244787F, + 0.7407328655F, 0.7415401041F, 0.7423461920F, 0.7431511261F, + 0.7439549040F, 0.7447575227F, 0.7455589797F, 0.7463592723F, + 0.7471583976F, 0.7479563532F, 0.7487531363F, 0.7495487443F, + 0.7503431745F, 0.7511364244F, 0.7519284913F, 0.7527193726F, + 0.7535090658F, 0.7542975683F, 0.7550848776F, 0.7558709910F, + 0.7566559062F, 0.7574396205F, 0.7582221314F, 0.7590034366F, + 0.7597835334F, 0.7605624194F, 0.7613400923F, 0.7621165495F, + 0.7628917886F, 0.7636658072F, 0.7644386030F, 0.7652101735F, + 0.7659805164F, 0.7667496292F, 0.7675175098F, 0.7682841556F, + 0.7690495645F, 0.7698137341F, 0.7705766622F, 0.7713383463F, + 0.7720987844F, 0.7728579741F, 0.7736159132F, 0.7743725994F, + 0.7751280306F, 0.7758822046F, 0.7766351192F, 0.7773867722F, + 0.7781371614F, 0.7788862848F, 0.7796341401F, 0.7803807253F, + 0.7811260383F, 0.7818700769F, 0.7826128392F, 0.7833543230F, + 0.7840945263F, 0.7848334471F, 0.7855710833F, 0.7863074330F, + 0.7870424941F, 0.7877762647F, 0.7885087428F, 0.7892399264F, + 0.7899698137F, 0.7906984026F, 0.7914256914F, 0.7921516780F, + 0.7928763607F, 0.7935997375F, 0.7943218065F, 0.7950425661F, + 0.7957620142F, 0.7964801492F, 0.7971969692F, 0.7979124724F, + 0.7986266570F, 0.7993395214F, 0.8000510638F, 0.8007612823F, + 0.8014701754F, 0.8021777413F, 0.8028839784F, 0.8035888849F, + 0.8042924592F, 0.8049946997F, 0.8056956048F, 0.8063951727F, + 0.8070934020F, 0.8077902910F, 0.8084858381F, 0.8091800419F, + 0.8098729007F, 0.8105644130F, 0.8112545774F, 0.8119433922F, + 0.8126308561F, 0.8133169676F, 0.8140017251F, 0.8146851272F, + 0.8153671726F, 0.8160478598F, 0.8167271874F, 0.8174051539F, + 0.8180817582F, 0.8187569986F, 0.8194308741F, 0.8201033831F, + 0.8207745244F, 0.8214442966F, 0.8221126986F, 0.8227797290F, + 0.8234453865F, 0.8241096700F, 0.8247725781F, 0.8254341097F, + 0.8260942636F, 0.8267530385F, 0.8274104334F, 0.8280664470F, + 0.8287210782F, 0.8293743259F, 0.8300261889F, 0.8306766662F, + 0.8313257566F, 0.8319734591F, 0.8326197727F, 0.8332646963F, + 0.8339082288F, 0.8345503692F, 0.8351911167F, 0.8358304700F, + 0.8364684284F, 0.8371049907F, 0.8377401562F, 0.8383739238F, + 0.8390062927F, 0.8396372618F, 0.8402668305F, 0.8408949977F, + 0.8415217626F, 0.8421471245F, 0.8427710823F, 0.8433936354F, + 0.8440147830F, 0.8446345242F, 0.8452528582F, 0.8458697844F, + 0.8464853020F, 0.8470994102F, 0.8477121084F, 0.8483233958F, + 0.8489332718F, 0.8495417356F, 0.8501487866F, 0.8507544243F, + 0.8513586479F, 0.8519614568F, 0.8525628505F, 0.8531628283F, + 0.8537613897F, 0.8543585341F, 0.8549542611F, 0.8555485699F, + 0.8561414603F, 0.8567329315F, 0.8573229832F, 0.8579116149F, + 0.8584988262F, 0.8590846165F, 0.8596689855F, 0.8602519327F, + 0.8608334577F, 0.8614135603F, 0.8619922399F, 0.8625694962F, + 0.8631453289F, 0.8637197377F, 0.8642927222F, 0.8648642821F, + 0.8654344172F, 0.8660031272F, 0.8665704118F, 0.8671362708F, + 0.8677007039F, 0.8682637109F, 0.8688252917F, 0.8693854460F, + 0.8699441737F, 0.8705014745F, 0.8710573485F, 0.8716117953F, + 0.8721648150F, 0.8727164073F, 0.8732665723F, 0.8738153098F, + 0.8743626197F, 0.8749085021F, 0.8754529569F, 0.8759959840F, + 0.8765375835F, 0.8770777553F, 0.8776164996F, 0.8781538162F, + 0.8786897054F, 0.8792241670F, 0.8797572013F, 0.8802888082F, + 0.8808189880F, 0.8813477407F, 0.8818750664F, 0.8824009653F, + 0.8829254375F, 0.8834484833F, 0.8839701028F, 0.8844902961F, + 0.8850090636F, 0.8855264054F, 0.8860423218F, 0.8865568131F, + 0.8870698794F, 0.8875815212F, 0.8880917386F, 0.8886005319F, + 0.8891079016F, 0.8896138479F, 0.8901183712F, 0.8906214719F, + 0.8911231503F, 0.8916234067F, 0.8921222417F, 0.8926196556F, + 0.8931156489F, 0.8936102219F, 0.8941033752F, 0.8945951092F, + 0.8950854244F, 0.8955743212F, 0.8960618003F, 0.8965478621F, + 0.8970325071F, 0.8975157359F, 0.8979975490F, 0.8984779471F, + 0.8989569307F, 0.8994345004F, 0.8999106568F, 0.9003854005F, + 0.9008587323F, 0.9013306526F, 0.9018011623F, 0.9022702619F, + 0.9027379521F, 0.9032042337F, 0.9036691074F, 0.9041325739F, + 0.9045946339F, 0.9050552882F, 0.9055145376F, 0.9059723828F, + 0.9064288246F, 0.9068838638F, 0.9073375013F, 0.9077897379F, + 0.9082405743F, 0.9086900115F, 0.9091380503F, 0.9095846917F, + 0.9100299364F, 0.9104737854F, 0.9109162397F, 0.9113573001F, + 0.9117969675F, 0.9122352430F, 0.9126721275F, 0.9131076219F, + 0.9135417273F, 0.9139744447F, 0.9144057750F, 0.9148357194F, + 0.9152642787F, 0.9156914542F, 0.9161172468F, 0.9165416576F, + 0.9169646877F, 0.9173863382F, 0.9178066102F, 0.9182255048F, + 0.9186430232F, 0.9190591665F, 0.9194739359F, 0.9198873324F, + 0.9202993574F, 0.9207100120F, 0.9211192973F, 0.9215272147F, + 0.9219337653F, 0.9223389504F, 0.9227427713F, 0.9231452290F, + 0.9235463251F, 0.9239460607F, 0.9243444371F, 0.9247414557F, + 0.9251371177F, 0.9255314245F, 0.9259243774F, 0.9263159778F, + 0.9267062270F, 0.9270951264F, 0.9274826774F, 0.9278688814F, + 0.9282537398F, 0.9286372540F, 0.9290194254F, 0.9294002555F, + 0.9297797458F, 0.9301578976F, 0.9305347125F, 0.9309101919F, + 0.9312843373F, 0.9316571503F, 0.9320286323F, 0.9323987849F, + 0.9327676097F, 0.9331351080F, 0.9335012816F, 0.9338661320F, + 0.9342296607F, 0.9345918694F, 0.9349527596F, 0.9353123330F, + 0.9356705911F, 0.9360275357F, 0.9363831683F, 0.9367374905F, + 0.9370905042F, 0.9374422108F, 0.9377926122F, 0.9381417099F, + 0.9384895057F, 0.9388360014F, 0.9391811985F, 0.9395250989F, + 0.9398677043F, 0.9402090165F, 0.9405490371F, 0.9408877680F, + 0.9412252110F, 0.9415613678F, 0.9418962402F, 0.9422298301F, + 0.9425621392F, 0.9428931695F, 0.9432229226F, 0.9435514005F, + 0.9438786050F, 0.9442045381F, 0.9445292014F, 0.9448525971F, + 0.9451747268F, 0.9454955926F, 0.9458151963F, 0.9461335399F, + 0.9464506253F, 0.9467664545F, 0.9470810293F, 0.9473943517F, + 0.9477064238F, 0.9480172474F, 0.9483268246F, 0.9486351573F, + 0.9489422475F, 0.9492480973F, 0.9495527087F, 0.9498560837F, + 0.9501582243F, 0.9504591325F, 0.9507588105F, 0.9510572603F, + 0.9513544839F, 0.9516504834F, 0.9519452609F, 0.9522388186F, + 0.9525311584F, 0.9528222826F, 0.9531121932F, 0.9534008923F, + 0.9536883821F, 0.9539746647F, 0.9542597424F, 0.9545436171F, + 0.9548262912F, 0.9551077667F, 0.9553880459F, 0.9556671309F, + 0.9559450239F, 0.9562217272F, 0.9564972429F, 0.9567715733F, + 0.9570447206F, 0.9573166871F, 0.9575874749F, 0.9578570863F, + 0.9581255236F, 0.9583927890F, 0.9586588849F, 0.9589238134F, + 0.9591875769F, 0.9594501777F, 0.9597116180F, 0.9599719003F, + 0.9602310267F, 0.9604889995F, 0.9607458213F, 0.9610014942F, + 0.9612560206F, 0.9615094028F, 0.9617616433F, 0.9620127443F, + 0.9622627083F, 0.9625115376F, 0.9627592345F, 0.9630058016F, + 0.9632512411F, 0.9634955555F, 0.9637387471F, 0.9639808185F, + 0.9642217720F, 0.9644616100F, 0.9647003349F, 0.9649379493F, + 0.9651744556F, 0.9654098561F, 0.9656441534F, 0.9658773499F, + 0.9661094480F, 0.9663404504F, 0.9665703593F, 0.9667991774F, + 0.9670269071F, 0.9672535509F, 0.9674791114F, 0.9677035909F, + 0.9679269921F, 0.9681493174F, 0.9683705694F, 0.9685907506F, + 0.9688098636F, 0.9690279108F, 0.9692448948F, 0.9694608182F, + 0.9696756836F, 0.9698894934F, 0.9701022503F, 0.9703139569F, + 0.9705246156F, 0.9707342291F, 0.9709428000F, 0.9711503309F, + 0.9713568243F, 0.9715622829F, 0.9717667093F, 0.9719701060F, + 0.9721724757F, 0.9723738210F, 0.9725741446F, 0.9727734490F, + 0.9729717369F, 0.9731690109F, 0.9733652737F, 0.9735605279F, + 0.9737547762F, 0.9739480212F, 0.9741402656F, 0.9743315120F, + 0.9745217631F, 0.9747110216F, 0.9748992901F, 0.9750865714F, + 0.9752728681F, 0.9754581829F, 0.9756425184F, 0.9758258775F, + 0.9760082627F, 0.9761896768F, 0.9763701224F, 0.9765496024F, + 0.9767281193F, 0.9769056760F, 0.9770822751F, 0.9772579193F, + 0.9774326114F, 0.9776063542F, 0.9777791502F, 0.9779510023F, + 0.9781219133F, 0.9782918858F, 0.9784609226F, 0.9786290264F, + 0.9787962000F, 0.9789624461F, 0.9791277676F, 0.9792921671F, + 0.9794556474F, 0.9796182113F, 0.9797798615F, 0.9799406009F, + 0.9801004321F, 0.9802593580F, 0.9804173813F, 0.9805745049F, + 0.9807307314F, 0.9808860637F, 0.9810405046F, 0.9811940568F, + 0.9813467232F, 0.9814985065F, 0.9816494095F, 0.9817994351F, + 0.9819485860F, 0.9820968650F, 0.9822442750F, 0.9823908186F, + 0.9825364988F, 0.9826813184F, 0.9828252801F, 0.9829683868F, + 0.9831106413F, 0.9832520463F, 0.9833926048F, 0.9835323195F, + 0.9836711932F, 0.9838092288F, 0.9839464291F, 0.9840827969F, + 0.9842183351F, 0.9843530464F, 0.9844869337F, 0.9846199998F, + 0.9847522475F, 0.9848836798F, 0.9850142993F, 0.9851441090F, + 0.9852731117F, 0.9854013101F, 0.9855287073F, 0.9856553058F, + 0.9857811087F, 0.9859061188F, 0.9860303388F, 0.9861537717F, + 0.9862764202F, 0.9863982872F, 0.9865193756F, 0.9866396882F, + 0.9867592277F, 0.9868779972F, 0.9869959993F, 0.9871132370F, + 0.9872297131F, 0.9873454304F, 0.9874603918F, 0.9875746001F, + 0.9876880581F, 0.9878007688F, 0.9879127348F, 0.9880239592F, + 0.9881344447F, 0.9882441941F, 0.9883532104F, 0.9884614962F, + 0.9885690546F, 0.9886758883F, 0.9887820001F, 0.9888873930F, + 0.9889920697F, 0.9890960331F, 0.9891992859F, 0.9893018312F, + 0.9894036716F, 0.9895048100F, 0.9896052493F, 0.9897049923F, + 0.9898040418F, 0.9899024006F, 0.9900000717F, 0.9900970577F, + 0.9901933616F, 0.9902889862F, 0.9903839343F, 0.9904782087F, + 0.9905718122F, 0.9906647477F, 0.9907570180F, 0.9908486259F, + 0.9909395742F, 0.9910298658F, 0.9911195034F, 0.9912084899F, + 0.9912968281F, 0.9913845208F, 0.9914715708F, 0.9915579810F, + 0.9916437540F, 0.9917288928F, 0.9918134001F, 0.9918972788F, + 0.9919805316F, 0.9920631613F, 0.9921451707F, 0.9922265626F, + 0.9923073399F, 0.9923875052F, 0.9924670615F, 0.9925460114F, + 0.9926243577F, 0.9927021033F, 0.9927792508F, 0.9928558032F, + 0.9929317631F, 0.9930071333F, 0.9930819167F, 0.9931561158F, + 0.9932297337F, 0.9933027728F, 0.9933752362F, 0.9934471264F, + 0.9935184462F, 0.9935891985F, 0.9936593859F, 0.9937290112F, + 0.9937980771F, 0.9938665864F, 0.9939345418F, 0.9940019460F, + 0.9940688018F, 0.9941351118F, 0.9942008789F, 0.9942661057F, + 0.9943307950F, 0.9943949494F, 0.9944585717F, 0.9945216645F, + 0.9945842307F, 0.9946462728F, 0.9947077936F, 0.9947687957F, + 0.9948292820F, 0.9948892550F, 0.9949487174F, 0.9950076719F, + 0.9950661212F, 0.9951240679F, 0.9951815148F, 0.9952384645F, + 0.9952949196F, 0.9953508828F, 0.9954063568F, 0.9954613442F, + 0.9955158476F, 0.9955698697F, 0.9956234132F, 0.9956764806F, + 0.9957290746F, 0.9957811978F, 0.9958328528F, 0.9958840423F, + 0.9959347688F, 0.9959850351F, 0.9960348435F, 0.9960841969F, + 0.9961330977F, 0.9961815486F, 0.9962295521F, 0.9962771108F, + 0.9963242274F, 0.9963709043F, 0.9964171441F, 0.9964629494F, + 0.9965083228F, 0.9965532668F, 0.9965977840F, 0.9966418768F, + 0.9966855479F, 0.9967287998F, 0.9967716350F, 0.9968140559F, + 0.9968560653F, 0.9968976655F, 0.9969388591F, 0.9969796485F, + 0.9970200363F, 0.9970600250F, 0.9970996170F, 0.9971388149F, + 0.9971776211F, 0.9972160380F, 0.9972540683F, 0.9972917142F, + 0.9973289783F, 0.9973658631F, 0.9974023709F, 0.9974385042F, + 0.9974742655F, 0.9975096571F, 0.9975446816F, 0.9975793413F, + 0.9976136386F, 0.9976475759F, 0.9976811557F, 0.9977143803F, + 0.9977472521F, 0.9977797736F, 0.9978119470F, 0.9978437748F, + 0.9978752593F, 0.9979064029F, 0.9979372079F, 0.9979676768F, + 0.9979978117F, 0.9980276151F, 0.9980570893F, 0.9980862367F, + 0.9981150595F, 0.9981435600F, 0.9981717406F, 0.9981996035F, + 0.9982271511F, 0.9982543856F, 0.9982813093F, 0.9983079246F, + 0.9983342336F, 0.9983602386F, 0.9983859418F, 0.9984113456F, + 0.9984364522F, 0.9984612638F, 0.9984857825F, 0.9985100108F, + 0.9985339507F, 0.9985576044F, 0.9985809743F, 0.9986040624F, + 0.9986268710F, 0.9986494022F, 0.9986716583F, 0.9986936413F, + 0.9987153535F, 0.9987367969F, 0.9987579738F, 0.9987788864F, + 0.9987995366F, 0.9988199267F, 0.9988400587F, 0.9988599348F, + 0.9988795572F, 0.9988989278F, 0.9989180487F, 0.9989369222F, + 0.9989555501F, 0.9989739347F, 0.9989920780F, 0.9990099820F, + 0.9990276487F, 0.9990450803F, 0.9990622787F, 0.9990792460F, + 0.9990959841F, 0.9991124952F, 0.9991287812F, 0.9991448440F, + 0.9991606858F, 0.9991763084F, 0.9991917139F, 0.9992069042F, + 0.9992218813F, 0.9992366471F, 0.9992512035F, 0.9992655525F, + 0.9992796961F, 0.9992936361F, 0.9993073744F, 0.9993209131F, + 0.9993342538F, 0.9993473987F, 0.9993603494F, 0.9993731080F, + 0.9993856762F, 0.9993980559F, 0.9994102490F, 0.9994222573F, + 0.9994340827F, 0.9994457269F, 0.9994571918F, 0.9994684793F, + 0.9994795910F, 0.9994905288F, 0.9995012945F, 0.9995118898F, + 0.9995223165F, 0.9995325765F, 0.9995426713F, 0.9995526029F, + 0.9995623728F, 0.9995719829F, 0.9995814349F, 0.9995907304F, + 0.9995998712F, 0.9996088590F, 0.9996176954F, 0.9996263821F, + 0.9996349208F, 0.9996433132F, 0.9996515609F, 0.9996596656F, + 0.9996676288F, 0.9996754522F, 0.9996831375F, 0.9996906862F, + 0.9996981000F, 0.9997053804F, 0.9997125290F, 0.9997195474F, + 0.9997264371F, 0.9997331998F, 0.9997398369F, 0.9997463500F, + 0.9997527406F, 0.9997590103F, 0.9997651606F, 0.9997711930F, + 0.9997771089F, 0.9997829098F, 0.9997885973F, 0.9997941728F, + 0.9997996378F, 0.9998049936F, 0.9998102419F, 0.9998153839F, + 0.9998204211F, 0.9998253550F, 0.9998301868F, 0.9998349182F, + 0.9998395503F, 0.9998440847F, 0.9998485226F, 0.9998528654F, + 0.9998571146F, 0.9998612713F, 0.9998653370F, 0.9998693130F, + 0.9998732007F, 0.9998770012F, 0.9998807159F, 0.9998843461F, + 0.9998878931F, 0.9998913581F, 0.9998947424F, 0.9998980473F, + 0.9999012740F, 0.9999044237F, 0.9999074976F, 0.9999104971F, + 0.9999134231F, 0.9999162771F, 0.9999190601F, 0.9999217733F, + 0.9999244179F, 0.9999269950F, 0.9999295058F, 0.9999319515F, + 0.9999343332F, 0.9999366519F, 0.9999389088F, 0.9999411050F, + 0.9999432416F, 0.9999453196F, 0.9999473402F, 0.9999493044F, + 0.9999512132F, 0.9999530677F, 0.9999548690F, 0.9999566180F, + 0.9999583157F, 0.9999599633F, 0.9999615616F, 0.9999631116F, + 0.9999646144F, 0.9999660709F, 0.9999674820F, 0.9999688487F, + 0.9999701719F, 0.9999714526F, 0.9999726917F, 0.9999738900F, + 0.9999750486F, 0.9999761682F, 0.9999772497F, 0.9999782941F, + 0.9999793021F, 0.9999802747F, 0.9999812126F, 0.9999821167F, + 0.9999829878F, 0.9999838268F, 0.9999846343F, 0.9999854113F, + 0.9999861584F, 0.9999868765F, 0.9999875664F, 0.9999882287F, + 0.9999888642F, 0.9999894736F, 0.9999900577F, 0.9999906172F, + 0.9999911528F, 0.9999916651F, 0.9999921548F, 0.9999926227F, + 0.9999930693F, 0.9999934954F, 0.9999939015F, 0.9999942883F, + 0.9999946564F, 0.9999950064F, 0.9999953390F, 0.9999956547F, + 0.9999959541F, 0.9999962377F, 0.9999965062F, 0.9999967601F, + 0.9999969998F, 0.9999972260F, 0.9999974392F, 0.9999976399F, + 0.9999978285F, 0.9999980056F, 0.9999981716F, 0.9999983271F, + 0.9999984724F, 0.9999986081F, 0.9999987345F, 0.9999988521F, + 0.9999989613F, 0.9999990625F, 0.9999991562F, 0.9999992426F, + 0.9999993223F, 0.9999993954F, 0.9999994625F, 0.9999995239F, + 0.9999995798F, 0.9999996307F, 0.9999996768F, 0.9999997184F, + 0.9999997559F, 0.9999997895F, 0.9999998195F, 0.9999998462F, + 0.9999998698F, 0.9999998906F, 0.9999999088F, 0.9999999246F, + 0.9999999383F, 0.9999999500F, 0.9999999600F, 0.9999999684F, + 0.9999999754F, 0.9999999811F, 0.9999999858F, 0.9999999896F, + 0.9999999925F, 0.9999999948F, 0.9999999965F, 0.9999999978F, + 0.9999999986F, 0.9999999992F, 0.9999999996F, 0.9999999998F, + 0.9999999999F, 1.0000000000F, 1.0000000000F, 1.0000000000F, +}; + +DECLARE_ALIGNED(16, static const float, vwin8192)[4096] = { + 0.0000000578F, 0.0000005198F, 0.0000014438F, 0.0000028299F, + 0.0000046780F, 0.0000069882F, 0.0000097604F, 0.0000129945F, + 0.0000166908F, 0.0000208490F, 0.0000254692F, 0.0000305515F, + 0.0000360958F, 0.0000421021F, 0.0000485704F, 0.0000555006F, + 0.0000628929F, 0.0000707472F, 0.0000790635F, 0.0000878417F, + 0.0000970820F, 0.0001067842F, 0.0001169483F, 0.0001275744F, + 0.0001386625F, 0.0001502126F, 0.0001622245F, 0.0001746984F, + 0.0001876343F, 0.0002010320F, 0.0002148917F, 0.0002292132F, + 0.0002439967F, 0.0002592421F, 0.0002749493F, 0.0002911184F, + 0.0003077493F, 0.0003248421F, 0.0003423967F, 0.0003604132F, + 0.0003788915F, 0.0003978316F, 0.0004172335F, 0.0004370971F, + 0.0004574226F, 0.0004782098F, 0.0004994587F, 0.0005211694F, + 0.0005433418F, 0.0005659759F, 0.0005890717F, 0.0006126292F, + 0.0006366484F, 0.0006611292F, 0.0006860716F, 0.0007114757F, + 0.0007373414F, 0.0007636687F, 0.0007904576F, 0.0008177080F, + 0.0008454200F, 0.0008735935F, 0.0009022285F, 0.0009313250F, + 0.0009608830F, 0.0009909025F, 0.0010213834F, 0.0010523257F, + 0.0010837295F, 0.0011155946F, 0.0011479211F, 0.0011807090F, + 0.0012139582F, 0.0012476687F, 0.0012818405F, 0.0013164736F, + 0.0013515679F, 0.0013871235F, 0.0014231402F, 0.0014596182F, + 0.0014965573F, 0.0015339576F, 0.0015718190F, 0.0016101415F, + 0.0016489251F, 0.0016881698F, 0.0017278754F, 0.0017680421F, + 0.0018086698F, 0.0018497584F, 0.0018913080F, 0.0019333185F, + 0.0019757898F, 0.0020187221F, 0.0020621151F, 0.0021059690F, + 0.0021502837F, 0.0021950591F, 0.0022402953F, 0.0022859921F, + 0.0023321497F, 0.0023787679F, 0.0024258467F, 0.0024733861F, + 0.0025213861F, 0.0025698466F, 0.0026187676F, 0.0026681491F, + 0.0027179911F, 0.0027682935F, 0.0028190562F, 0.0028702794F, + 0.0029219628F, 0.0029741066F, 0.0030267107F, 0.0030797749F, + 0.0031332994F, 0.0031872841F, 0.0032417289F, 0.0032966338F, + 0.0033519988F, 0.0034078238F, 0.0034641089F, 0.0035208539F, + 0.0035780589F, 0.0036357237F, 0.0036938485F, 0.0037524331F, + 0.0038114775F, 0.0038709817F, 0.0039309456F, 0.0039913692F, + 0.0040522524F, 0.0041135953F, 0.0041753978F, 0.0042376599F, + 0.0043003814F, 0.0043635624F, 0.0044272029F, 0.0044913028F, + 0.0045558620F, 0.0046208806F, 0.0046863585F, 0.0047522955F, + 0.0048186919F, 0.0048855473F, 0.0049528619F, 0.0050206356F, + 0.0050888684F, 0.0051575601F, 0.0052267108F, 0.0052963204F, + 0.0053663890F, 0.0054369163F, 0.0055079025F, 0.0055793474F, + 0.0056512510F, 0.0057236133F, 0.0057964342F, 0.0058697137F, + 0.0059434517F, 0.0060176482F, 0.0060923032F, 0.0061674166F, + 0.0062429883F, 0.0063190183F, 0.0063955066F, 0.0064724532F, + 0.0065498579F, 0.0066277207F, 0.0067060416F, 0.0067848205F, + 0.0068640575F, 0.0069437523F, 0.0070239051F, 0.0071045157F, + 0.0071855840F, 0.0072671102F, 0.0073490940F, 0.0074315355F, + 0.0075144345F, 0.0075977911F, 0.0076816052F, 0.0077658768F, + 0.0078506057F, 0.0079357920F, 0.0080214355F, 0.0081075363F, + 0.0081940943F, 0.0082811094F, 0.0083685816F, 0.0084565108F, + 0.0085448970F, 0.0086337401F, 0.0087230401F, 0.0088127969F, + 0.0089030104F, 0.0089936807F, 0.0090848076F, 0.0091763911F, + 0.0092684311F, 0.0093609276F, 0.0094538805F, 0.0095472898F, + 0.0096411554F, 0.0097354772F, 0.0098302552F, 0.0099254894F, + 0.0100211796F, 0.0101173259F, 0.0102139281F, 0.0103109863F, + 0.0104085002F, 0.0105064700F, 0.0106048955F, 0.0107037766F, + 0.0108031133F, 0.0109029056F, 0.0110031534F, 0.0111038565F, + 0.0112050151F, 0.0113066289F, 0.0114086980F, 0.0115112222F, + 0.0116142015F, 0.0117176359F, 0.0118215252F, 0.0119258695F, + 0.0120306686F, 0.0121359225F, 0.0122416312F, 0.0123477944F, + 0.0124544123F, 0.0125614847F, 0.0126690116F, 0.0127769928F, + 0.0128854284F, 0.0129943182F, 0.0131036623F, 0.0132134604F, + 0.0133237126F, 0.0134344188F, 0.0135455790F, 0.0136571929F, + 0.0137692607F, 0.0138817821F, 0.0139947572F, 0.0141081859F, + 0.0142220681F, 0.0143364037F, 0.0144511927F, 0.0145664350F, + 0.0146821304F, 0.0147982791F, 0.0149148808F, 0.0150319355F, + 0.0151494431F, 0.0152674036F, 0.0153858168F, 0.0155046828F, + 0.0156240014F, 0.0157437726F, 0.0158639962F, 0.0159846723F, + 0.0161058007F, 0.0162273814F, 0.0163494142F, 0.0164718991F, + 0.0165948361F, 0.0167182250F, 0.0168420658F, 0.0169663584F, + 0.0170911027F, 0.0172162987F, 0.0173419462F, 0.0174680452F, + 0.0175945956F, 0.0177215974F, 0.0178490504F, 0.0179769545F, + 0.0181053098F, 0.0182341160F, 0.0183633732F, 0.0184930812F, + 0.0186232399F, 0.0187538494F, 0.0188849094F, 0.0190164200F, + 0.0191483809F, 0.0192807923F, 0.0194136539F, 0.0195469656F, + 0.0196807275F, 0.0198149394F, 0.0199496012F, 0.0200847128F, + 0.0202202742F, 0.0203562853F, 0.0204927460F, 0.0206296561F, + 0.0207670157F, 0.0209048245F, 0.0210430826F, 0.0211817899F, + 0.0213209462F, 0.0214605515F, 0.0216006057F, 0.0217411086F, + 0.0218820603F, 0.0220234605F, 0.0221653093F, 0.0223076066F, + 0.0224503521F, 0.0225935459F, 0.0227371879F, 0.0228812779F, + 0.0230258160F, 0.0231708018F, 0.0233162355F, 0.0234621169F, + 0.0236084459F, 0.0237552224F, 0.0239024462F, 0.0240501175F, + 0.0241982359F, 0.0243468015F, 0.0244958141F, 0.0246452736F, + 0.0247951800F, 0.0249455331F, 0.0250963329F, 0.0252475792F, + 0.0253992720F, 0.0255514111F, 0.0257039965F, 0.0258570281F, + 0.0260105057F, 0.0261644293F, 0.0263187987F, 0.0264736139F, + 0.0266288747F, 0.0267845811F, 0.0269407330F, 0.0270973302F, + 0.0272543727F, 0.0274118604F, 0.0275697930F, 0.0277281707F, + 0.0278869932F, 0.0280462604F, 0.0282059723F, 0.0283661287F, + 0.0285267295F, 0.0286877747F, 0.0288492641F, 0.0290111976F, + 0.0291735751F, 0.0293363965F, 0.0294996617F, 0.0296633706F, + 0.0298275231F, 0.0299921190F, 0.0301571583F, 0.0303226409F, + 0.0304885667F, 0.0306549354F, 0.0308217472F, 0.0309890017F, + 0.0311566989F, 0.0313248388F, 0.0314934211F, 0.0316624459F, + 0.0318319128F, 0.0320018220F, 0.0321721732F, 0.0323429663F, + 0.0325142013F, 0.0326858779F, 0.0328579962F, 0.0330305559F, + 0.0332035570F, 0.0333769994F, 0.0335508829F, 0.0337252074F, + 0.0338999728F, 0.0340751790F, 0.0342508259F, 0.0344269134F, + 0.0346034412F, 0.0347804094F, 0.0349578178F, 0.0351356663F, + 0.0353139548F, 0.0354926831F, 0.0356718511F, 0.0358514588F, + 0.0360315059F, 0.0362119924F, 0.0363929182F, 0.0365742831F, + 0.0367560870F, 0.0369383297F, 0.0371210113F, 0.0373041315F, + 0.0374876902F, 0.0376716873F, 0.0378561226F, 0.0380409961F, + 0.0382263077F, 0.0384120571F, 0.0385982443F, 0.0387848691F, + 0.0389719315F, 0.0391594313F, 0.0393473683F, 0.0395357425F, + 0.0397245537F, 0.0399138017F, 0.0401034866F, 0.0402936080F, + 0.0404841660F, 0.0406751603F, 0.0408665909F, 0.0410584576F, + 0.0412507603F, 0.0414434988F, 0.0416366731F, 0.0418302829F, + 0.0420243282F, 0.0422188088F, 0.0424137246F, 0.0426090755F, + 0.0428048613F, 0.0430010819F, 0.0431977371F, 0.0433948269F, + 0.0435923511F, 0.0437903095F, 0.0439887020F, 0.0441875285F, + 0.0443867889F, 0.0445864830F, 0.0447866106F, 0.0449871717F, + 0.0451881661F, 0.0453895936F, 0.0455914542F, 0.0457937477F, + 0.0459964738F, 0.0461996326F, 0.0464032239F, 0.0466072475F, + 0.0468117032F, 0.0470165910F, 0.0472219107F, 0.0474276622F, + 0.0476338452F, 0.0478404597F, 0.0480475056F, 0.0482549827F, + 0.0484628907F, 0.0486712297F, 0.0488799994F, 0.0490891998F, + 0.0492988306F, 0.0495088917F, 0.0497193830F, 0.0499303043F, + 0.0501416554F, 0.0503534363F, 0.0505656468F, 0.0507782867F, + 0.0509913559F, 0.0512048542F, 0.0514187815F, 0.0516331376F, + 0.0518479225F, 0.0520631358F, 0.0522787775F, 0.0524948475F, + 0.0527113455F, 0.0529282715F, 0.0531456252F, 0.0533634066F, + 0.0535816154F, 0.0538002515F, 0.0540193148F, 0.0542388051F, + 0.0544587222F, 0.0546790660F, 0.0548998364F, 0.0551210331F, + 0.0553426561F, 0.0555647051F, 0.0557871801F, 0.0560100807F, + 0.0562334070F, 0.0564571587F, 0.0566813357F, 0.0569059378F, + 0.0571309649F, 0.0573564168F, 0.0575822933F, 0.0578085942F, + 0.0580353195F, 0.0582624689F, 0.0584900423F, 0.0587180396F, + 0.0589464605F, 0.0591753049F, 0.0594045726F, 0.0596342635F, + 0.0598643774F, 0.0600949141F, 0.0603258735F, 0.0605572555F, + 0.0607890597F, 0.0610212862F, 0.0612539346F, 0.0614870049F, + 0.0617204968F, 0.0619544103F, 0.0621887451F, 0.0624235010F, + 0.0626586780F, 0.0628942758F, 0.0631302942F, 0.0633667331F, + 0.0636035923F, 0.0638408717F, 0.0640785710F, 0.0643166901F, + 0.0645552288F, 0.0647941870F, 0.0650335645F, 0.0652733610F, + 0.0655135765F, 0.0657542108F, 0.0659952636F, 0.0662367348F, + 0.0664786242F, 0.0667209316F, 0.0669636570F, 0.0672068000F, + 0.0674503605F, 0.0676943384F, 0.0679387334F, 0.0681835454F, + 0.0684287742F, 0.0686744196F, 0.0689204814F, 0.0691669595F, + 0.0694138536F, 0.0696611637F, 0.0699088894F, 0.0701570307F, + 0.0704055873F, 0.0706545590F, 0.0709039458F, 0.0711537473F, + 0.0714039634F, 0.0716545939F, 0.0719056387F, 0.0721570975F, + 0.0724089702F, 0.0726612565F, 0.0729139563F, 0.0731670694F, + 0.0734205956F, 0.0736745347F, 0.0739288866F, 0.0741836510F, + 0.0744388277F, 0.0746944166F, 0.0749504175F, 0.0752068301F, + 0.0754636543F, 0.0757208899F, 0.0759785367F, 0.0762365946F, + 0.0764950632F, 0.0767539424F, 0.0770132320F, 0.0772729319F, + 0.0775330418F, 0.0777935616F, 0.0780544909F, 0.0783158298F, + 0.0785775778F, 0.0788397349F, 0.0791023009F, 0.0793652755F, + 0.0796286585F, 0.0798924498F, 0.0801566492F, 0.0804212564F, + 0.0806862712F, 0.0809516935F, 0.0812175231F, 0.0814837597F, + 0.0817504031F, 0.0820174532F, 0.0822849097F, 0.0825527724F, + 0.0828210412F, 0.0830897158F, 0.0833587960F, 0.0836282816F, + 0.0838981724F, 0.0841684682F, 0.0844391688F, 0.0847102740F, + 0.0849817835F, 0.0852536973F, 0.0855260150F, 0.0857987364F, + 0.0860718614F, 0.0863453897F, 0.0866193211F, 0.0868936554F, + 0.0871683924F, 0.0874435319F, 0.0877190737F, 0.0879950175F, + 0.0882713632F, 0.0885481105F, 0.0888252592F, 0.0891028091F, + 0.0893807600F, 0.0896591117F, 0.0899378639F, 0.0902170165F, + 0.0904965692F, 0.0907765218F, 0.0910568740F, 0.0913376258F, + 0.0916187767F, 0.0919003268F, 0.0921822756F, 0.0924646230F, + 0.0927473687F, 0.0930305126F, 0.0933140545F, 0.0935979940F, + 0.0938823310F, 0.0941670653F, 0.0944521966F, 0.0947377247F, + 0.0950236494F, 0.0953099704F, 0.0955966876F, 0.0958838007F, + 0.0961713094F, 0.0964592136F, 0.0967475131F, 0.0970362075F, + 0.0973252967F, 0.0976147805F, 0.0979046585F, 0.0981949307F, + 0.0984855967F, 0.0987766563F, 0.0990681093F, 0.0993599555F, + 0.0996521945F, 0.0999448263F, 0.1002378506F, 0.1005312671F, + 0.1008250755F, 0.1011192757F, 0.1014138675F, 0.1017088505F, + 0.1020042246F, 0.1022999895F, 0.1025961450F, 0.1028926909F, + 0.1031896268F, 0.1034869526F, 0.1037846680F, 0.1040827729F, + 0.1043812668F, 0.1046801497F, 0.1049794213F, 0.1052790813F, + 0.1055791294F, 0.1058795656F, 0.1061803894F, 0.1064816006F, + 0.1067831991F, 0.1070851846F, 0.1073875568F, 0.1076903155F, + 0.1079934604F, 0.1082969913F, 0.1086009079F, 0.1089052101F, + 0.1092098975F, 0.1095149699F, 0.1098204270F, 0.1101262687F, + 0.1104324946F, 0.1107391045F, 0.1110460982F, 0.1113534754F, + 0.1116612359F, 0.1119693793F, 0.1122779055F, 0.1125868142F, + 0.1128961052F, 0.1132057781F, 0.1135158328F, 0.1138262690F, + 0.1141370863F, 0.1144482847F, 0.1147598638F, 0.1150718233F, + 0.1153841631F, 0.1156968828F, 0.1160099822F, 0.1163234610F, + 0.1166373190F, 0.1169515559F, 0.1172661714F, 0.1175811654F, + 0.1178965374F, 0.1182122874F, 0.1185284149F, 0.1188449198F, + 0.1191618018F, 0.1194790606F, 0.1197966960F, 0.1201147076F, + 0.1204330953F, 0.1207518587F, 0.1210709976F, 0.1213905118F, + 0.1217104009F, 0.1220306647F, 0.1223513029F, 0.1226723153F, + 0.1229937016F, 0.1233154615F, 0.1236375948F, 0.1239601011F, + 0.1242829803F, 0.1246062319F, 0.1249298559F, 0.1252538518F, + 0.1255782195F, 0.1259029586F, 0.1262280689F, 0.1265535501F, + 0.1268794019F, 0.1272056241F, 0.1275322163F, 0.1278591784F, + 0.1281865099F, 0.1285142108F, 0.1288422805F, 0.1291707190F, + 0.1294995259F, 0.1298287009F, 0.1301582437F, 0.1304881542F, + 0.1308184319F, 0.1311490766F, 0.1314800881F, 0.1318114660F, + 0.1321432100F, 0.1324753200F, 0.1328077955F, 0.1331406364F, + 0.1334738422F, 0.1338074129F, 0.1341413479F, 0.1344756472F, + 0.1348103103F, 0.1351453370F, 0.1354807270F, 0.1358164801F, + 0.1361525959F, 0.1364890741F, 0.1368259145F, 0.1371631167F, + 0.1375006805F, 0.1378386056F, 0.1381768917F, 0.1385155384F, + 0.1388545456F, 0.1391939129F, 0.1395336400F, 0.1398737266F, + 0.1402141724F, 0.1405549772F, 0.1408961406F, 0.1412376623F, + 0.1415795421F, 0.1419217797F, 0.1422643746F, 0.1426073268F, + 0.1429506358F, 0.1432943013F, 0.1436383231F, 0.1439827008F, + 0.1443274342F, 0.1446725229F, 0.1450179667F, 0.1453637652F, + 0.1457099181F, 0.1460564252F, 0.1464032861F, 0.1467505006F, + 0.1470980682F, 0.1474459888F, 0.1477942620F, 0.1481428875F, + 0.1484918651F, 0.1488411942F, 0.1491908748F, 0.1495409065F, + 0.1498912889F, 0.1502420218F, 0.1505931048F, 0.1509445376F, + 0.1512963200F, 0.1516484516F, 0.1520009321F, 0.1523537612F, + 0.1527069385F, 0.1530604638F, 0.1534143368F, 0.1537685571F, + 0.1541231244F, 0.1544780384F, 0.1548332987F, 0.1551889052F, + 0.1555448574F, 0.1559011550F, 0.1562577978F, 0.1566147853F, + 0.1569721173F, 0.1573297935F, 0.1576878135F, 0.1580461771F, + 0.1584048838F, 0.1587639334F, 0.1591233255F, 0.1594830599F, + 0.1598431361F, 0.1602035540F, 0.1605643131F, 0.1609254131F, + 0.1612868537F, 0.1616486346F, 0.1620107555F, 0.1623732160F, + 0.1627360158F, 0.1630991545F, 0.1634626319F, 0.1638264476F, + 0.1641906013F, 0.1645550926F, 0.1649199212F, 0.1652850869F, + 0.1656505892F, 0.1660164278F, 0.1663826024F, 0.1667491127F, + 0.1671159583F, 0.1674831388F, 0.1678506541F, 0.1682185036F, + 0.1685866872F, 0.1689552044F, 0.1693240549F, 0.1696932384F, + 0.1700627545F, 0.1704326029F, 0.1708027833F, 0.1711732952F, + 0.1715441385F, 0.1719153127F, 0.1722868175F, 0.1726586526F, + 0.1730308176F, 0.1734033121F, 0.1737761359F, 0.1741492886F, + 0.1745227698F, 0.1748965792F, 0.1752707164F, 0.1756451812F, + 0.1760199731F, 0.1763950918F, 0.1767705370F, 0.1771463083F, + 0.1775224054F, 0.1778988279F, 0.1782755754F, 0.1786526477F, + 0.1790300444F, 0.1794077651F, 0.1797858094F, 0.1801641771F, + 0.1805428677F, 0.1809218810F, 0.1813012165F, 0.1816808739F, + 0.1820608528F, 0.1824411530F, 0.1828217739F, 0.1832027154F, + 0.1835839770F, 0.1839655584F, 0.1843474592F, 0.1847296790F, + 0.1851122175F, 0.1854950744F, 0.1858782492F, 0.1862617417F, + 0.1866455514F, 0.1870296780F, 0.1874141211F, 0.1877988804F, + 0.1881839555F, 0.1885693461F, 0.1889550517F, 0.1893410721F, + 0.1897274068F, 0.1901140555F, 0.1905010178F, 0.1908882933F, + 0.1912758818F, 0.1916637828F, 0.1920519959F, 0.1924405208F, + 0.1928293571F, 0.1932185044F, 0.1936079625F, 0.1939977308F, + 0.1943878091F, 0.1947781969F, 0.1951688939F, 0.1955598998F, + 0.1959512141F, 0.1963428364F, 0.1967347665F, 0.1971270038F, + 0.1975195482F, 0.1979123990F, 0.1983055561F, 0.1986990190F, + 0.1990927873F, 0.1994868607F, 0.1998812388F, 0.2002759212F, + 0.2006709075F, 0.2010661974F, 0.2014617904F, 0.2018576862F, + 0.2022538844F, 0.2026503847F, 0.2030471865F, 0.2034442897F, + 0.2038416937F, 0.2042393982F, 0.2046374028F, 0.2050357071F, + 0.2054343107F, 0.2058332133F, 0.2062324145F, 0.2066319138F, + 0.2070317110F, 0.2074318055F, 0.2078321970F, 0.2082328852F, + 0.2086338696F, 0.2090351498F, 0.2094367255F, 0.2098385962F, + 0.2102407617F, 0.2106432213F, 0.2110459749F, 0.2114490220F, + 0.2118523621F, 0.2122559950F, 0.2126599202F, 0.2130641373F, + 0.2134686459F, 0.2138734456F, 0.2142785361F, 0.2146839168F, + 0.2150895875F, 0.2154955478F, 0.2159017972F, 0.2163083353F, + 0.2167151617F, 0.2171222761F, 0.2175296780F, 0.2179373670F, + 0.2183453428F, 0.2187536049F, 0.2191621529F, 0.2195709864F, + 0.2199801051F, 0.2203895085F, 0.2207991961F, 0.2212091677F, + 0.2216194228F, 0.2220299610F, 0.2224407818F, 0.2228518850F, + 0.2232632699F, 0.2236749364F, 0.2240868839F, 0.2244991121F, + 0.2249116204F, 0.2253244086F, 0.2257374763F, 0.2261508229F, + 0.2265644481F, 0.2269783514F, 0.2273925326F, 0.2278069911F, + 0.2282217265F, 0.2286367384F, 0.2290520265F, 0.2294675902F, + 0.2298834292F, 0.2302995431F, 0.2307159314F, 0.2311325937F, + 0.2315495297F, 0.2319667388F, 0.2323842207F, 0.2328019749F, + 0.2332200011F, 0.2336382988F, 0.2340568675F, 0.2344757070F, + 0.2348948166F, 0.2353141961F, 0.2357338450F, 0.2361537629F, + 0.2365739493F, 0.2369944038F, 0.2374151261F, 0.2378361156F, + 0.2382573720F, 0.2386788948F, 0.2391006836F, 0.2395227380F, + 0.2399450575F, 0.2403676417F, 0.2407904902F, 0.2412136026F, + 0.2416369783F, 0.2420606171F, 0.2424845185F, 0.2429086820F, + 0.2433331072F, 0.2437577936F, 0.2441827409F, 0.2446079486F, + 0.2450334163F, 0.2454591435F, 0.2458851298F, 0.2463113747F, + 0.2467378779F, 0.2471646389F, 0.2475916573F, 0.2480189325F, + 0.2484464643F, 0.2488742521F, 0.2493022955F, 0.2497305940F, + 0.2501591473F, 0.2505879549F, 0.2510170163F, 0.2514463311F, + 0.2518758989F, 0.2523057193F, 0.2527357916F, 0.2531661157F, + 0.2535966909F, 0.2540275169F, 0.2544585931F, 0.2548899193F, + 0.2553214948F, 0.2557533193F, 0.2561853924F, 0.2566177135F, + 0.2570502822F, 0.2574830981F, 0.2579161608F, 0.2583494697F, + 0.2587830245F, 0.2592168246F, 0.2596508697F, 0.2600851593F, + 0.2605196929F, 0.2609544701F, 0.2613894904F, 0.2618247534F, + 0.2622602586F, 0.2626960055F, 0.2631319938F, 0.2635682230F, + 0.2640046925F, 0.2644414021F, 0.2648783511F, 0.2653155391F, + 0.2657529657F, 0.2661906305F, 0.2666285329F, 0.2670666725F, + 0.2675050489F, 0.2679436616F, 0.2683825101F, 0.2688215940F, + 0.2692609127F, 0.2697004660F, 0.2701402532F, 0.2705802739F, + 0.2710205278F, 0.2714610142F, 0.2719017327F, 0.2723426830F, + 0.2727838644F, 0.2732252766F, 0.2736669191F, 0.2741087914F, + 0.2745508930F, 0.2749932235F, 0.2754357824F, 0.2758785693F, + 0.2763215837F, 0.2767648251F, 0.2772082930F, 0.2776519870F, + 0.2780959066F, 0.2785400513F, 0.2789844207F, 0.2794290143F, + 0.2798738316F, 0.2803188722F, 0.2807641355F, 0.2812096211F, + 0.2816553286F, 0.2821012574F, 0.2825474071F, 0.2829937773F, + 0.2834403673F, 0.2838871768F, 0.2843342053F, 0.2847814523F, + 0.2852289174F, 0.2856765999F, 0.2861244996F, 0.2865726159F, + 0.2870209482F, 0.2874694962F, 0.2879182594F, 0.2883672372F, + 0.2888164293F, 0.2892658350F, 0.2897154540F, 0.2901652858F, + 0.2906153298F, 0.2910655856F, 0.2915160527F, 0.2919667306F, + 0.2924176189F, 0.2928687171F, 0.2933200246F, 0.2937715409F, + 0.2942232657F, 0.2946751984F, 0.2951273386F, 0.2955796856F, + 0.2960322391F, 0.2964849986F, 0.2969379636F, 0.2973911335F, + 0.2978445080F, 0.2982980864F, 0.2987518684F, 0.2992058534F, + 0.2996600409F, 0.3001144305F, 0.3005690217F, 0.3010238139F, + 0.3014788067F, 0.3019339995F, 0.3023893920F, 0.3028449835F, + 0.3033007736F, 0.3037567618F, 0.3042129477F, 0.3046693306F, + 0.3051259102F, 0.3055826859F, 0.3060396572F, 0.3064968236F, + 0.3069541847F, 0.3074117399F, 0.3078694887F, 0.3083274307F, + 0.3087855653F, 0.3092438920F, 0.3097024104F, 0.3101611199F, + 0.3106200200F, 0.3110791103F, 0.3115383902F, 0.3119978592F, + 0.3124575169F, 0.3129173627F, 0.3133773961F, 0.3138376166F, + 0.3142980238F, 0.3147586170F, 0.3152193959F, 0.3156803598F, + 0.3161415084F, 0.3166028410F, 0.3170643573F, 0.3175260566F, + 0.3179879384F, 0.3184500023F, 0.3189122478F, 0.3193746743F, + 0.3198372814F, 0.3203000685F, 0.3207630351F, 0.3212261807F, + 0.3216895048F, 0.3221530069F, 0.3226166865F, 0.3230805430F, + 0.3235445760F, 0.3240087849F, 0.3244731693F, 0.3249377285F, + 0.3254024622F, 0.3258673698F, 0.3263324507F, 0.3267977045F, + 0.3272631306F, 0.3277287286F, 0.3281944978F, 0.3286604379F, + 0.3291265482F, 0.3295928284F, 0.3300592777F, 0.3305258958F, + 0.3309926821F, 0.3314596361F, 0.3319267573F, 0.3323940451F, + 0.3328614990F, 0.3333291186F, 0.3337969033F, 0.3342648525F, + 0.3347329658F, 0.3352012427F, 0.3356696825F, 0.3361382849F, + 0.3366070492F, 0.3370759749F, 0.3375450616F, 0.3380143087F, + 0.3384837156F, 0.3389532819F, 0.3394230071F, 0.3398928905F, + 0.3403629317F, 0.3408331302F, 0.3413034854F, 0.3417739967F, + 0.3422446638F, 0.3427154860F, 0.3431864628F, 0.3436575938F, + 0.3441288782F, 0.3446003158F, 0.3450719058F, 0.3455436478F, + 0.3460155412F, 0.3464875856F, 0.3469597804F, 0.3474321250F, + 0.3479046189F, 0.3483772617F, 0.3488500527F, 0.3493229914F, + 0.3497960774F, 0.3502693100F, 0.3507426887F, 0.3512162131F, + 0.3516898825F, 0.3521636965F, 0.3526376545F, 0.3531117559F, + 0.3535860003F, 0.3540603870F, 0.3545349157F, 0.3550095856F, + 0.3554843964F, 0.3559593474F, 0.3564344381F, 0.3569096680F, + 0.3573850366F, 0.3578605432F, 0.3583361875F, 0.3588119687F, + 0.3592878865F, 0.3597639402F, 0.3602401293F, 0.3607164533F, + 0.3611929117F, 0.3616695038F, 0.3621462292F, 0.3626230873F, + 0.3631000776F, 0.3635771995F, 0.3640544525F, 0.3645318360F, + 0.3650093496F, 0.3654869926F, 0.3659647645F, 0.3664426648F, + 0.3669206930F, 0.3673988484F, 0.3678771306F, 0.3683555390F, + 0.3688340731F, 0.3693127322F, 0.3697915160F, 0.3702704237F, + 0.3707494549F, 0.3712286091F, 0.3717078857F, 0.3721872840F, + 0.3726668037F, 0.3731464441F, 0.3736262047F, 0.3741060850F, + 0.3745860843F, 0.3750662023F, 0.3755464382F, 0.3760267915F, + 0.3765072618F, 0.3769878484F, 0.3774685509F, 0.3779493686F, + 0.3784303010F, 0.3789113475F, 0.3793925076F, 0.3798737809F, + 0.3803551666F, 0.3808366642F, 0.3813182733F, 0.3817999932F, + 0.3822818234F, 0.3827637633F, 0.3832458124F, 0.3837279702F, + 0.3842102360F, 0.3846926093F, 0.3851750897F, 0.3856576764F, + 0.3861403690F, 0.3866231670F, 0.3871060696F, 0.3875890765F, + 0.3880721870F, 0.3885554007F, 0.3890387168F, 0.3895221349F, + 0.3900056544F, 0.3904892748F, 0.3909729955F, 0.3914568160F, + 0.3919407356F, 0.3924247539F, 0.3929088702F, 0.3933930841F, + 0.3938773949F, 0.3943618021F, 0.3948463052F, 0.3953309035F, + 0.3958155966F, 0.3963003838F, 0.3967852646F, 0.3972702385F, + 0.3977553048F, 0.3982404631F, 0.3987257127F, 0.3992110531F, + 0.3996964838F, 0.4001820041F, 0.4006676136F, 0.4011533116F, + 0.4016390976F, 0.4021249710F, 0.4026109313F, 0.4030969779F, + 0.4035831102F, 0.4040693277F, 0.4045556299F, 0.4050420160F, + 0.4055284857F, 0.4060150383F, 0.4065016732F, 0.4069883899F, + 0.4074751879F, 0.4079620665F, 0.4084490252F, 0.4089360635F, + 0.4094231807F, 0.4099103763F, 0.4103976498F, 0.4108850005F, + 0.4113724280F, 0.4118599315F, 0.4123475107F, 0.4128351648F, + 0.4133228934F, 0.4138106959F, 0.4142985716F, 0.4147865201F, + 0.4152745408F, 0.4157626330F, 0.4162507963F, 0.4167390301F, + 0.4172273337F, 0.4177157067F, 0.4182041484F, 0.4186926583F, + 0.4191812359F, 0.4196698805F, 0.4201585915F, 0.4206473685F, + 0.4211362108F, 0.4216251179F, 0.4221140892F, 0.4226031241F, + 0.4230922221F, 0.4235813826F, 0.4240706050F, 0.4245598887F, + 0.4250492332F, 0.4255386379F, 0.4260281022F, 0.4265176256F, + 0.4270072075F, 0.4274968473F, 0.4279865445F, 0.4284762984F, + 0.4289661086F, 0.4294559743F, 0.4299458951F, 0.4304358704F, + 0.4309258996F, 0.4314159822F, 0.4319061175F, 0.4323963050F, + 0.4328865441F, 0.4333768342F, 0.4338671749F, 0.4343575654F, + 0.4348480052F, 0.4353384938F, 0.4358290306F, 0.4363196149F, + 0.4368102463F, 0.4373009241F, 0.4377916478F, 0.4382824168F, + 0.4387732305F, 0.4392640884F, 0.4397549899F, 0.4402459343F, + 0.4407369212F, 0.4412279499F, 0.4417190198F, 0.4422101305F, + 0.4427012813F, 0.4431924717F, 0.4436837010F, 0.4441749686F, + 0.4446662742F, 0.4451576169F, 0.4456489963F, 0.4461404118F, + 0.4466318628F, 0.4471233487F, 0.4476148690F, 0.4481064230F, + 0.4485980103F, 0.4490896302F, 0.4495812821F, 0.4500729654F, + 0.4505646797F, 0.4510564243F, 0.4515481986F, 0.4520400021F, + 0.4525318341F, 0.4530236942F, 0.4535155816F, 0.4540074959F, + 0.4544994365F, 0.4549914028F, 0.4554833941F, 0.4559754100F, + 0.4564674499F, 0.4569595131F, 0.4574515991F, 0.4579437074F, + 0.4584358372F, 0.4589279881F, 0.4594201595F, 0.4599123508F, + 0.4604045615F, 0.4608967908F, 0.4613890383F, 0.4618813034F, + 0.4623735855F, 0.4628658841F, 0.4633581984F, 0.4638505281F, + 0.4643428724F, 0.4648352308F, 0.4653276028F, 0.4658199877F, + 0.4663123849F, 0.4668047940F, 0.4672972143F, 0.4677896451F, + 0.4682820861F, 0.4687745365F, 0.4692669958F, 0.4697594634F, + 0.4702519387F, 0.4707444211F, 0.4712369102F, 0.4717294052F, + 0.4722219056F, 0.4727144109F, 0.4732069204F, 0.4736994336F, + 0.4741919498F, 0.4746844686F, 0.4751769893F, 0.4756695113F, + 0.4761620341F, 0.4766545571F, 0.4771470797F, 0.4776396013F, + 0.4781321213F, 0.4786246392F, 0.4791171544F, 0.4796096663F, + 0.4801021744F, 0.4805946779F, 0.4810871765F, 0.4815796694F, + 0.4820721561F, 0.4825646360F, 0.4830571086F, 0.4835495732F, + 0.4840420293F, 0.4845344763F, 0.4850269136F, 0.4855193407F, + 0.4860117569F, 0.4865041617F, 0.4869965545F, 0.4874889347F, + 0.4879813018F, 0.4884736551F, 0.4889659941F, 0.4894583182F, + 0.4899506268F, 0.4904429193F, 0.4909351952F, 0.4914274538F, + 0.4919196947F, 0.4924119172F, 0.4929041207F, 0.4933963046F, + 0.4938884685F, 0.4943806116F, 0.4948727335F, 0.4953648335F, + 0.4958569110F, 0.4963489656F, 0.4968409965F, 0.4973330032F, + 0.4978249852F, 0.4983169419F, 0.4988088726F, 0.4993007768F, + 0.4997926539F, 0.5002845034F, 0.5007763247F, 0.5012681171F, + 0.5017598801F, 0.5022516132F, 0.5027433157F, 0.5032349871F, + 0.5037266268F, 0.5042182341F, 0.5047098086F, 0.5052013497F, + 0.5056928567F, 0.5061843292F, 0.5066757664F, 0.5071671679F, + 0.5076585330F, 0.5081498613F, 0.5086411520F, 0.5091324047F, + 0.5096236187F, 0.5101147934F, 0.5106059284F, 0.5110970230F, + 0.5115880766F, 0.5120790887F, 0.5125700587F, 0.5130609860F, + 0.5135518700F, 0.5140427102F, 0.5145335059F, 0.5150242566F, + 0.5155149618F, 0.5160056208F, 0.5164962331F, 0.5169867980F, + 0.5174773151F, 0.5179677837F, 0.5184582033F, 0.5189485733F, + 0.5194388931F, 0.5199291621F, 0.5204193798F, 0.5209095455F, + 0.5213996588F, 0.5218897190F, 0.5223797256F, 0.5228696779F, + 0.5233595755F, 0.5238494177F, 0.5243392039F, 0.5248289337F, + 0.5253186063F, 0.5258082213F, 0.5262977781F, 0.5267872760F, + 0.5272767146F, 0.5277660932F, 0.5282554112F, 0.5287446682F, + 0.5292338635F, 0.5297229965F, 0.5302120667F, 0.5307010736F, + 0.5311900164F, 0.5316788947F, 0.5321677079F, 0.5326564554F, + 0.5331451366F, 0.5336337511F, 0.5341222981F, 0.5346107771F, + 0.5350991876F, 0.5355875290F, 0.5360758007F, 0.5365640021F, + 0.5370521327F, 0.5375401920F, 0.5380281792F, 0.5385160939F, + 0.5390039355F, 0.5394917034F, 0.5399793971F, 0.5404670159F, + 0.5409545594F, 0.5414420269F, 0.5419294179F, 0.5424167318F, + 0.5429039680F, 0.5433911261F, 0.5438782053F, 0.5443652051F, + 0.5448521250F, 0.5453389644F, 0.5458257228F, 0.5463123995F, + 0.5467989940F, 0.5472855057F, 0.5477719341F, 0.5482582786F, + 0.5487445387F, 0.5492307137F, 0.5497168031F, 0.5502028063F, + 0.5506887228F, 0.5511745520F, 0.5516602934F, 0.5521459463F, + 0.5526315103F, 0.5531169847F, 0.5536023690F, 0.5540876626F, + 0.5545728649F, 0.5550579755F, 0.5555429937F, 0.5560279189F, + 0.5565127507F, 0.5569974884F, 0.5574821315F, 0.5579666794F, + 0.5584511316F, 0.5589354875F, 0.5594197465F, 0.5599039080F, + 0.5603879716F, 0.5608719367F, 0.5613558026F, 0.5618395689F, + 0.5623232350F, 0.5628068002F, 0.5632902642F, 0.5637736262F, + 0.5642568858F, 0.5647400423F, 0.5652230953F, 0.5657060442F, + 0.5661888883F, 0.5666716272F, 0.5671542603F, 0.5676367870F, + 0.5681192069F, 0.5686015192F, 0.5690837235F, 0.5695658192F, + 0.5700478058F, 0.5705296827F, 0.5710114494F, 0.5714931052F, + 0.5719746497F, 0.5724560822F, 0.5729374023F, 0.5734186094F, + 0.5738997029F, 0.5743806823F, 0.5748615470F, 0.5753422965F, + 0.5758229301F, 0.5763034475F, 0.5767838480F, 0.5772641310F, + 0.5777442960F, 0.5782243426F, 0.5787042700F, 0.5791840778F, + 0.5796637654F, 0.5801433322F, 0.5806227778F, 0.5811021016F, + 0.5815813029F, 0.5820603814F, 0.5825393363F, 0.5830181673F, + 0.5834968737F, 0.5839754549F, 0.5844539105F, 0.5849322399F, + 0.5854104425F, 0.5858885179F, 0.5863664653F, 0.5868442844F, + 0.5873219746F, 0.5877995353F, 0.5882769660F, 0.5887542661F, + 0.5892314351F, 0.5897084724F, 0.5901853776F, 0.5906621500F, + 0.5911387892F, 0.5916152945F, 0.5920916655F, 0.5925679016F, + 0.5930440022F, 0.5935199669F, 0.5939957950F, 0.5944714861F, + 0.5949470396F, 0.5954224550F, 0.5958977317F, 0.5963728692F, + 0.5968478669F, 0.5973227244F, 0.5977974411F, 0.5982720163F, + 0.5987464497F, 0.5992207407F, 0.5996948887F, 0.6001688932F, + 0.6006427537F, 0.6011164696F, 0.6015900405F, 0.6020634657F, + 0.6025367447F, 0.6030098770F, 0.6034828621F, 0.6039556995F, + 0.6044283885F, 0.6049009288F, 0.6053733196F, 0.6058455606F, + 0.6063176512F, 0.6067895909F, 0.6072613790F, 0.6077330152F, + 0.6082044989F, 0.6086758295F, 0.6091470065F, 0.6096180294F, + 0.6100888977F, 0.6105596108F, 0.6110301682F, 0.6115005694F, + 0.6119708139F, 0.6124409011F, 0.6129108305F, 0.6133806017F, + 0.6138502139F, 0.6143196669F, 0.6147889599F, 0.6152580926F, + 0.6157270643F, 0.6161958746F, 0.6166645230F, 0.6171330088F, + 0.6176013317F, 0.6180694910F, 0.6185374863F, 0.6190053171F, + 0.6194729827F, 0.6199404828F, 0.6204078167F, 0.6208749841F, + 0.6213419842F, 0.6218088168F, 0.6222754811F, 0.6227419768F, + 0.6232083032F, 0.6236744600F, 0.6241404465F, 0.6246062622F, + 0.6250719067F, 0.6255373795F, 0.6260026799F, 0.6264678076F, + 0.6269327619F, 0.6273975425F, 0.6278621487F, 0.6283265800F, + 0.6287908361F, 0.6292549163F, 0.6297188201F, 0.6301825471F, + 0.6306460966F, 0.6311094683F, 0.6315726617F, 0.6320356761F, + 0.6324985111F, 0.6329611662F, 0.6334236410F, 0.6338859348F, + 0.6343480472F, 0.6348099777F, 0.6352717257F, 0.6357332909F, + 0.6361946726F, 0.6366558704F, 0.6371168837F, 0.6375777122F, + 0.6380383552F, 0.6384988123F, 0.6389590830F, 0.6394191668F, + 0.6398790631F, 0.6403387716F, 0.6407982916F, 0.6412576228F, + 0.6417167645F, 0.6421757163F, 0.6426344778F, 0.6430930483F, + 0.6435514275F, 0.6440096149F, 0.6444676098F, 0.6449254119F, + 0.6453830207F, 0.6458404356F, 0.6462976562F, 0.6467546820F, + 0.6472115125F, 0.6476681472F, 0.6481245856F, 0.6485808273F, + 0.6490368717F, 0.6494927183F, 0.6499483667F, 0.6504038164F, + 0.6508590670F, 0.6513141178F, 0.6517689684F, 0.6522236185F, + 0.6526780673F, 0.6531323146F, 0.6535863598F, 0.6540402024F, + 0.6544938419F, 0.6549472779F, 0.6554005099F, 0.6558535373F, + 0.6563063598F, 0.6567589769F, 0.6572113880F, 0.6576635927F, + 0.6581155906F, 0.6585673810F, 0.6590189637F, 0.6594703380F, + 0.6599215035F, 0.6603724598F, 0.6608232064F, 0.6612737427F, + 0.6617240684F, 0.6621741829F, 0.6626240859F, 0.6630737767F, + 0.6635232550F, 0.6639725202F, 0.6644215720F, 0.6648704098F, + 0.6653190332F, 0.6657674417F, 0.6662156348F, 0.6666636121F, + 0.6671113731F, 0.6675589174F, 0.6680062445F, 0.6684533538F, + 0.6689002450F, 0.6693469177F, 0.6697933712F, 0.6702396052F, + 0.6706856193F, 0.6711314129F, 0.6715769855F, 0.6720223369F, + 0.6724674664F, 0.6729123736F, 0.6733570581F, 0.6738015194F, + 0.6742457570F, 0.6746897706F, 0.6751335596F, 0.6755771236F, + 0.6760204621F, 0.6764635747F, 0.6769064609F, 0.6773491204F, + 0.6777915525F, 0.6782337570F, 0.6786757332F, 0.6791174809F, + 0.6795589995F, 0.6800002886F, 0.6804413477F, 0.6808821765F, + 0.6813227743F, 0.6817631409F, 0.6822032758F, 0.6826431785F, + 0.6830828485F, 0.6835222855F, 0.6839614890F, 0.6844004585F, + 0.6848391936F, 0.6852776939F, 0.6857159589F, 0.6861539883F, + 0.6865917815F, 0.6870293381F, 0.6874666576F, 0.6879037398F, + 0.6883405840F, 0.6887771899F, 0.6892135571F, 0.6896496850F, + 0.6900855733F, 0.6905212216F, 0.6909566294F, 0.6913917963F, + 0.6918267218F, 0.6922614055F, 0.6926958471F, 0.6931300459F, + 0.6935640018F, 0.6939977141F, 0.6944311825F, 0.6948644066F, + 0.6952973859F, 0.6957301200F, 0.6961626085F, 0.6965948510F, + 0.6970268470F, 0.6974585961F, 0.6978900980F, 0.6983213521F, + 0.6987523580F, 0.6991831154F, 0.6996136238F, 0.7000438828F, + 0.7004738921F, 0.7009036510F, 0.7013331594F, 0.7017624166F, + 0.7021914224F, 0.7026201763F, 0.7030486779F, 0.7034769268F, + 0.7039049226F, 0.7043326648F, 0.7047601531F, 0.7051873870F, + 0.7056143662F, 0.7060410902F, 0.7064675586F, 0.7068937711F, + 0.7073197271F, 0.7077454264F, 0.7081708684F, 0.7085960529F, + 0.7090209793F, 0.7094456474F, 0.7098700566F, 0.7102942066F, + 0.7107180970F, 0.7111417274F, 0.7115650974F, 0.7119882066F, + 0.7124110545F, 0.7128336409F, 0.7132559653F, 0.7136780272F, + 0.7140998264F, 0.7145213624F, 0.7149426348F, 0.7153636433F, + 0.7157843874F, 0.7162048668F, 0.7166250810F, 0.7170450296F, + 0.7174647124F, 0.7178841289F, 0.7183032786F, 0.7187221613F, + 0.7191407765F, 0.7195591239F, 0.7199772030F, 0.7203950135F, + 0.7208125550F, 0.7212298271F, 0.7216468294F, 0.7220635616F, + 0.7224800233F, 0.7228962140F, 0.7233121335F, 0.7237277813F, + 0.7241431571F, 0.7245582604F, 0.7249730910F, 0.7253876484F, + 0.7258019322F, 0.7262159422F, 0.7266296778F, 0.7270431388F, + 0.7274563247F, 0.7278692353F, 0.7282818700F, 0.7286942287F, + 0.7291063108F, 0.7295181160F, 0.7299296440F, 0.7303408944F, + 0.7307518669F, 0.7311625609F, 0.7315729763F, 0.7319831126F, + 0.7323929695F, 0.7328025466F, 0.7332118435F, 0.7336208600F, + 0.7340295955F, 0.7344380499F, 0.7348462226F, 0.7352541134F, + 0.7356617220F, 0.7360690478F, 0.7364760907F, 0.7368828502F, + 0.7372893259F, 0.7376955176F, 0.7381014249F, 0.7385070475F, + 0.7389123849F, 0.7393174368F, 0.7397222029F, 0.7401266829F, + 0.7405308763F, 0.7409347829F, 0.7413384023F, 0.7417417341F, + 0.7421447780F, 0.7425475338F, 0.7429500009F, 0.7433521791F, + 0.7437540681F, 0.7441556674F, 0.7445569769F, 0.7449579960F, + 0.7453587245F, 0.7457591621F, 0.7461593084F, 0.7465591631F, + 0.7469587259F, 0.7473579963F, 0.7477569741F, 0.7481556590F, + 0.7485540506F, 0.7489521486F, 0.7493499526F, 0.7497474623F, + 0.7501446775F, 0.7505415977F, 0.7509382227F, 0.7513345521F, + 0.7517305856F, 0.7521263229F, 0.7525217636F, 0.7529169074F, + 0.7533117541F, 0.7537063032F, 0.7541005545F, 0.7544945076F, + 0.7548881623F, 0.7552815182F, 0.7556745749F, 0.7560673323F, + 0.7564597899F, 0.7568519474F, 0.7572438046F, 0.7576353611F, + 0.7580266166F, 0.7584175708F, 0.7588082235F, 0.7591985741F, + 0.7595886226F, 0.7599783685F, 0.7603678116F, 0.7607569515F, + 0.7611457879F, 0.7615343206F, 0.7619225493F, 0.7623104735F, + 0.7626980931F, 0.7630854078F, 0.7634724171F, 0.7638591209F, + 0.7642455188F, 0.7646316106F, 0.7650173959F, 0.7654028744F, + 0.7657880459F, 0.7661729100F, 0.7665574664F, 0.7669417150F, + 0.7673256553F, 0.7677092871F, 0.7680926100F, 0.7684756239F, + 0.7688583284F, 0.7692407232F, 0.7696228080F, 0.7700045826F, + 0.7703860467F, 0.7707671999F, 0.7711480420F, 0.7715285728F, + 0.7719087918F, 0.7722886989F, 0.7726682938F, 0.7730475762F, + 0.7734265458F, 0.7738052023F, 0.7741835454F, 0.7745615750F, + 0.7749392906F, 0.7753166921F, 0.7756937791F, 0.7760705514F, + 0.7764470087F, 0.7768231508F, 0.7771989773F, 0.7775744880F, + 0.7779496827F, 0.7783245610F, 0.7786991227F, 0.7790733676F, + 0.7794472953F, 0.7798209056F, 0.7801941982F, 0.7805671729F, + 0.7809398294F, 0.7813121675F, 0.7816841869F, 0.7820558873F, + 0.7824272684F, 0.7827983301F, 0.7831690720F, 0.7835394940F, + 0.7839095957F, 0.7842793768F, 0.7846488373F, 0.7850179767F, + 0.7853867948F, 0.7857552914F, 0.7861234663F, 0.7864913191F, + 0.7868588497F, 0.7872260578F, 0.7875929431F, 0.7879595055F, + 0.7883257445F, 0.7886916601F, 0.7890572520F, 0.7894225198F, + 0.7897874635F, 0.7901520827F, 0.7905163772F, 0.7908803468F, + 0.7912439912F, 0.7916073102F, 0.7919703035F, 0.7923329710F, + 0.7926953124F, 0.7930573274F, 0.7934190158F, 0.7937803774F, + 0.7941414120F, 0.7945021193F, 0.7948624991F, 0.7952225511F, + 0.7955822752F, 0.7959416711F, 0.7963007387F, 0.7966594775F, + 0.7970178875F, 0.7973759685F, 0.7977337201F, 0.7980911422F, + 0.7984482346F, 0.7988049970F, 0.7991614292F, 0.7995175310F, + 0.7998733022F, 0.8002287426F, 0.8005838519F, 0.8009386299F, + 0.8012930765F, 0.8016471914F, 0.8020009744F, 0.8023544253F, + 0.8027075438F, 0.8030603298F, 0.8034127831F, 0.8037649035F, + 0.8041166906F, 0.8044681445F, 0.8048192647F, 0.8051700512F, + 0.8055205038F, 0.8058706222F, 0.8062204062F, 0.8065698556F, + 0.8069189702F, 0.8072677499F, 0.8076161944F, 0.8079643036F, + 0.8083120772F, 0.8086595151F, 0.8090066170F, 0.8093533827F, + 0.8096998122F, 0.8100459051F, 0.8103916613F, 0.8107370806F, + 0.8110821628F, 0.8114269077F, 0.8117713151F, 0.8121153849F, + 0.8124591169F, 0.8128025108F, 0.8131455666F, 0.8134882839F, + 0.8138306627F, 0.8141727027F, 0.8145144038F, 0.8148557658F, + 0.8151967886F, 0.8155374718F, 0.8158778154F, 0.8162178192F, + 0.8165574830F, 0.8168968067F, 0.8172357900F, 0.8175744328F, + 0.8179127349F, 0.8182506962F, 0.8185883164F, 0.8189255955F, + 0.8192625332F, 0.8195991295F, 0.8199353840F, 0.8202712967F, + 0.8206068673F, 0.8209420958F, 0.8212769820F, 0.8216115256F, + 0.8219457266F, 0.8222795848F, 0.8226131000F, 0.8229462721F, + 0.8232791009F, 0.8236115863F, 0.8239437280F, 0.8242755260F, + 0.8246069801F, 0.8249380901F, 0.8252688559F, 0.8255992774F, + 0.8259293544F, 0.8262590867F, 0.8265884741F, 0.8269175167F, + 0.8272462141F, 0.8275745663F, 0.8279025732F, 0.8282302344F, + 0.8285575501F, 0.8288845199F, 0.8292111437F, 0.8295374215F, + 0.8298633530F, 0.8301889382F, 0.8305141768F, 0.8308390688F, + 0.8311636141F, 0.8314878124F, 0.8318116637F, 0.8321351678F, + 0.8324583246F, 0.8327811340F, 0.8331035957F, 0.8334257098F, + 0.8337474761F, 0.8340688944F, 0.8343899647F, 0.8347106867F, + 0.8350310605F, 0.8353510857F, 0.8356707624F, 0.8359900904F, + 0.8363090696F, 0.8366276999F, 0.8369459811F, 0.8372639131F, + 0.8375814958F, 0.8378987292F, 0.8382156130F, 0.8385321472F, + 0.8388483316F, 0.8391641662F, 0.8394796508F, 0.8397947853F, + 0.8401095697F, 0.8404240037F, 0.8407380873F, 0.8410518204F, + 0.8413652029F, 0.8416782347F, 0.8419909156F, 0.8423032456F, + 0.8426152245F, 0.8429268523F, 0.8432381289F, 0.8435490541F, + 0.8438596279F, 0.8441698502F, 0.8444797208F, 0.8447892396F, + 0.8450984067F, 0.8454072218F, 0.8457156849F, 0.8460237959F, + 0.8463315547F, 0.8466389612F, 0.8469460154F, 0.8472527170F, + 0.8475590661F, 0.8478650625F, 0.8481707063F, 0.8484759971F, + 0.8487809351F, 0.8490855201F, 0.8493897521F, 0.8496936308F, + 0.8499971564F, 0.8503003286F, 0.8506031474F, 0.8509056128F, + 0.8512077246F, 0.8515094828F, 0.8518108872F, 0.8521119379F, + 0.8524126348F, 0.8527129777F, 0.8530129666F, 0.8533126015F, + 0.8536118822F, 0.8539108087F, 0.8542093809F, 0.8545075988F, + 0.8548054623F, 0.8551029712F, 0.8554001257F, 0.8556969255F, + 0.8559933707F, 0.8562894611F, 0.8565851968F, 0.8568805775F, + 0.8571756034F, 0.8574702743F, 0.8577645902F, 0.8580585509F, + 0.8583521566F, 0.8586454070F, 0.8589383021F, 0.8592308420F, + 0.8595230265F, 0.8598148556F, 0.8601063292F, 0.8603974473F, + 0.8606882098F, 0.8609786167F, 0.8612686680F, 0.8615583636F, + 0.8618477034F, 0.8621366874F, 0.8624253156F, 0.8627135878F, + 0.8630015042F, 0.8632890646F, 0.8635762690F, 0.8638631173F, + 0.8641496096F, 0.8644357457F, 0.8647215257F, 0.8650069495F, + 0.8652920171F, 0.8655767283F, 0.8658610833F, 0.8661450820F, + 0.8664287243F, 0.8667120102F, 0.8669949397F, 0.8672775127F, + 0.8675597293F, 0.8678415894F, 0.8681230929F, 0.8684042398F, + 0.8686850302F, 0.8689654640F, 0.8692455412F, 0.8695252617F, + 0.8698046255F, 0.8700836327F, 0.8703622831F, 0.8706405768F, + 0.8709185138F, 0.8711960940F, 0.8714733174F, 0.8717501840F, + 0.8720266939F, 0.8723028469F, 0.8725786430F, 0.8728540824F, + 0.8731291648F, 0.8734038905F, 0.8736782592F, 0.8739522711F, + 0.8742259261F, 0.8744992242F, 0.8747721653F, 0.8750447496F, + 0.8753169770F, 0.8755888475F, 0.8758603611F, 0.8761315177F, + 0.8764023175F, 0.8766727603F, 0.8769428462F, 0.8772125752F, + 0.8774819474F, 0.8777509626F, 0.8780196209F, 0.8782879224F, + 0.8785558669F, 0.8788234546F, 0.8790906854F, 0.8793575594F, + 0.8796240765F, 0.8798902368F, 0.8801560403F, 0.8804214870F, + 0.8806865768F, 0.8809513099F, 0.8812156863F, 0.8814797059F, + 0.8817433687F, 0.8820066749F, 0.8822696243F, 0.8825322171F, + 0.8827944532F, 0.8830563327F, 0.8833178556F, 0.8835790219F, + 0.8838398316F, 0.8841002848F, 0.8843603815F, 0.8846201217F, + 0.8848795054F, 0.8851385327F, 0.8853972036F, 0.8856555182F, + 0.8859134764F, 0.8861710783F, 0.8864283239F, 0.8866852133F, + 0.8869417464F, 0.8871979234F, 0.8874537443F, 0.8877092090F, + 0.8879643177F, 0.8882190704F, 0.8884734671F, 0.8887275078F, + 0.8889811927F, 0.8892345216F, 0.8894874948F, 0.8897401122F, + 0.8899923738F, 0.8902442798F, 0.8904958301F, 0.8907470248F, + 0.8909978640F, 0.8912483477F, 0.8914984759F, 0.8917482487F, + 0.8919976662F, 0.8922467284F, 0.8924954353F, 0.8927437871F, + 0.8929917837F, 0.8932394252F, 0.8934867118F, 0.8937336433F, + 0.8939802199F, 0.8942264417F, 0.8944723087F, 0.8947178210F, + 0.8949629785F, 0.8952077815F, 0.8954522299F, 0.8956963239F, + 0.8959400634F, 0.8961834486F, 0.8964264795F, 0.8966691561F, + 0.8969114786F, 0.8971534470F, 0.8973950614F, 0.8976363219F, + 0.8978772284F, 0.8981177812F, 0.8983579802F, 0.8985978256F, + 0.8988373174F, 0.8990764556F, 0.8993152405F, 0.8995536720F, + 0.8997917502F, 0.9000294751F, 0.9002668470F, 0.9005038658F, + 0.9007405317F, 0.9009768446F, 0.9012128048F, 0.9014484123F, + 0.9016836671F, 0.9019185693F, 0.9021531191F, 0.9023873165F, + 0.9026211616F, 0.9028546546F, 0.9030877954F, 0.9033205841F, + 0.9035530210F, 0.9037851059F, 0.9040168392F, 0.9042482207F, + 0.9044792507F, 0.9047099293F, 0.9049402564F, 0.9051702323F, + 0.9053998569F, 0.9056291305F, 0.9058580531F, 0.9060866248F, + 0.9063148457F, 0.9065427159F, 0.9067702355F, 0.9069974046F, + 0.9072242233F, 0.9074506917F, 0.9076768100F, 0.9079025782F, + 0.9081279964F, 0.9083530647F, 0.9085777833F, 0.9088021523F, + 0.9090261717F, 0.9092498417F, 0.9094731623F, 0.9096961338F, + 0.9099187561F, 0.9101410295F, 0.9103629540F, 0.9105845297F, + 0.9108057568F, 0.9110266354F, 0.9112471656F, 0.9114673475F, + 0.9116871812F, 0.9119066668F, 0.9121258046F, 0.9123445945F, + 0.9125630367F, 0.9127811314F, 0.9129988786F, 0.9132162785F, + 0.9134333312F, 0.9136500368F, 0.9138663954F, 0.9140824073F, + 0.9142980724F, 0.9145133910F, 0.9147283632F, 0.9149429890F, + 0.9151572687F, 0.9153712023F, 0.9155847900F, 0.9157980319F, + 0.9160109282F, 0.9162234790F, 0.9164356844F, 0.9166475445F, + 0.9168590595F, 0.9170702296F, 0.9172810548F, 0.9174915354F, + 0.9177016714F, 0.9179114629F, 0.9181209102F, 0.9183300134F, + 0.9185387726F, 0.9187471879F, 0.9189552595F, 0.9191629876F, + 0.9193703723F, 0.9195774136F, 0.9197841119F, 0.9199904672F, + 0.9201964797F, 0.9204021495F, 0.9206074767F, 0.9208124616F, + 0.9210171043F, 0.9212214049F, 0.9214253636F, 0.9216289805F, + 0.9218322558F, 0.9220351896F, 0.9222377821F, 0.9224400335F, + 0.9226419439F, 0.9228435134F, 0.9230447423F, 0.9232456307F, + 0.9234461787F, 0.9236463865F, 0.9238462543F, 0.9240457822F, + 0.9242449704F, 0.9244438190F, 0.9246423282F, 0.9248404983F, + 0.9250383293F, 0.9252358214F, 0.9254329747F, 0.9256297896F, + 0.9258262660F, 0.9260224042F, 0.9262182044F, 0.9264136667F, + 0.9266087913F, 0.9268035783F, 0.9269980280F, 0.9271921405F, + 0.9273859160F, 0.9275793546F, 0.9277724566F, 0.9279652221F, + 0.9281576513F, 0.9283497443F, 0.9285415014F, 0.9287329227F, + 0.9289240084F, 0.9291147586F, 0.9293051737F, 0.9294952536F, + 0.9296849987F, 0.9298744091F, 0.9300634850F, 0.9302522266F, + 0.9304406340F, 0.9306287074F, 0.9308164471F, 0.9310038532F, + 0.9311909259F, 0.9313776654F, 0.9315640719F, 0.9317501455F, + 0.9319358865F, 0.9321212951F, 0.9323063713F, 0.9324911155F, + 0.9326755279F, 0.9328596085F, 0.9330433577F, 0.9332267756F, + 0.9334098623F, 0.9335926182F, 0.9337750434F, 0.9339571380F, + 0.9341389023F, 0.9343203366F, 0.9345014409F, 0.9346822155F, + 0.9348626606F, 0.9350427763F, 0.9352225630F, 0.9354020207F, + 0.9355811498F, 0.9357599503F, 0.9359384226F, 0.9361165667F, + 0.9362943830F, 0.9364718716F, 0.9366490327F, 0.9368258666F, + 0.9370023733F, 0.9371785533F, 0.9373544066F, 0.9375299335F, + 0.9377051341F, 0.9378800087F, 0.9380545576F, 0.9382287809F, + 0.9384026787F, 0.9385762515F, 0.9387494993F, 0.9389224223F, + 0.9390950209F, 0.9392672951F, 0.9394392453F, 0.9396108716F, + 0.9397821743F, 0.9399531536F, 0.9401238096F, 0.9402941427F, + 0.9404641530F, 0.9406338407F, 0.9408032061F, 0.9409722495F, + 0.9411409709F, 0.9413093707F, 0.9414774491F, 0.9416452062F, + 0.9418126424F, 0.9419797579F, 0.9421465528F, 0.9423130274F, + 0.9424791819F, 0.9426450166F, 0.9428105317F, 0.9429757274F, + 0.9431406039F, 0.9433051616F, 0.9434694005F, 0.9436333209F, + 0.9437969232F, 0.9439602074F, 0.9441231739F, 0.9442858229F, + 0.9444481545F, 0.9446101691F, 0.9447718669F, 0.9449332481F, + 0.9450943129F, 0.9452550617F, 0.9454154945F, 0.9455756118F, + 0.9457354136F, 0.9458949003F, 0.9460540721F, 0.9462129292F, + 0.9463714719F, 0.9465297003F, 0.9466876149F, 0.9468452157F, + 0.9470025031F, 0.9471594772F, 0.9473161384F, 0.9474724869F, + 0.9476285229F, 0.9477842466F, 0.9479396584F, 0.9480947585F, + 0.9482495470F, 0.9484040243F, 0.9485581906F, 0.9487120462F, + 0.9488655913F, 0.9490188262F, 0.9491717511F, 0.9493243662F, + 0.9494766718F, 0.9496286683F, 0.9497803557F, 0.9499317345F, + 0.9500828047F, 0.9502335668F, 0.9503840209F, 0.9505341673F, + 0.9506840062F, 0.9508335380F, 0.9509827629F, 0.9511316810F, + 0.9512802928F, 0.9514285984F, 0.9515765982F, 0.9517242923F, + 0.9518716810F, 0.9520187646F, 0.9521655434F, 0.9523120176F, + 0.9524581875F, 0.9526040534F, 0.9527496154F, 0.9528948739F, + 0.9530398292F, 0.9531844814F, 0.9533288310F, 0.9534728780F, + 0.9536166229F, 0.9537600659F, 0.9539032071F, 0.9540460470F, + 0.9541885858F, 0.9543308237F, 0.9544727611F, 0.9546143981F, + 0.9547557351F, 0.9548967723F, 0.9550375100F, 0.9551779485F, + 0.9553180881F, 0.9554579290F, 0.9555974714F, 0.9557367158F, + 0.9558756623F, 0.9560143112F, 0.9561526628F, 0.9562907174F, + 0.9564284752F, 0.9565659366F, 0.9567031017F, 0.9568399710F, + 0.9569765446F, 0.9571128229F, 0.9572488061F, 0.9573844944F, + 0.9575198883F, 0.9576549879F, 0.9577897936F, 0.9579243056F, + 0.9580585242F, 0.9581924497F, 0.9583260824F, 0.9584594226F, + 0.9585924705F, 0.9587252264F, 0.9588576906F, 0.9589898634F, + 0.9591217452F, 0.9592533360F, 0.9593846364F, 0.9595156465F, + 0.9596463666F, 0.9597767971F, 0.9599069382F, 0.9600367901F, + 0.9601663533F, 0.9602956279F, 0.9604246143F, 0.9605533128F, + 0.9606817236F, 0.9608098471F, 0.9609376835F, 0.9610652332F, + 0.9611924963F, 0.9613194733F, 0.9614461644F, 0.9615725699F, + 0.9616986901F, 0.9618245253F, 0.9619500757F, 0.9620753418F, + 0.9622003238F, 0.9623250219F, 0.9624494365F, 0.9625735679F, + 0.9626974163F, 0.9628209821F, 0.9629442656F, 0.9630672671F, + 0.9631899868F, 0.9633124251F, 0.9634345822F, 0.9635564585F, + 0.9636780543F, 0.9637993699F, 0.9639204056F, 0.9640411616F, + 0.9641616383F, 0.9642818359F, 0.9644017549F, 0.9645213955F, + 0.9646407579F, 0.9647598426F, 0.9648786497F, 0.9649971797F, + 0.9651154328F, 0.9652334092F, 0.9653511095F, 0.9654685337F, + 0.9655856823F, 0.9657025556F, 0.9658191538F, 0.9659354773F, + 0.9660515263F, 0.9661673013F, 0.9662828024F, 0.9663980300F, + 0.9665129845F, 0.9666276660F, 0.9667420750F, 0.9668562118F, + 0.9669700766F, 0.9670836698F, 0.9671969917F, 0.9673100425F, + 0.9674228227F, 0.9675353325F, 0.9676475722F, 0.9677595422F, + 0.9678712428F, 0.9679826742F, 0.9680938368F, 0.9682047309F, + 0.9683153569F, 0.9684257150F, 0.9685358056F, 0.9686456289F, + 0.9687551853F, 0.9688644752F, 0.9689734987F, 0.9690822564F, + 0.9691907483F, 0.9692989750F, 0.9694069367F, 0.9695146337F, + 0.9696220663F, 0.9697292349F, 0.9698361398F, 0.9699427813F, + 0.9700491597F, 0.9701552754F, 0.9702611286F, 0.9703667197F, + 0.9704720490F, 0.9705771169F, 0.9706819236F, 0.9707864695F, + 0.9708907549F, 0.9709947802F, 0.9710985456F, 0.9712020514F, + 0.9713052981F, 0.9714082859F, 0.9715110151F, 0.9716134862F, + 0.9717156993F, 0.9718176549F, 0.9719193532F, 0.9720207946F, + 0.9721219794F, 0.9722229080F, 0.9723235806F, 0.9724239976F, + 0.9725241593F, 0.9726240661F, 0.9727237183F, 0.9728231161F, + 0.9729222601F, 0.9730211503F, 0.9731197873F, 0.9732181713F, + 0.9733163027F, 0.9734141817F, 0.9735118088F, 0.9736091842F, + 0.9737063083F, 0.9738031814F, 0.9738998039F, 0.9739961760F, + 0.9740922981F, 0.9741881706F, 0.9742837938F, 0.9743791680F, + 0.9744742935F, 0.9745691707F, 0.9746637999F, 0.9747581814F, + 0.9748523157F, 0.9749462029F, 0.9750398435F, 0.9751332378F, + 0.9752263861F, 0.9753192887F, 0.9754119461F, 0.9755043585F, + 0.9755965262F, 0.9756884496F, 0.9757801291F, 0.9758715650F, + 0.9759627575F, 0.9760537071F, 0.9761444141F, 0.9762348789F, + 0.9763251016F, 0.9764150828F, 0.9765048228F, 0.9765943218F, + 0.9766835802F, 0.9767725984F, 0.9768613767F, 0.9769499154F, + 0.9770382149F, 0.9771262755F, 0.9772140976F, 0.9773016815F, + 0.9773890275F, 0.9774761360F, 0.9775630073F, 0.9776496418F, + 0.9777360398F, 0.9778222016F, 0.9779081277F, 0.9779938182F, + 0.9780792736F, 0.9781644943F, 0.9782494805F, 0.9783342326F, + 0.9784187509F, 0.9785030359F, 0.9785870877F, 0.9786709069F, + 0.9787544936F, 0.9788378484F, 0.9789209714F, 0.9790038631F, + 0.9790865238F, 0.9791689538F, 0.9792511535F, 0.9793331232F, + 0.9794148633F, 0.9794963742F, 0.9795776561F, 0.9796587094F, + 0.9797395345F, 0.9798201316F, 0.9799005013F, 0.9799806437F, + 0.9800605593F, 0.9801402483F, 0.9802197112F, 0.9802989483F, + 0.9803779600F, 0.9804567465F, 0.9805353082F, 0.9806136455F, + 0.9806917587F, 0.9807696482F, 0.9808473143F, 0.9809247574F, + 0.9810019778F, 0.9810789759F, 0.9811557519F, 0.9812323064F, + 0.9813086395F, 0.9813847517F, 0.9814606433F, 0.9815363147F, + 0.9816117662F, 0.9816869981F, 0.9817620108F, 0.9818368047F, + 0.9819113801F, 0.9819857374F, 0.9820598769F, 0.9821337989F, + 0.9822075038F, 0.9822809920F, 0.9823542638F, 0.9824273195F, + 0.9825001596F, 0.9825727843F, 0.9826451940F, 0.9827173891F, + 0.9827893700F, 0.9828611368F, 0.9829326901F, 0.9830040302F, + 0.9830751574F, 0.9831460720F, 0.9832167745F, 0.9832872652F, + 0.9833575444F, 0.9834276124F, 0.9834974697F, 0.9835671166F, + 0.9836365535F, 0.9837057806F, 0.9837747983F, 0.9838436071F, + 0.9839122072F, 0.9839805990F, 0.9840487829F, 0.9841167591F, + 0.9841845282F, 0.9842520903F, 0.9843194459F, 0.9843865953F, + 0.9844535389F, 0.9845202771F, 0.9845868101F, 0.9846531383F, + 0.9847192622F, 0.9847851820F, 0.9848508980F, 0.9849164108F, + 0.9849817205F, 0.9850468276F, 0.9851117324F, 0.9851764352F, + 0.9852409365F, 0.9853052366F, 0.9853693358F, 0.9854332344F, + 0.9854969330F, 0.9855604317F, 0.9856237309F, 0.9856868310F, + 0.9857497325F, 0.9858124355F, 0.9858749404F, 0.9859372477F, + 0.9859993577F, 0.9860612707F, 0.9861229871F, 0.9861845072F, + 0.9862458315F, 0.9863069601F, 0.9863678936F, 0.9864286322F, + 0.9864891764F, 0.9865495264F, 0.9866096826F, 0.9866696454F, + 0.9867294152F, 0.9867889922F, 0.9868483769F, 0.9869075695F, + 0.9869665706F, 0.9870253803F, 0.9870839991F, 0.9871424273F, + 0.9872006653F, 0.9872587135F, 0.9873165721F, 0.9873742415F, + 0.9874317222F, 0.9874890144F, 0.9875461185F, 0.9876030348F, + 0.9876597638F, 0.9877163057F, 0.9877726610F, 0.9878288300F, + 0.9878848130F, 0.9879406104F, 0.9879962225F, 0.9880516497F, + 0.9881068924F, 0.9881619509F, 0.9882168256F, 0.9882715168F, + 0.9883260249F, 0.9883803502F, 0.9884344931F, 0.9884884539F, + 0.9885422331F, 0.9885958309F, 0.9886492477F, 0.9887024838F, + 0.9887555397F, 0.9888084157F, 0.9888611120F, 0.9889136292F, + 0.9889659675F, 0.9890181273F, 0.9890701089F, 0.9891219128F, + 0.9891735392F, 0.9892249885F, 0.9892762610F, 0.9893273572F, + 0.9893782774F, 0.9894290219F, 0.9894795911F, 0.9895299853F, + 0.9895802049F, 0.9896302502F, 0.9896801217F, 0.9897298196F, + 0.9897793443F, 0.9898286961F, 0.9898778755F, 0.9899268828F, + 0.9899757183F, 0.9900243823F, 0.9900728753F, 0.9901211976F, + 0.9901693495F, 0.9902173314F, 0.9902651436F, 0.9903127865F, + 0.9903602605F, 0.9904075659F, 0.9904547031F, 0.9905016723F, + 0.9905484740F, 0.9905951086F, 0.9906415763F, 0.9906878775F, + 0.9907340126F, 0.9907799819F, 0.9908257858F, 0.9908714247F, + 0.9909168988F, 0.9909622086F, 0.9910073543F, 0.9910523364F, + 0.9910971552F, 0.9911418110F, 0.9911863042F, 0.9912306351F, + 0.9912748042F, 0.9913188117F, 0.9913626580F, 0.9914063435F, + 0.9914498684F, 0.9914932333F, 0.9915364383F, 0.9915794839F, + 0.9916223703F, 0.9916650981F, 0.9917076674F, 0.9917500787F, + 0.9917923323F, 0.9918344286F, 0.9918763679F, 0.9919181505F, + 0.9919597769F, 0.9920012473F, 0.9920425621F, 0.9920837217F, + 0.9921247263F, 0.9921655765F, 0.9922062724F, 0.9922468145F, + 0.9922872030F, 0.9923274385F, 0.9923675211F, 0.9924074513F, + 0.9924472294F, 0.9924868557F, 0.9925263306F, 0.9925656544F, + 0.9926048275F, 0.9926438503F, 0.9926827230F, 0.9927214461F, + 0.9927600199F, 0.9927984446F, 0.9928367208F, 0.9928748486F, + 0.9929128285F, 0.9929506608F, 0.9929883459F, 0.9930258841F, + 0.9930632757F, 0.9931005211F, 0.9931376207F, 0.9931745747F, + 0.9932113836F, 0.9932480476F, 0.9932845671F, 0.9933209425F, + 0.9933571742F, 0.9933932623F, 0.9934292074F, 0.9934650097F, + 0.9935006696F, 0.9935361874F, 0.9935715635F, 0.9936067982F, + 0.9936418919F, 0.9936768448F, 0.9937116574F, 0.9937463300F, + 0.9937808629F, 0.9938152565F, 0.9938495111F, 0.9938836271F, + 0.9939176047F, 0.9939514444F, 0.9939851465F, 0.9940187112F, + 0.9940521391F, 0.9940854303F, 0.9941185853F, 0.9941516044F, + 0.9941844879F, 0.9942172361F, 0.9942498495F, 0.9942823283F, + 0.9943146729F, 0.9943468836F, 0.9943789608F, 0.9944109047F, + 0.9944427158F, 0.9944743944F, 0.9945059408F, 0.9945373553F, + 0.9945686384F, 0.9945997902F, 0.9946308112F, 0.9946617017F, + 0.9946924621F, 0.9947230926F, 0.9947535937F, 0.9947839656F, + 0.9948142086F, 0.9948443232F, 0.9948743097F, 0.9949041683F, + 0.9949338995F, 0.9949635035F, 0.9949929807F, 0.9950223315F, + 0.9950515561F, 0.9950806549F, 0.9951096282F, 0.9951384764F, + 0.9951671998F, 0.9951957987F, 0.9952242735F, 0.9952526245F, + 0.9952808520F, 0.9953089564F, 0.9953369380F, 0.9953647971F, + 0.9953925340F, 0.9954201491F, 0.9954476428F, 0.9954750153F, + 0.9955022670F, 0.9955293981F, 0.9955564092F, 0.9955833003F, + 0.9956100720F, 0.9956367245F, 0.9956632582F, 0.9956896733F, + 0.9957159703F, 0.9957421494F, 0.9957682110F, 0.9957941553F, + 0.9958199828F, 0.9958456937F, 0.9958712884F, 0.9958967672F, + 0.9959221305F, 0.9959473784F, 0.9959725115F, 0.9959975300F, + 0.9960224342F, 0.9960472244F, 0.9960719011F, 0.9960964644F, + 0.9961209148F, 0.9961452525F, 0.9961694779F, 0.9961935913F, + 0.9962175930F, 0.9962414834F, 0.9962652627F, 0.9962889313F, + 0.9963124895F, 0.9963359377F, 0.9963592761F, 0.9963825051F, + 0.9964056250F, 0.9964286361F, 0.9964515387F, 0.9964743332F, + 0.9964970198F, 0.9965195990F, 0.9965420709F, 0.9965644360F, + 0.9965866946F, 0.9966088469F, 0.9966308932F, 0.9966528340F, + 0.9966746695F, 0.9966964001F, 0.9967180260F, 0.9967395475F, + 0.9967609651F, 0.9967822789F, 0.9968034894F, 0.9968245968F, + 0.9968456014F, 0.9968665036F, 0.9968873037F, 0.9969080019F, + 0.9969285987F, 0.9969490942F, 0.9969694889F, 0.9969897830F, + 0.9970099769F, 0.9970300708F, 0.9970500651F, 0.9970699601F, + 0.9970897561F, 0.9971094533F, 0.9971290522F, 0.9971485531F, + 0.9971679561F, 0.9971872617F, 0.9972064702F, 0.9972255818F, + 0.9972445968F, 0.9972635157F, 0.9972823386F, 0.9973010659F, + 0.9973196980F, 0.9973382350F, 0.9973566773F, 0.9973750253F, + 0.9973932791F, 0.9974114392F, 0.9974295059F, 0.9974474793F, + 0.9974653599F, 0.9974831480F, 0.9975008438F, 0.9975184476F, + 0.9975359598F, 0.9975533806F, 0.9975707104F, 0.9975879495F, + 0.9976050981F, 0.9976221566F, 0.9976391252F, 0.9976560043F, + 0.9976727941F, 0.9976894950F, 0.9977061073F, 0.9977226312F, + 0.9977390671F, 0.9977554152F, 0.9977716759F, 0.9977878495F, + 0.9978039361F, 0.9978199363F, 0.9978358501F, 0.9978516780F, + 0.9978674202F, 0.9978830771F, 0.9978986488F, 0.9979141358F, + 0.9979295383F, 0.9979448566F, 0.9979600909F, 0.9979752417F, + 0.9979903091F, 0.9980052936F, 0.9980201952F, 0.9980350145F, + 0.9980497515F, 0.9980644067F, 0.9980789804F, 0.9980934727F, + 0.9981078841F, 0.9981222147F, 0.9981364649F, 0.9981506350F, + 0.9981647253F, 0.9981787360F, 0.9981926674F, 0.9982065199F, + 0.9982202936F, 0.9982339890F, 0.9982476062F, 0.9982611456F, + 0.9982746074F, 0.9982879920F, 0.9983012996F, 0.9983145304F, + 0.9983276849F, 0.9983407632F, 0.9983537657F, 0.9983666926F, + 0.9983795442F, 0.9983923208F, 0.9984050226F, 0.9984176501F, + 0.9984302033F, 0.9984426827F, 0.9984550884F, 0.9984674208F, + 0.9984796802F, 0.9984918667F, 0.9985039808F, 0.9985160227F, + 0.9985279926F, 0.9985398909F, 0.9985517177F, 0.9985634734F, + 0.9985751583F, 0.9985867727F, 0.9985983167F, 0.9986097907F, + 0.9986211949F, 0.9986325297F, 0.9986437953F, 0.9986549919F, + 0.9986661199F, 0.9986771795F, 0.9986881710F, 0.9986990946F, + 0.9987099507F, 0.9987207394F, 0.9987314611F, 0.9987421161F, + 0.9987527045F, 0.9987632267F, 0.9987736829F, 0.9987840734F, + 0.9987943985F, 0.9988046584F, 0.9988148534F, 0.9988249838F, + 0.9988350498F, 0.9988450516F, 0.9988549897F, 0.9988648641F, + 0.9988746753F, 0.9988844233F, 0.9988941086F, 0.9989037313F, + 0.9989132918F, 0.9989227902F, 0.9989322269F, 0.9989416021F, + 0.9989509160F, 0.9989601690F, 0.9989693613F, 0.9989784931F, + 0.9989875647F, 0.9989965763F, 0.9990055283F, 0.9990144208F, + 0.9990232541F, 0.9990320286F, 0.9990407443F, 0.9990494016F, + 0.9990580008F, 0.9990665421F, 0.9990750257F, 0.9990834519F, + 0.9990918209F, 0.9991001331F, 0.9991083886F, 0.9991165877F, + 0.9991247307F, 0.9991328177F, 0.9991408491F, 0.9991488251F, + 0.9991567460F, 0.9991646119F, 0.9991724232F, 0.9991801801F, + 0.9991878828F, 0.9991955316F, 0.9992031267F, 0.9992106684F, + 0.9992181569F, 0.9992255925F, 0.9992329753F, 0.9992403057F, + 0.9992475839F, 0.9992548101F, 0.9992619846F, 0.9992691076F, + 0.9992761793F, 0.9992832001F, 0.9992901701F, 0.9992970895F, + 0.9993039587F, 0.9993107777F, 0.9993175470F, 0.9993242667F, + 0.9993309371F, 0.9993375583F, 0.9993441307F, 0.9993506545F, + 0.9993571298F, 0.9993635570F, 0.9993699362F, 0.9993762678F, + 0.9993825519F, 0.9993887887F, 0.9993949785F, 0.9994011216F, + 0.9994072181F, 0.9994132683F, 0.9994192725F, 0.9994252307F, + 0.9994311434F, 0.9994370107F, 0.9994428327F, 0.9994486099F, + 0.9994543423F, 0.9994600303F, 0.9994656739F, 0.9994712736F, + 0.9994768294F, 0.9994823417F, 0.9994878105F, 0.9994932363F, + 0.9994986191F, 0.9995039592F, 0.9995092568F, 0.9995145122F, + 0.9995197256F, 0.9995248971F, 0.9995300270F, 0.9995351156F, + 0.9995401630F, 0.9995451695F, 0.9995501352F, 0.9995550604F, + 0.9995599454F, 0.9995647903F, 0.9995695953F, 0.9995743607F, + 0.9995790866F, 0.9995837734F, 0.9995884211F, 0.9995930300F, + 0.9995976004F, 0.9996021324F, 0.9996066263F, 0.9996110822F, + 0.9996155004F, 0.9996198810F, 0.9996242244F, 0.9996285306F, + 0.9996327999F, 0.9996370326F, 0.9996412287F, 0.9996453886F, + 0.9996495125F, 0.9996536004F, 0.9996576527F, 0.9996616696F, + 0.9996656512F, 0.9996695977F, 0.9996735094F, 0.9996773865F, + 0.9996812291F, 0.9996850374F, 0.9996888118F, 0.9996925523F, + 0.9996962591F, 0.9996999325F, 0.9997035727F, 0.9997071798F, + 0.9997107541F, 0.9997142957F, 0.9997178049F, 0.9997212818F, + 0.9997247266F, 0.9997281396F, 0.9997315209F, 0.9997348708F, + 0.9997381893F, 0.9997414767F, 0.9997447333F, 0.9997479591F, + 0.9997511544F, 0.9997543194F, 0.9997574542F, 0.9997605591F, + 0.9997636342F, 0.9997666797F, 0.9997696958F, 0.9997726828F, + 0.9997756407F, 0.9997785698F, 0.9997814703F, 0.9997843423F, + 0.9997871860F, 0.9997900016F, 0.9997927894F, 0.9997955494F, + 0.9997982818F, 0.9998009869F, 0.9998036648F, 0.9998063157F, + 0.9998089398F, 0.9998115373F, 0.9998141082F, 0.9998166529F, + 0.9998191715F, 0.9998216642F, 0.9998241311F, 0.9998265724F, + 0.9998289884F, 0.9998313790F, 0.9998337447F, 0.9998360854F, + 0.9998384015F, 0.9998406930F, 0.9998429602F, 0.9998452031F, + 0.9998474221F, 0.9998496171F, 0.9998517885F, 0.9998539364F, + 0.9998560610F, 0.9998581624F, 0.9998602407F, 0.9998622962F, + 0.9998643291F, 0.9998663394F, 0.9998683274F, 0.9998702932F, + 0.9998722370F, 0.9998741589F, 0.9998760591F, 0.9998779378F, + 0.9998797952F, 0.9998816313F, 0.9998834464F, 0.9998852406F, + 0.9998870141F, 0.9998887670F, 0.9998904995F, 0.9998922117F, + 0.9998939039F, 0.9998955761F, 0.9998972285F, 0.9998988613F, + 0.9999004746F, 0.9999020686F, 0.9999036434F, 0.9999051992F, + 0.9999067362F, 0.9999082544F, 0.9999097541F, 0.9999112354F, + 0.9999126984F, 0.9999141433F, 0.9999155703F, 0.9999169794F, + 0.9999183709F, 0.9999197449F, 0.9999211014F, 0.9999224408F, + 0.9999237631F, 0.9999250684F, 0.9999263570F, 0.9999276289F, + 0.9999288843F, 0.9999301233F, 0.9999313461F, 0.9999325529F, + 0.9999337437F, 0.9999349187F, 0.9999360780F, 0.9999372218F, + 0.9999383503F, 0.9999394635F, 0.9999405616F, 0.9999416447F, + 0.9999427129F, 0.9999437665F, 0.9999448055F, 0.9999458301F, + 0.9999468404F, 0.9999478365F, 0.9999488185F, 0.9999497867F, + 0.9999507411F, 0.9999516819F, 0.9999526091F, 0.9999535230F, + 0.9999544236F, 0.9999553111F, 0.9999561856F, 0.9999570472F, + 0.9999578960F, 0.9999587323F, 0.9999595560F, 0.9999603674F, + 0.9999611666F, 0.9999619536F, 0.9999627286F, 0.9999634917F, + 0.9999642431F, 0.9999649828F, 0.9999657110F, 0.9999664278F, + 0.9999671334F, 0.9999678278F, 0.9999685111F, 0.9999691835F, + 0.9999698451F, 0.9999704960F, 0.9999711364F, 0.9999717662F, + 0.9999723858F, 0.9999729950F, 0.9999735942F, 0.9999741834F, + 0.9999747626F, 0.9999753321F, 0.9999758919F, 0.9999764421F, + 0.9999769828F, 0.9999775143F, 0.9999780364F, 0.9999785495F, + 0.9999790535F, 0.9999795485F, 0.9999800348F, 0.9999805124F, + 0.9999809813F, 0.9999814417F, 0.9999818938F, 0.9999823375F, + 0.9999827731F, 0.9999832005F, 0.9999836200F, 0.9999840316F, + 0.9999844353F, 0.9999848314F, 0.9999852199F, 0.9999856008F, + 0.9999859744F, 0.9999863407F, 0.9999866997F, 0.9999870516F, + 0.9999873965F, 0.9999877345F, 0.9999880656F, 0.9999883900F, + 0.9999887078F, 0.9999890190F, 0.9999893237F, 0.9999896220F, + 0.9999899140F, 0.9999901999F, 0.9999904796F, 0.9999907533F, + 0.9999910211F, 0.9999912830F, 0.9999915391F, 0.9999917896F, + 0.9999920345F, 0.9999922738F, 0.9999925077F, 0.9999927363F, + 0.9999929596F, 0.9999931777F, 0.9999933907F, 0.9999935987F, + 0.9999938018F, 0.9999940000F, 0.9999941934F, 0.9999943820F, + 0.9999945661F, 0.9999947456F, 0.9999949206F, 0.9999950912F, + 0.9999952575F, 0.9999954195F, 0.9999955773F, 0.9999957311F, + 0.9999958807F, 0.9999960265F, 0.9999961683F, 0.9999963063F, + 0.9999964405F, 0.9999965710F, 0.9999966979F, 0.9999968213F, + 0.9999969412F, 0.9999970576F, 0.9999971707F, 0.9999972805F, + 0.9999973871F, 0.9999974905F, 0.9999975909F, 0.9999976881F, + 0.9999977824F, 0.9999978738F, 0.9999979624F, 0.9999980481F, + 0.9999981311F, 0.9999982115F, 0.9999982892F, 0.9999983644F, + 0.9999984370F, 0.9999985072F, 0.9999985750F, 0.9999986405F, + 0.9999987037F, 0.9999987647F, 0.9999988235F, 0.9999988802F, + 0.9999989348F, 0.9999989873F, 0.9999990379F, 0.9999990866F, + 0.9999991334F, 0.9999991784F, 0.9999992217F, 0.9999992632F, + 0.9999993030F, 0.9999993411F, 0.9999993777F, 0.9999994128F, + 0.9999994463F, 0.9999994784F, 0.9999995091F, 0.9999995384F, + 0.9999995663F, 0.9999995930F, 0.9999996184F, 0.9999996426F, + 0.9999996657F, 0.9999996876F, 0.9999997084F, 0.9999997282F, + 0.9999997469F, 0.9999997647F, 0.9999997815F, 0.9999997973F, + 0.9999998123F, 0.9999998265F, 0.9999998398F, 0.9999998524F, + 0.9999998642F, 0.9999998753F, 0.9999998857F, 0.9999998954F, + 0.9999999045F, 0.9999999130F, 0.9999999209F, 0.9999999282F, + 0.9999999351F, 0.9999999414F, 0.9999999472F, 0.9999999526F, + 0.9999999576F, 0.9999999622F, 0.9999999664F, 0.9999999702F, + 0.9999999737F, 0.9999999769F, 0.9999999798F, 0.9999999824F, + 0.9999999847F, 0.9999999868F, 0.9999999887F, 0.9999999904F, + 0.9999999919F, 0.9999999932F, 0.9999999943F, 0.9999999953F, + 0.9999999961F, 0.9999999969F, 0.9999999975F, 0.9999999980F, + 0.9999999985F, 0.9999999988F, 0.9999999991F, 0.9999999993F, + 0.9999999995F, 0.9999999997F, 0.9999999998F, 0.9999999999F, + 0.9999999999F, 1.0000000000F, 1.0000000000F, 1.0000000000F, + 1.0000000000F, 1.0000000000F, 1.0000000000F, 1.0000000000F, +}; + +const float ff_vorbis_floor1_inverse_db_table[256]={ + 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F, + 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F, + 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F, + 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F, + 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F, + 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F, + 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F, + 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F, + 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F, + 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F, + 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F, + 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F, + 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F, + 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F, + 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F, + 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F, + 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F, + 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F, + 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F, + 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F, + 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F, + 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F, + 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F, + 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F, + 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F, + 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F, + 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F, + 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F, + 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F, + 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F, + 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F, + 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F, + 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F, + 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F, + 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F, + 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F, + 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F, + 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F, + 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F, + 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F, + 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F, + 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F, + 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F, + 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F, + 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F, + 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F, + 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F, + 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F, + 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F, + 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F, + 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F, + 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F, + 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F, + 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F, + 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F, + 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F, + 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F, + 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, + 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F, + 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F, + 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F, + 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F, + 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F, + 0.82788260F, 0.88168307F, 0.9389798F, 1.F, +}; + +const float * const ff_vorbis_vwin[8] = { + vwin64, vwin128, vwin256, vwin512, + vwin1024, vwin2048, vwin4096, vwin8192 +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_enc_data.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_enc_data.h new file mode 100644 index 0000000000..a51aaec978 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_enc_data.h @@ -0,0 +1,504 @@ +/* + * copyright (c) 2006 Oded Shimon + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VORBIS_ENC_DATA_H +#define AVCODEC_VORBIS_ENC_DATA_H + +#include + +static const uint8_t codebook0[] = { + 2, 10, 8, 14, 7, 12, 11, 14, 1, 5, 3, 7, 4, 9, 7, 13, +}; + +static const uint8_t codebook1[] = { + 1, 4, 2, 6, 3, 7, 5, 7, +}; + +static const uint8_t codebook2[] = { + 1, 5, 7, 21, 5, 8, 9, 21, 10, 9, 12, 20, 20, 16, 20, + 20, 4, 8, 9, 20, 6, 8, 9, 20, 11, 11, 13, 20, 20, 15, + 17, 20, 9, 11, 14, 20, 8, 10, 15, 20, 11, 13, 15, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 13, 20, 20, 20, 18, 18, 20, 20, + 20, 20, 20, 20, 3, 6, 8, 20, 6, 7, 9, 20, 10, 9, 12, + 20, 20, 20, 20, 20, 5, 7, 9, 20, 6, 6, 9, 20, 10, 9, + 12, 20, 20, 20, 20, 20, 8, 10, 13, 20, 8, 9, 12, 20, 11, + 10, 12, 20, 20, 20, 20, 20, 18, 20, 20, 20, 15, 17, 18, 20, + 18, 17, 18, 20, 20, 20, 20, 20, 7, 10, 12, 20, 8, 9, 11, + 20, 14, 13, 14, 20, 20, 20, 20, 20, 6, 9, 12, 20, 7, 8, + 11, 20, 12, 11, 13, 20, 20, 20, 20, 20, 9, 11, 15, 20, 8, + 10, 14, 20, 12, 11, 14, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 11, 16, 18, + 20, 15, 15, 17, 20, 20, 17, 20, 20, 20, 20, 20, 20, 9, 14, + 16, 20, 12, 12, 15, 20, 17, 15, 18, 20, 20, 20, 20, 20, 16, + 19, 18, 20, 15, 16, 20, 20, 17, 17, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, +}; + +static const uint8_t codebook3[] = { + 2, 3, 7, 13, 4, 4, 7, 15, 8, 6, 9, 17, 21, 16, 15, + 21, 2, 5, 7, 11, 5, 5, 7, 14, 9, 7, 10, 16, 17, 15, + 16, 21, 4, 7, 10, 17, 7, 7, 9, 15, 11, 9, 11, 16, 21, + 18, 15, 21, 18, 21, 21, 21, 15, 17, 17, 19, 21, 19, 18, 20, + 21, 21, 21, 20, +}; + +static const uint8_t codebook4[] = { + 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, + 5, 6, 5, 6, 5, 6, 5, 6, 5, 7, 5, 7, 5, 7, 5, + 7, 5, 8, 6, 8, 6, 8, 6, 9, 6, 9, 6, 10, 6, 10, + 6, 11, 6, 11, 7, 11, 7, 12, 7, 12, 7, 12, 7, 12, 7, + 12, 7, 12, 7, 12, 7, 12, 8, 13, 8, 12, 8, 12, 8, 13, + 8, 13, 9, 13, 9, 13, 9, 13, 9, 12, 10, 12, 10, 13, 10, + 14, 11, 14, 12, 14, 13, 14, 13, 14, 14, 15, 16, 15, 15, 15, + 14, 15, 17, 21, 22, 22, 21, 22, 22, 22, 22, 22, 22, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, +}; + +static const uint8_t codebook5[] = { + 2, 5, 5, 4, 5, 4, 5, 4, 5, 4, 6, 5, 6, 5, 6, + 5, 6, 5, 7, 5, 7, 6, 8, 6, 8, 6, 8, 6, 9, 6, + 9, 6, +}; + +static const uint8_t codebook6[] = { + 8, 5, 8, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, 4, 9, + 4, 9, 4, 9, 4, 9, 4, 8, 4, 8, 4, 9, 5, 9, 5, + 9, 5, 9, 5, 9, 6, 10, 6, 10, 7, 10, 8, 11, 9, 11, + 11, 12, 13, 12, 14, 13, 15, 13, 15, 14, 16, 14, 17, 15, 17, + 15, 15, 16, 16, 15, 16, 16, 16, 15, 18, 16, 15, 17, 17, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, +}; + +static const uint8_t codebook7[] = { + 1, 5, 5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 6, 5, 6, + 5, 6, 6, 7, 7, 7, 7, 8, 7, 8, 8, 9, 8, 10, 9, + 10, 9, +}; + +static const uint8_t codebook8[] = { + 4, 3, 4, 3, 4, 4, 5, 4, 5, 4, 5, 5, 6, 5, 6, + 5, 7, 5, 7, 6, 7, 6, 8, 7, 8, 7, 8, 7, 9, 8, + 9, 9, 9, 9, 10, 10, 10, 11, 9, 12, 9, 12, 9, 15, 10, + 14, 9, 13, 10, 13, 10, 12, 10, 12, 10, 13, 10, 12, 11, 13, + 11, 14, 12, 13, 13, 14, 14, 13, 14, 15, 14, 16, 13, 13, 14, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 15, 15, +}; + +static const uint8_t codebook9[] = { + 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4, 4, 4, 4, 5, + 5, 5, +}; + +static const uint8_t codebook10[] = { + 3, 3, 4, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 5, + 7, 5, 8, 6, 8, 6, 9, 7, 10, 7, 10, 8, 10, 8, 11, + 9, 11, +}; + +static const uint8_t codebook11[] = { + 3, 7, 3, 8, 3, 10, 3, 8, 3, 9, 3, 8, 4, 9, 4, + 9, 5, 9, 6, 10, 6, 9, 7, 11, 7, 12, 9, 13, 10, 13, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, +}; + +static const uint8_t codebook12[] = { + 4, 5, 4, 5, 4, 5, 4, 5, 3, 5, 3, 5, 3, 5, 4, + 5, 4, +}; + +static const uint8_t codebook13[] = { + 4, 2, 4, 2, 5, 3, 5, 4, 6, 6, 6, 7, 7, 8, 7, + 8, 7, 8, 7, 9, 8, 9, 8, 9, 8, 10, 8, 11, 9, 12, + 9, 12, +}; + +static const uint8_t codebook14[] = { + 2, 5, 2, 6, 3, 6, 4, 7, 4, 7, 5, 9, 5, 11, 6, + 11, 6, 11, 7, 11, 6, 11, 6, 11, 9, 11, 8, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, + 10, 10, 10, +}; + +static const uint8_t codebook15[] = { + 5, 6, 11, 11, 11, 11, 10, 10, 12, 11, 5, 2, 11, 5, 6, + 6, 7, 9, 11, 13, 13, 10, 7, 11, 6, 7, 8, 9, 10, 12, + 11, 5, 11, 6, 8, 7, 9, 11, 14, 15, 11, 6, 6, 8, 4, + 5, 7, 8, 10, 13, 10, 5, 7, 7, 5, 5, 6, 8, 10, 11, + 10, 7, 7, 8, 6, 5, 5, 7, 9, 9, 11, 8, 8, 11, 8, + 7, 6, 6, 7, 9, 12, 11, 10, 13, 9, 9, 7, 7, 7, 9, + 11, 13, 12, 15, 12, 11, 9, 8, 8, 8, +}; + +static const uint8_t codebook16[] = { + 2, 4, 4, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, + 0, 0, 0, 5, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, + 7, 8, 8, 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, + 0, 0, 0, 0, 0, 0, 6, 8, 7, 0, 0, 0, 0, 0, 0, + 7, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, + 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, 7, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 8, 8, 0, 0, 0, 0, 0, 0, 8, 8, 9, 0, 0, 0, + 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 8, 8, 0, 0, 0, 0, 0, 0, + 7, 9, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 7, 7, 0, 0, 0, 0, 0, 0, 7, 8, 8, + 0, 0, 0, 0, 0, 0, 7, 8, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 8, 8, 0, 0, 0, + 0, 0, 0, 8, 9, 9, 0, 0, 0, 0, 0, 0, 7, 8, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 8, 8, 0, 0, 0, 0, 0, 0, 8, 9, 9, 0, 0, 0, + 0, 0, 0, 8, 9, 8, +}; + +static const uint8_t codebook17[] = { + 2, 5, 5, 0, 0, 0, 5, 5, 0, 0, 0, 5, 5, 0, 0, + 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, + 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 5, 6, 6, 0, 0, 0, 7, 7, 0, 0, + 0, 7, 7, 0, 0, 0, 10, 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, + 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, + 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5, 7, 7, 0, 0, 0, 7, 7, 0, 0, + 0, 7, 7, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, + 5, 7, 7, 0, 0, 0, 7, 7, 0, 0, 0, 7, 7, 0, 0, + 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 10, 0, 0, + 0, 9, 9, 0, 0, 0, 9, 9, 0, 0, 0, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 8, 10, 10, 0, 0, 0, 9, 9, 0, 0, + 0, 9, 9, 0, 0, 0, 10, 10, +}; + +static const uint8_t codebook18[] = { + 2, 4, 3, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 6, 6, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 7, 9, 9, +}; + +static const uint8_t codebook19[] = { + 2, 3, 3, 6, 6, 0, 0, 0, 0, 0, 4, 4, 6, 6, 0, + 0, 0, 0, 0, 4, 4, 6, 6, 0, 0, 0, 0, 0, 5, 5, + 6, 6, 0, 0, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 0, + 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, + 0, 0, 0, 0, 0, 0, 9, 9, +}; + +static const uint8_t codebook20[] = { + 1, 3, 4, 6, 6, 7, 7, 9, 9, 0, 5, 5, 7, 7, 7, + 8, 9, 9, 0, 5, 5, 7, 7, 8, 8, 9, 9, 0, 7, 7, + 8, 8, 8, 8, 10, 10, 0, 0, 0, 8, 8, 8, 8, 10, 10, + 0, 0, 0, 9, 9, 9, 9, 10, 10, 0, 0, 0, 9, 9, 9, + 9, 10, 10, 0, 0, 0, 10, 10, 10, 10, 11, 11, 0, 0, 0, + 0, 0, 10, 10, 11, 11, +}; + +static const uint8_t codebook21[] = { + 2, 3, 3, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 10, 10, + 11, 10, 0, 5, 5, 7, 7, 8, 8, 9, 9, 9, 9, 10, 10, + 10, 10, 11, 11, 0, 5, 5, 7, 7, 8, 8, 9, 9, 9, 9, + 10, 10, 10, 10, 11, 11, 0, 6, 6, 7, 7, 8, 8, 9, 9, + 9, 9, 10, 10, 11, 11, 11, 11, 0, 0, 0, 7, 7, 8, 8, + 9, 9, 9, 9, 10, 10, 11, 11, 11, 12, 0, 0, 0, 8, 8, + 8, 8, 9, 9, 9, 9, 10, 10, 11, 11, 12, 12, 0, 0, 0, + 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 11, 11, 12, 12, 0, + 0, 0, 9, 9, 9, 9, 10, 10, 10, 10, 11, 10, 11, 11, 12, + 12, 0, 0, 0, 0, 0, 9, 9, 10, 10, 10, 10, 11, 11, 11, + 11, 12, 12, 0, 0, 0, 0, 0, 9, 8, 9, 9, 10, 10, 11, + 11, 12, 12, 12, 12, 0, 0, 0, 0, 0, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 11, 12, 12, 0, 0, 0, 0, 0, 9, 10, 10, + 10, 11, 11, 11, 11, 12, 12, 13, 13, 0, 0, 0, 0, 0, 0, + 0, 10, 10, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0, 0, 0, + 0, 0, 0, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 0, 0, + 0, 0, 0, 0, 0, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, + 0, 0, 0, 0, 0, 0, 0, 11, 11, 12, 12, 12, 12, 13, 13, + 13, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 12, + 13, 13, 13, 13, +}; + +static const uint8_t codebook22[] = { + 1, 4, 4, 7, 6, 6, 7, 6, 6, 4, 7, 7, 10, 9, 9, + 11, 9, 9, 4, 7, 7, 10, 9, 9, 11, 9, 9, 7, 10, 10, + 11, 11, 10, 12, 11, 11, 6, 9, 9, 11, 10, 10, 11, 10, 10, + 6, 9, 9, 11, 10, 10, 11, 10, 10, 7, 11, 11, 11, 11, 11, + 12, 11, 11, 6, 9, 9, 11, 10, 10, 11, 10, 10, 6, 9, 9, + 11, 10, 10, 11, 10, 10, +}; + +static const uint8_t codebook23[] = { + 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 8, 10, 5, 5, 6, + 6, 7, 7, 8, 8, 8, 8, 10, 5, 5, 6, 6, 7, 7, 8, + 8, 8, 8, 10, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 10, + 10, 10, 7, 7, 8, 7, 8, 8, 8, 8, 10, 10, 10, 8, 8, + 8, 8, 8, 8, 8, 8, 10, 10, 10, 7, 8, 8, 8, 8, 8, + 8, 8, 10, 10, 10, 8, 8, 8, 8, 8, 8, 8, 8, 10, 10, + 10, 10, 10, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 9, + 9, 8, 8, 9, 8, 10, 10, 10, 10, 10, 8, 8, 8, 8, 8, + 8, +}; + +static const uint8_t codebook24[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 6, 5, + 5, 7, 7, 8, 8, 8, 8, 9, 9, 10, 10, 7, 5, 5, 7, + 7, 8, 8, 8, 8, 9, 9, 11, 10, 0, 8, 8, 8, 8, 9, + 9, 9, 9, 10, 10, 11, 11, 0, 8, 8, 8, 8, 9, 9, 9, + 9, 10, 10, 11, 11, 0, 12, 12, 9, 9, 10, 10, 10, 10, 11, + 11, 11, 12, 0, 13, 13, 9, 9, 10, 10, 10, 10, 11, 11, 12, + 12, 0, 0, 0, 10, 10, 10, 10, 11, 11, 12, 12, 12, 12, 0, + 0, 0, 10, 10, 10, 10, 11, 11, 12, 12, 12, 12, 0, 0, 0, + 14, 14, 11, 11, 11, 11, 12, 12, 13, 13, 0, 0, 0, 14, 14, + 11, 11, 11, 11, 12, 12, 13, 13, 0, 0, 0, 0, 0, 12, 12, + 12, 12, 13, 13, 14, 13, 0, 0, 0, 0, 0, 13, 13, 12, 12, + 13, 12, 14, 13, +}; + +static const uint8_t codebook25[] = { + 2, 4, 4, 5, 5, 6, 5, 5, 5, 5, 6, 4, 5, 5, 5, + 6, 5, 5, 5, 5, 6, 6, 6, 5, 5, +}; + +static const uint8_t codebook26[] = { + 1, 4, 4, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 4, 9, + 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 9, 7, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, +}; + +static const uint8_t codebook27[] = { + 1, 4, 4, 6, 6, 7, 7, 8, 7, 9, 9, 10, 10, 10, 10, + 6, 5, 5, 7, 7, 8, 8, 10, 8, 11, 10, 12, 12, 13, 13, + 6, 5, 5, 7, 7, 8, 8, 10, 9, 11, 11, 12, 12, 13, 12, + 18, 8, 8, 8, 8, 9, 9, 10, 9, 11, 10, 12, 12, 13, 13, + 18, 8, 8, 8, 8, 9, 9, 10, 10, 11, 11, 13, 12, 14, 13, + 18, 11, 11, 9, 9, 10, 10, 11, 11, 11, 12, 13, 12, 13, 14, + 18, 11, 11, 9, 8, 11, 10, 11, 11, 11, 11, 12, 12, 14, 13, + 18, 18, 18, 10, 11, 10, 11, 12, 12, 12, 12, 13, 12, 14, 13, + 18, 18, 18, 10, 11, 11, 9, 12, 11, 12, 12, 12, 13, 13, 13, + 18, 18, 17, 14, 14, 11, 11, 12, 12, 13, 12, 14, 12, 14, 13, + 18, 18, 18, 14, 14, 11, 10, 12, 9, 12, 13, 13, 13, 13, 13, + 18, 18, 17, 16, 18, 13, 13, 12, 12, 13, 11, 14, 12, 14, 14, + 17, 18, 18, 17, 18, 13, 12, 13, 10, 12, 11, 14, 14, 14, 14, + 17, 18, 18, 18, 18, 15, 16, 12, 12, 13, 10, 14, 12, 14, 15, + 18, 18, 18, 16, 17, 16, 14, 12, 11, 13, 10, 13, 13, 14, 15, +}; + +static const uint8_t codebook28[] = { + 2, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 10, 6, 6, 7, 7, 8, 7, 8, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 10, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 10, 7, 7, 7, 7, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 7, 7, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 8, 8, + 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, + 10, 10, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, + 9, 10, 10, 10, 11, 11, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 11, 10, 11, 11, 11, 9, 9, 9, 9, 9, 9, 10, + 10, 9, 9, 10, 9, 11, 10, 11, 11, 11, 9, 9, 9, 9, 9, + 9, 9, 9, 10, 10, 10, 9, 11, 11, 11, 11, 11, 9, 9, 9, + 9, 10, 10, 9, 9, 9, 9, 10, 9, 11, 11, 11, 11, 11, 11, + 11, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, + 11, 11, 11, 10, 9, 10, 10, 9, 10, 9, 9, 10, 9, 11, 10, + 10, 11, 11, 11, 11, 9, 10, 9, 9, 9, 9, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 10, 10, 10, 9, 9, 10, 9, 10, 9, + 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 9, 9, 9, 9, + 9, 10, 10, 10, +}; + +static const struct { + int dim; + int len; + int real_len; + const uint8_t *clens; + int lookup; + float min; + float delta; + const uint8_t *quant; +} cvectors[] = { + { 2, 16, 16, codebook0, 0 }, + { 2, 8, 8, codebook1, 0 }, + { 2, 256, 256, codebook2, 0 }, + { 2, 64, 64, codebook3, 0 }, + { 2, 128, 128, codebook4, 0 }, + { 2, 32, 32, codebook5, 0 }, + { 2, 96, 96, codebook6, 0 }, + { 2, 32, 32, codebook7, 0 }, + { 2, 96, 96, codebook8, 0 }, + { 2, 17, 17, codebook9, 0 }, + { 2, 32, 32, codebook10, 0 }, + { 2, 78, 78, codebook11, 0 }, + { 2, 17, 17, codebook12, 0 }, + { 2, 32, 32, codebook13, 0 }, + { 2, 78, 78, codebook14, 0 }, + { 2, 100, 100, codebook15, 0 }, + { 8, 1641, 6561, codebook16, 1, -1.0, 1.0, (const uint8_t[]){ 1, 0, 2, } }, + { 4, 443, 625, codebook17, 1, -2.0, 1.0, (const uint8_t[]){ 2, 1, 3, 0, 4, } }, + { 4, 105, 625, codebook18, 1, -2.0, 1.0, (const uint8_t[]){ 2, 1, 3, 0, 4, } }, + { 2, 68, 81, codebook19, 1, -4.0, 1.0, (const uint8_t[]){ 4, 3, 5, 2, 6, 1, 7, 0, 8, } }, + { 2, 81, 81, codebook20, 1, -4.0, 1.0, (const uint8_t[]){ 4, 3, 5, 2, 6, 1, 7, 0, 8, } }, + { 2, 289, 289, codebook21, 1, -8.0, 1.0, (const uint8_t[]){ 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, 0, 16, } }, + { 4, 81, 81, codebook22, 1, -11.0, 11.0, (const uint8_t[]){ 1, 0, 2, } }, + { 2, 121, 121, codebook23, 1, -5.0, 1.0, (const uint8_t[]){ 5, 4, 6, 3, 7, 2, 8, 1, 9, 0, 10, } }, + { 2, 169, 169, codebook24, 1, -30.0, 5.0, (const uint8_t[]){ 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12, } }, + { 2, 25, 25, codebook25, 1, -2.0, 1.0, (const uint8_t[]){ 2, 1, 3, 0, 4, } }, + { 2, 169, 169, codebook26, 1, -1530.0, 255.0, (const uint8_t[]){ 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12, } }, + { 2, 225, 225, codebook27, 1, -119.0, 17.0, (const uint8_t[]){ 7, 6, 8, 5, 9, 4, 10, 3, 11, 2, 12, 1, 13, 0, 14, } }, + { 2, 289, 289, codebook28, 1, -8.0, 1.0, (const uint8_t[]){ 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, 0, 16, } }, +}; + +static const struct { + int dim; + int subclass; + int masterbook; + const int nbooks[4]; +} floor_classes[] = { + { 3, 0, 0, { 4 } }, + { 4, 1, 0, { 5, 6 } }, + { 3, 1, 1, { 7, 8 } }, + { 4, 2, 2, { -1, 9, 10, 11 } }, + { 3, 2, 3, { -1, 12, 13, 14 } }, +}; + +#endif /* AVCODEC_VORBIS_ENC_DATA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser.c new file mode 100644 index 0000000000..0b2c97cde5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Vorbis audio parser + * + * Determines the duration for each packet. + */ + +#include "libavutil/log.h" + +#include "get_bits.h" +#include "parser.h" +#include "xiph.h" +#include "vorbis_parser_internal.h" + +static const AVClass vorbis_parser_class = { + .class_name = "Vorbis parser", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +static int parse_id_header(AVVorbisParseContext *s, + const uint8_t *buf, int buf_size) +{ + /* Id header should be 30 bytes */ + if (buf_size < 30) { + av_log(s, AV_LOG_ERROR, "Id header is too short\n"); + return AVERROR_INVALIDDATA; + } + + /* make sure this is the Id header */ + if (buf[0] != 1) { + av_log(s, AV_LOG_ERROR, "Wrong packet type in Id header\n"); + return AVERROR_INVALIDDATA; + } + + /* check for header signature */ + if (memcmp(&buf[1], "vorbis", 6)) { + av_log(s, AV_LOG_ERROR, "Invalid packet signature in Id header\n"); + return AVERROR_INVALIDDATA; + } + + if (!(buf[29] & 0x1)) { + av_log(s, AV_LOG_ERROR, "Invalid framing bit in Id header\n"); + return AVERROR_INVALIDDATA; + } + + s->blocksize[0] = 1 << (buf[28] & 0xF); + s->blocksize[1] = 1 << (buf[28] >> 4); + + return 0; +} + +static int parse_setup_header(AVVorbisParseContext *s, + const uint8_t *buf, int buf_size) +{ + GetBitContext gb, gb0; + uint8_t *rev_buf; + int i, ret = 0; + int got_framing_bit, mode_count, got_mode_header, last_mode_count = 0; + + /* avoid overread */ + if (buf_size < 7) { + av_log(s, AV_LOG_ERROR, "Setup header is too short\n"); + return AVERROR_INVALIDDATA; + } + + /* make sure this is the Setup header */ + if (buf[0] != 5) { + av_log(s, AV_LOG_ERROR, "Wrong packet type in Setup header\n"); + return AVERROR_INVALIDDATA; + } + + /* check for header signature */ + if (memcmp(&buf[1], "vorbis", 6)) { + av_log(s, AV_LOG_ERROR, "Invalid packet signature in Setup header\n"); + return AVERROR_INVALIDDATA; + } + + /* reverse bytes so we can easily read backwards with get_bits() */ + if (!(rev_buf = av_malloc(buf_size))) { + av_log(s, AV_LOG_ERROR, "Out of memory\n"); + return AVERROR(ENOMEM); + } + for (i = 0; i < buf_size; i++) + rev_buf[i] = buf[buf_size - 1 - i]; + init_get_bits(&gb, rev_buf, buf_size * 8); + + got_framing_bit = 0; + while (get_bits_left(&gb) > 97) { + if (get_bits1(&gb)) { + got_framing_bit = get_bits_count(&gb); + break; + } + } + if (!got_framing_bit) { + av_log(s, AV_LOG_ERROR, "Invalid Setup header\n"); + ret = AVERROR_INVALIDDATA; + goto bad_header; + } + + /* Now we search backwards to find possible valid mode counts. This is not + * fool-proof because we could have false positive matches and read too + * far, but there isn't really any way to be sure without parsing through + * all the many variable-sized fields before the modes. This approach seems + * to work well in testing, and it is similar to how it is handled in + * liboggz. */ + mode_count = 0; + got_mode_header = 0; + while (get_bits_left(&gb) >= 97) { + if (get_bits(&gb, 8) > 63 || get_bits(&gb, 16) || get_bits(&gb, 16)) + break; + skip_bits(&gb, 1); + mode_count++; + if (mode_count > 64) + break; + gb0 = gb; + if (get_bits(&gb0, 6) + 1 == mode_count) { + got_mode_header = 1; + last_mode_count = mode_count; + } + } + if (!got_mode_header) { + av_log(s, AV_LOG_ERROR, "Invalid Setup header\n"); + ret = AVERROR_INVALIDDATA; + goto bad_header; + } + /* All samples I've seen use <= 2 modes, so ask for a sample if we find + * more than that, as it is most likely a false positive. If we get any + * we may need to approach this the long way and parse the whole Setup + * header, but I hope very much that it never comes to that. */ + if (last_mode_count > 2) { + avpriv_request_sample(s, + "%d modes (either a false positive or a " + "sample from an unknown encoder)", + last_mode_count); + } + /* We're limiting the mode count to 63 so that we know that the previous + * block flag will be in the first packet byte. */ + if (last_mode_count > 63) { + av_log(s, AV_LOG_ERROR, "Unsupported mode count: %d\n", + last_mode_count); + ret = AVERROR_INVALIDDATA; + goto bad_header; + } + s->mode_count = mode_count = last_mode_count; + /* Determine the number of bits required to code the mode and turn that + * into a bitmask to directly access the mode from the first frame byte. */ + s->mode_mask = ((1 << (av_log2(mode_count - 1) + 1)) - 1) << 1; + /* The previous window flag is the next bit after the mode */ + s->prev_mask = (s->mode_mask | 0x1) + 1; + + init_get_bits(&gb, rev_buf, buf_size * 8); + skip_bits_long(&gb, got_framing_bit); + for (i = mode_count - 1; i >= 0; i--) { + skip_bits_long(&gb, 40); + s->mode_blocksize[i] = get_bits1(&gb); + } + +bad_header: + av_free(rev_buf); + return ret; +} + +static int vorbis_parse_init(AVVorbisParseContext *s, + const uint8_t *extradata, int extradata_size) +{ + const uint8_t *header_start[3]; + int header_len[3]; + int ret; + + s->class = &vorbis_parser_class; + s->extradata_parsed = 1; + + if ((ret = avpriv_split_xiph_headers(extradata, + extradata_size, 30, + header_start, header_len)) < 0) { + av_log(s, AV_LOG_ERROR, "Extradata corrupt.\n"); + return ret; + } + + if ((ret = parse_id_header(s, header_start[0], header_len[0])) < 0) + return ret; + + if ((ret = parse_setup_header(s, header_start[2], header_len[2])) < 0) + return ret; + + s->valid_extradata = 1; + s->previous_blocksize = s->blocksize[s->mode_blocksize[0]]; + + return 0; +} + +int av_vorbis_parse_frame_flags(AVVorbisParseContext *s, const uint8_t *buf, + int buf_size, int *flags) +{ + int duration = 0; + + if (s->valid_extradata && buf_size > 0) { + int mode, current_blocksize; + int previous_blocksize = s->previous_blocksize; + + if (buf[0] & 1) { + /* If the user doesn't care about special packets, it's a bad one. */ + if (!flags) + goto bad_packet; + + /* Set the flag for which kind of special packet it is. */ + if (buf[0] == 1) + *flags |= VORBIS_FLAG_HEADER; + else if (buf[0] == 3) + *flags |= VORBIS_FLAG_COMMENT; + else if (buf[0] == 5) + *flags |= VORBIS_FLAG_SETUP; + else + goto bad_packet; + + /* Special packets have no duration. */ + return 0; + +bad_packet: + av_log(s, AV_LOG_ERROR, "Invalid packet\n"); + return AVERROR_INVALIDDATA; + } + if (s->mode_count == 1) + mode = 0; + else + mode = (buf[0] & s->mode_mask) >> 1; + if (mode >= s->mode_count) { + av_log(s, AV_LOG_ERROR, "Invalid mode in packet\n"); + return AVERROR_INVALIDDATA; + } + if(s->mode_blocksize[mode]){ + int flag = !!(buf[0] & s->prev_mask); + previous_blocksize = s->blocksize[flag]; + } + current_blocksize = s->blocksize[s->mode_blocksize[mode]]; + duration = (previous_blocksize + current_blocksize) >> 2; + s->previous_blocksize = current_blocksize; + } + + return duration; +} + +int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf, + int buf_size) +{ + return av_vorbis_parse_frame_flags(s, buf, buf_size, NULL); +} + +void av_vorbis_parse_reset(AVVorbisParseContext *s) +{ + if (s->valid_extradata) + s->previous_blocksize = s->blocksize[0]; +} + +void av_vorbis_parse_free(AVVorbisParseContext **s) +{ + av_freep(s); +} + +AVVorbisParseContext *av_vorbis_parse_init(const uint8_t *extradata, + int extradata_size) +{ + AVVorbisParseContext *s = av_mallocz(sizeof(*s)); + int ret; + + if (!s) + return NULL; + + ret = vorbis_parse_init(s, extradata, extradata_size); + if (ret < 0) { + av_vorbis_parse_free(&s); + return NULL; + } + + return s; +} + +#if CONFIG_VORBIS_PARSER + +typedef struct VorbisParseContext { + AVVorbisParseContext *vp; +} VorbisParseContext; + +static int vorbis_parse(AVCodecParserContext *s1, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + VorbisParseContext *s = s1->priv_data; + int duration; + + if (!s->vp && avctx->extradata && avctx->extradata_size) { + s->vp = av_vorbis_parse_init(avctx->extradata, avctx->extradata_size); + } + if (!s->vp) + goto end; + + if ((duration = av_vorbis_parse_frame(s->vp, buf, buf_size)) >= 0) + s1->duration = duration; + +end: + /* always return the full packet. this parser isn't doing any splitting or + combining, only packet analysis */ + *poutbuf = buf; + *poutbuf_size = buf_size; + return buf_size; +} + +static void vorbis_parser_close(AVCodecParserContext *ctx) +{ + VorbisParseContext *s = ctx->priv_data; + av_vorbis_parse_free(&s->vp); +} + +AVCodecParser ff_vorbis_parser = { + .codec_ids = { AV_CODEC_ID_VORBIS }, + .priv_data_size = sizeof(VorbisParseContext), + .parser_parse = vorbis_parse, + .parser_close = vorbis_parser_close, +}; +#endif /* CONFIG_VORBIS_PARSER */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser.h new file mode 100644 index 0000000000..789932ac49 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser.h @@ -0,0 +1,74 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * A public API for Vorbis parsing + * + * Determines the duration for each packet. + */ + +#ifndef AVCODEC_VORBIS_PARSER_H +#define AVCODEC_VORBIS_PARSER_H + +#include + +typedef struct AVVorbisParseContext AVVorbisParseContext; + +/** + * Allocate and initialize the Vorbis parser using headers in the extradata. + */ +AVVorbisParseContext *av_vorbis_parse_init(const uint8_t *extradata, + int extradata_size); + +/** + * Free the parser and everything associated with it. + */ +void av_vorbis_parse_free(AVVorbisParseContext **s); + +#define VORBIS_FLAG_HEADER 0x00000001 +#define VORBIS_FLAG_COMMENT 0x00000002 +#define VORBIS_FLAG_SETUP 0x00000004 + +/** + * Get the duration for a Vorbis packet. + * + * If @p flags is @c NULL, + * special frames are considered invalid. + * + * @param s Vorbis parser context + * @param buf buffer containing a Vorbis frame + * @param buf_size size of the buffer + * @param flags flags for special frames + */ +int av_vorbis_parse_frame_flags(AVVorbisParseContext *s, const uint8_t *buf, + int buf_size, int *flags); + +/** + * Get the duration for a Vorbis packet. + * + * @param s Vorbis parser context + * @param buf buffer containing a Vorbis frame + * @param buf_size size of the buffer + */ +int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf, + int buf_size); + +void av_vorbis_parse_reset(AVVorbisParseContext *s); + +#endif /* AVCODEC_VORBIS_PARSER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser_internal.h new file mode 100644 index 0000000000..691a842385 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbis_parser_internal.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Vorbis audio parser + * + * Determines the duration for each packet. + */ + +#ifndef AVCODEC_VORBIS_PARSER_INTERNAL_H +#define AVCODEC_VORBIS_PARSER_INTERNAL_H + +#include "avcodec.h" +#include "vorbis_parser.h" + +struct AVVorbisParseContext { + const AVClass *class; + int extradata_parsed; ///< we have attempted to parse extradata + int valid_extradata; ///< extradata is valid, so we can calculate duration + int blocksize[2]; ///< short and long window sizes + int previous_blocksize; ///< previous window size + int mode_blocksize[64]; ///< window size mapping for each mode + int mode_count; ///< number of modes + int mode_mask; ///< bitmask used to get the mode in each packet + int prev_mask; ///< bitmask used to get the previous mode flag in each packet +}; + +#endif /* AVCODEC_VORBIS_PARSER_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbisdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbisdsp.h new file mode 100644 index 0000000000..7abec4e4b7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/vorbisdsp.h @@ -0,0 +1,38 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VORBISDSP_H +#define AVCODEC_VORBISDSP_H + +#include + +typedef struct VorbisDSPContext { + /* assume len is a multiple of 4, and arrays are 16-byte aligned */ + void (*vorbis_inverse_coupling)(float *mag, float *ang, + intptr_t blocksize); +} VorbisDSPContext; + +void ff_vorbisdsp_init(VorbisDSPContext *dsp); + +/* for internal use only */ +void ff_vorbisdsp_init_aarch64(VorbisDSPContext *dsp); +void ff_vorbisdsp_init_x86(VorbisDSPContext *dsp); +void ff_vorbisdsp_init_arm(VorbisDSPContext *dsp); +void ff_vorbisdsp_init_ppc(VorbisDSPContext *dsp); + +#endif /* AVCODEC_VORBISDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacencdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacencdsp_init.c new file mode 100644 index 0000000000..d761c3c5e6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacencdsp_init.c @@ -0,0 +1,43 @@ +/* + * AAC encoder assembly optimizations + * Copyright (C) 2016 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/float_dsp.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/aacenc.h" + +void ff_abs_pow34_sse(float *out, const float *in, const int size); + +void ff_aac_quantize_bands_sse2(int *out, const float *in, const float *scaled, + int size, int is_signed, int maxval, const float Q34, + const float rounding); + +av_cold void ff_aac_dsp_init_x86(AACEncContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE(cpu_flags)) + s->abs_pow34 = ff_abs_pow34_sse; + + if (EXTERNAL_SSE2(cpu_flags)) + s->quant_bands = ff_aac_quantize_bands_sse2; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacpsdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacpsdsp_init.c new file mode 100644 index 0000000000..21f00efa24 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacpsdsp_init.c @@ -0,0 +1,72 @@ +/* + * SIMD optimized MPEG-4 Parametric Stereo decoding functions + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" + +#include "libavutil/x86/cpu.h" +#include "libavutil/attributes.h" +#include "libavcodec/aacpsdsp.h" + +void ff_ps_add_squares_sse (float *dst, const float (*src)[2], int n); +void ff_ps_add_squares_sse3 (float *dst, const float (*src)[2], int n); +void ff_ps_mul_pair_single_sse (float (*dst)[2], float (*src0)[2], + float *src1, int n); +void ff_ps_hybrid_analysis_sse (float (*out)[2], float (*in)[2], + const float (*filter)[8][2], + ptrdiff_t stride, int n); +void ff_ps_hybrid_analysis_sse3(float (*out)[2], float (*in)[2], + const float (*filter)[8][2], + ptrdiff_t stride, int n); +void ff_ps_stereo_interpolate_sse3(float (*l)[2], float (*r)[2], + float h[2][4], float h_step[2][4], + int len); +void ff_ps_stereo_interpolate_ipdopd_sse3(float (*l)[2], float (*r)[2], + float h[2][4], float h_step[2][4], + int len); +void ff_ps_hybrid_synthesis_deint_sse(float out[2][38][64], float (*in)[32][2], + int i, int len); +void ff_ps_hybrid_synthesis_deint_sse4(float out[2][38][64], float (*in)[32][2], + int i, int len); +void ff_ps_hybrid_analysis_ileave_sse(float (*out)[32][2], float L[2][38][64], + int i, int len); + +av_cold void ff_psdsp_init_x86(PSDSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE(cpu_flags)) { + s->add_squares = ff_ps_add_squares_sse; + s->mul_pair_single = ff_ps_mul_pair_single_sse; + s->hybrid_analysis_ileave = ff_ps_hybrid_analysis_ileave_sse; + s->hybrid_synthesis_deint = ff_ps_hybrid_synthesis_deint_sse; + s->hybrid_analysis = ff_ps_hybrid_analysis_sse; + } + if (EXTERNAL_SSE3(cpu_flags)) { + s->add_squares = ff_ps_add_squares_sse3; + s->stereo_interpolate[0] = ff_ps_stereo_interpolate_sse3; + s->stereo_interpolate[1] = ff_ps_stereo_interpolate_ipdopd_sse3; + s->hybrid_analysis = ff_ps_hybrid_analysis_sse3; + } + if (EXTERNAL_SSE4(cpu_flags)) { + s->hybrid_synthesis_deint = ff_ps_hybrid_synthesis_deint_sse4; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ac3dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ac3dsp_init.c new file mode 100644 index 0000000000..2e7e2fb6da --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ac3dsp_init.c @@ -0,0 +1,164 @@ +/* + * x86-optimized AC-3 DSP functions + * Copyright (c) 2011 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/mem.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/ac3.h" +#include "libavcodec/ac3dsp.h" + +void ff_ac3_exponent_min_mmx (uint8_t *exp, int num_reuse_blocks, int nb_coefs); +void ff_ac3_exponent_min_mmxext(uint8_t *exp, int num_reuse_blocks, int nb_coefs); +void ff_ac3_exponent_min_sse2 (uint8_t *exp, int num_reuse_blocks, int nb_coefs); + +int ff_ac3_max_msb_abs_int16_mmx (const int16_t *src, int len); +int ff_ac3_max_msb_abs_int16_mmxext(const int16_t *src, int len); +int ff_ac3_max_msb_abs_int16_sse2 (const int16_t *src, int len); +int ff_ac3_max_msb_abs_int16_ssse3(const int16_t *src, int len); + +void ff_ac3_lshift_int16_mmx (int16_t *src, unsigned int len, unsigned int shift); +void ff_ac3_lshift_int16_sse2(int16_t *src, unsigned int len, unsigned int shift); + +void ff_ac3_rshift_int32_mmx (int32_t *src, unsigned int len, unsigned int shift); +void ff_ac3_rshift_int32_sse2(int32_t *src, unsigned int len, unsigned int shift); + +void ff_float_to_fixed24_3dnow(int32_t *dst, const float *src, unsigned int len); +void ff_float_to_fixed24_sse (int32_t *dst, const float *src, unsigned int len); +void ff_float_to_fixed24_sse2 (int32_t *dst, const float *src, unsigned int len); + +int ff_ac3_compute_mantissa_size_sse2(uint16_t mant_cnt[6][16]); + +void ff_ac3_extract_exponents_sse2 (uint8_t *exp, int32_t *coef, int nb_coefs); +void ff_ac3_extract_exponents_ssse3(uint8_t *exp, int32_t *coef, int nb_coefs); + +void ff_apply_window_int16_round_mmxext(int16_t *output, const int16_t *input, + const int16_t *window, unsigned int len); +void ff_apply_window_int16_round_sse2(int16_t *output, const int16_t *input, + const int16_t *window, unsigned int len); +void ff_apply_window_int16_mmxext(int16_t *output, const int16_t *input, + const int16_t *window, unsigned int len); +void ff_apply_window_int16_sse2(int16_t *output, const int16_t *input, + const int16_t *window, unsigned int len); +void ff_apply_window_int16_ssse3(int16_t *output, const int16_t *input, + const int16_t *window, unsigned int len); +void ff_apply_window_int16_ssse3_atom(int16_t *output, const int16_t *input, + const int16_t *window, unsigned int len); + +av_cold void ff_ac3dsp_init_x86(AC3DSPContext *c, int bit_exact) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + c->ac3_exponent_min = ff_ac3_exponent_min_mmx; + c->ac3_max_msb_abs_int16 = ff_ac3_max_msb_abs_int16_mmx; + c->ac3_lshift_int16 = ff_ac3_lshift_int16_mmx; + c->ac3_rshift_int32 = ff_ac3_rshift_int32_mmx; + } + if (EXTERNAL_AMD3DNOW(cpu_flags)) { + if (!bit_exact) { + c->float_to_fixed24 = ff_float_to_fixed24_3dnow; + } + } + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->ac3_exponent_min = ff_ac3_exponent_min_mmxext; + c->ac3_max_msb_abs_int16 = ff_ac3_max_msb_abs_int16_mmxext; + if (bit_exact) { + c->apply_window_int16 = ff_apply_window_int16_mmxext; + } else { + c->apply_window_int16 = ff_apply_window_int16_round_mmxext; + } + } + if (EXTERNAL_SSE(cpu_flags)) { + c->float_to_fixed24 = ff_float_to_fixed24_sse; + } + if (EXTERNAL_SSE2(cpu_flags)) { + c->ac3_exponent_min = ff_ac3_exponent_min_sse2; + c->ac3_max_msb_abs_int16 = ff_ac3_max_msb_abs_int16_sse2; + c->float_to_fixed24 = ff_float_to_fixed24_sse2; + c->compute_mantissa_size = ff_ac3_compute_mantissa_size_sse2; + c->extract_exponents = ff_ac3_extract_exponents_sse2; + if (bit_exact) { + c->apply_window_int16 = ff_apply_window_int16_sse2; + } + } + + if (EXTERNAL_SSE2_FAST(cpu_flags)) { + c->ac3_lshift_int16 = ff_ac3_lshift_int16_sse2; + c->ac3_rshift_int32 = ff_ac3_rshift_int32_sse2; + if (!bit_exact) { + c->apply_window_int16 = ff_apply_window_int16_round_sse2; + } + } + + if (EXTERNAL_SSSE3(cpu_flags)) { + c->ac3_max_msb_abs_int16 = ff_ac3_max_msb_abs_int16_ssse3; + if (cpu_flags & AV_CPU_FLAG_ATOM) { + c->apply_window_int16 = ff_apply_window_int16_ssse3_atom; + } else { + c->extract_exponents = ff_ac3_extract_exponents_ssse3; + c->apply_window_int16 = ff_apply_window_int16_ssse3; + } + } +} + +#define DOWNMIX_FUNC_OPT(ch, opt) \ +void ff_ac3_downmix_ ## ch ## _to_1_ ## opt(float **samples, \ + float **matrix, int len); \ +void ff_ac3_downmix_ ## ch ## _to_2_ ## opt(float **samples, \ + float **matrix, int len); + +#define DOWNMIX_FUNCS(opt) \ + DOWNMIX_FUNC_OPT(3, opt) \ + DOWNMIX_FUNC_OPT(4, opt) \ + DOWNMIX_FUNC_OPT(5, opt) \ + DOWNMIX_FUNC_OPT(6, opt) + +DOWNMIX_FUNCS(sse) +DOWNMIX_FUNCS(avx) +DOWNMIX_FUNCS(fma3) + +void ff_ac3dsp_set_downmix_x86(AC3DSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + +#define SET_DOWNMIX(ch, suf, SUF) \ + if (ch == c->in_channels) { \ + if (EXTERNAL_ ## SUF (cpu_flags)) { \ + if (c->out_channels == 1) \ + c->downmix = ff_ac3_downmix_ ## ch ## _to_1_ ## suf; \ + else \ + c->downmix = ff_ac3_downmix_ ## ch ## _to_2_ ## suf; \ + } \ + } + +#define SET_DOWNMIX_ALL(suf, SUF) \ + SET_DOWNMIX(3, suf, SUF) \ + SET_DOWNMIX(4, suf, SUF) \ + SET_DOWNMIX(5, suf, SUF) \ + SET_DOWNMIX(6, suf, SUF) + + SET_DOWNMIX_ALL(sse, SSE) + if (!(cpu_flags & AV_CPU_FLAG_AVXSLOW)) { + SET_DOWNMIX_ALL(avx, AVX) + SET_DOWNMIX_ALL(fma3, FMA3) + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/alacdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/alacdsp_init.c new file mode 100644 index 0000000000..18f7308a12 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/alacdsp_init.c @@ -0,0 +1,44 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/alacdsp.h" +#include "config.h" + +void ff_alac_decorrelate_stereo_sse4(int32_t *buffer[2], int nb_samples, + int decorr_shift, int decorr_left_weight); +void ff_alac_append_extra_bits_stereo_sse2(int32_t *buffer[2], int32_t *extra_bits_buffer[2], + int extra_bits, int channels, int nb_samples); +void ff_alac_append_extra_bits_mono_sse2(int32_t *buffer[2], int32_t *extra_bits_buffer[2], + int extra_bits, int channels, int nb_samples); + +av_cold void ff_alacdsp_init_x86(ALACDSPContext *c) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE2(cpu_flags)) { + c->append_extra_bits[0] = ff_alac_append_extra_bits_mono_sse2; + c->append_extra_bits[1] = ff_alac_append_extra_bits_stereo_sse2; + } + if (EXTERNAL_SSE4(cpu_flags)) { + c->decorrelate_stereo = ff_alac_decorrelate_stereo_sse4; + } +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/audiodsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/audiodsp_init.c new file mode 100644 index 0000000000..98e296c264 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/audiodsp_init.c @@ -0,0 +1,66 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/audiodsp.h" + +int32_t ff_scalarproduct_int16_mmxext(const int16_t *v1, const int16_t *v2, + int order); +int32_t ff_scalarproduct_int16_sse2(const int16_t *v1, const int16_t *v2, + int order); + +void ff_vector_clip_int32_mmx(int32_t *dst, const int32_t *src, + int32_t min, int32_t max, unsigned int len); +void ff_vector_clip_int32_sse2(int32_t *dst, const int32_t *src, + int32_t min, int32_t max, unsigned int len); +void ff_vector_clip_int32_int_sse2(int32_t *dst, const int32_t *src, + int32_t min, int32_t max, unsigned int len); +void ff_vector_clip_int32_sse4(int32_t *dst, const int32_t *src, + int32_t min, int32_t max, unsigned int len); +void ff_vector_clipf_sse(float *dst, const float *src, + int len, float min, float max); + +av_cold void ff_audiodsp_init_x86(AudioDSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) + c->vector_clip_int32 = ff_vector_clip_int32_mmx; + + if (EXTERNAL_MMXEXT(cpu_flags)) + c->scalarproduct_int16 = ff_scalarproduct_int16_mmxext; + + if (EXTERNAL_SSE(cpu_flags)) + c->vector_clipf = ff_vector_clipf_sse; + + if (EXTERNAL_SSE2(cpu_flags)) { + c->scalarproduct_int16 = ff_scalarproduct_int16_sse2; + if (cpu_flags & AV_CPU_FLAG_ATOM) + c->vector_clip_int32 = ff_vector_clip_int32_int_sse2; + else + c->vector_clip_int32 = ff_vector_clip_int32_sse2; + } + + if (EXTERNAL_SSE4(cpu_flags)) + c->vector_clip_int32 = ff_vector_clip_int32_sse4; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/blockdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/blockdsp_init.c new file mode 100644 index 0000000000..8b01a447cd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/blockdsp_init.c @@ -0,0 +1,60 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/internal.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/blockdsp.h" +#include "libavcodec/version.h" + +void ff_clear_block_mmx(int16_t *block); +void ff_clear_block_sse(int16_t *block); +void ff_clear_block_avx(int16_t *block); +void ff_clear_blocks_mmx(int16_t *blocks); +void ff_clear_blocks_sse(int16_t *blocks); +void ff_clear_blocks_avx(int16_t *blocks); + +av_cold void ff_blockdsp_init_x86(BlockDSPContext *c, + AVCodecContext *avctx) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + c->clear_block = ff_clear_block_mmx; + c->clear_blocks = ff_clear_blocks_mmx; + } + + /* XvMCCreateBlocks() may not allocate 16-byte aligned blocks */ + if (CONFIG_XVMC && avctx->hwaccel && avctx->hwaccel->decode_mb) + return; + + if (EXTERNAL_SSE(cpu_flags)) { + c->clear_block = ff_clear_block_sse; + c->clear_blocks = ff_clear_blocks_sse; + } + if (EXTERNAL_AVX_FAST(cpu_flags)) { + c->clear_block = ff_clear_block_avx; + c->clear_blocks = ff_clear_blocks_avx; + } +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/bswapdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/bswapdsp_init.c new file mode 100644 index 0000000000..877bab1a2c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/bswapdsp_init.c @@ -0,0 +1,40 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/bswapdsp.h" + +void ff_bswap32_buf_sse2(uint32_t *dst, const uint32_t *src, int w); +void ff_bswap32_buf_ssse3(uint32_t *dst, const uint32_t *src, int w); +void ff_bswap32_buf_avx2(uint32_t *dst, const uint32_t *src, int w); + +av_cold void ff_bswapdsp_init_x86(BswapDSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE2(cpu_flags)) + c->bswap_buf = ff_bswap32_buf_sse2; + if (EXTERNAL_SSSE3(cpu_flags)) + c->bswap_buf = ff_bswap32_buf_ssse3; + if (EXTERNAL_AVX2_FAST(cpu_flags)) + c->bswap_buf = ff_bswap32_buf_avx2; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/cabac.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/cabac.h new file mode 100644 index 0000000000..cfd3b759c9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/cabac.h @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_CABAC_H +#define AVCODEC_X86_CABAC_H + +#include "libavcodec/cabac.h" +#include "libavutil/attributes.h" +#include "libavutil/macros.h" +#include "libavutil/x86/asm.h" +#include "config.h" + +#if (defined(__i386) && defined(__clang__) && (__clang_major__<2 || (__clang_major__==2 && __clang_minor__<10)))\ + || ( !defined(__clang__) && defined(__llvm__) && __GNUC__==4 && __GNUC_MINOR__==2 && __GNUC_PATCHLEVEL__<=1)\ + || (defined(__INTEL_COMPILER) && defined(_MSC_VER)) +# define BROKEN_COMPILER 1 +#else +# define BROKEN_COMPILER 0 +#endif + +#if HAVE_INLINE_ASM + +#ifndef UNCHECKED_BITSTREAM_READER +#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER +#endif + +#if UNCHECKED_BITSTREAM_READER +#define END_CHECK(end) "" +#else +#define END_CHECK(end) \ + "cmp "end" , %%"FF_REG_c" \n\t"\ + "jge 1f \n\t" +#endif + +#ifdef BROKEN_RELOCATIONS +#define TABLES_ARG , "r"(tables) + +#if HAVE_FAST_CMOV +#define BRANCHLESS_GET_CABAC_UPDATE(ret, retq, low, range, tmp) \ + "cmp "low" , "tmp" \n\t"\ + "cmova %%ecx , "range" \n\t"\ + "sbb %%rcx , %%rcx \n\t"\ + "and %%ecx , "tmp" \n\t"\ + "xor %%rcx , "retq" \n\t"\ + "sub "tmp" , "low" \n\t" +#else /* HAVE_FAST_CMOV */ +#define BRANCHLESS_GET_CABAC_UPDATE(ret, retq, low, range, tmp) \ +/* P4 Prescott has crappy cmov,sbb,64-bit shift so avoid them */ \ + "sub "low" , "tmp" \n\t"\ + "sar $31 , "tmp" \n\t"\ + "sub %%ecx , "range" \n\t"\ + "and "tmp" , "range" \n\t"\ + "add %%ecx , "range" \n\t"\ + "shl $17 , %%ecx \n\t"\ + "and "tmp" , %%ecx \n\t"\ + "sub %%ecx , "low" \n\t"\ + "xor "tmp" , "ret" \n\t"\ + "movslq "ret" , "retq" \n\t" +#endif /* HAVE_FAST_CMOV */ + +#define BRANCHLESS_GET_CABAC(ret, retq, statep, low, lowword, range, rangeq, tmp, tmpbyte, byte, end, norm_off, lps_off, mlps_off, tables) \ + "movzbl "statep" , "ret" \n\t"\ + "mov "range" , "tmp" \n\t"\ + "and $0xC0 , "range" \n\t"\ + "lea ("ret", "range", 2), %%ecx \n\t"\ + "movzbl "lps_off"("tables", %%rcx), "range" \n\t"\ + "sub "range" , "tmp" \n\t"\ + "mov "tmp" , %%ecx \n\t"\ + "shl $17 , "tmp" \n\t"\ + BRANCHLESS_GET_CABAC_UPDATE(ret, retq, low, range, tmp) \ + "movzbl "norm_off"("tables", "rangeq"), %%ecx \n\t"\ + "shl %%cl , "range" \n\t"\ + "movzbl "mlps_off"+128("tables", "retq"), "tmp" \n\t"\ + "shl %%cl , "low" \n\t"\ + "mov "tmpbyte" , "statep" \n\t"\ + "test "lowword" , "lowword" \n\t"\ + "jnz 2f \n\t"\ + "mov "byte" , %%"FF_REG_c" \n\t"\ + END_CHECK(end)\ + "add"FF_OPSIZE" $2 , "byte" \n\t"\ + "1: \n\t"\ + "movzwl (%%"FF_REG_c") , "tmp" \n\t"\ + "lea -1("low") , %%ecx \n\t"\ + "xor "low" , %%ecx \n\t"\ + "shr $15 , %%ecx \n\t"\ + "bswap "tmp" \n\t"\ + "shr $15 , "tmp" \n\t"\ + "movzbl "norm_off"("tables", %%rcx), %%ecx \n\t"\ + "sub $0xFFFF , "tmp" \n\t"\ + "neg %%ecx \n\t"\ + "add $7 , %%ecx \n\t"\ + "shl %%cl , "tmp" \n\t"\ + "add "tmp" , "low" \n\t"\ + "2: \n\t" + +#else /* BROKEN_RELOCATIONS */ +#define TABLES_ARG NAMED_CONSTRAINTS_ARRAY_ADD(ff_h264_cabac_tables) +#define RIP_ARG + +#if HAVE_FAST_CMOV +#define BRANCHLESS_GET_CABAC_UPDATE(ret, low, range, tmp)\ + "mov "tmp" , %%ecx \n\t"\ + "shl $17 , "tmp" \n\t"\ + "cmp "low" , "tmp" \n\t"\ + "cmova %%ecx , "range" \n\t"\ + "sbb %%ecx , %%ecx \n\t"\ + "and %%ecx , "tmp" \n\t"\ + "xor %%ecx , "ret" \n\t"\ + "sub "tmp" , "low" \n\t" +#else /* HAVE_FAST_CMOV */ +#define BRANCHLESS_GET_CABAC_UPDATE(ret, low, range, tmp)\ + "mov "tmp" , %%ecx \n\t"\ + "shl $17 , "tmp" \n\t"\ + "sub "low" , "tmp" \n\t"\ + "sar $31 , "tmp" \n\t" /*lps_mask*/\ + "sub %%ecx , "range" \n\t" /*RangeLPS - range*/\ + "and "tmp" , "range" \n\t" /*(RangeLPS - range)&lps_mask*/\ + "add %%ecx , "range" \n\t" /*new range*/\ + "shl $17 , %%ecx \n\t"\ + "and "tmp" , %%ecx \n\t"\ + "sub %%ecx , "low" \n\t"\ + "xor "tmp" , "ret" \n\t" +#endif /* HAVE_FAST_CMOV */ + +#define BRANCHLESS_GET_CABAC(ret, retq, statep, low, lowword, range, rangeq, tmp, tmpbyte, byte, end, norm_off, lps_off, mlps_off, tables) \ + "movzbl "statep" , "ret" \n\t"\ + "mov "range" , "tmp" \n\t"\ + "and $0xC0 , "range" \n\t"\ + "movzbl "MANGLE(ff_h264_cabac_tables)"+"lps_off"("ret", "range", 2), "range" \n\t"\ + "sub "range" , "tmp" \n\t"\ + BRANCHLESS_GET_CABAC_UPDATE(ret, low, range, tmp) \ + "movzbl "MANGLE(ff_h264_cabac_tables)"+"norm_off"("range"), %%ecx \n\t"\ + "shl %%cl , "range" \n\t"\ + "movzbl "MANGLE(ff_h264_cabac_tables)"+"mlps_off"+128("ret"), "tmp" \n\t"\ + "shl %%cl , "low" \n\t"\ + "mov "tmpbyte" , "statep" \n\t"\ + "test "lowword" , "lowword" \n\t"\ + " jnz 2f \n\t"\ + "mov "byte" , %%"FF_REG_c" \n\t"\ + END_CHECK(end)\ + "add"FF_OPSIZE" $2 , "byte" \n\t"\ + "1: \n\t"\ + "movzwl (%%"FF_REG_c") , "tmp" \n\t"\ + "lea -1("low") , %%ecx \n\t"\ + "xor "low" , %%ecx \n\t"\ + "shr $15 , %%ecx \n\t"\ + "bswap "tmp" \n\t"\ + "shr $15 , "tmp" \n\t"\ + "movzbl "MANGLE(ff_h264_cabac_tables)"+"norm_off"(%%ecx), %%ecx \n\t"\ + "sub $0xFFFF , "tmp" \n\t"\ + "neg %%ecx \n\t"\ + "add $7 , %%ecx \n\t"\ + "shl %%cl , "tmp" \n\t"\ + "add "tmp" , "low" \n\t"\ + "2: \n\t" + +#endif /* BROKEN_RELOCATIONS */ + +#if HAVE_7REGS && !BROKEN_COMPILER +#define get_cabac_inline get_cabac_inline_x86 +static av_always_inline int get_cabac_inline_x86(CABACContext *c, + uint8_t *const state) +{ + int bit, tmp; +#ifdef BROKEN_RELOCATIONS + void *tables; + + __asm__ volatile( + "lea "MANGLE(ff_h264_cabac_tables)", %0 \n\t" + : "=&r"(tables) + : NAMED_CONSTRAINTS_ARRAY(ff_h264_cabac_tables) + ); +#endif + + __asm__ volatile( + BRANCHLESS_GET_CABAC("%0", "%q0", "(%4)", "%1", "%w1", + "%2", "%q2", "%3", "%b3", + "%c6(%5)", "%c7(%5)", + AV_STRINGIFY(H264_NORM_SHIFT_OFFSET), + AV_STRINGIFY(H264_LPS_RANGE_OFFSET), + AV_STRINGIFY(H264_MLPS_STATE_OFFSET), + "%8") + : "=&r"(bit), "=&r"(c->low), "=&r"(c->range), "=&q"(tmp) + : "r"(state), "r"(c), + "i"(offsetof(CABACContext, bytestream)), + "i"(offsetof(CABACContext, bytestream_end)) + TABLES_ARG + ,"1"(c->low), "2"(c->range) + : "%"FF_REG_c, "memory" + ); + return bit & 1; +} +#endif /* HAVE_7REGS && !BROKEN_COMPILER */ + +#if !BROKEN_COMPILER +#define get_cabac_bypass_sign get_cabac_bypass_sign_x86 +static av_always_inline int get_cabac_bypass_sign_x86(CABACContext *c, int val) +{ + x86_reg tmp; + __asm__ volatile( + "movl %c6(%2), %k1 \n\t" + "movl %c3(%2), %%eax \n\t" + "shl $17, %k1 \n\t" + "add %%eax, %%eax \n\t" + "sub %k1, %%eax \n\t" + "cdq \n\t" + "and %%edx, %k1 \n\t" + "add %k1, %%eax \n\t" + "xor %%edx, %%ecx \n\t" + "sub %%edx, %%ecx \n\t" + "test %%ax, %%ax \n\t" + "jnz 1f \n\t" + "mov %c4(%2), %1 \n\t" + "subl $0xFFFF, %%eax \n\t" + "movzwl (%1), %%edx \n\t" + "bswap %%edx \n\t" + "shrl $15, %%edx \n\t" +#if UNCHECKED_BITSTREAM_READER + "add $2, %1 \n\t" + "addl %%edx, %%eax \n\t" + "mov %1, %c4(%2) \n\t" +#else + "addl %%edx, %%eax \n\t" + "cmp %c5(%2), %1 \n\t" + "jge 1f \n\t" + "add"FF_OPSIZE" $2, %c4(%2) \n\t" +#endif + "1: \n\t" + "movl %%eax, %c3(%2) \n\t" + + : "+c"(val), "=&r"(tmp) + : "r"(c), + "i"(offsetof(CABACContext, low)), + "i"(offsetof(CABACContext, bytestream)), + "i"(offsetof(CABACContext, bytestream_end)), + "i"(offsetof(CABACContext, range)) + : "%eax", "%edx", "memory" + ); + return val; +} + +#define get_cabac_bypass get_cabac_bypass_x86 +static av_always_inline int get_cabac_bypass_x86(CABACContext *c) +{ + x86_reg tmp; + int res; + __asm__ volatile( + "movl %c6(%2), %k1 \n\t" + "movl %c3(%2), %%eax \n\t" + "shl $17, %k1 \n\t" + "add %%eax, %%eax \n\t" + "sub %k1, %%eax \n\t" + "cdq \n\t" + "and %%edx, %k1 \n\t" + "add %k1, %%eax \n\t" + "inc %%edx \n\t" + "test %%ax, %%ax \n\t" + "jnz 1f \n\t" + "mov %c4(%2), %1 \n\t" + "subl $0xFFFF, %%eax \n\t" + "movzwl (%1), %%ecx \n\t" + "bswap %%ecx \n\t" + "shrl $15, %%ecx \n\t" + "addl %%ecx, %%eax \n\t" + "cmp %c5(%2), %1 \n\t" + "jge 1f \n\t" + "add"FF_OPSIZE" $2, %c4(%2) \n\t" + "1: \n\t" + "movl %%eax, %c3(%2) \n\t" + + : "=&d"(res), "=&r"(tmp) + : "r"(c), + "i"(offsetof(CABACContext, low)), + "i"(offsetof(CABACContext, bytestream)), + "i"(offsetof(CABACContext, bytestream_end)), + "i"(offsetof(CABACContext, range)) + : "%eax", "%ecx", "memory" + ); + return res; +} +#endif /* !BROKEN_COMPILER */ + +#endif /* HAVE_INLINE_ASM */ +#endif /* AVCODEC_X86_CABAC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/cavsdsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/cavsdsp.c new file mode 100644 index 0000000000..becb3a4808 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/cavsdsp.c @@ -0,0 +1,463 @@ +/* + * Chinese AVS video (AVS1-P2, JiZhun profile) decoder. + * Copyright (c) 2006 Stefan Gehrer + * + * MMX-optimized DSP functions, based on H.264 optimizations by + * Michael Niedermayer and Loren Merritt + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/common.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/cavsdsp.h" +#include "libavcodec/idctdsp.h" +#include "constants.h" +#include "fpel.h" +#include "idctdsp.h" +#include "config.h" + + +#if HAVE_MMX_EXTERNAL + +void ff_cavs_idct8_mmx(int16_t *out, const int16_t *in); + +static void cavs_idct8_add_mmx(uint8_t *dst, int16_t *block, ptrdiff_t stride) +{ + LOCAL_ALIGNED(16, int16_t, b2, [64]); + ff_cavs_idct8_mmx(b2, block); + ff_add_pixels_clamped_mmx(b2, dst, stride); +} + +void ff_cavs_idct8_sse2(int16_t *out, const int16_t *in); + +static void cavs_idct8_add_sse2(uint8_t *dst, int16_t *block, ptrdiff_t stride) +{ + LOCAL_ALIGNED(16, int16_t, b2, [64]); + ff_cavs_idct8_sse2(b2, block); + ff_add_pixels_clamped_sse2(b2, dst, stride); +} + +#endif /* HAVE_MMX_EXTERNAL */ + +#if (HAVE_MMXEXT_INLINE || HAVE_AMD3DNOW_INLINE) + +/***************************************************************************** + * + * motion compensation + * + ****************************************************************************/ + +/* vertical filter [-1 -2 96 42 -7 0] */ +#define QPEL_CAVSV1(A,B,C,D,E,F,OP,ADD, MUL1, MUL2) \ + "movd (%0), "#F" \n\t"\ + "movq "#C", %%mm6 \n\t"\ + "pmullw "MANGLE(MUL1)", %%mm6\n\t"\ + "movq "#D", %%mm7 \n\t"\ + "pmullw "MANGLE(MUL2)", %%mm7\n\t"\ + "psllw $3, "#E" \n\t"\ + "psubw "#E", %%mm6 \n\t"\ + "psraw $3, "#E" \n\t"\ + "paddw %%mm7, %%mm6 \n\t"\ + "paddw "#E", %%mm6 \n\t"\ + "paddw "#B", "#B" \n\t"\ + "pxor %%mm7, %%mm7 \n\t"\ + "add %2, %0 \n\t"\ + "punpcklbw %%mm7, "#F" \n\t"\ + "psubw "#B", %%mm6 \n\t"\ + "psraw $1, "#B" \n\t"\ + "psubw "#A", %%mm6 \n\t"\ + "paddw "MANGLE(ADD)", %%mm6 \n\t"\ + "psraw $7, %%mm6 \n\t"\ + "packuswb %%mm6, %%mm6 \n\t"\ + OP(%%mm6, (%1), A, d) \ + "add %3, %1 \n\t" + +/* vertical filter [ 0 -1 5 5 -1 0] */ +#define QPEL_CAVSV2(A,B,C,D,E,F,OP,ADD, MUL1, MUL2) \ + "movd (%0), "#F" \n\t"\ + "movq "#C", %%mm6 \n\t"\ + "paddw "#D", %%mm6 \n\t"\ + "pmullw "MANGLE(MUL1)", %%mm6\n\t"\ + "add %2, %0 \n\t"\ + "punpcklbw %%mm7, "#F" \n\t"\ + "psubw "#B", %%mm6 \n\t"\ + "psubw "#E", %%mm6 \n\t"\ + "paddw "MANGLE(ADD)", %%mm6 \n\t"\ + "psraw $3, %%mm6 \n\t"\ + "packuswb %%mm6, %%mm6 \n\t"\ + OP(%%mm6, (%1), A, d) \ + "add %3, %1 \n\t" + +/* vertical filter [ 0 -7 42 96 -2 -1] */ +#define QPEL_CAVSV3(A,B,C,D,E,F,OP,ADD, MUL1, MUL2) \ + "movd (%0), "#F" \n\t"\ + "movq "#C", %%mm6 \n\t"\ + "pmullw "MANGLE(MUL2)", %%mm6\n\t"\ + "movq "#D", %%mm7 \n\t"\ + "pmullw "MANGLE(MUL1)", %%mm7\n\t"\ + "psllw $3, "#B" \n\t"\ + "psubw "#B", %%mm6 \n\t"\ + "psraw $3, "#B" \n\t"\ + "paddw %%mm7, %%mm6 \n\t"\ + "paddw "#B", %%mm6 \n\t"\ + "paddw "#E", "#E" \n\t"\ + "pxor %%mm7, %%mm7 \n\t"\ + "add %2, %0 \n\t"\ + "punpcklbw %%mm7, "#F" \n\t"\ + "psubw "#E", %%mm6 \n\t"\ + "psraw $1, "#E" \n\t"\ + "psubw "#F", %%mm6 \n\t"\ + "paddw "MANGLE(ADD)", %%mm6 \n\t"\ + "psraw $7, %%mm6 \n\t"\ + "packuswb %%mm6, %%mm6 \n\t"\ + OP(%%mm6, (%1), A, d) \ + "add %3, %1 \n\t" + + +#define QPEL_CAVSVNUM(VOP,OP,ADD,MUL1,MUL2)\ + int w= 2;\ + src -= 2*srcStride;\ + \ + while(w--){\ + __asm__ volatile(\ + "pxor %%mm7, %%mm7 \n\t"\ + "movd (%0), %%mm0 \n\t"\ + "add %2, %0 \n\t"\ + "movd (%0), %%mm1 \n\t"\ + "add %2, %0 \n\t"\ + "movd (%0), %%mm2 \n\t"\ + "add %2, %0 \n\t"\ + "movd (%0), %%mm3 \n\t"\ + "add %2, %0 \n\t"\ + "movd (%0), %%mm4 \n\t"\ + "add %2, %0 \n\t"\ + "punpcklbw %%mm7, %%mm0 \n\t"\ + "punpcklbw %%mm7, %%mm1 \n\t"\ + "punpcklbw %%mm7, %%mm2 \n\t"\ + "punpcklbw %%mm7, %%mm3 \n\t"\ + "punpcklbw %%mm7, %%mm4 \n\t"\ + VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, ADD, MUL1, MUL2)\ + VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, ADD, MUL1, MUL2)\ + VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, ADD, MUL1, MUL2)\ + VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, ADD, MUL1, MUL2)\ + VOP(%%mm4, %%mm5, %%mm0, %%mm1, %%mm2, %%mm3, OP, ADD, MUL1, MUL2)\ + VOP(%%mm5, %%mm0, %%mm1, %%mm2, %%mm3, %%mm4, OP, ADD, MUL1, MUL2)\ + VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, ADD, MUL1, MUL2)\ + VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, ADD, MUL1, MUL2)\ + \ + : "+a"(src), "+c"(dst)\ + : "S"((x86_reg)srcStride), "r"((x86_reg)dstStride)\ + NAMED_CONSTRAINTS_ADD(ADD,MUL1,MUL2)\ + : "memory"\ + );\ + if(h==16){\ + __asm__ volatile(\ + VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, ADD, MUL1, MUL2)\ + VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, ADD, MUL1, MUL2)\ + VOP(%%mm4, %%mm5, %%mm0, %%mm1, %%mm2, %%mm3, OP, ADD, MUL1, MUL2)\ + VOP(%%mm5, %%mm0, %%mm1, %%mm2, %%mm3, %%mm4, OP, ADD, MUL1, MUL2)\ + VOP(%%mm0, %%mm1, %%mm2, %%mm3, %%mm4, %%mm5, OP, ADD, MUL1, MUL2)\ + VOP(%%mm1, %%mm2, %%mm3, %%mm4, %%mm5, %%mm0, OP, ADD, MUL1, MUL2)\ + VOP(%%mm2, %%mm3, %%mm4, %%mm5, %%mm0, %%mm1, OP, ADD, MUL1, MUL2)\ + VOP(%%mm3, %%mm4, %%mm5, %%mm0, %%mm1, %%mm2, OP, ADD, MUL1, MUL2)\ + \ + : "+a"(src), "+c"(dst)\ + : "S"((x86_reg)srcStride), "r"((x86_reg)dstStride)\ + NAMED_CONSTRAINTS_ADD(ADD,MUL1,MUL2)\ + : "memory"\ + );\ + }\ + src += 4-(h+5)*srcStride;\ + dst += 4-h*dstStride;\ + } + +#define QPEL_CAVS(OPNAME, OP, MMX)\ +static void OPNAME ## cavs_qpel8_h_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{\ + int h=8;\ + __asm__ volatile(\ + "pxor %%mm7, %%mm7 \n\t"\ + "movq "MANGLE(ff_pw_5)", %%mm6\n\t"\ + "1: \n\t"\ + "movq (%0), %%mm0 \n\t"\ + "movq 1(%0), %%mm2 \n\t"\ + "movq %%mm0, %%mm1 \n\t"\ + "movq %%mm2, %%mm3 \n\t"\ + "punpcklbw %%mm7, %%mm0 \n\t"\ + "punpckhbw %%mm7, %%mm1 \n\t"\ + "punpcklbw %%mm7, %%mm2 \n\t"\ + "punpckhbw %%mm7, %%mm3 \n\t"\ + "paddw %%mm2, %%mm0 \n\t"\ + "paddw %%mm3, %%mm1 \n\t"\ + "pmullw %%mm6, %%mm0 \n\t"\ + "pmullw %%mm6, %%mm1 \n\t"\ + "movq -1(%0), %%mm2 \n\t"\ + "movq 2(%0), %%mm4 \n\t"\ + "movq %%mm2, %%mm3 \n\t"\ + "movq %%mm4, %%mm5 \n\t"\ + "punpcklbw %%mm7, %%mm2 \n\t"\ + "punpckhbw %%mm7, %%mm3 \n\t"\ + "punpcklbw %%mm7, %%mm4 \n\t"\ + "punpckhbw %%mm7, %%mm5 \n\t"\ + "paddw %%mm4, %%mm2 \n\t"\ + "paddw %%mm3, %%mm5 \n\t"\ + "psubw %%mm2, %%mm0 \n\t"\ + "psubw %%mm5, %%mm1 \n\t"\ + "movq "MANGLE(ff_pw_4)", %%mm5\n\t"\ + "paddw %%mm5, %%mm0 \n\t"\ + "paddw %%mm5, %%mm1 \n\t"\ + "psraw $3, %%mm0 \n\t"\ + "psraw $3, %%mm1 \n\t"\ + "packuswb %%mm1, %%mm0 \n\t"\ + OP(%%mm0, (%1),%%mm5, q) \ + "add %3, %0 \n\t"\ + "add %4, %1 \n\t"\ + "decl %2 \n\t"\ + " jnz 1b \n\t"\ + : "+a"(src), "+c"(dst), "+m"(h)\ + : "d"((x86_reg)srcStride), "S"((x86_reg)dstStride)\ + NAMED_CONSTRAINTS_ADD(ff_pw_4,ff_pw_5)\ + : "memory"\ + );\ +}\ +\ +static inline void OPNAME ## cavs_qpel8or16_v1_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)\ +{ \ + QPEL_CAVSVNUM(QPEL_CAVSV1,OP,ff_pw_64,ff_pw_96,ff_pw_42) \ +}\ +\ +static inline void OPNAME ## cavs_qpel8or16_v2_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)\ +{ \ + QPEL_CAVSVNUM(QPEL_CAVSV2,OP,ff_pw_4,ff_pw_5,ff_pw_42) \ +}\ +\ +static inline void OPNAME ## cavs_qpel8or16_v3_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride, int h)\ +{ \ + QPEL_CAVSVNUM(QPEL_CAVSV3,OP,ff_pw_64,ff_pw_96,ff_pw_42) \ +}\ +\ +static void OPNAME ## cavs_qpel8_v1_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{ \ + OPNAME ## cavs_qpel8or16_v1_ ## MMX(dst , src , dstStride, srcStride, 8);\ +}\ +static void OPNAME ## cavs_qpel16_v1_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{ \ + OPNAME ## cavs_qpel8or16_v1_ ## MMX(dst , src , dstStride, srcStride, 16);\ + OPNAME ## cavs_qpel8or16_v1_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\ +}\ +\ +static void OPNAME ## cavs_qpel8_v2_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{ \ + OPNAME ## cavs_qpel8or16_v2_ ## MMX(dst , src , dstStride, srcStride, 8);\ +}\ +static void OPNAME ## cavs_qpel16_v2_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{ \ + OPNAME ## cavs_qpel8or16_v2_ ## MMX(dst , src , dstStride, srcStride, 16);\ + OPNAME ## cavs_qpel8or16_v2_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\ +}\ +\ +static void OPNAME ## cavs_qpel8_v3_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{ \ + OPNAME ## cavs_qpel8or16_v3_ ## MMX(dst , src , dstStride, srcStride, 8);\ +}\ +static void OPNAME ## cavs_qpel16_v3_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{ \ + OPNAME ## cavs_qpel8or16_v3_ ## MMX(dst , src , dstStride, srcStride, 16);\ + OPNAME ## cavs_qpel8or16_v3_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\ +}\ +\ +static void OPNAME ## cavs_qpel16_h_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t dstStride, ptrdiff_t srcStride)\ +{ \ + OPNAME ## cavs_qpel8_h_ ## MMX(dst , src , dstStride, srcStride);\ + OPNAME ## cavs_qpel8_h_ ## MMX(dst+8, src+8, dstStride, srcStride);\ + src += 8*srcStride;\ + dst += 8*dstStride;\ + OPNAME ## cavs_qpel8_h_ ## MMX(dst , src , dstStride, srcStride);\ + OPNAME ## cavs_qpel8_h_ ## MMX(dst+8, src+8, dstStride, srcStride);\ +}\ + +#define CAVS_MC(OPNAME, SIZE, MMX) \ +static void OPNAME ## cavs_qpel ## SIZE ## _mc20_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + OPNAME ## cavs_qpel ## SIZE ## _h_ ## MMX(dst, src, stride, stride);\ +}\ +\ +static void OPNAME ## cavs_qpel ## SIZE ## _mc01_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + OPNAME ## cavs_qpel ## SIZE ## _v1_ ## MMX(dst, src, stride, stride);\ +}\ +\ +static void OPNAME ## cavs_qpel ## SIZE ## _mc02_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + OPNAME ## cavs_qpel ## SIZE ## _v2_ ## MMX(dst, src, stride, stride);\ +}\ +\ +static void OPNAME ## cavs_qpel ## SIZE ## _mc03_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + OPNAME ## cavs_qpel ## SIZE ## _v3_ ## MMX(dst, src, stride, stride);\ +}\ + +#define PUT_OP(a,b,temp, size) "mov" #size " " #a ", " #b " \n\t" +#define AVG_3DNOW_OP(a,b,temp, size) \ +"mov" #size " " #b ", " #temp " \n\t"\ +"pavgusb " #temp ", " #a " \n\t"\ +"mov" #size " " #a ", " #b " \n\t" +#define AVG_MMXEXT_OP(a, b, temp, size) \ +"mov" #size " " #b ", " #temp " \n\t"\ +"pavgb " #temp ", " #a " \n\t"\ +"mov" #size " " #a ", " #b " \n\t" + +#endif /* (HAVE_MMXEXT_INLINE || HAVE_AMD3DNOW_INLINE) */ + +#if HAVE_MMX_EXTERNAL +static void put_cavs_qpel8_mc00_mmx(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + ff_put_pixels8_mmx(dst, src, stride, 8); +} + +static void avg_cavs_qpel8_mc00_mmx(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + ff_avg_pixels8_mmx(dst, src, stride, 8); +} + +static void avg_cavs_qpel8_mc00_mmxext(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + ff_avg_pixels8_mmxext(dst, src, stride, 8); +} + +static void put_cavs_qpel16_mc00_mmx(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + ff_put_pixels16_mmx(dst, src, stride, 16); +} + +static void avg_cavs_qpel16_mc00_mmx(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + ff_avg_pixels16_mmx(dst, src, stride, 16); +} + +static void avg_cavs_qpel16_mc00_mmxext(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + ff_avg_pixels16_mmxext(dst, src, stride, 16); +} + +static void put_cavs_qpel16_mc00_sse2(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + ff_put_pixels16_sse2(dst, src, stride, 16); +} + +static void avg_cavs_qpel16_mc00_sse2(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + ff_avg_pixels16_sse2(dst, src, stride, 16); +} +#endif + +static av_cold void cavsdsp_init_mmx(CAVSDSPContext *c, + AVCodecContext *avctx) +{ +#if HAVE_MMX_EXTERNAL + c->put_cavs_qpel_pixels_tab[0][0] = put_cavs_qpel16_mc00_mmx; + c->put_cavs_qpel_pixels_tab[1][0] = put_cavs_qpel8_mc00_mmx; + c->avg_cavs_qpel_pixels_tab[0][0] = avg_cavs_qpel16_mc00_mmx; + c->avg_cavs_qpel_pixels_tab[1][0] = avg_cavs_qpel8_mc00_mmx; + + c->cavs_idct8_add = cavs_idct8_add_mmx; + c->idct_perm = FF_IDCT_PERM_TRANSPOSE; +#endif /* HAVE_MMX_EXTERNAL */ +} + +#define DSPFUNC(PFX, IDX, NUM, EXT) \ + c->PFX ## _cavs_qpel_pixels_tab[IDX][ 2] = PFX ## _cavs_qpel ## NUM ## _mc20_ ## EXT; \ + c->PFX ## _cavs_qpel_pixels_tab[IDX][ 4] = PFX ## _cavs_qpel ## NUM ## _mc01_ ## EXT; \ + c->PFX ## _cavs_qpel_pixels_tab[IDX][ 8] = PFX ## _cavs_qpel ## NUM ## _mc02_ ## EXT; \ + c->PFX ## _cavs_qpel_pixels_tab[IDX][12] = PFX ## _cavs_qpel ## NUM ## _mc03_ ## EXT; \ + +#if HAVE_MMXEXT_INLINE +QPEL_CAVS(put_, PUT_OP, mmxext) +QPEL_CAVS(avg_, AVG_MMXEXT_OP, mmxext) + +CAVS_MC(put_, 8, mmxext) +CAVS_MC(put_, 16, mmxext) +CAVS_MC(avg_, 8, mmxext) +CAVS_MC(avg_, 16, mmxext) +#endif /* HAVE_MMXEXT_INLINE */ + +#if HAVE_AMD3DNOW_INLINE +QPEL_CAVS(put_, PUT_OP, 3dnow) +QPEL_CAVS(avg_, AVG_3DNOW_OP, 3dnow) + +CAVS_MC(put_, 8, 3dnow) +CAVS_MC(put_, 16,3dnow) +CAVS_MC(avg_, 8, 3dnow) +CAVS_MC(avg_, 16,3dnow) + +static av_cold void cavsdsp_init_3dnow(CAVSDSPContext *c, + AVCodecContext *avctx) +{ + DSPFUNC(put, 0, 16, 3dnow); + DSPFUNC(put, 1, 8, 3dnow); + DSPFUNC(avg, 0, 16, 3dnow); + DSPFUNC(avg, 1, 8, 3dnow); +} +#endif /* HAVE_AMD3DNOW_INLINE */ + +av_cold void ff_cavsdsp_init_x86(CAVSDSPContext *c, AVCodecContext *avctx) +{ + av_unused int cpu_flags = av_get_cpu_flags(); + + if (X86_MMX(cpu_flags)) + cavsdsp_init_mmx(c, avctx); + +#if HAVE_AMD3DNOW_INLINE + if (INLINE_AMD3DNOW(cpu_flags)) + cavsdsp_init_3dnow(c, avctx); +#endif /* HAVE_AMD3DNOW_INLINE */ +#if HAVE_MMXEXT_INLINE + if (INLINE_MMXEXT(cpu_flags)) { + DSPFUNC(put, 0, 16, mmxext); + DSPFUNC(put, 1, 8, mmxext); + DSPFUNC(avg, 0, 16, mmxext); + DSPFUNC(avg, 1, 8, mmxext); + } +#endif +#if HAVE_MMX_EXTERNAL + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->avg_cavs_qpel_pixels_tab[0][0] = avg_cavs_qpel16_mc00_mmxext; + c->avg_cavs_qpel_pixels_tab[1][0] = avg_cavs_qpel8_mc00_mmxext; + } +#endif +#if HAVE_SSE2_EXTERNAL + if (EXTERNAL_SSE2(cpu_flags)) { + c->put_cavs_qpel_pixels_tab[0][0] = put_cavs_qpel16_mc00_sse2; + c->avg_cavs_qpel_pixels_tab[0][0] = avg_cavs_qpel16_mc00_sse2; + + c->cavs_idct8_add = cavs_idct8_add_sse2; + c->idct_perm = FF_IDCT_PERM_TRANSPOSE; + } +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/celt_pvq_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/celt_pvq_init.c new file mode 100644 index 0000000000..13724c3561 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/celt_pvq_init.c @@ -0,0 +1,43 @@ +/* + * Opus encoder assembly optimizations + * Copyright (C) 2017 Ivan Kalvachev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/x86/cpu.h" +#include "libavcodec/opus_pvq.h" + +extern float ff_pvq_search_approx_sse2(float *X, int *y, int K, int N); +extern float ff_pvq_search_approx_sse4(float *X, int *y, int K, int N); +extern float ff_pvq_search_exact_avx (float *X, int *y, int K, int N); + +av_cold void ff_celt_pvq_init_x86(CeltPVQ *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE2(cpu_flags)) + s->pvq_search = ff_pvq_search_approx_sse2; + + if (EXTERNAL_SSE4(cpu_flags)) + s->pvq_search = ff_pvq_search_approx_sse4; + + if (EXTERNAL_AVX_FAST(cpu_flags)) + s->pvq_search = ff_pvq_search_exact_avx; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/constants.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/constants.c new file mode 100644 index 0000000000..4bfb78cc36 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/constants.c @@ -0,0 +1,94 @@ +/* + * MMX/SSE/AVX constants used across x86 dsp optimizations. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/mem.h" +#include "libavutil/x86/asm.h" // for xmm_reg +#include "constants.h" + +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_1) = { 0x0001000100010001ULL, 0x0001000100010001ULL, + 0x0001000100010001ULL, 0x0001000100010001ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_2) = { 0x0002000200020002ULL, 0x0002000200020002ULL, + 0x0002000200020002ULL, 0x0002000200020002ULL }; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_3) = { 0x0003000300030003ULL, 0x0003000300030003ULL }; +DECLARE_ASM_ALIGNED(32, const ymm_reg, ff_pw_4) = { 0x0004000400040004ULL, 0x0004000400040004ULL, + 0x0004000400040004ULL, 0x0004000400040004ULL }; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_5) = { 0x0005000500050005ULL, 0x0005000500050005ULL }; +DECLARE_ALIGNED(16, const xmm_reg, ff_pw_8) = { 0x0008000800080008ULL, 0x0008000800080008ULL }; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_9) = { 0x0009000900090009ULL, 0x0009000900090009ULL }; +DECLARE_ALIGNED(8, const uint64_t, ff_pw_15) = 0x000F000F000F000FULL; +DECLARE_ALIGNED(16, const xmm_reg, ff_pw_16) = { 0x0010001000100010ULL, 0x0010001000100010ULL }; +DECLARE_ALIGNED(16, const xmm_reg, ff_pw_17) = { 0x0011001100110011ULL, 0x0011001100110011ULL }; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_18) = { 0x0012001200120012ULL, 0x0012001200120012ULL }; +DECLARE_ALIGNED(16, const xmm_reg, ff_pw_20) = { 0x0014001400140014ULL, 0x0014001400140014ULL }; +DECLARE_ALIGNED(16, const xmm_reg, ff_pw_32) = { 0x0020002000200020ULL, 0x0020002000200020ULL }; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_42) = 0x002A002A002A002AULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_53) = 0x0035003500350035ULL; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_64) = { 0x0040004000400040ULL, 0x0040004000400040ULL }; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_96) = 0x0060006000600060ULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_128) = 0x0080008000800080ULL; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_255) = { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, + 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_256) = { 0x0100010001000100ULL, 0x0100010001000100ULL, + 0x0100010001000100ULL, 0x0100010001000100ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_512) = { 0x0200020002000200ULL, 0x0200020002000200ULL, + 0x0200020002000200ULL, 0x0200020002000200ULL }; +DECLARE_ALIGNED(16, const xmm_reg, ff_pw_1019) = { 0x03FB03FB03FB03FBULL, 0x03FB03FB03FB03FBULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_1023) = { 0x03ff03ff03ff03ffULL, 0x03ff03ff03ff03ffULL, + 0x03ff03ff03ff03ffULL, 0x03ff03ff03ff03ffULL}; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_1024) = { 0x0400040004000400ULL, 0x0400040004000400ULL, + 0x0400040004000400ULL, 0x0400040004000400ULL}; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_2048) = { 0x0800080008000800ULL, 0x0800080008000800ULL, + 0x0800080008000800ULL, 0x0800080008000800ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_4095) = { 0x0fff0fff0fff0fffULL, 0x0fff0fff0fff0fffULL, + 0x0fff0fff0fff0fffULL, 0x0fff0fff0fff0fffULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_4096) = { 0x1000100010001000ULL, 0x1000100010001000ULL, + 0x1000100010001000ULL, 0x1000100010001000ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_8192) = { 0x2000200020002000ULL, 0x2000200020002000ULL, + 0x2000200020002000ULL, 0x2000200020002000ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pw_m1) = { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, + 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL }; + +DECLARE_ALIGNED(32, const ymm_reg, ff_pb_0) = { 0x0000000000000000ULL, 0x0000000000000000ULL, + 0x0000000000000000ULL, 0x0000000000000000ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pb_1) = { 0x0101010101010101ULL, 0x0101010101010101ULL, + 0x0101010101010101ULL, 0x0101010101010101ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pb_2) = { 0x0202020202020202ULL, 0x0202020202020202ULL, + 0x0202020202020202ULL, 0x0202020202020202ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pb_3) = { 0x0303030303030303ULL, 0x0303030303030303ULL, + 0x0303030303030303ULL, 0x0303030303030303ULL }; +DECLARE_ALIGNED(32, const xmm_reg, ff_pb_15) = { 0x0F0F0F0F0F0F0F0FULL, 0x0F0F0F0F0F0F0F0FULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pb_80) = { 0x8080808080808080ULL, 0x8080808080808080ULL, + 0x8080808080808080ULL, 0x8080808080808080ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pb_FE) = { 0xFEFEFEFEFEFEFEFEULL, 0xFEFEFEFEFEFEFEFEULL, + 0xFEFEFEFEFEFEFEFEULL, 0xFEFEFEFEFEFEFEFEULL }; +DECLARE_ALIGNED(8, const uint64_t, ff_pb_FC) = 0xFCFCFCFCFCFCFCFCULL; + +DECLARE_ALIGNED(16, const xmm_reg, ff_ps_neg) = { 0x8000000080000000ULL, 0x8000000080000000ULL }; + +DECLARE_ALIGNED(32, const ymm_reg, ff_pd_1) = { 0x0000000100000001ULL, 0x0000000100000001ULL, + 0x0000000100000001ULL, 0x0000000100000001ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pd_16) = { 0x0000001000000010ULL, 0x0000001000000010ULL, + 0x0000001000000010ULL, 0x0000001000000010ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pd_32) = { 0x0000002000000020ULL, 0x0000002000000020ULL, + 0x0000002000000020ULL, 0x0000002000000020ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pd_8192) = { 0x0000200000002000ULL, 0x0000200000002000ULL, + 0x0000200000002000ULL, 0x0000200000002000ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pd_65535)= { 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL, + 0x0000ffff0000ffffULL, 0x0000ffff0000ffffULL }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/constants.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/constants.h new file mode 100644 index 0000000000..85da38b7b9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/constants.h @@ -0,0 +1,72 @@ +/* + * MMX/SSE constants used across x86 dsp optimizations. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_CONSTANTS_H +#define AVCODEC_X86_CONSTANTS_H + +#include + +#include "libavutil/x86/asm.h" + +extern const ymm_reg ff_pw_1; +extern const ymm_reg ff_pw_2; +extern const xmm_reg ff_pw_3; +extern const ymm_reg ff_pw_4; +extern const xmm_reg ff_pw_5; +extern const xmm_reg ff_pw_8; +extern const xmm_reg ff_pw_9; +extern const uint64_t ff_pw_15; +extern const xmm_reg ff_pw_16; +extern const xmm_reg ff_pw_18; +extern const xmm_reg ff_pw_20; +extern const xmm_reg ff_pw_32; +extern const uint64_t ff_pw_42; +extern const uint64_t ff_pw_53; +extern const xmm_reg ff_pw_64; +extern const uint64_t ff_pw_96; +extern const uint64_t ff_pw_128; +extern const ymm_reg ff_pw_255; +extern const ymm_reg ff_pw_256; +extern const ymm_reg ff_pw_512; +extern const ymm_reg ff_pw_1023; +extern const ymm_reg ff_pw_1024; +extern const ymm_reg ff_pw_2048; +extern const ymm_reg ff_pw_4095; +extern const ymm_reg ff_pw_4096; +extern const ymm_reg ff_pw_8192; +extern const ymm_reg ff_pw_m1; + +extern const ymm_reg ff_pb_0; +extern const ymm_reg ff_pb_1; +extern const ymm_reg ff_pb_2; +extern const ymm_reg ff_pb_3; +extern const ymm_reg ff_pb_80; +extern const ymm_reg ff_pb_FE; +extern const uint64_t ff_pb_FC; + +extern const xmm_reg ff_ps_neg; + +extern const ymm_reg ff_pd_1; +extern const ymm_reg ff_pd_16; +extern const ymm_reg ff_pd_32; +extern const ymm_reg ff_pd_8192; +extern const ymm_reg ff_pd_65535; + +#endif /* AVCODEC_X86_CONSTANTS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dcadsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dcadsp_init.c new file mode 100644 index 0000000000..fc10fb8bc5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dcadsp_init.c @@ -0,0 +1,52 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/dcadsp.h" + +#define LFE_FIR_FLOAT_FUNC(opt) \ +void ff_lfe_fir0_float_##opt(float *pcm_samples, int32_t *lfe_samples, \ + const float *filter_coeff, ptrdiff_t npcmblocks); \ +void ff_lfe_fir1_float_##opt(float *pcm_samples, int32_t *lfe_samples, \ + const float *filter_coeff, ptrdiff_t npcmblocks); + +LFE_FIR_FLOAT_FUNC(sse) +LFE_FIR_FLOAT_FUNC(sse2) +LFE_FIR_FLOAT_FUNC(sse3) +LFE_FIR_FLOAT_FUNC(avx) +LFE_FIR_FLOAT_FUNC(fma3) + +av_cold void ff_dcadsp_init_x86(DCADSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (ARCH_X86_32 && EXTERNAL_SSE(cpu_flags)) + s->lfe_fir_float[0] = ff_lfe_fir0_float_sse; + if (EXTERNAL_SSE2(cpu_flags)) + s->lfe_fir_float[0] = ff_lfe_fir0_float_sse2; + if (EXTERNAL_SSE3(cpu_flags)) + s->lfe_fir_float[1] = ff_lfe_fir1_float_sse3; + if (EXTERNAL_AVX(cpu_flags)) { + s->lfe_fir_float[0] = ff_lfe_fir0_float_avx; + s->lfe_fir_float[1] = ff_lfe_fir1_float_avx; + } + if (EXTERNAL_FMA3(cpu_flags)) + s->lfe_fir_float[0] = ff_lfe_fir0_float_fma3; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dct_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dct_init.c new file mode 100644 index 0000000000..c31ef92238 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dct_init.c @@ -0,0 +1,41 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/dct.h" + +void ff_dct32_float_sse(FFTSample *out, const FFTSample *in); +void ff_dct32_float_sse2(FFTSample *out, const FFTSample *in); +void ff_dct32_float_avx(FFTSample *out, const FFTSample *in); + +av_cold void ff_dct_init_x86(DCTContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + +#if ARCH_X86_32 + if (EXTERNAL_SSE(cpu_flags)) + s->dct32 = ff_dct32_float_sse; +#endif + if (EXTERNAL_SSE2(cpu_flags)) + s->dct32 = ff_dct32_float_sse2; + if (EXTERNAL_AVX_FAST(cpu_flags)) + s->dct32 = ff_dct32_float_avx; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dirac_dwt_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dirac_dwt_init.c new file mode 100644 index 0000000000..49a6380add --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dirac_dwt_init.c @@ -0,0 +1,229 @@ +/* + * x86 optimized discrete wavelet transform + * Copyright (c) 2002-2004 Michael Niedermayer + * Copyright (c) 2010 David Conrad + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/dirac_dwt.h" + +#define COMPOSE_VERTICAL(ext, align) \ +void ff_vertical_compose53iL0##ext(int16_t *b0, int16_t *b1, int16_t *b2, int width); \ +void ff_vertical_compose_dirac53iH0##ext(int16_t *b0, int16_t *b1, int16_t *b2, int width); \ +void ff_vertical_compose_dd137iL0##ext(int16_t *b0, int16_t *b1, int16_t *b2, int16_t *b3, int16_t *b4, int width); \ +void ff_vertical_compose_dd97iH0##ext(int16_t *b0, int16_t *b1, int16_t *b2, int16_t *b3, int16_t *b4, int width); \ +void ff_vertical_compose_haar##ext(int16_t *b0, int16_t *b1, int width); \ +void ff_horizontal_compose_haar0i##ext(int16_t *b, int16_t *tmp, int w);\ +void ff_horizontal_compose_haar1i##ext(int16_t *b, int16_t *tmp, int w);\ +\ +static void vertical_compose53iL0##ext(uint8_t *_b0, uint8_t *_b1, uint8_t *_b2, int width) \ +{ \ + int i, width_align = width&~(align-1); \ + int16_t *b0 = (int16_t *)_b0; \ + int16_t *b1 = (int16_t *)_b1; \ + int16_t *b2 = (int16_t *)_b2; \ +\ + for(i=width_align; i>1;\ + int x= w2 - (w2&(align-1));\ + int16_t *b = (int16_t *)_b; \ + int16_t *tmp = (int16_t *)_tmp; \ +\ + ff_horizontal_compose_haar0i##ext(b, tmp, w);\ +\ + for (; x < w2; x++) {\ + b[2*x ] = tmp[x];\ + b[2*x+1] = COMPOSE_HAARiH0(b[x+w2], tmp[x]);\ + }\ +}\ +static void horizontal_compose_haar1i##ext(uint8_t *_b, uint8_t *_tmp, int w)\ +{\ + int w2= w>>1;\ + int x= w2 - (w2&(align-1));\ + int16_t *b = (int16_t *)_b; \ + int16_t *tmp = (int16_t *)_tmp; \ +\ + ff_horizontal_compose_haar1i##ext(b, tmp, w);\ +\ + for (; x < w2; x++) {\ + b[2*x ] = (tmp[x] + 1)>>1;\ + b[2*x+1] = (COMPOSE_HAARiH0(b[x+w2], tmp[x]) + 1)>>1;\ + }\ +}\ +\ + +#if HAVE_X86ASM +#if !ARCH_X86_64 +COMPOSE_VERTICAL(_mmx, 4) +#endif +COMPOSE_VERTICAL(_sse2, 8) + + +void ff_horizontal_compose_dd97i_ssse3(int16_t *_b, int16_t *_tmp, int w); + +static void horizontal_compose_dd97i_ssse3(uint8_t *_b, uint8_t *_tmp, int w) +{ + int w2= w>>1; + int x= w2 - (w2&7); + int16_t *b = (int16_t *)_b; + int16_t *tmp = (int16_t *)_tmp; + + ff_horizontal_compose_dd97i_ssse3(b, tmp, w); + + for (; x < w2; x++) { + b[2*x ] = (tmp[x] + 1)>>1; + b[2*x+1] = (COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1)>>1; + } +} +#endif + +void ff_spatial_idwt_init_x86(DWTContext *d, enum dwt_type type) +{ +#if HAVE_X86ASM + int mm_flags = av_get_cpu_flags(); + +#if !ARCH_X86_64 + if (!(mm_flags & AV_CPU_FLAG_MMX)) + return; + + switch (type) { + case DWT_DIRAC_DD9_7: + d->vertical_compose_l0 = (void*)vertical_compose53iL0_mmx; + d->vertical_compose_h0 = (void*)vertical_compose_dd97iH0_mmx; + break; + case DWT_DIRAC_LEGALL5_3: + d->vertical_compose_l0 = (void*)vertical_compose53iL0_mmx; + d->vertical_compose_h0 = (void*)vertical_compose_dirac53iH0_mmx; + break; + case DWT_DIRAC_DD13_7: + d->vertical_compose_l0 = (void*)vertical_compose_dd137iL0_mmx; + d->vertical_compose_h0 = (void*)vertical_compose_dd97iH0_mmx; + break; + case DWT_DIRAC_HAAR0: + d->vertical_compose = (void*)vertical_compose_haar_mmx; + d->horizontal_compose = horizontal_compose_haar0i_mmx; + break; + case DWT_DIRAC_HAAR1: + d->vertical_compose = (void*)vertical_compose_haar_mmx; + d->horizontal_compose = horizontal_compose_haar1i_mmx; + break; + } +#endif + + if (!(mm_flags & AV_CPU_FLAG_SSE2)) + return; + + switch (type) { + case DWT_DIRAC_DD9_7: + d->vertical_compose_l0 = (void*)vertical_compose53iL0_sse2; + d->vertical_compose_h0 = (void*)vertical_compose_dd97iH0_sse2; + break; + case DWT_DIRAC_LEGALL5_3: + d->vertical_compose_l0 = (void*)vertical_compose53iL0_sse2; + d->vertical_compose_h0 = (void*)vertical_compose_dirac53iH0_sse2; + break; + case DWT_DIRAC_DD13_7: + d->vertical_compose_l0 = (void*)vertical_compose_dd137iL0_sse2; + d->vertical_compose_h0 = (void*)vertical_compose_dd97iH0_sse2; + break; + case DWT_DIRAC_HAAR0: + d->vertical_compose = (void*)vertical_compose_haar_sse2; + d->horizontal_compose = horizontal_compose_haar0i_sse2; + break; + case DWT_DIRAC_HAAR1: + d->vertical_compose = (void*)vertical_compose_haar_sse2; + d->horizontal_compose = horizontal_compose_haar1i_sse2; + break; + } + + if (!(mm_flags & AV_CPU_FLAG_SSSE3)) + return; + + switch (type) { + case DWT_DIRAC_DD9_7: + d->horizontal_compose = horizontal_compose_dd97i_ssse3; + break; + } +#endif // HAVE_X86ASM +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/diracdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/diracdsp_init.c new file mode 100644 index 0000000000..8cb84eb74c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/diracdsp_init.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2010 David Conrad + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/x86/cpu.h" +#include "libavcodec/diracdsp.h" +#include "fpel.h" + +DECL_DIRAC_PIXOP(put, mmx); +DECL_DIRAC_PIXOP(avg, mmx); +DECL_DIRAC_PIXOP(avg, mmxext); + +void ff_put_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h); +void ff_avg_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h); +void ff_put_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h); +void ff_avg_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h); + +void ff_add_rect_clamped_mmx(uint8_t *, const uint16_t *, int, const int16_t *, int, int, int); +void ff_add_rect_clamped_sse2(uint8_t *, const uint16_t *, int, const int16_t *, int, int, int); + +void ff_add_dirac_obmc8_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); +void ff_add_dirac_obmc16_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); +void ff_add_dirac_obmc32_mmx(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); + +void ff_add_dirac_obmc16_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); +void ff_add_dirac_obmc32_sse2(uint16_t *dst, const uint8_t *src, int stride, const uint8_t *obmc_weight, int yblen); + +void ff_put_rect_clamped_mmx(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height); +void ff_put_rect_clamped_sse2(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height); +void ff_put_signed_rect_clamped_mmx(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height); +void ff_put_signed_rect_clamped_sse2(uint8_t *dst, int dst_stride, const int16_t *src, int src_stride, int width, int height); +void ff_put_signed_rect_clamped_10_sse4(uint8_t *dst, int dst_stride, const uint8_t *src, int src_stride, int width, int height); + +void ff_dequant_subband_32_sse4(uint8_t *src, uint8_t *dst, ptrdiff_t stride, const int qf, const int qs, int tot_v, int tot_h); + +#if HAVE_X86ASM + +#define HPEL_FILTER(MMSIZE, EXT) \ + void ff_dirac_hpel_filter_v_ ## EXT(uint8_t *, const uint8_t *, int, int); \ + void ff_dirac_hpel_filter_h_ ## EXT(uint8_t *, const uint8_t *, int); \ + \ + static void dirac_hpel_filter_ ## EXT(uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, \ + const uint8_t *src, int stride, int width, int height) \ + { \ + while( height-- ) \ + { \ + ff_dirac_hpel_filter_v_ ## EXT(dstv-MMSIZE, src-MMSIZE, stride, width+MMSIZE+5); \ + ff_dirac_hpel_filter_h_ ## EXT(dsth, src, width); \ + ff_dirac_hpel_filter_h_ ## EXT(dstc, dstv, width); \ + \ + dsth += stride; \ + dstv += stride; \ + dstc += stride; \ + src += stride; \ + } \ + } + +#define PIXFUNC(PFX, IDX, EXT) \ + /*MMXDISABLEDc->PFX ## _dirac_pixels_tab[0][IDX] = ff_ ## PFX ## _dirac_pixels8_ ## EXT;*/ \ + c->PFX ## _dirac_pixels_tab[1][IDX] = ff_ ## PFX ## _dirac_pixels16_ ## EXT; \ + c->PFX ## _dirac_pixels_tab[2][IDX] = ff_ ## PFX ## _dirac_pixels32_ ## EXT + +#define DIRAC_PIXOP(OPNAME2, OPNAME, EXT)\ +void ff_ ## OPNAME2 ## _dirac_pixels8_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + if (h&3)\ + ff_ ## OPNAME2 ## _dirac_pixels8_c(dst, src, stride, h);\ + else\ + OPNAME ## _pixels8_ ## EXT(dst, src[0], stride, h);\ +}\ +void ff_ ## OPNAME2 ## _dirac_pixels16_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + if (h&3)\ + ff_ ## OPNAME2 ## _dirac_pixels16_c(dst, src, stride, h);\ + else\ + OPNAME ## _pixels16_ ## EXT(dst, src[0], stride, h);\ +}\ +void ff_ ## OPNAME2 ## _dirac_pixels32_ ## EXT(uint8_t *dst, const uint8_t *src[5], int stride, int h)\ +{\ + if (h&3) {\ + ff_ ## OPNAME2 ## _dirac_pixels32_c(dst, src, stride, h);\ + } else {\ + OPNAME ## _pixels16_ ## EXT(dst , src[0] , stride, h);\ + OPNAME ## _pixels16_ ## EXT(dst+16, src[0]+16, stride, h);\ + }\ +} + +DIRAC_PIXOP(put, ff_put, mmx) +DIRAC_PIXOP(avg, ff_avg, mmx) +DIRAC_PIXOP(avg, ff_avg, mmxext) + +void ff_put_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h) +{ + if (h&3) + ff_put_dirac_pixels16_c(dst, src, stride, h); + else + ff_put_pixels16_sse2(dst, src[0], stride, h); +} +void ff_avg_dirac_pixels16_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h) +{ + if (h&3) + ff_avg_dirac_pixels16_c(dst, src, stride, h); + else + ff_avg_pixels16_sse2(dst, src[0], stride, h); +} +void ff_put_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h) +{ + if (h&3) { + ff_put_dirac_pixels32_c(dst, src, stride, h); + } else { + ff_put_pixels16_sse2(dst , src[0] , stride, h); + ff_put_pixels16_sse2(dst+16, src[0]+16, stride, h); + } +} +void ff_avg_dirac_pixels32_sse2(uint8_t *dst, const uint8_t *src[5], int stride, int h) +{ + if (h&3) { + ff_avg_dirac_pixels32_c(dst, src, stride, h); + } else { + ff_avg_pixels16_sse2(dst , src[0] , stride, h); + ff_avg_pixels16_sse2(dst+16, src[0]+16, stride, h); + } +} + +#else // HAVE_X86ASM + +#define HPEL_FILTER(MMSIZE, EXT) \ + void dirac_hpel_filter_ ## EXT(uint8_t *dsth, uint8_t *dstv, uint8_t *dstc, \ + const uint8_t *src, int stride, int width, int height); + +#define PIXFUNC(PFX, IDX, EXT) do {} while (0) + +#endif // HAVE_X86ASM + +#if !ARCH_X86_64 +HPEL_FILTER(8, mmx) +#endif +HPEL_FILTER(16, sse2) + +void ff_diracdsp_init_x86(DiracDSPContext* c) +{ + int mm_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(mm_flags)) { + c->add_dirac_obmc[0] = ff_add_dirac_obmc8_mmx; +#if !ARCH_X86_64 + c->add_dirac_obmc[1] = ff_add_dirac_obmc16_mmx; + c->add_dirac_obmc[2] = ff_add_dirac_obmc32_mmx; + c->dirac_hpel_filter = dirac_hpel_filter_mmx; + c->add_rect_clamped = ff_add_rect_clamped_mmx; + c->put_signed_rect_clamped[0] = (void *)ff_put_signed_rect_clamped_mmx; +#endif + PIXFUNC(put, 0, mmx); + PIXFUNC(avg, 0, mmx); + } + + if (EXTERNAL_MMXEXT(mm_flags)) { + PIXFUNC(avg, 0, mmxext); + } + + if (EXTERNAL_SSE2(mm_flags)) { + c->dirac_hpel_filter = dirac_hpel_filter_sse2; + c->add_rect_clamped = ff_add_rect_clamped_sse2; + c->put_signed_rect_clamped[0] = (void *)ff_put_signed_rect_clamped_sse2; + + c->add_dirac_obmc[1] = ff_add_dirac_obmc16_sse2; + c->add_dirac_obmc[2] = ff_add_dirac_obmc32_sse2; + + c->put_dirac_pixels_tab[1][0] = ff_put_dirac_pixels16_sse2; + c->avg_dirac_pixels_tab[1][0] = ff_avg_dirac_pixels16_sse2; + c->put_dirac_pixels_tab[2][0] = ff_put_dirac_pixels32_sse2; + c->avg_dirac_pixels_tab[2][0] = ff_avg_dirac_pixels32_sse2; + } + + if (EXTERNAL_SSE4(mm_flags)) { + c->dequant_subband[1] = ff_dequant_subband_32_sse4; + c->put_signed_rect_clamped[1] = ff_put_signed_rect_clamped_10_sse4; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dnxhdenc_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dnxhdenc_init.c new file mode 100644 index 0000000000..fd6f15005a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/dnxhdenc_init.c @@ -0,0 +1,37 @@ +/* + * VC3/DNxHD SIMD functions + * Copyright (c) 2007 Baptiste Coudurier + * + * VC-3 encoder funded by the British Broadcasting Corporation + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/dnxhdenc.h" + +void ff_get_pixels_8x4_sym_sse2(int16_t *block, const uint8_t *pixels, + ptrdiff_t line_size); + +av_cold void ff_dnxhdenc_init_x86(DNXHDEncContext *ctx) +{ + if (EXTERNAL_SSE2(av_get_cpu_flags())) { + if (ctx->cid_table->bit_depth == 8) + ctx->get_pixels_8x4_sym = ff_get_pixels_8x4_sym_sse2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/exrdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/exrdsp_init.c new file mode 100644 index 0000000000..63b3480d8f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/exrdsp_init.c @@ -0,0 +1,52 @@ +/* + * OpenEXR (.exr) image decoder + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/exrdsp.h" + +void ff_reorder_pixels_sse2(uint8_t *dst, const uint8_t *src, ptrdiff_t size); + +void ff_reorder_pixels_avx2(uint8_t *dst, const uint8_t *src, ptrdiff_t size); + +void ff_predictor_ssse3(uint8_t *src, ptrdiff_t size); + +void ff_predictor_avx(uint8_t *src, ptrdiff_t size); + +void ff_predictor_avx2(uint8_t *src, ptrdiff_t size); + +av_cold void ff_exrdsp_init_x86(ExrDSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE2(cpu_flags)) { + dsp->reorder_pixels = ff_reorder_pixels_sse2; + } + if (EXTERNAL_SSSE3(cpu_flags)) { + dsp->predictor = ff_predictor_ssse3; + } + if (EXTERNAL_AVX(cpu_flags)) { + dsp->predictor = ff_predictor_avx; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + dsp->reorder_pixels = ff_reorder_pixels_avx2; + dsp->predictor = ff_predictor_avx2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdct.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdct.c new file mode 100644 index 0000000000..112566ded0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdct.c @@ -0,0 +1,594 @@ +/* + * SIMD-optimized forward DCT + * The gcc porting is Copyright (c) 2001 Fabrice Bellard. + * cleanup/optimizations are Copyright (c) 2002-2004 Michael Niedermayer + * SSE2 optimization is Copyright (c) 2004 Denes Balatoni. + * + * from fdctam32.c - AP922 MMX(3D-Now) forward-DCT + * + * Intel Application Note AP-922 - fast, precise implementation of DCT + * http://developer.intel.com/vtune/cbts/appnotes.htm + * + * Also of inspiration: + * a page about fdct at http://www.geocities.com/ssavekar/dct.htm + * Skal's fdct at http://skal.planet-d.net/coding/dct.html + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/x86/asm.h" +#include "fdct.h" + +#if HAVE_MMX_INLINE + +////////////////////////////////////////////////////////////////////// +// +// constants for the forward DCT +// ----------------------------- +// +// Be sure to check that your compiler is aligning all constants to QWORD +// (8-byte) memory boundaries! Otherwise the unaligned memory access will +// severely stall MMX execution. +// +////////////////////////////////////////////////////////////////////// + +#define BITS_FRW_ACC 3 //; 2 or 3 for accuracy +#define SHIFT_FRW_COL BITS_FRW_ACC +#define SHIFT_FRW_ROW (BITS_FRW_ACC + 17 - 3) +#define RND_FRW_ROW (1 << (SHIFT_FRW_ROW-1)) +//#define RND_FRW_COL (1 << (SHIFT_FRW_COL-1)) + +#define X8(x) x,x,x,x,x,x,x,x + +//concatenated table, for forward DCT transformation +DECLARE_ALIGNED(16, static const int16_t, fdct_tg_all_16)[24] = { + X8(13036), // tg * (2<<16) + 0.5 + X8(27146), // tg * (2<<16) + 0.5 + X8(-21746) // tg * (2<<16) + 0.5 +}; + +DECLARE_ALIGNED(16, static const int16_t, ocos_4_16)[8] = { + X8(23170) //cos * (2<<15) + 0.5 +}; + +DECLARE_ALIGNED(16, static const int16_t, fdct_one_corr)[8] = { X8(1) }; + +DECLARE_ALIGNED(8, static const int32_t, fdct_r_row)[2] = {RND_FRW_ROW, RND_FRW_ROW }; + +static const struct +{ + DECLARE_ALIGNED(16, const int32_t, fdct_r_row_sse2)[4]; +} fdct_r_row_sse2 = +{{ + RND_FRW_ROW, RND_FRW_ROW, RND_FRW_ROW, RND_FRW_ROW +}}; +//DECLARE_ALIGNED(16, static const long, fdct_r_row_sse2)[4] = {RND_FRW_ROW, RND_FRW_ROW, RND_FRW_ROW, RND_FRW_ROW}; + +DECLARE_ALIGNED(8, static const int16_t, tab_frw_01234567)[] = { // forward_dct coeff table + 16384, 16384, 22725, 19266, + 16384, 16384, 12873, 4520, + 21407, 8867, 19266, -4520, + -8867, -21407, -22725, -12873, + 16384, -16384, 12873, -22725, + -16384, 16384, 4520, 19266, + 8867, -21407, 4520, -12873, + 21407, -8867, 19266, -22725, + + 22725, 22725, 31521, 26722, + 22725, 22725, 17855, 6270, + 29692, 12299, 26722, -6270, + -12299, -29692, -31521, -17855, + 22725, -22725, 17855, -31521, + -22725, 22725, 6270, 26722, + 12299, -29692, 6270, -17855, + 29692, -12299, 26722, -31521, + + 21407, 21407, 29692, 25172, + 21407, 21407, 16819, 5906, + 27969, 11585, 25172, -5906, + -11585, -27969, -29692, -16819, + 21407, -21407, 16819, -29692, + -21407, 21407, 5906, 25172, + 11585, -27969, 5906, -16819, + 27969, -11585, 25172, -29692, + + 19266, 19266, 26722, 22654, + 19266, 19266, 15137, 5315, + 25172, 10426, 22654, -5315, + -10426, -25172, -26722, -15137, + 19266, -19266, 15137, -26722, + -19266, 19266, 5315, 22654, + 10426, -25172, 5315, -15137, + 25172, -10426, 22654, -26722, + + 16384, 16384, 22725, 19266, + 16384, 16384, 12873, 4520, + 21407, 8867, 19266, -4520, + -8867, -21407, -22725, -12873, + 16384, -16384, 12873, -22725, + -16384, 16384, 4520, 19266, + 8867, -21407, 4520, -12873, + 21407, -8867, 19266, -22725, + + 19266, 19266, 26722, 22654, + 19266, 19266, 15137, 5315, + 25172, 10426, 22654, -5315, + -10426, -25172, -26722, -15137, + 19266, -19266, 15137, -26722, + -19266, 19266, 5315, 22654, + 10426, -25172, 5315, -15137, + 25172, -10426, 22654, -26722, + + 21407, 21407, 29692, 25172, + 21407, 21407, 16819, 5906, + 27969, 11585, 25172, -5906, + -11585, -27969, -29692, -16819, + 21407, -21407, 16819, -29692, + -21407, 21407, 5906, 25172, + 11585, -27969, 5906, -16819, + 27969, -11585, 25172, -29692, + + 22725, 22725, 31521, 26722, + 22725, 22725, 17855, 6270, + 29692, 12299, 26722, -6270, + -12299, -29692, -31521, -17855, + 22725, -22725, 17855, -31521, + -22725, 22725, 6270, 26722, + 12299, -29692, 6270, -17855, + 29692, -12299, 26722, -31521, +}; + +static const struct +{ + DECLARE_ALIGNED(16, const int16_t, tab_frw_01234567_sse2)[256]; +} tab_frw_01234567_sse2 = +{{ +//DECLARE_ALIGNED(16, static const int16_t, tab_frw_01234567_sse2)[] = { // forward_dct coeff table +#define TABLE_SSE2 C4, C4, C1, C3, -C6, -C2, -C1, -C5, \ + C4, C4, C5, C7, C2, C6, C3, -C7, \ + -C4, C4, C7, C3, C6, -C2, C7, -C5, \ + C4, -C4, C5, -C1, C2, -C6, C3, -C1, +// c1..c7 * cos(pi/4) * 2^15 +#define C1 22725 +#define C2 21407 +#define C3 19266 +#define C4 16384 +#define C5 12873 +#define C6 8867 +#define C7 4520 +TABLE_SSE2 + +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +#define C1 31521 +#define C2 29692 +#define C3 26722 +#define C4 22725 +#define C5 17855 +#define C6 12299 +#define C7 6270 +TABLE_SSE2 + +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +#define C1 29692 +#define C2 27969 +#define C3 25172 +#define C4 21407 +#define C5 16819 +#define C6 11585 +#define C7 5906 +TABLE_SSE2 + +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +#define C1 26722 +#define C2 25172 +#define C3 22654 +#define C4 19266 +#define C5 15137 +#define C6 10426 +#define C7 5315 +TABLE_SSE2 + +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +#define C1 22725 +#define C2 21407 +#define C3 19266 +#define C4 16384 +#define C5 12873 +#define C6 8867 +#define C7 4520 +TABLE_SSE2 + +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +#define C1 26722 +#define C2 25172 +#define C3 22654 +#define C4 19266 +#define C5 15137 +#define C6 10426 +#define C7 5315 +TABLE_SSE2 + +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +#define C1 29692 +#define C2 27969 +#define C3 25172 +#define C4 21407 +#define C5 16819 +#define C6 11585 +#define C7 5906 +TABLE_SSE2 + +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +#define C1 31521 +#define C2 29692 +#define C3 26722 +#define C4 22725 +#define C5 17855 +#define C6 12299 +#define C7 6270 +TABLE_SSE2 +}}; + +#define S(s) AV_TOSTRING(s) //AV_STRINGIFY is too long + +#define FDCT_COL(cpu, mm, mov)\ +static av_always_inline void fdct_col_##cpu(const int16_t *in, int16_t *out, int offset)\ +{\ + __asm__ volatile (\ + #mov" 16(%0), %%"#mm"0 \n\t" \ + #mov" 96(%0), %%"#mm"1 \n\t" \ + #mov" %%"#mm"0, %%"#mm"2 \n\t" \ + #mov" 32(%0), %%"#mm"3 \n\t" \ + "paddsw %%"#mm"1, %%"#mm"0 \n\t" \ + #mov" 80(%0), %%"#mm"4 \n\t" \ + "psllw $"S(SHIFT_FRW_COL)", %%"#mm"0 \n\t" \ + #mov" (%0), %%"#mm"5 \n\t" \ + "paddsw %%"#mm"3, %%"#mm"4 \n\t" \ + "paddsw 112(%0), %%"#mm"5 \n\t" \ + "psllw $"S(SHIFT_FRW_COL)", %%"#mm"4 \n\t" \ + #mov" %%"#mm"0, %%"#mm"6 \n\t" \ + "psubsw %%"#mm"1, %%"#mm"2 \n\t" \ + #mov" 16(%1), %%"#mm"1 \n\t" \ + "psubsw %%"#mm"4, %%"#mm"0 \n\t" \ + #mov" 48(%0), %%"#mm"7 \n\t" \ + "pmulhw %%"#mm"0, %%"#mm"1 \n\t" \ + "paddsw 64(%0), %%"#mm"7 \n\t" \ + "psllw $"S(SHIFT_FRW_COL)", %%"#mm"5 \n\t" \ + "paddsw %%"#mm"4, %%"#mm"6 \n\t" \ + "psllw $"S(SHIFT_FRW_COL)", %%"#mm"7 \n\t" \ + #mov" %%"#mm"5, %%"#mm"4 \n\t" \ + "psubsw %%"#mm"7, %%"#mm"5 \n\t" \ + "paddsw %%"#mm"5, %%"#mm"1 \n\t" \ + "paddsw %%"#mm"7, %%"#mm"4 \n\t" \ + "por (%2), %%"#mm"1 \n\t" \ + "psllw $"S(SHIFT_FRW_COL)"+1, %%"#mm"2 \n\t" \ + "pmulhw 16(%1), %%"#mm"5 \n\t" \ + #mov" %%"#mm"4, %%"#mm"7 \n\t" \ + "psubsw 80(%0), %%"#mm"3 \n\t" \ + "psubsw %%"#mm"6, %%"#mm"4 \n\t" \ + #mov" %%"#mm"1, 32(%3) \n\t" \ + "paddsw %%"#mm"6, %%"#mm"7 \n\t" \ + #mov" 48(%0), %%"#mm"1 \n\t" \ + "psllw $"S(SHIFT_FRW_COL)"+1, %%"#mm"3 \n\t" \ + "psubsw 64(%0), %%"#mm"1 \n\t" \ + #mov" %%"#mm"2, %%"#mm"6 \n\t" \ + #mov" %%"#mm"4, 64(%3) \n\t" \ + "paddsw %%"#mm"3, %%"#mm"2 \n\t" \ + "pmulhw (%4), %%"#mm"2 \n\t" \ + "psubsw %%"#mm"3, %%"#mm"6 \n\t" \ + "pmulhw (%4), %%"#mm"6 \n\t" \ + "psubsw %%"#mm"0, %%"#mm"5 \n\t" \ + "por (%2), %%"#mm"5 \n\t" \ + "psllw $"S(SHIFT_FRW_COL)", %%"#mm"1 \n\t" \ + "por (%2), %%"#mm"2 \n\t" \ + #mov" %%"#mm"1, %%"#mm"4 \n\t" \ + #mov" (%0), %%"#mm"3 \n\t" \ + "paddsw %%"#mm"6, %%"#mm"1 \n\t" \ + "psubsw 112(%0), %%"#mm"3 \n\t" \ + "psubsw %%"#mm"6, %%"#mm"4 \n\t" \ + #mov" (%1), %%"#mm"0 \n\t" \ + "psllw $"S(SHIFT_FRW_COL)", %%"#mm"3 \n\t" \ + #mov" 32(%1), %%"#mm"6 \n\t" \ + "pmulhw %%"#mm"1, %%"#mm"0 \n\t" \ + #mov" %%"#mm"7, (%3) \n\t" \ + "pmulhw %%"#mm"4, %%"#mm"6 \n\t" \ + #mov" %%"#mm"5, 96(%3) \n\t" \ + #mov" %%"#mm"3, %%"#mm"7 \n\t" \ + #mov" 32(%1), %%"#mm"5 \n\t" \ + "psubsw %%"#mm"2, %%"#mm"7 \n\t" \ + "paddsw %%"#mm"2, %%"#mm"3 \n\t" \ + "pmulhw %%"#mm"7, %%"#mm"5 \n\t" \ + "paddsw %%"#mm"3, %%"#mm"0 \n\t" \ + "paddsw %%"#mm"4, %%"#mm"6 \n\t" \ + "pmulhw (%1), %%"#mm"3 \n\t" \ + "por (%2), %%"#mm"0 \n\t" \ + "paddsw %%"#mm"7, %%"#mm"5 \n\t" \ + "psubsw %%"#mm"6, %%"#mm"7 \n\t" \ + #mov" %%"#mm"0, 16(%3) \n\t" \ + "paddsw %%"#mm"4, %%"#mm"5 \n\t" \ + #mov" %%"#mm"7, 48(%3) \n\t" \ + "psubsw %%"#mm"1, %%"#mm"3 \n\t" \ + #mov" %%"#mm"5, 80(%3) \n\t" \ + #mov" %%"#mm"3, 112(%3) \n\t" \ + : \ + : "r" (in + offset), "r" (fdct_tg_all_16), "r" (fdct_one_corr), \ + "r" (out + offset), "r" (ocos_4_16)); \ +} + +FDCT_COL(mmx, mm, movq) +FDCT_COL(sse2, xmm, movdqa) + +static av_always_inline void fdct_row_sse2(const int16_t *in, int16_t *out) +{ + __asm__ volatile( +#define FDCT_ROW_SSE2_H1(i,t) \ + "movq " #i "(%0), %%xmm2 \n\t" \ + "movq " #i "+8(%0), %%xmm0 \n\t" \ + "movdqa " #t "+32(%1), %%xmm3 \n\t" \ + "movdqa " #t "+48(%1), %%xmm7 \n\t" \ + "movdqa " #t "(%1), %%xmm4 \n\t" \ + "movdqa " #t "+16(%1), %%xmm5 \n\t" + +#define FDCT_ROW_SSE2_H2(i,t) \ + "movq " #i "(%0), %%xmm2 \n\t" \ + "movq " #i "+8(%0), %%xmm0 \n\t" \ + "movdqa " #t "+32(%1), %%xmm3 \n\t" \ + "movdqa " #t "+48(%1), %%xmm7 \n\t" + +#define FDCT_ROW_SSE2(i) \ + "movq %%xmm2, %%xmm1 \n\t" \ + "pshuflw $27, %%xmm0, %%xmm0 \n\t" \ + "paddsw %%xmm0, %%xmm1 \n\t" \ + "psubsw %%xmm0, %%xmm2 \n\t" \ + "punpckldq %%xmm2, %%xmm1 \n\t" \ + "pshufd $78, %%xmm1, %%xmm2 \n\t" \ + "pmaddwd %%xmm2, %%xmm3 \n\t" \ + "pmaddwd %%xmm1, %%xmm7 \n\t" \ + "pmaddwd %%xmm5, %%xmm2 \n\t" \ + "pmaddwd %%xmm4, %%xmm1 \n\t" \ + "paddd %%xmm7, %%xmm3 \n\t" \ + "paddd %%xmm2, %%xmm1 \n\t" \ + "paddd %%xmm6, %%xmm3 \n\t" \ + "paddd %%xmm6, %%xmm1 \n\t" \ + "psrad %3, %%xmm3 \n\t" \ + "psrad %3, %%xmm1 \n\t" \ + "packssdw %%xmm3, %%xmm1 \n\t" \ + "movdqa %%xmm1, " #i "(%4) \n\t" + + "movdqa (%2), %%xmm6 \n\t" + FDCT_ROW_SSE2_H1(0,0) + FDCT_ROW_SSE2(0) + FDCT_ROW_SSE2_H2(64,0) + FDCT_ROW_SSE2(64) + + FDCT_ROW_SSE2_H1(16,64) + FDCT_ROW_SSE2(16) + FDCT_ROW_SSE2_H2(112,64) + FDCT_ROW_SSE2(112) + + FDCT_ROW_SSE2_H1(32,128) + FDCT_ROW_SSE2(32) + FDCT_ROW_SSE2_H2(96,128) + FDCT_ROW_SSE2(96) + + FDCT_ROW_SSE2_H1(48,192) + FDCT_ROW_SSE2(48) + FDCT_ROW_SSE2_H2(80,192) + FDCT_ROW_SSE2(80) + : + : "r" (in), "r" (tab_frw_01234567_sse2.tab_frw_01234567_sse2), + "r" (fdct_r_row_sse2.fdct_r_row_sse2), "i" (SHIFT_FRW_ROW), "r" (out) + XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3", + "%xmm4", "%xmm5", "%xmm6", "%xmm7") + ); +} + +static av_always_inline void fdct_row_mmxext(const int16_t *in, int16_t *out, + const int16_t *table) +{ + __asm__ volatile ( + "pshufw $0x1B, 8(%0), %%mm5 \n\t" + "movq (%0), %%mm0 \n\t" + "movq %%mm0, %%mm1 \n\t" + "paddsw %%mm5, %%mm0 \n\t" + "psubsw %%mm5, %%mm1 \n\t" + "movq %%mm0, %%mm2 \n\t" + "punpckldq %%mm1, %%mm0 \n\t" + "punpckhdq %%mm1, %%mm2 \n\t" + "movq (%1), %%mm1 \n\t" + "movq 8(%1), %%mm3 \n\t" + "movq 16(%1), %%mm4 \n\t" + "movq 24(%1), %%mm5 \n\t" + "movq 32(%1), %%mm6 \n\t" + "movq 40(%1), %%mm7 \n\t" + "pmaddwd %%mm0, %%mm1 \n\t" + "pmaddwd %%mm2, %%mm3 \n\t" + "pmaddwd %%mm0, %%mm4 \n\t" + "pmaddwd %%mm2, %%mm5 \n\t" + "pmaddwd %%mm0, %%mm6 \n\t" + "pmaddwd %%mm2, %%mm7 \n\t" + "pmaddwd 48(%1), %%mm0 \n\t" + "pmaddwd 56(%1), %%mm2 \n\t" + "paddd %%mm1, %%mm3 \n\t" + "paddd %%mm4, %%mm5 \n\t" + "paddd %%mm6, %%mm7 \n\t" + "paddd %%mm0, %%mm2 \n\t" + "movq (%2), %%mm0 \n\t" + "paddd %%mm0, %%mm3 \n\t" + "paddd %%mm0, %%mm5 \n\t" + "paddd %%mm0, %%mm7 \n\t" + "paddd %%mm0, %%mm2 \n\t" + "psrad $"S(SHIFT_FRW_ROW)", %%mm3 \n\t" + "psrad $"S(SHIFT_FRW_ROW)", %%mm5 \n\t" + "psrad $"S(SHIFT_FRW_ROW)", %%mm7 \n\t" + "psrad $"S(SHIFT_FRW_ROW)", %%mm2 \n\t" + "packssdw %%mm5, %%mm3 \n\t" + "packssdw %%mm2, %%mm7 \n\t" + "movq %%mm3, (%3) \n\t" + "movq %%mm7, 8(%3) \n\t" + : + : "r" (in), "r" (table), "r" (fdct_r_row), "r" (out)); +} + +static av_always_inline void fdct_row_mmx(const int16_t *in, int16_t *out, const int16_t *table) +{ + //FIXME reorder (I do not have an old MMX-only CPU here to benchmark ...) + __asm__ volatile( + "movd 12(%0), %%mm1 \n\t" + "punpcklwd 8(%0), %%mm1 \n\t" + "movq %%mm1, %%mm2 \n\t" + "psrlq $0x20, %%mm1 \n\t" + "movq 0(%0), %%mm0 \n\t" + "punpcklwd %%mm2, %%mm1 \n\t" + "movq %%mm0, %%mm5 \n\t" + "paddsw %%mm1, %%mm0 \n\t" + "psubsw %%mm1, %%mm5 \n\t" + "movq %%mm0, %%mm2 \n\t" + "punpckldq %%mm5, %%mm0 \n\t" + "punpckhdq %%mm5, %%mm2 \n\t" + "movq 0(%1), %%mm1 \n\t" + "movq 8(%1), %%mm3 \n\t" + "movq 16(%1), %%mm4 \n\t" + "movq 24(%1), %%mm5 \n\t" + "movq 32(%1), %%mm6 \n\t" + "movq 40(%1), %%mm7 \n\t" + "pmaddwd %%mm0, %%mm1 \n\t" + "pmaddwd %%mm2, %%mm3 \n\t" + "pmaddwd %%mm0, %%mm4 \n\t" + "pmaddwd %%mm2, %%mm5 \n\t" + "pmaddwd %%mm0, %%mm6 \n\t" + "pmaddwd %%mm2, %%mm7 \n\t" + "pmaddwd 48(%1), %%mm0 \n\t" + "pmaddwd 56(%1), %%mm2 \n\t" + "paddd %%mm1, %%mm3 \n\t" + "paddd %%mm4, %%mm5 \n\t" + "paddd %%mm6, %%mm7 \n\t" + "paddd %%mm0, %%mm2 \n\t" + "movq (%2), %%mm0 \n\t" + "paddd %%mm0, %%mm3 \n\t" + "paddd %%mm0, %%mm5 \n\t" + "paddd %%mm0, %%mm7 \n\t" + "paddd %%mm0, %%mm2 \n\t" + "psrad $"S(SHIFT_FRW_ROW)", %%mm3 \n\t" + "psrad $"S(SHIFT_FRW_ROW)", %%mm5 \n\t" + "psrad $"S(SHIFT_FRW_ROW)", %%mm7 \n\t" + "psrad $"S(SHIFT_FRW_ROW)", %%mm2 \n\t" + "packssdw %%mm5, %%mm3 \n\t" + "packssdw %%mm2, %%mm7 \n\t" + "movq %%mm3, 0(%3) \n\t" + "movq %%mm7, 8(%3) \n\t" + : + : "r" (in), "r" (table), "r" (fdct_r_row), "r" (out)); +} + +void ff_fdct_mmx(int16_t *block) +{ + DECLARE_ALIGNED(8, int64_t, align_tmp)[16]; + int16_t * block1= (int16_t*)align_tmp; + const int16_t *table= tab_frw_01234567; + int i; + + fdct_col_mmx(block, block1, 0); + fdct_col_mmx(block, block1, 4); + + for(i=8;i>0;i--) { + fdct_row_mmx(block1, block, table); + block1 += 8; + table += 32; + block += 8; + } +} + +#endif /* HAVE_MMX_INLINE */ + +#if HAVE_MMXEXT_INLINE + +void ff_fdct_mmxext(int16_t *block) +{ + DECLARE_ALIGNED(8, int64_t, align_tmp)[16]; + int16_t *block1= (int16_t*)align_tmp; + const int16_t *table= tab_frw_01234567; + int i; + + fdct_col_mmx(block, block1, 0); + fdct_col_mmx(block, block1, 4); + + for(i=8;i>0;i--) { + fdct_row_mmxext(block1, block, table); + block1 += 8; + table += 32; + block += 8; + } +} + +#endif /* HAVE_MMXEXT_INLINE */ + +#if HAVE_SSE2_INLINE + +void ff_fdct_sse2(int16_t *block) +{ + DECLARE_ALIGNED(16, int64_t, align_tmp)[16]; + int16_t * const block1= (int16_t*)align_tmp; + + fdct_col_sse2(block, block1, 0); + fdct_row_sse2(block1, block); +} + +#endif /* HAVE_SSE2_INLINE */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdct.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdct.h new file mode 100644 index 0000000000..648cdc5350 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdct.h @@ -0,0 +1,28 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_FDCT_H +#define AVCODEC_X86_FDCT_H + +#include + +void ff_fdct_mmx(int16_t *block); +void ff_fdct_mmxext(int16_t *block); +void ff_fdct_sse2(int16_t *block); + +#endif /* AVCODEC_X86_FDCT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdctdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdctdsp_init.c new file mode 100644 index 0000000000..0cb5fd625b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fdctdsp_init.c @@ -0,0 +1,44 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/fdctdsp.h" +#include "fdct.h" + +av_cold void ff_fdctdsp_init_x86(FDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth) +{ + int cpu_flags = av_get_cpu_flags(); + const int dct_algo = avctx->dct_algo; + + if (!high_bit_depth) { + if ((dct_algo == FF_DCT_AUTO || dct_algo == FF_DCT_MMX)) { + if (INLINE_MMX(cpu_flags)) + c->fdct = ff_fdct_mmx; + + if (INLINE_MMXEXT(cpu_flags)) + c->fdct = ff_fdct_mmxext; + + if (INLINE_SSE2(cpu_flags)) + c->fdct = ff_fdct_sse2; + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft.h new file mode 100644 index 0000000000..398091eb1f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft.h @@ -0,0 +1,38 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_FFT_H +#define AVCODEC_X86_FFT_H + +#include "libavcodec/fft.h" + +void ff_fft_permute_sse(FFTContext *s, FFTComplex *z); +void ff_fft_calc_avx(FFTContext *s, FFTComplex *z); +void ff_fft_calc_sse(FFTContext *s, FFTComplex *z); +void ff_fft_calc_3dnow(FFTContext *s, FFTComplex *z); +void ff_fft_calc_3dnowext(FFTContext *s, FFTComplex *z); + +void ff_imdct_calc_3dnow(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_imdct_half_3dnow(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_imdct_calc_3dnowext(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_imdct_half_3dnowext(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_imdct_calc_sse(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_imdct_half_sse(FFTContext *s, FFTSample *output, const FFTSample *input); +void ff_imdct_half_avx(FFTContext *s, FFTSample *output, const FFTSample *input); + +#endif /* AVCODEC_X86_FFT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft_init.c new file mode 100644 index 0000000000..928f1dcda7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft_init.c @@ -0,0 +1,61 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" + +#include "fft.h" + +av_cold void ff_fft_init_x86(FFTContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (s->nbits > 16) + return; + +#if ARCH_X86_32 + if (EXTERNAL_AMD3DNOW(cpu_flags)) { + s->imdct_calc = ff_imdct_calc_3dnow; + s->imdct_half = ff_imdct_half_3dnow; + s->fft_calc = ff_fft_calc_3dnow; + } + + if (EXTERNAL_AMD3DNOWEXT(cpu_flags)) { + s->imdct_calc = ff_imdct_calc_3dnowext; + s->imdct_half = ff_imdct_half_3dnowext; + s->fft_calc = ff_fft_calc_3dnowext; + } +#endif /* ARCH_X86_32 */ + + if (EXTERNAL_SSE(cpu_flags)) { + s->imdct_calc = ff_imdct_calc_sse; + s->imdct_half = ff_imdct_half_sse; + s->fft_permute = ff_fft_permute_sse; + s->fft_calc = ff_fft_calc_sse; + s->fft_permutation = FF_FFT_PERM_SWAP_LSBS; + } + + if (EXTERNAL_AVX_FAST(cpu_flags) && s->nbits >= 5) { + s->imdct_half = ff_imdct_half_avx; + s->fft_calc = ff_fft_calc_avx; + s->fft_permutation = FF_FFT_PERM_AVX; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/flacdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/flacdsp_init.c new file mode 100644 index 0000000000..1971f81b8d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/flacdsp_init.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/flacdsp.h" +#include "libavutil/x86/cpu.h" +#include "config.h" + +void ff_flac_lpc_32_sse4(int32_t *samples, const int coeffs[32], int order, + int qlevel, int len); +void ff_flac_lpc_32_xop(int32_t *samples, const int coeffs[32], int order, + int qlevel, int len); + +void ff_flac_enc_lpc_16_sse4(int32_t *, const int32_t *, int, int, const int32_t *,int); + +#define DECORRELATE_FUNCS(fmt, opt) \ +void ff_flac_decorrelate_ls_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \ + int len, int shift); \ +void ff_flac_decorrelate_rs_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \ + int len, int shift); \ +void ff_flac_decorrelate_ms_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \ + int len, int shift); \ +void ff_flac_decorrelate_indep2_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \ + int len, int shift); \ +void ff_flac_decorrelate_indep4_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \ + int len, int shift); \ +void ff_flac_decorrelate_indep6_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \ + int len, int shift); \ +void ff_flac_decorrelate_indep8_##fmt##_##opt(uint8_t **out, int32_t **in, int channels, \ + int len, int shift) + +DECORRELATE_FUNCS(16, sse2); +DECORRELATE_FUNCS(16, avx); +DECORRELATE_FUNCS(32, sse2); +DECORRELATE_FUNCS(32, avx); + +av_cold void ff_flacdsp_init_x86(FLACDSPContext *c, enum AVSampleFormat fmt, int channels, + int bps) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + +#if CONFIG_FLAC_DECODER + if (EXTERNAL_SSE2(cpu_flags)) { + if (fmt == AV_SAMPLE_FMT_S16) { + if (channels == 2) + c->decorrelate[0] = ff_flac_decorrelate_indep2_16_sse2; + else if (channels == 4) + c->decorrelate[0] = ff_flac_decorrelate_indep4_16_sse2; + else if (channels == 6) + c->decorrelate[0] = ff_flac_decorrelate_indep6_16_sse2; + else if (ARCH_X86_64 && channels == 8) + c->decorrelate[0] = ff_flac_decorrelate_indep8_16_sse2; + c->decorrelate[1] = ff_flac_decorrelate_ls_16_sse2; + c->decorrelate[2] = ff_flac_decorrelate_rs_16_sse2; + c->decorrelate[3] = ff_flac_decorrelate_ms_16_sse2; + } else if (fmt == AV_SAMPLE_FMT_S32) { + if (channels == 2) + c->decorrelate[0] = ff_flac_decorrelate_indep2_32_sse2; + else if (channels == 4) + c->decorrelate[0] = ff_flac_decorrelate_indep4_32_sse2; + else if (channels == 6) + c->decorrelate[0] = ff_flac_decorrelate_indep6_32_sse2; + else if (ARCH_X86_64 && channels == 8) + c->decorrelate[0] = ff_flac_decorrelate_indep8_32_sse2; + c->decorrelate[1] = ff_flac_decorrelate_ls_32_sse2; + c->decorrelate[2] = ff_flac_decorrelate_rs_32_sse2; + c->decorrelate[3] = ff_flac_decorrelate_ms_32_sse2; + } + } + if (EXTERNAL_SSE4(cpu_flags)) { + c->lpc32 = ff_flac_lpc_32_sse4; + } + if (EXTERNAL_AVX(cpu_flags)) { + if (fmt == AV_SAMPLE_FMT_S16) { + if (ARCH_X86_64 && channels == 8) + c->decorrelate[0] = ff_flac_decorrelate_indep8_16_avx; + } else if (fmt == AV_SAMPLE_FMT_S32) { + if (channels == 4) + c->decorrelate[0] = ff_flac_decorrelate_indep4_32_avx; + else if (channels == 6) + c->decorrelate[0] = ff_flac_decorrelate_indep6_32_avx; + else if (ARCH_X86_64 && channels == 8) + c->decorrelate[0] = ff_flac_decorrelate_indep8_32_avx; + } + } + if (EXTERNAL_XOP(cpu_flags)) { + c->lpc32 = ff_flac_lpc_32_xop; + } +#endif + +#if CONFIG_FLAC_ENCODER + if (EXTERNAL_SSE4(cpu_flags)) { + if (CONFIG_GPL) + c->lpc16_encode = ff_flac_enc_lpc_16_sse4; + } +#endif +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fmtconvert_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fmtconvert_init.c new file mode 100644 index 0000000000..df097054e4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fmtconvert_init.c @@ -0,0 +1,55 @@ +/* + * Format Conversion Utils + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * MMX optimization by Nick Kurshev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/fmtconvert.h" + +#if HAVE_X86ASM + +void ff_int32_to_float_fmul_scalar_sse (float *dst, const int32_t *src, float mul, int len); +void ff_int32_to_float_fmul_scalar_sse2(float *dst, const int32_t *src, float mul, int len); +void ff_int32_to_float_fmul_array8_sse (FmtConvertContext *c, float *dst, const int32_t *src, + const float *mul, int len); +void ff_int32_to_float_fmul_array8_sse2(FmtConvertContext *c, float *dst, const int32_t *src, + const float *mul, int len); + +#endif /* HAVE_X86ASM */ + +av_cold void ff_fmt_convert_init_x86(FmtConvertContext *c, AVCodecContext *avctx) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE(cpu_flags)) { + c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_sse; + c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_sse; + } + if (EXTERNAL_SSE2(cpu_flags)) { + c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_sse2; + c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_sse2; + } +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fpel.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fpel.h new file mode 100644 index 0000000000..4e83cf71c3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fpel.h @@ -0,0 +1,49 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_FPEL_H +#define AVCODEC_X86_FPEL_H + +#include +#include + +void ff_avg_pixels4_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels4_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels4_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); + + +#endif /* AVCODEC_X86_FPEL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/g722dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/g722dsp_init.c new file mode 100644 index 0000000000..614695193b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/g722dsp_init.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/g722dsp.h" + +void ff_g722_apply_qmf_sse2(const int16_t *prev_samples, int xout[2]); + +av_cold void ff_g722dsp_init_x86(G722DSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE2(cpu_flags)) + dsp->apply_qmf = ff_g722_apply_qmf_sse2; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h263dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h263dsp_init.c new file mode 100644 index 0000000000..ab81063233 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h263dsp_init.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 Diego Biurrun + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/h263dsp.h" + +void ff_h263_h_loop_filter_mmx(uint8_t *src, int stride, int qscale); +void ff_h263_v_loop_filter_mmx(uint8_t *src, int stride, int qscale); + +av_cold void ff_h263dsp_init_x86(H263DSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + c->h263_h_loop_filter = ff_h263_h_loop_filter_mmx; + c->h263_v_loop_filter = ff_h263_v_loop_filter_mmx; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_cabac.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_cabac.c new file mode 100644 index 0000000000..2edc6d7e74 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_cabac.c @@ -0,0 +1,208 @@ +/* + * H.26L/H.264/AVC/JVT/14496-10/... encoder/decoder + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * H.264 / AVC / MPEG-4 part10 codec. + * non-SIMD x86-specific optimizations for H.264 + * @author Michael Niedermayer + */ + +#include + +#include "libavcodec/cabac.h" +#include "cabac.h" + +#if HAVE_INLINE_ASM + +#if ARCH_X86_64 +#define REG64 "r" +#else +#define REG64 "m" +#endif + +//FIXME use some macros to avoid duplicating get_cabac (cannot be done yet +//as that would make optimization work hard) +#if HAVE_7REGS && !BROKEN_COMPILER +#define decode_significance decode_significance_x86 +static int decode_significance_x86(CABACContext *c, int max_coeff, + uint8_t *significant_coeff_ctx_base, + int *index, x86_reg last_off){ + void *end= significant_coeff_ctx_base + max_coeff - 1; + int minusstart= -(intptr_t)significant_coeff_ctx_base; + int minusindex= 4-(intptr_t)index; + int bit; + x86_reg coeff_count; + +#ifdef BROKEN_RELOCATIONS + void *tables; + + __asm__ volatile( + "lea "MANGLE(ff_h264_cabac_tables)", %0 \n\t" + : "=&r"(tables) + : NAMED_CONSTRAINTS_ARRAY(ff_h264_cabac_tables) + ); +#endif + + __asm__ volatile( + "3: \n\t" + + BRANCHLESS_GET_CABAC("%4", "%q4", "(%1)", "%3", "%w3", + "%5", "%q5", "%k0", "%b0", + "%c11(%6)", "%c12(%6)", + AV_STRINGIFY(H264_NORM_SHIFT_OFFSET), + AV_STRINGIFY(H264_LPS_RANGE_OFFSET), + AV_STRINGIFY(H264_MLPS_STATE_OFFSET), + "%13") + + "test $1, %4 \n\t" + " jz 4f \n\t" + "add %10, %1 \n\t" + + BRANCHLESS_GET_CABAC("%4", "%q4", "(%1)", "%3", "%w3", + "%5", "%q5", "%k0", "%b0", + "%c11(%6)", "%c12(%6)", + AV_STRINGIFY(H264_NORM_SHIFT_OFFSET), + AV_STRINGIFY(H264_LPS_RANGE_OFFSET), + AV_STRINGIFY(H264_MLPS_STATE_OFFSET), + "%13") + + "sub %10, %1 \n\t" + "mov %2, %0 \n\t" + "movl %7, %%ecx \n\t" + "add %1, %%"FF_REG_c" \n\t" + "movl %%ecx, (%0) \n\t" + + "test $1, %4 \n\t" + " jnz 5f \n\t" + + "add"FF_OPSIZE" $4, %2 \n\t" + + "4: \n\t" + "add $1, %1 \n\t" + "cmp %8, %1 \n\t" + " jb 3b \n\t" + "mov %2, %0 \n\t" + "movl %7, %%ecx \n\t" + "add %1, %%"FF_REG_c" \n\t" + "movl %%ecx, (%0) \n\t" + "5: \n\t" + "add %9, %k0 \n\t" + "shr $2, %k0 \n\t" + : "=&q"(coeff_count), "+r"(significant_coeff_ctx_base), "+m"(index), + "+&r"(c->low), "=&r"(bit), "+&r"(c->range) + : "r"(c), "m"(minusstart), "m"(end), "m"(minusindex), "m"(last_off), + "i"(offsetof(CABACContext, bytestream)), + "i"(offsetof(CABACContext, bytestream_end)) + TABLES_ARG + : "%"FF_REG_c, "memory" + ); + return coeff_count; +} + +#define decode_significance_8x8 decode_significance_8x8_x86 +static int decode_significance_8x8_x86(CABACContext *c, + uint8_t *significant_coeff_ctx_base, + int *index, uint8_t *last_coeff_ctx_base, const uint8_t *sig_off){ + int minusindex= 4-(intptr_t)index; + int bit; + x86_reg coeff_count; + x86_reg last=0; + x86_reg state; + +#ifdef BROKEN_RELOCATIONS + void *tables; + + __asm__ volatile( + "lea "MANGLE(ff_h264_cabac_tables)", %0 \n\t" + : "=&r"(tables) + : NAMED_CONSTRAINTS_ARRAY(ff_h264_cabac_tables) + ); +#endif + + __asm__ volatile( + "mov %1, %6 \n\t" + "3: \n\t" + + "mov %10, %0 \n\t" + "movzb (%0, %6), %6 \n\t" + "add %9, %6 \n\t" + + BRANCHLESS_GET_CABAC("%4", "%q4", "(%6)", "%3", "%w3", + "%5", "%q5", "%k0", "%b0", + "%c12(%7)", "%c13(%7)", + AV_STRINGIFY(H264_NORM_SHIFT_OFFSET), + AV_STRINGIFY(H264_LPS_RANGE_OFFSET), + AV_STRINGIFY(H264_MLPS_STATE_OFFSET), + "%15") + + "mov %1, %6 \n\t" + "test $1, %4 \n\t" + " jz 4f \n\t" + +#ifdef BROKEN_RELOCATIONS + "movzb %c14(%15, %q6), %6\n\t" +#else + "movzb "MANGLE(ff_h264_cabac_tables)"+%c14(%6), %6\n\t" +#endif + "add %11, %6 \n\t" + + BRANCHLESS_GET_CABAC("%4", "%q4", "(%6)", "%3", "%w3", + "%5", "%q5", "%k0", "%b0", + "%c12(%7)", "%c13(%7)", + AV_STRINGIFY(H264_NORM_SHIFT_OFFSET), + AV_STRINGIFY(H264_LPS_RANGE_OFFSET), + AV_STRINGIFY(H264_MLPS_STATE_OFFSET), + "%15") + + "mov %2, %0 \n\t" + "mov %1, %6 \n\t" + "mov %k6, (%0) \n\t" + + "test $1, %4 \n\t" + " jnz 5f \n\t" + + "add"FF_OPSIZE" $4, %2 \n\t" + + "4: \n\t" + "add $1, %6 \n\t" + "mov %6, %1 \n\t" + "cmp $63, %6 \n\t" + " jb 3b \n\t" + "mov %2, %0 \n\t" + "mov %k6, (%0) \n\t" + "5: \n\t" + "addl %8, %k0 \n\t" + "shr $2, %k0 \n\t" + : "=&q"(coeff_count), "+"REG64(last), "+"REG64(index), "+&r"(c->low), + "=&r"(bit), "+&r"(c->range), "=&r"(state) + : "r"(c), "m"(minusindex), "m"(significant_coeff_ctx_base), + REG64(sig_off), REG64(last_coeff_ctx_base), + "i"(offsetof(CABACContext, bytestream)), + "i"(offsetof(CABACContext, bytestream_end)), + "i"(H264_LAST_COEFF_FLAG_OFFSET_8x8_OFFSET) TABLES_ARG + : "%"FF_REG_c, "memory" + ); + return coeff_count; +} +#endif /* HAVE_7REGS && BROKEN_COMPILER */ + +#endif /* HAVE_INLINE_ASM */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_intrapred_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_intrapred_init.c new file mode 100644 index 0000000000..bdd5125d68 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_intrapred_init.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2010 Fiona Glaser + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/h264pred.h" + +#define PRED4x4(TYPE, DEPTH, OPT) \ +void ff_pred4x4_ ## TYPE ## _ ## DEPTH ## _ ## OPT (uint8_t *src, \ + const uint8_t *topright, \ + ptrdiff_t stride); + +PRED4x4(dc, 10, mmxext) +PRED4x4(down_left, 10, sse2) +PRED4x4(down_left, 10, avx) +PRED4x4(down_right, 10, sse2) +PRED4x4(down_right, 10, ssse3) +PRED4x4(down_right, 10, avx) +PRED4x4(vertical_left, 10, sse2) +PRED4x4(vertical_left, 10, avx) +PRED4x4(vertical_right, 10, sse2) +PRED4x4(vertical_right, 10, ssse3) +PRED4x4(vertical_right, 10, avx) +PRED4x4(horizontal_up, 10, mmxext) +PRED4x4(horizontal_down, 10, sse2) +PRED4x4(horizontal_down, 10, ssse3) +PRED4x4(horizontal_down, 10, avx) + +#define PRED8x8(TYPE, DEPTH, OPT) \ +void ff_pred8x8_ ## TYPE ## _ ## DEPTH ## _ ## OPT (uint8_t *src, \ + ptrdiff_t stride); + +PRED8x8(dc, 10, mmxext) +PRED8x8(dc, 10, sse2) +PRED8x8(top_dc, 10, sse2) +PRED8x8(plane, 10, sse2) +PRED8x8(vertical, 10, sse2) +PRED8x8(horizontal, 10, sse2) + +#define PRED8x8L(TYPE, DEPTH, OPT)\ +void ff_pred8x8l_ ## TYPE ## _ ## DEPTH ## _ ## OPT (uint8_t *src, \ + int has_topleft, \ + int has_topright, \ + ptrdiff_t stride); + +PRED8x8L(dc, 10, sse2) +PRED8x8L(dc, 10, avx) +PRED8x8L(128_dc, 10, mmxext) +PRED8x8L(128_dc, 10, sse2) +PRED8x8L(top_dc, 10, sse2) +PRED8x8L(top_dc, 10, avx) +PRED8x8L(vertical, 10, sse2) +PRED8x8L(vertical, 10, avx) +PRED8x8L(horizontal, 10, sse2) +PRED8x8L(horizontal, 10, ssse3) +PRED8x8L(horizontal, 10, avx) +PRED8x8L(down_left, 10, sse2) +PRED8x8L(down_left, 10, ssse3) +PRED8x8L(down_left, 10, avx) +PRED8x8L(down_right, 10, sse2) +PRED8x8L(down_right, 10, ssse3) +PRED8x8L(down_right, 10, avx) +PRED8x8L(vertical_right, 10, sse2) +PRED8x8L(vertical_right, 10, ssse3) +PRED8x8L(vertical_right, 10, avx) +PRED8x8L(horizontal_up, 10, sse2) +PRED8x8L(horizontal_up, 10, ssse3) +PRED8x8L(horizontal_up, 10, avx) + +#define PRED16x16(TYPE, DEPTH, OPT)\ +void ff_pred16x16_ ## TYPE ## _ ## DEPTH ## _ ## OPT (uint8_t *src, \ + ptrdiff_t stride); + +PRED16x16(dc, 10, mmxext) +PRED16x16(dc, 10, sse2) +PRED16x16(top_dc, 10, mmxext) +PRED16x16(top_dc, 10, sse2) +PRED16x16(128_dc, 10, mmxext) +PRED16x16(128_dc, 10, sse2) +PRED16x16(left_dc, 10, mmxext) +PRED16x16(left_dc, 10, sse2) +PRED16x16(vertical, 10, mmxext) +PRED16x16(vertical, 10, sse2) +PRED16x16(horizontal, 10, mmxext) +PRED16x16(horizontal, 10, sse2) + +/* 8-bit versions */ +PRED16x16(vertical, 8, mmx) +PRED16x16(vertical, 8, sse) +PRED16x16(horizontal, 8, mmx) +PRED16x16(horizontal, 8, mmxext) +PRED16x16(horizontal, 8, ssse3) +PRED16x16(dc, 8, mmxext) +PRED16x16(dc, 8, sse2) +PRED16x16(dc, 8, ssse3) +PRED16x16(plane_h264, 8, mmx) +PRED16x16(plane_h264, 8, mmxext) +PRED16x16(plane_h264, 8, sse2) +PRED16x16(plane_h264, 8, ssse3) +PRED16x16(plane_rv40, 8, mmx) +PRED16x16(plane_rv40, 8, mmxext) +PRED16x16(plane_rv40, 8, sse2) +PRED16x16(plane_rv40, 8, ssse3) +PRED16x16(plane_svq3, 8, mmx) +PRED16x16(plane_svq3, 8, mmxext) +PRED16x16(plane_svq3, 8, sse2) +PRED16x16(plane_svq3, 8, ssse3) +PRED16x16(tm_vp8, 8, mmx) +PRED16x16(tm_vp8, 8, mmxext) +PRED16x16(tm_vp8, 8, sse2) +PRED16x16(tm_vp8, 8, avx2) + +PRED8x8(top_dc, 8, mmxext) +PRED8x8(dc_rv40, 8, mmxext) +PRED8x8(dc, 8, mmxext) +PRED8x8(vertical, 8, mmx) +PRED8x8(horizontal, 8, mmx) +PRED8x8(horizontal, 8, mmxext) +PRED8x8(horizontal, 8, ssse3) +PRED8x8(plane, 8, mmx) +PRED8x8(plane, 8, mmxext) +PRED8x8(plane, 8, sse2) +PRED8x8(plane, 8, ssse3) +PRED8x8(tm_vp8, 8, mmx) +PRED8x8(tm_vp8, 8, mmxext) +PRED8x8(tm_vp8, 8, sse2) +PRED8x8(tm_vp8, 8, ssse3) + +PRED8x8L(top_dc, 8, mmxext) +PRED8x8L(top_dc, 8, ssse3) +PRED8x8L(dc, 8, mmxext) +PRED8x8L(dc, 8, ssse3) +PRED8x8L(horizontal, 8, mmxext) +PRED8x8L(horizontal, 8, ssse3) +PRED8x8L(vertical, 8, mmxext) +PRED8x8L(vertical, 8, ssse3) +PRED8x8L(down_left, 8, mmxext) +PRED8x8L(down_left, 8, sse2) +PRED8x8L(down_left, 8, ssse3) +PRED8x8L(down_right, 8, mmxext) +PRED8x8L(down_right, 8, sse2) +PRED8x8L(down_right, 8, ssse3) +PRED8x8L(vertical_right, 8, mmxext) +PRED8x8L(vertical_right, 8, sse2) +PRED8x8L(vertical_right, 8, ssse3) +PRED8x8L(vertical_left, 8, sse2) +PRED8x8L(vertical_left, 8, ssse3) +PRED8x8L(horizontal_up, 8, mmxext) +PRED8x8L(horizontal_up, 8, ssse3) +PRED8x8L(horizontal_down, 8, mmxext) +PRED8x8L(horizontal_down, 8, sse2) +PRED8x8L(horizontal_down, 8, ssse3) + +PRED4x4(dc, 8, mmxext) +PRED4x4(down_left, 8, mmxext) +PRED4x4(down_right, 8, mmxext) +PRED4x4(vertical_left, 8, mmxext) +PRED4x4(vertical_right, 8, mmxext) +PRED4x4(horizontal_up, 8, mmxext) +PRED4x4(horizontal_down, 8, mmxext) +PRED4x4(tm_vp8, 8, mmx) +PRED4x4(tm_vp8, 8, mmxext) +PRED4x4(tm_vp8, 8, ssse3) +PRED4x4(vertical_vp8, 8, mmxext) + +av_cold void ff_h264_pred_init_x86(H264PredContext *h, int codec_id, + const int bit_depth, + const int chroma_format_idc) +{ + int cpu_flags = av_get_cpu_flags(); + + if (bit_depth == 8) { + if (EXTERNAL_MMX(cpu_flags)) { + h->pred16x16[VERT_PRED8x8 ] = ff_pred16x16_vertical_8_mmx; + h->pred16x16[HOR_PRED8x8 ] = ff_pred16x16_horizontal_8_mmx; + if (chroma_format_idc <= 1) { + h->pred8x8 [VERT_PRED8x8 ] = ff_pred8x8_vertical_8_mmx; + h->pred8x8 [HOR_PRED8x8 ] = ff_pred8x8_horizontal_8_mmx; + } + if (codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { + h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_tm_vp8_8_mmx; + h->pred8x8 [PLANE_PRED8x8 ] = ff_pred8x8_tm_vp8_8_mmx; + h->pred4x4 [TM_VP8_PRED ] = ff_pred4x4_tm_vp8_8_mmx; + } else { + if (chroma_format_idc <= 1) + h->pred8x8 [PLANE_PRED8x8] = ff_pred8x8_plane_8_mmx; + if (codec_id == AV_CODEC_ID_SVQ3) { + if (cpu_flags & AV_CPU_FLAG_CMOV) + h->pred16x16[PLANE_PRED8x8] = ff_pred16x16_plane_svq3_8_mmx; + } else if (codec_id == AV_CODEC_ID_RV40) { + h->pred16x16[PLANE_PRED8x8] = ff_pred16x16_plane_rv40_8_mmx; + } else { + h->pred16x16[PLANE_PRED8x8] = ff_pred16x16_plane_h264_8_mmx; + } + } + } + + if (EXTERNAL_MMXEXT(cpu_flags)) { + h->pred16x16[HOR_PRED8x8 ] = ff_pred16x16_horizontal_8_mmxext; + h->pred16x16[DC_PRED8x8 ] = ff_pred16x16_dc_8_mmxext; + if (chroma_format_idc <= 1) + h->pred8x8[HOR_PRED8x8 ] = ff_pred8x8_horizontal_8_mmxext; + h->pred8x8l [TOP_DC_PRED ] = ff_pred8x8l_top_dc_8_mmxext; + h->pred8x8l [DC_PRED ] = ff_pred8x8l_dc_8_mmxext; + h->pred8x8l [HOR_PRED ] = ff_pred8x8l_horizontal_8_mmxext; + h->pred8x8l [VERT_PRED ] = ff_pred8x8l_vertical_8_mmxext; + h->pred8x8l [DIAG_DOWN_RIGHT_PRED ] = ff_pred8x8l_down_right_8_mmxext; + h->pred8x8l [VERT_RIGHT_PRED ] = ff_pred8x8l_vertical_right_8_mmxext; + h->pred8x8l [HOR_UP_PRED ] = ff_pred8x8l_horizontal_up_8_mmxext; + h->pred8x8l [DIAG_DOWN_LEFT_PRED ] = ff_pred8x8l_down_left_8_mmxext; + h->pred8x8l [HOR_DOWN_PRED ] = ff_pred8x8l_horizontal_down_8_mmxext; + h->pred4x4 [DIAG_DOWN_RIGHT_PRED ] = ff_pred4x4_down_right_8_mmxext; + h->pred4x4 [VERT_RIGHT_PRED ] = ff_pred4x4_vertical_right_8_mmxext; + h->pred4x4 [HOR_DOWN_PRED ] = ff_pred4x4_horizontal_down_8_mmxext; + h->pred4x4 [DC_PRED ] = ff_pred4x4_dc_8_mmxext; + if (codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8 || + codec_id == AV_CODEC_ID_H264) { + h->pred4x4 [DIAG_DOWN_LEFT_PRED] = ff_pred4x4_down_left_8_mmxext; + } + if (codec_id == AV_CODEC_ID_SVQ3 || codec_id == AV_CODEC_ID_H264) { + h->pred4x4 [VERT_LEFT_PRED ] = ff_pred4x4_vertical_left_8_mmxext; + } + if (codec_id != AV_CODEC_ID_RV40) { + h->pred4x4 [HOR_UP_PRED ] = ff_pred4x4_horizontal_up_8_mmxext; + } + if (codec_id == AV_CODEC_ID_SVQ3 || codec_id == AV_CODEC_ID_H264) { + if (chroma_format_idc <= 1) { + h->pred8x8[TOP_DC_PRED8x8 ] = ff_pred8x8_top_dc_8_mmxext; + h->pred8x8[DC_PRED8x8 ] = ff_pred8x8_dc_8_mmxext; + } + } + if (codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { + h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_tm_vp8_8_mmxext; + h->pred8x8 [DC_PRED8x8 ] = ff_pred8x8_dc_rv40_8_mmxext; + h->pred8x8 [PLANE_PRED8x8 ] = ff_pred8x8_tm_vp8_8_mmxext; + h->pred4x4 [TM_VP8_PRED ] = ff_pred4x4_tm_vp8_8_mmxext; + h->pred4x4 [VERT_PRED ] = ff_pred4x4_vertical_vp8_8_mmxext; + } else { + if (chroma_format_idc <= 1) + h->pred8x8 [PLANE_PRED8x8] = ff_pred8x8_plane_8_mmxext; + if (codec_id == AV_CODEC_ID_SVQ3) { + h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_plane_svq3_8_mmxext; + } else if (codec_id == AV_CODEC_ID_RV40) { + h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_plane_rv40_8_mmxext; + } else { + h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_plane_h264_8_mmxext; + } + } + } + + if (EXTERNAL_SSE(cpu_flags)) { + h->pred16x16[VERT_PRED8x8] = ff_pred16x16_vertical_8_sse; + } + + if (EXTERNAL_SSE2(cpu_flags)) { + h->pred16x16[DC_PRED8x8 ] = ff_pred16x16_dc_8_sse2; + h->pred8x8l [DIAG_DOWN_LEFT_PRED ] = ff_pred8x8l_down_left_8_sse2; + h->pred8x8l [DIAG_DOWN_RIGHT_PRED ] = ff_pred8x8l_down_right_8_sse2; + h->pred8x8l [VERT_RIGHT_PRED ] = ff_pred8x8l_vertical_right_8_sse2; + h->pred8x8l [VERT_LEFT_PRED ] = ff_pred8x8l_vertical_left_8_sse2; + h->pred8x8l [HOR_DOWN_PRED ] = ff_pred8x8l_horizontal_down_8_sse2; + if (codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { + h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_tm_vp8_8_sse2; + h->pred8x8 [PLANE_PRED8x8 ] = ff_pred8x8_tm_vp8_8_sse2; + } else { + if (chroma_format_idc <= 1) + h->pred8x8 [PLANE_PRED8x8] = ff_pred8x8_plane_8_sse2; + if (codec_id == AV_CODEC_ID_SVQ3) { + h->pred16x16[PLANE_PRED8x8] = ff_pred16x16_plane_svq3_8_sse2; + } else if (codec_id == AV_CODEC_ID_RV40) { + h->pred16x16[PLANE_PRED8x8] = ff_pred16x16_plane_rv40_8_sse2; + } else { + h->pred16x16[PLANE_PRED8x8] = ff_pred16x16_plane_h264_8_sse2; + } + } + } + + if (EXTERNAL_SSSE3(cpu_flags)) { + h->pred16x16[HOR_PRED8x8 ] = ff_pred16x16_horizontal_8_ssse3; + h->pred16x16[DC_PRED8x8 ] = ff_pred16x16_dc_8_ssse3; + if (chroma_format_idc <= 1) + h->pred8x8 [HOR_PRED8x8 ] = ff_pred8x8_horizontal_8_ssse3; + h->pred8x8l [TOP_DC_PRED ] = ff_pred8x8l_top_dc_8_ssse3; + h->pred8x8l [DC_PRED ] = ff_pred8x8l_dc_8_ssse3; + h->pred8x8l [HOR_PRED ] = ff_pred8x8l_horizontal_8_ssse3; + h->pred8x8l [VERT_PRED ] = ff_pred8x8l_vertical_8_ssse3; + h->pred8x8l [DIAG_DOWN_LEFT_PRED ] = ff_pred8x8l_down_left_8_ssse3; + h->pred8x8l [DIAG_DOWN_RIGHT_PRED ] = ff_pred8x8l_down_right_8_ssse3; + h->pred8x8l [VERT_RIGHT_PRED ] = ff_pred8x8l_vertical_right_8_ssse3; + h->pred8x8l [VERT_LEFT_PRED ] = ff_pred8x8l_vertical_left_8_ssse3; + h->pred8x8l [HOR_UP_PRED ] = ff_pred8x8l_horizontal_up_8_ssse3; + h->pred8x8l [HOR_DOWN_PRED ] = ff_pred8x8l_horizontal_down_8_ssse3; + if (codec_id == AV_CODEC_ID_VP7 || codec_id == AV_CODEC_ID_VP8) { + h->pred8x8 [PLANE_PRED8x8 ] = ff_pred8x8_tm_vp8_8_ssse3; + h->pred4x4 [TM_VP8_PRED ] = ff_pred4x4_tm_vp8_8_ssse3; + } else { + if (chroma_format_idc <= 1) + h->pred8x8 [PLANE_PRED8x8] = ff_pred8x8_plane_8_ssse3; + if (codec_id == AV_CODEC_ID_SVQ3) { + h->pred16x16[PLANE_PRED8x8] = ff_pred16x16_plane_svq3_8_ssse3; + } else if (codec_id == AV_CODEC_ID_RV40) { + h->pred16x16[PLANE_PRED8x8] = ff_pred16x16_plane_rv40_8_ssse3; + } else { + h->pred16x16[PLANE_PRED8x8] = ff_pred16x16_plane_h264_8_ssse3; + } + } + } + + if(EXTERNAL_AVX2(cpu_flags)){ + if (codec_id == AV_CODEC_ID_VP8) { + h->pred16x16[PLANE_PRED8x8 ] = ff_pred16x16_tm_vp8_8_avx2; + } + } + } else if (bit_depth == 10) { + if (EXTERNAL_MMXEXT(cpu_flags)) { + h->pred4x4[DC_PRED ] = ff_pred4x4_dc_10_mmxext; + h->pred4x4[HOR_UP_PRED ] = ff_pred4x4_horizontal_up_10_mmxext; + + if (chroma_format_idc <= 1) + h->pred8x8[DC_PRED8x8 ] = ff_pred8x8_dc_10_mmxext; + + h->pred8x8l[DC_128_PRED ] = ff_pred8x8l_128_dc_10_mmxext; + + h->pred16x16[DC_PRED8x8 ] = ff_pred16x16_dc_10_mmxext; + h->pred16x16[TOP_DC_PRED8x8 ] = ff_pred16x16_top_dc_10_mmxext; + h->pred16x16[DC_128_PRED8x8 ] = ff_pred16x16_128_dc_10_mmxext; + h->pred16x16[LEFT_DC_PRED8x8 ] = ff_pred16x16_left_dc_10_mmxext; + h->pred16x16[VERT_PRED8x8 ] = ff_pred16x16_vertical_10_mmxext; + h->pred16x16[HOR_PRED8x8 ] = ff_pred16x16_horizontal_10_mmxext; + } + if (EXTERNAL_SSE2(cpu_flags)) { + h->pred4x4[DIAG_DOWN_LEFT_PRED ] = ff_pred4x4_down_left_10_sse2; + h->pred4x4[DIAG_DOWN_RIGHT_PRED] = ff_pred4x4_down_right_10_sse2; + h->pred4x4[VERT_LEFT_PRED ] = ff_pred4x4_vertical_left_10_sse2; + h->pred4x4[VERT_RIGHT_PRED ] = ff_pred4x4_vertical_right_10_sse2; + h->pred4x4[HOR_DOWN_PRED ] = ff_pred4x4_horizontal_down_10_sse2; + + if (chroma_format_idc <= 1) { + h->pred8x8[DC_PRED8x8 ] = ff_pred8x8_dc_10_sse2; + h->pred8x8[TOP_DC_PRED8x8 ] = ff_pred8x8_top_dc_10_sse2; + h->pred8x8[PLANE_PRED8x8 ] = ff_pred8x8_plane_10_sse2; + h->pred8x8[VERT_PRED8x8 ] = ff_pred8x8_vertical_10_sse2; + h->pred8x8[HOR_PRED8x8 ] = ff_pred8x8_horizontal_10_sse2; + } + + h->pred8x8l[VERT_PRED ] = ff_pred8x8l_vertical_10_sse2; + h->pred8x8l[HOR_PRED ] = ff_pred8x8l_horizontal_10_sse2; + h->pred8x8l[DC_PRED ] = ff_pred8x8l_dc_10_sse2; + h->pred8x8l[DC_128_PRED ] = ff_pred8x8l_128_dc_10_sse2; + h->pred8x8l[TOP_DC_PRED ] = ff_pred8x8l_top_dc_10_sse2; + h->pred8x8l[DIAG_DOWN_LEFT_PRED ] = ff_pred8x8l_down_left_10_sse2; + h->pred8x8l[DIAG_DOWN_RIGHT_PRED] = ff_pred8x8l_down_right_10_sse2; + h->pred8x8l[VERT_RIGHT_PRED ] = ff_pred8x8l_vertical_right_10_sse2; + h->pred8x8l[HOR_UP_PRED ] = ff_pred8x8l_horizontal_up_10_sse2; + + h->pred16x16[DC_PRED8x8 ] = ff_pred16x16_dc_10_sse2; + h->pred16x16[TOP_DC_PRED8x8 ] = ff_pred16x16_top_dc_10_sse2; + h->pred16x16[DC_128_PRED8x8 ] = ff_pred16x16_128_dc_10_sse2; + h->pred16x16[LEFT_DC_PRED8x8 ] = ff_pred16x16_left_dc_10_sse2; + h->pred16x16[VERT_PRED8x8 ] = ff_pred16x16_vertical_10_sse2; + h->pred16x16[HOR_PRED8x8 ] = ff_pred16x16_horizontal_10_sse2; + } + if (EXTERNAL_SSSE3(cpu_flags)) { + h->pred4x4[DIAG_DOWN_RIGHT_PRED] = ff_pred4x4_down_right_10_ssse3; + h->pred4x4[VERT_RIGHT_PRED ] = ff_pred4x4_vertical_right_10_ssse3; + h->pred4x4[HOR_DOWN_PRED ] = ff_pred4x4_horizontal_down_10_ssse3; + + h->pred8x8l[HOR_PRED ] = ff_pred8x8l_horizontal_10_ssse3; + h->pred8x8l[DIAG_DOWN_LEFT_PRED ] = ff_pred8x8l_down_left_10_ssse3; + h->pred8x8l[DIAG_DOWN_RIGHT_PRED] = ff_pred8x8l_down_right_10_ssse3; + h->pred8x8l[VERT_RIGHT_PRED ] = ff_pred8x8l_vertical_right_10_ssse3; + h->pred8x8l[HOR_UP_PRED ] = ff_pred8x8l_horizontal_up_10_ssse3; + } + if (EXTERNAL_AVX(cpu_flags)) { + h->pred4x4[DIAG_DOWN_LEFT_PRED ] = ff_pred4x4_down_left_10_avx; + h->pred4x4[DIAG_DOWN_RIGHT_PRED] = ff_pred4x4_down_right_10_avx; + h->pred4x4[VERT_LEFT_PRED ] = ff_pred4x4_vertical_left_10_avx; + h->pred4x4[VERT_RIGHT_PRED ] = ff_pred4x4_vertical_right_10_avx; + h->pred4x4[HOR_DOWN_PRED ] = ff_pred4x4_horizontal_down_10_avx; + + h->pred8x8l[VERT_PRED ] = ff_pred8x8l_vertical_10_avx; + h->pred8x8l[HOR_PRED ] = ff_pred8x8l_horizontal_10_avx; + h->pred8x8l[DC_PRED ] = ff_pred8x8l_dc_10_avx; + h->pred8x8l[TOP_DC_PRED ] = ff_pred8x8l_top_dc_10_avx; + h->pred8x8l[DIAG_DOWN_RIGHT_PRED] = ff_pred8x8l_down_right_10_avx; + h->pred8x8l[DIAG_DOWN_LEFT_PRED ] = ff_pred8x8l_down_left_10_avx; + h->pred8x8l[VERT_RIGHT_PRED ] = ff_pred8x8l_vertical_right_10_avx; + h->pred8x8l[HOR_UP_PRED ] = ff_pred8x8l_horizontal_up_10_avx; + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_qpel.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_qpel.c new file mode 100644 index 0000000000..0d3dbbadb0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264_qpel.c @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2004-2005 Michael Niedermayer, Loren Merritt + * Copyright (c) 2011 Daniel Kang + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/h264dec.h" +#include "libavcodec/h264qpel.h" +#include "libavcodec/pixels.h" +#include "fpel.h" + +#if HAVE_X86ASM +void ff_put_pixels4_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_avg_pixels4_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_put_pixels8_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_avg_pixels8_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_put_pixels16_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_avg_pixels16_l2_mmxext(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +#define ff_put_pixels8_l2_sse2 ff_put_pixels8_l2_mmxext +#define ff_avg_pixels8_l2_sse2 ff_avg_pixels8_l2_mmxext +#define ff_put_pixels16_l2_sse2 ff_put_pixels16_l2_mmxext +#define ff_avg_pixels16_l2_sse2 ff_avg_pixels16_l2_mmxext +#define ff_put_pixels16_mmxext ff_put_pixels16_mmx +#define ff_put_pixels8_mmxext ff_put_pixels8_mmx +#define ff_put_pixels4_mmxext ff_put_pixels4_mmx + +#define DEF_QPEL(OPNAME)\ +void ff_ ## OPNAME ## _h264_qpel4_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride);\ +void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride);\ +void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_ssse3(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride);\ +void ff_ ## OPNAME ## _h264_qpel4_h_lowpass_l2_mmxext(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride);\ +void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_l2_mmxext(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride);\ +void ff_ ## OPNAME ## _h264_qpel8_h_lowpass_l2_ssse3(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride);\ +void ff_ ## OPNAME ## _h264_qpel4_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride);\ +void ff_ ## OPNAME ## _h264_qpel8or16_v_lowpass_op_mmxext(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h);\ +void ff_ ## OPNAME ## _h264_qpel8or16_v_lowpass_sse2(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h);\ +void ff_ ## OPNAME ## _h264_qpel4_hv_lowpass_v_mmxext(const uint8_t *src, int16_t *tmp, int srcStride);\ +void ff_ ## OPNAME ## _h264_qpel4_hv_lowpass_h_mmxext(int16_t *tmp, uint8_t *dst, int dstStride);\ +void ff_ ## OPNAME ## _h264_qpel8or16_hv1_lowpass_op_mmxext(const uint8_t *src, int16_t *tmp, int srcStride, int size);\ +void ff_ ## OPNAME ## _h264_qpel8or16_hv1_lowpass_op_sse2(const uint8_t *src, int16_t *tmp, int srcStride, int size);\ +void ff_ ## OPNAME ## _h264_qpel8or16_hv2_lowpass_op_mmxext(uint8_t *dst, int16_t *tmp, int dstStride, int unused, int h);\ +void ff_ ## OPNAME ## _h264_qpel8or16_hv2_lowpass_ssse3(uint8_t *dst, int16_t *tmp, int dstStride, int tmpStride, int size);\ +void ff_ ## OPNAME ## _pixels4_l2_shift5_mmxext(uint8_t *dst, const int16_t *src16, const uint8_t *src8, int dstStride, int src8Stride, int h);\ +void ff_ ## OPNAME ## _pixels8_l2_shift5_mmxext(uint8_t *dst, const int16_t *src16, const uint8_t *src8, int dstStride, int src8Stride, int h); + +DEF_QPEL(avg) +DEF_QPEL(put) + +static av_always_inline void ff_put_h264_qpel8or16_hv1_lowpass_mmxext(int16_t *tmp, const uint8_t *src, int tmpStride, int srcStride, int size) +{ + int w = (size + 8) >> 2; + src -= 2 * srcStride + 2; + while (w--) { + ff_put_h264_qpel8or16_hv1_lowpass_op_mmxext(src, tmp, srcStride, size); + tmp += 4; + src += 4; + } +} + +#define QPEL_H264(OPNAME, OP, MMX)\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel4_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride){\ + int w=3;\ + src -= 2*srcStride+2;\ + while(w--){\ + ff_ ## OPNAME ## h264_qpel4_hv_lowpass_v_mmxext(src, tmp, srcStride);\ + tmp += 4;\ + src += 4;\ + }\ + tmp -= 3*4;\ + ff_ ## OPNAME ## h264_qpel4_hv_lowpass_h_mmxext(tmp, dst, dstStride);\ +}\ +\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride, int h){\ + src -= 2*srcStride;\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_op_mmxext(dst, src, dstStride, srcStride, h);\ + src += 4;\ + dst += 4;\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_op_mmxext(dst, src, dstStride, srcStride, h);\ +}\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel8or16_hv2_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, int dstStride, int tmpStride, int size){\ + int w = size>>4;\ + do{\ + ff_ ## OPNAME ## h264_qpel8or16_hv2_lowpass_op_mmxext(dst, tmp, dstStride, 0, size);\ + tmp += 8;\ + dst += 8;\ + }while(w--);\ +}\ +\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel8_v_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride){\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## MMX(dst , src , dstStride, srcStride, 8);\ +}\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_v_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride){\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## MMX(dst , src , dstStride, srcStride, 16);\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\ +}\ +\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride){\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst , src , dstStride, srcStride);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride);\ + src += 8*srcStride;\ + dst += 8*dstStride;\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst , src , dstStride, srcStride);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride);\ +}\ +\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_l2_ ## MMX(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride){\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst , src , src2 , dstStride, src2Stride);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst+8, src+8, src2+8, dstStride, src2Stride);\ + src += 8*dstStride;\ + dst += 8*dstStride;\ + src2 += 8*src2Stride;\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst , src , src2 , dstStride, src2Stride);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst+8, src+8, src2+8, dstStride, src2Stride);\ +}\ +\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel8or16_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride, int size){\ + ff_put_h264_qpel8or16_hv1_lowpass_ ## MMX(tmp, src, tmpStride, srcStride, size);\ + ff_ ## OPNAME ## h264_qpel8or16_hv2_lowpass_ ## MMX(dst, tmp, dstStride, tmpStride, size);\ +}\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel8_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride){\ + ff_ ## OPNAME ## h264_qpel8or16_hv_lowpass_ ## MMX(dst , tmp , src , dstStride, tmpStride, srcStride, 8);\ +}\ +\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride){\ + ff_ ## OPNAME ## h264_qpel8or16_hv_lowpass_ ## MMX(dst , tmp , src , dstStride, tmpStride, srcStride, 16);\ +}\ +\ +static av_always_inline void ff_ ## OPNAME ## pixels16_l2_shift5_ ## MMX(uint8_t *dst, const int16_t *src16, const uint8_t *src8, int dstStride, int src8Stride, int h)\ +{\ + ff_ ## OPNAME ## pixels8_l2_shift5_ ## MMX(dst , src16 , src8 , dstStride, src8Stride, h);\ + ff_ ## OPNAME ## pixels8_l2_shift5_ ## MMX(dst+8, src16+8, src8+8, dstStride, src8Stride, h);\ +}\ + + +#if ARCH_X86_64 +#define QPEL_H264_H16_XMM(OPNAME, OP, MMX)\ + +void ff_avg_h264_qpel16_h_lowpass_l2_ssse3(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride); +void ff_put_h264_qpel16_h_lowpass_l2_ssse3(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride); + +#else // ARCH_X86_64 +#define QPEL_H264_H16_XMM(OPNAME, OP, MMX)\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_l2_ ## MMX(uint8_t *dst, const uint8_t *src, const uint8_t *src2, int dstStride, int src2Stride){\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst , src , src2 , dstStride, src2Stride);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst+8, src+8, src2+8, dstStride, src2Stride);\ + src += 8*dstStride;\ + dst += 8*dstStride;\ + src2 += 8*src2Stride;\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst , src , src2 , dstStride, src2Stride);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_l2_ ## MMX(dst+8, src+8, src2+8, dstStride, src2Stride);\ +} +#endif // ARCH_X86_64 + +#define QPEL_H264_H_XMM(OPNAME, OP, MMX)\ +QPEL_H264_H16_XMM(OPNAME, OP, MMX)\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_h_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride){\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst , src , dstStride, srcStride);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride);\ + src += 8*srcStride;\ + dst += 8*dstStride;\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst , src , dstStride, srcStride);\ + ff_ ## OPNAME ## h264_qpel8_h_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride);\ +}\ + +#define QPEL_H264_V_XMM(OPNAME, OP, MMX)\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel8_v_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride){\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## MMX(dst , src , dstStride, srcStride, 8);\ +}\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_v_lowpass_ ## MMX(uint8_t *dst, const uint8_t *src, int dstStride, int srcStride){\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## MMX(dst , src , dstStride, srcStride, 16);\ + ff_ ## OPNAME ## h264_qpel8or16_v_lowpass_ ## MMX(dst+8, src+8, dstStride, srcStride, 16);\ +} + +static av_always_inline void put_h264_qpel8or16_hv1_lowpass_sse2(int16_t *tmp, + const uint8_t *src, + int tmpStride, + int srcStride, + int size) +{ + int w = (size+8)>>3; + src -= 2*srcStride+2; + while(w--){ + ff_put_h264_qpel8or16_hv1_lowpass_op_sse2(src, tmp, srcStride, size); + tmp += 8; + src += 8; + } +} + +#define QPEL_H264_HV_XMM(OPNAME, OP, MMX)\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel8or16_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride, int size){\ + put_h264_qpel8or16_hv1_lowpass_sse2(tmp, src, tmpStride, srcStride, size);\ + ff_ ## OPNAME ## h264_qpel8or16_hv2_lowpass_ ## MMX(dst, tmp, dstStride, tmpStride, size);\ +}\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel8_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride){\ + ff_ ## OPNAME ## h264_qpel8or16_hv_lowpass_ ## MMX(dst, tmp, src, dstStride, tmpStride, srcStride, 8);\ +}\ +static av_always_inline void ff_ ## OPNAME ## h264_qpel16_hv_lowpass_ ## MMX(uint8_t *dst, int16_t *tmp, const uint8_t *src, int dstStride, int tmpStride, int srcStride){\ + ff_ ## OPNAME ## h264_qpel8or16_hv_lowpass_ ## MMX(dst, tmp, src, dstStride, tmpStride, srcStride, 16);\ +}\ + +#define ff_put_h264_qpel8_h_lowpass_l2_sse2 ff_put_h264_qpel8_h_lowpass_l2_mmxext +#define ff_avg_h264_qpel8_h_lowpass_l2_sse2 ff_avg_h264_qpel8_h_lowpass_l2_mmxext +#define ff_put_h264_qpel16_h_lowpass_l2_sse2 ff_put_h264_qpel16_h_lowpass_l2_mmxext +#define ff_avg_h264_qpel16_h_lowpass_l2_sse2 ff_avg_h264_qpel16_h_lowpass_l2_mmxext + +#define ff_put_h264_qpel8_v_lowpass_ssse3 ff_put_h264_qpel8_v_lowpass_sse2 +#define ff_avg_h264_qpel8_v_lowpass_ssse3 ff_avg_h264_qpel8_v_lowpass_sse2 +#define ff_put_h264_qpel16_v_lowpass_ssse3 ff_put_h264_qpel16_v_lowpass_sse2 +#define ff_avg_h264_qpel16_v_lowpass_ssse3 ff_avg_h264_qpel16_v_lowpass_sse2 + +#define ff_put_h264_qpel8or16_hv2_lowpass_sse2 ff_put_h264_qpel8or16_hv2_lowpass_mmxext +#define ff_avg_h264_qpel8or16_hv2_lowpass_sse2 ff_avg_h264_qpel8or16_hv2_lowpass_mmxext + +#define H264_MC(OPNAME, SIZE, MMX, ALIGN) \ +H264_MC_C(OPNAME, SIZE, MMX, ALIGN)\ +H264_MC_V(OPNAME, SIZE, MMX, ALIGN)\ +H264_MC_H(OPNAME, SIZE, MMX, ALIGN)\ +H264_MC_HV(OPNAME, SIZE, MMX, ALIGN)\ + +static void put_h264_qpel16_mc00_sse2 (uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + ff_put_pixels16_sse2(dst, src, stride, 16); +} +static void avg_h264_qpel16_mc00_sse2 (uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + ff_avg_pixels16_sse2(dst, src, stride, 16); +} +#define put_h264_qpel8_mc00_sse2 put_h264_qpel8_mc00_mmxext +#define avg_h264_qpel8_mc00_sse2 avg_h264_qpel8_mc00_mmxext + +#define H264_MC_C(OPNAME, SIZE, MMX, ALIGN) \ +static void OPNAME ## h264_qpel ## SIZE ## _mc00_ ## MMX (uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + ff_ ## OPNAME ## pixels ## SIZE ## _ ## MMX(dst, src, stride, SIZE);\ +}\ + +#define H264_MC_H(OPNAME, SIZE, MMX, ALIGN) \ +static void OPNAME ## h264_qpel ## SIZE ## _mc10_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, src, stride, stride);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc20_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_ ## MMX(dst, src, stride, stride);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc30_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, src+1, stride, stride);\ +}\ + +#define H264_MC_V(OPNAME, SIZE, MMX, ALIGN) \ +static void OPNAME ## h264_qpel ## SIZE ## _mc01_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\ + ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src, SIZE, stride);\ + ff_ ## OPNAME ## pixels ## SIZE ## _l2_ ## MMX(dst, src, temp, stride, stride, SIZE);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc02_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _v_lowpass_ ## MMX(dst, src, stride, stride);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc03_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\ + ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src, SIZE, stride);\ + ff_ ## OPNAME ## pixels ## SIZE ## _l2_ ## MMX(dst, src+stride, temp, stride, stride, SIZE);\ +}\ + +#define H264_MC_HV(OPNAME, SIZE, MMX, ALIGN) \ +static void OPNAME ## h264_qpel ## SIZE ## _mc11_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\ + ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src, SIZE, stride);\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, temp, stride, SIZE);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc31_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\ + ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src+1, SIZE, stride);\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, temp, stride, SIZE);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc13_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\ + ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src, SIZE, stride);\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src+stride, temp, stride, SIZE);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc33_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*SIZE]);\ + ff_put_h264_qpel ## SIZE ## _v_lowpass_ ## MMX(temp, src+1, SIZE, stride);\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src+stride, temp, stride, SIZE);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc22_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint16_t, temp, [SIZE*(SIZE<8?12:24)]);\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(dst, temp, src, stride, SIZE, stride);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc21_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE]);\ + uint8_t * const halfHV= temp;\ + int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\ + av_assert2(((int)temp & 7) == 0);\ + ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src, halfHV, stride, SIZE);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc23_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE]);\ + uint8_t * const halfHV= temp;\ + int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\ + av_assert2(((int)temp & 7) == 0);\ + ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\ + ff_ ## OPNAME ## h264_qpel ## SIZE ## _h_lowpass_l2_ ## MMX(dst, src+stride, halfHV, stride, SIZE);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc12_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE]);\ + uint8_t * const halfHV= temp;\ + int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\ + av_assert2(((int)temp & 7) == 0);\ + ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\ + ff_ ## OPNAME ## pixels ## SIZE ## _l2_shift5_mmxext(dst, halfV+2, halfHV, stride, SIZE, SIZE);\ +}\ +\ +static void OPNAME ## h264_qpel ## SIZE ## _mc32_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride)\ +{\ + LOCAL_ALIGNED(ALIGN, uint8_t, temp, [SIZE*(SIZE<8?12:24)*2 + SIZE*SIZE]);\ + uint8_t * const halfHV= temp;\ + int16_t * const halfV= (int16_t*)(temp + SIZE*SIZE);\ + av_assert2(((int)temp & 7) == 0);\ + ff_put_h264_qpel ## SIZE ## _hv_lowpass_ ## MMX(halfHV, halfV, src, SIZE, SIZE, stride);\ + ff_ ## OPNAME ## pixels ## SIZE ## _l2_shift5_mmxext(dst, halfV+3, halfHV, stride, SIZE, SIZE);\ +}\ + +#define H264_MC_4816(MMX)\ +H264_MC(put_, 4, MMX, 8)\ +H264_MC(put_, 8, MMX, 8)\ +H264_MC(put_, 16,MMX, 8)\ +H264_MC(avg_, 4, MMX, 8)\ +H264_MC(avg_, 8, MMX, 8)\ +H264_MC(avg_, 16,MMX, 8)\ + +#define H264_MC_816(QPEL, XMM)\ +QPEL(put_, 8, XMM, 16)\ +QPEL(put_, 16,XMM, 16)\ +QPEL(avg_, 8, XMM, 16)\ +QPEL(avg_, 16,XMM, 16)\ + +QPEL_H264(put_, PUT_OP, mmxext) +QPEL_H264(avg_, AVG_MMXEXT_OP, mmxext) +QPEL_H264_V_XMM(put_, PUT_OP, sse2) +QPEL_H264_V_XMM(avg_,AVG_MMXEXT_OP, sse2) +QPEL_H264_HV_XMM(put_, PUT_OP, sse2) +QPEL_H264_HV_XMM(avg_,AVG_MMXEXT_OP, sse2) +QPEL_H264_H_XMM(put_, PUT_OP, ssse3) +QPEL_H264_H_XMM(avg_,AVG_MMXEXT_OP, ssse3) +QPEL_H264_HV_XMM(put_, PUT_OP, ssse3) +QPEL_H264_HV_XMM(avg_,AVG_MMXEXT_OP, ssse3) + +H264_MC_4816(mmxext) +H264_MC_816(H264_MC_V, sse2) +H264_MC_816(H264_MC_HV, sse2) +H264_MC_816(H264_MC_H, ssse3) +H264_MC_816(H264_MC_HV, ssse3) + + +//10bit +#define LUMA_MC_OP(OP, NUM, DEPTH, TYPE, OPT) \ +void ff_ ## OP ## _h264_qpel ## NUM ## _ ## TYPE ## _ ## DEPTH ## _ ## OPT \ + (uint8_t *dst, const uint8_t *src, ptrdiff_t stride); + +#define LUMA_MC_ALL(DEPTH, TYPE, OPT) \ + LUMA_MC_OP(put, 4, DEPTH, TYPE, OPT) \ + LUMA_MC_OP(avg, 4, DEPTH, TYPE, OPT) \ + LUMA_MC_OP(put, 8, DEPTH, TYPE, OPT) \ + LUMA_MC_OP(avg, 8, DEPTH, TYPE, OPT) \ + LUMA_MC_OP(put, 16, DEPTH, TYPE, OPT) \ + LUMA_MC_OP(avg, 16, DEPTH, TYPE, OPT) + +#define LUMA_MC_816(DEPTH, TYPE, OPT) \ + LUMA_MC_OP(put, 8, DEPTH, TYPE, OPT) \ + LUMA_MC_OP(avg, 8, DEPTH, TYPE, OPT) \ + LUMA_MC_OP(put, 16, DEPTH, TYPE, OPT) \ + LUMA_MC_OP(avg, 16, DEPTH, TYPE, OPT) + +LUMA_MC_ALL(10, mc00, mmxext) +LUMA_MC_ALL(10, mc10, mmxext) +LUMA_MC_ALL(10, mc20, mmxext) +LUMA_MC_ALL(10, mc30, mmxext) +LUMA_MC_ALL(10, mc01, mmxext) +LUMA_MC_ALL(10, mc11, mmxext) +LUMA_MC_ALL(10, mc21, mmxext) +LUMA_MC_ALL(10, mc31, mmxext) +LUMA_MC_ALL(10, mc02, mmxext) +LUMA_MC_ALL(10, mc12, mmxext) +LUMA_MC_ALL(10, mc22, mmxext) +LUMA_MC_ALL(10, mc32, mmxext) +LUMA_MC_ALL(10, mc03, mmxext) +LUMA_MC_ALL(10, mc13, mmxext) +LUMA_MC_ALL(10, mc23, mmxext) +LUMA_MC_ALL(10, mc33, mmxext) + +LUMA_MC_816(10, mc00, sse2) +LUMA_MC_816(10, mc10, sse2) +LUMA_MC_816(10, mc10, sse2_cache64) +LUMA_MC_816(10, mc10, ssse3_cache64) +LUMA_MC_816(10, mc20, sse2) +LUMA_MC_816(10, mc20, sse2_cache64) +LUMA_MC_816(10, mc20, ssse3_cache64) +LUMA_MC_816(10, mc30, sse2) +LUMA_MC_816(10, mc30, sse2_cache64) +LUMA_MC_816(10, mc30, ssse3_cache64) +LUMA_MC_816(10, mc01, sse2) +LUMA_MC_816(10, mc11, sse2) +LUMA_MC_816(10, mc21, sse2) +LUMA_MC_816(10, mc31, sse2) +LUMA_MC_816(10, mc02, sse2) +LUMA_MC_816(10, mc12, sse2) +LUMA_MC_816(10, mc22, sse2) +LUMA_MC_816(10, mc32, sse2) +LUMA_MC_816(10, mc03, sse2) +LUMA_MC_816(10, mc13, sse2) +LUMA_MC_816(10, mc23, sse2) +LUMA_MC_816(10, mc33, sse2) + +#define QPEL16_OPMC(OP, MC, MMX)\ +void ff_ ## OP ## _h264_qpel16_ ## MC ## _10_ ## MMX(uint8_t *dst, const uint8_t *src, ptrdiff_t stride){\ + ff_ ## OP ## _h264_qpel8_ ## MC ## _10_ ## MMX(dst , src , stride);\ + ff_ ## OP ## _h264_qpel8_ ## MC ## _10_ ## MMX(dst+16, src+16, stride);\ + src += 8*stride;\ + dst += 8*stride;\ + ff_ ## OP ## _h264_qpel8_ ## MC ## _10_ ## MMX(dst , src , stride);\ + ff_ ## OP ## _h264_qpel8_ ## MC ## _10_ ## MMX(dst+16, src+16, stride);\ +} + +#define QPEL16_OP(MC, MMX)\ +QPEL16_OPMC(put, MC, MMX)\ +QPEL16_OPMC(avg, MC, MMX) + +#define QPEL16(MMX)\ +QPEL16_OP(mc00, MMX)\ +QPEL16_OP(mc01, MMX)\ +QPEL16_OP(mc02, MMX)\ +QPEL16_OP(mc03, MMX)\ +QPEL16_OP(mc10, MMX)\ +QPEL16_OP(mc11, MMX)\ +QPEL16_OP(mc12, MMX)\ +QPEL16_OP(mc13, MMX)\ +QPEL16_OP(mc20, MMX)\ +QPEL16_OP(mc21, MMX)\ +QPEL16_OP(mc22, MMX)\ +QPEL16_OP(mc23, MMX)\ +QPEL16_OP(mc30, MMX)\ +QPEL16_OP(mc31, MMX)\ +QPEL16_OP(mc32, MMX)\ +QPEL16_OP(mc33, MMX) + +#if ARCH_X86_32 // ARCH_X86_64 implies SSE2+ +QPEL16(mmxext) +#endif + +#endif /* HAVE_X86ASM */ + +#define SET_QPEL_FUNCS(PFX, IDX, SIZE, CPU, PREFIX) \ + do { \ + c->PFX ## _pixels_tab[IDX][ 0] = PREFIX ## PFX ## SIZE ## _mc00_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 1] = PREFIX ## PFX ## SIZE ## _mc10_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 2] = PREFIX ## PFX ## SIZE ## _mc20_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 3] = PREFIX ## PFX ## SIZE ## _mc30_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 4] = PREFIX ## PFX ## SIZE ## _mc01_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 5] = PREFIX ## PFX ## SIZE ## _mc11_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 6] = PREFIX ## PFX ## SIZE ## _mc21_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 7] = PREFIX ## PFX ## SIZE ## _mc31_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 8] = PREFIX ## PFX ## SIZE ## _mc02_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 9] = PREFIX ## PFX ## SIZE ## _mc12_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][10] = PREFIX ## PFX ## SIZE ## _mc22_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][11] = PREFIX ## PFX ## SIZE ## _mc32_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][12] = PREFIX ## PFX ## SIZE ## _mc03_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][13] = PREFIX ## PFX ## SIZE ## _mc13_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][14] = PREFIX ## PFX ## SIZE ## _mc23_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][15] = PREFIX ## PFX ## SIZE ## _mc33_ ## CPU; \ + } while (0) + +#define H264_QPEL_FUNCS(x, y, CPU) \ + do { \ + c->put_h264_qpel_pixels_tab[0][x + y * 4] = put_h264_qpel16_mc ## x ## y ## _ ## CPU; \ + c->put_h264_qpel_pixels_tab[1][x + y * 4] = put_h264_qpel8_mc ## x ## y ## _ ## CPU; \ + c->avg_h264_qpel_pixels_tab[0][x + y * 4] = avg_h264_qpel16_mc ## x ## y ## _ ## CPU; \ + c->avg_h264_qpel_pixels_tab[1][x + y * 4] = avg_h264_qpel8_mc ## x ## y ## _ ## CPU; \ + } while (0) + +#define H264_QPEL_FUNCS_10(x, y, CPU) \ + do { \ + c->put_h264_qpel_pixels_tab[0][x + y * 4] = ff_put_h264_qpel16_mc ## x ## y ## _10_ ## CPU; \ + c->put_h264_qpel_pixels_tab[1][x + y * 4] = ff_put_h264_qpel8_mc ## x ## y ## _10_ ## CPU; \ + c->avg_h264_qpel_pixels_tab[0][x + y * 4] = ff_avg_h264_qpel16_mc ## x ## y ## _10_ ## CPU; \ + c->avg_h264_qpel_pixels_tab[1][x + y * 4] = ff_avg_h264_qpel8_mc ## x ## y ## _10_ ## CPU; \ + } while (0) + +av_cold void ff_h264qpel_init_x86(H264QpelContext *c, int bit_depth) +{ +#if HAVE_X86ASM + int high_bit_depth = bit_depth > 8; + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMXEXT(cpu_flags)) { + if (!high_bit_depth) { + SET_QPEL_FUNCS(put_h264_qpel, 0, 16, mmxext, ); + SET_QPEL_FUNCS(put_h264_qpel, 1, 8, mmxext, ); + SET_QPEL_FUNCS(put_h264_qpel, 2, 4, mmxext, ); + SET_QPEL_FUNCS(avg_h264_qpel, 0, 16, mmxext, ); + SET_QPEL_FUNCS(avg_h264_qpel, 1, 8, mmxext, ); + SET_QPEL_FUNCS(avg_h264_qpel, 2, 4, mmxext, ); + } else if (bit_depth == 10) { +#if ARCH_X86_32 + SET_QPEL_FUNCS(avg_h264_qpel, 0, 16, 10_mmxext, ff_); + SET_QPEL_FUNCS(put_h264_qpel, 0, 16, 10_mmxext, ff_); + SET_QPEL_FUNCS(put_h264_qpel, 1, 8, 10_mmxext, ff_); + SET_QPEL_FUNCS(avg_h264_qpel, 1, 8, 10_mmxext, ff_); +#endif + SET_QPEL_FUNCS(put_h264_qpel, 2, 4, 10_mmxext, ff_); + SET_QPEL_FUNCS(avg_h264_qpel, 2, 4, 10_mmxext, ff_); + } + } + + if (EXTERNAL_SSE2(cpu_flags)) { + if (!high_bit_depth) { + H264_QPEL_FUNCS(0, 1, sse2); + H264_QPEL_FUNCS(0, 2, sse2); + H264_QPEL_FUNCS(0, 3, sse2); + H264_QPEL_FUNCS(1, 1, sse2); + H264_QPEL_FUNCS(1, 2, sse2); + H264_QPEL_FUNCS(1, 3, sse2); + H264_QPEL_FUNCS(2, 1, sse2); + H264_QPEL_FUNCS(2, 2, sse2); + H264_QPEL_FUNCS(2, 3, sse2); + H264_QPEL_FUNCS(3, 1, sse2); + H264_QPEL_FUNCS(3, 2, sse2); + H264_QPEL_FUNCS(3, 3, sse2); + } + + if (bit_depth == 10) { + SET_QPEL_FUNCS(put_h264_qpel, 0, 16, 10_sse2, ff_); + SET_QPEL_FUNCS(put_h264_qpel, 1, 8, 10_sse2, ff_); + SET_QPEL_FUNCS(avg_h264_qpel, 0, 16, 10_sse2, ff_); + SET_QPEL_FUNCS(avg_h264_qpel, 1, 8, 10_sse2, ff_); + H264_QPEL_FUNCS_10(1, 0, sse2_cache64); + H264_QPEL_FUNCS_10(2, 0, sse2_cache64); + H264_QPEL_FUNCS_10(3, 0, sse2_cache64); + } + } + + if (EXTERNAL_SSE2_FAST(cpu_flags)) { + if (!high_bit_depth) { + H264_QPEL_FUNCS(0, 0, sse2); + } + } + + if (EXTERNAL_SSSE3(cpu_flags)) { + if (!high_bit_depth) { + H264_QPEL_FUNCS(1, 0, ssse3); + H264_QPEL_FUNCS(1, 1, ssse3); + H264_QPEL_FUNCS(1, 2, ssse3); + H264_QPEL_FUNCS(1, 3, ssse3); + H264_QPEL_FUNCS(2, 0, ssse3); + H264_QPEL_FUNCS(2, 1, ssse3); + H264_QPEL_FUNCS(2, 2, ssse3); + H264_QPEL_FUNCS(2, 3, ssse3); + H264_QPEL_FUNCS(3, 0, ssse3); + H264_QPEL_FUNCS(3, 1, ssse3); + H264_QPEL_FUNCS(3, 2, ssse3); + H264_QPEL_FUNCS(3, 3, ssse3); + } + + if (bit_depth == 10) { + H264_QPEL_FUNCS_10(1, 0, ssse3_cache64); + H264_QPEL_FUNCS_10(2, 0, ssse3_cache64); + H264_QPEL_FUNCS_10(3, 0, ssse3_cache64); + } + } + + if (EXTERNAL_AVX(cpu_flags)) { + /* AVX implies 64 byte cache lines without the need to avoid unaligned + * memory accesses that cross the boundary between two cache lines. + * TODO: Port X264_CPU_CACHELINE_32/64 detection from x264 to avoid + * having to treat SSE2 functions with such properties as AVX. */ + if (bit_depth == 10) { + H264_QPEL_FUNCS_10(1, 0, sse2); + H264_QPEL_FUNCS_10(2, 0, sse2); + H264_QPEL_FUNCS_10(3, 0, sse2); + } + } +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264chroma_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264chroma_init.c new file mode 100644 index 0000000000..36bf29df02 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264chroma_init.c @@ -0,0 +1,117 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/h264chroma.h" + +void ff_put_h264_chroma_mc8_rnd_mmx (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_h264_chroma_mc8_rnd_mmxext(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_h264_chroma_mc8_rnd_3dnow(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); + +void ff_put_h264_chroma_mc4_mmx (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_h264_chroma_mc4_mmxext (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_h264_chroma_mc4_3dnow (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); + +void ff_put_h264_chroma_mc2_mmxext (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_h264_chroma_mc2_mmxext (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); + +void ff_put_h264_chroma_mc8_rnd_ssse3(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_put_h264_chroma_mc4_ssse3 (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); + +void ff_avg_h264_chroma_mc8_rnd_ssse3(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_h264_chroma_mc4_ssse3 (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); + +#define CHROMA_MC(OP, NUM, DEPTH, OPT) \ +void ff_ ## OP ## _h264_chroma_mc ## NUM ## _ ## DEPTH ## _ ## OPT \ + (uint8_t *dst, uint8_t *src, \ + ptrdiff_t stride, int h, int x, int y); + +CHROMA_MC(put, 2, 10, mmxext) +CHROMA_MC(avg, 2, 10, mmxext) +CHROMA_MC(put, 4, 10, mmxext) +CHROMA_MC(avg, 4, 10, mmxext) +CHROMA_MC(put, 8, 10, sse2) +CHROMA_MC(avg, 8, 10, sse2) +CHROMA_MC(put, 8, 10, avx) +CHROMA_MC(avg, 8, 10, avx) + +av_cold void ff_h264chroma_init_x86(H264ChromaContext *c, int bit_depth) +{ + int high_bit_depth = bit_depth > 8; + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags) && !high_bit_depth) { + c->put_h264_chroma_pixels_tab[0] = ff_put_h264_chroma_mc8_rnd_mmx; + c->put_h264_chroma_pixels_tab[1] = ff_put_h264_chroma_mc4_mmx; + } + + if (EXTERNAL_AMD3DNOW(cpu_flags) && !high_bit_depth) { + c->avg_h264_chroma_pixels_tab[0] = ff_avg_h264_chroma_mc8_rnd_3dnow; + c->avg_h264_chroma_pixels_tab[1] = ff_avg_h264_chroma_mc4_3dnow; + } + + if (EXTERNAL_MMXEXT(cpu_flags) && !high_bit_depth) { + c->avg_h264_chroma_pixels_tab[0] = ff_avg_h264_chroma_mc8_rnd_mmxext; + c->avg_h264_chroma_pixels_tab[1] = ff_avg_h264_chroma_mc4_mmxext; + c->avg_h264_chroma_pixels_tab[2] = ff_avg_h264_chroma_mc2_mmxext; + c->put_h264_chroma_pixels_tab[2] = ff_put_h264_chroma_mc2_mmxext; + } + + if (EXTERNAL_MMXEXT(cpu_flags) && bit_depth > 8 && bit_depth <= 10) { + c->put_h264_chroma_pixels_tab[2] = ff_put_h264_chroma_mc2_10_mmxext; + c->avg_h264_chroma_pixels_tab[2] = ff_avg_h264_chroma_mc2_10_mmxext; + c->put_h264_chroma_pixels_tab[1] = ff_put_h264_chroma_mc4_10_mmxext; + c->avg_h264_chroma_pixels_tab[1] = ff_avg_h264_chroma_mc4_10_mmxext; + } + + if (EXTERNAL_SSE2(cpu_flags) && bit_depth > 8 && bit_depth <= 10) { + c->put_h264_chroma_pixels_tab[0] = ff_put_h264_chroma_mc8_10_sse2; + c->avg_h264_chroma_pixels_tab[0] = ff_avg_h264_chroma_mc8_10_sse2; + } + + if (EXTERNAL_SSSE3(cpu_flags) && !high_bit_depth) { + c->put_h264_chroma_pixels_tab[0] = ff_put_h264_chroma_mc8_rnd_ssse3; + c->avg_h264_chroma_pixels_tab[0] = ff_avg_h264_chroma_mc8_rnd_ssse3; + c->put_h264_chroma_pixels_tab[1] = ff_put_h264_chroma_mc4_ssse3; + c->avg_h264_chroma_pixels_tab[1] = ff_avg_h264_chroma_mc4_ssse3; + } + + if (EXTERNAL_AVX(cpu_flags) && bit_depth > 8 && bit_depth <= 10) { + // AVX implies !cache64. + // TODO: Port cache(32|64) detection from x264. + c->put_h264_chroma_pixels_tab[0] = ff_put_h264_chroma_mc8_10_avx; + c->avg_h264_chroma_pixels_tab[0] = ff_avg_h264_chroma_mc8_10_avx; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264dsp_init.c new file mode 100644 index 0000000000..08eb7ead44 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/h264dsp_init.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2004-2005 Michael Niedermayer, Loren Merritt + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/h264dsp.h" + +/***********************************/ +/* IDCT */ +#define IDCT_ADD_FUNC(NUM, DEPTH, OPT) \ +void ff_h264_idct ## NUM ## _add_ ## DEPTH ## _ ## OPT(uint8_t *dst, \ + int16_t *block, \ + int stride); + +IDCT_ADD_FUNC(, 8, mmx) +IDCT_ADD_FUNC(, 8, sse2) +IDCT_ADD_FUNC(, 8, avx) +IDCT_ADD_FUNC(, 10, sse2) +IDCT_ADD_FUNC(_dc, 8, mmxext) +IDCT_ADD_FUNC(_dc, 8, sse2) +IDCT_ADD_FUNC(_dc, 8, avx) +IDCT_ADD_FUNC(_dc, 10, mmxext) +IDCT_ADD_FUNC(8_dc, 8, mmxext) +IDCT_ADD_FUNC(8_dc, 10, sse2) +IDCT_ADD_FUNC(8, 8, mmx) +IDCT_ADD_FUNC(8, 8, sse2) +IDCT_ADD_FUNC(8, 10, sse2) +IDCT_ADD_FUNC(, 10, avx) +IDCT_ADD_FUNC(8_dc, 10, avx) +IDCT_ADD_FUNC(8, 10, avx) + + +#define IDCT_ADD_REP_FUNC(NUM, REP, DEPTH, OPT) \ +void ff_h264_idct ## NUM ## _add ## REP ## _ ## DEPTH ## _ ## OPT \ + (uint8_t *dst, const int *block_offset, \ + int16_t *block, int stride, const uint8_t nnzc[6 * 8]); + +IDCT_ADD_REP_FUNC(8, 4, 8, mmx) +IDCT_ADD_REP_FUNC(8, 4, 8, mmxext) +IDCT_ADD_REP_FUNC(8, 4, 8, sse2) +IDCT_ADD_REP_FUNC(8, 4, 10, sse2) +IDCT_ADD_REP_FUNC(8, 4, 10, avx) +IDCT_ADD_REP_FUNC(, 16, 8, mmx) +IDCT_ADD_REP_FUNC(, 16, 8, mmxext) +IDCT_ADD_REP_FUNC(, 16, 8, sse2) +IDCT_ADD_REP_FUNC(, 16, 10, sse2) +IDCT_ADD_REP_FUNC(, 16intra, 8, mmx) +IDCT_ADD_REP_FUNC(, 16intra, 8, mmxext) +IDCT_ADD_REP_FUNC(, 16intra, 8, sse2) +IDCT_ADD_REP_FUNC(, 16intra, 10, sse2) +IDCT_ADD_REP_FUNC(, 16, 10, avx) +IDCT_ADD_REP_FUNC(, 16intra, 10, avx) + + +#define IDCT_ADD_REP_FUNC2(NUM, REP, DEPTH, OPT) \ +void ff_h264_idct ## NUM ## _add ## REP ## _ ## DEPTH ## _ ## OPT \ + (uint8_t **dst, const int *block_offset, \ + int16_t *block, int stride, const uint8_t nnzc[6 * 8]); + +IDCT_ADD_REP_FUNC2(, 8, 8, mmx) +IDCT_ADD_REP_FUNC2(, 8, 8, mmxext) +IDCT_ADD_REP_FUNC2(, 8, 8, sse2) +IDCT_ADD_REP_FUNC2(, 8, 10, sse2) +IDCT_ADD_REP_FUNC2(, 8, 10, avx) + +IDCT_ADD_REP_FUNC2(, 8_422, 8, mmx) + +IDCT_ADD_REP_FUNC2(, 8_422, 10, sse2) +IDCT_ADD_REP_FUNC2(, 8_422, 10, avx) + +void ff_h264_luma_dc_dequant_idct_mmx(int16_t *output, int16_t *input, int qmul); +void ff_h264_luma_dc_dequant_idct_sse2(int16_t *output, int16_t *input, int qmul); + +/***********************************/ +/* deblocking */ + +void ff_h264_loop_filter_strength_mmxext(int16_t bS[2][4][4], uint8_t nnz[40], + int8_t ref[2][40], + int16_t mv[2][40][2], + int bidir, int edges, int step, + int mask_mv0, int mask_mv1, int field); + +#define LF_FUNC(DIR, TYPE, DEPTH, OPT) \ +void ff_deblock_ ## DIR ## _ ## TYPE ## _ ## DEPTH ## _ ## OPT(uint8_t *pix, \ + ptrdiff_t stride, \ + int alpha, \ + int beta, \ + int8_t *tc0); +#define LF_IFUNC(DIR, TYPE, DEPTH, OPT) \ +void ff_deblock_ ## DIR ## _ ## TYPE ## _ ## DEPTH ## _ ## OPT(uint8_t *pix, \ + ptrdiff_t stride, \ + int alpha, \ + int beta); + +#define LF_FUNCS(type, depth) \ +LF_FUNC(h, chroma, depth, mmxext) \ +LF_IFUNC(h, chroma_intra, depth, mmxext) \ +LF_FUNC(h, chroma422, depth, mmxext) \ +LF_IFUNC(h, chroma422_intra, depth, mmxext) \ +LF_FUNC(v, chroma, depth, mmxext) \ +LF_IFUNC(v, chroma_intra, depth, mmxext) \ +LF_FUNC(h, luma, depth, mmxext) \ +LF_IFUNC(h, luma_intra, depth, mmxext) \ +LF_FUNC(h, luma, depth, sse2) \ +LF_IFUNC(h, luma_intra, depth, sse2) \ +LF_FUNC(v, luma, depth, sse2) \ +LF_IFUNC(v, luma_intra, depth, sse2) \ +LF_FUNC(h, chroma, depth, sse2) \ +LF_IFUNC(h, chroma_intra, depth, sse2) \ +LF_FUNC(h, chroma422, depth, sse2) \ +LF_IFUNC(h, chroma422_intra, depth, sse2) \ +LF_FUNC(v, chroma, depth, sse2) \ +LF_IFUNC(v, chroma_intra, depth, sse2) \ +LF_FUNC(h, luma, depth, avx) \ +LF_IFUNC(h, luma_intra, depth, avx) \ +LF_FUNC(v, luma, depth, avx) \ +LF_IFUNC(v, luma_intra, depth, avx) \ +LF_FUNC(h, chroma, depth, avx) \ +LF_IFUNC(h, chroma_intra, depth, avx) \ +LF_FUNC(h, chroma422, depth, avx) \ +LF_IFUNC(h, chroma422_intra, depth, avx) \ +LF_FUNC(v, chroma, depth, avx) \ +LF_IFUNC(v, chroma_intra, depth, avx) + +LF_FUNC(h, luma_mbaff, 8, sse2) +LF_FUNC(h, luma_mbaff, 8, avx) + +LF_FUNCS(uint8_t, 8) +LF_FUNCS(uint16_t, 10) + +#if ARCH_X86_32 && HAVE_MMXEXT_EXTERNAL +LF_FUNC(v8, luma, 8, mmxext) +static void deblock_v_luma_8_mmxext(uint8_t *pix, int stride, int alpha, + int beta, int8_t *tc0) +{ + if ((tc0[0] & tc0[1]) >= 0) + ff_deblock_v8_luma_8_mmxext(pix + 0, stride, alpha, beta, tc0); + if ((tc0[2] & tc0[3]) >= 0) + ff_deblock_v8_luma_8_mmxext(pix + 8, stride, alpha, beta, tc0 + 2); +} +LF_IFUNC(v8, luma_intra, 8, mmxext) +static void deblock_v_luma_intra_8_mmxext(uint8_t *pix, int stride, + int alpha, int beta) +{ + ff_deblock_v8_luma_intra_8_mmxext(pix + 0, stride, alpha, beta); + ff_deblock_v8_luma_intra_8_mmxext(pix + 8, stride, alpha, beta); +} +#endif /* ARCH_X86_32 && HAVE_MMXEXT_EXTERNAL */ + +LF_FUNC(v, luma, 10, mmxext) +LF_IFUNC(v, luma_intra, 10, mmxext) + +/***********************************/ +/* weighted prediction */ + +#define H264_WEIGHT(W, OPT) \ +void ff_h264_weight_ ## W ## _ ## OPT(uint8_t *dst, ptrdiff_t stride, \ + int height, int log2_denom, \ + int weight, int offset); + +#define H264_BIWEIGHT(W, OPT) \ +void ff_h264_biweight_ ## W ## _ ## OPT(uint8_t *dst, uint8_t *src, \ + ptrdiff_t stride, int height, \ + int log2_denom, int weightd, \ + int weights, int offset); + +#define H264_BIWEIGHT_MMX(W) \ + H264_WEIGHT(W, mmxext) \ + H264_BIWEIGHT(W, mmxext) + +#define H264_BIWEIGHT_MMX_SSE(W) \ + H264_BIWEIGHT_MMX(W) \ + H264_WEIGHT(W, sse2) \ + H264_BIWEIGHT(W, sse2) \ + H264_BIWEIGHT(W, ssse3) + +H264_BIWEIGHT_MMX_SSE(16) +H264_BIWEIGHT_MMX_SSE(8) +H264_BIWEIGHT_MMX(4) + +#define H264_WEIGHT_10(W, DEPTH, OPT) \ +void ff_h264_weight_ ## W ## _ ## DEPTH ## _ ## OPT(uint8_t *dst, \ + ptrdiff_t stride, \ + int height, \ + int log2_denom, \ + int weight, \ + int offset); + +#define H264_BIWEIGHT_10(W, DEPTH, OPT) \ +void ff_h264_biweight_ ## W ## _ ## DEPTH ## _ ## OPT(uint8_t *dst, \ + uint8_t *src, \ + ptrdiff_t stride, \ + int height, \ + int log2_denom, \ + int weightd, \ + int weights, \ + int offset); + +#define H264_BIWEIGHT_10_SSE(W, DEPTH) \ + H264_WEIGHT_10(W, DEPTH, sse2) \ + H264_WEIGHT_10(W, DEPTH, sse4) \ + H264_BIWEIGHT_10(W, DEPTH, sse2) \ + H264_BIWEIGHT_10(W, DEPTH, sse4) + +H264_BIWEIGHT_10_SSE(16, 10) +H264_BIWEIGHT_10_SSE(8, 10) +H264_BIWEIGHT_10_SSE(4, 10) + +av_cold void ff_h264dsp_init_x86(H264DSPContext *c, const int bit_depth, + const int chroma_format_idc) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMXEXT(cpu_flags) && chroma_format_idc <= 1) + c->h264_loop_filter_strength = ff_h264_loop_filter_strength_mmxext; + + if (bit_depth == 8) { + if (EXTERNAL_MMX(cpu_flags)) { + c->h264_idct_dc_add = + c->h264_idct_add = ff_h264_idct_add_8_mmx; + c->h264_idct8_dc_add = + c->h264_idct8_add = ff_h264_idct8_add_8_mmx; + + c->h264_idct_add16 = ff_h264_idct_add16_8_mmx; + c->h264_idct8_add4 = ff_h264_idct8_add4_8_mmx; + if (chroma_format_idc <= 1) { + c->h264_idct_add8 = ff_h264_idct_add8_8_mmx; + } else { + c->h264_idct_add8 = ff_h264_idct_add8_422_8_mmx; + } + c->h264_idct_add16intra = ff_h264_idct_add16intra_8_mmx; + if (cpu_flags & AV_CPU_FLAG_CMOV) + c->h264_luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_mmx; + } + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->h264_idct_dc_add = ff_h264_idct_dc_add_8_mmxext; + c->h264_idct8_dc_add = ff_h264_idct8_dc_add_8_mmxext; + c->h264_idct_add16 = ff_h264_idct_add16_8_mmxext; + c->h264_idct8_add4 = ff_h264_idct8_add4_8_mmxext; + if (chroma_format_idc <= 1) + c->h264_idct_add8 = ff_h264_idct_add8_8_mmxext; + c->h264_idct_add16intra = ff_h264_idct_add16intra_8_mmxext; + + c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_8_mmxext; + c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_8_mmxext; + if (chroma_format_idc <= 1) { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma_8_mmxext; + c->h264_h_loop_filter_chroma_intra = ff_deblock_h_chroma_intra_8_mmxext; + } else { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma422_8_mmxext; + c->h264_h_loop_filter_chroma_intra = ff_deblock_h_chroma422_intra_8_mmxext; + } +#if ARCH_X86_32 && HAVE_MMXEXT_EXTERNAL + c->h264_v_loop_filter_luma = deblock_v_luma_8_mmxext; + c->h264_h_loop_filter_luma = ff_deblock_h_luma_8_mmxext; + c->h264_v_loop_filter_luma_intra = deblock_v_luma_intra_8_mmxext; + c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_8_mmxext; +#endif /* ARCH_X86_32 && HAVE_MMXEXT_EXTERNAL */ + c->weight_h264_pixels_tab[0] = ff_h264_weight_16_mmxext; + c->weight_h264_pixels_tab[1] = ff_h264_weight_8_mmxext; + c->weight_h264_pixels_tab[2] = ff_h264_weight_4_mmxext; + + c->biweight_h264_pixels_tab[0] = ff_h264_biweight_16_mmxext; + c->biweight_h264_pixels_tab[1] = ff_h264_biweight_8_mmxext; + c->biweight_h264_pixels_tab[2] = ff_h264_biweight_4_mmxext; + } + if (EXTERNAL_SSE2(cpu_flags)) { + c->h264_idct8_add = ff_h264_idct8_add_8_sse2; + + c->h264_idct_add16 = ff_h264_idct_add16_8_sse2; + c->h264_idct8_add4 = ff_h264_idct8_add4_8_sse2; + if (chroma_format_idc <= 1) + c->h264_idct_add8 = ff_h264_idct_add8_8_sse2; + c->h264_idct_add16intra = ff_h264_idct_add16intra_8_sse2; + c->h264_luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_sse2; + + c->weight_h264_pixels_tab[0] = ff_h264_weight_16_sse2; + c->weight_h264_pixels_tab[1] = ff_h264_weight_8_sse2; + + c->biweight_h264_pixels_tab[0] = ff_h264_biweight_16_sse2; + c->biweight_h264_pixels_tab[1] = ff_h264_biweight_8_sse2; + + c->h264_v_loop_filter_luma = ff_deblock_v_luma_8_sse2; + c->h264_h_loop_filter_luma = ff_deblock_h_luma_8_sse2; + c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_8_sse2; + c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_8_sse2; + +#if ARCH_X86_64 + c->h264_h_loop_filter_luma_mbaff = ff_deblock_h_luma_mbaff_8_sse2; +#endif + + c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_8_sse2; + c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_8_sse2; + if (chroma_format_idc <= 1) { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma_8_sse2; + c->h264_h_loop_filter_chroma_intra = ff_deblock_h_chroma_intra_8_sse2; + } else { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma422_8_sse2; + c->h264_h_loop_filter_chroma_intra = ff_deblock_h_chroma422_intra_8_sse2; + } + + c->h264_idct_add = ff_h264_idct_add_8_sse2; + c->h264_idct_dc_add = ff_h264_idct_dc_add_8_sse2; + } + if (EXTERNAL_SSSE3(cpu_flags)) { + c->biweight_h264_pixels_tab[0] = ff_h264_biweight_16_ssse3; + c->biweight_h264_pixels_tab[1] = ff_h264_biweight_8_ssse3; + } + if (EXTERNAL_AVX(cpu_flags)) { + c->h264_v_loop_filter_luma = ff_deblock_v_luma_8_avx; + c->h264_h_loop_filter_luma = ff_deblock_h_luma_8_avx; + c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_8_avx; + c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_8_avx; +#if ARCH_X86_64 + c->h264_h_loop_filter_luma_mbaff = ff_deblock_h_luma_mbaff_8_avx; +#endif + + c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_8_avx; + c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_8_avx; + if (chroma_format_idc <= 1) { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma_8_avx; + c->h264_h_loop_filter_chroma_intra = ff_deblock_h_chroma_intra_8_avx; + } else { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma422_8_avx; + c->h264_h_loop_filter_chroma_intra = ff_deblock_h_chroma422_intra_8_avx; + } + + c->h264_idct_add = ff_h264_idct_add_8_avx; + c->h264_idct_dc_add = ff_h264_idct_dc_add_8_avx; + } + } else if (bit_depth == 10) { + if (EXTERNAL_MMXEXT(cpu_flags)) { +#if ARCH_X86_32 + c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_10_mmxext; + c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_10_mmxext; + if (chroma_format_idc <= 1) { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma_10_mmxext; + } else { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma422_10_mmxext; + } + c->h264_v_loop_filter_luma = ff_deblock_v_luma_10_mmxext; + c->h264_h_loop_filter_luma = ff_deblock_h_luma_10_mmxext; + c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_10_mmxext; + c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_10_mmxext; +#endif /* ARCH_X86_32 */ + c->h264_idct_dc_add = ff_h264_idct_dc_add_10_mmxext; + } + if (EXTERNAL_SSE2(cpu_flags)) { + c->h264_idct_add = ff_h264_idct_add_10_sse2; + c->h264_idct8_dc_add = ff_h264_idct8_dc_add_10_sse2; + + c->h264_idct_add16 = ff_h264_idct_add16_10_sse2; + if (chroma_format_idc <= 1) { + c->h264_idct_add8 = ff_h264_idct_add8_10_sse2; + } else { + c->h264_idct_add8 = ff_h264_idct_add8_422_10_sse2; + } + c->h264_idct_add16intra = ff_h264_idct_add16intra_10_sse2; +#if HAVE_ALIGNED_STACK + c->h264_idct8_add = ff_h264_idct8_add_10_sse2; + c->h264_idct8_add4 = ff_h264_idct8_add4_10_sse2; +#endif /* HAVE_ALIGNED_STACK */ + + c->weight_h264_pixels_tab[0] = ff_h264_weight_16_10_sse2; + c->weight_h264_pixels_tab[1] = ff_h264_weight_8_10_sse2; + c->weight_h264_pixels_tab[2] = ff_h264_weight_4_10_sse2; + + c->biweight_h264_pixels_tab[0] = ff_h264_biweight_16_10_sse2; + c->biweight_h264_pixels_tab[1] = ff_h264_biweight_8_10_sse2; + c->biweight_h264_pixels_tab[2] = ff_h264_biweight_4_10_sse2; + + c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_10_sse2; + c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_10_sse2; + if (chroma_format_idc <= 1) { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma_10_sse2; + } else { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma422_10_sse2; + } +#if HAVE_ALIGNED_STACK + c->h264_v_loop_filter_luma = ff_deblock_v_luma_10_sse2; + c->h264_h_loop_filter_luma = ff_deblock_h_luma_10_sse2; + c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_10_sse2; + c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_10_sse2; +#endif /* HAVE_ALIGNED_STACK */ + } + if (EXTERNAL_SSE4(cpu_flags)) { + c->weight_h264_pixels_tab[0] = ff_h264_weight_16_10_sse4; + c->weight_h264_pixels_tab[1] = ff_h264_weight_8_10_sse4; + c->weight_h264_pixels_tab[2] = ff_h264_weight_4_10_sse4; + + c->biweight_h264_pixels_tab[0] = ff_h264_biweight_16_10_sse4; + c->biweight_h264_pixels_tab[1] = ff_h264_biweight_8_10_sse4; + c->biweight_h264_pixels_tab[2] = ff_h264_biweight_4_10_sse4; + } + if (EXTERNAL_AVX(cpu_flags)) { + c->h264_idct_dc_add = + c->h264_idct_add = ff_h264_idct_add_10_avx; + c->h264_idct8_dc_add = ff_h264_idct8_dc_add_10_avx; + + c->h264_idct_add16 = ff_h264_idct_add16_10_avx; + if (chroma_format_idc <= 1) { + c->h264_idct_add8 = ff_h264_idct_add8_10_avx; + } else { + c->h264_idct_add8 = ff_h264_idct_add8_422_10_avx; + } + c->h264_idct_add16intra = ff_h264_idct_add16intra_10_avx; +#if HAVE_ALIGNED_STACK + c->h264_idct8_add = ff_h264_idct8_add_10_avx; + c->h264_idct8_add4 = ff_h264_idct8_add4_10_avx; +#endif /* HAVE_ALIGNED_STACK */ + + c->h264_v_loop_filter_chroma = ff_deblock_v_chroma_10_avx; + c->h264_v_loop_filter_chroma_intra = ff_deblock_v_chroma_intra_10_avx; + if (chroma_format_idc <= 1) { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma_10_avx; + } else { + c->h264_h_loop_filter_chroma = ff_deblock_h_chroma422_10_avx; + } +#if HAVE_ALIGNED_STACK + c->h264_v_loop_filter_luma = ff_deblock_v_luma_10_avx; + c->h264_h_loop_filter_luma = ff_deblock_h_luma_10_avx; + c->h264_v_loop_filter_luma_intra = ff_deblock_v_luma_intra_10_avx; + c->h264_h_loop_filter_luma_intra = ff_deblock_h_luma_intra_10_avx; +#endif /* HAVE_ALIGNED_STACK */ + } + } +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hevcdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hevcdsp.h new file mode 100644 index 0000000000..67be0a9059 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hevcdsp.h @@ -0,0 +1,259 @@ +/* + * HEVC video decoder + * + * Copyright (C) 2012 - 2013 Guillaume Martres + * Copyright (C) 2013 - 2014 Pierre-Edouard Lepere + * + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_HEVCDSP_H +#define AVCODEC_X86_HEVCDSP_H + +#include +#include + + +#define PEL_LINK(dst, idx1, idx2, idx3, name, D, opt) \ +dst[idx1][idx2][idx3] = ff_hevc_put_hevc_ ## name ## _ ## D ## _##opt; \ +dst ## _bi[idx1][idx2][idx3] = ff_hevc_put_hevc_bi_ ## name ## _ ## D ## _##opt; \ +dst ## _uni[idx1][idx2][idx3] = ff_hevc_put_hevc_uni_ ## name ## _ ## D ## _##opt; \ +dst ## _uni_w[idx1][idx2][idx3] = ff_hevc_put_hevc_uni_w_ ## name ## _ ## D ## _##opt; \ +dst ## _bi_w[idx1][idx2][idx3] = ff_hevc_put_hevc_bi_w_ ## name ## _ ## D ## _##opt + + +#define PEL_PROTOTYPE(name, D, opt) \ +void ff_hevc_put_hevc_ ## name ## _ ## D ## _##opt(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); \ +void ff_hevc_put_hevc_bi_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); \ +void ff_hevc_put_hevc_uni_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my, int width); \ +void ff_hevc_put_hevc_uni_w_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width); \ +void ff_hevc_put_hevc_bi_w_ ## name ## _ ## D ## _##opt(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, int denom, int wx0, int wx1, int ox0, int ox1, intptr_t mx, intptr_t my, int width) + + +/////////////////////////////////////////////////////////////////////////////// +// MC functions +/////////////////////////////////////////////////////////////////////////////// + +#define EPEL_PROTOTYPES(fname, bitd, opt) \ + PEL_PROTOTYPE(fname##4, bitd, opt); \ + PEL_PROTOTYPE(fname##6, bitd, opt); \ + PEL_PROTOTYPE(fname##8, bitd, opt); \ + PEL_PROTOTYPE(fname##12, bitd, opt); \ + PEL_PROTOTYPE(fname##16, bitd, opt); \ + PEL_PROTOTYPE(fname##24, bitd, opt); \ + PEL_PROTOTYPE(fname##32, bitd, opt); \ + PEL_PROTOTYPE(fname##48, bitd, opt); \ + PEL_PROTOTYPE(fname##64, bitd, opt) + +#define QPEL_PROTOTYPES(fname, bitd, opt) \ + PEL_PROTOTYPE(fname##4, bitd, opt); \ + PEL_PROTOTYPE(fname##8, bitd, opt); \ + PEL_PROTOTYPE(fname##12, bitd, opt); \ + PEL_PROTOTYPE(fname##16, bitd, opt); \ + PEL_PROTOTYPE(fname##24, bitd, opt); \ + PEL_PROTOTYPE(fname##32, bitd, opt); \ + PEL_PROTOTYPE(fname##48, bitd, opt); \ + PEL_PROTOTYPE(fname##64, bitd, opt) + +#define WEIGHTING_PROTOTYPE(width, bitd, opt) \ +void ff_hevc_put_hevc_uni_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, int16_t *_src, int height, int denom, int _wx, int _ox); \ +void ff_hevc_put_hevc_bi_w##width##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, int16_t *_src, int16_t *_src2, int height, int denom, int _wx0, int _wx1, int _ox0, int _ox1) + +#define WEIGHTING_PROTOTYPES(bitd, opt) \ + WEIGHTING_PROTOTYPE(2, bitd, opt); \ + WEIGHTING_PROTOTYPE(4, bitd, opt); \ + WEIGHTING_PROTOTYPE(6, bitd, opt); \ + WEIGHTING_PROTOTYPE(8, bitd, opt); \ + WEIGHTING_PROTOTYPE(12, bitd, opt); \ + WEIGHTING_PROTOTYPE(16, bitd, opt); \ + WEIGHTING_PROTOTYPE(24, bitd, opt); \ + WEIGHTING_PROTOTYPE(32, bitd, opt); \ + WEIGHTING_PROTOTYPE(48, bitd, opt); \ + WEIGHTING_PROTOTYPE(64, bitd, opt) + + +/////////////////////////////////////////////////////////////////////////////// +// QPEL_PIXELS EPEL_PIXELS +/////////////////////////////////////////////////////////////////////////////// +EPEL_PROTOTYPES(pel_pixels , 8, sse4); +EPEL_PROTOTYPES(pel_pixels , 10, sse4); +EPEL_PROTOTYPES(pel_pixels , 12, sse4); + +void ff_hevc_put_hevc_pel_pixels16_8_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_pel_pixels24_8_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_pel_pixels32_8_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_pel_pixels48_8_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_pel_pixels64_8_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); + +void ff_hevc_put_hevc_pel_pixels16_10_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_pel_pixels24_10_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_pel_pixels32_10_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_pel_pixels48_10_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_pel_pixels64_10_avx2(int16_t *dst, uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); + + + +void ff_hevc_put_hevc_uni_pel_pixels32_8_avx2(uint8_t *dst, ptrdiff_t dststride,uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_uni_pel_pixels48_8_avx2(uint8_t *dst, ptrdiff_t dststride,uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_uni_pel_pixels64_8_avx2(uint8_t *dst, ptrdiff_t dststride,uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); +void ff_hevc_put_hevc_uni_pel_pixels96_8_avx2(uint8_t *dst, ptrdiff_t dststride,uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width); //used for 10bit +void ff_hevc_put_hevc_uni_pel_pixels128_8_avx2(uint8_t *dst, ptrdiff_t dststride,uint8_t *_src, ptrdiff_t _srcstride, int height, intptr_t mx, intptr_t my,int width);//used for 10bit + + +void ff_hevc_put_hevc_bi_pel_pixels16_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_hevc_bi_pel_pixels24_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_hevc_bi_pel_pixels32_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_hevc_bi_pel_pixels48_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_hevc_bi_pel_pixels64_8_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); + +void ff_hevc_put_hevc_bi_pel_pixels16_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_hevc_bi_pel_pixels24_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_hevc_bi_pel_pixels32_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_hevc_bi_pel_pixels48_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); +void ff_hevc_put_hevc_bi_pel_pixels64_10_avx2(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride, int16_t *src2, int height, intptr_t mx, intptr_t my, int width); + +/////////////////////////////////////////////////////////////////////////////// +// EPEL +/////////////////////////////////////////////////////////////////////////////// +EPEL_PROTOTYPES(epel_h , 8, sse4); +EPEL_PROTOTYPES(epel_h , 10, sse4); +EPEL_PROTOTYPES(epel_h , 12, sse4); + +EPEL_PROTOTYPES(epel_v , 8, sse4); +EPEL_PROTOTYPES(epel_v , 10, sse4); +EPEL_PROTOTYPES(epel_v , 12, sse4); + +EPEL_PROTOTYPES(epel_hv , 8, sse4); +EPEL_PROTOTYPES(epel_hv , 10, sse4); +EPEL_PROTOTYPES(epel_hv , 12, sse4); + +PEL_PROTOTYPE(epel_h16, 8, avx2); +PEL_PROTOTYPE(epel_h24, 8, avx2); +PEL_PROTOTYPE(epel_h32, 8, avx2); +PEL_PROTOTYPE(epel_h48, 8, avx2); +PEL_PROTOTYPE(epel_h64, 8, avx2); + +PEL_PROTOTYPE(epel_h16,10, avx2); +PEL_PROTOTYPE(epel_h24,10, avx2); +PEL_PROTOTYPE(epel_h32,10, avx2); +PEL_PROTOTYPE(epel_h48,10, avx2); +PEL_PROTOTYPE(epel_h64,10, avx2); + +PEL_PROTOTYPE(epel_v16, 8, avx2); +PEL_PROTOTYPE(epel_v24, 8, avx2); +PEL_PROTOTYPE(epel_v32, 8, avx2); +PEL_PROTOTYPE(epel_v48, 8, avx2); +PEL_PROTOTYPE(epel_v64, 8, avx2); + +PEL_PROTOTYPE(epel_v16,10, avx2); +PEL_PROTOTYPE(epel_v24,10, avx2); +PEL_PROTOTYPE(epel_v32,10, avx2); +PEL_PROTOTYPE(epel_v48,10, avx2); +PEL_PROTOTYPE(epel_v64,10, avx2); + +PEL_PROTOTYPE(epel_hv16, 8, avx2); +PEL_PROTOTYPE(epel_hv24, 8, avx2); +PEL_PROTOTYPE(epel_hv32, 8, avx2); +PEL_PROTOTYPE(epel_hv48, 8, avx2); +PEL_PROTOTYPE(epel_hv64, 8, avx2); + +PEL_PROTOTYPE(epel_hv16,10, avx2); +PEL_PROTOTYPE(epel_hv24,10, avx2); +PEL_PROTOTYPE(epel_hv32,10, avx2); +PEL_PROTOTYPE(epel_hv48,10, avx2); +PEL_PROTOTYPE(epel_hv64,10, avx2); + +/////////////////////////////////////////////////////////////////////////////// +// QPEL +/////////////////////////////////////////////////////////////////////////////// +QPEL_PROTOTYPES(qpel_h , 8, sse4); +QPEL_PROTOTYPES(qpel_h , 10, sse4); +QPEL_PROTOTYPES(qpel_h , 12, sse4); + +QPEL_PROTOTYPES(qpel_v, 8, sse4); +QPEL_PROTOTYPES(qpel_v, 10, sse4); +QPEL_PROTOTYPES(qpel_v, 12, sse4); + +QPEL_PROTOTYPES(qpel_hv, 8, sse4); +QPEL_PROTOTYPES(qpel_hv, 10, sse4); +QPEL_PROTOTYPES(qpel_hv, 12, sse4); + +PEL_PROTOTYPE(qpel_h16, 8, avx2); +PEL_PROTOTYPE(qpel_h24, 8, avx2); +PEL_PROTOTYPE(qpel_h32, 8, avx2); +PEL_PROTOTYPE(qpel_h48, 8, avx2); +PEL_PROTOTYPE(qpel_h64, 8, avx2); + +PEL_PROTOTYPE(qpel_h16,10, avx2); +PEL_PROTOTYPE(qpel_h24,10, avx2); +PEL_PROTOTYPE(qpel_h32,10, avx2); +PEL_PROTOTYPE(qpel_h48,10, avx2); +PEL_PROTOTYPE(qpel_h64,10, avx2); + +PEL_PROTOTYPE(qpel_v16, 8, avx2); +PEL_PROTOTYPE(qpel_v24, 8, avx2); +PEL_PROTOTYPE(qpel_v32, 8, avx2); +PEL_PROTOTYPE(qpel_v48, 8, avx2); +PEL_PROTOTYPE(qpel_v64, 8, avx2); + +PEL_PROTOTYPE(qpel_v16,10, avx2); +PEL_PROTOTYPE(qpel_v24,10, avx2); +PEL_PROTOTYPE(qpel_v32,10, avx2); +PEL_PROTOTYPE(qpel_v48,10, avx2); +PEL_PROTOTYPE(qpel_v64,10, avx2); + +PEL_PROTOTYPE(qpel_hv16, 8, avx2); +PEL_PROTOTYPE(qpel_hv24, 8, avx2); +PEL_PROTOTYPE(qpel_hv32, 8, avx2); +PEL_PROTOTYPE(qpel_hv48, 8, avx2); +PEL_PROTOTYPE(qpel_hv64, 8, avx2); + +PEL_PROTOTYPE(qpel_hv16,10, avx2); +PEL_PROTOTYPE(qpel_hv24,10, avx2); +PEL_PROTOTYPE(qpel_hv32,10, avx2); +PEL_PROTOTYPE(qpel_hv48,10, avx2); +PEL_PROTOTYPE(qpel_hv64,10, avx2); + +WEIGHTING_PROTOTYPES(8, sse4); +WEIGHTING_PROTOTYPES(10, sse4); +WEIGHTING_PROTOTYPES(12, sse4); + +/////////////////////////////////////////////////////////////////////////////// +// TRANSFORM_ADD +/////////////////////////////////////////////////////////////////////////////// + +void ff_hevc_add_residual_4_8_mmxext(uint8_t *dst, int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_8_8_sse2(uint8_t *dst, int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_16_8_sse2(uint8_t *dst, int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_8_sse2(uint8_t *dst, int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_8_8_avx(uint8_t *dst, int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_16_8_avx(uint8_t *dst, int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_8_avx(uint8_t *dst, int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_32_8_avx2(uint8_t *dst, int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_4_10_mmxext(uint8_t *dst, int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_8_10_sse2(uint8_t *dst, int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_16_10_sse2(uint8_t *dst, int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_10_sse2(uint8_t *dst, int16_t *res, ptrdiff_t stride); + +void ff_hevc_add_residual_16_10_avx2(uint8_t *dst, int16_t *res, ptrdiff_t stride); +void ff_hevc_add_residual_32_10_avx2(uint8_t *dst, int16_t *res, ptrdiff_t stride); + +#endif // AVCODEC_X86_HEVCDSP_H diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hevcdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hevcdsp_init.c new file mode 100644 index 0000000000..17cd2332aa --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hevcdsp_init.c @@ -0,0 +1,1151 @@ +/* + * Copyright (c) 2013 Seppo Tomperi + * Copyright (c) 2013 - 2014 Pierre-Edouard Lepere + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/get_bits.h" /* required for hevcdsp.h GetBitContext */ +#include "libavcodec/hevcdsp.h" +#include "libavcodec/x86/hevcdsp.h" + +#define LFC_FUNC(DIR, DEPTH, OPT) \ +void ff_hevc_ ## DIR ## _loop_filter_chroma_ ## DEPTH ## _ ## OPT(uint8_t *pix, ptrdiff_t stride, int *tc, uint8_t *no_p, uint8_t *no_q); + +#define LFL_FUNC(DIR, DEPTH, OPT) \ +void ff_hevc_ ## DIR ## _loop_filter_luma_ ## DEPTH ## _ ## OPT(uint8_t *pix, ptrdiff_t stride, int beta, int *tc, uint8_t *no_p, uint8_t *no_q); + +#define LFC_FUNCS(type, depth, opt) \ + LFC_FUNC(h, depth, opt) \ + LFC_FUNC(v, depth, opt) + +#define LFL_FUNCS(type, depth, opt) \ + LFL_FUNC(h, depth, opt) \ + LFL_FUNC(v, depth, opt) + +LFC_FUNCS(uint8_t, 8, sse2) +LFC_FUNCS(uint8_t, 10, sse2) +LFC_FUNCS(uint8_t, 12, sse2) +LFC_FUNCS(uint8_t, 8, avx) +LFC_FUNCS(uint8_t, 10, avx) +LFC_FUNCS(uint8_t, 12, avx) +LFL_FUNCS(uint8_t, 8, sse2) +LFL_FUNCS(uint8_t, 10, sse2) +LFL_FUNCS(uint8_t, 12, sse2) +LFL_FUNCS(uint8_t, 8, ssse3) +LFL_FUNCS(uint8_t, 10, ssse3) +LFL_FUNCS(uint8_t, 12, ssse3) +LFL_FUNCS(uint8_t, 8, avx) +LFL_FUNCS(uint8_t, 10, avx) +LFL_FUNCS(uint8_t, 12, avx) + +#define IDCT_DC_FUNCS(W, opt) \ +void ff_hevc_idct_ ## W ## _dc_8_ ## opt(int16_t *coeffs); \ +void ff_hevc_idct_ ## W ## _dc_10_ ## opt(int16_t *coeffs); \ +void ff_hevc_idct_ ## W ## _dc_12_ ## opt(int16_t *coeffs) + +IDCT_DC_FUNCS(4x4, mmxext); +IDCT_DC_FUNCS(8x8, mmxext); +IDCT_DC_FUNCS(8x8, sse2); +IDCT_DC_FUNCS(16x16, sse2); +IDCT_DC_FUNCS(32x32, sse2); +IDCT_DC_FUNCS(16x16, avx2); +IDCT_DC_FUNCS(32x32, avx2); + +#define IDCT_FUNCS(opt) \ +void ff_hevc_idct_4x4_8_ ## opt(int16_t *coeffs, int col_limit); \ +void ff_hevc_idct_4x4_10_ ## opt(int16_t *coeffs, int col_limit); \ +void ff_hevc_idct_8x8_8_ ## opt(int16_t *coeffs, int col_limit); \ +void ff_hevc_idct_8x8_10_ ## opt(int16_t *coeffs, int col_limit); \ +void ff_hevc_idct_16x16_8_ ## opt(int16_t *coeffs, int col_limit); \ +void ff_hevc_idct_16x16_10_ ## opt(int16_t *coeffs, int col_limit); \ +void ff_hevc_idct_32x32_8_ ## opt(int16_t *coeffs, int col_limit); \ +void ff_hevc_idct_32x32_10_ ## opt(int16_t *coeffs, int col_limit); + +IDCT_FUNCS(sse2) +IDCT_FUNCS(avx) + +#define mc_rep_func(name, bitd, step, W, opt) \ +void ff_hevc_put_hevc_##name##W##_##bitd##_##opt(int16_t *_dst, \ + uint8_t *_src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ +{ \ + int i; \ + uint8_t *src; \ + int16_t *dst; \ + for (i = 0; i < W; i += step) { \ + src = _src + (i * ((bitd + 7) / 8)); \ + dst = _dst + i; \ + ff_hevc_put_hevc_##name##step##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \ + } \ +} +#define mc_rep_uni_func(name, bitd, step, W, opt) \ +void ff_hevc_put_hevc_uni_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, \ + uint8_t *_src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ +{ \ + int i; \ + uint8_t *src; \ + uint8_t *dst; \ + for (i = 0; i < W; i += step) { \ + src = _src + (i * ((bitd + 7) / 8)); \ + dst = _dst + (i * ((bitd + 7) / 8)); \ + ff_hevc_put_hevc_uni_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, \ + height, mx, my, width); \ + } \ +} +#define mc_rep_bi_func(name, bitd, step, W, opt) \ +void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, uint8_t *_src, \ + ptrdiff_t _srcstride, int16_t* _src2, \ + int height, intptr_t mx, intptr_t my, int width) \ +{ \ + int i; \ + uint8_t *src; \ + uint8_t *dst; \ + int16_t *src2; \ + for (i = 0; i < W ; i += step) { \ + src = _src + (i * ((bitd + 7) / 8)); \ + dst = _dst + (i * ((bitd + 7) / 8)); \ + src2 = _src2 + i; \ + ff_hevc_put_hevc_bi_##name##step##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, \ + height, mx, my, width); \ + } \ +} + +#define mc_rep_funcs(name, bitd, step, W, opt) \ + mc_rep_func(name, bitd, step, W, opt) \ + mc_rep_uni_func(name, bitd, step, W, opt) \ + mc_rep_bi_func(name, bitd, step, W, opt) + +#define mc_rep_func2(name, bitd, step1, step2, W, opt) \ +void ff_hevc_put_hevc_##name##W##_##bitd##_##opt(int16_t *dst, \ + uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ +{ \ + ff_hevc_put_hevc_##name##step1##_##bitd##_##opt(dst, src, _srcstride, height, mx, my, width); \ + ff_hevc_put_hevc_##name##step2##_##bitd##_##opt(dst + step1, src + (step1 * ((bitd + 7) / 8)), \ + _srcstride, height, mx, my, width); \ +} +#define mc_rep_uni_func2(name, bitd, step1, step2, W, opt) \ +void ff_hevc_put_hevc_uni_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, \ + uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ +{ \ + ff_hevc_put_hevc_uni_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, height, mx, my, width);\ + ff_hevc_put_hevc_uni_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \ + src + (step1 * ((bitd + 7) / 8)), _srcstride, \ + height, mx, my, width); \ +} +#define mc_rep_bi_func2(name, bitd, step1, step2, W, opt) \ +void ff_hevc_put_hevc_bi_##name##W##_##bitd##_##opt(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \ + ptrdiff_t _srcstride, int16_t* src2, \ + int height, intptr_t mx, intptr_t my, int width) \ +{ \ + ff_hevc_put_hevc_bi_##name##step1##_##bitd##_##opt(dst, dststride, src, _srcstride, src2, height, mx, my, width);\ + ff_hevc_put_hevc_bi_##name##step2##_##bitd##_##opt(dst + (step1 * ((bitd + 7) / 8)), dststride, \ + src + (step1 * ((bitd + 7) / 8)), _srcstride, \ + src2 + step1, height, mx, my, width); \ +} + +#define mc_rep_funcs2(name, bitd, step1, step2, W, opt) \ + mc_rep_func2(name, bitd, step1, step2, W, opt) \ + mc_rep_uni_func2(name, bitd, step1, step2, W, opt) \ + mc_rep_bi_func2(name, bitd, step1, step2, W, opt) + +#if ARCH_X86_64 && HAVE_SSE4_EXTERNAL + +#define mc_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ +void ff_hevc_put_hevc_##name##width1##_10_##opt1(int16_t *dst, uint8_t *src, ptrdiff_t _srcstride, \ + int height, intptr_t mx, intptr_t my, int width) \ + \ +{ \ + ff_hevc_put_hevc_##name##width2##_10_##opt1(dst, src, _srcstride, height, mx, my, width); \ + ff_hevc_put_hevc_##name##width3##_10_##opt2(dst+ width2, src+ width4, _srcstride, height, mx, my, width); \ +} + +#define mc_bi_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ +void ff_hevc_put_hevc_bi_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \ + ptrdiff_t _srcstride, int16_t *src2, \ + int height, intptr_t mx, intptr_t my, int width) \ +{ \ + ff_hevc_put_hevc_bi_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, src2, \ + height, mx, my, width); \ + ff_hevc_put_hevc_bi_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, src2+width2,\ + height, mx, my, width); \ +} + +#define mc_uni_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ +void ff_hevc_put_hevc_uni_##name##width1##_10_##opt1(uint8_t *dst, ptrdiff_t dststride, \ + uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ +{ \ + ff_hevc_put_hevc_uni_##name##width2##_10_##opt1(dst, dststride, src, _srcstride, \ + height, mx, my, width); \ + ff_hevc_put_hevc_uni_##name##width3##_10_##opt2(dst+width4, dststride, src+width4, _srcstride, \ + height, mx, my, width); \ +} + +#define mc_rep_mixs_10(name, width1, width2, width3, opt1, opt2, width4) \ +mc_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ +mc_bi_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) \ +mc_uni_rep_mix_10(name, width1, width2, width3, opt1, opt2, width4) + +#define mc_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ +void ff_hevc_put_hevc_##name##width1##_8_##opt1(int16_t *dst, uint8_t *src, ptrdiff_t _srcstride, \ + int height, intptr_t mx, intptr_t my, int width) \ + \ +{ \ + ff_hevc_put_hevc_##name##width2##_8_##opt1(dst, src, _srcstride, height, mx, my, width); \ + ff_hevc_put_hevc_##name##width3##_8_##opt2(dst+ width2, src+ width2, _srcstride, height, mx, my, width); \ +} + +#define mc_bi_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ +void ff_hevc_put_hevc_bi_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \ + ptrdiff_t _srcstride, int16_t* src2, \ + int height, intptr_t mx, intptr_t my, int width) \ +{ \ + ff_hevc_put_hevc_bi_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \ + src2, height, mx, my, width); \ + ff_hevc_put_hevc_bi_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \ + src2+width2, height, mx, my, width); \ +} + +#define mc_uni_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ +void ff_hevc_put_hevc_uni_##name##width1##_8_##opt1(uint8_t *dst, ptrdiff_t dststride, \ + uint8_t *src, ptrdiff_t _srcstride, int height, \ + intptr_t mx, intptr_t my, int width) \ +{ \ + ff_hevc_put_hevc_uni_##name##width2##_8_##opt1(dst, dststride, src, _srcstride, \ + height, mx, my, width); \ + ff_hevc_put_hevc_uni_##name##width3##_8_##opt2(dst+width2, dststride, src+width2, _srcstride, \ + height, mx, my, width); \ +} + +#define mc_rep_mixs_8(name, width1, width2, width3, opt1, opt2) \ +mc_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ +mc_bi_rep_mix_8(name, width1, width2, width3, opt1, opt2) \ +mc_uni_rep_mix_8(name, width1, width2, width3, opt1, opt2) + +#if HAVE_AVX2_EXTERNAL + +mc_rep_mixs_8(pel_pixels, 48, 32, 16, avx2, sse4) +mc_rep_mixs_8(epel_hv, 48, 32, 16, avx2, sse4) +mc_rep_mixs_8(epel_h , 48, 32, 16, avx2, sse4) +mc_rep_mixs_8(epel_v , 48, 32, 16, avx2, sse4) + +mc_rep_mix_10(pel_pixels, 24, 16, 8, avx2, sse4, 32) +mc_bi_rep_mix_10(pel_pixels,24, 16, 8, avx2, sse4, 32) +mc_rep_mixs_10(epel_hv, 24, 16, 8, avx2, sse4, 32) +mc_rep_mixs_10(epel_h , 24, 16, 8, avx2, sse4, 32) +mc_rep_mixs_10(epel_v , 24, 16, 8, avx2, sse4, 32) + + +mc_rep_mixs_10(qpel_h , 24, 16, 8, avx2, sse4, 32) +mc_rep_mixs_10(qpel_v , 24, 16, 8, avx2, sse4, 32) +mc_rep_mixs_10(qpel_hv, 24, 16, 8, avx2, sse4, 32) + + +mc_rep_uni_func(pel_pixels, 8, 64, 128, avx2)//used for 10bit +mc_rep_uni_func(pel_pixels, 8, 32, 96, avx2) //used for 10bit + +mc_rep_funcs(pel_pixels, 8, 32, 64, avx2) + +mc_rep_func(pel_pixels, 10, 16, 32, avx2) +mc_rep_func(pel_pixels, 10, 16, 48, avx2) +mc_rep_func(pel_pixels, 10, 32, 64, avx2) + +mc_rep_bi_func(pel_pixels, 10, 16, 32, avx2) +mc_rep_bi_func(pel_pixels, 10, 16, 48, avx2) +mc_rep_bi_func(pel_pixels, 10, 32, 64, avx2) + +mc_rep_funcs(epel_h, 8, 32, 64, avx2) + +mc_rep_funcs(epel_v, 8, 32, 64, avx2) + +mc_rep_funcs(epel_h, 10, 16, 32, avx2) +mc_rep_funcs(epel_h, 10, 16, 48, avx2) +mc_rep_funcs(epel_h, 10, 32, 64, avx2) + +mc_rep_funcs(epel_v, 10, 16, 32, avx2) +mc_rep_funcs(epel_v, 10, 16, 48, avx2) +mc_rep_funcs(epel_v, 10, 32, 64, avx2) + + +mc_rep_funcs(epel_hv, 8, 32, 64, avx2) + +mc_rep_funcs(epel_hv, 10, 16, 32, avx2) +mc_rep_funcs(epel_hv, 10, 16, 48, avx2) +mc_rep_funcs(epel_hv, 10, 32, 64, avx2) + +mc_rep_funcs(qpel_h, 8, 32, 64, avx2) +mc_rep_mixs_8(qpel_h , 48, 32, 16, avx2, sse4) + +mc_rep_funcs(qpel_v, 8, 32, 64, avx2) +mc_rep_mixs_8(qpel_v, 48, 32, 16, avx2, sse4) + +mc_rep_funcs(qpel_h, 10, 16, 32, avx2) +mc_rep_funcs(qpel_h, 10, 16, 48, avx2) +mc_rep_funcs(qpel_h, 10, 32, 64, avx2) + +mc_rep_funcs(qpel_v, 10, 16, 32, avx2) +mc_rep_funcs(qpel_v, 10, 16, 48, avx2) +mc_rep_funcs(qpel_v, 10, 32, 64, avx2) + +mc_rep_funcs(qpel_hv, 10, 16, 32, avx2) +mc_rep_funcs(qpel_hv, 10, 16, 48, avx2) +mc_rep_funcs(qpel_hv, 10, 32, 64, avx2) + +#endif //AVX2 + +mc_rep_funcs(pel_pixels, 8, 16, 64, sse4) +mc_rep_funcs(pel_pixels, 8, 16, 48, sse4) +mc_rep_funcs(pel_pixels, 8, 16, 32, sse4) +mc_rep_funcs(pel_pixels, 8, 8, 24, sse4) +mc_rep_funcs(pel_pixels,10, 8, 64, sse4) +mc_rep_funcs(pel_pixels,10, 8, 48, sse4) +mc_rep_funcs(pel_pixels,10, 8, 32, sse4) +mc_rep_funcs(pel_pixels,10, 8, 24, sse4) +mc_rep_funcs(pel_pixels,10, 8, 16, sse4) +mc_rep_funcs(pel_pixels,10, 4, 12, sse4) +mc_rep_funcs(pel_pixels,12, 8, 64, sse4) +mc_rep_funcs(pel_pixels,12, 8, 48, sse4) +mc_rep_funcs(pel_pixels,12, 8, 32, sse4) +mc_rep_funcs(pel_pixels,12, 8, 24, sse4) +mc_rep_funcs(pel_pixels,12, 8, 16, sse4) +mc_rep_funcs(pel_pixels,12, 4, 12, sse4) + +mc_rep_funcs(epel_h, 8, 16, 64, sse4) +mc_rep_funcs(epel_h, 8, 16, 48, sse4) +mc_rep_funcs(epel_h, 8, 16, 32, sse4) +mc_rep_funcs(epel_h, 8, 8, 24, sse4) +mc_rep_funcs(epel_h,10, 8, 64, sse4) +mc_rep_funcs(epel_h,10, 8, 48, sse4) +mc_rep_funcs(epel_h,10, 8, 32, sse4) +mc_rep_funcs(epel_h,10, 8, 24, sse4) +mc_rep_funcs(epel_h,10, 8, 16, sse4) +mc_rep_funcs(epel_h,10, 4, 12, sse4) +mc_rep_funcs(epel_h,12, 8, 64, sse4) +mc_rep_funcs(epel_h,12, 8, 48, sse4) +mc_rep_funcs(epel_h,12, 8, 32, sse4) +mc_rep_funcs(epel_h,12, 8, 24, sse4) +mc_rep_funcs(epel_h,12, 8, 16, sse4) +mc_rep_funcs(epel_h,12, 4, 12, sse4) +mc_rep_funcs(epel_v, 8, 16, 64, sse4) +mc_rep_funcs(epel_v, 8, 16, 48, sse4) +mc_rep_funcs(epel_v, 8, 16, 32, sse4) +mc_rep_funcs(epel_v, 8, 8, 24, sse4) +mc_rep_funcs(epel_v,10, 8, 64, sse4) +mc_rep_funcs(epel_v,10, 8, 48, sse4) +mc_rep_funcs(epel_v,10, 8, 32, sse4) +mc_rep_funcs(epel_v,10, 8, 24, sse4) +mc_rep_funcs(epel_v,10, 8, 16, sse4) +mc_rep_funcs(epel_v,10, 4, 12, sse4) +mc_rep_funcs(epel_v,12, 8, 64, sse4) +mc_rep_funcs(epel_v,12, 8, 48, sse4) +mc_rep_funcs(epel_v,12, 8, 32, sse4) +mc_rep_funcs(epel_v,12, 8, 24, sse4) +mc_rep_funcs(epel_v,12, 8, 16, sse4) +mc_rep_funcs(epel_v,12, 4, 12, sse4) +mc_rep_funcs(epel_hv, 8, 16, 64, sse4) +mc_rep_funcs(epel_hv, 8, 16, 48, sse4) +mc_rep_funcs(epel_hv, 8, 16, 32, sse4) +mc_rep_funcs(epel_hv, 8, 8, 24, sse4) +mc_rep_funcs2(epel_hv,8, 8, 4, 12, sse4) +mc_rep_funcs(epel_hv,10, 8, 64, sse4) +mc_rep_funcs(epel_hv,10, 8, 48, sse4) +mc_rep_funcs(epel_hv,10, 8, 32, sse4) +mc_rep_funcs(epel_hv,10, 8, 24, sse4) +mc_rep_funcs(epel_hv,10, 8, 16, sse4) +mc_rep_funcs(epel_hv,10, 4, 12, sse4) +mc_rep_funcs(epel_hv,12, 8, 64, sse4) +mc_rep_funcs(epel_hv,12, 8, 48, sse4) +mc_rep_funcs(epel_hv,12, 8, 32, sse4) +mc_rep_funcs(epel_hv,12, 8, 24, sse4) +mc_rep_funcs(epel_hv,12, 8, 16, sse4) +mc_rep_funcs(epel_hv,12, 4, 12, sse4) + +mc_rep_funcs(qpel_h, 8, 16, 64, sse4) +mc_rep_funcs(qpel_h, 8, 16, 48, sse4) +mc_rep_funcs(qpel_h, 8, 16, 32, sse4) +mc_rep_funcs(qpel_h, 8, 8, 24, sse4) +mc_rep_funcs(qpel_h,10, 8, 64, sse4) +mc_rep_funcs(qpel_h,10, 8, 48, sse4) +mc_rep_funcs(qpel_h,10, 8, 32, sse4) +mc_rep_funcs(qpel_h,10, 8, 24, sse4) +mc_rep_funcs(qpel_h,10, 8, 16, sse4) +mc_rep_funcs(qpel_h,10, 4, 12, sse4) +mc_rep_funcs(qpel_h,12, 8, 64, sse4) +mc_rep_funcs(qpel_h,12, 8, 48, sse4) +mc_rep_funcs(qpel_h,12, 8, 32, sse4) +mc_rep_funcs(qpel_h,12, 8, 24, sse4) +mc_rep_funcs(qpel_h,12, 8, 16, sse4) +mc_rep_funcs(qpel_h,12, 4, 12, sse4) +mc_rep_funcs(qpel_v, 8, 16, 64, sse4) +mc_rep_funcs(qpel_v, 8, 16, 48, sse4) +mc_rep_funcs(qpel_v, 8, 16, 32, sse4) +mc_rep_funcs(qpel_v, 8, 8, 24, sse4) +mc_rep_funcs(qpel_v,10, 8, 64, sse4) +mc_rep_funcs(qpel_v,10, 8, 48, sse4) +mc_rep_funcs(qpel_v,10, 8, 32, sse4) +mc_rep_funcs(qpel_v,10, 8, 24, sse4) +mc_rep_funcs(qpel_v,10, 8, 16, sse4) +mc_rep_funcs(qpel_v,10, 4, 12, sse4) +mc_rep_funcs(qpel_v,12, 8, 64, sse4) +mc_rep_funcs(qpel_v,12, 8, 48, sse4) +mc_rep_funcs(qpel_v,12, 8, 32, sse4) +mc_rep_funcs(qpel_v,12, 8, 24, sse4) +mc_rep_funcs(qpel_v,12, 8, 16, sse4) +mc_rep_funcs(qpel_v,12, 4, 12, sse4) +mc_rep_funcs(qpel_hv, 8, 8, 64, sse4) +mc_rep_funcs(qpel_hv, 8, 8, 48, sse4) +mc_rep_funcs(qpel_hv, 8, 8, 32, sse4) +mc_rep_funcs(qpel_hv, 8, 8, 24, sse4) +mc_rep_funcs(qpel_hv, 8, 8, 16, sse4) +mc_rep_funcs2(qpel_hv,8, 8, 4, 12, sse4) +mc_rep_funcs(qpel_hv,10, 8, 64, sse4) +mc_rep_funcs(qpel_hv,10, 8, 48, sse4) +mc_rep_funcs(qpel_hv,10, 8, 32, sse4) +mc_rep_funcs(qpel_hv,10, 8, 24, sse4) +mc_rep_funcs(qpel_hv,10, 8, 16, sse4) +mc_rep_funcs(qpel_hv,10, 4, 12, sse4) +mc_rep_funcs(qpel_hv,12, 8, 64, sse4) +mc_rep_funcs(qpel_hv,12, 8, 48, sse4) +mc_rep_funcs(qpel_hv,12, 8, 32, sse4) +mc_rep_funcs(qpel_hv,12, 8, 24, sse4) +mc_rep_funcs(qpel_hv,12, 8, 16, sse4) +mc_rep_funcs(qpel_hv,12, 4, 12, sse4) + +#define mc_rep_uni_w(bitd, step, W, opt) \ +void ff_hevc_put_hevc_uni_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, int16_t *_src, \ + int height, int denom, int _wx, int _ox) \ +{ \ + int i; \ + int16_t *src; \ + uint8_t *dst; \ + for (i = 0; i < W; i += step) { \ + src= _src + i; \ + dst= _dst + (i * ((bitd + 7) / 8)); \ + ff_hevc_put_hevc_uni_w##step##_##bitd##_##opt(dst, dststride, src, \ + height, denom, _wx, _ox); \ + } \ +} + +mc_rep_uni_w(8, 6, 12, sse4) +mc_rep_uni_w(8, 8, 16, sse4) +mc_rep_uni_w(8, 8, 24, sse4) +mc_rep_uni_w(8, 8, 32, sse4) +mc_rep_uni_w(8, 8, 48, sse4) +mc_rep_uni_w(8, 8, 64, sse4) + +mc_rep_uni_w(10, 6, 12, sse4) +mc_rep_uni_w(10, 8, 16, sse4) +mc_rep_uni_w(10, 8, 24, sse4) +mc_rep_uni_w(10, 8, 32, sse4) +mc_rep_uni_w(10, 8, 48, sse4) +mc_rep_uni_w(10, 8, 64, sse4) + +mc_rep_uni_w(12, 6, 12, sse4) +mc_rep_uni_w(12, 8, 16, sse4) +mc_rep_uni_w(12, 8, 24, sse4) +mc_rep_uni_w(12, 8, 32, sse4) +mc_rep_uni_w(12, 8, 48, sse4) +mc_rep_uni_w(12, 8, 64, sse4) + +#define mc_rep_bi_w(bitd, step, W, opt) \ +void ff_hevc_put_hevc_bi_w##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t dststride, int16_t *_src, \ + int16_t *_src2, int height, \ + int denom, int _wx0, int _wx1, int _ox0, int _ox1) \ +{ \ + int i; \ + int16_t *src; \ + int16_t *src2; \ + uint8_t *dst; \ + for (i = 0; i < W; i += step) { \ + src = _src + i; \ + src2 = _src2 + i; \ + dst = _dst + (i * ((bitd + 7) / 8)); \ + ff_hevc_put_hevc_bi_w##step##_##bitd##_##opt(dst, dststride, src, src2, \ + height, denom, _wx0, _wx1, _ox0, _ox1); \ + } \ +} + +mc_rep_bi_w(8, 6, 12, sse4) +mc_rep_bi_w(8, 8, 16, sse4) +mc_rep_bi_w(8, 8, 24, sse4) +mc_rep_bi_w(8, 8, 32, sse4) +mc_rep_bi_w(8, 8, 48, sse4) +mc_rep_bi_w(8, 8, 64, sse4) + +mc_rep_bi_w(10, 6, 12, sse4) +mc_rep_bi_w(10, 8, 16, sse4) +mc_rep_bi_w(10, 8, 24, sse4) +mc_rep_bi_w(10, 8, 32, sse4) +mc_rep_bi_w(10, 8, 48, sse4) +mc_rep_bi_w(10, 8, 64, sse4) + +mc_rep_bi_w(12, 6, 12, sse4) +mc_rep_bi_w(12, 8, 16, sse4) +mc_rep_bi_w(12, 8, 24, sse4) +mc_rep_bi_w(12, 8, 32, sse4) +mc_rep_bi_w(12, 8, 48, sse4) +mc_rep_bi_w(12, 8, 64, sse4) + +#define mc_uni_w_func(name, bitd, W, opt) \ +void ff_hevc_put_hevc_uni_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \ + uint8_t *_src, ptrdiff_t _srcstride, \ + int height, int denom, \ + int _wx, int _ox, \ + intptr_t mx, intptr_t my, int width) \ +{ \ + LOCAL_ALIGNED_16(int16_t, temp, [71 * MAX_PB_SIZE]); \ + ff_hevc_put_hevc_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \ + ff_hevc_put_hevc_uni_w##W##_##bitd##_##opt(_dst, _dststride, temp, height, denom, _wx, _ox);\ +} + +#define mc_uni_w_funcs(name, bitd, opt) \ + mc_uni_w_func(name, bitd, 4, opt) \ + mc_uni_w_func(name, bitd, 8, opt) \ + mc_uni_w_func(name, bitd, 12, opt) \ + mc_uni_w_func(name, bitd, 16, opt) \ + mc_uni_w_func(name, bitd, 24, opt) \ + mc_uni_w_func(name, bitd, 32, opt) \ + mc_uni_w_func(name, bitd, 48, opt) \ + mc_uni_w_func(name, bitd, 64, opt) + +mc_uni_w_funcs(pel_pixels, 8, sse4) +mc_uni_w_func(pel_pixels, 8, 6, sse4) +mc_uni_w_funcs(epel_h, 8, sse4) +mc_uni_w_func(epel_h, 8, 6, sse4) +mc_uni_w_funcs(epel_v, 8, sse4) +mc_uni_w_func(epel_v, 8, 6, sse4) +mc_uni_w_funcs(epel_hv, 8, sse4) +mc_uni_w_func(epel_hv, 8, 6, sse4) +mc_uni_w_funcs(qpel_h, 8, sse4) +mc_uni_w_funcs(qpel_v, 8, sse4) +mc_uni_w_funcs(qpel_hv, 8, sse4) + +mc_uni_w_funcs(pel_pixels, 10, sse4) +mc_uni_w_func(pel_pixels, 10, 6, sse4) +mc_uni_w_funcs(epel_h, 10, sse4) +mc_uni_w_func(epel_h, 10, 6, sse4) +mc_uni_w_funcs(epel_v, 10, sse4) +mc_uni_w_func(epel_v, 10, 6, sse4) +mc_uni_w_funcs(epel_hv, 10, sse4) +mc_uni_w_func(epel_hv, 10, 6, sse4) +mc_uni_w_funcs(qpel_h, 10, sse4) +mc_uni_w_funcs(qpel_v, 10, sse4) +mc_uni_w_funcs(qpel_hv, 10, sse4) + +mc_uni_w_funcs(pel_pixels, 12, sse4) +mc_uni_w_func(pel_pixels, 12, 6, sse4) +mc_uni_w_funcs(epel_h, 12, sse4) +mc_uni_w_func(epel_h, 12, 6, sse4) +mc_uni_w_funcs(epel_v, 12, sse4) +mc_uni_w_func(epel_v, 12, 6, sse4) +mc_uni_w_funcs(epel_hv, 12, sse4) +mc_uni_w_func(epel_hv, 12, 6, sse4) +mc_uni_w_funcs(qpel_h, 12, sse4) +mc_uni_w_funcs(qpel_v, 12, sse4) +mc_uni_w_funcs(qpel_hv, 12, sse4) + +#define mc_bi_w_func(name, bitd, W, opt) \ +void ff_hevc_put_hevc_bi_w_##name##W##_##bitd##_##opt(uint8_t *_dst, ptrdiff_t _dststride, \ + uint8_t *_src, ptrdiff_t _srcstride, \ + int16_t *_src2, \ + int height, int denom, \ + int _wx0, int _wx1, int _ox0, int _ox1, \ + intptr_t mx, intptr_t my, int width) \ +{ \ + LOCAL_ALIGNED_16(int16_t, temp, [71 * MAX_PB_SIZE]); \ + ff_hevc_put_hevc_##name##W##_##bitd##_##opt(temp, _src, _srcstride, height, mx, my, width); \ + ff_hevc_put_hevc_bi_w##W##_##bitd##_##opt(_dst, _dststride, temp, _src2, \ + height, denom, _wx0, _wx1, _ox0, _ox1); \ +} + +#define mc_bi_w_funcs(name, bitd, opt) \ + mc_bi_w_func(name, bitd, 4, opt) \ + mc_bi_w_func(name, bitd, 8, opt) \ + mc_bi_w_func(name, bitd, 12, opt) \ + mc_bi_w_func(name, bitd, 16, opt) \ + mc_bi_w_func(name, bitd, 24, opt) \ + mc_bi_w_func(name, bitd, 32, opt) \ + mc_bi_w_func(name, bitd, 48, opt) \ + mc_bi_w_func(name, bitd, 64, opt) + +mc_bi_w_funcs(pel_pixels, 8, sse4) +mc_bi_w_func(pel_pixels, 8, 6, sse4) +mc_bi_w_funcs(epel_h, 8, sse4) +mc_bi_w_func(epel_h, 8, 6, sse4) +mc_bi_w_funcs(epel_v, 8, sse4) +mc_bi_w_func(epel_v, 8, 6, sse4) +mc_bi_w_funcs(epel_hv, 8, sse4) +mc_bi_w_func(epel_hv, 8, 6, sse4) +mc_bi_w_funcs(qpel_h, 8, sse4) +mc_bi_w_funcs(qpel_v, 8, sse4) +mc_bi_w_funcs(qpel_hv, 8, sse4) + +mc_bi_w_funcs(pel_pixels, 10, sse4) +mc_bi_w_func(pel_pixels, 10, 6, sse4) +mc_bi_w_funcs(epel_h, 10, sse4) +mc_bi_w_func(epel_h, 10, 6, sse4) +mc_bi_w_funcs(epel_v, 10, sse4) +mc_bi_w_func(epel_v, 10, 6, sse4) +mc_bi_w_funcs(epel_hv, 10, sse4) +mc_bi_w_func(epel_hv, 10, 6, sse4) +mc_bi_w_funcs(qpel_h, 10, sse4) +mc_bi_w_funcs(qpel_v, 10, sse4) +mc_bi_w_funcs(qpel_hv, 10, sse4) + +mc_bi_w_funcs(pel_pixels, 12, sse4) +mc_bi_w_func(pel_pixels, 12, 6, sse4) +mc_bi_w_funcs(epel_h, 12, sse4) +mc_bi_w_func(epel_h, 12, 6, sse4) +mc_bi_w_funcs(epel_v, 12, sse4) +mc_bi_w_func(epel_v, 12, 6, sse4) +mc_bi_w_funcs(epel_hv, 12, sse4) +mc_bi_w_func(epel_hv, 12, 6, sse4) +mc_bi_w_funcs(qpel_h, 12, sse4) +mc_bi_w_funcs(qpel_v, 12, sse4) +mc_bi_w_funcs(qpel_hv, 12, sse4) +#endif //ARCH_X86_64 && HAVE_SSE4_EXTERNAL + +#define SAO_BAND_FILTER_FUNCS(bitd, opt) \ +void ff_hevc_sao_band_filter_8_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + int16_t *sao_offset_val, int sao_left_class, int width, int height); \ +void ff_hevc_sao_band_filter_16_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + int16_t *sao_offset_val, int sao_left_class, int width, int height); \ +void ff_hevc_sao_band_filter_32_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + int16_t *sao_offset_val, int sao_left_class, int width, int height); \ +void ff_hevc_sao_band_filter_48_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + int16_t *sao_offset_val, int sao_left_class, int width, int height); \ +void ff_hevc_sao_band_filter_64_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t _stride_dst, ptrdiff_t _stride_src, \ + int16_t *sao_offset_val, int sao_left_class, int width, int height); + +SAO_BAND_FILTER_FUNCS(8, sse2) +SAO_BAND_FILTER_FUNCS(10, sse2) +SAO_BAND_FILTER_FUNCS(12, sse2) +SAO_BAND_FILTER_FUNCS(8, avx) +SAO_BAND_FILTER_FUNCS(10, avx) +SAO_BAND_FILTER_FUNCS(12, avx) +SAO_BAND_FILTER_FUNCS(8, avx2) +SAO_BAND_FILTER_FUNCS(10, avx2) +SAO_BAND_FILTER_FUNCS(12, avx2) + +#define SAO_BAND_INIT(bitd, opt) do { \ + c->sao_band_filter[0] = ff_hevc_sao_band_filter_8_##bitd##_##opt; \ + c->sao_band_filter[1] = ff_hevc_sao_band_filter_16_##bitd##_##opt; \ + c->sao_band_filter[2] = ff_hevc_sao_band_filter_32_##bitd##_##opt; \ + c->sao_band_filter[3] = ff_hevc_sao_band_filter_48_##bitd##_##opt; \ + c->sao_band_filter[4] = ff_hevc_sao_band_filter_64_##bitd##_##opt; \ +} while (0) + +#define SAO_EDGE_FILTER_FUNCS(bitd, opt) \ +void ff_hevc_sao_edge_filter_8_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, \ + int eo, int width, int height); \ +void ff_hevc_sao_edge_filter_16_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, \ + int eo, int width, int height); \ +void ff_hevc_sao_edge_filter_32_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, \ + int eo, int width, int height); \ +void ff_hevc_sao_edge_filter_48_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, \ + int eo, int width, int height); \ +void ff_hevc_sao_edge_filter_64_##bitd##_##opt(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, \ + int eo, int width, int height); \ + +SAO_EDGE_FILTER_FUNCS(8, ssse3) +SAO_EDGE_FILTER_FUNCS(8, avx2) +SAO_EDGE_FILTER_FUNCS(10, sse2) +SAO_EDGE_FILTER_FUNCS(10, avx2) +SAO_EDGE_FILTER_FUNCS(12, sse2) +SAO_EDGE_FILTER_FUNCS(12, avx2) + +#define SAO_EDGE_INIT(bitd, opt) do { \ + c->sao_edge_filter[0] = ff_hevc_sao_edge_filter_8_##bitd##_##opt; \ + c->sao_edge_filter[1] = ff_hevc_sao_edge_filter_16_##bitd##_##opt; \ + c->sao_edge_filter[2] = ff_hevc_sao_edge_filter_32_##bitd##_##opt; \ + c->sao_edge_filter[3] = ff_hevc_sao_edge_filter_48_##bitd##_##opt; \ + c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_64_##bitd##_##opt; \ +} while (0) + +#define EPEL_LINKS(pointer, my, mx, fname, bitd, opt ) \ + PEL_LINK(pointer, 1, my , mx , fname##4 , bitd, opt ); \ + PEL_LINK(pointer, 2, my , mx , fname##6 , bitd, opt ); \ + PEL_LINK(pointer, 3, my , mx , fname##8 , bitd, opt ); \ + PEL_LINK(pointer, 4, my , mx , fname##12, bitd, opt ); \ + PEL_LINK(pointer, 5, my , mx , fname##16, bitd, opt ); \ + PEL_LINK(pointer, 6, my , mx , fname##24, bitd, opt ); \ + PEL_LINK(pointer, 7, my , mx , fname##32, bitd, opt ); \ + PEL_LINK(pointer, 8, my , mx , fname##48, bitd, opt ); \ + PEL_LINK(pointer, 9, my , mx , fname##64, bitd, opt ) +#define QPEL_LINKS(pointer, my, mx, fname, bitd, opt) \ + PEL_LINK(pointer, 1, my , mx , fname##4 , bitd, opt ); \ + PEL_LINK(pointer, 3, my , mx , fname##8 , bitd, opt ); \ + PEL_LINK(pointer, 4, my , mx , fname##12, bitd, opt ); \ + PEL_LINK(pointer, 5, my , mx , fname##16, bitd, opt ); \ + PEL_LINK(pointer, 6, my , mx , fname##24, bitd, opt ); \ + PEL_LINK(pointer, 7, my , mx , fname##32, bitd, opt ); \ + PEL_LINK(pointer, 8, my , mx , fname##48, bitd, opt ); \ + PEL_LINK(pointer, 9, my , mx , fname##64, bitd, opt ) + +void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth) +{ + int cpu_flags = av_get_cpu_flags(); + + if (bit_depth == 8) { + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->idct_dc[0] = ff_hevc_idct_4x4_dc_8_mmxext; + c->idct_dc[1] = ff_hevc_idct_8x8_dc_8_mmxext; + + c->add_residual[0] = ff_hevc_add_residual_4_8_mmxext; + } + if (EXTERNAL_SSE2(cpu_flags)) { + c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_8_sse2; + c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_8_sse2; + if (ARCH_X86_64) { + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_sse2; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_sse2; + + c->idct[2] = ff_hevc_idct_16x16_8_sse2; + c->idct[3] = ff_hevc_idct_32x32_8_sse2; + } + SAO_BAND_INIT(8, sse2); + + c->idct_dc[1] = ff_hevc_idct_8x8_dc_8_sse2; + c->idct_dc[2] = ff_hevc_idct_16x16_dc_8_sse2; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_8_sse2; + + c->idct[0] = ff_hevc_idct_4x4_8_sse2; + c->idct[1] = ff_hevc_idct_8x8_8_sse2; + + c->add_residual[1] = ff_hevc_add_residual_8_8_sse2; + c->add_residual[2] = ff_hevc_add_residual_16_8_sse2; + c->add_residual[3] = ff_hevc_add_residual_32_8_sse2; + } + if (EXTERNAL_SSSE3(cpu_flags)) { + if(ARCH_X86_64) { + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_ssse3; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_ssse3; + } + SAO_EDGE_INIT(8, ssse3); + } + if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) { + + EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 8, sse4); + EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 8, sse4); + EPEL_LINKS(c->put_hevc_epel, 1, 0, epel_v, 8, sse4); + EPEL_LINKS(c->put_hevc_epel, 1, 1, epel_hv, 8, sse4); + + QPEL_LINKS(c->put_hevc_qpel, 0, 0, pel_pixels, 8, sse4); + QPEL_LINKS(c->put_hevc_qpel, 0, 1, qpel_h, 8, sse4); + QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 8, sse4); + QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 8, sse4); + } + if (EXTERNAL_AVX(cpu_flags)) { + c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_8_avx; + c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_8_avx; + if (ARCH_X86_64) { + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_8_avx; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_8_avx; + + c->idct[2] = ff_hevc_idct_16x16_8_avx; + c->idct[3] = ff_hevc_idct_32x32_8_avx; + } + SAO_BAND_INIT(8, avx); + + c->idct[0] = ff_hevc_idct_4x4_8_avx; + c->idct[1] = ff_hevc_idct_8x8_8_avx; + + c->add_residual[1] = ff_hevc_add_residual_8_8_avx; + c->add_residual[2] = ff_hevc_add_residual_16_8_avx; + c->add_residual[3] = ff_hevc_add_residual_32_8_avx; + } + if (EXTERNAL_AVX2(cpu_flags)) { + c->sao_band_filter[0] = ff_hevc_sao_band_filter_8_8_avx2; + c->sao_band_filter[1] = ff_hevc_sao_band_filter_16_8_avx2; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->idct_dc[2] = ff_hevc_idct_16x16_dc_8_avx2; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_8_avx2; + if (ARCH_X86_64) { + c->put_hevc_epel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_8_avx2; + c->put_hevc_epel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_8_avx2; + c->put_hevc_epel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_8_avx2; + + c->put_hevc_qpel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_8_avx2; + c->put_hevc_qpel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_8_avx2; + c->put_hevc_qpel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_8_avx2; + + c->put_hevc_epel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; + c->put_hevc_epel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; + c->put_hevc_epel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; + + c->put_hevc_qpel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; + c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; + c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; + + c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_8_avx2; + c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_8_avx2; + c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_8_avx2; + + c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_8_avx2; + c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_8_avx2; + c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_8_avx2; + + c->put_hevc_epel[7][0][1] = ff_hevc_put_hevc_epel_h32_8_avx2; + c->put_hevc_epel[8][0][1] = ff_hevc_put_hevc_epel_h48_8_avx2; + c->put_hevc_epel[9][0][1] = ff_hevc_put_hevc_epel_h64_8_avx2; + + c->put_hevc_epel_uni[7][0][1] = ff_hevc_put_hevc_uni_epel_h32_8_avx2; + c->put_hevc_epel_uni[8][0][1] = ff_hevc_put_hevc_uni_epel_h48_8_avx2; + c->put_hevc_epel_uni[9][0][1] = ff_hevc_put_hevc_uni_epel_h64_8_avx2; + + c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_hevc_bi_epel_h32_8_avx2; + c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_hevc_bi_epel_h48_8_avx2; + c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_hevc_bi_epel_h64_8_avx2; + + c->put_hevc_epel[7][1][0] = ff_hevc_put_hevc_epel_v32_8_avx2; + c->put_hevc_epel[8][1][0] = ff_hevc_put_hevc_epel_v48_8_avx2; + c->put_hevc_epel[9][1][0] = ff_hevc_put_hevc_epel_v64_8_avx2; + + c->put_hevc_epel_uni[7][1][0] = ff_hevc_put_hevc_uni_epel_v32_8_avx2; + c->put_hevc_epel_uni[8][1][0] = ff_hevc_put_hevc_uni_epel_v48_8_avx2; + c->put_hevc_epel_uni[9][1][0] = ff_hevc_put_hevc_uni_epel_v64_8_avx2; + + c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_hevc_bi_epel_v32_8_avx2; + c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_hevc_bi_epel_v48_8_avx2; + c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_hevc_bi_epel_v64_8_avx2; + + c->put_hevc_epel[7][1][1] = ff_hevc_put_hevc_epel_hv32_8_avx2; + c->put_hevc_epel[8][1][1] = ff_hevc_put_hevc_epel_hv48_8_avx2; + c->put_hevc_epel[9][1][1] = ff_hevc_put_hevc_epel_hv64_8_avx2; + + c->put_hevc_epel_uni[7][1][1] = ff_hevc_put_hevc_uni_epel_hv32_8_avx2; + c->put_hevc_epel_uni[8][1][1] = ff_hevc_put_hevc_uni_epel_hv48_8_avx2; + c->put_hevc_epel_uni[9][1][1] = ff_hevc_put_hevc_uni_epel_hv64_8_avx2; + + c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_hevc_bi_epel_hv32_8_avx2; + c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_hevc_bi_epel_hv48_8_avx2; + c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_hevc_bi_epel_hv64_8_avx2; + + c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_8_avx2; + c->put_hevc_qpel[8][0][1] = ff_hevc_put_hevc_qpel_h48_8_avx2; + c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_8_avx2; + + c->put_hevc_qpel[7][1][0] = ff_hevc_put_hevc_qpel_v32_8_avx2; + c->put_hevc_qpel[8][1][0] = ff_hevc_put_hevc_qpel_v48_8_avx2; + c->put_hevc_qpel[9][1][0] = ff_hevc_put_hevc_qpel_v64_8_avx2; + + c->put_hevc_qpel_uni[7][0][1] = ff_hevc_put_hevc_uni_qpel_h32_8_avx2; + c->put_hevc_qpel_uni[8][0][1] = ff_hevc_put_hevc_uni_qpel_h48_8_avx2; + c->put_hevc_qpel_uni[9][0][1] = ff_hevc_put_hevc_uni_qpel_h64_8_avx2; + + c->put_hevc_qpel_uni[7][1][0] = ff_hevc_put_hevc_uni_qpel_v32_8_avx2; + c->put_hevc_qpel_uni[8][1][0] = ff_hevc_put_hevc_uni_qpel_v48_8_avx2; + c->put_hevc_qpel_uni[9][1][0] = ff_hevc_put_hevc_uni_qpel_v64_8_avx2; + + c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_hevc_bi_qpel_h32_8_avx2; + c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_hevc_bi_qpel_h48_8_avx2; + c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_hevc_bi_qpel_h64_8_avx2; + + c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_hevc_bi_qpel_v32_8_avx2; + c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_hevc_bi_qpel_v48_8_avx2; + c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_hevc_bi_qpel_v64_8_avx2; + } + SAO_BAND_INIT(8, avx2); + + c->sao_edge_filter[2] = ff_hevc_sao_edge_filter_32_8_avx2; + c->sao_edge_filter[3] = ff_hevc_sao_edge_filter_48_8_avx2; + c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_64_8_avx2; + + c->add_residual[3] = ff_hevc_add_residual_32_8_avx2; + } + } else if (bit_depth == 10) { + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->add_residual[0] = ff_hevc_add_residual_4_10_mmxext; + c->idct_dc[0] = ff_hevc_idct_4x4_dc_10_mmxext; + c->idct_dc[1] = ff_hevc_idct_8x8_dc_10_mmxext; + } + if (EXTERNAL_SSE2(cpu_flags)) { + c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_10_sse2; + c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_10_sse2; + if (ARCH_X86_64) { + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_sse2; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_sse2; + + c->idct[2] = ff_hevc_idct_16x16_10_sse2; + c->idct[3] = ff_hevc_idct_32x32_10_sse2; + } + SAO_BAND_INIT(10, sse2); + SAO_EDGE_INIT(10, sse2); + + c->idct_dc[1] = ff_hevc_idct_8x8_dc_10_sse2; + c->idct_dc[2] = ff_hevc_idct_16x16_dc_10_sse2; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_10_sse2; + + c->idct[0] = ff_hevc_idct_4x4_10_sse2; + c->idct[1] = ff_hevc_idct_8x8_10_sse2; + + c->add_residual[1] = ff_hevc_add_residual_8_10_sse2; + c->add_residual[2] = ff_hevc_add_residual_16_10_sse2; + c->add_residual[3] = ff_hevc_add_residual_32_10_sse2; + } + if (EXTERNAL_SSSE3(cpu_flags) && ARCH_X86_64) { + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_ssse3; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_ssse3; + } + if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) { + EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 10, sse4); + EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 10, sse4); + EPEL_LINKS(c->put_hevc_epel, 1, 0, epel_v, 10, sse4); + EPEL_LINKS(c->put_hevc_epel, 1, 1, epel_hv, 10, sse4); + + QPEL_LINKS(c->put_hevc_qpel, 0, 0, pel_pixels, 10, sse4); + QPEL_LINKS(c->put_hevc_qpel, 0, 1, qpel_h, 10, sse4); + QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 10, sse4); + QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 10, sse4); + } + if (EXTERNAL_AVX(cpu_flags)) { + c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_10_avx; + c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_10_avx; + if (ARCH_X86_64) { + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_10_avx; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_10_avx; + + c->idct[2] = ff_hevc_idct_16x16_10_avx; + c->idct[3] = ff_hevc_idct_32x32_10_avx; + } + + c->idct[0] = ff_hevc_idct_4x4_10_avx; + c->idct[1] = ff_hevc_idct_8x8_10_avx; + + SAO_BAND_INIT(10, avx); + } + if (EXTERNAL_AVX2(cpu_flags)) { + c->sao_band_filter[0] = ff_hevc_sao_band_filter_8_10_avx2; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->idct_dc[2] = ff_hevc_idct_16x16_dc_10_avx2; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_10_avx2; + if (ARCH_X86_64) { + c->put_hevc_epel[5][0][0] = ff_hevc_put_hevc_pel_pixels16_10_avx2; + c->put_hevc_epel[6][0][0] = ff_hevc_put_hevc_pel_pixels24_10_avx2; + c->put_hevc_epel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_10_avx2; + c->put_hevc_epel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_10_avx2; + c->put_hevc_epel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_10_avx2; + + c->put_hevc_qpel[5][0][0] = ff_hevc_put_hevc_pel_pixels16_10_avx2; + c->put_hevc_qpel[6][0][0] = ff_hevc_put_hevc_pel_pixels24_10_avx2; + c->put_hevc_qpel[7][0][0] = ff_hevc_put_hevc_pel_pixels32_10_avx2; + c->put_hevc_qpel[8][0][0] = ff_hevc_put_hevc_pel_pixels48_10_avx2; + c->put_hevc_qpel[9][0][0] = ff_hevc_put_hevc_pel_pixels64_10_avx2; + + c->put_hevc_epel_uni[5][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; + c->put_hevc_epel_uni[6][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; + c->put_hevc_epel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; + c->put_hevc_epel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels96_8_avx2; + c->put_hevc_epel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels128_8_avx2; + + c->put_hevc_qpel_uni[5][0][0] = ff_hevc_put_hevc_uni_pel_pixels32_8_avx2; + c->put_hevc_qpel_uni[6][0][0] = ff_hevc_put_hevc_uni_pel_pixels48_8_avx2; + c->put_hevc_qpel_uni[7][0][0] = ff_hevc_put_hevc_uni_pel_pixels64_8_avx2; + c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_hevc_uni_pel_pixels96_8_avx2; + c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_hevc_uni_pel_pixels128_8_avx2; + + c->put_hevc_epel_bi[5][0][0] = ff_hevc_put_hevc_bi_pel_pixels16_10_avx2; + c->put_hevc_epel_bi[6][0][0] = ff_hevc_put_hevc_bi_pel_pixels24_10_avx2; + c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_10_avx2; + c->put_hevc_epel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_10_avx2; + c->put_hevc_epel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_10_avx2; + c->put_hevc_qpel_bi[5][0][0] = ff_hevc_put_hevc_bi_pel_pixels16_10_avx2; + c->put_hevc_qpel_bi[6][0][0] = ff_hevc_put_hevc_bi_pel_pixels24_10_avx2; + c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_hevc_bi_pel_pixels32_10_avx2; + c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_hevc_bi_pel_pixels48_10_avx2; + c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_hevc_bi_pel_pixels64_10_avx2; + + c->put_hevc_epel[5][0][1] = ff_hevc_put_hevc_epel_h16_10_avx2; + c->put_hevc_epel[6][0][1] = ff_hevc_put_hevc_epel_h24_10_avx2; + c->put_hevc_epel[7][0][1] = ff_hevc_put_hevc_epel_h32_10_avx2; + c->put_hevc_epel[8][0][1] = ff_hevc_put_hevc_epel_h48_10_avx2; + c->put_hevc_epel[9][0][1] = ff_hevc_put_hevc_epel_h64_10_avx2; + + c->put_hevc_epel_uni[5][0][1] = ff_hevc_put_hevc_uni_epel_h16_10_avx2; + c->put_hevc_epel_uni[6][0][1] = ff_hevc_put_hevc_uni_epel_h24_10_avx2; + c->put_hevc_epel_uni[7][0][1] = ff_hevc_put_hevc_uni_epel_h32_10_avx2; + c->put_hevc_epel_uni[8][0][1] = ff_hevc_put_hevc_uni_epel_h48_10_avx2; + c->put_hevc_epel_uni[9][0][1] = ff_hevc_put_hevc_uni_epel_h64_10_avx2; + + c->put_hevc_epel_bi[5][0][1] = ff_hevc_put_hevc_bi_epel_h16_10_avx2; + c->put_hevc_epel_bi[6][0][1] = ff_hevc_put_hevc_bi_epel_h24_10_avx2; + c->put_hevc_epel_bi[7][0][1] = ff_hevc_put_hevc_bi_epel_h32_10_avx2; + c->put_hevc_epel_bi[8][0][1] = ff_hevc_put_hevc_bi_epel_h48_10_avx2; + c->put_hevc_epel_bi[9][0][1] = ff_hevc_put_hevc_bi_epel_h64_10_avx2; + + c->put_hevc_epel[5][1][0] = ff_hevc_put_hevc_epel_v16_10_avx2; + c->put_hevc_epel[6][1][0] = ff_hevc_put_hevc_epel_v24_10_avx2; + c->put_hevc_epel[7][1][0] = ff_hevc_put_hevc_epel_v32_10_avx2; + c->put_hevc_epel[8][1][0] = ff_hevc_put_hevc_epel_v48_10_avx2; + c->put_hevc_epel[9][1][0] = ff_hevc_put_hevc_epel_v64_10_avx2; + + c->put_hevc_epel_uni[5][1][0] = ff_hevc_put_hevc_uni_epel_v16_10_avx2; + c->put_hevc_epel_uni[6][1][0] = ff_hevc_put_hevc_uni_epel_v24_10_avx2; + c->put_hevc_epel_uni[7][1][0] = ff_hevc_put_hevc_uni_epel_v32_10_avx2; + c->put_hevc_epel_uni[8][1][0] = ff_hevc_put_hevc_uni_epel_v48_10_avx2; + c->put_hevc_epel_uni[9][1][0] = ff_hevc_put_hevc_uni_epel_v64_10_avx2; + + c->put_hevc_epel_bi[5][1][0] = ff_hevc_put_hevc_bi_epel_v16_10_avx2; + c->put_hevc_epel_bi[6][1][0] = ff_hevc_put_hevc_bi_epel_v24_10_avx2; + c->put_hevc_epel_bi[7][1][0] = ff_hevc_put_hevc_bi_epel_v32_10_avx2; + c->put_hevc_epel_bi[8][1][0] = ff_hevc_put_hevc_bi_epel_v48_10_avx2; + c->put_hevc_epel_bi[9][1][0] = ff_hevc_put_hevc_bi_epel_v64_10_avx2; + + c->put_hevc_epel[5][1][1] = ff_hevc_put_hevc_epel_hv16_10_avx2; + c->put_hevc_epel[6][1][1] = ff_hevc_put_hevc_epel_hv24_10_avx2; + c->put_hevc_epel[7][1][1] = ff_hevc_put_hevc_epel_hv32_10_avx2; + c->put_hevc_epel[8][1][1] = ff_hevc_put_hevc_epel_hv48_10_avx2; + c->put_hevc_epel[9][1][1] = ff_hevc_put_hevc_epel_hv64_10_avx2; + + c->put_hevc_epel_uni[5][1][1] = ff_hevc_put_hevc_uni_epel_hv16_10_avx2; + c->put_hevc_epel_uni[6][1][1] = ff_hevc_put_hevc_uni_epel_hv24_10_avx2; + c->put_hevc_epel_uni[7][1][1] = ff_hevc_put_hevc_uni_epel_hv32_10_avx2; + c->put_hevc_epel_uni[8][1][1] = ff_hevc_put_hevc_uni_epel_hv48_10_avx2; + c->put_hevc_epel_uni[9][1][1] = ff_hevc_put_hevc_uni_epel_hv64_10_avx2; + + c->put_hevc_epel_bi[5][1][1] = ff_hevc_put_hevc_bi_epel_hv16_10_avx2; + c->put_hevc_epel_bi[6][1][1] = ff_hevc_put_hevc_bi_epel_hv24_10_avx2; + c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_hevc_bi_epel_hv32_10_avx2; + c->put_hevc_epel_bi[8][1][1] = ff_hevc_put_hevc_bi_epel_hv48_10_avx2; + c->put_hevc_epel_bi[9][1][1] = ff_hevc_put_hevc_bi_epel_hv64_10_avx2; + + c->put_hevc_qpel[5][0][1] = ff_hevc_put_hevc_qpel_h16_10_avx2; + c->put_hevc_qpel[6][0][1] = ff_hevc_put_hevc_qpel_h24_10_avx2; + c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_10_avx2; + c->put_hevc_qpel[8][0][1] = ff_hevc_put_hevc_qpel_h48_10_avx2; + c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_10_avx2; + + c->put_hevc_qpel_uni[5][0][1] = ff_hevc_put_hevc_uni_qpel_h16_10_avx2; + c->put_hevc_qpel_uni[6][0][1] = ff_hevc_put_hevc_uni_qpel_h24_10_avx2; + c->put_hevc_qpel_uni[7][0][1] = ff_hevc_put_hevc_uni_qpel_h32_10_avx2; + c->put_hevc_qpel_uni[8][0][1] = ff_hevc_put_hevc_uni_qpel_h48_10_avx2; + c->put_hevc_qpel_uni[9][0][1] = ff_hevc_put_hevc_uni_qpel_h64_10_avx2; + + c->put_hevc_qpel_bi[5][0][1] = ff_hevc_put_hevc_bi_qpel_h16_10_avx2; + c->put_hevc_qpel_bi[6][0][1] = ff_hevc_put_hevc_bi_qpel_h24_10_avx2; + c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_hevc_bi_qpel_h32_10_avx2; + c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_hevc_bi_qpel_h48_10_avx2; + c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_hevc_bi_qpel_h64_10_avx2; + + c->put_hevc_qpel[5][1][0] = ff_hevc_put_hevc_qpel_v16_10_avx2; + c->put_hevc_qpel[6][1][0] = ff_hevc_put_hevc_qpel_v24_10_avx2; + c->put_hevc_qpel[7][1][0] = ff_hevc_put_hevc_qpel_v32_10_avx2; + c->put_hevc_qpel[8][1][0] = ff_hevc_put_hevc_qpel_v48_10_avx2; + c->put_hevc_qpel[9][1][0] = ff_hevc_put_hevc_qpel_v64_10_avx2; + + c->put_hevc_qpel_uni[5][1][0] = ff_hevc_put_hevc_uni_qpel_v16_10_avx2; + c->put_hevc_qpel_uni[6][1][0] = ff_hevc_put_hevc_uni_qpel_v24_10_avx2; + c->put_hevc_qpel_uni[7][1][0] = ff_hevc_put_hevc_uni_qpel_v32_10_avx2; + c->put_hevc_qpel_uni[8][1][0] = ff_hevc_put_hevc_uni_qpel_v48_10_avx2; + c->put_hevc_qpel_uni[9][1][0] = ff_hevc_put_hevc_uni_qpel_v64_10_avx2; + + c->put_hevc_qpel_bi[5][1][0] = ff_hevc_put_hevc_bi_qpel_v16_10_avx2; + c->put_hevc_qpel_bi[6][1][0] = ff_hevc_put_hevc_bi_qpel_v24_10_avx2; + c->put_hevc_qpel_bi[7][1][0] = ff_hevc_put_hevc_bi_qpel_v32_10_avx2; + c->put_hevc_qpel_bi[8][1][0] = ff_hevc_put_hevc_bi_qpel_v48_10_avx2; + c->put_hevc_qpel_bi[9][1][0] = ff_hevc_put_hevc_bi_qpel_v64_10_avx2; + + c->put_hevc_qpel[5][1][1] = ff_hevc_put_hevc_qpel_hv16_10_avx2; + c->put_hevc_qpel[6][1][1] = ff_hevc_put_hevc_qpel_hv24_10_avx2; + c->put_hevc_qpel[7][1][1] = ff_hevc_put_hevc_qpel_hv32_10_avx2; + c->put_hevc_qpel[8][1][1] = ff_hevc_put_hevc_qpel_hv48_10_avx2; + c->put_hevc_qpel[9][1][1] = ff_hevc_put_hevc_qpel_hv64_10_avx2; + + c->put_hevc_qpel_uni[5][1][1] = ff_hevc_put_hevc_uni_qpel_hv16_10_avx2; + c->put_hevc_qpel_uni[6][1][1] = ff_hevc_put_hevc_uni_qpel_hv24_10_avx2; + c->put_hevc_qpel_uni[7][1][1] = ff_hevc_put_hevc_uni_qpel_hv32_10_avx2; + c->put_hevc_qpel_uni[8][1][1] = ff_hevc_put_hevc_uni_qpel_hv48_10_avx2; + c->put_hevc_qpel_uni[9][1][1] = ff_hevc_put_hevc_uni_qpel_hv64_10_avx2; + + c->put_hevc_qpel_bi[5][1][1] = ff_hevc_put_hevc_bi_qpel_hv16_10_avx2; + c->put_hevc_qpel_bi[6][1][1] = ff_hevc_put_hevc_bi_qpel_hv24_10_avx2; + c->put_hevc_qpel_bi[7][1][1] = ff_hevc_put_hevc_bi_qpel_hv32_10_avx2; + c->put_hevc_qpel_bi[8][1][1] = ff_hevc_put_hevc_bi_qpel_hv48_10_avx2; + c->put_hevc_qpel_bi[9][1][1] = ff_hevc_put_hevc_bi_qpel_hv64_10_avx2; + } + SAO_BAND_INIT(10, avx2); + SAO_EDGE_INIT(10, avx2); + + c->add_residual[2] = ff_hevc_add_residual_16_10_avx2; + c->add_residual[3] = ff_hevc_add_residual_32_10_avx2; + } + } else if (bit_depth == 12) { + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->idct_dc[0] = ff_hevc_idct_4x4_dc_12_mmxext; + c->idct_dc[1] = ff_hevc_idct_8x8_dc_12_mmxext; + } + if (EXTERNAL_SSE2(cpu_flags)) { + c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_12_sse2; + c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_12_sse2; + if (ARCH_X86_64) { + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_sse2; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_sse2; + } + SAO_BAND_INIT(12, sse2); + SAO_EDGE_INIT(12, sse2); + + c->idct_dc[1] = ff_hevc_idct_8x8_dc_12_sse2; + c->idct_dc[2] = ff_hevc_idct_16x16_dc_12_sse2; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_12_sse2; + } + if (EXTERNAL_SSSE3(cpu_flags) && ARCH_X86_64) { + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_ssse3; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_ssse3; + } + if (EXTERNAL_SSE4(cpu_flags) && ARCH_X86_64) { + EPEL_LINKS(c->put_hevc_epel, 0, 0, pel_pixels, 12, sse4); + EPEL_LINKS(c->put_hevc_epel, 0, 1, epel_h, 12, sse4); + EPEL_LINKS(c->put_hevc_epel, 1, 0, epel_v, 12, sse4); + EPEL_LINKS(c->put_hevc_epel, 1, 1, epel_hv, 12, sse4); + + QPEL_LINKS(c->put_hevc_qpel, 0, 0, pel_pixels, 12, sse4); + QPEL_LINKS(c->put_hevc_qpel, 0, 1, qpel_h, 12, sse4); + QPEL_LINKS(c->put_hevc_qpel, 1, 0, qpel_v, 12, sse4); + QPEL_LINKS(c->put_hevc_qpel, 1, 1, qpel_hv, 12, sse4); + } + if (EXTERNAL_AVX(cpu_flags)) { + c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_12_avx; + c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_12_avx; + if (ARCH_X86_64) { + c->hevc_v_loop_filter_luma = ff_hevc_v_loop_filter_luma_12_avx; + c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_12_avx; + } + SAO_BAND_INIT(12, avx); + } + if (EXTERNAL_AVX2(cpu_flags)) { + c->sao_band_filter[0] = ff_hevc_sao_band_filter_8_12_avx2; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->idct_dc[2] = ff_hevc_idct_16x16_dc_12_avx2; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_12_avx2; + + SAO_BAND_INIT(12, avx2); + SAO_EDGE_INIT(12, avx2); + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp.h new file mode 100644 index 0000000000..bf97029b57 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp.h @@ -0,0 +1,57 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_HPELDSP_H +#define AVCODEC_X86_HPELDSP_H + +#include +#include + +#include "libavcodec/hpeldsp.h" + +void ff_avg_pixels8_x2_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); + +void ff_avg_pixels8_xy2_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_xy2_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_xy2_ssse3(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); + +void ff_avg_pixels16_xy2_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_xy2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_xy2_ssse3(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); + +void ff_put_pixels8_xy2_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_xy2_ssse3(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_xy2_mmx(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_xy2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_xy2_ssse3(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); + +void ff_hpeldsp_vp3_init_x86(HpelDSPContext *c, int cpu_flags, int flags); + +#endif /* AVCODEC_X86_HPELDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_init.c new file mode 100644 index 0000000000..d89928cec6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_init.c @@ -0,0 +1,313 @@ +/* + * SIMD-optimized halfpel functions + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * MMX optimization by Nick Kurshev + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/hpeldsp.h" +#include "libavcodec/pixels.h" +#include "fpel.h" +#include "hpeldsp.h" + +void ff_put_pixels8_x2_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_x2_3dnow(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_x2_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_x2_3dnow(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_x2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_x2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels16_y2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels16_y2_sse2(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels8_x2_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels8_x2_3dnow(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_y2_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_pixels8_y2_3dnow(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels8_y2_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels8_y2_3dnow(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_3dnow(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_x2_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_x2_3dnow(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_y2_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_y2_3dnow(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_pixels8_xy2_3dnow(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_approx_pixels8_xy2_mmxext(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_avg_approx_pixels8_xy2_3dnow(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h); + +#define avg_pixels8_mmx ff_avg_pixels8_mmx +#define avg_pixels8_x2_mmx ff_avg_pixels8_x2_mmx +#define avg_pixels16_mmx ff_avg_pixels16_mmx +#define avg_pixels8_xy2_mmx ff_avg_pixels8_xy2_mmx +#define avg_pixels16_xy2_mmx ff_avg_pixels16_xy2_mmx +#define put_pixels8_mmx ff_put_pixels8_mmx +#define put_pixels16_mmx ff_put_pixels16_mmx +#define put_pixels8_xy2_mmx ff_put_pixels8_xy2_mmx +#define put_pixels16_xy2_mmx ff_put_pixels16_xy2_mmx +#define avg_no_rnd_pixels16_mmx ff_avg_pixels16_mmx +#define put_no_rnd_pixels8_mmx ff_put_pixels8_mmx +#define put_no_rnd_pixels16_mmx ff_put_pixels16_mmx + +#if HAVE_INLINE_ASM + +/***********************************/ +/* MMX no rounding */ +#define DEF(x, y) x ## _no_rnd_ ## y ## _mmx +#define SET_RND MOVQ_WONE +#define PAVGBP(a, b, c, d, e, f) PAVGBP_MMX_NO_RND(a, b, c, d, e, f) +#define PAVGB(a, b, c, e) PAVGB_MMX_NO_RND(a, b, c, e) +#define STATIC static + +#include "rnd_template.c" +#include "hpeldsp_rnd_template.c" + +#undef DEF +#undef SET_RND +#undef PAVGBP +#undef PAVGB +#undef STATIC + +#if HAVE_MMX +CALL_2X_PIXELS(avg_no_rnd_pixels16_y2_mmx, avg_no_rnd_pixels8_y2_mmx, 8) +CALL_2X_PIXELS(put_no_rnd_pixels16_y2_mmx, put_no_rnd_pixels8_y2_mmx, 8) + +CALL_2X_PIXELS(avg_no_rnd_pixels16_xy2_mmx, avg_no_rnd_pixels8_xy2_mmx, 8) +CALL_2X_PIXELS(put_no_rnd_pixels16_xy2_mmx, put_no_rnd_pixels8_xy2_mmx, 8) +#endif + +/***********************************/ +/* MMX rounding */ + +#define DEF(x, y) x ## _ ## y ## _mmx +#define SET_RND MOVQ_WTWO +#define PAVGBP(a, b, c, d, e, f) PAVGBP_MMX(a, b, c, d, e, f) +#define PAVGB(a, b, c, e) PAVGB_MMX(a, b, c, e) + +#include "hpeldsp_rnd_template.c" + +#undef DEF +#define DEF(x, y) ff_ ## x ## _ ## y ## _mmx +#define STATIC + +#include "rnd_template.c" + +#undef DEF +#undef SET_RND +#undef PAVGBP +#undef PAVGB + +#if HAVE_MMX +CALL_2X_PIXELS(avg_pixels16_y2_mmx, avg_pixels8_y2_mmx, 8) +CALL_2X_PIXELS(put_pixels16_y2_mmx, put_pixels8_y2_mmx, 8) + +CALL_2X_PIXELS_EXPORT(ff_avg_pixels16_xy2_mmx, ff_avg_pixels8_xy2_mmx, 8) +CALL_2X_PIXELS_EXPORT(ff_put_pixels16_xy2_mmx, ff_put_pixels8_xy2_mmx, 8) +#endif + +#endif /* HAVE_INLINE_ASM */ + + +#if HAVE_X86ASM + +#define HPELDSP_AVG_PIXELS16(CPUEXT) \ + CALL_2X_PIXELS(put_no_rnd_pixels16_x2 ## CPUEXT, ff_put_no_rnd_pixels8_x2 ## CPUEXT, 8) \ + CALL_2X_PIXELS(put_pixels16_y2 ## CPUEXT, ff_put_pixels8_y2 ## CPUEXT, 8) \ + CALL_2X_PIXELS(put_no_rnd_pixels16_y2 ## CPUEXT, ff_put_no_rnd_pixels8_y2 ## CPUEXT, 8) \ + CALL_2X_PIXELS(avg_pixels16 ## CPUEXT, ff_avg_pixels8 ## CPUEXT, 8) \ + CALL_2X_PIXELS(avg_pixels16_x2 ## CPUEXT, ff_avg_pixels8_x2 ## CPUEXT, 8) \ + CALL_2X_PIXELS(avg_pixels16_y2 ## CPUEXT, ff_avg_pixels8_y2 ## CPUEXT, 8) \ + CALL_2X_PIXELS(avg_pixels16_xy2 ## CPUEXT, ff_avg_pixels8_xy2 ## CPUEXT, 8) \ + CALL_2X_PIXELS(avg_approx_pixels16_xy2## CPUEXT, ff_avg_approx_pixels8_xy2## CPUEXT, 8) + +HPELDSP_AVG_PIXELS16(_3dnow) +HPELDSP_AVG_PIXELS16(_mmxext) + +#endif /* HAVE_X86ASM */ + +#define SET_HPEL_FUNCS_EXT(PFX, IDX, SIZE, CPU) \ + if (HAVE_MMX_EXTERNAL) \ + c->PFX ## _pixels_tab IDX [0] = PFX ## _pixels ## SIZE ## _ ## CPU; + +#if HAVE_MMX_INLINE +#define SET_HPEL_FUNCS(PFX, IDX, SIZE, CPU) \ + do { \ + SET_HPEL_FUNCS_EXT(PFX, IDX, SIZE, CPU) \ + c->PFX ## _pixels_tab IDX [1] = PFX ## _pixels ## SIZE ## _x2_ ## CPU; \ + c->PFX ## _pixels_tab IDX [2] = PFX ## _pixels ## SIZE ## _y2_ ## CPU; \ + c->PFX ## _pixels_tab IDX [3] = PFX ## _pixels ## SIZE ## _xy2_ ## CPU; \ + } while (0) +#else +#define SET_HPEL_FUNCS(PFX, IDX, SIZE, CPU) \ + do { \ + SET_HPEL_FUNCS_EXT(PFX, IDX, SIZE, CPU) \ + } while (0) +#endif + +static void hpeldsp_init_mmx(HpelDSPContext *c, int flags) +{ + SET_HPEL_FUNCS(put, [0], 16, mmx); + SET_HPEL_FUNCS(put_no_rnd, [0], 16, mmx); + SET_HPEL_FUNCS(avg, [0], 16, mmx); + SET_HPEL_FUNCS(avg_no_rnd, , 16, mmx); + SET_HPEL_FUNCS(put, [1], 8, mmx); + SET_HPEL_FUNCS(put_no_rnd, [1], 8, mmx); + if (HAVE_MMX_EXTERNAL) { + c->avg_pixels_tab[1][0] = ff_avg_pixels8_mmx; + c->avg_pixels_tab[1][1] = ff_avg_pixels8_x2_mmx; + } +#if HAVE_MMX_INLINE + c->avg_pixels_tab[1][2] = avg_pixels8_y2_mmx; + c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_mmx; +#endif +} + +static void hpeldsp_init_mmxext(HpelDSPContext *c, int flags) +{ +#if HAVE_MMXEXT_EXTERNAL + c->put_pixels_tab[0][1] = ff_put_pixels16_x2_mmxext; + c->put_pixels_tab[0][2] = put_pixels16_y2_mmxext; + + c->avg_pixels_tab[0][0] = avg_pixels16_mmxext; + c->avg_pixels_tab[0][1] = avg_pixels16_x2_mmxext; + c->avg_pixels_tab[0][2] = avg_pixels16_y2_mmxext; + c->avg_pixels_tab[0][3] = avg_pixels16_xy2_mmxext; + + c->put_pixels_tab[1][1] = ff_put_pixels8_x2_mmxext; + c->put_pixels_tab[1][2] = ff_put_pixels8_y2_mmxext; + + c->avg_pixels_tab[1][0] = ff_avg_pixels8_mmxext; + c->avg_pixels_tab[1][1] = ff_avg_pixels8_x2_mmxext; + c->avg_pixels_tab[1][2] = ff_avg_pixels8_y2_mmxext; + c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_mmxext; + + if (!(flags & AV_CODEC_FLAG_BITEXACT)) { + c->put_no_rnd_pixels_tab[0][1] = put_no_rnd_pixels16_x2_mmxext; + c->put_no_rnd_pixels_tab[0][2] = put_no_rnd_pixels16_y2_mmxext; + c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_mmxext; + c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_mmxext; + + c->avg_pixels_tab[0][3] = avg_approx_pixels16_xy2_mmxext; + c->avg_pixels_tab[1][3] = ff_avg_approx_pixels8_xy2_mmxext; + } +#endif /* HAVE_MMXEXT_EXTERNAL */ +} + +static void hpeldsp_init_3dnow(HpelDSPContext *c, int flags) +{ +#if HAVE_AMD3DNOW_EXTERNAL + c->put_pixels_tab[0][1] = ff_put_pixels16_x2_3dnow; + c->put_pixels_tab[0][2] = put_pixels16_y2_3dnow; + + c->avg_pixels_tab[0][0] = avg_pixels16_3dnow; + c->avg_pixels_tab[0][1] = avg_pixels16_x2_3dnow; + c->avg_pixels_tab[0][2] = avg_pixels16_y2_3dnow; + c->avg_pixels_tab[0][3] = avg_pixels16_xy2_3dnow; + + c->put_pixels_tab[1][1] = ff_put_pixels8_x2_3dnow; + c->put_pixels_tab[1][2] = ff_put_pixels8_y2_3dnow; + + c->avg_pixels_tab[1][0] = ff_avg_pixels8_3dnow; + c->avg_pixels_tab[1][1] = ff_avg_pixels8_x2_3dnow; + c->avg_pixels_tab[1][2] = ff_avg_pixels8_y2_3dnow; + c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_3dnow; + + if (!(flags & AV_CODEC_FLAG_BITEXACT)){ + c->put_no_rnd_pixels_tab[0][1] = put_no_rnd_pixels16_x2_3dnow; + c->put_no_rnd_pixels_tab[0][2] = put_no_rnd_pixels16_y2_3dnow; + c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_3dnow; + c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_3dnow; + + c->avg_pixels_tab[0][3] = avg_approx_pixels16_xy2_3dnow; + c->avg_pixels_tab[1][3] = ff_avg_approx_pixels8_xy2_3dnow; + } +#endif /* HAVE_AMD3DNOW_EXTERNAL */ +} + +static void hpeldsp_init_sse2_fast(HpelDSPContext *c, int flags) +{ +#if HAVE_SSE2_EXTERNAL + c->put_pixels_tab[0][0] = ff_put_pixels16_sse2; + c->put_no_rnd_pixels_tab[0][0] = ff_put_pixels16_sse2; + c->put_pixels_tab[0][1] = ff_put_pixels16_x2_sse2; + c->put_pixels_tab[0][2] = ff_put_pixels16_y2_sse2; + c->put_pixels_tab[0][3] = ff_put_pixels16_xy2_sse2; + c->avg_pixels_tab[0][0] = ff_avg_pixels16_sse2; + c->avg_pixels_tab[0][1] = ff_avg_pixels16_x2_sse2; + c->avg_pixels_tab[0][2] = ff_avg_pixels16_y2_sse2; + c->avg_pixels_tab[0][3] = ff_avg_pixels16_xy2_sse2; +#endif /* HAVE_SSE2_EXTERNAL */ +} + +static void hpeldsp_init_ssse3(HpelDSPContext *c, int flags) +{ +#if HAVE_SSSE3_EXTERNAL + c->put_pixels_tab[0][3] = ff_put_pixels16_xy2_ssse3; + c->avg_pixels_tab[0][3] = ff_avg_pixels16_xy2_ssse3; + c->put_pixels_tab[1][3] = ff_put_pixels8_xy2_ssse3; + c->avg_pixels_tab[1][3] = ff_avg_pixels8_xy2_ssse3; +#endif +} + +av_cold void ff_hpeldsp_init_x86(HpelDSPContext *c, int flags) +{ + int cpu_flags = av_get_cpu_flags(); + + if (INLINE_MMX(cpu_flags)) + hpeldsp_init_mmx(c, flags); + + if (EXTERNAL_AMD3DNOW(cpu_flags)) + hpeldsp_init_3dnow(c, flags); + + if (EXTERNAL_MMXEXT(cpu_flags)) + hpeldsp_init_mmxext(c, flags); + + if (EXTERNAL_SSE2_FAST(cpu_flags)) + hpeldsp_init_sse2_fast(c, flags); + + if (EXTERNAL_SSSE3(cpu_flags)) + hpeldsp_init_ssse3(c, flags); + + if (CONFIG_VP3_DECODER) + ff_hpeldsp_vp3_init_x86(c, cpu_flags, flags); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_rnd_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_rnd_template.c new file mode 100644 index 0000000000..2bff2d2766 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_rnd_template.c @@ -0,0 +1,202 @@ +/* + * SIMD-optimized halfpel functions are compiled twice for rnd/no_rnd + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2003-2004 Michael Niedermayer + * + * MMX optimization by Nick Kurshev + * mostly rewritten by Michael Niedermayer + * and improved by Zdenek Kabelac + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +// put_pixels +av_unused static void DEF(put, pixels8_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +{ + MOVQ_BFE(mm6); + __asm__ volatile( + "lea (%3, %3), %%"FF_REG_a" \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm1 \n\t" + "movq (%1, %3), %%mm2 \n\t" + "movq 1(%1, %3), %%mm3 \n\t" + PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm1 \n\t" + "movq (%1, %3), %%mm2 \n\t" + "movq 1(%1, %3), %%mm3 \n\t" + PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "subl $4, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels), "+D"(block) + :"r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} + +av_unused static void DEF(put, pixels16_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +{ + MOVQ_BFE(mm6); + __asm__ volatile( + "lea (%3, %3), %%"FF_REG_a" \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm1 \n\t" + "movq (%1, %3), %%mm2 \n\t" + "movq 1(%1, %3), %%mm3 \n\t" + PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "movq 8(%1), %%mm0 \n\t" + "movq 9(%1), %%mm1 \n\t" + "movq 8(%1, %3), %%mm2 \n\t" + "movq 9(%1, %3), %%mm3 \n\t" + PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, 8(%2) \n\t" + "movq %%mm5, 8(%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm1 \n\t" + "movq (%1, %3), %%mm2 \n\t" + "movq 1(%1, %3), %%mm3 \n\t" + PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "movq 8(%1), %%mm0 \n\t" + "movq 9(%1), %%mm1 \n\t" + "movq 8(%1, %3), %%mm2 \n\t" + "movq 9(%1, %3), %%mm3 \n\t" + PAVGBP(%%mm0, %%mm1, %%mm4, %%mm2, %%mm3, %%mm5) + "movq %%mm4, 8(%2) \n\t" + "movq %%mm5, 8(%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "subl $4, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels), "+D"(block) + :"r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} + +av_unused static void DEF(put, pixels8_y2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +{ + MOVQ_BFE(mm6); + __asm__ volatile( + "lea (%3, %3), %%"FF_REG_a" \n\t" + "movq (%1), %%mm0 \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1, %3), %%mm1 \n\t" + "movq (%1, %%"FF_REG_a"),%%mm2\n\t" + PAVGBP(%%mm1, %%mm0, %%mm4, %%mm2, %%mm1, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "movq (%1, %3), %%mm1 \n\t" + "movq (%1, %%"FF_REG_a"),%%mm0\n\t" + PAVGBP(%%mm1, %%mm2, %%mm4, %%mm0, %%mm1, %%mm5) + "movq %%mm4, (%2) \n\t" + "movq %%mm5, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + "subl $4, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels), "+D"(block) + :"r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} + +av_unused static void DEF(avg, pixels16_x2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +{ + MOVQ_BFE(mm6); + __asm__ volatile( + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm1 \n\t" + "movq (%2), %%mm3 \n\t" + PAVGB(%%mm0, %%mm1, %%mm2, %%mm6) + PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6) + "movq %%mm0, (%2) \n\t" + "movq 8(%1), %%mm0 \n\t" + "movq 9(%1), %%mm1 \n\t" + "movq 8(%2), %%mm3 \n\t" + PAVGB(%%mm0, %%mm1, %%mm2, %%mm6) + PAVGB_MMX(%%mm3, %%mm2, %%mm0, %%mm6) + "movq %%mm0, 8(%2) \n\t" + "add %3, %1 \n\t" + "add %3, %2 \n\t" + "subl $1, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels), "+D"(block) + :"r"((x86_reg)line_size) + :"memory"); +} + +av_unused static void DEF(avg, pixels8_y2)(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) +{ + MOVQ_BFE(mm6); + __asm__ volatile( + "lea (%3, %3), %%"FF_REG_a" \n\t" + "movq (%1), %%mm0 \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1, %3), %%mm1 \n\t" + "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" + PAVGBP(%%mm1, %%mm0, %%mm4, %%mm2, %%mm1, %%mm5) + "movq (%2), %%mm3 \n\t" + PAVGB_MMX(%%mm3, %%mm4, %%mm0, %%mm6) + "movq (%2, %3), %%mm3 \n\t" + PAVGB_MMX(%%mm3, %%mm5, %%mm1, %%mm6) + "movq %%mm0, (%2) \n\t" + "movq %%mm1, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + + "movq (%1, %3), %%mm1 \n\t" + "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" + PAVGBP(%%mm1, %%mm2, %%mm4, %%mm0, %%mm1, %%mm5) + "movq (%2), %%mm3 \n\t" + PAVGB_MMX(%%mm3, %%mm4, %%mm2, %%mm6) + "movq (%2, %3), %%mm3 \n\t" + PAVGB_MMX(%%mm3, %%mm5, %%mm1, %%mm6) + "movq %%mm2, (%2) \n\t" + "movq %%mm1, (%2, %3) \n\t" + "add %%"FF_REG_a", %1 \n\t" + "add %%"FF_REG_a", %2 \n\t" + + "subl $4, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels), "+D"(block) + :"r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_vp3_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_vp3_init.c new file mode 100644 index 0000000000..5979f4123c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/hpeldsp_vp3_init.c @@ -0,0 +1,56 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" + +#include "libavcodec/avcodec.h" +#include "libavcodec/hpeldsp.h" + +#include "hpeldsp.h" + +void ff_put_no_rnd_pixels8_x2_exact_mmxext(uint8_t *block, + const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels8_x2_exact_3dnow(uint8_t *block, + const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels8_y2_exact_mmxext(uint8_t *block, + const uint8_t *pixels, + ptrdiff_t line_size, int h); +void ff_put_no_rnd_pixels8_y2_exact_3dnow(uint8_t *block, + const uint8_t *pixels, + ptrdiff_t line_size, int h); + +av_cold void ff_hpeldsp_vp3_init_x86(HpelDSPContext *c, int cpu_flags, int flags) +{ + if (EXTERNAL_AMD3DNOW(cpu_flags)) { + if (flags & AV_CODEC_FLAG_BITEXACT) { + c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_exact_3dnow; + c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_exact_3dnow; + } + } + + if (EXTERNAL_MMXEXT(cpu_flags)) { + if (flags & AV_CODEC_FLAG_BITEXACT) { + c->put_no_rnd_pixels_tab[1][1] = ff_put_no_rnd_pixels8_x2_exact_mmxext; + c->put_no_rnd_pixels_tab[1][2] = ff_put_no_rnd_pixels8_y2_exact_mmxext; + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/huffyuvdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/huffyuvdsp_init.c new file mode 100644 index 0000000000..eb10de383d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/huffyuvdsp_init.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2009 Loren Merritt + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/pixdesc.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/huffyuvdsp.h" + +void ff_add_int16_mmx(uint16_t *dst, const uint16_t *src, unsigned mask, int w); +void ff_add_int16_sse2(uint16_t *dst, const uint16_t *src, unsigned mask, int w); +void ff_add_int16_avx2(uint16_t *dst, const uint16_t *src, unsigned mask, int w); + +void ff_add_hfyu_left_pred_bgr32_mmx(uint8_t *dst, const uint8_t *src, + intptr_t w, uint8_t *left); +void ff_add_hfyu_left_pred_bgr32_sse2(uint8_t *dst, const uint8_t *src, + intptr_t w, uint8_t *left); +void ff_add_hfyu_median_pred_int16_mmxext(uint16_t *dst, const uint16_t *top, const uint16_t *diff, unsigned mask, int w, int *left, int *left_top); + +av_cold void ff_huffyuvdsp_init_x86(HuffYUVDSPContext *c, enum AVPixelFormat pix_fmt) +{ + int cpu_flags = av_get_cpu_flags(); + const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(pix_fmt); + + if (ARCH_X86_32 && EXTERNAL_MMX(cpu_flags)) { + c->add_hfyu_left_pred_bgr32 = ff_add_hfyu_left_pred_bgr32_mmx; + c->add_int16 = ff_add_int16_mmx; + } + + if (EXTERNAL_MMXEXT(cpu_flags) && pix_desc && pix_desc->comp[0].depth<16) { + c->add_hfyu_median_pred_int16 = ff_add_hfyu_median_pred_int16_mmxext; + } + + if (EXTERNAL_SSE2(cpu_flags)) { + c->add_int16 = ff_add_int16_sse2; + c->add_hfyu_left_pred_bgr32 = ff_add_hfyu_left_pred_bgr32_sse2; + } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->add_int16 = ff_add_int16_avx2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/huffyuvencdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/huffyuvencdsp_init.c new file mode 100644 index 0000000000..6c6e068cf8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/huffyuvencdsp_init.c @@ -0,0 +1,60 @@ +/* + * SIMD-optimized HuffYUV encoding functions + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * MMX optimization by Nick Kurshev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/pixdesc.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/huffyuvencdsp.h" + +void ff_diff_int16_mmx (uint16_t *dst, const uint16_t *src1, const uint16_t *src2, + unsigned mask, int w); +void ff_diff_int16_sse2(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, + unsigned mask, int w); +void ff_diff_int16_avx2(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, + unsigned mask, int w); +void ff_sub_hfyu_median_pred_int16_mmxext(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, + unsigned mask, int w, int *left, int *left_top); + +av_cold void ff_huffyuvencdsp_init_x86(HuffYUVEncDSPContext *c, AVCodecContext *avctx) +{ + av_unused int cpu_flags = av_get_cpu_flags(); + const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(avctx->pix_fmt); + + if (ARCH_X86_32 && EXTERNAL_MMX(cpu_flags)) { + c->diff_int16 = ff_diff_int16_mmx; + } + + if (EXTERNAL_MMXEXT(cpu_flags) && pix_desc && pix_desc->comp[0].depth<16) { + c->sub_hfyu_median_pred_int16 = ff_sub_hfyu_median_pred_int16_mmxext; + } + + if (EXTERNAL_SSE2(cpu_flags)) { + c->diff_int16 = ff_diff_int16_sse2; + } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->diff_int16 = ff_diff_int16_avx2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/idctdsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/idctdsp.h new file mode 100644 index 0000000000..0d0bdb5f57 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/idctdsp.h @@ -0,0 +1,39 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_IDCTDSP_H +#define AVCODEC_X86_IDCTDSP_H + +#include +#include + +void ff_add_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels, + ptrdiff_t line_size); +void ff_add_pixels_clamped_sse2(const int16_t *block, uint8_t *pixels, + ptrdiff_t line_size); +void ff_put_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels, + ptrdiff_t line_size); +void ff_put_pixels_clamped_sse2(const int16_t *block, uint8_t *pixels, + ptrdiff_t line_size); +void ff_put_signed_pixels_clamped_mmx(const int16_t *block, uint8_t *pixels, + ptrdiff_t line_size); +void ff_put_signed_pixels_clamped_sse2(const int16_t *block, uint8_t *pixels, + ptrdiff_t line_size); + + +#endif /* AVCODEC_X86_IDCTDSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/idctdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/idctdsp_init.c new file mode 100644 index 0000000000..9103b92ce7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/idctdsp_init.c @@ -0,0 +1,162 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/idctdsp.h" +#include "idctdsp.h" +#include "simple_idct.h" + +/* Input permutation for the simple_idct_mmx */ +static const uint8_t simple_mmx_permutation[64] = { + 0x00, 0x08, 0x04, 0x09, 0x01, 0x0C, 0x05, 0x0D, + 0x10, 0x18, 0x14, 0x19, 0x11, 0x1C, 0x15, 0x1D, + 0x20, 0x28, 0x24, 0x29, 0x21, 0x2C, 0x25, 0x2D, + 0x12, 0x1A, 0x16, 0x1B, 0x13, 0x1E, 0x17, 0x1F, + 0x02, 0x0A, 0x06, 0x0B, 0x03, 0x0E, 0x07, 0x0F, + 0x30, 0x38, 0x34, 0x39, 0x31, 0x3C, 0x35, 0x3D, + 0x22, 0x2A, 0x26, 0x2B, 0x23, 0x2E, 0x27, 0x2F, + 0x32, 0x3A, 0x36, 0x3B, 0x33, 0x3E, 0x37, 0x3F, +}; + +static const uint8_t idct_sse2_row_perm[8] = { 0, 4, 1, 5, 2, 6, 3, 7 }; + +av_cold int ff_init_scantable_permutation_x86(uint8_t *idct_permutation, + enum idct_permutation_type perm_type) +{ + int i; + + switch (perm_type) { + case FF_IDCT_PERM_SIMPLE: + for (i = 0; i < 64; i++) + idct_permutation[i] = simple_mmx_permutation[i]; + return 1; + case FF_IDCT_PERM_SSE2: + for (i = 0; i < 64; i++) + idct_permutation[i] = (i & 0x38) | idct_sse2_row_perm[i & 7]; + return 1; + } + + return 0; +} + +av_cold void ff_idctdsp_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + c->put_signed_pixels_clamped = ff_put_signed_pixels_clamped_mmx; + c->put_pixels_clamped = ff_put_pixels_clamped_mmx; + c->add_pixels_clamped = ff_add_pixels_clamped_mmx; + + if (!high_bit_depth && + avctx->lowres == 0 && + (avctx->idct_algo == FF_IDCT_AUTO || + avctx->idct_algo == FF_IDCT_SIMPLEAUTO || + avctx->idct_algo == FF_IDCT_SIMPLEMMX)) { + c->idct_put = ff_simple_idct_put_mmx; + c->idct_add = ff_simple_idct_add_mmx; + c->idct = ff_simple_idct_mmx; + c->perm_type = FF_IDCT_PERM_SIMPLE; + } + } + + if (EXTERNAL_SSE2(cpu_flags)) { + c->put_signed_pixels_clamped = ff_put_signed_pixels_clamped_sse2; + c->put_pixels_clamped = ff_put_pixels_clamped_sse2; + c->add_pixels_clamped = ff_add_pixels_clamped_sse2; + + if (!high_bit_depth && + avctx->lowres == 0 && + (avctx->idct_algo == FF_IDCT_AUTO || + avctx->idct_algo == FF_IDCT_SIMPLEAUTO || + avctx->idct_algo == FF_IDCT_SIMPLEMMX)) { + c->idct_put = ff_simple_idct_put_sse2; + c->idct_add = ff_simple_idct_add_sse2; + c->perm_type = FF_IDCT_PERM_SIMPLE; + } + + if (ARCH_X86_64 && + !high_bit_depth && + avctx->lowres == 0 && + (avctx->idct_algo == FF_IDCT_AUTO || + avctx->idct_algo == FF_IDCT_SIMPLEAUTO || + avctx->idct_algo == FF_IDCT_SIMPLEMMX || + avctx->idct_algo == FF_IDCT_SIMPLE)) { + c->idct = ff_simple_idct8_sse2; + c->idct_put = ff_simple_idct8_put_sse2; + c->idct_add = ff_simple_idct8_add_sse2; + c->perm_type = FF_IDCT_PERM_TRANSPOSE; + } + } + + if (ARCH_X86_64 && avctx->lowres == 0) { + if (EXTERNAL_AVX(cpu_flags) && + !high_bit_depth && + (avctx->idct_algo == FF_IDCT_AUTO || + avctx->idct_algo == FF_IDCT_SIMPLEAUTO || + avctx->idct_algo == FF_IDCT_SIMPLEMMX || + avctx->idct_algo == FF_IDCT_SIMPLE)) { + c->idct = ff_simple_idct8_avx; + c->idct_put = ff_simple_idct8_put_avx; + c->idct_add = ff_simple_idct8_add_avx; + c->perm_type = FF_IDCT_PERM_TRANSPOSE; + } + + if (avctx->bits_per_raw_sample == 10 && + avctx->codec_id != AV_CODEC_ID_MPEG4 && + (avctx->idct_algo == FF_IDCT_AUTO || + avctx->idct_algo == FF_IDCT_SIMPLEAUTO || + avctx->idct_algo == FF_IDCT_SIMPLE)) { + if (EXTERNAL_SSE2(cpu_flags)) { + c->idct_put = ff_simple_idct10_put_sse2; + c->idct_add = NULL; + c->idct = ff_simple_idct10_sse2; + c->perm_type = FF_IDCT_PERM_TRANSPOSE; + + } + if (EXTERNAL_AVX(cpu_flags)) { + c->idct_put = ff_simple_idct10_put_avx; + c->idct_add = NULL; + c->idct = ff_simple_idct10_avx; + c->perm_type = FF_IDCT_PERM_TRANSPOSE; + } + } + + if (avctx->bits_per_raw_sample == 12 && + (avctx->idct_algo == FF_IDCT_AUTO || + avctx->idct_algo == FF_IDCT_SIMPLEMMX)) { + if (EXTERNAL_SSE2(cpu_flags)) { + c->idct_put = ff_simple_idct12_put_sse2; + c->idct_add = NULL; + c->idct = ff_simple_idct12_sse2; + c->perm_type = FF_IDCT_PERM_TRANSPOSE; + } + if (EXTERNAL_AVX(cpu_flags)) { + c->idct_put = ff_simple_idct12_put_avx; + c->idct_add = NULL; + c->idct = ff_simple_idct12_avx; + c->perm_type = FF_IDCT_PERM_TRANSPOSE; + } + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/inline_asm.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/inline_asm.h new file mode 100644 index 0000000000..0198746719 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/inline_asm.h @@ -0,0 +1,100 @@ +/* + * inline assembly helper macros + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_INLINE_ASM_H +#define AVCODEC_X86_INLINE_ASM_H + +#include "constants.h" + +#define MOVQ_WONE(regd) \ + __asm__ volatile ( \ + "pcmpeqd %%" #regd ", %%" #regd " \n\t" \ + "psrlw $15, %%" #regd ::) + +#define JUMPALIGN() __asm__ volatile (".p2align 3"::) +#define MOVQ_ZERO(regd) __asm__ volatile ("pxor %%"#regd", %%"#regd ::) + +#define MOVQ_BFE(regd) \ + __asm__ volatile ( \ + "pcmpeqd %%"#regd", %%"#regd" \n\t" \ + "paddb %%"#regd", %%"#regd" \n\t" ::) + +#ifndef PIC +#define MOVQ_WTWO(regd) __asm__ volatile ("movq %0, %%"#regd" \n\t" :: "m"(ff_pw_2)) +#else +// for shared library it's better to use this way for accessing constants +// pcmpeqd -> -1 +#define MOVQ_WTWO(regd) \ + __asm__ volatile ( \ + "pcmpeqd %%"#regd", %%"#regd" \n\t" \ + "psrlw $15, %%"#regd" \n\t" \ + "psllw $1, %%"#regd" \n\t"::) + +#endif + +// using regr as temporary and for the output result +// first argument is unmodified and second is trashed +// regfe is supposed to contain 0xfefefefefefefefe +#define PAVGB_MMX_NO_RND(rega, regb, regr, regfe) \ + "movq "#rega", "#regr" \n\t" \ + "pand "#regb", "#regr" \n\t" \ + "pxor "#rega", "#regb" \n\t" \ + "pand "#regfe", "#regb" \n\t" \ + "psrlq $1, "#regb" \n\t" \ + "paddb "#regb", "#regr" \n\t" + +#define PAVGB_MMX(rega, regb, regr, regfe) \ + "movq "#rega", "#regr" \n\t" \ + "por "#regb", "#regr" \n\t" \ + "pxor "#rega", "#regb" \n\t" \ + "pand "#regfe", "#regb" \n\t" \ + "psrlq $1, "#regb" \n\t" \ + "psubb "#regb", "#regr" \n\t" + +// mm6 is supposed to contain 0xfefefefefefefefe +#define PAVGBP_MMX_NO_RND(rega, regb, regr, regc, regd, regp) \ + "movq "#rega", "#regr" \n\t" \ + "movq "#regc", "#regp" \n\t" \ + "pand "#regb", "#regr" \n\t" \ + "pand "#regd", "#regp" \n\t" \ + "pxor "#rega", "#regb" \n\t" \ + "pxor "#regc", "#regd" \n\t" \ + "pand %%mm6, "#regb" \n\t" \ + "pand %%mm6, "#regd" \n\t" \ + "psrlq $1, "#regb" \n\t" \ + "psrlq $1, "#regd" \n\t" \ + "paddb "#regb", "#regr" \n\t" \ + "paddb "#regd", "#regp" \n\t" + +#define PAVGBP_MMX(rega, regb, regr, regc, regd, regp) \ + "movq "#rega", "#regr" \n\t" \ + "movq "#regc", "#regp" \n\t" \ + "por "#regb", "#regr" \n\t" \ + "por "#regd", "#regp" \n\t" \ + "pxor "#rega", "#regb" \n\t" \ + "pxor "#regc", "#regd" \n\t" \ + "pand %%mm6, "#regb" \n\t" \ + "pand %%mm6, "#regd" \n\t" \ + "psrlq $1, "#regd" \n\t" \ + "psrlq $1, "#regb" \n\t" \ + "psubb "#regb", "#regr" \n\t" \ + "psubb "#regd", "#regp" \n\t" + +#endif /* AVCODEC_X86_INLINE_ASM_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/jpeg2000dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/jpeg2000dsp_init.c new file mode 100644 index 0000000000..7310a1d0e1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/jpeg2000dsp_init.c @@ -0,0 +1,60 @@ +/* + * SIMD optimized JPEG 2000 DSP functions + * Copyright (c) 2015 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/jpeg2000dsp.h" + +void ff_ict_float_sse(void *src0, void *src1, void *src2, int csize); +void ff_ict_float_avx(void *src0, void *src1, void *src2, int csize); +void ff_ict_float_fma3(void *src0, void *src1, void *src2, int csize); +void ff_ict_float_fma4(void *src0, void *src1, void *src2, int csize); +void ff_rct_int_sse2 (void *src0, void *src1, void *src2, int csize); +void ff_rct_int_avx2 (void *src0, void *src1, void *src2, int csize); + +av_cold void ff_jpeg2000dsp_init_x86(Jpeg2000DSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + if (EXTERNAL_SSE(cpu_flags)) { + c->mct_decode[FF_DWT97] = ff_ict_float_sse; + } + + if (EXTERNAL_SSE2(cpu_flags)) { + c->mct_decode[FF_DWT53] = ff_rct_int_sse2; + } + + if (EXTERNAL_AVX_FAST(cpu_flags)) { + c->mct_decode[FF_DWT97] = ff_ict_float_avx; + } + + if (EXTERNAL_FMA4(cpu_flags)) { + c->mct_decode[FF_DWT97] = ff_ict_float_fma4; + } + + if (EXTERNAL_FMA3_FAST(cpu_flags)) { + c->mct_decode[FF_DWT97] = ff_ict_float_fma3; + } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->mct_decode[FF_DWT53] = ff_rct_int_avx2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_audiodsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_audiodsp_init.c new file mode 100644 index 0000000000..f74c7e4361 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_audiodsp_init.c @@ -0,0 +1,56 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/lossless_audiodsp.h" + +int32_t ff_scalarproduct_and_madd_int16_mmxext(int16_t *v1, const int16_t *v2, + const int16_t *v3, + int order, int mul); +int32_t ff_scalarproduct_and_madd_int16_sse2(int16_t *v1, const int16_t *v2, + const int16_t *v3, + int order, int mul); +int32_t ff_scalarproduct_and_madd_int16_ssse3(int16_t *v1, const int16_t *v2, + const int16_t *v3, + int order, int mul); + +int32_t ff_scalarproduct_and_madd_int32_sse4(int16_t *v1, const int32_t *v2, + const int16_t *v3, + int order, int mul); + +av_cold void ff_llauddsp_init_x86(LLAudDSPContext *c) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMXEXT(cpu_flags)) + c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_mmxext; + + if (EXTERNAL_SSE2(cpu_flags)) + c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_sse2; + + if (EXTERNAL_SSSE3(cpu_flags) && + !(cpu_flags & (AV_CPU_FLAG_SSE42 | AV_CPU_FLAG_3DNOW))) // cachesplit + c->scalarproduct_and_madd_int16 = ff_scalarproduct_and_madd_int16_ssse3; + + if (EXTERNAL_SSE4(cpu_flags)) + c->scalarproduct_and_madd_int32 = ff_scalarproduct_and_madd_int32_sse4; +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_videodsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_videodsp_init.c new file mode 100644 index 0000000000..6d71f14e7f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_videodsp_init.c @@ -0,0 +1,128 @@ +/* + * Lossless video DSP utils + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/x86/asm.h" +#include "../lossless_videodsp.h" +#include "libavutil/x86/cpu.h" + +void ff_add_bytes_mmx(uint8_t *dst, uint8_t *src, ptrdiff_t w); +void ff_add_bytes_sse2(uint8_t *dst, uint8_t *src, ptrdiff_t w); +void ff_add_bytes_avx2(uint8_t *dst, uint8_t *src, ptrdiff_t w); + +void ff_add_median_pred_mmxext(uint8_t *dst, const uint8_t *top, + const uint8_t *diff, ptrdiff_t w, + int *left, int *left_top); +void ff_add_median_pred_sse2(uint8_t *dst, const uint8_t *top, + const uint8_t *diff, ptrdiff_t w, + int *left, int *left_top); + +int ff_add_left_pred_ssse3(uint8_t *dst, const uint8_t *src, + ptrdiff_t w, int left); +int ff_add_left_pred_unaligned_ssse3(uint8_t *dst, const uint8_t *src, + ptrdiff_t w, int left); +int ff_add_left_pred_unaligned_avx2(uint8_t *dst, const uint8_t *src, + ptrdiff_t w, int left); + +int ff_add_left_pred_int16_ssse3(uint16_t *dst, const uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); +int ff_add_left_pred_int16_unaligned_ssse3(uint16_t *dst, const uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); + +void ff_add_gradient_pred_ssse3(uint8_t *src, const ptrdiff_t stride, const ptrdiff_t width); +void ff_add_gradient_pred_avx2(uint8_t *src, const ptrdiff_t stride, const ptrdiff_t width); + +#if HAVE_INLINE_ASM && HAVE_7REGS && ARCH_X86_32 +static void add_median_pred_cmov(uint8_t *dst, const uint8_t *top, + const uint8_t *diff, ptrdiff_t w, + int *left, int *left_top) +{ + x86_reg w2 = -w; + x86_reg x; + int l = *left & 0xff; + int tl = *left_top & 0xff; + int t; + __asm__ volatile ( + "mov %7, %3 \n" + "1: \n" + "movzbl (%3, %4), %2 \n" + "mov %2, %k3 \n" + "sub %b1, %b3 \n" + "add %b0, %b3 \n" + "mov %2, %1 \n" + "cmp %0, %2 \n" + "cmovg %0, %2 \n" + "cmovg %1, %0 \n" + "cmp %k3, %0 \n" + "cmovg %k3, %0 \n" + "mov %7, %3 \n" + "cmp %2, %0 \n" + "cmovl %2, %0 \n" + "add (%6, %4), %b0 \n" + "mov %b0, (%5, %4) \n" + "inc %4 \n" + "jl 1b \n" + : "+&q"(l), "+&q"(tl), "=&r"(t), "=&q"(x), "+&r"(w2) + : "r"(dst + w), "r"(diff + w), "rm"(top + w) + ); + *left = l; + *left_top = tl; +} +#endif + +void ff_llviddsp_init_x86(LLVidDSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + +#if HAVE_INLINE_ASM && HAVE_7REGS && ARCH_X86_32 + if (cpu_flags & AV_CPU_FLAG_CMOV) + c->add_median_pred = add_median_pred_cmov; +#endif + + if (ARCH_X86_32 && EXTERNAL_MMX(cpu_flags)) { + c->add_bytes = ff_add_bytes_mmx; + } + + if (ARCH_X86_32 && EXTERNAL_MMXEXT(cpu_flags)) { + /* slower than cmov version on AMD */ + if (!(cpu_flags & AV_CPU_FLAG_3DNOW)) + c->add_median_pred = ff_add_median_pred_mmxext; + } + + if (EXTERNAL_SSE2(cpu_flags)) { + c->add_bytes = ff_add_bytes_sse2; + c->add_median_pred = ff_add_median_pred_sse2; + } + + if (EXTERNAL_SSSE3(cpu_flags)) { + c->add_left_pred = ff_add_left_pred_ssse3; + c->add_left_pred_int16 = ff_add_left_pred_int16_ssse3; + c->add_gradient_pred = ff_add_gradient_pred_ssse3; + } + + if (EXTERNAL_SSSE3_FAST(cpu_flags)) { + c->add_left_pred = ff_add_left_pred_unaligned_ssse3; + c->add_left_pred_int16 = ff_add_left_pred_int16_unaligned_ssse3; + } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->add_bytes = ff_add_bytes_avx2; + c->add_left_pred = ff_add_left_pred_unaligned_avx2; + c->add_gradient_pred = ff_add_gradient_pred_avx2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_videoencdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_videoencdsp_init.c new file mode 100644 index 0000000000..40407add52 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lossless_videoencdsp_init.c @@ -0,0 +1,111 @@ +/* + * SIMD-optimized lossless video encoding functions + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * MMX optimization by Nick Kurshev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/lossless_videoencdsp.h" +#include "libavcodec/mathops.h" + +void ff_diff_bytes_mmx(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + intptr_t w); +void ff_diff_bytes_sse2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + intptr_t w); +void ff_diff_bytes_avx2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, + intptr_t w); + +void ff_sub_left_predict_avx(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, ptrdiff_t width, int height); + +#if HAVE_INLINE_ASM + +static void sub_median_pred_mmxext(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, intptr_t w, + int *left, int *left_top) +{ + x86_reg i = 0; + uint8_t l, lt; + + __asm__ volatile ( + "movq (%1, %0), %%mm0 \n\t" // LT + "psllq $8, %%mm0 \n\t" + "1: \n\t" + "movq (%1, %0), %%mm1 \n\t" // T + "movq -1(%2, %0), %%mm2 \n\t" // L + "movq (%2, %0), %%mm3 \n\t" // X + "movq %%mm2, %%mm4 \n\t" // L + "psubb %%mm0, %%mm2 \n\t" + "paddb %%mm1, %%mm2 \n\t" // L + T - LT + "movq %%mm4, %%mm5 \n\t" // L + "pmaxub %%mm1, %%mm4 \n\t" // max(T, L) + "pminub %%mm5, %%mm1 \n\t" // min(T, L) + "pminub %%mm2, %%mm4 \n\t" + "pmaxub %%mm1, %%mm4 \n\t" + "psubb %%mm4, %%mm3 \n\t" // dst - pred + "movq %%mm3, (%3, %0) \n\t" + "add $8, %0 \n\t" + "movq -1(%1, %0), %%mm0 \n\t" // LT + "cmp %4, %0 \n\t" + " jb 1b \n\t" + : "+r" (i) + : "r" (src1), "r" (src2), "r" (dst), "r" ((x86_reg) w)); + + l = *left; + lt = *left_top; + + dst[0] = src2[0] - mid_pred(l, src1[0], (l + src1[0] - lt) & 0xFF); + + *left_top = src1[w - 1]; + *left = src2[w - 1]; +} + +#endif /* HAVE_INLINE_ASM */ + +av_cold void ff_llvidencdsp_init_x86(LLVidEncDSPContext *c) +{ + av_unused int cpu_flags = av_get_cpu_flags(); + + if (ARCH_X86_32 && EXTERNAL_MMX(cpu_flags)) { + c->diff_bytes = ff_diff_bytes_mmx; + } + +#if HAVE_INLINE_ASM + if (INLINE_MMXEXT(cpu_flags)) { + c->sub_median_pred = sub_median_pred_mmxext; + } +#endif /* HAVE_INLINE_ASM */ + + if (EXTERNAL_SSE2(cpu_flags)) { + c->diff_bytes = ff_diff_bytes_sse2; + } + + if (EXTERNAL_AVX(cpu_flags)) { + c->sub_left_predict = ff_sub_left_predict_avx; + } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->diff_bytes = ff_diff_bytes_avx2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lpc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lpc.c new file mode 100644 index 0000000000..6c72e21bac --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/lpc.c @@ -0,0 +1,162 @@ +/* + * SIMD-optimized LPC functions + * Copyright (c) 2007 Loren Merritt + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/mem.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/lpc.h" + +DECLARE_ASM_CONST(16, double, pd_1)[2] = { 1.0, 1.0 }; +DECLARE_ASM_CONST(16, double, pd_2)[2] = { 2.0, 2.0 }; + +#if HAVE_SSE2_INLINE + +static void lpc_apply_welch_window_sse2(const int32_t *data, int len, + double *w_data) +{ + double c = 2.0 / (len-1.0); + int n2 = len>>1; + x86_reg i = -n2*sizeof(int32_t); + x86_reg j = n2*sizeof(int32_t); + __asm__ volatile( + "movsd %4, %%xmm7 \n\t" + "movapd "MANGLE(pd_1)", %%xmm6 \n\t" + "movapd "MANGLE(pd_2)", %%xmm5 \n\t" + "movlhps %%xmm7, %%xmm7 \n\t" + "subpd %%xmm5, %%xmm7 \n\t" + "addsd %%xmm6, %%xmm7 \n\t" + "test $1, %5 \n\t" + "jz 2f \n\t" +#define WELCH(MOVPD, offset)\ + "1: \n\t"\ + "movapd %%xmm7, %%xmm1 \n\t"\ + "mulpd %%xmm1, %%xmm1 \n\t"\ + "movapd %%xmm6, %%xmm0 \n\t"\ + "subpd %%xmm1, %%xmm0 \n\t"\ + "pshufd $0x4e, %%xmm0, %%xmm1 \n\t"\ + "cvtpi2pd (%3,%0), %%xmm2 \n\t"\ + "cvtpi2pd "#offset"*4(%3,%1), %%xmm3 \n\t"\ + "mulpd %%xmm0, %%xmm2 \n\t"\ + "mulpd %%xmm1, %%xmm3 \n\t"\ + "movapd %%xmm2, (%2,%0,2) \n\t"\ + MOVPD" %%xmm3, "#offset"*8(%2,%1,2) \n\t"\ + "subpd %%xmm5, %%xmm7 \n\t"\ + "sub $8, %1 \n\t"\ + "add $8, %0 \n\t"\ + "jl 1b \n\t"\ + + WELCH("movupd", -1) + "jmp 3f \n\t" + "2: \n\t" + WELCH("movapd", -2) + "3: \n\t" + :"+&r"(i), "+&r"(j) + :"r"(w_data+n2), "r"(data+n2), "m"(c), "r"(len) + NAMED_CONSTRAINTS_ARRAY_ADD(pd_1,pd_2) + XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3", + "%xmm5", "%xmm6", "%xmm7") + ); +#undef WELCH +} + +static void lpc_compute_autocorr_sse2(const double *data, int len, int lag, + double *autoc) +{ + int j; + + if((x86_reg)data & 15) + data++; + + for(j=0; jlpc_apply_welch_window = lpc_apply_welch_window_sse2; + c->lpc_compute_autocorr = lpc_compute_autocorr_sse2; + } +#endif /* HAVE_SSE2_INLINE */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mathops.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mathops.h new file mode 100644 index 0000000000..6298f5ed19 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mathops.h @@ -0,0 +1,133 @@ +/* + * simple math operations + * Copyright (c) 2006 Michael Niedermayer et al + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_MATHOPS_H +#define AVCODEC_X86_MATHOPS_H + +#include "config.h" + +#include "libavutil/common.h" +#include "libavutil/x86/asm.h" + +#if HAVE_INLINE_ASM + +#if ARCH_X86_32 + +#define MULL MULL +static av_always_inline av_const int MULL(int a, int b, unsigned shift) +{ + int rt, dummy; + __asm__ ( + "imull %3 \n\t" + "shrdl %4, %%edx, %%eax \n\t" + :"=a"(rt), "=d"(dummy) + :"a"(a), "rm"(b), "ci"((uint8_t)shift) + ); + return rt; +} + +#define MULH MULH +static av_always_inline av_const int MULH(int a, int b) +{ + int rt, dummy; + __asm__ ( + "imull %3" + :"=d"(rt), "=a"(dummy) + :"a"(a), "rm"(b) + ); + return rt; +} + +#define MUL64 MUL64 +static av_always_inline av_const int64_t MUL64(int a, int b) +{ + int64_t rt; + __asm__ ( + "imull %2" + :"=A"(rt) + :"a"(a), "rm"(b) + ); + return rt; +} + +#endif /* ARCH_X86_32 */ + +#if HAVE_I686 +/* median of 3 */ +#define mid_pred mid_pred +static inline av_const int mid_pred(int a, int b, int c) +{ + int i=b; + __asm__ ( + "cmp %2, %1 \n\t" + "cmovg %1, %0 \n\t" + "cmovg %2, %1 \n\t" + "cmp %3, %1 \n\t" + "cmovl %3, %1 \n\t" + "cmp %1, %0 \n\t" + "cmovg %1, %0 \n\t" + :"+&r"(i), "+&r"(a) + :"r"(b), "r"(c) + ); + return i; +} + +#if HAVE_6REGS +#define COPY3_IF_LT(x, y, a, b, c, d)\ +__asm__ volatile(\ + "cmpl %0, %3 \n\t"\ + "cmovl %3, %0 \n\t"\ + "cmovl %4, %1 \n\t"\ + "cmovl %5, %2 \n\t"\ + : "+&r" (x), "+&r" (a), "+r" (c)\ + : "r" (y), "r" (b), "r" (d)\ +); +#endif /* HAVE_6REGS */ + +#endif /* HAVE_I686 */ + +#define MASK_ABS(mask, level) \ + __asm__ ("cdq \n\t" \ + "xorl %1, %0 \n\t" \ + "subl %1, %0 \n\t" \ + : "+a"(level), "=&d"(mask)) + +// avoid +32 for shift optimization (gcc should do that ...) +#define NEG_SSR32 NEG_SSR32 +static inline int32_t NEG_SSR32( int32_t a, int8_t s){ + __asm__ ("sarl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} + +#define NEG_USR32 NEG_USR32 +static inline uint32_t NEG_USR32(uint32_t a, int8_t s){ + __asm__ ("shrl %1, %0\n\t" + : "+r" (a) + : "ic" ((uint8_t)(-s)) + ); + return a; +} + +#endif /* HAVE_INLINE_ASM */ +#endif /* AVCODEC_X86_MATHOPS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mdct15_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mdct15_init.c new file mode 100644 index 0000000000..444801d9cf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mdct15_init.c @@ -0,0 +1,99 @@ +/* + * SIMD optimized non-power-of-two MDCT functions + * + * Copyright (C) 2017 Rostislav Pehlivanov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/x86/cpu.h" +#include "libavcodec/mdct15.h" + +void ff_mdct15_postreindex_sse3(FFTComplex *out, FFTComplex *in, FFTComplex *exp, int *lut, ptrdiff_t len8); +void ff_mdct15_postreindex_avx2(FFTComplex *out, FFTComplex *in, FFTComplex *exp, int *lut, ptrdiff_t len8); + +void ff_fft15_avx(FFTComplex *out, FFTComplex *in, FFTComplex *exptab, ptrdiff_t stride); + +static void perm_twiddles(MDCT15Context *s) +{ + int k; + FFTComplex tmp[30]; + + /* 5-point FFT twiddles */ + s->exptab[60].re = s->exptab[60].im = s->exptab[19].re; + s->exptab[61].re = s->exptab[61].im = s->exptab[19].im; + s->exptab[62].re = s->exptab[62].im = s->exptab[20].re; + s->exptab[63].re = s->exptab[63].im = s->exptab[20].im; + + /* 15-point FFT twiddles */ + for (k = 0; k < 5; k++) { + tmp[6*k + 0] = s->exptab[k + 0]; + tmp[6*k + 2] = s->exptab[k + 5]; + tmp[6*k + 4] = s->exptab[k + 10]; + + tmp[6*k + 1] = s->exptab[2 * (k + 0)]; + tmp[6*k + 3] = s->exptab[2 * (k + 5)]; + tmp[6*k + 5] = s->exptab[2 * k + 5 ]; + } + + for (k = 0; k < 6; k++) { + FFTComplex ac_exp[] = { + { tmp[6*1 + k].re, tmp[6*1 + k].re }, + { tmp[6*2 + k].re, tmp[6*2 + k].re }, + { tmp[6*3 + k].re, tmp[6*3 + k].re }, + { tmp[6*4 + k].re, tmp[6*4 + k].re }, + { tmp[6*1 + k].im, -tmp[6*1 + k].im }, + { tmp[6*2 + k].im, -tmp[6*2 + k].im }, + { tmp[6*3 + k].im, -tmp[6*3 + k].im }, + { tmp[6*4 + k].im, -tmp[6*4 + k].im }, + }; + memcpy(s->exptab + 8*k, ac_exp, 8*sizeof(FFTComplex)); + } + + /* Specialcase when k = 0 */ + for (k = 0; k < 3; k++) { + FFTComplex dc_exp[] = { + { tmp[2*k + 0].re, -tmp[2*k + 0].im }, + { tmp[2*k + 0].im, tmp[2*k + 0].re }, + { tmp[2*k + 1].re, -tmp[2*k + 1].im }, + { tmp[2*k + 1].im, tmp[2*k + 1].re }, + }; + memcpy(s->exptab + 8*6 + 4*k, dc_exp, 4*sizeof(FFTComplex)); + } +} + +av_cold void ff_mdct15_init_x86(MDCT15Context *s) +{ + int adjust_twiddles = 0; + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE3(cpu_flags)) + s->postreindex = ff_mdct15_postreindex_sse3; + + if (ARCH_X86_64 && EXTERNAL_AVX(cpu_flags)) { + s->fft15 = ff_fft15_avx; + adjust_twiddles = 1; + } + + if (ARCH_X86_64 && EXTERNAL_AVX2_FAST(cpu_flags)) + s->postreindex = ff_mdct15_postreindex_avx2; + + if (adjust_twiddles) + perm_twiddles(s); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/me_cmp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/me_cmp_init.c new file mode 100644 index 0000000000..6aec93e55f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/me_cmp_init.c @@ -0,0 +1,651 @@ +/* + * SIMD-optimized motion estimation + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * MMX optimization by Nick Kurshev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/me_cmp.h" +#include "libavcodec/mpegvideo.h" + +int ff_sum_abs_dctelem_mmx(int16_t *block); +int ff_sum_abs_dctelem_mmxext(int16_t *block); +int ff_sum_abs_dctelem_sse2(int16_t *block); +int ff_sum_abs_dctelem_ssse3(int16_t *block); +int ff_sse8_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sse16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sse16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_hf_noise8_mmx(uint8_t *pix1, ptrdiff_t stride, int h); +int ff_hf_noise16_mmx(uint8_t *pix1, ptrdiff_t stride, int h); +int ff_sad8_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad16_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad8_x2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad16_x2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad16_x2_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad8_y2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad16_y2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad16_y2_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad8_approx_xy2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad16_approx_xy2_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_sad16_approx_xy2_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad_intra8_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad_intra16_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad_intra16_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad8_approx_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad16_approx_mmxext(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); +int ff_vsad16_approx_sse2(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h); + +#define hadamard_func(cpu) \ + int ff_hadamard8_diff_ ## cpu(MpegEncContext *s, uint8_t *src1, \ + uint8_t *src2, ptrdiff_t stride, int h); \ + int ff_hadamard8_diff16_ ## cpu(MpegEncContext *s, uint8_t *src1, \ + uint8_t *src2, ptrdiff_t stride, int h); + +hadamard_func(mmx) +hadamard_func(mmxext) +hadamard_func(sse2) +hadamard_func(ssse3) + +#if HAVE_X86ASM +static int nsse16_mmx(MpegEncContext *c, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int score1, score2; + + if (c) + score1 = c->mecc.sse[0](c, pix1, pix2, stride, h); + else + score1 = ff_sse16_mmx(c, pix1, pix2, stride, h); + score2 = ff_hf_noise16_mmx(pix1, stride, h) + ff_hf_noise8_mmx(pix1+8, stride, h) + - ff_hf_noise16_mmx(pix2, stride, h) - ff_hf_noise8_mmx(pix2+8, stride, h); + + if (c) + return score1 + FFABS(score2) * c->avctx->nsse_weight; + else + return score1 + FFABS(score2) * 8; +} + +static int nsse8_mmx(MpegEncContext *c, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int score1 = ff_sse8_mmx(c, pix1, pix2, stride, h); + int score2 = ff_hf_noise8_mmx(pix1, stride, h) - + ff_hf_noise8_mmx(pix2, stride, h); + + if (c) + return score1 + FFABS(score2) * c->avctx->nsse_weight; + else + return score1 + FFABS(score2) * 8; +} + +#endif /* HAVE_X86ASM */ + +#if HAVE_INLINE_ASM + +static int vsad_intra16_mmx(MpegEncContext *v, uint8_t *pix, uint8_t *dummy, + ptrdiff_t stride, int h) +{ + int tmp; + + av_assert2((((int) pix) & 7) == 0); + av_assert2((stride & 7) == 0); + +#define SUM(in0, in1, out0, out1) \ + "movq (%0), %%mm2\n" \ + "movq 8(%0), %%mm3\n" \ + "add %2,%0\n" \ + "movq %%mm2, " #out0 "\n" \ + "movq %%mm3, " #out1 "\n" \ + "psubusb " #in0 ", %%mm2\n" \ + "psubusb " #in1 ", %%mm3\n" \ + "psubusb " #out0 ", " #in0 "\n" \ + "psubusb " #out1 ", " #in1 "\n" \ + "por %%mm2, " #in0 "\n" \ + "por %%mm3, " #in1 "\n" \ + "movq " #in0 ", %%mm2\n" \ + "movq " #in1 ", %%mm3\n" \ + "punpcklbw %%mm7, " #in0 "\n" \ + "punpcklbw %%mm7, " #in1 "\n" \ + "punpckhbw %%mm7, %%mm2\n" \ + "punpckhbw %%mm7, %%mm3\n" \ + "paddw " #in1 ", " #in0 "\n" \ + "paddw %%mm3, %%mm2\n" \ + "paddw %%mm2, " #in0 "\n" \ + "paddw " #in0 ", %%mm6\n" + + + __asm__ volatile ( + "movl %3, %%ecx\n" + "pxor %%mm6, %%mm6\n" + "pxor %%mm7, %%mm7\n" + "movq (%0), %%mm0\n" + "movq 8(%0), %%mm1\n" + "add %2, %0\n" + "jmp 2f\n" + "1:\n" + + SUM(%%mm4, %%mm5, %%mm0, %%mm1) + "2:\n" + SUM(%%mm0, %%mm1, %%mm4, %%mm5) + + "subl $2, %%ecx\n" + "jnz 1b\n" + + "movq %%mm6, %%mm0\n" + "psrlq $32, %%mm6\n" + "paddw %%mm6, %%mm0\n" + "movq %%mm0, %%mm6\n" + "psrlq $16, %%mm0\n" + "paddw %%mm6, %%mm0\n" + "movd %%mm0, %1\n" + : "+r" (pix), "=r" (tmp) + : "r" (stride), "m" (h) + : "%ecx"); + + return tmp & 0xFFFF; +} +#undef SUM + +static int vsad16_mmx(MpegEncContext *v, uint8_t *pix1, uint8_t *pix2, + ptrdiff_t stride, int h) +{ + int tmp; + + av_assert2((((int) pix1) & 7) == 0); + av_assert2((((int) pix2) & 7) == 0); + av_assert2((stride & 7) == 0); + +#define SUM(in0, in1, out0, out1) \ + "movq (%0), %%mm2\n" \ + "movq (%1), " #out0 "\n" \ + "movq 8(%0), %%mm3\n" \ + "movq 8(%1), " #out1 "\n" \ + "add %3, %0\n" \ + "add %3, %1\n" \ + "psubb " #out0 ", %%mm2\n" \ + "psubb " #out1 ", %%mm3\n" \ + "pxor %%mm7, %%mm2\n" \ + "pxor %%mm7, %%mm3\n" \ + "movq %%mm2, " #out0 "\n" \ + "movq %%mm3, " #out1 "\n" \ + "psubusb " #in0 ", %%mm2\n" \ + "psubusb " #in1 ", %%mm3\n" \ + "psubusb " #out0 ", " #in0 "\n" \ + "psubusb " #out1 ", " #in1 "\n" \ + "por %%mm2, " #in0 "\n" \ + "por %%mm3, " #in1 "\n" \ + "movq " #in0 ", %%mm2\n" \ + "movq " #in1 ", %%mm3\n" \ + "punpcklbw %%mm7, " #in0 "\n" \ + "punpcklbw %%mm7, " #in1 "\n" \ + "punpckhbw %%mm7, %%mm2\n" \ + "punpckhbw %%mm7, %%mm3\n" \ + "paddw " #in1 ", " #in0 "\n" \ + "paddw %%mm3, %%mm2\n" \ + "paddw %%mm2, " #in0 "\n" \ + "paddw " #in0 ", %%mm6\n" + + + __asm__ volatile ( + "movl %4, %%ecx\n" + "pxor %%mm6, %%mm6\n" + "pcmpeqw %%mm7, %%mm7\n" + "psllw $15, %%mm7\n" + "packsswb %%mm7, %%mm7\n" + "movq (%0), %%mm0\n" + "movq (%1), %%mm2\n" + "movq 8(%0), %%mm1\n" + "movq 8(%1), %%mm3\n" + "add %3, %0\n" + "add %3, %1\n" + "psubb %%mm2, %%mm0\n" + "psubb %%mm3, %%mm1\n" + "pxor %%mm7, %%mm0\n" + "pxor %%mm7, %%mm1\n" + "jmp 2f\n" + "1:\n" + + SUM(%%mm4, %%mm5, %%mm0, %%mm1) + "2:\n" + SUM(%%mm0, %%mm1, %%mm4, %%mm5) + + "subl $2, %%ecx\n" + "jnz 1b\n" + + "movq %%mm6, %%mm0\n" + "psrlq $32, %%mm6\n" + "paddw %%mm6, %%mm0\n" + "movq %%mm0, %%mm6\n" + "psrlq $16, %%mm0\n" + "paddw %%mm6, %%mm0\n" + "movd %%mm0, %2\n" + : "+r" (pix1), "+r" (pix2), "=r" (tmp) + : "r" (stride), "m" (h) + : "%ecx"); + + return tmp & 0x7FFF; +} +#undef SUM + +DECLARE_ASM_CONST(8, uint64_t, round_tab)[3] = { + 0x0000000000000000ULL, + 0x0001000100010001ULL, + 0x0002000200020002ULL, +}; + +static inline void sad8_1_mmx(uint8_t *blk1, uint8_t *blk2, + ptrdiff_t stride, int h) +{ + x86_reg len = -stride * h; + __asm__ volatile ( + ".p2align 4 \n\t" + "1: \n\t" + "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm2 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm4 \n\t" + "add %3, %%"FF_REG_a" \n\t" + "psubusb %%mm0, %%mm2 \n\t" + "psubusb %%mm4, %%mm0 \n\t" + "movq (%1, %%"FF_REG_a"), %%mm1 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm3 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm5 \n\t" + "psubusb %%mm1, %%mm3 \n\t" + "psubusb %%mm5, %%mm1 \n\t" + "por %%mm2, %%mm0 \n\t" + "por %%mm1, %%mm3 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm3, %%mm2 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpckhbw %%mm7, %%mm1 \n\t" + "punpcklbw %%mm7, %%mm3 \n\t" + "punpckhbw %%mm7, %%mm2 \n\t" + "paddw %%mm1, %%mm0 \n\t" + "paddw %%mm3, %%mm2 \n\t" + "paddw %%mm2, %%mm0 \n\t" + "paddw %%mm0, %%mm6 \n\t" + "add %3, %%"FF_REG_a" \n\t" + " js 1b \n\t" + : "+a" (len) + : "r" (blk1 - len), "r" (blk2 - len), "r" (stride)); +} + +static inline void sad8_2_mmx(uint8_t *blk1a, uint8_t *blk1b, uint8_t *blk2, + ptrdiff_t stride, int h) +{ + x86_reg len = -stride * h; + __asm__ volatile ( + ".p2align 4 \n\t" + "1: \n\t" + "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm1 \n\t" + "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm3 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm1 \n\t" + "punpckhbw %%mm7, %%mm2 \n\t" + "punpckhbw %%mm7, %%mm3 \n\t" + "paddw %%mm0, %%mm1 \n\t" + "paddw %%mm2, %%mm3 \n\t" + "movq (%3, %%"FF_REG_a"), %%mm4 \n\t" + "movq (%3, %%"FF_REG_a"), %%mm2 \n\t" + "paddw %%mm5, %%mm1 \n\t" + "paddw %%mm5, %%mm3 \n\t" + "psrlw $1, %%mm1 \n\t" + "psrlw $1, %%mm3 \n\t" + "packuswb %%mm3, %%mm1 \n\t" + "psubusb %%mm1, %%mm4 \n\t" + "psubusb %%mm2, %%mm1 \n\t" + "por %%mm4, %%mm1 \n\t" + "movq %%mm1, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpckhbw %%mm7, %%mm1 \n\t" + "paddw %%mm1, %%mm0 \n\t" + "paddw %%mm0, %%mm6 \n\t" + "add %4, %%"FF_REG_a" \n\t" + " js 1b \n\t" + : "+a" (len) + : "r" (blk1a - len), "r" (blk1b - len), "r" (blk2 - len), + "r" (stride)); +} + +static inline void sad8_4_mmx(uint8_t *blk1, uint8_t *blk2, + ptrdiff_t stride, int h) +{ + x86_reg len = -stride * h; + __asm__ volatile ( + "movq (%1, %%"FF_REG_a"), %%mm0\n\t" + "movq 1(%1, %%"FF_REG_a"), %%mm2\n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm2, %%mm3 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpckhbw %%mm7, %%mm1 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpckhbw %%mm7, %%mm3 \n\t" + "paddw %%mm2, %%mm0 \n\t" + "paddw %%mm3, %%mm1 \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movq (%2, %%"FF_REG_a"), %%mm2\n\t" + "movq 1(%2, %%"FF_REG_a"), %%mm4\n\t" + "movq %%mm2, %%mm3 \n\t" + "movq %%mm4, %%mm5 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpckhbw %%mm7, %%mm3 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "punpckhbw %%mm7, %%mm5 \n\t" + "paddw %%mm4, %%mm2 \n\t" + "paddw %%mm5, %%mm3 \n\t" + "movq %5, %%mm5 \n\t" + "paddw %%mm2, %%mm0 \n\t" + "paddw %%mm3, %%mm1 \n\t" + "paddw %%mm5, %%mm0 \n\t" + "paddw %%mm5, %%mm1 \n\t" + "movq (%3, %%"FF_REG_a"), %%mm4 \n\t" + "movq (%3, %%"FF_REG_a"), %%mm5 \n\t" + "psrlw $2, %%mm0 \n\t" + "psrlw $2, %%mm1 \n\t" + "packuswb %%mm1, %%mm0 \n\t" + "psubusb %%mm0, %%mm4 \n\t" + "psubusb %%mm5, %%mm0 \n\t" + "por %%mm4, %%mm0 \n\t" + "movq %%mm0, %%mm4 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpckhbw %%mm7, %%mm4 \n\t" + "paddw %%mm0, %%mm6 \n\t" + "paddw %%mm4, %%mm6 \n\t" + "movq %%mm2, %%mm0 \n\t" + "movq %%mm3, %%mm1 \n\t" + "add %4, %%"FF_REG_a" \n\t" + " js 1b \n\t" + : "+a" (len) + : "r" (blk1 - len), "r" (blk1 - len + stride), "r" (blk2 - len), + "r" (stride), "m" (round_tab[2])); +} + +static inline int sum_mmx(void) +{ + int ret; + __asm__ volatile ( + "movq %%mm6, %%mm0 \n\t" + "psrlq $32, %%mm6 \n\t" + "paddw %%mm0, %%mm6 \n\t" + "movq %%mm6, %%mm0 \n\t" + "psrlq $16, %%mm6 \n\t" + "paddw %%mm0, %%mm6 \n\t" + "movd %%mm6, %0 \n\t" + : "=r" (ret)); + return ret & 0xFFFF; +} + +static inline void sad8_x2a_mmx(uint8_t *blk1, uint8_t *blk2, + ptrdiff_t stride, int h) +{ + sad8_2_mmx(blk1, blk1 + 1, blk2, stride, h); +} + +static inline void sad8_y2a_mmx(uint8_t *blk1, uint8_t *blk2, + ptrdiff_t stride, int h) +{ + sad8_2_mmx(blk1, blk1 + stride, blk2, stride, h); +} + +#define PIX_SAD(suf) \ +static int sad8_ ## suf(MpegEncContext *v, uint8_t *blk2, \ + uint8_t *blk1, ptrdiff_t stride, int h) \ +{ \ + av_assert2(h == 8); \ + __asm__ volatile ( \ + "pxor %%mm7, %%mm7 \n\t" \ + "pxor %%mm6, %%mm6 \n\t" \ + :); \ + \ + sad8_1_ ## suf(blk1, blk2, stride, 8); \ + \ + return sum_ ## suf(); \ +} \ + \ +static int sad8_x2_ ## suf(MpegEncContext *v, uint8_t *blk2, \ + uint8_t *blk1, ptrdiff_t stride, int h) \ +{ \ + av_assert2(h == 8); \ + __asm__ volatile ( \ + "pxor %%mm7, %%mm7 \n\t" \ + "pxor %%mm6, %%mm6 \n\t" \ + "movq %0, %%mm5 \n\t" \ + :: "m" (round_tab[1])); \ + \ + sad8_x2a_ ## suf(blk1, blk2, stride, 8); \ + \ + return sum_ ## suf(); \ +} \ + \ +static int sad8_y2_ ## suf(MpegEncContext *v, uint8_t *blk2, \ + uint8_t *blk1, ptrdiff_t stride, int h) \ +{ \ + av_assert2(h == 8); \ + __asm__ volatile ( \ + "pxor %%mm7, %%mm7 \n\t" \ + "pxor %%mm6, %%mm6 \n\t" \ + "movq %0, %%mm5 \n\t" \ + :: "m" (round_tab[1])); \ + \ + sad8_y2a_ ## suf(blk1, blk2, stride, 8); \ + \ + return sum_ ## suf(); \ +} \ + \ +static int sad8_xy2_ ## suf(MpegEncContext *v, uint8_t *blk2, \ + uint8_t *blk1, ptrdiff_t stride, int h) \ +{ \ + av_assert2(h == 8); \ + __asm__ volatile ( \ + "pxor %%mm7, %%mm7 \n\t" \ + "pxor %%mm6, %%mm6 \n\t" \ + ::); \ + \ + sad8_4_ ## suf(blk1, blk2, stride, 8); \ + \ + return sum_ ## suf(); \ +} \ + \ +static int sad16_ ## suf(MpegEncContext *v, uint8_t *blk2, \ + uint8_t *blk1, ptrdiff_t stride, int h) \ +{ \ + __asm__ volatile ( \ + "pxor %%mm7, %%mm7 \n\t" \ + "pxor %%mm6, %%mm6 \n\t" \ + :); \ + \ + sad8_1_ ## suf(blk1, blk2, stride, h); \ + sad8_1_ ## suf(blk1 + 8, blk2 + 8, stride, h); \ + \ + return sum_ ## suf(); \ +} \ + \ +static int sad16_x2_ ## suf(MpegEncContext *v, uint8_t *blk2, \ + uint8_t *blk1, ptrdiff_t stride, int h) \ +{ \ + __asm__ volatile ( \ + "pxor %%mm7, %%mm7 \n\t" \ + "pxor %%mm6, %%mm6 \n\t" \ + "movq %0, %%mm5 \n\t" \ + :: "m" (round_tab[1])); \ + \ + sad8_x2a_ ## suf(blk1, blk2, stride, h); \ + sad8_x2a_ ## suf(blk1 + 8, blk2 + 8, stride, h); \ + \ + return sum_ ## suf(); \ +} \ + \ +static int sad16_y2_ ## suf(MpegEncContext *v, uint8_t *blk2, \ + uint8_t *blk1, ptrdiff_t stride, int h) \ +{ \ + __asm__ volatile ( \ + "pxor %%mm7, %%mm7 \n\t" \ + "pxor %%mm6, %%mm6 \n\t" \ + "movq %0, %%mm5 \n\t" \ + :: "m" (round_tab[1])); \ + \ + sad8_y2a_ ## suf(blk1, blk2, stride, h); \ + sad8_y2a_ ## suf(blk1 + 8, blk2 + 8, stride, h); \ + \ + return sum_ ## suf(); \ +} \ + \ +static int sad16_xy2_ ## suf(MpegEncContext *v, uint8_t *blk2, \ + uint8_t *blk1, ptrdiff_t stride, int h) \ +{ \ + __asm__ volatile ( \ + "pxor %%mm7, %%mm7 \n\t" \ + "pxor %%mm6, %%mm6 \n\t" \ + ::); \ + \ + sad8_4_ ## suf(blk1, blk2, stride, h); \ + sad8_4_ ## suf(blk1 + 8, blk2 + 8, stride, h); \ + \ + return sum_ ## suf(); \ +} \ + +PIX_SAD(mmx) + +#endif /* HAVE_INLINE_ASM */ + +av_cold void ff_me_cmp_init_x86(MECmpContext *c, AVCodecContext *avctx) +{ + int cpu_flags = av_get_cpu_flags(); + +#if HAVE_INLINE_ASM + if (INLINE_MMX(cpu_flags)) { + c->pix_abs[0][0] = sad16_mmx; + c->pix_abs[0][1] = sad16_x2_mmx; + c->pix_abs[0][2] = sad16_y2_mmx; + c->pix_abs[0][3] = sad16_xy2_mmx; + c->pix_abs[1][0] = sad8_mmx; + c->pix_abs[1][1] = sad8_x2_mmx; + c->pix_abs[1][2] = sad8_y2_mmx; + c->pix_abs[1][3] = sad8_xy2_mmx; + + c->sad[0] = sad16_mmx; + c->sad[1] = sad8_mmx; + + c->vsad[4] = vsad_intra16_mmx; + + if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { + c->vsad[0] = vsad16_mmx; + } + } + +#endif /* HAVE_INLINE_ASM */ + + if (EXTERNAL_MMX(cpu_flags)) { + c->hadamard8_diff[0] = ff_hadamard8_diff16_mmx; + c->hadamard8_diff[1] = ff_hadamard8_diff_mmx; + c->sum_abs_dctelem = ff_sum_abs_dctelem_mmx; + c->sse[0] = ff_sse16_mmx; + c->sse[1] = ff_sse8_mmx; +#if HAVE_X86ASM + c->nsse[0] = nsse16_mmx; + c->nsse[1] = nsse8_mmx; +#endif + } + + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->hadamard8_diff[0] = ff_hadamard8_diff16_mmxext; + c->hadamard8_diff[1] = ff_hadamard8_diff_mmxext; + c->sum_abs_dctelem = ff_sum_abs_dctelem_mmxext; + + c->sad[0] = ff_sad16_mmxext; + c->sad[1] = ff_sad8_mmxext; + + c->pix_abs[0][0] = ff_sad16_mmxext; + c->pix_abs[0][1] = ff_sad16_x2_mmxext; + c->pix_abs[0][2] = ff_sad16_y2_mmxext; + c->pix_abs[1][0] = ff_sad8_mmxext; + c->pix_abs[1][1] = ff_sad8_x2_mmxext; + c->pix_abs[1][2] = ff_sad8_y2_mmxext; + + c->vsad[4] = ff_vsad_intra16_mmxext; + c->vsad[5] = ff_vsad_intra8_mmxext; + + if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { + c->pix_abs[0][3] = ff_sad16_approx_xy2_mmxext; + c->pix_abs[1][3] = ff_sad8_approx_xy2_mmxext; + + c->vsad[0] = ff_vsad16_approx_mmxext; + c->vsad[1] = ff_vsad8_approx_mmxext; + } + } + + if (EXTERNAL_SSE2(cpu_flags)) { + c->sse[0] = ff_sse16_sse2; + c->sum_abs_dctelem = ff_sum_abs_dctelem_sse2; + +#if HAVE_ALIGNED_STACK + c->hadamard8_diff[0] = ff_hadamard8_diff16_sse2; + c->hadamard8_diff[1] = ff_hadamard8_diff_sse2; +#endif + if (!(cpu_flags & AV_CPU_FLAG_SSE2SLOW) && avctx->codec_id != AV_CODEC_ID_SNOW) { + c->sad[0] = ff_sad16_sse2; + c->pix_abs[0][0] = ff_sad16_sse2; + c->pix_abs[0][1] = ff_sad16_x2_sse2; + c->pix_abs[0][2] = ff_sad16_y2_sse2; + + c->vsad[4] = ff_vsad_intra16_sse2; + if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { + c->pix_abs[0][3] = ff_sad16_approx_xy2_sse2; + c->vsad[0] = ff_vsad16_approx_sse2; + } + } + } + + if (EXTERNAL_SSSE3(cpu_flags)) { + c->sum_abs_dctelem = ff_sum_abs_dctelem_ssse3; +#if HAVE_ALIGNED_STACK + c->hadamard8_diff[0] = ff_hadamard8_diff16_ssse3; + c->hadamard8_diff[1] = ff_hadamard8_diff_ssse3; +#endif + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mlpdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mlpdsp_init.c new file mode 100644 index 0000000000..cb90ca24f0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mlpdsp_init.c @@ -0,0 +1,204 @@ +/* + * MLP DSP functions x86-optimized + * Copyright (c) 2009 Ramiro Polla + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/mlpdsp.h" +#include "libavcodec/mlp.h" + +#define REMATRIX_CHANNEL_FUNC(opt) \ +void ff_mlp_rematrix_channel_##opt(int32_t *samples, \ + const int32_t *coeffs, \ + const uint8_t *bypassed_lsbs, \ + const int8_t *noise_buffer, \ + int index, \ + unsigned int dest_ch, \ + uint16_t blockpos, \ + unsigned int maxchan, \ + int matrix_noise_shift, \ + int access_unit_size_pow2, \ + int32_t mask); + +REMATRIX_CHANNEL_FUNC(sse4) +REMATRIX_CHANNEL_FUNC(avx2_bmi2) + +#if HAVE_7REGS && HAVE_INLINE_ASM && HAVE_INLINE_ASM_NONLOCAL_LABELS + +extern char ff_mlp_firorder_8; +extern char ff_mlp_firorder_7; +extern char ff_mlp_firorder_6; +extern char ff_mlp_firorder_5; +extern char ff_mlp_firorder_4; +extern char ff_mlp_firorder_3; +extern char ff_mlp_firorder_2; +extern char ff_mlp_firorder_1; +extern char ff_mlp_firorder_0; + +extern char ff_mlp_iirorder_4; +extern char ff_mlp_iirorder_3; +extern char ff_mlp_iirorder_2; +extern char ff_mlp_iirorder_1; +extern char ff_mlp_iirorder_0; + +static const void * const firtable[9] = { &ff_mlp_firorder_0, &ff_mlp_firorder_1, + &ff_mlp_firorder_2, &ff_mlp_firorder_3, + &ff_mlp_firorder_4, &ff_mlp_firorder_5, + &ff_mlp_firorder_6, &ff_mlp_firorder_7, + &ff_mlp_firorder_8 }; +static const void * const iirtable[5] = { &ff_mlp_iirorder_0, &ff_mlp_iirorder_1, + &ff_mlp_iirorder_2, &ff_mlp_iirorder_3, + &ff_mlp_iirorder_4 }; + +#if ARCH_X86_64 + +#define MLPMUL(label, offset, offs, offc) \ + LABEL_MANGLE(label)": \n\t" \ + "movslq "offset"+"offs"(%0), %%rax\n\t" \ + "movslq "offset"+"offc"(%1), %%rdx\n\t" \ + "imul %%rdx, %%rax\n\t" \ + "add %%rax, %%rsi\n\t" + +#define FIRMULREG(label, offset, firc)\ + LABEL_MANGLE(label)": \n\t" \ + "movslq "#offset"(%0), %%rax\n\t" \ + "imul %"#firc", %%rax\n\t" \ + "add %%rax, %%rsi\n\t" + +#define CLEAR_ACCUM \ + "xor %%rsi, %%rsi\n\t" + +#define SHIFT_ACCUM \ + "shr %%cl, %%rsi\n\t" + +#define ACCUM "%%rdx" +#define RESULT "%%rsi" +#define RESULT32 "%%esi" + +#else /* if ARCH_X86_32 */ + +#define MLPMUL(label, offset, offs, offc) \ + LABEL_MANGLE(label)": \n\t" \ + "mov "offset"+"offs"(%0), %%eax\n\t" \ + "imull "offset"+"offc"(%1) \n\t" \ + "add %%eax , %%esi\n\t" \ + "adc %%edx , %%ecx\n\t" + +#define FIRMULREG(label, offset, firc) \ + MLPMUL(label, #offset, "0", "0") + +#define CLEAR_ACCUM \ + "xor %%esi, %%esi\n\t" \ + "xor %%ecx, %%ecx\n\t" + +#define SHIFT_ACCUM \ + "mov %%ecx, %%edx\n\t" \ + "mov %%esi, %%eax\n\t" \ + "movzbl %7 , %%ecx\n\t" \ + "shrd %%cl, %%edx, %%eax\n\t" \ + +#define ACCUM "%%edx" +#define RESULT "%%eax" +#define RESULT32 "%%eax" + +#endif /* !ARCH_X86_64 */ + +#define BINC AV_STRINGIFY(4* MAX_CHANNELS) +#define IOFFS AV_STRINGIFY(4*(MAX_FIR_ORDER + MAX_BLOCKSIZE)) +#define IOFFC AV_STRINGIFY(4* MAX_FIR_ORDER) + +#define FIRMUL(label, offset) MLPMUL(label, #offset, "0", "0") +#define IIRMUL(label, offset) MLPMUL(label, #offset, IOFFS, IOFFC) + +static void mlp_filter_channel_x86(int32_t *state, const int32_t *coeff, + int firorder, int iirorder, + unsigned int filter_shift, int32_t mask, + int blocksize, int32_t *sample_buffer) +{ + const void *firjump = firtable[firorder]; + const void *iirjump = iirtable[iirorder]; + + blocksize = -blocksize; + + __asm__ volatile( + "1: \n\t" + CLEAR_ACCUM + "jmp *%5 \n\t" + FIRMUL (ff_mlp_firorder_8, 0x1c ) + FIRMUL (ff_mlp_firorder_7, 0x18 ) + FIRMUL (ff_mlp_firorder_6, 0x14 ) + FIRMUL (ff_mlp_firorder_5, 0x10 ) + FIRMUL (ff_mlp_firorder_4, 0x0c ) + FIRMUL (ff_mlp_firorder_3, 0x08 ) + FIRMUL (ff_mlp_firorder_2, 0x04 ) + FIRMULREG(ff_mlp_firorder_1, 0x00, 8) + LABEL_MANGLE(ff_mlp_firorder_0)":\n\t" + "jmp *%6 \n\t" + IIRMUL (ff_mlp_iirorder_4, 0x0c ) + IIRMUL (ff_mlp_iirorder_3, 0x08 ) + IIRMUL (ff_mlp_iirorder_2, 0x04 ) + IIRMUL (ff_mlp_iirorder_1, 0x00 ) + LABEL_MANGLE(ff_mlp_iirorder_0)":\n\t" + SHIFT_ACCUM + "mov "RESULT" ,"ACCUM" \n\t" + "add (%2) ,"RESULT" \n\t" + "and %4 ,"RESULT" \n\t" + "sub $4 , %0 \n\t" + "mov "RESULT32", (%0) \n\t" + "mov "RESULT32", (%2) \n\t" + "add $"BINC" , %2 \n\t" + "sub "ACCUM" ,"RESULT" \n\t" + "mov "RESULT32","IOFFS"(%0) \n\t" + "incl %3 \n\t" + "js 1b \n\t" + : /* 0*/"+r"(state), + /* 1*/"+r"(coeff), + /* 2*/"+r"(sample_buffer), +#if ARCH_X86_64 + /* 3*/"+r"(blocksize) + : /* 4*/"r"((x86_reg)mask), /* 5*/"r"(firjump), + /* 6*/"r"(iirjump) , /* 7*/"c"(filter_shift) + , /* 8*/"r"((int64_t)coeff[0]) + : "rax", "rdx", "rsi" +#else /* ARCH_X86_32 */ + /* 3*/"+m"(blocksize) + : /* 4*/"m"( mask), /* 5*/"m"(firjump), + /* 6*/"m"(iirjump) , /* 7*/"m"(filter_shift) + : "eax", "edx", "esi", "ecx" +#endif /* !ARCH_X86_64 */ + ); +} + +#endif /* HAVE_7REGS && HAVE_INLINE_ASM */ + +av_cold void ff_mlpdsp_init_x86(MLPDSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); +#if HAVE_7REGS && HAVE_INLINE_ASM && HAVE_INLINE_ASM_NONLOCAL_LABELS + if (INLINE_MMX(cpu_flags)) + c->mlp_filter_channel = mlp_filter_channel_x86; +#endif + if (ARCH_X86_64 && EXTERNAL_SSE4(cpu_flags)) + c->mlp_rematrix_channel = ff_mlp_rematrix_channel_sse4; + if (ARCH_X86_64 && EXTERNAL_AVX2_FAST(cpu_flags) && cpu_flags & AV_CPU_FLAG_BMI2) + c->mlp_rematrix_channel = ff_mlp_rematrix_channel_avx2_bmi2; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegaudiodsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegaudiodsp.c new file mode 100644 index 0000000000..f46a5c4f3d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegaudiodsp.c @@ -0,0 +1,289 @@ +/* + * SIMD-optimized MP3 decoding functions + * Copyright (c) 2010 Vitor Sessak + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/internal.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/mpegaudiodsp.h" + +#define DECL(CPU)\ +static void imdct36_blocks_ ## CPU(float *out, float *buf, float *in, int count, int switch_point, int block_type);\ +void ff_imdct36_float_ ## CPU(float *out, float *buf, float *in, float *win); + +#if HAVE_X86ASM +#if ARCH_X86_32 +DECL(sse) +#endif +DECL(sse2) +DECL(sse3) +DECL(ssse3) +DECL(avx) +#endif /* HAVE_X86ASM */ + +void ff_four_imdct36_float_sse(float *out, float *buf, float *in, float *win, + float *tmpbuf); +void ff_four_imdct36_float_avx(float *out, float *buf, float *in, float *win, + float *tmpbuf); + +DECLARE_ALIGNED(16, static float, mdct_win_sse)[2][4][4*40]; + +#if HAVE_6REGS && HAVE_SSE_INLINE + +#define MACS(rt, ra, rb) rt+=(ra)*(rb) +#define MLSS(rt, ra, rb) rt-=(ra)*(rb) + +#define SUM8(op, sum, w, p) \ +{ \ + op(sum, (w)[0 * 64], (p)[0 * 64]); \ + op(sum, (w)[1 * 64], (p)[1 * 64]); \ + op(sum, (w)[2 * 64], (p)[2 * 64]); \ + op(sum, (w)[3 * 64], (p)[3 * 64]); \ + op(sum, (w)[4 * 64], (p)[4 * 64]); \ + op(sum, (w)[5 * 64], (p)[5 * 64]); \ + op(sum, (w)[6 * 64], (p)[6 * 64]); \ + op(sum, (w)[7 * 64], (p)[7 * 64]); \ +} + +static void apply_window(const float *buf, const float *win1, + const float *win2, float *sum1, float *sum2, int len) +{ + x86_reg count = - 4*len; + const float *win1a = win1+len; + const float *win2a = win2+len; + const float *bufa = buf+len; + float *sum1a = sum1+len; + float *sum2a = sum2+len; + + +#define MULT(a, b) \ + "movaps " #a "(%1,%0), %%xmm1 \n\t" \ + "movaps " #a "(%3,%0), %%xmm2 \n\t" \ + "mulps %%xmm2, %%xmm1 \n\t" \ + "subps %%xmm1, %%xmm0 \n\t" \ + "mulps " #b "(%2,%0), %%xmm2 \n\t" \ + "subps %%xmm2, %%xmm4 \n\t" \ + + __asm__ volatile( + "1: \n\t" + "xorps %%xmm0, %%xmm0 \n\t" + "xorps %%xmm4, %%xmm4 \n\t" + + MULT( 0, 0) + MULT( 256, 64) + MULT( 512, 128) + MULT( 768, 192) + MULT(1024, 256) + MULT(1280, 320) + MULT(1536, 384) + MULT(1792, 448) + + "movaps %%xmm0, (%4,%0) \n\t" + "movaps %%xmm4, (%5,%0) \n\t" + "add $16, %0 \n\t" + "jl 1b \n\t" + :"+&r"(count) + :"r"(win1a), "r"(win2a), "r"(bufa), "r"(sum1a), "r"(sum2a) + ); + +#undef MULT +} + +static void apply_window_mp3(float *in, float *win, int *unused, float *out, + ptrdiff_t incr) +{ + LOCAL_ALIGNED_16(float, suma, [17]); + LOCAL_ALIGNED_16(float, sumb, [17]); + LOCAL_ALIGNED_16(float, sumc, [17]); + LOCAL_ALIGNED_16(float, sumd, [17]); + + float sum; + + /* copy to avoid wrap */ + __asm__ volatile( + "movaps 0(%0), %%xmm0 \n\t" \ + "movaps 16(%0), %%xmm1 \n\t" \ + "movaps 32(%0), %%xmm2 \n\t" \ + "movaps 48(%0), %%xmm3 \n\t" \ + "movaps %%xmm0, 0(%1) \n\t" \ + "movaps %%xmm1, 16(%1) \n\t" \ + "movaps %%xmm2, 32(%1) \n\t" \ + "movaps %%xmm3, 48(%1) \n\t" \ + "movaps 64(%0), %%xmm0 \n\t" \ + "movaps 80(%0), %%xmm1 \n\t" \ + "movaps 96(%0), %%xmm2 \n\t" \ + "movaps 112(%0), %%xmm3 \n\t" \ + "movaps %%xmm0, 64(%1) \n\t" \ + "movaps %%xmm1, 80(%1) \n\t" \ + "movaps %%xmm2, 96(%1) \n\t" \ + "movaps %%xmm3, 112(%1) \n\t" + ::"r"(in), "r"(in+512) + :"memory" + ); + + apply_window(in + 16, win , win + 512, suma, sumc, 16); + apply_window(in + 32, win + 48, win + 640, sumb, sumd, 16); + + SUM8(MACS, suma[0], win + 32, in + 48); + + sumc[ 0] = 0; + sumb[16] = 0; + sumd[16] = 0; + +#define SUMS(suma, sumb, sumc, sumd, out1, out2) \ + "movups " #sumd "(%4), %%xmm0 \n\t" \ + "shufps $0x1b, %%xmm0, %%xmm0 \n\t" \ + "subps " #suma "(%1), %%xmm0 \n\t" \ + "movaps %%xmm0," #out1 "(%0) \n\t" \ +\ + "movups " #sumc "(%3), %%xmm0 \n\t" \ + "shufps $0x1b, %%xmm0, %%xmm0 \n\t" \ + "addps " #sumb "(%2), %%xmm0 \n\t" \ + "movaps %%xmm0," #out2 "(%0) \n\t" + + if (incr == 1) { + __asm__ volatile( + SUMS( 0, 48, 4, 52, 0, 112) + SUMS(16, 32, 20, 36, 16, 96) + SUMS(32, 16, 36, 20, 32, 80) + SUMS(48, 0, 52, 4, 48, 64) + + :"+&r"(out) + :"r"(&suma[0]), "r"(&sumb[0]), "r"(&sumc[0]), "r"(&sumd[0]) + :"memory" + ); + out += 16*incr; + } else { + int j; + float *out2 = out + 32 * incr; + out[0 ] = -suma[ 0]; + out += incr; + out2 -= incr; + for(j=1;j<16;j++) { + *out = -suma[ j] + sumd[16-j]; + *out2 = sumb[16-j] + sumc[ j]; + out += incr; + out2 -= incr; + } + } + + sum = 0; + SUM8(MLSS, sum, win + 16 + 32, in + 32); + *out = sum; +} + +#endif /* HAVE_6REGS && HAVE_SSE_INLINE */ + +#if HAVE_X86ASM +#define DECL_IMDCT_BLOCKS(CPU1, CPU2) \ +static void imdct36_blocks_ ## CPU1(float *out, float *buf, float *in, \ + int count, int switch_point, int block_type) \ +{ \ + int align_end = count - (count & 3); \ + int j; \ + for (j = 0; j < align_end; j+= 4) { \ + LOCAL_ALIGNED_16(float, tmpbuf, [1024]); \ + float *win = mdct_win_sse[switch_point && j < 4][block_type]; \ + /* apply window & overlap with previous buffer */ \ + \ + /* select window */ \ + ff_four_imdct36_float_ ## CPU2(out, buf, in, win, tmpbuf); \ + in += 4*18; \ + buf += 4*18; \ + out += 4; \ + } \ + for (; j < count; j++) { \ + /* apply window & overlap with previous buffer */ \ + \ + /* select window */ \ + int win_idx = (switch_point && j < 2) ? 0 : block_type; \ + float *win = ff_mdct_win_float[win_idx + (4 & -(j & 1))]; \ + \ + ff_imdct36_float_ ## CPU1(out, buf, in, win); \ + \ + in += 18; \ + buf++; \ + out++; \ + } \ +} + +#if HAVE_SSE +#if ARCH_X86_32 +DECL_IMDCT_BLOCKS(sse,sse) +#endif +DECL_IMDCT_BLOCKS(sse2,sse) +DECL_IMDCT_BLOCKS(sse3,sse) +DECL_IMDCT_BLOCKS(ssse3,sse) +#endif +#if HAVE_AVX_EXTERNAL +DECL_IMDCT_BLOCKS(avx,avx) +#endif +#endif /* HAVE_X86ASM */ + +av_cold void ff_mpadsp_init_x86(MPADSPContext *s) +{ + av_unused int cpu_flags = av_get_cpu_flags(); + + int i, j; + for (j = 0; j < 4; j++) { + for (i = 0; i < 40; i ++) { + mdct_win_sse[0][j][4*i ] = ff_mdct_win_float[j ][i]; + mdct_win_sse[0][j][4*i + 1] = ff_mdct_win_float[j + 4][i]; + mdct_win_sse[0][j][4*i + 2] = ff_mdct_win_float[j ][i]; + mdct_win_sse[0][j][4*i + 3] = ff_mdct_win_float[j + 4][i]; + mdct_win_sse[1][j][4*i ] = ff_mdct_win_float[0 ][i]; + mdct_win_sse[1][j][4*i + 1] = ff_mdct_win_float[4 ][i]; + mdct_win_sse[1][j][4*i + 2] = ff_mdct_win_float[j ][i]; + mdct_win_sse[1][j][4*i + 3] = ff_mdct_win_float[j + 4][i]; + } + } + +#if HAVE_6REGS && HAVE_SSE_INLINE + if (INLINE_SSE(cpu_flags)) { + s->apply_window_float = apply_window_mp3; + } +#endif /* HAVE_SSE_INLINE */ + +#if HAVE_X86ASM +#if HAVE_SSE +#if ARCH_X86_32 + if (EXTERNAL_SSE(cpu_flags)) { + s->imdct36_blocks_float = imdct36_blocks_sse; + } +#endif + if (EXTERNAL_SSE2(cpu_flags)) { + s->imdct36_blocks_float = imdct36_blocks_sse2; + } + if (EXTERNAL_SSE3(cpu_flags)) { + s->imdct36_blocks_float = imdct36_blocks_sse3; + } + if (EXTERNAL_SSSE3(cpu_flags)) { + s->imdct36_blocks_float = imdct36_blocks_ssse3; + } +#endif +#if HAVE_AVX_EXTERNAL + if (EXTERNAL_AVX(cpu_flags)) { + s->imdct36_blocks_float = imdct36_blocks_avx; + } +#endif +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideo.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideo.c new file mode 100644 index 0000000000..73967cafda --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideo.c @@ -0,0 +1,469 @@ +/* + * Optimized for ia32 CPUs by Nick Kurshev + * H.263, MPEG-1, MPEG-2 dequantizer & draw_edges by Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/mpegvideo.h" +#include "libavcodec/mpegvideodata.h" + +#if HAVE_MMX_INLINE + +static void dct_unquantize_h263_intra_mmx(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + x86_reg level, qmul, qadd, nCoeffs; + + qmul = qscale << 1; + + av_assert2(s->block_last_index[n]>=0 || s->h263_aic); + + if (!s->h263_aic) { + if (n < 4) + level = block[0] * s->y_dc_scale; + else + level = block[0] * s->c_dc_scale; + qadd = (qscale - 1) | 1; + }else{ + qadd = 0; + level= block[0]; + } + if(s->ac_pred) + nCoeffs=63; + else + nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; + +__asm__ volatile( + "movd %1, %%mm6 \n\t" //qmul + "packssdw %%mm6, %%mm6 \n\t" + "packssdw %%mm6, %%mm6 \n\t" + "movd %2, %%mm5 \n\t" //qadd + "pxor %%mm7, %%mm7 \n\t" + "packssdw %%mm5, %%mm5 \n\t" + "packssdw %%mm5, %%mm5 \n\t" + "psubw %%mm5, %%mm7 \n\t" + "pxor %%mm4, %%mm4 \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movq (%0, %3), %%mm0 \n\t" + "movq 8(%0, %3), %%mm1 \n\t" + + "pmullw %%mm6, %%mm0 \n\t" + "pmullw %%mm6, %%mm1 \n\t" + + "movq (%0, %3), %%mm2 \n\t" + "movq 8(%0, %3), %%mm3 \n\t" + + "pcmpgtw %%mm4, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 + "pcmpgtw %%mm4, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 + + "pxor %%mm2, %%mm0 \n\t" + "pxor %%mm3, %%mm1 \n\t" + + "paddw %%mm7, %%mm0 \n\t" + "paddw %%mm7, %%mm1 \n\t" + + "pxor %%mm0, %%mm2 \n\t" + "pxor %%mm1, %%mm3 \n\t" + + "pcmpeqw %%mm7, %%mm0 \n\t" // block[i] == 0 ? -1 : 0 + "pcmpeqw %%mm7, %%mm1 \n\t" // block[i] == 0 ? -1 : 0 + + "pandn %%mm2, %%mm0 \n\t" + "pandn %%mm3, %%mm1 \n\t" + + "movq %%mm0, (%0, %3) \n\t" + "movq %%mm1, 8(%0, %3) \n\t" + + "add $16, %3 \n\t" + "jng 1b \n\t" + ::"r" (block+nCoeffs), "rm"(qmul), "rm" (qadd), "r" (2*(-nCoeffs)) + : "memory" + ); + block[0]= level; +} + + +static void dct_unquantize_h263_inter_mmx(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + x86_reg qmul, qadd, nCoeffs; + + qmul = qscale << 1; + qadd = (qscale - 1) | 1; + + av_assert2(s->block_last_index[n]>=0 || s->h263_aic); + + nCoeffs= s->inter_scantable.raster_end[ s->block_last_index[n] ]; + +__asm__ volatile( + "movd %1, %%mm6 \n\t" //qmul + "packssdw %%mm6, %%mm6 \n\t" + "packssdw %%mm6, %%mm6 \n\t" + "movd %2, %%mm5 \n\t" //qadd + "pxor %%mm7, %%mm7 \n\t" + "packssdw %%mm5, %%mm5 \n\t" + "packssdw %%mm5, %%mm5 \n\t" + "psubw %%mm5, %%mm7 \n\t" + "pxor %%mm4, %%mm4 \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movq (%0, %3), %%mm0 \n\t" + "movq 8(%0, %3), %%mm1 \n\t" + + "pmullw %%mm6, %%mm0 \n\t" + "pmullw %%mm6, %%mm1 \n\t" + + "movq (%0, %3), %%mm2 \n\t" + "movq 8(%0, %3), %%mm3 \n\t" + + "pcmpgtw %%mm4, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 + "pcmpgtw %%mm4, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 + + "pxor %%mm2, %%mm0 \n\t" + "pxor %%mm3, %%mm1 \n\t" + + "paddw %%mm7, %%mm0 \n\t" + "paddw %%mm7, %%mm1 \n\t" + + "pxor %%mm0, %%mm2 \n\t" + "pxor %%mm1, %%mm3 \n\t" + + "pcmpeqw %%mm7, %%mm0 \n\t" // block[i] == 0 ? -1 : 0 + "pcmpeqw %%mm7, %%mm1 \n\t" // block[i] == 0 ? -1 : 0 + + "pandn %%mm2, %%mm0 \n\t" + "pandn %%mm3, %%mm1 \n\t" + + "movq %%mm0, (%0, %3) \n\t" + "movq %%mm1, 8(%0, %3) \n\t" + + "add $16, %3 \n\t" + "jng 1b \n\t" + ::"r" (block+nCoeffs), "rm"(qmul), "rm" (qadd), "r" (2*(-nCoeffs)) + : "memory" + ); +} + +static void dct_unquantize_mpeg1_intra_mmx(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + x86_reg nCoeffs; + const uint16_t *quant_matrix; + int block0; + + av_assert2(s->block_last_index[n]>=0); + + nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]+1; + + if (n < 4) + block0 = block[0] * s->y_dc_scale; + else + block0 = block[0] * s->c_dc_scale; + /* XXX: only MPEG-1 */ + quant_matrix = s->intra_matrix; +__asm__ volatile( + "pcmpeqw %%mm7, %%mm7 \n\t" + "psrlw $15, %%mm7 \n\t" + "movd %2, %%mm6 \n\t" + "packssdw %%mm6, %%mm6 \n\t" + "packssdw %%mm6, %%mm6 \n\t" + "mov %3, %%"FF_REG_a" \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movq (%0, %%"FF_REG_a"), %%mm0 \n\t" + "movq 8(%0, %%"FF_REG_a"), %%mm1\n\t" + "movq (%1, %%"FF_REG_a"), %%mm4 \n\t" + "movq 8(%1, %%"FF_REG_a"), %%mm5\n\t" + "pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i] + "pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i] + "pxor %%mm2, %%mm2 \n\t" + "pxor %%mm3, %%mm3 \n\t" + "pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 + "pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 + "pxor %%mm2, %%mm0 \n\t" + "pxor %%mm3, %%mm1 \n\t" + "psubw %%mm2, %%mm0 \n\t" // abs(block[i]) + "psubw %%mm3, %%mm1 \n\t" // abs(block[i]) + "pmullw %%mm4, %%mm0 \n\t" // abs(block[i])*q + "pmullw %%mm5, %%mm1 \n\t" // abs(block[i])*q + "pxor %%mm4, %%mm4 \n\t" + "pxor %%mm5, %%mm5 \n\t" // FIXME slow + "pcmpeqw (%0, %%"FF_REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0 + "pcmpeqw 8(%0, %%"FF_REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0 + "psraw $3, %%mm0 \n\t" + "psraw $3, %%mm1 \n\t" + "psubw %%mm7, %%mm0 \n\t" + "psubw %%mm7, %%mm1 \n\t" + "por %%mm7, %%mm0 \n\t" + "por %%mm7, %%mm1 \n\t" + "pxor %%mm2, %%mm0 \n\t" + "pxor %%mm3, %%mm1 \n\t" + "psubw %%mm2, %%mm0 \n\t" + "psubw %%mm3, %%mm1 \n\t" + "pandn %%mm0, %%mm4 \n\t" + "pandn %%mm1, %%mm5 \n\t" + "movq %%mm4, (%0, %%"FF_REG_a") \n\t" + "movq %%mm5, 8(%0, %%"FF_REG_a")\n\t" + + "add $16, %%"FF_REG_a" \n\t" + "js 1b \n\t" + ::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "g" (-2*nCoeffs) + : "%"FF_REG_a, "memory" + ); + block[0]= block0; +} + +static void dct_unquantize_mpeg1_inter_mmx(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + x86_reg nCoeffs; + const uint16_t *quant_matrix; + + av_assert2(s->block_last_index[n]>=0); + + nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]+1; + + quant_matrix = s->inter_matrix; +__asm__ volatile( + "pcmpeqw %%mm7, %%mm7 \n\t" + "psrlw $15, %%mm7 \n\t" + "movd %2, %%mm6 \n\t" + "packssdw %%mm6, %%mm6 \n\t" + "packssdw %%mm6, %%mm6 \n\t" + "mov %3, %%"FF_REG_a" \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movq (%0, %%"FF_REG_a"), %%mm0 \n\t" + "movq 8(%0, %%"FF_REG_a"), %%mm1\n\t" + "movq (%1, %%"FF_REG_a"), %%mm4 \n\t" + "movq 8(%1, %%"FF_REG_a"), %%mm5\n\t" + "pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i] + "pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i] + "pxor %%mm2, %%mm2 \n\t" + "pxor %%mm3, %%mm3 \n\t" + "pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 + "pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 + "pxor %%mm2, %%mm0 \n\t" + "pxor %%mm3, %%mm1 \n\t" + "psubw %%mm2, %%mm0 \n\t" // abs(block[i]) + "psubw %%mm3, %%mm1 \n\t" // abs(block[i]) + "paddw %%mm0, %%mm0 \n\t" // abs(block[i])*2 + "paddw %%mm1, %%mm1 \n\t" // abs(block[i])*2 + "paddw %%mm7, %%mm0 \n\t" // abs(block[i])*2 + 1 + "paddw %%mm7, %%mm1 \n\t" // abs(block[i])*2 + 1 + "pmullw %%mm4, %%mm0 \n\t" // (abs(block[i])*2 + 1)*q + "pmullw %%mm5, %%mm1 \n\t" // (abs(block[i])*2 + 1)*q + "pxor %%mm4, %%mm4 \n\t" + "pxor %%mm5, %%mm5 \n\t" // FIXME slow + "pcmpeqw (%0, %%"FF_REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0 + "pcmpeqw 8(%0, %%"FF_REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0 + "psraw $4, %%mm0 \n\t" + "psraw $4, %%mm1 \n\t" + "psubw %%mm7, %%mm0 \n\t" + "psubw %%mm7, %%mm1 \n\t" + "por %%mm7, %%mm0 \n\t" + "por %%mm7, %%mm1 \n\t" + "pxor %%mm2, %%mm0 \n\t" + "pxor %%mm3, %%mm1 \n\t" + "psubw %%mm2, %%mm0 \n\t" + "psubw %%mm3, %%mm1 \n\t" + "pandn %%mm0, %%mm4 \n\t" + "pandn %%mm1, %%mm5 \n\t" + "movq %%mm4, (%0, %%"FF_REG_a") \n\t" + "movq %%mm5, 8(%0, %%"FF_REG_a")\n\t" + + "add $16, %%"FF_REG_a" \n\t" + "js 1b \n\t" + ::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "g" (-2*nCoeffs) + : "%"FF_REG_a, "memory" + ); +} + +static void dct_unquantize_mpeg2_intra_mmx(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + x86_reg nCoeffs; + const uint16_t *quant_matrix; + int block0; + + av_assert2(s->block_last_index[n]>=0); + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + if(s->alternate_scan) nCoeffs= 63; //FIXME + else nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; + + if (n < 4) + block0 = block[0] * s->y_dc_scale; + else + block0 = block[0] * s->c_dc_scale; + quant_matrix = s->intra_matrix; +__asm__ volatile( + "pcmpeqw %%mm7, %%mm7 \n\t" + "psrlw $15, %%mm7 \n\t" + "movd %2, %%mm6 \n\t" + "packssdw %%mm6, %%mm6 \n\t" + "packssdw %%mm6, %%mm6 \n\t" + "mov %3, %%"FF_REG_a" \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movq (%0, %%"FF_REG_a"), %%mm0 \n\t" + "movq 8(%0, %%"FF_REG_a"), %%mm1\n\t" + "movq (%1, %%"FF_REG_a"), %%mm4 \n\t" + "movq 8(%1, %%"FF_REG_a"), %%mm5\n\t" + "pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i] + "pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i] + "pxor %%mm2, %%mm2 \n\t" + "pxor %%mm3, %%mm3 \n\t" + "pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 + "pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 + "pxor %%mm2, %%mm0 \n\t" + "pxor %%mm3, %%mm1 \n\t" + "psubw %%mm2, %%mm0 \n\t" // abs(block[i]) + "psubw %%mm3, %%mm1 \n\t" // abs(block[i]) + "pmullw %%mm4, %%mm0 \n\t" // abs(block[i])*q + "pmullw %%mm5, %%mm1 \n\t" // abs(block[i])*q + "pxor %%mm4, %%mm4 \n\t" + "pxor %%mm5, %%mm5 \n\t" // FIXME slow + "pcmpeqw (%0, %%"FF_REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0 + "pcmpeqw 8(%0, %%"FF_REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0 + "psraw $4, %%mm0 \n\t" + "psraw $4, %%mm1 \n\t" + "pxor %%mm2, %%mm0 \n\t" + "pxor %%mm3, %%mm1 \n\t" + "psubw %%mm2, %%mm0 \n\t" + "psubw %%mm3, %%mm1 \n\t" + "pandn %%mm0, %%mm4 \n\t" + "pandn %%mm1, %%mm5 \n\t" + "movq %%mm4, (%0, %%"FF_REG_a") \n\t" + "movq %%mm5, 8(%0, %%"FF_REG_a")\n\t" + + "add $16, %%"FF_REG_a" \n\t" + "jng 1b \n\t" + ::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "g" (-2*nCoeffs) + : "%"FF_REG_a, "memory" + ); + block[0]= block0; + //Note, we do not do mismatch control for intra as errors cannot accumulate +} + +static void dct_unquantize_mpeg2_inter_mmx(MpegEncContext *s, + int16_t *block, int n, int qscale) +{ + x86_reg nCoeffs; + const uint16_t *quant_matrix; + + av_assert2(s->block_last_index[n]>=0); + + if (s->q_scale_type) qscale = ff_mpeg2_non_linear_qscale[qscale]; + else qscale <<= 1; + + if(s->alternate_scan) nCoeffs= 63; //FIXME + else nCoeffs= s->intra_scantable.raster_end[ s->block_last_index[n] ]; + + quant_matrix = s->inter_matrix; +__asm__ volatile( + "pcmpeqw %%mm7, %%mm7 \n\t" + "psrlq $48, %%mm7 \n\t" + "movd %2, %%mm6 \n\t" + "packssdw %%mm6, %%mm6 \n\t" + "packssdw %%mm6, %%mm6 \n\t" + "mov %3, %%"FF_REG_a" \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movq (%0, %%"FF_REG_a"), %%mm0 \n\t" + "movq 8(%0, %%"FF_REG_a"), %%mm1\n\t" + "movq (%1, %%"FF_REG_a"), %%mm4 \n\t" + "movq 8(%1, %%"FF_REG_a"), %%mm5\n\t" + "pmullw %%mm6, %%mm4 \n\t" // q=qscale*quant_matrix[i] + "pmullw %%mm6, %%mm5 \n\t" // q=qscale*quant_matrix[i] + "pxor %%mm2, %%mm2 \n\t" + "pxor %%mm3, %%mm3 \n\t" + "pcmpgtw %%mm0, %%mm2 \n\t" // block[i] < 0 ? -1 : 0 + "pcmpgtw %%mm1, %%mm3 \n\t" // block[i] < 0 ? -1 : 0 + "pxor %%mm2, %%mm0 \n\t" + "pxor %%mm3, %%mm1 \n\t" + "psubw %%mm2, %%mm0 \n\t" // abs(block[i]) + "psubw %%mm3, %%mm1 \n\t" // abs(block[i]) + "paddw %%mm0, %%mm0 \n\t" // abs(block[i])*2 + "paddw %%mm1, %%mm1 \n\t" // abs(block[i])*2 + "pmullw %%mm4, %%mm0 \n\t" // abs(block[i])*2*q + "pmullw %%mm5, %%mm1 \n\t" // abs(block[i])*2*q + "paddw %%mm4, %%mm0 \n\t" // (abs(block[i])*2 + 1)*q + "paddw %%mm5, %%mm1 \n\t" // (abs(block[i])*2 + 1)*q + "pxor %%mm4, %%mm4 \n\t" + "pxor %%mm5, %%mm5 \n\t" // FIXME slow + "pcmpeqw (%0, %%"FF_REG_a"), %%mm4 \n\t" // block[i] == 0 ? -1 : 0 + "pcmpeqw 8(%0, %%"FF_REG_a"), %%mm5\n\t" // block[i] == 0 ? -1 : 0 + "psrlw $5, %%mm0 \n\t" + "psrlw $5, %%mm1 \n\t" + "pxor %%mm2, %%mm0 \n\t" + "pxor %%mm3, %%mm1 \n\t" + "psubw %%mm2, %%mm0 \n\t" + "psubw %%mm3, %%mm1 \n\t" + "pandn %%mm0, %%mm4 \n\t" + "pandn %%mm1, %%mm5 \n\t" + "pxor %%mm4, %%mm7 \n\t" + "pxor %%mm5, %%mm7 \n\t" + "movq %%mm4, (%0, %%"FF_REG_a") \n\t" + "movq %%mm5, 8(%0, %%"FF_REG_a")\n\t" + + "add $16, %%"FF_REG_a" \n\t" + "jng 1b \n\t" + "movd 124(%0, %3), %%mm0 \n\t" + "movq %%mm7, %%mm6 \n\t" + "psrlq $32, %%mm7 \n\t" + "pxor %%mm6, %%mm7 \n\t" + "movq %%mm7, %%mm6 \n\t" + "psrlq $16, %%mm7 \n\t" + "pxor %%mm6, %%mm7 \n\t" + "pslld $31, %%mm7 \n\t" + "psrlq $15, %%mm7 \n\t" + "pxor %%mm7, %%mm0 \n\t" + "movd %%mm0, 124(%0, %3) \n\t" + + ::"r" (block+nCoeffs), "r"(quant_matrix+nCoeffs), "rm" (qscale), "r" (-2*nCoeffs) + : "%"FF_REG_a, "memory" + ); +} + +#endif /* HAVE_MMX_INLINE */ + +av_cold void ff_mpv_common_init_x86(MpegEncContext *s) +{ +#if HAVE_MMX_INLINE + int cpu_flags = av_get_cpu_flags(); + + if (INLINE_MMX(cpu_flags)) { + s->dct_unquantize_h263_intra = dct_unquantize_h263_intra_mmx; + s->dct_unquantize_h263_inter = dct_unquantize_h263_inter_mmx; + s->dct_unquantize_mpeg1_intra = dct_unquantize_mpeg1_intra_mmx; + s->dct_unquantize_mpeg1_inter = dct_unquantize_mpeg1_inter_mmx; + if (!(s->avctx->flags & AV_CODEC_FLAG_BITEXACT)) + s->dct_unquantize_mpeg2_intra = dct_unquantize_mpeg2_intra_mmx; + s->dct_unquantize_mpeg2_inter = dct_unquantize_mpeg2_inter_mmx; + } +#endif /* HAVE_MMX_INLINE */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideodsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideodsp.c new file mode 100644 index 0000000000..6009b64e07 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideodsp.c @@ -0,0 +1,161 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/mpegvideodsp.h" +#include "libavcodec/videodsp.h" + +#if HAVE_INLINE_ASM + +static void gmc_mmx(uint8_t *dst, uint8_t *src, + int stride, int h, int ox, int oy, + int dxx, int dxy, int dyx, int dyy, + int shift, int r, int width, int height) +{ + const int w = 8; + const int ix = ox >> (16 + shift); + const int iy = oy >> (16 + shift); + const int oxs = ox >> 4; + const int oys = oy >> 4; + const int dxxs = dxx >> 4; + const int dxys = dxy >> 4; + const int dyxs = dyx >> 4; + const int dyys = dyy >> 4; + const uint16_t r4[4] = { r, r, r, r }; + const uint16_t dxy4[4] = { dxys, dxys, dxys, dxys }; + const uint16_t dyy4[4] = { dyys, dyys, dyys, dyys }; + const uint64_t shift2 = 2 * shift; +#define MAX_STRIDE 4096U +#define MAX_H 8U + uint8_t edge_buf[(MAX_H + 1) * MAX_STRIDE]; + int x, y; + + const int dxw = (dxx - (1 << (16 + shift))) * (w - 1); + const int dyh = (dyy - (1 << (16 + shift))) * (h - 1); + const int dxh = dxy * (h - 1); + const int dyw = dyx * (w - 1); + int need_emu = (unsigned) ix >= width - w || width < w || + (unsigned) iy >= height - h || height< h + ; + + if ( // non-constant fullpel offset (3% of blocks) + ((ox ^ (ox + dxw)) | (ox ^ (ox + dxh)) | (ox ^ (ox + dxw + dxh)) | + (oy ^ (oy + dyw)) | (oy ^ (oy + dyh)) | (oy ^ (oy + dyw + dyh))) >> (16 + shift) || + // uses more than 16 bits of subpel mv (only at huge resolution) + (dxx | dxy | dyx | dyy) & 15 || + (need_emu && (h > MAX_H || stride > MAX_STRIDE))) { + // FIXME could still use mmx for some of the rows + ff_gmc_c(dst, src, stride, h, ox, oy, dxx, dxy, dyx, dyy, + shift, r, width, height); + return; + } + + src += ix + iy * stride; + if (need_emu) { + ff_emulated_edge_mc_8(edge_buf, src, stride, stride, w + 1, h + 1, ix, iy, width, height); + src = edge_buf; + } + + __asm__ volatile ( + "movd %0, %%mm6 \n\t" + "pxor %%mm7, %%mm7 \n\t" + "punpcklwd %%mm6, %%mm6 \n\t" + "punpcklwd %%mm6, %%mm6 \n\t" + :: "r" (1 << shift)); + + for (x = 0; x < w; x += 4) { + uint16_t dx4[4] = { oxs - dxys + dxxs * (x + 0), + oxs - dxys + dxxs * (x + 1), + oxs - dxys + dxxs * (x + 2), + oxs - dxys + dxxs * (x + 3) }; + uint16_t dy4[4] = { oys - dyys + dyxs * (x + 0), + oys - dyys + dyxs * (x + 1), + oys - dyys + dyxs * (x + 2), + oys - dyys + dyxs * (x + 3) }; + + for (y = 0; y < h; y++) { + __asm__ volatile ( + "movq %0, %%mm4 \n\t" + "movq %1, %%mm5 \n\t" + "paddw %2, %%mm4 \n\t" + "paddw %3, %%mm5 \n\t" + "movq %%mm4, %0 \n\t" + "movq %%mm5, %1 \n\t" + "psrlw $12, %%mm4 \n\t" + "psrlw $12, %%mm5 \n\t" + : "+m" (*dx4), "+m" (*dy4) + : "m" (*dxy4), "m" (*dyy4)); + + __asm__ volatile ( + "movq %%mm6, %%mm2 \n\t" + "movq %%mm6, %%mm1 \n\t" + "psubw %%mm4, %%mm2 \n\t" + "psubw %%mm5, %%mm1 \n\t" + "movq %%mm2, %%mm0 \n\t" + "movq %%mm4, %%mm3 \n\t" + "pmullw %%mm1, %%mm0 \n\t" // (s - dx) * (s - dy) + "pmullw %%mm5, %%mm3 \n\t" // dx * dy + "pmullw %%mm5, %%mm2 \n\t" // (s - dx) * dy + "pmullw %%mm4, %%mm1 \n\t" // dx * (s - dy) + + "movd %4, %%mm5 \n\t" + "movd %3, %%mm4 \n\t" + "punpcklbw %%mm7, %%mm5 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "pmullw %%mm5, %%mm3 \n\t" // src[1, 1] * dx * dy + "pmullw %%mm4, %%mm2 \n\t" // src[0, 1] * (s - dx) * dy + + "movd %2, %%mm5 \n\t" + "movd %1, %%mm4 \n\t" + "punpcklbw %%mm7, %%mm5 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "pmullw %%mm5, %%mm1 \n\t" // src[1, 0] * dx * (s - dy) + "pmullw %%mm4, %%mm0 \n\t" // src[0, 0] * (s - dx) * (s - dy) + "paddw %5, %%mm1 \n\t" + "paddw %%mm3, %%mm2 \n\t" + "paddw %%mm1, %%mm0 \n\t" + "paddw %%mm2, %%mm0 \n\t" + + "psrlw %6, %%mm0 \n\t" + "packuswb %%mm0, %%mm0 \n\t" + "movd %%mm0, %0 \n\t" + + : "=m" (dst[x + y * stride]) + : "m" (src[0]), "m" (src[1]), + "m" (src[stride]), "m" (src[stride + 1]), + "m" (*r4), "m" (shift2)); + src += stride; + } + src += 4 - h * stride; + } +} + +#endif /* HAVE_INLINE_ASM */ + +av_cold void ff_mpegvideodsp_init_x86(MpegVideoDSPContext *c) +{ +#if HAVE_INLINE_ASM + int cpu_flags = av_get_cpu_flags(); + + if (INLINE_MMX(cpu_flags)) + c->gmc = gmc_mmx; +#endif /* HAVE_INLINE_ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc.c new file mode 100644 index 0000000000..c884cf121b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc.c @@ -0,0 +1,244 @@ +/* + * The simplest mpeg encoder (well, it was the simplest!) + * Copyright (c) 2000,2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/dct.h" +#include "libavcodec/mpegvideo.h" + +/* not permutated inverse zigzag_direct + 1 for MMX quantizer */ +DECLARE_ALIGNED(16, static const uint16_t, inv_zigzag_direct16)[64] = { + 1, 2, 6, 7, 15, 16, 28, 29, + 3, 5, 8, 14, 17, 27, 30, 43, + 4, 9, 13, 18, 26, 31, 42, 44, + 10, 12, 19, 25, 32, 41, 45, 54, + 11, 20, 24, 33, 40, 46, 53, 55, + 21, 23, 34, 39, 47, 52, 56, 61, + 22, 35, 38, 48, 51, 57, 60, 62, + 36, 37, 49, 50, 58, 59, 63, 64, +}; + +#if HAVE_6REGS + +#if HAVE_MMX_INLINE +#define COMPILE_TEMPLATE_MMXEXT 0 +#define COMPILE_TEMPLATE_SSE2 0 +#define COMPILE_TEMPLATE_SSSE3 0 +#define RENAME(a) a ## _mmx +#define RENAME_FDCT(a) a ## _mmx +#include "mpegvideoenc_template.c" +#endif /* HAVE_MMX_INLINE */ + +#if HAVE_MMXEXT_INLINE +#undef COMPILE_TEMPLATE_SSSE3 +#undef COMPILE_TEMPLATE_SSE2 +#undef COMPILE_TEMPLATE_MMXEXT +#define COMPILE_TEMPLATE_MMXEXT 1 +#define COMPILE_TEMPLATE_SSE2 0 +#define COMPILE_TEMPLATE_SSSE3 0 +#undef RENAME +#undef RENAME_FDCT +#define RENAME(a) a ## _mmxext +#define RENAME_FDCT(a) a ## _mmxext +#include "mpegvideoenc_template.c" +#endif /* HAVE_MMXEXT_INLINE */ + +#if HAVE_SSE2_INLINE +#undef COMPILE_TEMPLATE_MMXEXT +#undef COMPILE_TEMPLATE_SSE2 +#undef COMPILE_TEMPLATE_SSSE3 +#define COMPILE_TEMPLATE_MMXEXT 0 +#define COMPILE_TEMPLATE_SSE2 1 +#define COMPILE_TEMPLATE_SSSE3 0 +#undef RENAME +#undef RENAME_FDCT +#define RENAME(a) a ## _sse2 +#define RENAME_FDCT(a) a ## _sse2 +#include "mpegvideoenc_template.c" +#endif /* HAVE_SSE2_INLINE */ + +#if HAVE_SSSE3_INLINE +#undef COMPILE_TEMPLATE_MMXEXT +#undef COMPILE_TEMPLATE_SSE2 +#undef COMPILE_TEMPLATE_SSSE3 +#define COMPILE_TEMPLATE_MMXEXT 0 +#define COMPILE_TEMPLATE_SSE2 1 +#define COMPILE_TEMPLATE_SSSE3 1 +#undef RENAME +#undef RENAME_FDCT +#define RENAME(a) a ## _ssse3 +#define RENAME_FDCT(a) a ## _sse2 +#include "mpegvideoenc_template.c" +#endif /* HAVE_SSSE3_INLINE */ + +#endif /* HAVE_6REGS */ + +#if HAVE_INLINE_ASM +#if HAVE_MMX_INLINE +static void denoise_dct_mmx(MpegEncContext *s, int16_t *block){ + const int intra= s->mb_intra; + int *sum= s->dct_error_sum[intra]; + uint16_t *offset= s->dct_offset[intra]; + + s->dct_count[intra]++; + + __asm__ volatile( + "pxor %%mm7, %%mm7 \n\t" + "1: \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "movq (%0), %%mm2 \n\t" + "movq 8(%0), %%mm3 \n\t" + "pcmpgtw %%mm2, %%mm0 \n\t" + "pcmpgtw %%mm3, %%mm1 \n\t" + "pxor %%mm0, %%mm2 \n\t" + "pxor %%mm1, %%mm3 \n\t" + "psubw %%mm0, %%mm2 \n\t" + "psubw %%mm1, %%mm3 \n\t" + "movq %%mm2, %%mm4 \n\t" + "movq %%mm3, %%mm5 \n\t" + "psubusw (%2), %%mm2 \n\t" + "psubusw 8(%2), %%mm3 \n\t" + "pxor %%mm0, %%mm2 \n\t" + "pxor %%mm1, %%mm3 \n\t" + "psubw %%mm0, %%mm2 \n\t" + "psubw %%mm1, %%mm3 \n\t" + "movq %%mm2, (%0) \n\t" + "movq %%mm3, 8(%0) \n\t" + "movq %%mm4, %%mm2 \n\t" + "movq %%mm5, %%mm3 \n\t" + "punpcklwd %%mm7, %%mm4 \n\t" + "punpckhwd %%mm7, %%mm2 \n\t" + "punpcklwd %%mm7, %%mm5 \n\t" + "punpckhwd %%mm7, %%mm3 \n\t" + "paddd (%1), %%mm4 \n\t" + "paddd 8(%1), %%mm2 \n\t" + "paddd 16(%1), %%mm5 \n\t" + "paddd 24(%1), %%mm3 \n\t" + "movq %%mm4, (%1) \n\t" + "movq %%mm2, 8(%1) \n\t" + "movq %%mm5, 16(%1) \n\t" + "movq %%mm3, 24(%1) \n\t" + "add $16, %0 \n\t" + "add $32, %1 \n\t" + "add $16, %2 \n\t" + "cmp %3, %0 \n\t" + " jb 1b \n\t" + : "+r" (block), "+r" (sum), "+r" (offset) + : "r"(block+64) + ); +} +#endif /* HAVE_MMX_INLINE */ + +#if HAVE_SSE2_INLINE +static void denoise_dct_sse2(MpegEncContext *s, int16_t *block){ + const int intra= s->mb_intra; + int *sum= s->dct_error_sum[intra]; + uint16_t *offset= s->dct_offset[intra]; + + s->dct_count[intra]++; + + __asm__ volatile( + "pxor %%xmm7, %%xmm7 \n\t" + "1: \n\t" + "pxor %%xmm0, %%xmm0 \n\t" + "pxor %%xmm1, %%xmm1 \n\t" + "movdqa (%0), %%xmm2 \n\t" + "movdqa 16(%0), %%xmm3 \n\t" + "pcmpgtw %%xmm2, %%xmm0 \n\t" + "pcmpgtw %%xmm3, %%xmm1 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pxor %%xmm1, %%xmm3 \n\t" + "psubw %%xmm0, %%xmm2 \n\t" + "psubw %%xmm1, %%xmm3 \n\t" + "movdqa %%xmm2, %%xmm4 \n\t" + "movdqa %%xmm3, %%xmm5 \n\t" + "psubusw (%2), %%xmm2 \n\t" + "psubusw 16(%2), %%xmm3 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pxor %%xmm1, %%xmm3 \n\t" + "psubw %%xmm0, %%xmm2 \n\t" + "psubw %%xmm1, %%xmm3 \n\t" + "movdqa %%xmm2, (%0) \n\t" + "movdqa %%xmm3, 16(%0) \n\t" + "movdqa %%xmm4, %%xmm6 \n\t" + "movdqa %%xmm5, %%xmm0 \n\t" + "punpcklwd %%xmm7, %%xmm4 \n\t" + "punpckhwd %%xmm7, %%xmm6 \n\t" + "punpcklwd %%xmm7, %%xmm5 \n\t" + "punpckhwd %%xmm7, %%xmm0 \n\t" + "paddd (%1), %%xmm4 \n\t" + "paddd 16(%1), %%xmm6 \n\t" + "paddd 32(%1), %%xmm5 \n\t" + "paddd 48(%1), %%xmm0 \n\t" + "movdqa %%xmm4, (%1) \n\t" + "movdqa %%xmm6, 16(%1) \n\t" + "movdqa %%xmm5, 32(%1) \n\t" + "movdqa %%xmm0, 48(%1) \n\t" + "add $32, %0 \n\t" + "add $64, %1 \n\t" + "add $32, %2 \n\t" + "cmp %3, %0 \n\t" + " jb 1b \n\t" + : "+r" (block), "+r" (sum), "+r" (offset) + : "r"(block+64) + XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3", + "%xmm4", "%xmm5", "%xmm6", "%xmm7") + ); +} +#endif /* HAVE_SSE2_INLINE */ +#endif /* HAVE_INLINE_ASM */ + +av_cold void ff_dct_encode_init_x86(MpegEncContext *s) +{ + const int dct_algo = s->avctx->dct_algo; + + if (dct_algo == FF_DCT_AUTO || dct_algo == FF_DCT_MMX) { +#if HAVE_MMX_INLINE + int cpu_flags = av_get_cpu_flags(); + if (INLINE_MMX(cpu_flags)) { +#if HAVE_6REGS + s->dct_quantize = dct_quantize_mmx; +#endif + s->denoise_dct = denoise_dct_mmx; + } +#endif +#if HAVE_6REGS && HAVE_MMXEXT_INLINE + if (INLINE_MMXEXT(cpu_flags)) + s->dct_quantize = dct_quantize_mmxext; +#endif +#if HAVE_SSE2_INLINE + if (INLINE_SSE2(cpu_flags)) { +#if HAVE_6REGS + s->dct_quantize = dct_quantize_sse2; +#endif + s->denoise_dct = denoise_dct_sse2; + } +#endif +#if HAVE_6REGS && HAVE_SSSE3_INLINE + if (INLINE_SSSE3(cpu_flags)) + s->dct_quantize = dct_quantize_ssse3; +#endif + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc_qns_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc_qns_template.c new file mode 100644 index 0000000000..882d486205 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc_qns_template.c @@ -0,0 +1,109 @@ +/* + * QNS functions are compiled 3 times for MMX/3DNOW/SSSE3 + * Copyright (c) 2004 Michael Niedermayer + * + * MMX optimization by Michael Niedermayer + * 3DNow! and SSSE3 optimization by Zuxy Meng + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/x86/asm.h" + +#include "inline_asm.h" + +#define MAX_ABS (512 >> (SCALE_OFFSET>0 ? SCALE_OFFSET : 0)) + +static int DEF(try_8x8basis)(int16_t rem[64], int16_t weight[64], int16_t basis[64], int scale) +{ + x86_reg i=0; + + av_assert2(FFABS(scale) < MAX_ABS); + scale<<= 16 + SCALE_OFFSET - BASIS_SHIFT + RECON_SHIFT; + + SET_RND(mm6); + __asm__ volatile( + "pxor %%mm7, %%mm7 \n\t" + "movd %4, %%mm5 \n\t" + "punpcklwd %%mm5, %%mm5 \n\t" + "punpcklwd %%mm5, %%mm5 \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movq (%1, %0), %%mm0 \n\t" + "movq 8(%1, %0), %%mm1 \n\t" + PMULHRW(%%mm0, %%mm1, %%mm5, %%mm6) + "paddw (%2, %0), %%mm0 \n\t" + "paddw 8(%2, %0), %%mm1 \n\t" + "psraw $6, %%mm0 \n\t" + "psraw $6, %%mm1 \n\t" + "pmullw (%3, %0), %%mm0 \n\t" + "pmullw 8(%3, %0), %%mm1 \n\t" + "pmaddwd %%mm0, %%mm0 \n\t" + "pmaddwd %%mm1, %%mm1 \n\t" + "paddd %%mm1, %%mm0 \n\t" + "psrld $4, %%mm0 \n\t" + "paddd %%mm0, %%mm7 \n\t" + "add $16, %0 \n\t" + "cmp $128, %0 \n\t" //FIXME optimize & bench + " jb 1b \n\t" + PHADDD(%%mm7, %%mm6) + "psrld $2, %%mm7 \n\t" + "movd %%mm7, %0 \n\t" + + : "+r" (i) + : "r"(basis), "r"(rem), "r"(weight), "g"(scale) + ); + return i; +} + +static void DEF(add_8x8basis)(int16_t rem[64], int16_t basis[64], int scale) +{ + x86_reg i=0; + + if(FFABS(scale) < MAX_ABS){ + scale<<= 16 + SCALE_OFFSET - BASIS_SHIFT + RECON_SHIFT; + SET_RND(mm6); + __asm__ volatile( + "movd %3, %%mm5 \n\t" + "punpcklwd %%mm5, %%mm5 \n\t" + "punpcklwd %%mm5, %%mm5 \n\t" + ".p2align 4 \n\t" + "1: \n\t" + "movq (%1, %0), %%mm0 \n\t" + "movq 8(%1, %0), %%mm1 \n\t" + PMULHRW(%%mm0, %%mm1, %%mm5, %%mm6) + "paddw (%2, %0), %%mm0 \n\t" + "paddw 8(%2, %0), %%mm1 \n\t" + "movq %%mm0, (%2, %0) \n\t" + "movq %%mm1, 8(%2, %0) \n\t" + "add $16, %0 \n\t" + "cmp $128, %0 \n\t" // FIXME optimize & bench + " jb 1b \n\t" + + : "+r" (i) + : "r"(basis), "r"(rem), "g"(scale) + ); + }else{ + for(i=0; i<8*8; i++){ + rem[i] += (basis[i]*scale + (1<<(BASIS_SHIFT - RECON_SHIFT-1)))>>(BASIS_SHIFT - RECON_SHIFT); + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc_template.c new file mode 100644 index 0000000000..1201be514b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoenc_template.c @@ -0,0 +1,423 @@ +/* + * MPEG video MMX templates + * + * Copyright (c) 2002 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/internal.h" +#include "libavutil/x86/asm.h" +#include "libavcodec/mpegutils.h" +#include "libavcodec/mpegvideo.h" +#include "fdct.h" + +#undef MMREG_WIDTH +#undef MM +#undef MOVQ +#undef SPREADW +#undef PMAXW +#undef PMAX +#undef SAVE_SIGN +#undef RESTORE_SIGN + +#if COMPILE_TEMPLATE_SSE2 +#define MMREG_WIDTH "16" +#define MM "%%xmm" +#define MOVQ "movdqa" +#define SPREADW(a) \ + "pshuflw $0, "a", "a" \n\t"\ + "punpcklwd "a", "a" \n\t" +#define PMAXW(a,b) "pmaxsw "a", "b" \n\t" +#define PMAX(a,b) \ + "movhlps "a", "b" \n\t"\ + PMAXW(b, a)\ + "pshuflw $0x0E, "a", "b" \n\t"\ + PMAXW(b, a)\ + "pshuflw $0x01, "a", "b" \n\t"\ + PMAXW(b, a) +#else +#define MMREG_WIDTH "8" +#define MM "%%mm" +#define MOVQ "movq" +#if COMPILE_TEMPLATE_MMXEXT +#define SPREADW(a) "pshufw $0, "a", "a" \n\t" +#define PMAXW(a,b) "pmaxsw "a", "b" \n\t" +#define PMAX(a,b) \ + "pshufw $0x0E, "a", "b" \n\t"\ + PMAXW(b, a)\ + "pshufw $0x01, "a", "b" \n\t"\ + PMAXW(b, a) +#else +#define SPREADW(a) \ + "punpcklwd "a", "a" \n\t"\ + "punpcklwd "a", "a" \n\t" +#define PMAXW(a,b) \ + "psubusw "a", "b" \n\t"\ + "paddw "a", "b" \n\t" +#define PMAX(a,b) \ + "movq "a", "b" \n\t"\ + "psrlq $32, "a" \n\t"\ + PMAXW(b, a)\ + "movq "a", "b" \n\t"\ + "psrlq $16, "a" \n\t"\ + PMAXW(b, a) + +#endif +#endif + +#if COMPILE_TEMPLATE_SSSE3 +#define SAVE_SIGN(a,b) \ + "movdqa "b", "a" \n\t"\ + "pabsw "b", "b" \n\t" +#define RESTORE_SIGN(a,b) \ + "psignw "a", "b" \n\t" +#else +#define SAVE_SIGN(a,b) \ + "pxor "a", "a" \n\t"\ + "pcmpgtw "b", "a" \n\t" /* block[i] <= 0 ? 0xFF : 0x00 */\ + "pxor "a", "b" \n\t"\ + "psubw "a", "b" \n\t" /* ABS(block[i]) */ +#define RESTORE_SIGN(a,b) \ + "pxor "a", "b" \n\t"\ + "psubw "a", "b" \n\t" // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) +#endif + +static int RENAME(dct_quantize)(MpegEncContext *s, + int16_t *block, int n, + int qscale, int *overflow) +{ + x86_reg last_non_zero_p1; + int level=0, q; //=0 is because gcc says uninitialized ... + const uint16_t *qmat, *bias; + LOCAL_ALIGNED_16(int16_t, temp_block, [64]); + + av_assert2((7&(int)(&temp_block[0])) == 0); //did gcc align it correctly? + + //s->fdct (block); + RENAME_FDCT(ff_fdct)(block); // cannot be anything else ... + + if(s->dct_error_sum) + s->denoise_dct(s, block); + + if (s->mb_intra) { + int dummy; + if (n < 4){ + q = s->y_dc_scale; + bias = s->q_intra_matrix16[qscale][1]; + qmat = s->q_intra_matrix16[qscale][0]; + }else{ + q = s->c_dc_scale; + bias = s->q_chroma_intra_matrix16[qscale][1]; + qmat = s->q_chroma_intra_matrix16[qscale][0]; + } + /* note: block[0] is assumed to be positive */ + if (!s->h263_aic) { + __asm__ volatile ( + "mul %%ecx \n\t" + : "=d" (level), "=a"(dummy) + : "a" ((block[0]>>2) + q), "c" (ff_inverse[q<<1]) + ); + } else + /* For AIC we skip quant/dequant of INTRADC */ + level = (block[0] + 4)>>3; + + block[0]=0; //avoid fake overflow +// temp_block[0] = (block[0] + (q >> 1)) / q; + last_non_zero_p1 = 1; + } else { + last_non_zero_p1 = 0; + bias = s->q_inter_matrix16[qscale][1]; + qmat = s->q_inter_matrix16[qscale][0]; + } + + if((s->out_format == FMT_H263 || s->out_format == FMT_H261) && s->mpeg_quant==0){ + + __asm__ volatile( + "movd %%"FF_REG_a", "MM"3 \n\t" // last_non_zero_p1 + SPREADW(MM"3") + "pxor "MM"7, "MM"7 \n\t" // 0 + "pxor "MM"4, "MM"4 \n\t" // 0 + MOVQ" (%2), "MM"5 \n\t" // qmat[0] + "pxor "MM"6, "MM"6 \n\t" + "psubw (%3), "MM"6 \n\t" // -bias[0] + "mov $-128, %%"FF_REG_a" \n\t" + ".p2align 4 \n\t" + "1: \n\t" + MOVQ" (%1, %%"FF_REG_a"), "MM"0 \n\t" // block[i] + SAVE_SIGN(MM"1", MM"0") // ABS(block[i]) + "psubusw "MM"6, "MM"0 \n\t" // ABS(block[i]) + bias[0] + "pmulhw "MM"5, "MM"0 \n\t" // (ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16 + "por "MM"0, "MM"4 \n\t" + RESTORE_SIGN(MM"1", MM"0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) + MOVQ" "MM"0, (%5, %%"FF_REG_a") \n\t" + "pcmpeqw "MM"7, "MM"0 \n\t" // out==0 ? 0xFF : 0x00 + MOVQ" (%4, %%"FF_REG_a"), "MM"1 \n\t" + MOVQ" "MM"7, (%1, %%"FF_REG_a") \n\t" // 0 + "pandn "MM"1, "MM"0 \n\t" + PMAXW(MM"0", MM"3") + "add $"MMREG_WIDTH", %%"FF_REG_a" \n\t" + " js 1b \n\t" + PMAX(MM"3", MM"0") + "movd "MM"3, %%"FF_REG_a" \n\t" + "movzbl %%al, %%eax \n\t" // last_non_zero_p1 + : "+a" (last_non_zero_p1) + : "r" (block+64), "r" (qmat), "r" (bias), + "r" (inv_zigzag_direct16 + 64), "r" (temp_block + 64) + XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3", + "%xmm4", "%xmm5", "%xmm6", "%xmm7") + ); + }else{ // FMT_H263 + __asm__ volatile( + "movd %%"FF_REG_a", "MM"3 \n\t" // last_non_zero_p1 + SPREADW(MM"3") + "pxor "MM"7, "MM"7 \n\t" // 0 + "pxor "MM"4, "MM"4 \n\t" // 0 + "mov $-128, %%"FF_REG_a" \n\t" + ".p2align 4 \n\t" + "1: \n\t" + MOVQ" (%1, %%"FF_REG_a"), "MM"0 \n\t" // block[i] + SAVE_SIGN(MM"1", MM"0") // ABS(block[i]) + MOVQ" (%3, %%"FF_REG_a"), "MM"6 \n\t" // bias[0] + "paddusw "MM"6, "MM"0 \n\t" // ABS(block[i]) + bias[0] + MOVQ" (%2, %%"FF_REG_a"), "MM"5 \n\t" // qmat[i] + "pmulhw "MM"5, "MM"0 \n\t" // (ABS(block[i])*qmat[0] + bias[0]*qmat[0])>>16 + "por "MM"0, "MM"4 \n\t" + RESTORE_SIGN(MM"1", MM"0") // out=((ABS(block[i])*qmat[0] - bias[0]*qmat[0])>>16)*sign(block[i]) + MOVQ" "MM"0, (%5, %%"FF_REG_a") \n\t" + "pcmpeqw "MM"7, "MM"0 \n\t" // out==0 ? 0xFF : 0x00 + MOVQ" (%4, %%"FF_REG_a"), "MM"1 \n\t" + MOVQ" "MM"7, (%1, %%"FF_REG_a") \n\t" // 0 + "pandn "MM"1, "MM"0 \n\t" + PMAXW(MM"0", MM"3") + "add $"MMREG_WIDTH", %%"FF_REG_a" \n\t" + " js 1b \n\t" + PMAX(MM"3", MM"0") + "movd "MM"3, %%"FF_REG_a" \n\t" + "movzbl %%al, %%eax \n\t" // last_non_zero_p1 + : "+a" (last_non_zero_p1) + : "r" (block+64), "r" (qmat+64), "r" (bias+64), + "r" (inv_zigzag_direct16 + 64), "r" (temp_block + 64) + XMM_CLOBBERS_ONLY("%xmm0", "%xmm1", "%xmm2", "%xmm3", + "%xmm4", "%xmm5", "%xmm6", "%xmm7") + ); + } + __asm__ volatile( + "movd %1, "MM"1 \n\t" // max_qcoeff + SPREADW(MM"1") + "psubusw "MM"1, "MM"4 \n\t" + "packuswb "MM"4, "MM"4 \n\t" +#if COMPILE_TEMPLATE_SSE2 + "packsswb "MM"4, "MM"4 \n\t" +#endif + "movd "MM"4, %0 \n\t" // *overflow + : "=g" (*overflow) + : "g" (s->max_qcoeff) + ); + + if(s->mb_intra) block[0]= level; + else block[0]= temp_block[0]; + + if (s->idsp.perm_type == FF_IDCT_PERM_SIMPLE) { + if(last_non_zero_p1 <= 1) goto end; + block[0x08] = temp_block[0x01]; block[0x10] = temp_block[0x08]; + block[0x20] = temp_block[0x10]; + if(last_non_zero_p1 <= 4) goto end; + block[0x18] = temp_block[0x09]; block[0x04] = temp_block[0x02]; + block[0x09] = temp_block[0x03]; + if(last_non_zero_p1 <= 7) goto end; + block[0x14] = temp_block[0x0A]; block[0x28] = temp_block[0x11]; + block[0x12] = temp_block[0x18]; block[0x02] = temp_block[0x20]; + if(last_non_zero_p1 <= 11) goto end; + block[0x1A] = temp_block[0x19]; block[0x24] = temp_block[0x12]; + block[0x19] = temp_block[0x0B]; block[0x01] = temp_block[0x04]; + block[0x0C] = temp_block[0x05]; + if(last_non_zero_p1 <= 16) goto end; + block[0x11] = temp_block[0x0C]; block[0x29] = temp_block[0x13]; + block[0x16] = temp_block[0x1A]; block[0x0A] = temp_block[0x21]; + block[0x30] = temp_block[0x28]; block[0x22] = temp_block[0x30]; + block[0x38] = temp_block[0x29]; block[0x06] = temp_block[0x22]; + if(last_non_zero_p1 <= 24) goto end; + block[0x1B] = temp_block[0x1B]; block[0x21] = temp_block[0x14]; + block[0x1C] = temp_block[0x0D]; block[0x05] = temp_block[0x06]; + block[0x0D] = temp_block[0x07]; block[0x15] = temp_block[0x0E]; + block[0x2C] = temp_block[0x15]; block[0x13] = temp_block[0x1C]; + if(last_non_zero_p1 <= 32) goto end; + block[0x0B] = temp_block[0x23]; block[0x34] = temp_block[0x2A]; + block[0x2A] = temp_block[0x31]; block[0x32] = temp_block[0x38]; + block[0x3A] = temp_block[0x39]; block[0x26] = temp_block[0x32]; + block[0x39] = temp_block[0x2B]; block[0x03] = temp_block[0x24]; + if(last_non_zero_p1 <= 40) goto end; + block[0x1E] = temp_block[0x1D]; block[0x25] = temp_block[0x16]; + block[0x1D] = temp_block[0x0F]; block[0x2D] = temp_block[0x17]; + block[0x17] = temp_block[0x1E]; block[0x0E] = temp_block[0x25]; + block[0x31] = temp_block[0x2C]; block[0x2B] = temp_block[0x33]; + if(last_non_zero_p1 <= 48) goto end; + block[0x36] = temp_block[0x3A]; block[0x3B] = temp_block[0x3B]; + block[0x23] = temp_block[0x34]; block[0x3C] = temp_block[0x2D]; + block[0x07] = temp_block[0x26]; block[0x1F] = temp_block[0x1F]; + block[0x0F] = temp_block[0x27]; block[0x35] = temp_block[0x2E]; + if(last_non_zero_p1 <= 56) goto end; + block[0x2E] = temp_block[0x35]; block[0x33] = temp_block[0x3C]; + block[0x3E] = temp_block[0x3D]; block[0x27] = temp_block[0x36]; + block[0x3D] = temp_block[0x2F]; block[0x2F] = temp_block[0x37]; + block[0x37] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; + }else if(s->idsp.perm_type == FF_IDCT_PERM_LIBMPEG2){ + if(last_non_zero_p1 <= 1) goto end; + block[0x04] = temp_block[0x01]; + block[0x08] = temp_block[0x08]; block[0x10] = temp_block[0x10]; + if(last_non_zero_p1 <= 4) goto end; + block[0x0C] = temp_block[0x09]; block[0x01] = temp_block[0x02]; + block[0x05] = temp_block[0x03]; + if(last_non_zero_p1 <= 7) goto end; + block[0x09] = temp_block[0x0A]; block[0x14] = temp_block[0x11]; + block[0x18] = temp_block[0x18]; block[0x20] = temp_block[0x20]; + if(last_non_zero_p1 <= 11) goto end; + block[0x1C] = temp_block[0x19]; + block[0x11] = temp_block[0x12]; block[0x0D] = temp_block[0x0B]; + block[0x02] = temp_block[0x04]; block[0x06] = temp_block[0x05]; + if(last_non_zero_p1 <= 16) goto end; + block[0x0A] = temp_block[0x0C]; block[0x15] = temp_block[0x13]; + block[0x19] = temp_block[0x1A]; block[0x24] = temp_block[0x21]; + block[0x28] = temp_block[0x28]; block[0x30] = temp_block[0x30]; + block[0x2C] = temp_block[0x29]; block[0x21] = temp_block[0x22]; + if(last_non_zero_p1 <= 24) goto end; + block[0x1D] = temp_block[0x1B]; block[0x12] = temp_block[0x14]; + block[0x0E] = temp_block[0x0D]; block[0x03] = temp_block[0x06]; + block[0x07] = temp_block[0x07]; block[0x0B] = temp_block[0x0E]; + block[0x16] = temp_block[0x15]; block[0x1A] = temp_block[0x1C]; + if(last_non_zero_p1 <= 32) goto end; + block[0x25] = temp_block[0x23]; block[0x29] = temp_block[0x2A]; + block[0x34] = temp_block[0x31]; block[0x38] = temp_block[0x38]; + block[0x3C] = temp_block[0x39]; block[0x31] = temp_block[0x32]; + block[0x2D] = temp_block[0x2B]; block[0x22] = temp_block[0x24]; + if(last_non_zero_p1 <= 40) goto end; + block[0x1E] = temp_block[0x1D]; block[0x13] = temp_block[0x16]; + block[0x0F] = temp_block[0x0F]; block[0x17] = temp_block[0x17]; + block[0x1B] = temp_block[0x1E]; block[0x26] = temp_block[0x25]; + block[0x2A] = temp_block[0x2C]; block[0x35] = temp_block[0x33]; + if(last_non_zero_p1 <= 48) goto end; + block[0x39] = temp_block[0x3A]; block[0x3D] = temp_block[0x3B]; + block[0x32] = temp_block[0x34]; block[0x2E] = temp_block[0x2D]; + block[0x23] = temp_block[0x26]; block[0x1F] = temp_block[0x1F]; + block[0x27] = temp_block[0x27]; block[0x2B] = temp_block[0x2E]; + if(last_non_zero_p1 <= 56) goto end; + block[0x36] = temp_block[0x35]; block[0x3A] = temp_block[0x3C]; + block[0x3E] = temp_block[0x3D]; block[0x33] = temp_block[0x36]; + block[0x2F] = temp_block[0x2F]; block[0x37] = temp_block[0x37]; + block[0x3B] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; + } else if (s->idsp.perm_type == FF_IDCT_PERM_NONE) { + if(last_non_zero_p1 <= 1) goto end; + block[0x01] = temp_block[0x01]; + block[0x08] = temp_block[0x08]; block[0x10] = temp_block[0x10]; + if(last_non_zero_p1 <= 4) goto end; + block[0x09] = temp_block[0x09]; block[0x02] = temp_block[0x02]; + block[0x03] = temp_block[0x03]; + if(last_non_zero_p1 <= 7) goto end; + block[0x0A] = temp_block[0x0A]; block[0x11] = temp_block[0x11]; + block[0x18] = temp_block[0x18]; block[0x20] = temp_block[0x20]; + if(last_non_zero_p1 <= 11) goto end; + block[0x19] = temp_block[0x19]; + block[0x12] = temp_block[0x12]; block[0x0B] = temp_block[0x0B]; + block[0x04] = temp_block[0x04]; block[0x05] = temp_block[0x05]; + if(last_non_zero_p1 <= 16) goto end; + block[0x0C] = temp_block[0x0C]; block[0x13] = temp_block[0x13]; + block[0x1A] = temp_block[0x1A]; block[0x21] = temp_block[0x21]; + block[0x28] = temp_block[0x28]; block[0x30] = temp_block[0x30]; + block[0x29] = temp_block[0x29]; block[0x22] = temp_block[0x22]; + if(last_non_zero_p1 <= 24) goto end; + block[0x1B] = temp_block[0x1B]; block[0x14] = temp_block[0x14]; + block[0x0D] = temp_block[0x0D]; block[0x06] = temp_block[0x06]; + block[0x07] = temp_block[0x07]; block[0x0E] = temp_block[0x0E]; + block[0x15] = temp_block[0x15]; block[0x1C] = temp_block[0x1C]; + if(last_non_zero_p1 <= 32) goto end; + block[0x23] = temp_block[0x23]; block[0x2A] = temp_block[0x2A]; + block[0x31] = temp_block[0x31]; block[0x38] = temp_block[0x38]; + block[0x39] = temp_block[0x39]; block[0x32] = temp_block[0x32]; + block[0x2B] = temp_block[0x2B]; block[0x24] = temp_block[0x24]; + if(last_non_zero_p1 <= 40) goto end; + block[0x1D] = temp_block[0x1D]; block[0x16] = temp_block[0x16]; + block[0x0F] = temp_block[0x0F]; block[0x17] = temp_block[0x17]; + block[0x1E] = temp_block[0x1E]; block[0x25] = temp_block[0x25]; + block[0x2C] = temp_block[0x2C]; block[0x33] = temp_block[0x33]; + if(last_non_zero_p1 <= 48) goto end; + block[0x3A] = temp_block[0x3A]; block[0x3B] = temp_block[0x3B]; + block[0x34] = temp_block[0x34]; block[0x2D] = temp_block[0x2D]; + block[0x26] = temp_block[0x26]; block[0x1F] = temp_block[0x1F]; + block[0x27] = temp_block[0x27]; block[0x2E] = temp_block[0x2E]; + if(last_non_zero_p1 <= 56) goto end; + block[0x35] = temp_block[0x35]; block[0x3C] = temp_block[0x3C]; + block[0x3D] = temp_block[0x3D]; block[0x36] = temp_block[0x36]; + block[0x2F] = temp_block[0x2F]; block[0x37] = temp_block[0x37]; + block[0x3E] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; + } else if (s->idsp.perm_type == FF_IDCT_PERM_TRANSPOSE) { + if(last_non_zero_p1 <= 1) goto end; + block[0x08] = temp_block[0x01]; + block[0x01] = temp_block[0x08]; block[0x02] = temp_block[0x10]; + if(last_non_zero_p1 <= 4) goto end; + block[0x09] = temp_block[0x09]; block[0x10] = temp_block[0x02]; + block[0x18] = temp_block[0x03]; + if(last_non_zero_p1 <= 7) goto end; + block[0x11] = temp_block[0x0A]; block[0x0A] = temp_block[0x11]; + block[0x03] = temp_block[0x18]; block[0x04] = temp_block[0x20]; + if(last_non_zero_p1 <= 11) goto end; + block[0x0B] = temp_block[0x19]; + block[0x12] = temp_block[0x12]; block[0x19] = temp_block[0x0B]; + block[0x20] = temp_block[0x04]; block[0x28] = temp_block[0x05]; + if(last_non_zero_p1 <= 16) goto end; + block[0x21] = temp_block[0x0C]; block[0x1A] = temp_block[0x13]; + block[0x13] = temp_block[0x1A]; block[0x0C] = temp_block[0x21]; + block[0x05] = temp_block[0x28]; block[0x06] = temp_block[0x30]; + block[0x0D] = temp_block[0x29]; block[0x14] = temp_block[0x22]; + if(last_non_zero_p1 <= 24) goto end; + block[0x1B] = temp_block[0x1B]; block[0x22] = temp_block[0x14]; + block[0x29] = temp_block[0x0D]; block[0x30] = temp_block[0x06]; + block[0x38] = temp_block[0x07]; block[0x31] = temp_block[0x0E]; + block[0x2A] = temp_block[0x15]; block[0x23] = temp_block[0x1C]; + if(last_non_zero_p1 <= 32) goto end; + block[0x1C] = temp_block[0x23]; block[0x15] = temp_block[0x2A]; + block[0x0E] = temp_block[0x31]; block[0x07] = temp_block[0x38]; + block[0x0F] = temp_block[0x39]; block[0x16] = temp_block[0x32]; + block[0x1D] = temp_block[0x2B]; block[0x24] = temp_block[0x24]; + if(last_non_zero_p1 <= 40) goto end; + block[0x2B] = temp_block[0x1D]; block[0x32] = temp_block[0x16]; + block[0x39] = temp_block[0x0F]; block[0x3A] = temp_block[0x17]; + block[0x33] = temp_block[0x1E]; block[0x2C] = temp_block[0x25]; + block[0x25] = temp_block[0x2C]; block[0x1E] = temp_block[0x33]; + if(last_non_zero_p1 <= 48) goto end; + block[0x17] = temp_block[0x3A]; block[0x1F] = temp_block[0x3B]; + block[0x26] = temp_block[0x34]; block[0x2D] = temp_block[0x2D]; + block[0x34] = temp_block[0x26]; block[0x3B] = temp_block[0x1F]; + block[0x3C] = temp_block[0x27]; block[0x35] = temp_block[0x2E]; + if(last_non_zero_p1 <= 56) goto end; + block[0x2E] = temp_block[0x35]; block[0x27] = temp_block[0x3C]; + block[0x2F] = temp_block[0x3D]; block[0x36] = temp_block[0x36]; + block[0x3D] = temp_block[0x2F]; block[0x3E] = temp_block[0x37]; + block[0x37] = temp_block[0x3E]; block[0x3F] = temp_block[0x3F]; + } else { + av_log(s, AV_LOG_DEBUG, "s->idsp.perm_type: %d\n", + (int)s->idsp.perm_type); + av_assert0(s->idsp.perm_type == FF_IDCT_PERM_NONE || + s->idsp.perm_type == FF_IDCT_PERM_LIBMPEG2 || + s->idsp.perm_type == FF_IDCT_PERM_SIMPLE || + s->idsp.perm_type == FF_IDCT_PERM_TRANSPOSE); + } + end: + return last_non_zero_p1 - 1; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoencdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoencdsp_init.c new file mode 100644 index 0000000000..532836cec9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mpegvideoencdsp_init.c @@ -0,0 +1,272 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/mpegvideoencdsp.h" + +int ff_pix_sum16_mmx(uint8_t *pix, int line_size); +int ff_pix_sum16_mmxext(uint8_t *pix, int line_size); +int ff_pix_sum16_sse2(uint8_t *pix, int line_size); +int ff_pix_sum16_xop(uint8_t *pix, int line_size); +int ff_pix_norm1_mmx(uint8_t *pix, int line_size); +int ff_pix_norm1_sse2(uint8_t *pix, int line_size); + +#if HAVE_INLINE_ASM + +#define PHADDD(a, t) \ + "movq " #a ", " #t " \n\t" \ + "psrlq $32, " #a " \n\t" \ + "paddd " #t ", " #a " \n\t" + +/* + * pmulhw: dst[0 - 15] = (src[0 - 15] * dst[0 - 15])[16 - 31] + * pmulhrw: dst[0 - 15] = (src[0 - 15] * dst[0 - 15] + 0x8000)[16 - 31] + * pmulhrsw: dst[0 - 15] = (src[0 - 15] * dst[0 - 15] + 0x4000)[15 - 30] + */ +#define PMULHRW(x, y, s, o) \ + "pmulhw " #s ", " #x " \n\t" \ + "pmulhw " #s ", " #y " \n\t" \ + "paddw " #o ", " #x " \n\t" \ + "paddw " #o ", " #y " \n\t" \ + "psraw $1, " #x " \n\t" \ + "psraw $1, " #y " \n\t" +#define DEF(x) x ## _mmx +#define SET_RND MOVQ_WONE +#define SCALE_OFFSET 1 + +#include "mpegvideoenc_qns_template.c" + +#undef DEF +#undef SET_RND +#undef SCALE_OFFSET +#undef PMULHRW + +#define DEF(x) x ## _3dnow +#define SET_RND(x) +#define SCALE_OFFSET 0 +#define PMULHRW(x, y, s, o) \ + "pmulhrw " #s ", " #x " \n\t" \ + "pmulhrw " #s ", " #y " \n\t" + +#include "mpegvideoenc_qns_template.c" + +#undef DEF +#undef SET_RND +#undef SCALE_OFFSET +#undef PMULHRW + +#if HAVE_SSSE3_INLINE +#undef PHADDD +#define DEF(x) x ## _ssse3 +#define SET_RND(x) +#define SCALE_OFFSET -1 + +#define PHADDD(a, t) \ + "pshufw $0x0E, " #a ", " #t " \n\t" \ + /* faster than phaddd on core2 */ \ + "paddd " #t ", " #a " \n\t" + +#define PMULHRW(x, y, s, o) \ + "pmulhrsw " #s ", " #x " \n\t" \ + "pmulhrsw " #s ", " #y " \n\t" + +#include "mpegvideoenc_qns_template.c" + +#undef DEF +#undef SET_RND +#undef SCALE_OFFSET +#undef PMULHRW +#undef PHADDD +#endif /* HAVE_SSSE3_INLINE */ + +/* Draw the edges of width 'w' of an image of size width, height + * this MMX version can only handle w == 8 || w == 16. */ +static void draw_edges_mmx(uint8_t *buf, int wrap, int width, int height, + int w, int h, int sides) +{ + uint8_t *ptr, *last_line; + int i; + + last_line = buf + (height - 1) * wrap; + /* left and right */ + ptr = buf; + if (w == 8) { + __asm__ volatile ( + "1: \n\t" + "movd (%0), %%mm0 \n\t" + "punpcklbw %%mm0, %%mm0 \n\t" + "punpcklwd %%mm0, %%mm0 \n\t" + "punpckldq %%mm0, %%mm0 \n\t" + "movq %%mm0, -8(%0) \n\t" + "movq -8(%0, %2), %%mm1 \n\t" + "punpckhbw %%mm1, %%mm1 \n\t" + "punpckhwd %%mm1, %%mm1 \n\t" + "punpckhdq %%mm1, %%mm1 \n\t" + "movq %%mm1, (%0, %2) \n\t" + "add %1, %0 \n\t" + "cmp %3, %0 \n\t" + "jb 1b \n\t" + : "+r" (ptr) + : "r" ((x86_reg) wrap), "r" ((x86_reg) width), + "r" (ptr + wrap * height)); + } else if (w == 16) { + __asm__ volatile ( + "1: \n\t" + "movd (%0), %%mm0 \n\t" + "punpcklbw %%mm0, %%mm0 \n\t" + "punpcklwd %%mm0, %%mm0 \n\t" + "punpckldq %%mm0, %%mm0 \n\t" + "movq %%mm0, -8(%0) \n\t" + "movq %%mm0, -16(%0) \n\t" + "movq -8(%0, %2), %%mm1 \n\t" + "punpckhbw %%mm1, %%mm1 \n\t" + "punpckhwd %%mm1, %%mm1 \n\t" + "punpckhdq %%mm1, %%mm1 \n\t" + "movq %%mm1, (%0, %2) \n\t" + "movq %%mm1, 8(%0, %2) \n\t" + "add %1, %0 \n\t" + "cmp %3, %0 \n\t" + "jb 1b \n\t" + : "+r"(ptr) + : "r"((x86_reg)wrap), "r"((x86_reg)width), "r"(ptr + wrap * height) + ); + } else { + av_assert1(w == 4); + __asm__ volatile ( + "1: \n\t" + "movd (%0), %%mm0 \n\t" + "punpcklbw %%mm0, %%mm0 \n\t" + "punpcklwd %%mm0, %%mm0 \n\t" + "movd %%mm0, -4(%0) \n\t" + "movd -4(%0, %2), %%mm1 \n\t" + "punpcklbw %%mm1, %%mm1 \n\t" + "punpckhwd %%mm1, %%mm1 \n\t" + "punpckhdq %%mm1, %%mm1 \n\t" + "movd %%mm1, (%0, %2) \n\t" + "add %1, %0 \n\t" + "cmp %3, %0 \n\t" + "jb 1b \n\t" + : "+r" (ptr) + : "r" ((x86_reg) wrap), "r" ((x86_reg) width), + "r" (ptr + wrap * height)); + } + + /* top and bottom (and hopefully also the corners) */ + if (sides & EDGE_TOP) { + for (i = 0; i < h; i += 4) { + ptr = buf - (i + 1) * wrap - w; + __asm__ volatile ( + "1: \n\t" + "movq (%1, %0), %%mm0 \n\t" + "movq %%mm0, (%0) \n\t" + "movq %%mm0, (%0, %2) \n\t" + "movq %%mm0, (%0, %2, 2) \n\t" + "movq %%mm0, (%0, %3) \n\t" + "add $8, %0 \n\t" + "cmp %4, %0 \n\t" + "jb 1b \n\t" + : "+r" (ptr) + : "r" ((x86_reg) buf - (x86_reg) ptr - w), + "r" ((x86_reg) - wrap), "r" ((x86_reg) - wrap * 3), + "r" (ptr + width + 2 * w)); + } + } + + if (sides & EDGE_BOTTOM) { + for (i = 0; i < h; i += 4) { + ptr = last_line + (i + 1) * wrap - w; + __asm__ volatile ( + "1: \n\t" + "movq (%1, %0), %%mm0 \n\t" + "movq %%mm0, (%0) \n\t" + "movq %%mm0, (%0, %2) \n\t" + "movq %%mm0, (%0, %2, 2) \n\t" + "movq %%mm0, (%0, %3) \n\t" + "add $8, %0 \n\t" + "cmp %4, %0 \n\t" + "jb 1b \n\t" + : "+r" (ptr) + : "r" ((x86_reg) last_line - (x86_reg) ptr - w), + "r" ((x86_reg) wrap), "r" ((x86_reg) wrap * 3), + "r" (ptr + width + 2 * w)); + } + } +} + +#endif /* HAVE_INLINE_ASM */ + +av_cold void ff_mpegvideoencdsp_init_x86(MpegvideoEncDSPContext *c, + AVCodecContext *avctx) +{ + int cpu_flags = av_get_cpu_flags(); + +#if ARCH_X86_32 + if (EXTERNAL_MMX(cpu_flags)) { + c->pix_sum = ff_pix_sum16_mmx; + c->pix_norm1 = ff_pix_norm1_mmx; + } + + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->pix_sum = ff_pix_sum16_mmxext; + } +#endif + + if (EXTERNAL_SSE2(cpu_flags)) { + c->pix_sum = ff_pix_sum16_sse2; + c->pix_norm1 = ff_pix_norm1_sse2; + } + + if (EXTERNAL_XOP(cpu_flags)) { + c->pix_sum = ff_pix_sum16_xop; + } + +#if HAVE_INLINE_ASM + + if (INLINE_MMX(cpu_flags)) { + if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { + c->try_8x8basis = try_8x8basis_mmx; + } + c->add_8x8basis = add_8x8basis_mmx; + + if (avctx->bits_per_raw_sample <= 8) { + c->draw_edges = draw_edges_mmx; + } + } + + if (INLINE_AMD3DNOW(cpu_flags)) { + if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { + c->try_8x8basis = try_8x8basis_3dnow; + } + c->add_8x8basis = add_8x8basis_3dnow; + } + +#if HAVE_SSSE3_INLINE + if (INLINE_SSSE3(cpu_flags)) { + if (!(avctx->flags & AV_CODEC_FLAG_BITEXACT)) { + c->try_8x8basis = try_8x8basis_ssse3; + } + c->add_8x8basis = add_8x8basis_ssse3; + } +#endif /* HAVE_SSSE3_INLINE */ + +#endif /* HAVE_INLINE_ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/opusdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/opusdsp_init.c new file mode 100644 index 0000000000..6834c4e6a4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/opusdsp_init.c @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/x86/cpu.h" +#include "libavcodec/opusdsp.h" + +void ff_opus_postfilter_fma3(float *data, int period, float *gains, int len); +float ff_opus_deemphasis_fma3(float *out, float *in, float coeff, int len); + +av_cold void ff_opus_dsp_init_x86(OpusDSP *ctx) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_FMA3_FAST(cpu_flags)) { + ctx->postfilter = ff_opus_postfilter_fma3; + ctx->deemphasis = ff_opus_deemphasis_fma3; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/pixblockdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/pixblockdsp_init.c new file mode 100644 index 0000000000..ade55e01a3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/pixblockdsp_init.c @@ -0,0 +1,52 @@ +/* + * SIMD-optimized pixel operations + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/pixblockdsp.h" + +void ff_get_pixels_mmx(int16_t *block, const uint8_t *pixels, ptrdiff_t stride); +void ff_get_pixels_sse2(int16_t *block, const uint8_t *pixels, ptrdiff_t stride); +void ff_diff_pixels_mmx(int16_t *block, const uint8_t *s1, const uint8_t *s2, + ptrdiff_t stride); +void ff_diff_pixels_sse2(int16_t *block, const uint8_t *s1, const uint8_t *s2, + ptrdiff_t stride); + +av_cold void ff_pixblockdsp_init_x86(PixblockDSPContext *c, + AVCodecContext *avctx, + unsigned high_bit_depth) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + if (!high_bit_depth) + c->get_pixels = ff_get_pixels_mmx; + c->diff_pixels_unaligned = + c->diff_pixels = ff_diff_pixels_mmx; + } + + if (EXTERNAL_SSE2(cpu_flags)) { + if (!high_bit_depth) + c->get_pixels = ff_get_pixels_sse2; + c->diff_pixels_unaligned = + c->diff_pixels = ff_diff_pixels_sse2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/pngdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/pngdsp_init.c new file mode 100644 index 0000000000..7dca62c675 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/pngdsp_init.c @@ -0,0 +1,50 @@ +/* + * x86 PNG optimizations. + * Copyright (c) 2008 Loren Merrit + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/common.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/pngdsp.h" + +void ff_add_png_paeth_prediction_mmxext(uint8_t *dst, uint8_t *src, + uint8_t *top, int w, int bpp); +void ff_add_png_paeth_prediction_ssse3(uint8_t *dst, uint8_t *src, + uint8_t *top, int w, int bpp); +void ff_add_bytes_l2_mmx (uint8_t *dst, uint8_t *src1, + uint8_t *src2, int w); +void ff_add_bytes_l2_sse2(uint8_t *dst, uint8_t *src1, + uint8_t *src2, int w); + +av_cold void ff_pngdsp_init_x86(PNGDSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + +#if ARCH_X86_32 + if (EXTERNAL_MMX(cpu_flags)) + dsp->add_bytes_l2 = ff_add_bytes_l2_mmx; +#endif + if (EXTERNAL_MMXEXT(cpu_flags)) + dsp->add_paeth_prediction = ff_add_png_paeth_prediction_mmxext; + if (EXTERNAL_SSE2(cpu_flags)) + dsp->add_bytes_l2 = ff_add_bytes_l2_sse2; + if (EXTERNAL_SSSE3(cpu_flags)) + dsp->add_paeth_prediction = ff_add_png_paeth_prediction_ssse3; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/proresdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/proresdsp_init.c new file mode 100644 index 0000000000..bde79ab8c0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/proresdsp_init.c @@ -0,0 +1,50 @@ +/* + * Apple ProRes compatible decoder + * + * Copyright (c) 2010-2011 Maxim Poliakovski + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/idctdsp.h" +#include "libavcodec/proresdsp.h" + +void ff_prores_idct_put_10_sse2(uint16_t *dst, ptrdiff_t linesize, + int16_t *block, const int16_t *qmat); +void ff_prores_idct_put_10_avx (uint16_t *dst, ptrdiff_t linesize, + int16_t *block, const int16_t *qmat); + +av_cold void ff_proresdsp_init_x86(ProresDSPContext *dsp, AVCodecContext *avctx) +{ +#if ARCH_X86_64 + int cpu_flags = av_get_cpu_flags(); + + if (avctx->bits_per_raw_sample == 10){ + if (EXTERNAL_SSE2(cpu_flags)) { + dsp->idct_permutation_type = FF_IDCT_PERM_TRANSPOSE; + dsp->idct_put = ff_prores_idct_put_10_sse2; + } + + if (EXTERNAL_AVX(cpu_flags)) { + dsp->idct_permutation_type = FF_IDCT_PERM_TRANSPOSE; + dsp->idct_put = ff_prores_idct_put_10_avx; + } + } +#endif /* ARCH_X86_64 */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/qpeldsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/qpeldsp_init.c new file mode 100644 index 0000000000..3b05e156cc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/qpeldsp_init.c @@ -0,0 +1,544 @@ +/* + * quarterpel DSP functions + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/pixels.h" +#include "libavcodec/qpeldsp.h" +#include "fpel.h" + +void ff_put_pixels8_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_put_no_rnd_pixels8_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_avg_pixels8_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_put_pixels16_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_avg_pixels16_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_put_no_rnd_pixels16_l2_mmxext(uint8_t *dst, + const uint8_t *src1, const uint8_t *src2, + int dstStride, int src1Stride, int h); +void ff_put_mpeg4_qpel16_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, + int dstStride, int srcStride, int h); +void ff_avg_mpeg4_qpel16_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, + int dstStride, int srcStride, int h); +void ff_put_no_rnd_mpeg4_qpel16_h_lowpass_mmxext(uint8_t *dst, + const uint8_t *src, + int dstStride, int srcStride, + int h); +void ff_put_mpeg4_qpel8_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, + int dstStride, int srcStride, int h); +void ff_avg_mpeg4_qpel8_h_lowpass_mmxext(uint8_t *dst, const uint8_t *src, + int dstStride, int srcStride, int h); +void ff_put_no_rnd_mpeg4_qpel8_h_lowpass_mmxext(uint8_t *dst, + const uint8_t *src, + int dstStride, int srcStride, + int h); +void ff_put_mpeg4_qpel16_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, + int dstStride, int srcStride); +void ff_avg_mpeg4_qpel16_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, + int dstStride, int srcStride); +void ff_put_no_rnd_mpeg4_qpel16_v_lowpass_mmxext(uint8_t *dst, + const uint8_t *src, + int dstStride, int srcStride); +void ff_put_mpeg4_qpel8_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, + int dstStride, int srcStride); +void ff_avg_mpeg4_qpel8_v_lowpass_mmxext(uint8_t *dst, const uint8_t *src, + int dstStride, int srcStride); +void ff_put_no_rnd_mpeg4_qpel8_v_lowpass_mmxext(uint8_t *dst, + const uint8_t *src, + int dstStride, int srcStride); +#define ff_put_no_rnd_pixels16_mmxext ff_put_pixels16_mmx +#define ff_put_no_rnd_pixels8_mmxext ff_put_pixels8_mmx + +#if HAVE_X86ASM + +#define ff_put_pixels16_mmxext ff_put_pixels16_mmx +#define ff_put_pixels8_mmxext ff_put_pixels8_mmx + +#define QPEL_OP(OPNAME, RND, MMX) \ +static void OPNAME ## qpel8_mc00_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + ff_ ## OPNAME ## pixels8_ ## MMX(dst, src, stride, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc10_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t temp[8]; \ + uint8_t *const half = (uint8_t *) temp; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(half, src, 8, \ + stride, 8); \ + ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, src, half, \ + stride, stride, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc20_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + ff_ ## OPNAME ## mpeg4_qpel8_h_lowpass_ ## MMX(dst, src, stride, \ + stride, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc30_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t temp[8]; \ + uint8_t *const half = (uint8_t *) temp; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(half, src, 8, \ + stride, 8); \ + ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, src + 1, half, stride, \ + stride, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc01_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t temp[8]; \ + uint8_t *const half = (uint8_t *) temp; \ + ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(half, src, \ + 8, stride); \ + ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, src, half, \ + stride, stride, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc02_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + ff_ ## OPNAME ## mpeg4_qpel8_v_lowpass_ ## MMX(dst, src, \ + stride, stride); \ +} \ + \ +static void OPNAME ## qpel8_mc03_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t temp[8]; \ + uint8_t *const half = (uint8_t *) temp; \ + ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(half, src, \ + 8, stride); \ + ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, src + stride, half, stride,\ + stride, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc11_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[8 + 9]; \ + uint8_t *const halfH = (uint8_t *) half + 64; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ + stride, 9); \ + ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src, halfH, 8, \ + stride, 9); \ + ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ + ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc31_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[8 + 9]; \ + uint8_t *const halfH = (uint8_t *) half + 64; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ + stride, 9); \ + ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src + 1, halfH, 8, \ + stride, 9); \ + ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ + ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc13_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[8 + 9]; \ + uint8_t *const halfH = (uint8_t *) half + 64; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ + stride, 9); \ + ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src, halfH, 8, \ + stride, 9); \ + ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ + ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH + 8, halfHV, \ + stride, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc33_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[8 + 9]; \ + uint8_t *const halfH = (uint8_t *) half + 64; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ + stride, 9); \ + ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src + 1, halfH, 8, \ + stride, 9); \ + ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ + ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH + 8, halfHV, \ + stride, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc21_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[8 + 9]; \ + uint8_t *const halfH = (uint8_t *) half + 64; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ + stride, 9); \ + ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ + ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc23_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[8 + 9]; \ + uint8_t *const halfH = (uint8_t *) half + 64; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ + stride, 9); \ + ff_put ## RND ## mpeg4_qpel8_v_lowpass_ ## MMX(halfHV, halfH, 8, 8);\ + ff_ ## OPNAME ## pixels8_l2_ ## MMX(dst, halfH + 8, halfHV, \ + stride, 8, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc12_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[8 + 9]; \ + uint8_t *const halfH = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ + stride, 9); \ + ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src, halfH, \ + 8, stride, 9); \ + ff_ ## OPNAME ## mpeg4_qpel8_v_lowpass_ ## MMX(dst, halfH, \ + stride, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc32_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[8 + 9]; \ + uint8_t *const halfH = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ + stride, 9); \ + ff_put ## RND ## pixels8_l2_ ## MMX(halfH, src + 1, halfH, 8, \ + stride, 9); \ + ff_ ## OPNAME ## mpeg4_qpel8_v_lowpass_ ## MMX(dst, halfH, \ + stride, 8); \ +} \ + \ +static void OPNAME ## qpel8_mc22_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[9]; \ + uint8_t *const halfH = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel8_h_lowpass_ ## MMX(halfH, src, 8, \ + stride, 9); \ + ff_ ## OPNAME ## mpeg4_qpel8_v_lowpass_ ## MMX(dst, halfH, \ + stride, 8); \ +} \ + \ +static void OPNAME ## qpel16_mc00_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + ff_ ## OPNAME ## pixels16_ ## MMX(dst, src, stride, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc10_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t temp[32]; \ + uint8_t *const half = (uint8_t *) temp; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(half, src, 16, \ + stride, 16); \ + ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, src, half, stride, \ + stride, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc20_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + ff_ ## OPNAME ## mpeg4_qpel16_h_lowpass_ ## MMX(dst, src, \ + stride, stride, 16);\ +} \ + \ +static void OPNAME ## qpel16_mc30_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t temp[32]; \ + uint8_t *const half = (uint8_t*) temp; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(half, src, 16, \ + stride, 16); \ + ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, src + 1, half, \ + stride, stride, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc01_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t temp[32]; \ + uint8_t *const half = (uint8_t *) temp; \ + ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(half, src, 16, \ + stride); \ + ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, src, half, stride, \ + stride, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc02_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + ff_ ## OPNAME ## mpeg4_qpel16_v_lowpass_ ## MMX(dst, src, \ + stride, stride); \ +} \ + \ +static void OPNAME ## qpel16_mc03_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t temp[32]; \ + uint8_t *const half = (uint8_t *) temp; \ + ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(half, src, 16, \ + stride); \ + ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, src+stride, half, \ + stride, stride, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc11_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[16 * 2 + 17 * 2]; \ + uint8_t *const halfH = (uint8_t *) half + 256; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ + stride, 17); \ + ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src, halfH, 16, \ + stride, 17); \ + ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ + 16, 16); \ + ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc31_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[16 * 2 + 17 * 2]; \ + uint8_t *const halfH = (uint8_t *) half + 256; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ + stride, 17); \ + ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src + 1, halfH, 16, \ + stride, 17); \ + ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ + 16, 16); \ + ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc13_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[16 * 2 + 17 * 2]; \ + uint8_t *const halfH = (uint8_t *) half + 256; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ + stride, 17); \ + ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src, halfH, 16, \ + stride, 17); \ + ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ + 16, 16); \ + ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH + 16, halfHV, \ + stride, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc33_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[16 * 2 + 17 * 2]; \ + uint8_t *const halfH = (uint8_t *) half + 256; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ + stride, 17); \ + ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src + 1, halfH, 16, \ + stride, 17); \ + ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ + 16, 16); \ + ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH + 16, halfHV, \ + stride, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc21_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[16 * 2 + 17 * 2]; \ + uint8_t *const halfH = (uint8_t *) half + 256; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ + stride, 17); \ + ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ + 16, 16); \ + ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH, halfHV, \ + stride, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc23_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[16 * 2 + 17 * 2]; \ + uint8_t *const halfH = (uint8_t *) half + 256; \ + uint8_t *const halfHV = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ + stride, 17); \ + ff_put ## RND ## mpeg4_qpel16_v_lowpass_ ## MMX(halfHV, halfH, \ + 16, 16); \ + ff_ ## OPNAME ## pixels16_l2_ ## MMX(dst, halfH + 16, halfHV, \ + stride, 16, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc12_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[17 * 2]; \ + uint8_t *const halfH = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ + stride, 17); \ + ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src, halfH, 16, \ + stride, 17); \ + ff_ ## OPNAME ## mpeg4_qpel16_v_lowpass_ ## MMX(dst, halfH, \ + stride, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc32_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[17 * 2]; \ + uint8_t *const halfH = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ + stride, 17); \ + ff_put ## RND ## pixels16_l2_ ## MMX(halfH, src + 1, halfH, 16, \ + stride, 17); \ + ff_ ## OPNAME ## mpeg4_qpel16_v_lowpass_ ## MMX(dst, halfH, \ + stride, 16); \ +} \ + \ +static void OPNAME ## qpel16_mc22_ ## MMX(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + uint64_t half[17 * 2]; \ + uint8_t *const halfH = (uint8_t *) half; \ + ff_put ## RND ## mpeg4_qpel16_h_lowpass_ ## MMX(halfH, src, 16, \ + stride, 17); \ + ff_ ## OPNAME ## mpeg4_qpel16_v_lowpass_ ## MMX(dst, halfH, \ + stride, 16); \ +} + +QPEL_OP(put_, _, mmxext) +QPEL_OP(avg_, _, mmxext) +QPEL_OP(put_no_rnd_, _no_rnd_, mmxext) + +#endif /* HAVE_X86ASM */ + +#define SET_QPEL_FUNCS(PFX, IDX, SIZE, CPU, PREFIX) \ +do { \ + c->PFX ## _pixels_tab[IDX][ 0] = PREFIX ## PFX ## SIZE ## _mc00_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 1] = PREFIX ## PFX ## SIZE ## _mc10_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 2] = PREFIX ## PFX ## SIZE ## _mc20_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 3] = PREFIX ## PFX ## SIZE ## _mc30_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 4] = PREFIX ## PFX ## SIZE ## _mc01_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 5] = PREFIX ## PFX ## SIZE ## _mc11_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 6] = PREFIX ## PFX ## SIZE ## _mc21_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 7] = PREFIX ## PFX ## SIZE ## _mc31_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 8] = PREFIX ## PFX ## SIZE ## _mc02_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][ 9] = PREFIX ## PFX ## SIZE ## _mc12_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][10] = PREFIX ## PFX ## SIZE ## _mc22_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][11] = PREFIX ## PFX ## SIZE ## _mc32_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][12] = PREFIX ## PFX ## SIZE ## _mc03_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][13] = PREFIX ## PFX ## SIZE ## _mc13_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][14] = PREFIX ## PFX ## SIZE ## _mc23_ ## CPU; \ + c->PFX ## _pixels_tab[IDX][15] = PREFIX ## PFX ## SIZE ## _mc33_ ## CPU; \ +} while (0) + +av_cold void ff_qpeldsp_init_x86(QpelDSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (X86_MMXEXT(cpu_flags)) { +#if HAVE_MMXEXT_EXTERNAL + SET_QPEL_FUNCS(avg_qpel, 0, 16, mmxext, ); + SET_QPEL_FUNCS(avg_qpel, 1, 8, mmxext, ); + + SET_QPEL_FUNCS(put_qpel, 0, 16, mmxext, ); + SET_QPEL_FUNCS(put_qpel, 1, 8, mmxext, ); + SET_QPEL_FUNCS(put_no_rnd_qpel, 0, 16, mmxext, ); + SET_QPEL_FUNCS(put_no_rnd_qpel, 1, 8, mmxext, ); +#endif /* HAVE_MMXEXT_EXTERNAL */ + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rnd_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rnd_template.c new file mode 100644 index 0000000000..09946bd23f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rnd_template.c @@ -0,0 +1,175 @@ +/* + * SIMD-optimized halfpel functions are compiled twice for rnd/no_rnd + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2003-2004 Michael Niedermayer + * + * MMX optimization by Nick Kurshev + * mostly rewritten by Michael Niedermayer + * and improved by Zdenek Kabelac + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "inline_asm.h" + +// put_pixels +av_unused STATIC void DEF(put, pixels8_xy2)(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h) +{ + MOVQ_ZERO(mm7); + SET_RND(mm6); // =2 for rnd and =1 for no_rnd version + __asm__ volatile( + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm4 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm4, %%mm5 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "punpckhbw %%mm7, %%mm1 \n\t" + "punpckhbw %%mm7, %%mm5 \n\t" + "paddusw %%mm0, %%mm4 \n\t" + "paddusw %%mm1, %%mm5 \n\t" + "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" + "add %3, %1 \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" + "movq 1(%1, %%"FF_REG_a"), %%mm2 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm2, %%mm3 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpckhbw %%mm7, %%mm1 \n\t" + "punpckhbw %%mm7, %%mm3 \n\t" + "paddusw %%mm2, %%mm0 \n\t" + "paddusw %%mm3, %%mm1 \n\t" + "paddusw %%mm6, %%mm4 \n\t" + "paddusw %%mm6, %%mm5 \n\t" + "paddusw %%mm0, %%mm4 \n\t" + "paddusw %%mm1, %%mm5 \n\t" + "psrlw $2, %%mm4 \n\t" + "psrlw $2, %%mm5 \n\t" + "packuswb %%mm5, %%mm4 \n\t" + "movq %%mm4, (%2, %%"FF_REG_a") \n\t" + "add %3, %%"FF_REG_a" \n\t" + + "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" // 0 <-> 2 1 <-> 3 + "movq 1(%1, %%"FF_REG_a"), %%mm4 \n\t" + "movq %%mm2, %%mm3 \n\t" + "movq %%mm4, %%mm5 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "punpckhbw %%mm7, %%mm3 \n\t" + "punpckhbw %%mm7, %%mm5 \n\t" + "paddusw %%mm2, %%mm4 \n\t" + "paddusw %%mm3, %%mm5 \n\t" + "paddusw %%mm6, %%mm0 \n\t" + "paddusw %%mm6, %%mm1 \n\t" + "paddusw %%mm4, %%mm0 \n\t" + "paddusw %%mm5, %%mm1 \n\t" + "psrlw $2, %%mm0 \n\t" + "psrlw $2, %%mm1 \n\t" + "packuswb %%mm1, %%mm0 \n\t" + "movq %%mm0, (%2, %%"FF_REG_a") \n\t" + "add %3, %%"FF_REG_a" \n\t" + + "subl $2, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels) + :"D"(block), "r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} + +// avg_pixels +// this routine is 'slightly' suboptimal but mostly unused +av_unused STATIC void DEF(avg, pixels8_xy2)(uint8_t *block, const uint8_t *pixels, + ptrdiff_t line_size, int h) +{ + MOVQ_ZERO(mm7); + SET_RND(mm6); // =2 for rnd and =1 for no_rnd version + __asm__ volatile( + "movq (%1), %%mm0 \n\t" + "movq 1(%1), %%mm4 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm4, %%mm5 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "punpckhbw %%mm7, %%mm1 \n\t" + "punpckhbw %%mm7, %%mm5 \n\t" + "paddusw %%mm0, %%mm4 \n\t" + "paddusw %%mm1, %%mm5 \n\t" + "xor %%"FF_REG_a", %%"FF_REG_a" \n\t" + "add %3, %1 \n\t" + ".p2align 3 \n\t" + "1: \n\t" + "movq (%1, %%"FF_REG_a"), %%mm0 \n\t" + "movq 1(%1, %%"FF_REG_a"), %%mm2 \n\t" + "movq %%mm0, %%mm1 \n\t" + "movq %%mm2, %%mm3 \n\t" + "punpcklbw %%mm7, %%mm0 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpckhbw %%mm7, %%mm1 \n\t" + "punpckhbw %%mm7, %%mm3 \n\t" + "paddusw %%mm2, %%mm0 \n\t" + "paddusw %%mm3, %%mm1 \n\t" + "paddusw %%mm6, %%mm4 \n\t" + "paddusw %%mm6, %%mm5 \n\t" + "paddusw %%mm0, %%mm4 \n\t" + "paddusw %%mm1, %%mm5 \n\t" + "psrlw $2, %%mm4 \n\t" + "psrlw $2, %%mm5 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm3 \n\t" + "packuswb %%mm5, %%mm4 \n\t" + "pcmpeqd %%mm2, %%mm2 \n\t" + "paddb %%mm2, %%mm2 \n\t" + PAVGB_MMX(%%mm3, %%mm4, %%mm5, %%mm2) + "movq %%mm5, (%2, %%"FF_REG_a") \n\t" + "add %3, %%"FF_REG_a" \n\t" + + "movq (%1, %%"FF_REG_a"), %%mm2 \n\t" // 0 <-> 2 1 <-> 3 + "movq 1(%1, %%"FF_REG_a"), %%mm4 \n\t" + "movq %%mm2, %%mm3 \n\t" + "movq %%mm4, %%mm5 \n\t" + "punpcklbw %%mm7, %%mm2 \n\t" + "punpcklbw %%mm7, %%mm4 \n\t" + "punpckhbw %%mm7, %%mm3 \n\t" + "punpckhbw %%mm7, %%mm5 \n\t" + "paddusw %%mm2, %%mm4 \n\t" + "paddusw %%mm3, %%mm5 \n\t" + "paddusw %%mm6, %%mm0 \n\t" + "paddusw %%mm6, %%mm1 \n\t" + "paddusw %%mm4, %%mm0 \n\t" + "paddusw %%mm5, %%mm1 \n\t" + "psrlw $2, %%mm0 \n\t" + "psrlw $2, %%mm1 \n\t" + "movq (%2, %%"FF_REG_a"), %%mm3 \n\t" + "packuswb %%mm1, %%mm0 \n\t" + "pcmpeqd %%mm2, %%mm2 \n\t" + "paddb %%mm2, %%mm2 \n\t" + PAVGB_MMX(%%mm3, %%mm0, %%mm1, %%mm2) + "movq %%mm1, (%2, %%"FF_REG_a") \n\t" + "add %3, %%"FF_REG_a" \n\t" + + "subl $2, %0 \n\t" + "jnz 1b \n\t" + :"+g"(h), "+S"(pixels) + :"D"(block), "r"((x86_reg)line_size) + :FF_REG_a, "memory"); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rv34dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rv34dsp_init.c new file mode 100644 index 0000000000..7310122458 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rv34dsp_init.c @@ -0,0 +1,48 @@ +/* + * RV30/40 MMX/SSE2 optimizations + * Copyright (C) 2012 Christophe Gisquet + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/rv34dsp.h" + +void ff_rv34_idct_dc_mmxext(int16_t *block); +void ff_rv34_idct_dc_noround_mmxext(int16_t *block); +void ff_rv34_idct_dc_add_mmx(uint8_t *dst, ptrdiff_t stride, int dc); +void ff_rv34_idct_dc_add_sse2(uint8_t *dst, ptrdiff_t stride, int dc); +void ff_rv34_idct_dc_add_sse4(uint8_t *dst, ptrdiff_t stride, int dc); +void ff_rv34_idct_add_mmxext(uint8_t *dst, ptrdiff_t stride, int16_t *block); + +av_cold void ff_rv34dsp_init_x86(RV34DSPContext* c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (ARCH_X86_32 && EXTERNAL_MMX(cpu_flags)) + c->rv34_idct_dc_add = ff_rv34_idct_dc_add_mmx; + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->rv34_inv_transform_dc = ff_rv34_idct_dc_noround_mmxext; + c->rv34_idct_add = ff_rv34_idct_add_mmxext; + } + if (EXTERNAL_SSE2(cpu_flags)) + c->rv34_idct_dc_add = ff_rv34_idct_dc_add_sse2; + if (EXTERNAL_SSE4(cpu_flags)) + c->rv34_idct_dc_add = ff_rv34_idct_dc_add_sse4; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rv40dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rv40dsp_init.c new file mode 100644 index 0000000000..b57a3fc31a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/rv40dsp_init.c @@ -0,0 +1,278 @@ +/* + * RV40 decoder motion compensation functions x86-optimised + * Copyright (c) 2008 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * RV40 decoder motion compensation functions x86-optimised + * 2,0 and 0,2 have h264 equivalents. + * 3,3 is bugged in the rv40 format and maps to _xy2 version + */ + +#include "libavcodec/rv34dsp.h" +#include "libavutil/attributes.h" +#include "libavutil/mem.h" +#include "libavutil/x86/cpu.h" +#include "hpeldsp.h" + +#define DEFINE_FN(op, size, insn) \ +static void op##_rv40_qpel##size##_mc33_##insn(uint8_t *dst, const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + ff_##op##_pixels##size##_xy2_##insn(dst, src, stride, size); \ +} + +#if HAVE_X86ASM +void ff_put_rv40_chroma_mc8_mmx (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_rv40_chroma_mc8_mmxext(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_rv40_chroma_mc8_3dnow(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); + +void ff_put_rv40_chroma_mc4_mmx (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_rv40_chroma_mc4_mmxext(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_rv40_chroma_mc4_3dnow(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); + +#define DECLARE_WEIGHT(opt) \ +void ff_rv40_weight_func_rnd_16_##opt(uint8_t *dst, uint8_t *src1, uint8_t *src2, \ + int w1, int w2, ptrdiff_t stride); \ +void ff_rv40_weight_func_rnd_8_##opt (uint8_t *dst, uint8_t *src1, uint8_t *src2, \ + int w1, int w2, ptrdiff_t stride); \ +void ff_rv40_weight_func_nornd_16_##opt(uint8_t *dst, uint8_t *src1, uint8_t *src2, \ + int w1, int w2, ptrdiff_t stride); \ +void ff_rv40_weight_func_nornd_8_##opt (uint8_t *dst, uint8_t *src1, uint8_t *src2, \ + int w1, int w2, ptrdiff_t stride); +DECLARE_WEIGHT(mmxext) +DECLARE_WEIGHT(sse2) +DECLARE_WEIGHT(ssse3) + +/** @{ */ +/** + * Define one qpel function. + * LOOPSIZE must be already set to the number of pixels processed per + * iteration in the inner loop of the called functions. + * COFF(x) must be already defined so as to provide the offset into any + * array of coeffs used by the called function for the qpel position x. + */ +#define QPEL_FUNC_DECL(OP, SIZE, PH, PV, OPT) \ +static void OP ## rv40_qpel ##SIZE ##_mc ##PH ##PV ##OPT(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride) \ +{ \ + int i; \ + if (PH && PV) { \ + LOCAL_ALIGNED(16, uint8_t, tmp, [SIZE * (SIZE + 5)]); \ + uint8_t *tmpptr = tmp + SIZE * 2; \ + src -= stride * 2; \ + \ + for (i = 0; i < SIZE; i += LOOPSIZE) \ + ff_put_rv40_qpel_h ##OPT(tmp + i, SIZE, src + i, stride, \ + SIZE + 5, HCOFF(PH)); \ + for (i = 0; i < SIZE; i += LOOPSIZE) \ + ff_ ##OP ##rv40_qpel_v ##OPT(dst + i, stride, tmpptr + i, \ + SIZE, SIZE, VCOFF(PV)); \ + } else if (PV) { \ + for (i = 0; i < SIZE; i += LOOPSIZE) \ + ff_ ##OP ##rv40_qpel_v ## OPT(dst + i, stride, src + i, \ + stride, SIZE, VCOFF(PV)); \ + } else { \ + for (i = 0; i < SIZE; i += LOOPSIZE) \ + ff_ ##OP ##rv40_qpel_h ## OPT(dst + i, stride, src + i, \ + stride, SIZE, HCOFF(PH)); \ + } \ +} + +/** Declare functions for sizes 8 and 16 and given operations + * and qpel position. */ +#define QPEL_FUNCS_DECL(OP, PH, PV, OPT) \ + QPEL_FUNC_DECL(OP, 8, PH, PV, OPT) \ + QPEL_FUNC_DECL(OP, 16, PH, PV, OPT) + +/** Declare all functions for all sizes and qpel positions */ +#define QPEL_MC_DECL(OP, OPT) \ +void ff_ ##OP ##rv40_qpel_h ##OPT(uint8_t *dst, ptrdiff_t dstStride, \ + const uint8_t *src, \ + ptrdiff_t srcStride, \ + int len, int m); \ +void ff_ ##OP ##rv40_qpel_v ##OPT(uint8_t *dst, ptrdiff_t dstStride, \ + const uint8_t *src, \ + ptrdiff_t srcStride, \ + int len, int m); \ +QPEL_FUNCS_DECL(OP, 0, 1, OPT) \ +QPEL_FUNCS_DECL(OP, 0, 3, OPT) \ +QPEL_FUNCS_DECL(OP, 1, 0, OPT) \ +QPEL_FUNCS_DECL(OP, 1, 1, OPT) \ +QPEL_FUNCS_DECL(OP, 1, 2, OPT) \ +QPEL_FUNCS_DECL(OP, 1, 3, OPT) \ +QPEL_FUNCS_DECL(OP, 2, 1, OPT) \ +QPEL_FUNCS_DECL(OP, 2, 2, OPT) \ +QPEL_FUNCS_DECL(OP, 2, 3, OPT) \ +QPEL_FUNCS_DECL(OP, 3, 0, OPT) \ +QPEL_FUNCS_DECL(OP, 3, 1, OPT) \ +QPEL_FUNCS_DECL(OP, 3, 2, OPT) +/** @} */ + +#define LOOPSIZE 8 +#define HCOFF(x) (32 * ((x) - 1)) +#define VCOFF(x) (32 * ((x) - 1)) +QPEL_MC_DECL(put_, _ssse3) +QPEL_MC_DECL(avg_, _ssse3) + +#undef LOOPSIZE +#undef HCOFF +#undef VCOFF +#define LOOPSIZE 8 +#define HCOFF(x) (64 * ((x) - 1)) +#define VCOFF(x) (64 * ((x) - 1)) +QPEL_MC_DECL(put_, _sse2) +QPEL_MC_DECL(avg_, _sse2) + +#if ARCH_X86_32 +#undef LOOPSIZE +#undef HCOFF +#undef VCOFF +#define LOOPSIZE 4 +#define HCOFF(x) (64 * ((x) - 1)) +#define VCOFF(x) (64 * ((x) - 1)) + +QPEL_MC_DECL(put_, _mmx) + +#define ff_put_rv40_qpel_h_mmxext ff_put_rv40_qpel_h_mmx +#define ff_put_rv40_qpel_v_mmxext ff_put_rv40_qpel_v_mmx +QPEL_MC_DECL(avg_, _mmxext) + +#define ff_put_rv40_qpel_h_3dnow ff_put_rv40_qpel_h_mmx +#define ff_put_rv40_qpel_v_3dnow ff_put_rv40_qpel_v_mmx +QPEL_MC_DECL(avg_, _3dnow) +#endif + +/** @{ */ +/** Set one function */ +#define QPEL_FUNC_SET(OP, SIZE, PH, PV, OPT) \ + c-> OP ## pixels_tab[2 - SIZE / 8][4 * PV + PH] = OP ## rv40_qpel ##SIZE ## _mc ##PH ##PV ##OPT; + +/** Set functions put and avg for sizes 8 and 16 and a given qpel position */ +#define QPEL_FUNCS_SET(OP, PH, PV, OPT) \ + QPEL_FUNC_SET(OP, 8, PH, PV, OPT) \ + QPEL_FUNC_SET(OP, 16, PH, PV, OPT) + +/** Set all functions for all sizes and qpel positions */ +#define QPEL_MC_SET(OP, OPT) \ +QPEL_FUNCS_SET (OP, 0, 1, OPT) \ +QPEL_FUNCS_SET (OP, 0, 3, OPT) \ +QPEL_FUNCS_SET (OP, 1, 0, OPT) \ +QPEL_FUNCS_SET (OP, 1, 1, OPT) \ +QPEL_FUNCS_SET (OP, 1, 2, OPT) \ +QPEL_FUNCS_SET (OP, 1, 3, OPT) \ +QPEL_FUNCS_SET (OP, 2, 1, OPT) \ +QPEL_FUNCS_SET (OP, 2, 2, OPT) \ +QPEL_FUNCS_SET (OP, 2, 3, OPT) \ +QPEL_FUNCS_SET (OP, 3, 0, OPT) \ +QPEL_FUNCS_SET (OP, 3, 1, OPT) \ +QPEL_FUNCS_SET (OP, 3, 2, OPT) +/** @} */ + +DEFINE_FN(put, 8, ssse3) + +DEFINE_FN(put, 16, sse2) +DEFINE_FN(put, 16, ssse3) + +DEFINE_FN(avg, 8, mmxext) +DEFINE_FN(avg, 8, ssse3) + +DEFINE_FN(avg, 16, sse2) +DEFINE_FN(avg, 16, ssse3) +#endif /* HAVE_X86ASM */ + +#if HAVE_MMX_INLINE +DEFINE_FN(put, 8, mmx) +DEFINE_FN(avg, 8, mmx) +DEFINE_FN(put, 16, mmx) +DEFINE_FN(avg, 16, mmx) +#endif + +av_cold void ff_rv40dsp_init_x86(RV34DSPContext *c) +{ + av_unused int cpu_flags = av_get_cpu_flags(); + +#if HAVE_MMX_INLINE + if (INLINE_MMX(cpu_flags)) { + c->put_pixels_tab[0][15] = put_rv40_qpel16_mc33_mmx; + c->put_pixels_tab[1][15] = put_rv40_qpel8_mc33_mmx; + c->avg_pixels_tab[0][15] = avg_rv40_qpel16_mc33_mmx; + c->avg_pixels_tab[1][15] = avg_rv40_qpel8_mc33_mmx; + } +#endif /* HAVE_MMX_INLINE */ + +#if HAVE_X86ASM + if (EXTERNAL_MMX(cpu_flags)) { + c->put_chroma_pixels_tab[0] = ff_put_rv40_chroma_mc8_mmx; + c->put_chroma_pixels_tab[1] = ff_put_rv40_chroma_mc4_mmx; +#if ARCH_X86_32 + QPEL_MC_SET(put_, _mmx) +#endif + } + if (EXTERNAL_AMD3DNOW(cpu_flags)) { + c->avg_chroma_pixels_tab[0] = ff_avg_rv40_chroma_mc8_3dnow; + c->avg_chroma_pixels_tab[1] = ff_avg_rv40_chroma_mc4_3dnow; +#if ARCH_X86_32 + QPEL_MC_SET(avg_, _3dnow) +#endif + } + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->avg_pixels_tab[1][15] = avg_rv40_qpel8_mc33_mmxext; + c->avg_chroma_pixels_tab[0] = ff_avg_rv40_chroma_mc8_mmxext; + c->avg_chroma_pixels_tab[1] = ff_avg_rv40_chroma_mc4_mmxext; + c->rv40_weight_pixels_tab[0][0] = ff_rv40_weight_func_rnd_16_mmxext; + c->rv40_weight_pixels_tab[0][1] = ff_rv40_weight_func_rnd_8_mmxext; + c->rv40_weight_pixels_tab[1][0] = ff_rv40_weight_func_nornd_16_mmxext; + c->rv40_weight_pixels_tab[1][1] = ff_rv40_weight_func_nornd_8_mmxext; +#if ARCH_X86_32 + QPEL_MC_SET(avg_, _mmxext) +#endif + } + if (EXTERNAL_SSE2(cpu_flags)) { + c->put_pixels_tab[0][15] = put_rv40_qpel16_mc33_sse2; + c->avg_pixels_tab[0][15] = avg_rv40_qpel16_mc33_sse2; + c->rv40_weight_pixels_tab[0][0] = ff_rv40_weight_func_rnd_16_sse2; + c->rv40_weight_pixels_tab[0][1] = ff_rv40_weight_func_rnd_8_sse2; + c->rv40_weight_pixels_tab[1][0] = ff_rv40_weight_func_nornd_16_sse2; + c->rv40_weight_pixels_tab[1][1] = ff_rv40_weight_func_nornd_8_sse2; + QPEL_MC_SET(put_, _sse2) + QPEL_MC_SET(avg_, _sse2) + } + if (EXTERNAL_SSSE3(cpu_flags)) { + c->put_pixels_tab[0][15] = put_rv40_qpel16_mc33_ssse3; + c->put_pixels_tab[1][15] = put_rv40_qpel8_mc33_ssse3; + c->avg_pixels_tab[0][15] = avg_rv40_qpel16_mc33_ssse3; + c->avg_pixels_tab[1][15] = avg_rv40_qpel8_mc33_ssse3; + c->rv40_weight_pixels_tab[0][0] = ff_rv40_weight_func_rnd_16_ssse3; + c->rv40_weight_pixels_tab[0][1] = ff_rv40_weight_func_rnd_8_ssse3; + c->rv40_weight_pixels_tab[1][0] = ff_rv40_weight_func_nornd_16_ssse3; + c->rv40_weight_pixels_tab[1][1] = ff_rv40_weight_func_nornd_8_ssse3; + QPEL_MC_SET(put_, _ssse3) + QPEL_MC_SET(avg_, _ssse3) + } +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbcdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbcdsp_init.c new file mode 100644 index 0000000000..86effecfdf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbcdsp_init.c @@ -0,0 +1,51 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC MMX optimization for some basic "building bricks" + */ + +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/sbcdsp.h" + +void ff_sbc_analyze_4_mmx(const int16_t *in, int32_t *out, const int16_t *consts); +void ff_sbc_analyze_8_mmx(const int16_t *in, int32_t *out, const int16_t *consts); +void ff_sbc_calc_scalefactors_mmx(int32_t sb_sample_f[16][2][8], + uint32_t scale_factor[2][8], + int blocks, int channels, int subbands); + +av_cold void ff_sbcdsp_init_x86(SBCDSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + s->sbc_analyze_4 = ff_sbc_analyze_4_mmx; + s->sbc_analyze_8 = ff_sbc_analyze_8_mmx; + s->sbc_calc_scalefactors = ff_sbc_calc_scalefactors_mmx; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbrdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbrdsp_init.c new file mode 100644 index 0000000000..6911a1a515 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbrdsp_init.c @@ -0,0 +1,87 @@ +/* + * AAC Spectral Band Replication decoding functions + * Copyright (c) 2012 Christophe Gisquet + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/sbrdsp.h" + +float ff_sbr_sum_square_sse(float (*x)[2], int n); +void ff_sbr_sum64x5_sse(float *z); +void ff_sbr_hf_g_filt_sse(float (*Y)[2], const float (*X_high)[40][2], + const float *g_filt, int m_max, intptr_t ixh); +void ff_sbr_hf_gen_sse(float (*X_high)[2], const float (*X_low)[2], + const float alpha0[2], const float alpha1[2], + float bw, int start, int end); +void ff_sbr_neg_odd_64_sse(float *z); +void ff_sbr_qmf_post_shuffle_sse(float W[32][2], const float *z); +void ff_sbr_qmf_deint_bfly_sse(float *v, const float *src0, const float *src1); +void ff_sbr_qmf_deint_bfly_sse2(float *v, const float *src0, const float *src1); +void ff_sbr_qmf_pre_shuffle_sse2(float *z); + +void ff_sbr_hf_apply_noise_0_sse2(float (*Y)[2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); +void ff_sbr_hf_apply_noise_1_sse2(float (*Y)[2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); +void ff_sbr_hf_apply_noise_2_sse2(float (*Y)[2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); +void ff_sbr_hf_apply_noise_3_sse2(float (*Y)[2], const float *s_m, + const float *q_filt, int noise, + int kx, int m_max); + +void ff_sbr_qmf_deint_neg_sse(float *v, const float *src); + +void ff_sbr_autocorrelate_sse (const float x[40][2], float phi[3][2][2]); +void ff_sbr_autocorrelate_sse3(const float x[40][2], float phi[3][2][2]); + +av_cold void ff_sbrdsp_init_x86(SBRDSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE(cpu_flags)) { + s->neg_odd_64 = ff_sbr_neg_odd_64_sse; + s->sum_square = ff_sbr_sum_square_sse; + s->sum64x5 = ff_sbr_sum64x5_sse; + s->hf_g_filt = ff_sbr_hf_g_filt_sse; + s->hf_gen = ff_sbr_hf_gen_sse; + s->qmf_post_shuffle = ff_sbr_qmf_post_shuffle_sse; + s->qmf_deint_bfly = ff_sbr_qmf_deint_bfly_sse; + s->qmf_deint_neg = ff_sbr_qmf_deint_neg_sse; + s->autocorrelate = ff_sbr_autocorrelate_sse; + } + + if (EXTERNAL_SSE2(cpu_flags)) { + s->qmf_deint_bfly = ff_sbr_qmf_deint_bfly_sse2; + s->qmf_pre_shuffle = ff_sbr_qmf_pre_shuffle_sse2; + s->hf_apply_noise[0] = ff_sbr_hf_apply_noise_0_sse2; + s->hf_apply_noise[1] = ff_sbr_hf_apply_noise_1_sse2; + s->hf_apply_noise[2] = ff_sbr_hf_apply_noise_2_sse2; + s->hf_apply_noise[3] = ff_sbr_hf_apply_noise_3_sse2; + } + + if (EXTERNAL_SSE3(cpu_flags)) { + s->autocorrelate = ff_sbr_autocorrelate_sse3; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/simple_idct.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/simple_idct.h new file mode 100644 index 0000000000..9b64cfe9bc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/simple_idct.h @@ -0,0 +1,53 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_SIMPLE_IDCT_H +#define AVCODEC_X86_SIMPLE_IDCT_H + +#include +#include + +void ff_simple_idct_mmx(int16_t *block); +void ff_simple_idct_add_mmx(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_put_mmx(uint8_t *dest, ptrdiff_t line_size, int16_t *block); + +void ff_simple_idct_add_sse2(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_put_sse2(uint8_t *dest, ptrdiff_t line_size, int16_t *block); + +void ff_simple_idct8_sse2(int16_t *block); +void ff_simple_idct8_avx(int16_t *block); + +void ff_simple_idct8_put_sse2(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct8_put_avx(uint8_t *dest, ptrdiff_t line_size, int16_t *block); + +void ff_simple_idct8_add_sse2(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct8_add_avx(uint8_t *dest, ptrdiff_t line_size, int16_t *block); + +void ff_simple_idct10_sse2(int16_t *block); +void ff_simple_idct10_avx(int16_t *block); + +void ff_simple_idct10_put_sse2(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct10_put_avx(uint8_t *dest, ptrdiff_t line_size, int16_t *block); + +void ff_simple_idct12_sse2(int16_t *block); +void ff_simple_idct12_avx(int16_t *block); + +void ff_simple_idct12_put_sse2(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct12_put_avx(uint8_t *dest, ptrdiff_t line_size, int16_t *block); + +#endif /* AVCODEC_X86_SIMPLE_IDCT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/snowdsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/snowdsp.c new file mode 100644 index 0000000000..218e6864db --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/snowdsp.c @@ -0,0 +1,908 @@ +/* + * MMX and SSE2 optimized snow DSP utils + * Copyright (c) 2005-2006 Robert Edele + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/snow.h" +#include "libavcodec/snow_dwt.h" + +#if HAVE_INLINE_ASM + +static void ff_snow_horizontal_compose97i_sse2(IDWTELEM *b, IDWTELEM *temp, int width){ + const int w2= (width+1)>>1; + const int w_l= (width>>1); + const int w_r= w2 - 1; + int i; + + { // Lift 0 + IDWTELEM * const ref = b + w2 - 1; + IDWTELEM b_0 = b[0]; //By allowing the first entry in b[0] to be calculated twice + // (the first time erroneously), we allow the SSE2 code to run an extra pass. + // The savings in code and time are well worth having to store this value and + // calculate b[0] correctly afterwards. + + i = 0; + __asm__ volatile( + "pcmpeqd %%xmm7, %%xmm7 \n\t" + "pcmpeqd %%xmm3, %%xmm3 \n\t" + "psllw $1, %%xmm3 \n\t" + "paddw %%xmm7, %%xmm3 \n\t" + "psllw $13, %%xmm3 \n\t" + ::); + for(; i>W_DS); + } + + { // Lift 1 + IDWTELEM * const dst = b+w2; + + i = 0; + for(; (((x86_reg)&dst[i]) & 0x1F) && i> W_BS); + } + + { // Lift 3 + IDWTELEM * const src = b+w2; + + i = 0; + for(; (((x86_reg)&temp[i]) & 0x1F) && i>W_AS); + } + for(; i>1]; + b[i] = b[i>>1]; + } + for (i-=62; i>=0; i-=64){ + __asm__ volatile( + "movdqa (%1), %%xmm0 \n\t" + "movdqa 16(%1), %%xmm2 \n\t" + "movdqa 32(%1), %%xmm4 \n\t" + "movdqa 48(%1), %%xmm6 \n\t" + "movdqa (%1), %%xmm1 \n\t" + "movdqa 16(%1), %%xmm3 \n\t" + "movdqa 32(%1), %%xmm5 \n\t" + "movdqa 48(%1), %%xmm7 \n\t" + "punpcklwd (%2), %%xmm0 \n\t" + "punpcklwd 16(%2), %%xmm2 \n\t" + "punpcklwd 32(%2), %%xmm4 \n\t" + "punpcklwd 48(%2), %%xmm6 \n\t" + "movdqa %%xmm0, (%0) \n\t" + "movdqa %%xmm2, 32(%0) \n\t" + "movdqa %%xmm4, 64(%0) \n\t" + "movdqa %%xmm6, 96(%0) \n\t" + "punpckhwd (%2), %%xmm1 \n\t" + "punpckhwd 16(%2), %%xmm3 \n\t" + "punpckhwd 32(%2), %%xmm5 \n\t" + "punpckhwd 48(%2), %%xmm7 \n\t" + "movdqa %%xmm1, 16(%0) \n\t" + "movdqa %%xmm3, 48(%0) \n\t" + "movdqa %%xmm5, 80(%0) \n\t" + "movdqa %%xmm7, 112(%0) \n\t" + :: "r"(&(b)[i]), "r"(&(b)[i>>1]), "r"(&(temp)[i>>1]) + : "memory" + ); + } + } +} + +static void ff_snow_horizontal_compose97i_mmx(IDWTELEM *b, IDWTELEM *temp, int width){ + const int w2= (width+1)>>1; + const int w_l= (width>>1); + const int w_r= w2 - 1; + int i; + + { // Lift 0 + IDWTELEM * const ref = b + w2 - 1; + + i = 1; + b[0] = b[0] - ((W_DM * 2 * ref[1]+W_DO)>>W_DS); + __asm__ volatile( + "pcmpeqw %%mm7, %%mm7 \n\t" + "pcmpeqw %%mm3, %%mm3 \n\t" + "psllw $1, %%mm3 \n\t" + "paddw %%mm7, %%mm3 \n\t" + "psllw $13, %%mm3 \n\t" + ::); + for(; i> W_BS); + __asm__ volatile( + "psllw $15, %%mm7 \n\t" + "pcmpeqw %%mm6, %%mm6 \n\t" + "psrlw $13, %%mm6 \n\t" + "paddw %%mm7, %%mm6 \n\t" + ::); + for(; i>1]; + b[i] = b[i>>1]; + } + for (i-=30; i>=0; i-=32){ + __asm__ volatile( + "movq (%1), %%mm0 \n\t" + "movq 8(%1), %%mm2 \n\t" + "movq 16(%1), %%mm4 \n\t" + "movq 24(%1), %%mm6 \n\t" + "movq (%1), %%mm1 \n\t" + "movq 8(%1), %%mm3 \n\t" + "movq 16(%1), %%mm5 \n\t" + "movq 24(%1), %%mm7 \n\t" + "punpcklwd (%2), %%mm0 \n\t" + "punpcklwd 8(%2), %%mm2 \n\t" + "punpcklwd 16(%2), %%mm4 \n\t" + "punpcklwd 24(%2), %%mm6 \n\t" + "movq %%mm0, (%0) \n\t" + "movq %%mm2, 16(%0) \n\t" + "movq %%mm4, 32(%0) \n\t" + "movq %%mm6, 48(%0) \n\t" + "punpckhwd (%2), %%mm1 \n\t" + "punpckhwd 8(%2), %%mm3 \n\t" + "punpckhwd 16(%2), %%mm5 \n\t" + "punpckhwd 24(%2), %%mm7 \n\t" + "movq %%mm1, 8(%0) \n\t" + "movq %%mm3, 24(%0) \n\t" + "movq %%mm5, 40(%0) \n\t" + "movq %%mm7, 56(%0) \n\t" + :: "r"(&b[i]), "r"(&b[i>>1]), "r"(&temp[i>>1]) + : "memory" + ); + } + } +} + +#if HAVE_7REGS +#define snow_vertical_compose_sse2_load_add(op,r,t0,t1,t2,t3)\ + ""op" ("r",%%"FF_REG_d"), %%"t0" \n\t"\ + ""op" 16("r",%%"FF_REG_d"), %%"t1" \n\t"\ + ""op" 32("r",%%"FF_REG_d"), %%"t2" \n\t"\ + ""op" 48("r",%%"FF_REG_d"), %%"t3" \n\t" + +#define snow_vertical_compose_sse2_load(r,t0,t1,t2,t3)\ + snow_vertical_compose_sse2_load_add("movdqa",r,t0,t1,t2,t3) + +#define snow_vertical_compose_sse2_add(r,t0,t1,t2,t3)\ + snow_vertical_compose_sse2_load_add("paddw",r,t0,t1,t2,t3) + +#define snow_vertical_compose_r2r_sub(s0,s1,s2,s3,t0,t1,t2,t3)\ + "psubw %%"s0", %%"t0" \n\t"\ + "psubw %%"s1", %%"t1" \n\t"\ + "psubw %%"s2", %%"t2" \n\t"\ + "psubw %%"s3", %%"t3" \n\t" + +#define snow_vertical_compose_sse2_store(w,s0,s1,s2,s3)\ + "movdqa %%"s0", ("w",%%"FF_REG_d") \n\t"\ + "movdqa %%"s1", 16("w",%%"FF_REG_d") \n\t"\ + "movdqa %%"s2", 32("w",%%"FF_REG_d") \n\t"\ + "movdqa %%"s3", 48("w",%%"FF_REG_d") \n\t" + +#define snow_vertical_compose_sra(n,t0,t1,t2,t3)\ + "psraw $"n", %%"t0" \n\t"\ + "psraw $"n", %%"t1" \n\t"\ + "psraw $"n", %%"t2" \n\t"\ + "psraw $"n", %%"t3" \n\t" + +#define snow_vertical_compose_r2r_add(s0,s1,s2,s3,t0,t1,t2,t3)\ + "paddw %%"s0", %%"t0" \n\t"\ + "paddw %%"s1", %%"t1" \n\t"\ + "paddw %%"s2", %%"t2" \n\t"\ + "paddw %%"s3", %%"t3" \n\t" + +#define snow_vertical_compose_r2r_pmulhw(s0,s1,s2,s3,t0,t1,t2,t3)\ + "pmulhw %%"s0", %%"t0" \n\t"\ + "pmulhw %%"s1", %%"t1" \n\t"\ + "pmulhw %%"s2", %%"t2" \n\t"\ + "pmulhw %%"s3", %%"t3" \n\t" + +#define snow_vertical_compose_sse2_move(s0,s1,s2,s3,t0,t1,t2,t3)\ + "movdqa %%"s0", %%"t0" \n\t"\ + "movdqa %%"s1", %%"t1" \n\t"\ + "movdqa %%"s2", %%"t2" \n\t"\ + "movdqa %%"s3", %%"t3" \n\t" + +static void ff_snow_vertical_compose97i_sse2(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5, int width){ + x86_reg i = width; + + while(i & 0x1F) + { + i--; + b4[i] -= (W_DM*(b3[i] + b5[i])+W_DO)>>W_DS; + b3[i] -= (W_CM*(b2[i] + b4[i])+W_CO)>>W_CS; + b2[i] += (W_BM*(b1[i] + b3[i])+4*b2[i]+W_BO)>>W_BS; + b1[i] += (W_AM*(b0[i] + b2[i])+W_AO)>>W_AS; + } + i+=i; + + __asm__ volatile ( + "jmp 2f \n\t" + "1: \n\t" + snow_vertical_compose_sse2_load("%4","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sse2_add("%6","xmm0","xmm2","xmm4","xmm6") + + + "pcmpeqw %%xmm0, %%xmm0 \n\t" + "pcmpeqw %%xmm2, %%xmm2 \n\t" + "paddw %%xmm2, %%xmm2 \n\t" + "paddw %%xmm0, %%xmm2 \n\t" + "psllw $13, %%xmm2 \n\t" + snow_vertical_compose_r2r_add("xmm0","xmm0","xmm0","xmm0","xmm1","xmm3","xmm5","xmm7") + snow_vertical_compose_r2r_pmulhw("xmm2","xmm2","xmm2","xmm2","xmm1","xmm3","xmm5","xmm7") + snow_vertical_compose_sse2_add("%5","xmm1","xmm3","xmm5","xmm7") + snow_vertical_compose_sse2_store("%5","xmm1","xmm3","xmm5","xmm7") + snow_vertical_compose_sse2_load("%4","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sse2_add("%3","xmm1","xmm3","xmm5","xmm7") + snow_vertical_compose_r2r_sub("xmm1","xmm3","xmm5","xmm7","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sse2_store("%4","xmm0","xmm2","xmm4","xmm6") + + "pcmpeqw %%xmm7, %%xmm7 \n\t" + "pcmpeqw %%xmm5, %%xmm5 \n\t" + "psllw $15, %%xmm7 \n\t" + "psrlw $13, %%xmm5 \n\t" + "paddw %%xmm7, %%xmm5 \n\t" + snow_vertical_compose_r2r_add("xmm5","xmm5","xmm5","xmm5","xmm0","xmm2","xmm4","xmm6") + "movq (%2,%%"FF_REG_d"), %%xmm1 \n\t" + "movq 8(%2,%%"FF_REG_d"), %%xmm3 \n\t" + "paddw %%xmm7, %%xmm1 \n\t" + "paddw %%xmm7, %%xmm3 \n\t" + "pavgw %%xmm1, %%xmm0 \n\t" + "pavgw %%xmm3, %%xmm2 \n\t" + "movq 16(%2,%%"FF_REG_d"), %%xmm1 \n\t" + "movq 24(%2,%%"FF_REG_d"), %%xmm3 \n\t" + "paddw %%xmm7, %%xmm1 \n\t" + "paddw %%xmm7, %%xmm3 \n\t" + "pavgw %%xmm1, %%xmm4 \n\t" + "pavgw %%xmm3, %%xmm6 \n\t" + snow_vertical_compose_r2r_sub("xmm7","xmm7","xmm7","xmm7","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sra("1","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sse2_add("%3","xmm0","xmm2","xmm4","xmm6") + + snow_vertical_compose_sra("2","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sse2_add("%3","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sse2_store("%3","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sse2_add("%1","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sse2_move("xmm0","xmm2","xmm4","xmm6","xmm1","xmm3","xmm5","xmm7") + snow_vertical_compose_sra("1","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_r2r_add("xmm1","xmm3","xmm5","xmm7","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sse2_add("%2","xmm0","xmm2","xmm4","xmm6") + snow_vertical_compose_sse2_store("%2","xmm0","xmm2","xmm4","xmm6") + + "2: \n\t" + "sub $64, %%"FF_REG_d" \n\t" + "jge 1b \n\t" + :"+d"(i) + :"r"(b0),"r"(b1),"r"(b2),"r"(b3),"r"(b4),"r"(b5)); +} + +#define snow_vertical_compose_mmx_load_add(op,r,t0,t1,t2,t3)\ + ""op" ("r",%%"FF_REG_d"), %%"t0" \n\t"\ + ""op" 8("r",%%"FF_REG_d"), %%"t1" \n\t"\ + ""op" 16("r",%%"FF_REG_d"), %%"t2" \n\t"\ + ""op" 24("r",%%"FF_REG_d"), %%"t3" \n\t" + +#define snow_vertical_compose_mmx_load(r,t0,t1,t2,t3)\ + snow_vertical_compose_mmx_load_add("movq",r,t0,t1,t2,t3) + +#define snow_vertical_compose_mmx_add(r,t0,t1,t2,t3)\ + snow_vertical_compose_mmx_load_add("paddw",r,t0,t1,t2,t3) + +#define snow_vertical_compose_mmx_store(w,s0,s1,s2,s3)\ + "movq %%"s0", ("w",%%"FF_REG_d") \n\t"\ + "movq %%"s1", 8("w",%%"FF_REG_d") \n\t"\ + "movq %%"s2", 16("w",%%"FF_REG_d") \n\t"\ + "movq %%"s3", 24("w",%%"FF_REG_d") \n\t" + +#define snow_vertical_compose_mmx_move(s0,s1,s2,s3,t0,t1,t2,t3)\ + "movq %%"s0", %%"t0" \n\t"\ + "movq %%"s1", %%"t1" \n\t"\ + "movq %%"s2", %%"t2" \n\t"\ + "movq %%"s3", %%"t3" \n\t" + + +static void ff_snow_vertical_compose97i_mmx(IDWTELEM *b0, IDWTELEM *b1, IDWTELEM *b2, IDWTELEM *b3, IDWTELEM *b4, IDWTELEM *b5, int width){ + x86_reg i = width; + while(i & 15) + { + i--; + b4[i] -= (W_DM*(b3[i] + b5[i])+W_DO)>>W_DS; + b3[i] -= (W_CM*(b2[i] + b4[i])+W_CO)>>W_CS; + b2[i] += (W_BM*(b1[i] + b3[i])+4*b2[i]+W_BO)>>W_BS; + b1[i] += (W_AM*(b0[i] + b2[i])+W_AO)>>W_AS; + } + i+=i; + __asm__ volatile( + "jmp 2f \n\t" + "1: \n\t" + + snow_vertical_compose_mmx_load("%4","mm1","mm3","mm5","mm7") + snow_vertical_compose_mmx_add("%6","mm1","mm3","mm5","mm7") + "pcmpeqw %%mm0, %%mm0 \n\t" + "pcmpeqw %%mm2, %%mm2 \n\t" + "paddw %%mm2, %%mm2 \n\t" + "paddw %%mm0, %%mm2 \n\t" + "psllw $13, %%mm2 \n\t" + snow_vertical_compose_r2r_add("mm0","mm0","mm0","mm0","mm1","mm3","mm5","mm7") + snow_vertical_compose_r2r_pmulhw("mm2","mm2","mm2","mm2","mm1","mm3","mm5","mm7") + snow_vertical_compose_mmx_add("%5","mm1","mm3","mm5","mm7") + snow_vertical_compose_mmx_store("%5","mm1","mm3","mm5","mm7") + snow_vertical_compose_mmx_load("%4","mm0","mm2","mm4","mm6") + snow_vertical_compose_mmx_add("%3","mm1","mm3","mm5","mm7") + snow_vertical_compose_r2r_sub("mm1","mm3","mm5","mm7","mm0","mm2","mm4","mm6") + snow_vertical_compose_mmx_store("%4","mm0","mm2","mm4","mm6") + "pcmpeqw %%mm7, %%mm7 \n\t" + "pcmpeqw %%mm5, %%mm5 \n\t" + "psllw $15, %%mm7 \n\t" + "psrlw $13, %%mm5 \n\t" + "paddw %%mm7, %%mm5 \n\t" + snow_vertical_compose_r2r_add("mm5","mm5","mm5","mm5","mm0","mm2","mm4","mm6") + "movq (%2,%%"FF_REG_d"), %%mm1 \n\t" + "movq 8(%2,%%"FF_REG_d"), %%mm3 \n\t" + "paddw %%mm7, %%mm1 \n\t" + "paddw %%mm7, %%mm3 \n\t" + "pavgw %%mm1, %%mm0 \n\t" + "pavgw %%mm3, %%mm2 \n\t" + "movq 16(%2,%%"FF_REG_d"), %%mm1 \n\t" + "movq 24(%2,%%"FF_REG_d"), %%mm3 \n\t" + "paddw %%mm7, %%mm1 \n\t" + "paddw %%mm7, %%mm3 \n\t" + "pavgw %%mm1, %%mm4 \n\t" + "pavgw %%mm3, %%mm6 \n\t" + snow_vertical_compose_r2r_sub("mm7","mm7","mm7","mm7","mm0","mm2","mm4","mm6") + snow_vertical_compose_sra("1","mm0","mm2","mm4","mm6") + snow_vertical_compose_mmx_add("%3","mm0","mm2","mm4","mm6") + + snow_vertical_compose_sra("2","mm0","mm2","mm4","mm6") + snow_vertical_compose_mmx_add("%3","mm0","mm2","mm4","mm6") + snow_vertical_compose_mmx_store("%3","mm0","mm2","mm4","mm6") + snow_vertical_compose_mmx_add("%1","mm0","mm2","mm4","mm6") + snow_vertical_compose_mmx_move("mm0","mm2","mm4","mm6","mm1","mm3","mm5","mm7") + snow_vertical_compose_sra("1","mm0","mm2","mm4","mm6") + snow_vertical_compose_r2r_add("mm1","mm3","mm5","mm7","mm0","mm2","mm4","mm6") + snow_vertical_compose_mmx_add("%2","mm0","mm2","mm4","mm6") + snow_vertical_compose_mmx_store("%2","mm0","mm2","mm4","mm6") + + "2: \n\t" + "sub $32, %%"FF_REG_d" \n\t" + "jge 1b \n\t" + :"+d"(i) + :"r"(b0),"r"(b1),"r"(b2),"r"(b3),"r"(b4),"r"(b5)); +} +#endif //HAVE_7REGS + +#if HAVE_6REGS +#define snow_inner_add_yblock_sse2_header \ + IDWTELEM * * dst_array = sb->line + src_y;\ + x86_reg tmp;\ + __asm__ volatile(\ + "mov %7, %%"FF_REG_c" \n\t"\ + "mov %6, %2 \n\t"\ + "mov %4, %%"FF_REG_S" \n\t"\ + "pxor %%xmm7, %%xmm7 \n\t" /* 0 */\ + "pcmpeqd %%xmm3, %%xmm3 \n\t"\ + "psllw $15, %%xmm3 \n\t"\ + "psrlw $12, %%xmm3 \n\t" /* FRAC_BITS >> 1 */\ + "1: \n\t"\ + "mov %1, %%"FF_REG_D" \n\t"\ + "mov (%%"FF_REG_D"), %%"FF_REG_D" \n\t"\ + "add %3, %%"FF_REG_D" \n\t" + +#define snow_inner_add_yblock_sse2_start_8(out_reg1, out_reg2, ptr_offset, s_offset)\ + "mov "FF_PTR_SIZE"*"ptr_offset"(%%"FF_REG_a"), %%"FF_REG_d"; \n\t"\ + "movq (%%"FF_REG_d"), %%"out_reg1" \n\t"\ + "movq (%%"FF_REG_d", %%"FF_REG_c"), %%"out_reg2" \n\t"\ + "punpcklbw %%xmm7, %%"out_reg1" \n\t"\ + "punpcklbw %%xmm7, %%"out_reg2" \n\t"\ + "movq "s_offset"(%%"FF_REG_S"), %%xmm0 \n\t"\ + "movq "s_offset"+16(%%"FF_REG_S"), %%xmm4 \n\t"\ + "punpcklbw %%xmm7, %%xmm0 \n\t"\ + "punpcklbw %%xmm7, %%xmm4 \n\t"\ + "pmullw %%xmm0, %%"out_reg1" \n\t"\ + "pmullw %%xmm4, %%"out_reg2" \n\t" + +#define snow_inner_add_yblock_sse2_start_16(out_reg1, out_reg2, ptr_offset, s_offset)\ + "mov "FF_PTR_SIZE"*"ptr_offset"(%%"FF_REG_a"), %%"FF_REG_d"; \n\t"\ + "movq (%%"FF_REG_d"), %%"out_reg1" \n\t"\ + "movq 8(%%"FF_REG_d"), %%"out_reg2" \n\t"\ + "punpcklbw %%xmm7, %%"out_reg1" \n\t"\ + "punpcklbw %%xmm7, %%"out_reg2" \n\t"\ + "movq "s_offset"(%%"FF_REG_S"), %%xmm0 \n\t"\ + "movq "s_offset"+8(%%"FF_REG_S"), %%xmm4 \n\t"\ + "punpcklbw %%xmm7, %%xmm0 \n\t"\ + "punpcklbw %%xmm7, %%xmm4 \n\t"\ + "pmullw %%xmm0, %%"out_reg1" \n\t"\ + "pmullw %%xmm4, %%"out_reg2" \n\t" + +#define snow_inner_add_yblock_sse2_accum_8(ptr_offset, s_offset) \ + snow_inner_add_yblock_sse2_start_8("xmm2", "xmm6", ptr_offset, s_offset)\ + "paddusw %%xmm2, %%xmm1 \n\t"\ + "paddusw %%xmm6, %%xmm5 \n\t" + +#define snow_inner_add_yblock_sse2_accum_16(ptr_offset, s_offset) \ + snow_inner_add_yblock_sse2_start_16("xmm2", "xmm6", ptr_offset, s_offset)\ + "paddusw %%xmm2, %%xmm1 \n\t"\ + "paddusw %%xmm6, %%xmm5 \n\t" + +#define snow_inner_add_yblock_sse2_end_common1\ + "add $32, %%"FF_REG_S" \n\t"\ + "add %%"FF_REG_c", %0 \n\t"\ + "add %%"FF_REG_c", "FF_PTR_SIZE"*3(%%"FF_REG_a"); \n\t"\ + "add %%"FF_REG_c", "FF_PTR_SIZE"*2(%%"FF_REG_a"); \n\t"\ + "add %%"FF_REG_c", "FF_PTR_SIZE"*1(%%"FF_REG_a"); \n\t"\ + "add %%"FF_REG_c", (%%"FF_REG_a") \n\t" + +#define snow_inner_add_yblock_sse2_end_common2\ + "jnz 1b \n\t"\ + :"+m"(dst8),"+m"(dst_array),"=&r"(tmp)\ + :\ + "rm"((x86_reg)(src_x<<1)),"m"(obmc),"a"(block),"m"(b_h),"m"(src_stride):\ + XMM_CLOBBERS("%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", )\ + "%"FF_REG_c"","%"FF_REG_S"","%"FF_REG_D"","%"FF_REG_d""); + +#define snow_inner_add_yblock_sse2_end_8\ + "sal $1, %%"FF_REG_c" \n\t"\ + "add"FF_OPSIZE" $"FF_PTR_SIZE"*2, %1 \n\t"\ + snow_inner_add_yblock_sse2_end_common1\ + "sar $1, %%"FF_REG_c" \n\t"\ + "sub $2, %2 \n\t"\ + snow_inner_add_yblock_sse2_end_common2 + +#define snow_inner_add_yblock_sse2_end_16\ + "add"FF_OPSIZE" $"FF_PTR_SIZE"*1, %1 \n\t"\ + snow_inner_add_yblock_sse2_end_common1\ + "dec %2 \n\t"\ + snow_inner_add_yblock_sse2_end_common2 + +static void inner_add_yblock_bw_8_obmc_16_bh_even_sse2(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h, + int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){ +snow_inner_add_yblock_sse2_header +snow_inner_add_yblock_sse2_start_8("xmm1", "xmm5", "3", "0") +snow_inner_add_yblock_sse2_accum_8("2", "8") +snow_inner_add_yblock_sse2_accum_8("1", "128") +snow_inner_add_yblock_sse2_accum_8("0", "136") + + "mov %0, %%"FF_REG_d" \n\t" + "movdqa (%%"FF_REG_D"), %%xmm0 \n\t" + "movdqa %%xmm1, %%xmm2 \n\t" + + "punpckhwd %%xmm7, %%xmm1 \n\t" + "punpcklwd %%xmm7, %%xmm2 \n\t" + "paddd %%xmm2, %%xmm0 \n\t" + "movdqa 16(%%"FF_REG_D"), %%xmm2\n\t" + "paddd %%xmm1, %%xmm2 \n\t" + "paddd %%xmm3, %%xmm0 \n\t" + "paddd %%xmm3, %%xmm2 \n\t" + + "mov %1, %%"FF_REG_D" \n\t" + "mov "FF_PTR_SIZE"(%%"FF_REG_D"), %%"FF_REG_D"; \n\t" + "add %3, %%"FF_REG_D" \n\t" + + "movdqa (%%"FF_REG_D"), %%xmm4 \n\t" + "movdqa %%xmm5, %%xmm6 \n\t" + "punpckhwd %%xmm7, %%xmm5 \n\t" + "punpcklwd %%xmm7, %%xmm6 \n\t" + "paddd %%xmm6, %%xmm4 \n\t" + "movdqa 16(%%"FF_REG_D"), %%xmm6\n\t" + "paddd %%xmm5, %%xmm6 \n\t" + "paddd %%xmm3, %%xmm4 \n\t" + "paddd %%xmm3, %%xmm6 \n\t" + + "psrad $8, %%xmm0 \n\t" /* FRAC_BITS. */ + "psrad $8, %%xmm2 \n\t" /* FRAC_BITS. */ + "packssdw %%xmm2, %%xmm0 \n\t" + "packuswb %%xmm7, %%xmm0 \n\t" + "movq %%xmm0, (%%"FF_REG_d") \n\t" + + "psrad $8, %%xmm4 \n\t" /* FRAC_BITS. */ + "psrad $8, %%xmm6 \n\t" /* FRAC_BITS. */ + "packssdw %%xmm6, %%xmm4 \n\t" + "packuswb %%xmm7, %%xmm4 \n\t" + "movq %%xmm4, (%%"FF_REG_d",%%"FF_REG_c"); \n\t" +snow_inner_add_yblock_sse2_end_8 +} + +static void inner_add_yblock_bw_16_obmc_32_sse2(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h, + int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){ +snow_inner_add_yblock_sse2_header +snow_inner_add_yblock_sse2_start_16("xmm1", "xmm5", "3", "0") +snow_inner_add_yblock_sse2_accum_16("2", "16") +snow_inner_add_yblock_sse2_accum_16("1", "512") +snow_inner_add_yblock_sse2_accum_16("0", "528") + + "mov %0, %%"FF_REG_d" \n\t" + "psrlw $4, %%xmm1 \n\t" + "psrlw $4, %%xmm5 \n\t" + "paddw (%%"FF_REG_D"), %%xmm1 \n\t" + "paddw 16(%%"FF_REG_D"), %%xmm5 \n\t" + "paddw %%xmm3, %%xmm1 \n\t" + "paddw %%xmm3, %%xmm5 \n\t" + "psraw $4, %%xmm1 \n\t" /* FRAC_BITS. */ + "psraw $4, %%xmm5 \n\t" /* FRAC_BITS. */ + "packuswb %%xmm5, %%xmm1 \n\t" + + "movdqu %%xmm1, (%%"FF_REG_d") \n\t" + +snow_inner_add_yblock_sse2_end_16 +} + +#define snow_inner_add_yblock_mmx_header \ + IDWTELEM * * dst_array = sb->line + src_y;\ + x86_reg tmp;\ + __asm__ volatile(\ + "mov %7, %%"FF_REG_c" \n\t"\ + "mov %6, %2 \n\t"\ + "mov %4, %%"FF_REG_S" \n\t"\ + "pxor %%mm7, %%mm7 \n\t" /* 0 */\ + "pcmpeqd %%mm3, %%mm3 \n\t"\ + "psllw $15, %%mm3 \n\t"\ + "psrlw $12, %%mm3 \n\t" /* FRAC_BITS >> 1 */\ + "1: \n\t"\ + "mov %1, %%"FF_REG_D" \n\t"\ + "mov (%%"FF_REG_D"), %%"FF_REG_D" \n\t"\ + "add %3, %%"FF_REG_D" \n\t" + +#define snow_inner_add_yblock_mmx_start(out_reg1, out_reg2, ptr_offset, s_offset, d_offset)\ + "mov "FF_PTR_SIZE"*"ptr_offset"(%%"FF_REG_a"), %%"FF_REG_d"; \n\t"\ + "movd "d_offset"(%%"FF_REG_d"), %%"out_reg1" \n\t"\ + "movd "d_offset"+4(%%"FF_REG_d"), %%"out_reg2" \n\t"\ + "punpcklbw %%mm7, %%"out_reg1" \n\t"\ + "punpcklbw %%mm7, %%"out_reg2" \n\t"\ + "movd "s_offset"(%%"FF_REG_S"), %%mm0 \n\t"\ + "movd "s_offset"+4(%%"FF_REG_S"), %%mm4 \n\t"\ + "punpcklbw %%mm7, %%mm0 \n\t"\ + "punpcklbw %%mm7, %%mm4 \n\t"\ + "pmullw %%mm0, %%"out_reg1" \n\t"\ + "pmullw %%mm4, %%"out_reg2" \n\t" + +#define snow_inner_add_yblock_mmx_accum(ptr_offset, s_offset, d_offset) \ + snow_inner_add_yblock_mmx_start("mm2", "mm6", ptr_offset, s_offset, d_offset)\ + "paddusw %%mm2, %%mm1 \n\t"\ + "paddusw %%mm6, %%mm5 \n\t" + +#define snow_inner_add_yblock_mmx_mix(read_offset, write_offset)\ + "mov %0, %%"FF_REG_d" \n\t"\ + "psrlw $4, %%mm1 \n\t"\ + "psrlw $4, %%mm5 \n\t"\ + "paddw "read_offset"(%%"FF_REG_D"), %%mm1 \n\t"\ + "paddw "read_offset"+8(%%"FF_REG_D"), %%mm5 \n\t"\ + "paddw %%mm3, %%mm1 \n\t"\ + "paddw %%mm3, %%mm5 \n\t"\ + "psraw $4, %%mm1 \n\t"\ + "psraw $4, %%mm5 \n\t"\ + "packuswb %%mm5, %%mm1 \n\t"\ + "movq %%mm1, "write_offset"(%%"FF_REG_d") \n\t" + +#define snow_inner_add_yblock_mmx_end(s_step)\ + "add $"s_step", %%"FF_REG_S" \n\t"\ + "add %%"FF_REG_c", "FF_PTR_SIZE"*3(%%"FF_REG_a"); \n\t"\ + "add %%"FF_REG_c", "FF_PTR_SIZE"*2(%%"FF_REG_a"); \n\t"\ + "add %%"FF_REG_c", "FF_PTR_SIZE"*1(%%"FF_REG_a"); \n\t"\ + "add %%"FF_REG_c", (%%"FF_REG_a") \n\t"\ + "add"FF_OPSIZE " $"FF_PTR_SIZE"*1, %1 \n\t"\ + "add %%"FF_REG_c", %0 \n\t"\ + "dec %2 \n\t"\ + "jnz 1b \n\t"\ + :"+m"(dst8),"+m"(dst_array),"=&r"(tmp)\ + :\ + "rm"((x86_reg)(src_x<<1)),"m"(obmc),"a"(block),"m"(b_h),"m"(src_stride):\ + "%"FF_REG_c"","%"FF_REG_S"","%"FF_REG_D"","%"FF_REG_d""); + +static void inner_add_yblock_bw_8_obmc_16_mmx(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h, + int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){ +snow_inner_add_yblock_mmx_header +snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "0", "0") +snow_inner_add_yblock_mmx_accum("2", "8", "0") +snow_inner_add_yblock_mmx_accum("1", "128", "0") +snow_inner_add_yblock_mmx_accum("0", "136", "0") +snow_inner_add_yblock_mmx_mix("0", "0") +snow_inner_add_yblock_mmx_end("16") +} + +static void inner_add_yblock_bw_16_obmc_32_mmx(const uint8_t *obmc, const x86_reg obmc_stride, uint8_t * * block, int b_w, x86_reg b_h, + int src_x, int src_y, x86_reg src_stride, slice_buffer * sb, int add, uint8_t * dst8){ +snow_inner_add_yblock_mmx_header +snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "0", "0") +snow_inner_add_yblock_mmx_accum("2", "16", "0") +snow_inner_add_yblock_mmx_accum("1", "512", "0") +snow_inner_add_yblock_mmx_accum("0", "528", "0") +snow_inner_add_yblock_mmx_mix("0", "0") + +snow_inner_add_yblock_mmx_start("mm1", "mm5", "3", "8", "8") +snow_inner_add_yblock_mmx_accum("2", "24", "8") +snow_inner_add_yblock_mmx_accum("1", "520", "8") +snow_inner_add_yblock_mmx_accum("0", "536", "8") +snow_inner_add_yblock_mmx_mix("16", "8") +snow_inner_add_yblock_mmx_end("32") +} + +static void ff_snow_inner_add_yblock_sse2(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h, + int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){ + + if (b_w == 16) + inner_add_yblock_bw_16_obmc_32_sse2(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8); + else if (b_w == 8 && obmc_stride == 16) { + if (!(b_h & 1)) + inner_add_yblock_bw_8_obmc_16_bh_even_sse2(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8); + else + inner_add_yblock_bw_8_obmc_16_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8); + } else + ff_snow_inner_add_yblock(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8); +} + +static void ff_snow_inner_add_yblock_mmx(const uint8_t *obmc, const int obmc_stride, uint8_t * * block, int b_w, int b_h, + int src_x, int src_y, int src_stride, slice_buffer * sb, int add, uint8_t * dst8){ + if (b_w == 16) + inner_add_yblock_bw_16_obmc_32_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8); + else if (b_w == 8 && obmc_stride == 16) + inner_add_yblock_bw_8_obmc_16_mmx(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8); + else + ff_snow_inner_add_yblock(obmc, obmc_stride, block, b_w, b_h, src_x,src_y, src_stride, sb, add, dst8); +} +#endif /* HAVE_6REGS */ + +#endif /* HAVE_INLINE_ASM */ + +av_cold void ff_dwt_init_x86(SnowDWTContext *c) +{ +#if HAVE_INLINE_ASM + int mm_flags = av_get_cpu_flags(); + + if (mm_flags & AV_CPU_FLAG_MMX) { + if(mm_flags & AV_CPU_FLAG_SSE2 & 0){ + c->horizontal_compose97i = ff_snow_horizontal_compose97i_sse2; +#if HAVE_7REGS + c->vertical_compose97i = ff_snow_vertical_compose97i_sse2; +#endif +#if HAVE_6REGS + c->inner_add_yblock = ff_snow_inner_add_yblock_sse2; +#endif + } + else{ + if (mm_flags & AV_CPU_FLAG_MMXEXT) { + c->horizontal_compose97i = ff_snow_horizontal_compose97i_mmx; +#if HAVE_7REGS + c->vertical_compose97i = ff_snow_vertical_compose97i_mmx; +#endif + } +#if HAVE_6REGS + c->inner_add_yblock = ff_snow_inner_add_yblock_mmx; +#endif + } + } +#endif /* HAVE_INLINE_ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/svq1enc_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/svq1enc_init.c new file mode 100644 index 0000000000..40b4b0e183 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/svq1enc_init.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2007 Loren Merritt + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/svq1enc.h" + +int ff_ssd_int8_vs_int16_mmx(const int8_t *pix1, const int16_t *pix2, + intptr_t size); +int ff_ssd_int8_vs_int16_sse2(const int8_t *pix1, const int16_t *pix2, + intptr_t size); + +av_cold void ff_svq1enc_init_x86(SVQ1EncContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + c->ssd_int8_vs_int16 = ff_ssd_int8_vs_int16_mmx; + } + if (EXTERNAL_SSE2(cpu_flags)) { + c->ssd_int8_vs_int16 = ff_ssd_int8_vs_int16_sse2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/synth_filter_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/synth_filter_init.c new file mode 100644 index 0000000000..35e2b47a3e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/synth_filter_init.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2012-2014 Christophe Gisquet + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/synth_filter.h" + +#define SYNTH_FILTER_FUNC(opt) \ +void ff_synth_filter_inner_##opt(float *synth_buf_ptr, float synth_buf2[32], \ + const float window[512], \ + float out[32], intptr_t offset, float scale); \ +static void synth_filter_##opt(FFTContext *imdct, \ + float *synth_buf_ptr, int *synth_buf_offset, \ + float synth_buf2[32], const float window[512], \ + float out[32], const float in[32], float scale) \ +{ \ + float *synth_buf= synth_buf_ptr + *synth_buf_offset; \ + \ + imdct->imdct_half(imdct, synth_buf, in); \ + \ + ff_synth_filter_inner_##opt(synth_buf, synth_buf2, window, \ + out, *synth_buf_offset, scale); \ + \ + *synth_buf_offset = (*synth_buf_offset - 32) & 511; \ +} \ + +#if HAVE_X86ASM +#if ARCH_X86_32 +SYNTH_FILTER_FUNC(sse) +#endif +SYNTH_FILTER_FUNC(sse2) +SYNTH_FILTER_FUNC(avx) +SYNTH_FILTER_FUNC(fma3) +#endif /* HAVE_X86ASM */ + +av_cold void ff_synth_filter_init_x86(SynthFilterContext *s) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + +#if ARCH_X86_32 + if (EXTERNAL_SSE(cpu_flags)) { + s->synth_filter_float = synth_filter_sse; + } +#endif + if (EXTERNAL_SSE2(cpu_flags)) { + s->synth_filter_float = synth_filter_sse2; + } + if (EXTERNAL_AVX_FAST(cpu_flags)) { + s->synth_filter_float = synth_filter_avx; + } + if (EXTERNAL_FMA3_FAST(cpu_flags)) { + s->synth_filter_float = synth_filter_fma3; + } +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/takdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/takdsp_init.c new file mode 100644 index 0000000000..fe0c846afd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/takdsp_init.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/takdsp.h" +#include "libavutil/x86/cpu.h" +#include "config.h" + +void ff_tak_decorrelate_ls_sse2(int32_t *p1, int32_t *p2, int length); +void ff_tak_decorrelate_sr_sse2(int32_t *p1, int32_t *p2, int length); +void ff_tak_decorrelate_sm_sse2(int32_t *p1, int32_t *p2, int length); +void ff_tak_decorrelate_sf_sse4(int32_t *p1, int32_t *p2, int length, int dshift, int dfactor); + +av_cold void ff_takdsp_init_x86(TAKDSPContext *c) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE2(cpu_flags)) { + c->decorrelate_ls = ff_tak_decorrelate_ls_sse2; + c->decorrelate_sr = ff_tak_decorrelate_sr_sse2; + c->decorrelate_sm = ff_tak_decorrelate_sm_sse2; + } + + if (EXTERNAL_SSE4(cpu_flags)) { + c->decorrelate_sf = ff_tak_decorrelate_sf_sse4; + } +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ttadsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ttadsp_init.c new file mode 100644 index 0000000000..7441c97769 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ttadsp_init.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/ttadsp.h" +#include "libavutil/x86/cpu.h" +#include "config.h" + +void ff_tta_filter_process_ssse3(int32_t *qm, int32_t *dx, int32_t *dl, + int32_t *error, int32_t *in, int32_t shift, + int32_t round); +void ff_tta_filter_process_sse4(int32_t *qm, int32_t *dx, int32_t *dl, + int32_t *error, int32_t *in, int32_t shift, + int32_t round); + +av_cold void ff_ttadsp_init_x86(TTADSPContext *c) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSSE3(cpu_flags)) + c->filter_process = ff_tta_filter_process_ssse3; + if (EXTERNAL_SSE4(cpu_flags)) + c->filter_process = ff_tta_filter_process_sse4; +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ttaencdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ttaencdsp_init.c new file mode 100644 index 0000000000..61971a4282 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/ttaencdsp_init.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014-2016 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/ttaencdsp.h" +#include "libavutil/x86/cpu.h" +#include "config.h" + +void ff_ttaenc_filter_process_ssse3(int32_t *qm, int32_t *dx, int32_t *dl, + int32_t *error, int32_t *in, int32_t shift, + int32_t round); +void ff_ttaenc_filter_process_sse4(int32_t *qm, int32_t *dx, int32_t *dl, + int32_t *error, int32_t *in, int32_t shift, + int32_t round); + +av_cold void ff_ttaencdsp_init_x86(TTAEncDSPContext *c) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSSE3(cpu_flags)) + c->filter_process = ff_ttaenc_filter_process_ssse3; + if (EXTERNAL_SSE4(cpu_flags)) + c->filter_process = ff_ttaenc_filter_process_sse4; +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/utvideodsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/utvideodsp_init.c new file mode 100644 index 0000000000..2b436c6c5c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/utvideodsp_init.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/utvideodsp.h" + +void ff_restore_rgb_planes_sse2(uint8_t *src_r, uint8_t *src_g, uint8_t *src_b, + ptrdiff_t linesize_r, ptrdiff_t linesize_g, + ptrdiff_t linesize_b, int width, int height); +void ff_restore_rgb_planes_avx2(uint8_t *src_r, uint8_t *src_g, uint8_t *src_b, + ptrdiff_t linesize_r, ptrdiff_t linesize_g, + ptrdiff_t linesize_b, int width, int height); + +void ff_restore_rgb_planes10_sse2(uint16_t *src_r, uint16_t *src_g, uint16_t *src_b, + ptrdiff_t linesize_r, ptrdiff_t linesize_g, + ptrdiff_t linesize_b, int width, int height); +void ff_restore_rgb_planes10_avx2(uint16_t *src_r, uint16_t *src_g, uint16_t *src_b, + ptrdiff_t linesize_r, ptrdiff_t linesize_g, + ptrdiff_t linesize_b, int width, int height); + +av_cold void ff_utvideodsp_init_x86(UTVideoDSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE2(cpu_flags)) { + c->restore_rgb_planes = ff_restore_rgb_planes_sse2; + c->restore_rgb_planes10 = ff_restore_rgb_planes10_sse2; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->restore_rgb_planes = ff_restore_rgb_planes_avx2; + c->restore_rgb_planes10 = ff_restore_rgb_planes10_avx2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/v210-init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/v210-init.c new file mode 100644 index 0000000000..cb9a6cbd6a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/v210-init.c @@ -0,0 +1,56 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/cpu.h" +#include "libavcodec/v210dec.h" + +extern void ff_v210_planar_unpack_unaligned_ssse3(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); +extern void ff_v210_planar_unpack_unaligned_avx(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); +extern void ff_v210_planar_unpack_unaligned_avx2(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); + +extern void ff_v210_planar_unpack_aligned_ssse3(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); +extern void ff_v210_planar_unpack_aligned_avx(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); +extern void ff_v210_planar_unpack_aligned_avx2(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); + +av_cold void ff_v210_x86_init(V210DecContext *s) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (s->aligned_input) { + if (cpu_flags & AV_CPU_FLAG_SSSE3) + s->unpack_frame = ff_v210_planar_unpack_aligned_ssse3; + + if (HAVE_AVX_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX) + s->unpack_frame = ff_v210_planar_unpack_aligned_avx; + + if (HAVE_AVX2_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX2) + s->unpack_frame = ff_v210_planar_unpack_aligned_avx2; + } + else { + if (cpu_flags & AV_CPU_FLAG_SSSE3) + s->unpack_frame = ff_v210_planar_unpack_unaligned_ssse3; + + if (HAVE_AVX_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX) + s->unpack_frame = ff_v210_planar_unpack_unaligned_avx; + + if (HAVE_AVX2_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX2) + s->unpack_frame = ff_v210_planar_unpack_unaligned_avx2; + } +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/v210enc_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/v210enc_init.c new file mode 100644 index 0000000000..e997b4b67a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/v210enc_init.c @@ -0,0 +1,54 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/x86/cpu.h" +#include "libavcodec/v210enc.h" + +void ff_v210_planar_pack_8_ssse3(const uint8_t *y, const uint8_t *u, + const uint8_t *v, uint8_t *dst, + ptrdiff_t width); +void ff_v210_planar_pack_8_avx(const uint8_t *y, const uint8_t *u, + const uint8_t *v, uint8_t *dst, ptrdiff_t width); +void ff_v210_planar_pack_8_avx2(const uint8_t *y, const uint8_t *u, + const uint8_t *v, uint8_t *dst, ptrdiff_t width); +void ff_v210_planar_pack_10_ssse3(const uint16_t *y, const uint16_t *u, + const uint16_t *v, uint8_t *dst, + ptrdiff_t width); +void ff_v210_planar_pack_10_avx2(const uint16_t *y, const uint16_t *u, + const uint16_t *v, uint8_t *dst, + ptrdiff_t width); + +av_cold void ff_v210enc_init_x86(V210EncContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSSE3(cpu_flags)) { + s->pack_line_8 = ff_v210_planar_pack_8_ssse3; + s->pack_line_10 = ff_v210_planar_pack_10_ssse3; + } + + if (EXTERNAL_AVX(cpu_flags)) + s->pack_line_8 = ff_v210_planar_pack_8_avx; + + if (EXTERNAL_AVX2(cpu_flags)) { + s->sample_factor_8 = 2; + s->pack_line_8 = ff_v210_planar_pack_8_avx2; + s->sample_factor_10 = 2; + s->pack_line_10 = ff_v210_planar_pack_10_avx2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp.h new file mode 100644 index 0000000000..fdd4de1813 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp.h @@ -0,0 +1,29 @@ +/* + * VC-1 and WMV3 decoder - X86 DSP init functions + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_VC1DSP_H +#define AVCODEC_X86_VC1DSP_H + +#include "libavcodec/vc1dsp.h" + +void ff_vc1dsp_init_mmx(VC1DSPContext *dsp); +void ff_vc1dsp_init_mmxext(VC1DSPContext *dsp); + +#endif /* AVCODEC_X86_VC1DSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp_init.c new file mode 100644 index 0000000000..8e0c284cc0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp_init.c @@ -0,0 +1,168 @@ +/* + * VC-1 and WMV3 - DSP functions MMX-optimized + * Copyright (c) 2007 Christophe GISQUET + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavcodec/vc1dsp.h" +#include "fpel.h" +#include "vc1dsp.h" +#include "config.h" + +#define LOOP_FILTER(EXT) \ +void ff_vc1_v_loop_filter4_ ## EXT(uint8_t *src, int stride, int pq); \ +void ff_vc1_h_loop_filter4_ ## EXT(uint8_t *src, int stride, int pq); \ +void ff_vc1_v_loop_filter8_ ## EXT(uint8_t *src, int stride, int pq); \ +void ff_vc1_h_loop_filter8_ ## EXT(uint8_t *src, int stride, int pq); \ +\ +static void vc1_v_loop_filter16_ ## EXT(uint8_t *src, int stride, int pq) \ +{ \ + ff_vc1_v_loop_filter8_ ## EXT(src, stride, pq); \ + ff_vc1_v_loop_filter8_ ## EXT(src+8, stride, pq); \ +} \ +\ +static void vc1_h_loop_filter16_ ## EXT(uint8_t *src, int stride, int pq) \ +{ \ + ff_vc1_h_loop_filter8_ ## EXT(src, stride, pq); \ + ff_vc1_h_loop_filter8_ ## EXT(src+8*stride, stride, pq); \ +} + +#if HAVE_X86ASM +LOOP_FILTER(mmxext) +LOOP_FILTER(sse2) +LOOP_FILTER(ssse3) + +void ff_vc1_h_loop_filter8_sse4(uint8_t *src, int stride, int pq); + +static void vc1_h_loop_filter16_sse4(uint8_t *src, int stride, int pq) +{ + ff_vc1_h_loop_filter8_sse4(src, stride, pq); + ff_vc1_h_loop_filter8_sse4(src+8*stride, stride, pq); +} + +#define DECLARE_FUNCTION(OP, DEPTH, INSN) \ + static void OP##vc1_mspel_mc00_##DEPTH##INSN(uint8_t *dst, \ + const uint8_t *src, ptrdiff_t stride, int rnd) \ + { \ + ff_ ## OP ## pixels ## DEPTH ## INSN(dst, src, stride, DEPTH); \ + } + +DECLARE_FUNCTION(put_, 8, _mmx) +DECLARE_FUNCTION(put_, 16, _mmx) +DECLARE_FUNCTION(avg_, 8, _mmx) +DECLARE_FUNCTION(avg_, 16, _mmx) +DECLARE_FUNCTION(avg_, 8, _mmxext) +DECLARE_FUNCTION(avg_, 16, _mmxext) +DECLARE_FUNCTION(put_, 16, _sse2) +DECLARE_FUNCTION(avg_, 16, _sse2) + +#endif /* HAVE_X86ASM */ + +void ff_put_vc1_chroma_mc8_nornd_mmx (uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_vc1_chroma_mc8_nornd_mmxext(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_vc1_chroma_mc8_nornd_3dnow(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_put_vc1_chroma_mc8_nornd_ssse3(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_avg_vc1_chroma_mc8_nornd_ssse3(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, int h, int x, int y); +void ff_vc1_inv_trans_4x4_dc_mmxext(uint8_t *dest, ptrdiff_t linesize, + int16_t *block); +void ff_vc1_inv_trans_4x8_dc_mmxext(uint8_t *dest, ptrdiff_t linesize, + int16_t *block); +void ff_vc1_inv_trans_8x4_dc_mmxext(uint8_t *dest, ptrdiff_t linesize, + int16_t *block); +void ff_vc1_inv_trans_8x8_dc_mmxext(uint8_t *dest, ptrdiff_t linesize, + int16_t *block); + + +av_cold void ff_vc1dsp_init_x86(VC1DSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (HAVE_6REGS && INLINE_MMX(cpu_flags)) + if (EXTERNAL_MMX(cpu_flags)) + ff_vc1dsp_init_mmx(dsp); + + if (HAVE_6REGS && INLINE_MMXEXT(cpu_flags)) + if (EXTERNAL_MMXEXT(cpu_flags)) + ff_vc1dsp_init_mmxext(dsp); + +#define ASSIGN_LF(EXT) \ + dsp->vc1_v_loop_filter4 = ff_vc1_v_loop_filter4_ ## EXT; \ + dsp->vc1_h_loop_filter4 = ff_vc1_h_loop_filter4_ ## EXT; \ + dsp->vc1_v_loop_filter8 = ff_vc1_v_loop_filter8_ ## EXT; \ + dsp->vc1_h_loop_filter8 = ff_vc1_h_loop_filter8_ ## EXT; \ + dsp->vc1_v_loop_filter16 = vc1_v_loop_filter16_ ## EXT; \ + dsp->vc1_h_loop_filter16 = vc1_h_loop_filter16_ ## EXT + +#if HAVE_X86ASM + if (EXTERNAL_MMX(cpu_flags)) { + dsp->put_no_rnd_vc1_chroma_pixels_tab[0] = ff_put_vc1_chroma_mc8_nornd_mmx; + + dsp->put_vc1_mspel_pixels_tab[1][0] = put_vc1_mspel_mc00_8_mmx; + dsp->put_vc1_mspel_pixels_tab[0][0] = put_vc1_mspel_mc00_16_mmx; + dsp->avg_vc1_mspel_pixels_tab[1][0] = avg_vc1_mspel_mc00_8_mmx; + dsp->avg_vc1_mspel_pixels_tab[0][0] = avg_vc1_mspel_mc00_16_mmx; + } + if (EXTERNAL_AMD3DNOW(cpu_flags)) { + dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = ff_avg_vc1_chroma_mc8_nornd_3dnow; + } + if (EXTERNAL_MMXEXT(cpu_flags)) { + ASSIGN_LF(mmxext); + dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = ff_avg_vc1_chroma_mc8_nornd_mmxext; + + dsp->avg_vc1_mspel_pixels_tab[1][0] = avg_vc1_mspel_mc00_8_mmxext; + dsp->avg_vc1_mspel_pixels_tab[0][0] = avg_vc1_mspel_mc00_16_mmxext; + + dsp->vc1_inv_trans_8x8_dc = ff_vc1_inv_trans_8x8_dc_mmxext; + dsp->vc1_inv_trans_4x8_dc = ff_vc1_inv_trans_4x8_dc_mmxext; + dsp->vc1_inv_trans_8x4_dc = ff_vc1_inv_trans_8x4_dc_mmxext; + dsp->vc1_inv_trans_4x4_dc = ff_vc1_inv_trans_4x4_dc_mmxext; + } + if (EXTERNAL_SSE2(cpu_flags)) { + dsp->vc1_v_loop_filter8 = ff_vc1_v_loop_filter8_sse2; + dsp->vc1_h_loop_filter8 = ff_vc1_h_loop_filter8_sse2; + dsp->vc1_v_loop_filter16 = vc1_v_loop_filter16_sse2; + dsp->vc1_h_loop_filter16 = vc1_h_loop_filter16_sse2; + + dsp->put_vc1_mspel_pixels_tab[0][0] = put_vc1_mspel_mc00_16_sse2; + dsp->avg_vc1_mspel_pixels_tab[0][0] = avg_vc1_mspel_mc00_16_sse2; + } + if (EXTERNAL_SSSE3(cpu_flags)) { + ASSIGN_LF(ssse3); + dsp->put_no_rnd_vc1_chroma_pixels_tab[0] = ff_put_vc1_chroma_mc8_nornd_ssse3; + dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = ff_avg_vc1_chroma_mc8_nornd_ssse3; + } + if (EXTERNAL_SSE4(cpu_flags)) { + dsp->vc1_h_loop_filter8 = ff_vc1_h_loop_filter8_sse4; + dsp->vc1_h_loop_filter16 = vc1_h_loop_filter16_sse4; + } +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp_mmx.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp_mmx.c new file mode 100644 index 0000000000..45c8a68f29 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vc1dsp_mmx.c @@ -0,0 +1,486 @@ +/* + * VC-1 and WMV3 - DSP functions MMX-optimized + * Copyright (c) 2007 Christophe GISQUET + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "libavutil/cpu.h" +#include "libavutil/mem.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/vc1dsp.h" +#include "constants.h" +#include "fpel.h" +#include "vc1dsp.h" + +#if HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL + +void ff_vc1_put_ver_16b_shift2_mmx(int16_t *dst, + const uint8_t *src, x86_reg stride, + int rnd, int64_t shift); +void ff_vc1_put_hor_16b_shift2_mmx(uint8_t *dst, x86_reg stride, + const int16_t *src, int rnd); +void ff_vc1_avg_hor_16b_shift2_mmxext(uint8_t *dst, x86_reg stride, + const int16_t *src, int rnd); + +#define OP_PUT(S,D) +#define OP_AVG(S,D) "pavgb " #S ", " #D " \n\t" + +/** Add rounder from mm7 to mm3 and pack result at destination */ +#define NORMALIZE_MMX(SHIFT) \ + "paddw %%mm7, %%mm3 \n\t" /* +bias-r */ \ + "paddw %%mm7, %%mm4 \n\t" /* +bias-r */ \ + "psraw "SHIFT", %%mm3 \n\t" \ + "psraw "SHIFT", %%mm4 \n\t" + +#define TRANSFER_DO_PACK(OP) \ + "packuswb %%mm4, %%mm3 \n\t" \ + OP((%2), %%mm3) \ + "movq %%mm3, (%2) \n\t" + +#define TRANSFER_DONT_PACK(OP) \ + OP(0(%2), %%mm3) \ + OP(8(%2), %%mm4) \ + "movq %%mm3, 0(%2) \n\t" \ + "movq %%mm4, 8(%2) \n\t" + +/** @see MSPEL_FILTER13_CORE for use as UNPACK macro */ +#define DO_UNPACK(reg) "punpcklbw %%mm0, " reg "\n\t" +#define DONT_UNPACK(reg) + +/** Compute the rounder 32-r or 8-r and unpacks it to mm7 */ +#define LOAD_ROUNDER_MMX(ROUND) \ + "movd "ROUND", %%mm7 \n\t" \ + "punpcklwd %%mm7, %%mm7 \n\t" \ + "punpckldq %%mm7, %%mm7 \n\t" + +/** + * Purely vertical or horizontal 1/2 shift interpolation. + * Sacrifice mm6 for *9 factor. + */ +#define VC1_SHIFT2(OP, OPNAME)\ +static void OPNAME ## vc1_shift2_mmx(uint8_t *dst, const uint8_t *src,\ + x86_reg stride, int rnd, x86_reg offset)\ +{\ + rnd = 8-rnd;\ + __asm__ volatile(\ + "mov $8, %%"FF_REG_c" \n\t"\ + LOAD_ROUNDER_MMX("%5")\ + "movq "MANGLE(ff_pw_9)", %%mm6\n\t"\ + "1: \n\t"\ + "movd 0(%0 ), %%mm3 \n\t"\ + "movd 4(%0 ), %%mm4 \n\t"\ + "movd 0(%0,%2), %%mm1 \n\t"\ + "movd 4(%0,%2), %%mm2 \n\t"\ + "add %2, %0 \n\t"\ + "punpcklbw %%mm0, %%mm3 \n\t"\ + "punpcklbw %%mm0, %%mm4 \n\t"\ + "punpcklbw %%mm0, %%mm1 \n\t"\ + "punpcklbw %%mm0, %%mm2 \n\t"\ + "paddw %%mm1, %%mm3 \n\t"\ + "paddw %%mm2, %%mm4 \n\t"\ + "movd 0(%0,%3), %%mm1 \n\t"\ + "movd 4(%0,%3), %%mm2 \n\t"\ + "pmullw %%mm6, %%mm3 \n\t" /* 0,9,9,0*/\ + "pmullw %%mm6, %%mm4 \n\t" /* 0,9,9,0*/\ + "punpcklbw %%mm0, %%mm1 \n\t"\ + "punpcklbw %%mm0, %%mm2 \n\t"\ + "psubw %%mm1, %%mm3 \n\t" /*-1,9,9,0*/\ + "psubw %%mm2, %%mm4 \n\t" /*-1,9,9,0*/\ + "movd 0(%0,%2), %%mm1 \n\t"\ + "movd 4(%0,%2), %%mm2 \n\t"\ + "punpcklbw %%mm0, %%mm1 \n\t"\ + "punpcklbw %%mm0, %%mm2 \n\t"\ + "psubw %%mm1, %%mm3 \n\t" /*-1,9,9,-1*/\ + "psubw %%mm2, %%mm4 \n\t" /*-1,9,9,-1*/\ + NORMALIZE_MMX("$4")\ + "packuswb %%mm4, %%mm3 \n\t"\ + OP((%1), %%mm3)\ + "movq %%mm3, (%1) \n\t"\ + "add %6, %0 \n\t"\ + "add %4, %1 \n\t"\ + "dec %%"FF_REG_c" \n\t"\ + "jnz 1b \n\t"\ + : "+r"(src), "+r"(dst)\ + : "r"(offset), "r"(-2*offset), "g"(stride), "m"(rnd),\ + "g"(stride-offset)\ + NAMED_CONSTRAINTS_ADD(ff_pw_9)\ + : "%"FF_REG_c, "memory"\ + );\ +} + +VC1_SHIFT2(OP_PUT, put_) +VC1_SHIFT2(OP_AVG, avg_) + +/** + * Core of the 1/4 and 3/4 shift bicubic interpolation. + * + * @param UNPACK Macro unpacking arguments from 8 to 16 bits (can be empty). + * @param MOVQ "movd 1" or "movq 2", if data read is already unpacked. + * @param A1 Address of 1st tap (beware of unpacked/packed). + * @param A2 Address of 2nd tap + * @param A3 Address of 3rd tap + * @param A4 Address of 4th tap + */ +#define MSPEL_FILTER13_CORE(UNPACK, MOVQ, A1, A2, A3, A4) \ + MOVQ "*0+"A1", %%mm1 \n\t" \ + MOVQ "*4+"A1", %%mm2 \n\t" \ + UNPACK("%%mm1") \ + UNPACK("%%mm2") \ + "pmullw "MANGLE(ff_pw_3)", %%mm1\n\t" \ + "pmullw "MANGLE(ff_pw_3)", %%mm2\n\t" \ + MOVQ "*0+"A2", %%mm3 \n\t" \ + MOVQ "*4+"A2", %%mm4 \n\t" \ + UNPACK("%%mm3") \ + UNPACK("%%mm4") \ + "pmullw %%mm6, %%mm3 \n\t" /* *18 */ \ + "pmullw %%mm6, %%mm4 \n\t" /* *18 */ \ + "psubw %%mm1, %%mm3 \n\t" /* 18,-3 */ \ + "psubw %%mm2, %%mm4 \n\t" /* 18,-3 */ \ + MOVQ "*0+"A4", %%mm1 \n\t" \ + MOVQ "*4+"A4", %%mm2 \n\t" \ + UNPACK("%%mm1") \ + UNPACK("%%mm2") \ + "psllw $2, %%mm1 \n\t" /* 4* */ \ + "psllw $2, %%mm2 \n\t" /* 4* */ \ + "psubw %%mm1, %%mm3 \n\t" /* -4,18,-3 */ \ + "psubw %%mm2, %%mm4 \n\t" /* -4,18,-3 */ \ + MOVQ "*0+"A3", %%mm1 \n\t" \ + MOVQ "*4+"A3", %%mm2 \n\t" \ + UNPACK("%%mm1") \ + UNPACK("%%mm2") \ + "pmullw %%mm5, %%mm1 \n\t" /* *53 */ \ + "pmullw %%mm5, %%mm2 \n\t" /* *53 */ \ + "paddw %%mm1, %%mm3 \n\t" /* 4,53,18,-3 */ \ + "paddw %%mm2, %%mm4 \n\t" /* 4,53,18,-3 */ + +/** + * Macro to build the vertical 16 bits version of vc1_put_shift[13]. + * Here, offset=src_stride. Parameters passed A1 to A4 must use + * %3 (src_stride) and %4 (3*src_stride). + * + * @param NAME Either 1 or 3 + * @see MSPEL_FILTER13_CORE for information on A1->A4 + */ +#define MSPEL_FILTER13_VER_16B(NAME, A1, A2, A3, A4) \ +static void \ +vc1_put_ver_16b_ ## NAME ## _mmx(int16_t *dst, const uint8_t *src, \ + x86_reg src_stride, \ + int rnd, int64_t shift) \ +{ \ + int h = 8; \ + src -= src_stride; \ + __asm__ volatile( \ + LOAD_ROUNDER_MMX("%5") \ + "movq "MANGLE(ff_pw_53)", %%mm5\n\t" \ + "movq "MANGLE(ff_pw_18)", %%mm6\n\t" \ + ".p2align 3 \n\t" \ + "1: \n\t" \ + MSPEL_FILTER13_CORE(DO_UNPACK, "movd 1", A1, A2, A3, A4) \ + NORMALIZE_MMX("%6") \ + TRANSFER_DONT_PACK(OP_PUT) \ + /* Last 3 (in fact 4) bytes on the line */ \ + "movd 8+"A1", %%mm1 \n\t" \ + DO_UNPACK("%%mm1") \ + "movq %%mm1, %%mm3 \n\t" \ + "paddw %%mm1, %%mm1 \n\t" \ + "paddw %%mm3, %%mm1 \n\t" /* 3* */ \ + "movd 8+"A2", %%mm3 \n\t" \ + DO_UNPACK("%%mm3") \ + "pmullw %%mm6, %%mm3 \n\t" /* *18 */ \ + "psubw %%mm1, %%mm3 \n\t" /*18,-3 */ \ + "movd 8+"A3", %%mm1 \n\t" \ + DO_UNPACK("%%mm1") \ + "pmullw %%mm5, %%mm1 \n\t" /* *53 */ \ + "paddw %%mm1, %%mm3 \n\t" /*53,18,-3 */ \ + "movd 8+"A4", %%mm1 \n\t" \ + DO_UNPACK("%%mm1") \ + "psllw $2, %%mm1 \n\t" /* 4* */ \ + "psubw %%mm1, %%mm3 \n\t" \ + "paddw %%mm7, %%mm3 \n\t" \ + "psraw %6, %%mm3 \n\t" \ + "movq %%mm3, 16(%2) \n\t" \ + "add %3, %1 \n\t" \ + "add $24, %2 \n\t" \ + "decl %0 \n\t" \ + "jnz 1b \n\t" \ + : "+r"(h), "+r" (src), "+r" (dst) \ + : "r"(src_stride), "r"(3*src_stride), \ + "m"(rnd), "m"(shift) \ + NAMED_CONSTRAINTS_ADD(ff_pw_3,ff_pw_53,ff_pw_18) \ + : "memory" \ + ); \ +} + +/** + * Macro to build the horizontal 16 bits version of vc1_put_shift[13]. + * Here, offset=16 bits, so parameters passed A1 to A4 should be simple. + * + * @param NAME Either 1 or 3 + * @see MSPEL_FILTER13_CORE for information on A1->A4 + */ +#define MSPEL_FILTER13_HOR_16B(NAME, A1, A2, A3, A4, OP, OPNAME) \ +static void \ +OPNAME ## vc1_hor_16b_ ## NAME ## _mmx(uint8_t *dst, x86_reg stride, \ + const int16_t *src, int rnd) \ +{ \ + int h = 8; \ + src -= 1; \ + rnd -= (-4+58+13-3)*256; /* Add -256 bias */ \ + __asm__ volatile( \ + LOAD_ROUNDER_MMX("%4") \ + "movq "MANGLE(ff_pw_18)", %%mm6 \n\t" \ + "movq "MANGLE(ff_pw_53)", %%mm5 \n\t" \ + ".p2align 3 \n\t" \ + "1: \n\t" \ + MSPEL_FILTER13_CORE(DONT_UNPACK, "movq 2", A1, A2, A3, A4) \ + NORMALIZE_MMX("$7") \ + /* Remove bias */ \ + "paddw "MANGLE(ff_pw_128)", %%mm3 \n\t" \ + "paddw "MANGLE(ff_pw_128)", %%mm4 \n\t" \ + TRANSFER_DO_PACK(OP) \ + "add $24, %1 \n\t" \ + "add %3, %2 \n\t" \ + "decl %0 \n\t" \ + "jnz 1b \n\t" \ + : "+r"(h), "+r" (src), "+r" (dst) \ + : "r"(stride), "m"(rnd) \ + NAMED_CONSTRAINTS_ADD(ff_pw_3,ff_pw_18,ff_pw_53,ff_pw_128) \ + : "memory" \ + ); \ +} + +/** + * Macro to build the 8 bits, any direction, version of vc1_put_shift[13]. + * Here, offset=src_stride. Parameters passed A1 to A4 must use + * %3 (offset) and %4 (3*offset). + * + * @param NAME Either 1 or 3 + * @see MSPEL_FILTER13_CORE for information on A1->A4 + */ +#define MSPEL_FILTER13_8B(NAME, A1, A2, A3, A4, OP, OPNAME) \ +static void \ +OPNAME ## vc1_## NAME ## _mmx(uint8_t *dst, const uint8_t *src, \ + x86_reg stride, int rnd, x86_reg offset) \ +{ \ + int h = 8; \ + src -= offset; \ + rnd = 32-rnd; \ + __asm__ volatile ( \ + LOAD_ROUNDER_MMX("%6") \ + "movq "MANGLE(ff_pw_53)", %%mm5 \n\t" \ + "movq "MANGLE(ff_pw_18)", %%mm6 \n\t" \ + ".p2align 3 \n\t" \ + "1: \n\t" \ + MSPEL_FILTER13_CORE(DO_UNPACK, "movd 1", A1, A2, A3, A4) \ + NORMALIZE_MMX("$6") \ + TRANSFER_DO_PACK(OP) \ + "add %5, %1 \n\t" \ + "add %5, %2 \n\t" \ + "decl %0 \n\t" \ + "jnz 1b \n\t" \ + : "+r"(h), "+r" (src), "+r" (dst) \ + : "r"(offset), "r"(3*offset), "g"(stride), "m"(rnd) \ + NAMED_CONSTRAINTS_ADD(ff_pw_53,ff_pw_18,ff_pw_3) \ + : "memory" \ + ); \ +} + +/** 1/4 shift bicubic interpolation */ +MSPEL_FILTER13_8B (shift1, "0(%1,%4 )", "0(%1,%3,2)", "0(%1,%3 )", "0(%1 )", OP_PUT, put_) +MSPEL_FILTER13_8B (shift1, "0(%1,%4 )", "0(%1,%3,2)", "0(%1,%3 )", "0(%1 )", OP_AVG, avg_) +MSPEL_FILTER13_VER_16B(shift1, "0(%1,%4 )", "0(%1,%3,2)", "0(%1,%3 )", "0(%1 )") +MSPEL_FILTER13_HOR_16B(shift1, "2*3(%1)", "2*2(%1)", "2*1(%1)", "2*0(%1)", OP_PUT, put_) +MSPEL_FILTER13_HOR_16B(shift1, "2*3(%1)", "2*2(%1)", "2*1(%1)", "2*0(%1)", OP_AVG, avg_) + +/** 3/4 shift bicubic interpolation */ +MSPEL_FILTER13_8B (shift3, "0(%1 )", "0(%1,%3 )", "0(%1,%3,2)", "0(%1,%4 )", OP_PUT, put_) +MSPEL_FILTER13_8B (shift3, "0(%1 )", "0(%1,%3 )", "0(%1,%3,2)", "0(%1,%4 )", OP_AVG, avg_) +MSPEL_FILTER13_VER_16B(shift3, "0(%1 )", "0(%1,%3 )", "0(%1,%3,2)", "0(%1,%4 )") +MSPEL_FILTER13_HOR_16B(shift3, "2*0(%1)", "2*1(%1)", "2*2(%1)", "2*3(%1)", OP_PUT, put_) +MSPEL_FILTER13_HOR_16B(shift3, "2*0(%1)", "2*1(%1)", "2*2(%1)", "2*3(%1)", OP_AVG, avg_) + +typedef void (*vc1_mspel_mc_filter_ver_16bits)(int16_t *dst, const uint8_t *src, x86_reg src_stride, int rnd, int64_t shift); +typedef void (*vc1_mspel_mc_filter_hor_16bits)(uint8_t *dst, x86_reg dst_stride, const int16_t *src, int rnd); +typedef void (*vc1_mspel_mc_filter_8bits)(uint8_t *dst, const uint8_t *src, x86_reg stride, int rnd, x86_reg offset); + +/** + * Interpolate fractional pel values by applying proper vertical then + * horizontal filter. + * + * @param dst Destination buffer for interpolated pels. + * @param src Source buffer. + * @param stride Stride for both src and dst buffers. + * @param hmode Horizontal filter (expressed in quarter pixels shift). + * @param hmode Vertical filter. + * @param rnd Rounding bias. + */ +#define VC1_MSPEL_MC(OP, INSTR)\ +static void OP ## vc1_mspel_mc(uint8_t *dst, const uint8_t *src, int stride,\ + int hmode, int vmode, int rnd)\ +{\ + static const vc1_mspel_mc_filter_ver_16bits vc1_put_shift_ver_16bits[] =\ + { NULL, vc1_put_ver_16b_shift1_mmx, ff_vc1_put_ver_16b_shift2_mmx, vc1_put_ver_16b_shift3_mmx };\ + static const vc1_mspel_mc_filter_hor_16bits vc1_put_shift_hor_16bits[] =\ + { NULL, OP ## vc1_hor_16b_shift1_mmx, ff_vc1_ ## OP ## hor_16b_shift2_ ## INSTR, OP ## vc1_hor_16b_shift3_mmx };\ + static const vc1_mspel_mc_filter_8bits vc1_put_shift_8bits[] =\ + { NULL, OP ## vc1_shift1_mmx, OP ## vc1_shift2_mmx, OP ## vc1_shift3_mmx };\ +\ + __asm__ volatile(\ + "pxor %%mm0, %%mm0 \n\t"\ + ::: "memory"\ + );\ +\ + if (vmode) { /* Vertical filter to apply */\ + if (hmode) { /* Horizontal filter to apply, output to tmp */\ + static const int shift_value[] = { 0, 5, 1, 5 };\ + int shift = (shift_value[hmode]+shift_value[vmode])>>1;\ + int r;\ + LOCAL_ALIGNED(16, int16_t, tmp, [12*8]);\ +\ + r = (1<<(shift-1)) + rnd-1;\ + vc1_put_shift_ver_16bits[vmode](tmp, src-1, stride, r, shift);\ +\ + vc1_put_shift_hor_16bits[hmode](dst, stride, tmp+1, 64-rnd);\ + return;\ + }\ + else { /* No horizontal filter, output 8 lines to dst */\ + vc1_put_shift_8bits[vmode](dst, src, stride, 1-rnd, stride);\ + return;\ + }\ + }\ +\ + /* Horizontal mode with no vertical mode */\ + vc1_put_shift_8bits[hmode](dst, src, stride, rnd, 1);\ +} \ +static void OP ## vc1_mspel_mc_16(uint8_t *dst, const uint8_t *src, \ + int stride, int hmode, int vmode, int rnd)\ +{ \ + OP ## vc1_mspel_mc(dst + 0, src + 0, stride, hmode, vmode, rnd); \ + OP ## vc1_mspel_mc(dst + 8, src + 8, stride, hmode, vmode, rnd); \ + dst += 8*stride; src += 8*stride; \ + OP ## vc1_mspel_mc(dst + 0, src + 0, stride, hmode, vmode, rnd); \ + OP ## vc1_mspel_mc(dst + 8, src + 8, stride, hmode, vmode, rnd); \ +} + +VC1_MSPEL_MC(put_, mmx) +VC1_MSPEL_MC(avg_, mmxext) + +/** Macro to ease bicubic filter interpolation functions declarations */ +#define DECLARE_FUNCTION(a, b) \ +static void put_vc1_mspel_mc ## a ## b ## _mmx(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride, \ + int rnd) \ +{ \ + put_vc1_mspel_mc(dst, src, stride, a, b, rnd); \ +}\ +static void avg_vc1_mspel_mc ## a ## b ## _mmxext(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride, \ + int rnd) \ +{ \ + avg_vc1_mspel_mc(dst, src, stride, a, b, rnd); \ +}\ +static void put_vc1_mspel_mc ## a ## b ## _16_mmx(uint8_t *dst, \ + const uint8_t *src, \ + ptrdiff_t stride, \ + int rnd) \ +{ \ + put_vc1_mspel_mc_16(dst, src, stride, a, b, rnd); \ +}\ +static void avg_vc1_mspel_mc ## a ## b ## _16_mmxext(uint8_t *dst, \ + const uint8_t *src,\ + ptrdiff_t stride, \ + int rnd) \ +{ \ + avg_vc1_mspel_mc_16(dst, src, stride, a, b, rnd); \ +} + +DECLARE_FUNCTION(0, 1) +DECLARE_FUNCTION(0, 2) +DECLARE_FUNCTION(0, 3) + +DECLARE_FUNCTION(1, 0) +DECLARE_FUNCTION(1, 1) +DECLARE_FUNCTION(1, 2) +DECLARE_FUNCTION(1, 3) + +DECLARE_FUNCTION(2, 0) +DECLARE_FUNCTION(2, 1) +DECLARE_FUNCTION(2, 2) +DECLARE_FUNCTION(2, 3) + +DECLARE_FUNCTION(3, 0) +DECLARE_FUNCTION(3, 1) +DECLARE_FUNCTION(3, 2) +DECLARE_FUNCTION(3, 3) + +#define FN_ASSIGN(OP, X, Y, INSN) \ + dsp->OP##vc1_mspel_pixels_tab[1][X+4*Y] = OP##vc1_mspel_mc##X##Y##INSN; \ + dsp->OP##vc1_mspel_pixels_tab[0][X+4*Y] = OP##vc1_mspel_mc##X##Y##_16##INSN + +av_cold void ff_vc1dsp_init_mmx(VC1DSPContext *dsp) +{ + FN_ASSIGN(put_, 0, 1, _mmx); + FN_ASSIGN(put_, 0, 2, _mmx); + FN_ASSIGN(put_, 0, 3, _mmx); + + FN_ASSIGN(put_, 1, 0, _mmx); + FN_ASSIGN(put_, 1, 1, _mmx); + FN_ASSIGN(put_, 1, 2, _mmx); + FN_ASSIGN(put_, 1, 3, _mmx); + + FN_ASSIGN(put_, 2, 0, _mmx); + FN_ASSIGN(put_, 2, 1, _mmx); + FN_ASSIGN(put_, 2, 2, _mmx); + FN_ASSIGN(put_, 2, 3, _mmx); + + FN_ASSIGN(put_, 3, 0, _mmx); + FN_ASSIGN(put_, 3, 1, _mmx); + FN_ASSIGN(put_, 3, 2, _mmx); + FN_ASSIGN(put_, 3, 3, _mmx); +} + +av_cold void ff_vc1dsp_init_mmxext(VC1DSPContext *dsp) +{ + FN_ASSIGN(avg_, 0, 1, _mmxext); + FN_ASSIGN(avg_, 0, 2, _mmxext); + FN_ASSIGN(avg_, 0, 3, _mmxext); + + FN_ASSIGN(avg_, 1, 0, _mmxext); + FN_ASSIGN(avg_, 1, 1, _mmxext); + FN_ASSIGN(avg_, 1, 2, _mmxext); + FN_ASSIGN(avg_, 1, 3, _mmxext); + + FN_ASSIGN(avg_, 2, 0, _mmxext); + FN_ASSIGN(avg_, 2, 1, _mmxext); + FN_ASSIGN(avg_, 2, 2, _mmxext); + FN_ASSIGN(avg_, 2, 3, _mmxext); + + FN_ASSIGN(avg_, 3, 0, _mmxext); + FN_ASSIGN(avg_, 3, 1, _mmxext); + FN_ASSIGN(avg_, 3, 2, _mmxext); + FN_ASSIGN(avg_, 3, 3, _mmxext); +} +#endif /* HAVE_6REGS && HAVE_INLINE_ASM && HAVE_MMX_EXTERNAL */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/videodsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/videodsp_init.c new file mode 100644 index 0000000000..eeebb41547 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/videodsp_init.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2002-2012 Michael Niedermayer + * Copyright (C) 2012 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/cpu.h" +#include "libavutil/mem.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/videodsp.h" + +#if HAVE_X86ASM +typedef void emu_edge_vfix_func(uint8_t *dst, x86_reg dst_stride, + const uint8_t *src, x86_reg src_stride, + x86_reg start_y, x86_reg end_y, x86_reg bh); +typedef void emu_edge_vvar_func(uint8_t *dst, x86_reg dst_stride, + const uint8_t *src, x86_reg src_stride, + x86_reg start_y, x86_reg end_y, x86_reg bh, + x86_reg w); + +extern emu_edge_vfix_func ff_emu_edge_vfix1_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix2_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix3_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix4_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix5_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix6_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix7_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix8_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix9_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix10_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix11_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix12_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix13_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix14_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix15_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix16_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix17_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix18_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix19_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix20_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix21_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix22_mmx; +#if ARCH_X86_32 +static emu_edge_vfix_func * const vfixtbl_mmx[22] = { + &ff_emu_edge_vfix1_mmx, &ff_emu_edge_vfix2_mmx, &ff_emu_edge_vfix3_mmx, + &ff_emu_edge_vfix4_mmx, &ff_emu_edge_vfix5_mmx, &ff_emu_edge_vfix6_mmx, + &ff_emu_edge_vfix7_mmx, &ff_emu_edge_vfix8_mmx, &ff_emu_edge_vfix9_mmx, + &ff_emu_edge_vfix10_mmx, &ff_emu_edge_vfix11_mmx, &ff_emu_edge_vfix12_mmx, + &ff_emu_edge_vfix13_mmx, &ff_emu_edge_vfix14_mmx, &ff_emu_edge_vfix15_mmx, + &ff_emu_edge_vfix16_mmx, &ff_emu_edge_vfix17_mmx, &ff_emu_edge_vfix18_mmx, + &ff_emu_edge_vfix19_mmx, &ff_emu_edge_vfix20_mmx, &ff_emu_edge_vfix21_mmx, + &ff_emu_edge_vfix22_mmx +}; +#endif +extern emu_edge_vvar_func ff_emu_edge_vvar_mmx; +extern emu_edge_vfix_func ff_emu_edge_vfix16_sse; +extern emu_edge_vfix_func ff_emu_edge_vfix17_sse; +extern emu_edge_vfix_func ff_emu_edge_vfix18_sse; +extern emu_edge_vfix_func ff_emu_edge_vfix19_sse; +extern emu_edge_vfix_func ff_emu_edge_vfix20_sse; +extern emu_edge_vfix_func ff_emu_edge_vfix21_sse; +extern emu_edge_vfix_func ff_emu_edge_vfix22_sse; +static emu_edge_vfix_func * const vfixtbl_sse[22] = { + ff_emu_edge_vfix1_mmx, ff_emu_edge_vfix2_mmx, ff_emu_edge_vfix3_mmx, + ff_emu_edge_vfix4_mmx, ff_emu_edge_vfix5_mmx, ff_emu_edge_vfix6_mmx, + ff_emu_edge_vfix7_mmx, ff_emu_edge_vfix8_mmx, ff_emu_edge_vfix9_mmx, + ff_emu_edge_vfix10_mmx, ff_emu_edge_vfix11_mmx, ff_emu_edge_vfix12_mmx, + ff_emu_edge_vfix13_mmx, ff_emu_edge_vfix14_mmx, ff_emu_edge_vfix15_mmx, + ff_emu_edge_vfix16_sse, ff_emu_edge_vfix17_sse, ff_emu_edge_vfix18_sse, + ff_emu_edge_vfix19_sse, ff_emu_edge_vfix20_sse, ff_emu_edge_vfix21_sse, + ff_emu_edge_vfix22_sse +}; +extern emu_edge_vvar_func ff_emu_edge_vvar_sse; + +typedef void emu_edge_hfix_func(uint8_t *dst, x86_reg dst_stride, + x86_reg start_x, x86_reg bh); +typedef void emu_edge_hvar_func(uint8_t *dst, x86_reg dst_stride, + x86_reg start_x, x86_reg n_words, x86_reg bh); + +extern emu_edge_hfix_func ff_emu_edge_hfix2_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix4_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix6_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix8_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix10_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix12_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix14_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix16_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix18_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix20_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix22_mmx; +#if ARCH_X86_32 +static emu_edge_hfix_func * const hfixtbl_mmx[11] = { + ff_emu_edge_hfix2_mmx, ff_emu_edge_hfix4_mmx, ff_emu_edge_hfix6_mmx, + ff_emu_edge_hfix8_mmx, ff_emu_edge_hfix10_mmx, ff_emu_edge_hfix12_mmx, + ff_emu_edge_hfix14_mmx, ff_emu_edge_hfix16_mmx, ff_emu_edge_hfix18_mmx, + ff_emu_edge_hfix20_mmx, ff_emu_edge_hfix22_mmx +}; +#endif +extern emu_edge_hvar_func ff_emu_edge_hvar_mmx; +extern emu_edge_hfix_func ff_emu_edge_hfix16_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix18_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix20_sse2; +extern emu_edge_hfix_func ff_emu_edge_hfix22_sse2; +static emu_edge_hfix_func * const hfixtbl_sse2[11] = { + ff_emu_edge_hfix2_mmx, ff_emu_edge_hfix4_mmx, ff_emu_edge_hfix6_mmx, + ff_emu_edge_hfix8_mmx, ff_emu_edge_hfix10_mmx, ff_emu_edge_hfix12_mmx, + ff_emu_edge_hfix14_mmx, ff_emu_edge_hfix16_sse2, ff_emu_edge_hfix18_sse2, + ff_emu_edge_hfix20_sse2, ff_emu_edge_hfix22_sse2 +}; +extern emu_edge_hvar_func ff_emu_edge_hvar_sse2; +#if HAVE_AVX2_EXTERNAL +extern emu_edge_hfix_func ff_emu_edge_hfix8_avx2; +extern emu_edge_hfix_func ff_emu_edge_hfix10_avx2; +extern emu_edge_hfix_func ff_emu_edge_hfix12_avx2; +extern emu_edge_hfix_func ff_emu_edge_hfix14_avx2; +extern emu_edge_hfix_func ff_emu_edge_hfix16_avx2; +extern emu_edge_hfix_func ff_emu_edge_hfix18_avx2; +extern emu_edge_hfix_func ff_emu_edge_hfix20_avx2; +extern emu_edge_hfix_func ff_emu_edge_hfix22_avx2; +static emu_edge_hfix_func * const hfixtbl_avx2[11] = { + ff_emu_edge_hfix2_mmx, ff_emu_edge_hfix4_mmx, ff_emu_edge_hfix6_mmx, + ff_emu_edge_hfix8_avx2, ff_emu_edge_hfix10_avx2, ff_emu_edge_hfix12_avx2, + ff_emu_edge_hfix14_avx2, ff_emu_edge_hfix16_avx2, ff_emu_edge_hfix18_avx2, + ff_emu_edge_hfix20_avx2, ff_emu_edge_hfix22_avx2 +}; +extern emu_edge_hvar_func ff_emu_edge_hvar_avx2; +#endif + +static av_always_inline void emulated_edge_mc(uint8_t *dst, const uint8_t *src, + ptrdiff_t dst_stride, + ptrdiff_t src_stride, + x86_reg block_w, x86_reg block_h, + x86_reg src_x, x86_reg src_y, + x86_reg w, x86_reg h, + emu_edge_vfix_func * const *vfix_tbl, + emu_edge_vvar_func *v_extend_var, + emu_edge_hfix_func * const *hfix_tbl, + emu_edge_hvar_func *h_extend_var) +{ + x86_reg start_y, start_x, end_y, end_x, src_y_add = 0, p; + + if (!w || !h) + return; + + av_assert2(block_w <= FFABS(dst_stride)); + + if (src_y >= h) { + src -= src_y*src_stride; + src_y_add = h - 1; + src_y = h - 1; + } else if (src_y <= -block_h) { + src -= src_y*src_stride; + src_y_add = 1 - block_h; + src_y = 1 - block_h; + } + if (src_x >= w) { + src += w - 1 - src_x; + src_x = w - 1; + } else if (src_x <= -block_w) { + src += 1 - block_w - src_x; + src_x = 1 - block_w; + } + + start_y = FFMAX(0, -src_y); + start_x = FFMAX(0, -src_x); + end_y = FFMIN(block_h, h-src_y); + end_x = FFMIN(block_w, w-src_x); + av_assert2(start_x < end_x && block_w > 0); + av_assert2(start_y < end_y && block_h > 0); + + // fill in the to-be-copied part plus all above/below + src += (src_y_add + start_y) * src_stride + start_x; + w = end_x - start_x; + if (w <= 22) { + vfix_tbl[w - 1](dst + start_x, dst_stride, src, src_stride, + start_y, end_y, block_h); + } else { + v_extend_var(dst + start_x, dst_stride, src, src_stride, + start_y, end_y, block_h, w); + } + + // fill left + if (start_x) { + if (start_x <= 22) { + hfix_tbl[(start_x - 1) >> 1](dst, dst_stride, start_x, block_h); + } else { + h_extend_var(dst, dst_stride, + start_x, (start_x + 1) >> 1, block_h); + } + } + + // fill right + p = block_w - end_x; + if (p) { + if (p <= 22) { + hfix_tbl[(p - 1) >> 1](dst + end_x - (p & 1), dst_stride, + -!(p & 1), block_h); + } else { + h_extend_var(dst + end_x - (p & 1), dst_stride, + -!(p & 1), (p + 1) >> 1, block_h); + } + } +} + +#if ARCH_X86_32 +static av_noinline void emulated_edge_mc_mmx(uint8_t *buf, const uint8_t *src, + ptrdiff_t buf_stride, + ptrdiff_t src_stride, + int block_w, int block_h, + int src_x, int src_y, int w, int h) +{ + emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h, + src_x, src_y, w, h, vfixtbl_mmx, &ff_emu_edge_vvar_mmx, + hfixtbl_mmx, &ff_emu_edge_hvar_mmx); +} + +static av_noinline void emulated_edge_mc_sse(uint8_t *buf, const uint8_t *src, + ptrdiff_t buf_stride, + ptrdiff_t src_stride, + int block_w, int block_h, + int src_x, int src_y, int w, int h) +{ + emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h, + src_x, src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse, + hfixtbl_mmx, &ff_emu_edge_hvar_mmx); +} +#endif + +static av_noinline void emulated_edge_mc_sse2(uint8_t *buf, const uint8_t *src, + ptrdiff_t buf_stride, + ptrdiff_t src_stride, + int block_w, int block_h, + int src_x, int src_y, int w, + int h) +{ + emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h, + src_x, src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse, + hfixtbl_sse2, &ff_emu_edge_hvar_sse2); +} + +#if HAVE_AVX2_EXTERNAL +static av_noinline void emulated_edge_mc_avx2(uint8_t *buf, const uint8_t *src, + ptrdiff_t buf_stride, + ptrdiff_t src_stride, + int block_w, int block_h, + int src_x, int src_y, int w, + int h) +{ + emulated_edge_mc(buf, src, buf_stride, src_stride, block_w, block_h, + src_x, src_y, w, h, vfixtbl_sse, &ff_emu_edge_vvar_sse, + hfixtbl_avx2, &ff_emu_edge_hvar_avx2); +} +#endif /* HAVE_AVX2_EXTERNAL */ +#endif /* HAVE_X86ASM */ + +void ff_prefetch_mmxext(uint8_t *buf, ptrdiff_t stride, int h); +void ff_prefetch_3dnow(uint8_t *buf, ptrdiff_t stride, int h); + +av_cold void ff_videodsp_init_x86(VideoDSPContext *ctx, int bpc) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + +#if ARCH_X86_32 + if (EXTERNAL_MMX(cpu_flags) && bpc <= 8) { + ctx->emulated_edge_mc = emulated_edge_mc_mmx; + } + if (EXTERNAL_AMD3DNOW(cpu_flags)) { + ctx->prefetch = ff_prefetch_3dnow; + } +#endif /* ARCH_X86_32 */ + if (EXTERNAL_MMXEXT(cpu_flags)) { + ctx->prefetch = ff_prefetch_mmxext; + } +#if ARCH_X86_32 + if (EXTERNAL_SSE(cpu_flags) && bpc <= 8) { + ctx->emulated_edge_mc = emulated_edge_mc_sse; + } +#endif /* ARCH_X86_32 */ + if (EXTERNAL_SSE2(cpu_flags) && bpc <= 8) { + ctx->emulated_edge_mc = emulated_edge_mc_sse2; + } +#if HAVE_AVX2_EXTERNAL + if (EXTERNAL_AVX2(cpu_flags) && bpc <= 8) { + ctx->emulated_edge_mc = emulated_edge_mc_avx2; + } +#endif +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vorbisdsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vorbisdsp_init.c new file mode 100644 index 0000000000..bc1cc43a18 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vorbisdsp_init.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 Loren Merritt + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/vorbisdsp.h" + +void ff_vorbis_inverse_coupling_3dnow(float *mag, float *ang, + intptr_t blocksize); +void ff_vorbis_inverse_coupling_sse(float *mag, float *ang, + intptr_t blocksize); + +av_cold void ff_vorbisdsp_init_x86(VorbisDSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + +#if ARCH_X86_32 + if (EXTERNAL_AMD3DNOW(cpu_flags)) + dsp->vorbis_inverse_coupling = ff_vorbis_inverse_coupling_3dnow; +#endif /* ARCH_X86_32 */ + if (EXTERNAL_SSE(cpu_flags)) + dsp->vorbis_inverse_coupling = ff_vorbis_inverse_coupling_sse; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp3dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp3dsp_init.c new file mode 100644 index 0000000000..1ba9576431 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp3dsp_init.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2009 David Conrad + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/vp3dsp.h" + +void ff_vp3_idct_put_mmx(uint8_t *dest, ptrdiff_t stride, int16_t *block); +void ff_vp3_idct_add_mmx(uint8_t *dest, ptrdiff_t stride, int16_t *block); + +void ff_vp3_idct_put_sse2(uint8_t *dest, ptrdiff_t stride, int16_t *block); +void ff_vp3_idct_add_sse2(uint8_t *dest, ptrdiff_t stride, int16_t *block); + +void ff_vp3_idct_dc_add_mmxext(uint8_t *dest, ptrdiff_t stride, int16_t *block); + +void ff_vp3_v_loop_filter_mmxext(uint8_t *src, ptrdiff_t stride, + int *bounding_values); +void ff_vp3_h_loop_filter_mmxext(uint8_t *src, ptrdiff_t stride, + int *bounding_values); + +void ff_put_vp_no_rnd_pixels8_l2_mmx(uint8_t *dst, const uint8_t *a, + const uint8_t *b, ptrdiff_t stride, + int h); + +av_cold void ff_vp3dsp_init_x86(VP3DSPContext *c, int flags) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + c->put_no_rnd_pixels_l2 = ff_put_vp_no_rnd_pixels8_l2_mmx; +#if ARCH_X86_32 + c->idct_put = ff_vp3_idct_put_mmx; + c->idct_add = ff_vp3_idct_add_mmx; +#endif + } + + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->idct_dc_add = ff_vp3_idct_dc_add_mmxext; + + if (!(flags & AV_CODEC_FLAG_BITEXACT)) { + c->v_loop_filter = ff_vp3_v_loop_filter_mmxext; + c->h_loop_filter = ff_vp3_h_loop_filter_mmxext; + } + } + + if (EXTERNAL_SSE2(cpu_flags)) { + c->idct_put = ff_vp3_idct_put_sse2; + c->idct_add = ff_vp3_idct_add_sse2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp56_arith.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp56_arith.h new file mode 100644 index 0000000000..810cc8dcd8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp56_arith.h @@ -0,0 +1,51 @@ +/** + * VP5 and VP6 compatible video decoder (arith decoder) + * + * Copyright (C) 2006 Aurelien Jacobs + * Copyright (C) 2010 Eli Friedman + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_VP56_ARITH_H +#define AVCODEC_X86_VP56_ARITH_H + +#if HAVE_INLINE_ASM && HAVE_FAST_CMOV && HAVE_6REGS +#define vp56_rac_get_prob vp56_rac_get_prob +static av_always_inline int vp56_rac_get_prob(VP56RangeCoder *c, uint8_t prob) +{ + unsigned int code_word = vp56_rac_renorm(c); + unsigned int low = 1 + (((c->high - 1) * prob) >> 8); + unsigned int low_shift = low << 16; + int bit = 0; + c->code_word = code_word; + + __asm__( + "subl %4, %1 \n\t" + "subl %3, %2 \n\t" + "setae %b0 \n\t" + "cmovb %4, %1 \n\t" + "cmovb %5, %2 \n\t" + : "+q"(bit), "+&r"(c->high), "+&r"(c->code_word) + : "r"(low_shift), "r"(low), "r"(code_word) + ); + + return bit; +} +#endif + +#endif /* AVCODEC_X86_VP56_ARITH_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp6dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp6dsp_init.c new file mode 100644 index 0000000000..ce498931d0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp6dsp_init.c @@ -0,0 +1,45 @@ +/* + * VP6 MMX/SSE2 optimizations + * Copyright (C) 2009 Sebastien Lucas + * Copyright (C) 2009 Zuxy Meng + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/vp56dsp.h" + +void ff_vp6_filter_diag4_mmx(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + const int16_t *h_weights,const int16_t *v_weights); +void ff_vp6_filter_diag4_sse2(uint8_t *dst, uint8_t *src, ptrdiff_t stride, + const int16_t *h_weights,const int16_t *v_weights); + +av_cold void ff_vp6dsp_init_x86(VP56DSPContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + +#if ARCH_X86_32 + if (EXTERNAL_MMX(cpu_flags)) { + c->vp6_filter_diag4 = ff_vp6_filter_diag4_mmx; + } +#endif + if (EXTERNAL_SSE2(cpu_flags)) { + c->vp6_filter_diag4 = ff_vp6_filter_diag4_sse2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp8dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp8dsp_init.c new file mode 100644 index 0000000000..397b2518cb --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp8dsp_init.c @@ -0,0 +1,467 @@ +/* + * VP8 DSP functions x86-optimized + * Copyright (c) 2010 Ronald S. Bultje + * Copyright (c) 2010 Fiona Glaser + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/mem.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/vp8dsp.h" + +#if HAVE_X86ASM + +/* + * MC functions + */ +void ff_put_vp8_epel4_h4_mmxext(uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel4_h6_mmxext(uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel4_v4_mmxext(uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel4_v6_mmxext(uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); + +void ff_put_vp8_epel8_h4_sse2 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel8_h6_sse2 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel8_v4_sse2 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel8_v6_sse2 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); + +void ff_put_vp8_epel4_h4_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel4_h6_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel4_v4_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel4_v6_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel8_h4_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel8_h6_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel8_v4_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_epel8_v6_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); + +void ff_put_vp8_bilinear4_h_mmxext(uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_bilinear8_h_sse2 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_bilinear4_h_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_bilinear8_h_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); + +void ff_put_vp8_bilinear4_v_mmxext(uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_bilinear8_v_sse2 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_bilinear4_v_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_bilinear8_v_ssse3 (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); + + +void ff_put_vp8_pixels8_mmx (uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_pixels16_mmx(uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); +void ff_put_vp8_pixels16_sse(uint8_t *dst, ptrdiff_t dststride, + uint8_t *src, ptrdiff_t srcstride, + int height, int mx, int my); + +#define TAP_W16(OPT, FILTERTYPE, TAPTYPE) \ +static void ff_put_vp8_ ## FILTERTYPE ## 16_ ## TAPTYPE ## _ ## OPT( \ + uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \ + ptrdiff_t srcstride, int height, int mx, int my) \ +{ \ + ff_put_vp8_ ## FILTERTYPE ## 8_ ## TAPTYPE ## _ ## OPT( \ + dst, dststride, src, srcstride, height, mx, my); \ + ff_put_vp8_ ## FILTERTYPE ## 8_ ## TAPTYPE ## _ ## OPT( \ + dst + 8, dststride, src + 8, srcstride, height, mx, my); \ +} +#define TAP_W8(OPT, FILTERTYPE, TAPTYPE) \ +static void ff_put_vp8_ ## FILTERTYPE ## 8_ ## TAPTYPE ## _ ## OPT( \ + uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \ + ptrdiff_t srcstride, int height, int mx, int my) \ +{ \ + ff_put_vp8_ ## FILTERTYPE ## 4_ ## TAPTYPE ## _ ## OPT( \ + dst, dststride, src, srcstride, height, mx, my); \ + ff_put_vp8_ ## FILTERTYPE ## 4_ ## TAPTYPE ## _ ## OPT( \ + dst + 4, dststride, src + 4, srcstride, height, mx, my); \ +} + +#if ARCH_X86_32 +TAP_W8 (mmxext, epel, h4) +TAP_W8 (mmxext, epel, h6) +TAP_W16(mmxext, epel, h6) +TAP_W8 (mmxext, epel, v4) +TAP_W8 (mmxext, epel, v6) +TAP_W16(mmxext, epel, v6) +TAP_W8 (mmxext, bilinear, h) +TAP_W16(mmxext, bilinear, h) +TAP_W8 (mmxext, bilinear, v) +TAP_W16(mmxext, bilinear, v) +#endif + +TAP_W16(sse2, epel, h6) +TAP_W16(sse2, epel, v6) +TAP_W16(sse2, bilinear, h) +TAP_W16(sse2, bilinear, v) + +TAP_W16(ssse3, epel, h6) +TAP_W16(ssse3, epel, v6) +TAP_W16(ssse3, bilinear, h) +TAP_W16(ssse3, bilinear, v) + +#define HVTAP(OPT, ALIGN, TAPNUMX, TAPNUMY, SIZE, MAXHEIGHT) \ +static void ff_put_vp8_epel ## SIZE ## _h ## TAPNUMX ## v ## TAPNUMY ## _ ## OPT( \ + uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \ + ptrdiff_t srcstride, int height, int mx, int my) \ +{ \ + LOCAL_ALIGNED(ALIGN, uint8_t, tmp, [SIZE * (MAXHEIGHT + TAPNUMY - 1)]); \ + uint8_t *tmpptr = tmp + SIZE * (TAPNUMY / 2 - 1); \ + src -= srcstride * (TAPNUMY / 2 - 1); \ + ff_put_vp8_epel ## SIZE ## _h ## TAPNUMX ## _ ## OPT( \ + tmp, SIZE, src, srcstride, height + TAPNUMY - 1, mx, my); \ + ff_put_vp8_epel ## SIZE ## _v ## TAPNUMY ## _ ## OPT( \ + dst, dststride, tmpptr, SIZE, height, mx, my); \ +} + +#if ARCH_X86_32 +#define HVTAPMMX(x, y) \ +HVTAP(mmxext, 8, x, y, 4, 8) \ +HVTAP(mmxext, 8, x, y, 8, 16) + +HVTAP(mmxext, 8, 6, 6, 16, 16) +#else +#define HVTAPMMX(x, y) \ +HVTAP(mmxext, 8, x, y, 4, 8) +#endif + +HVTAPMMX(4, 4) +HVTAPMMX(4, 6) +HVTAPMMX(6, 4) +HVTAPMMX(6, 6) + +#define HVTAPSSE2(x, y, w) \ +HVTAP(sse2, 16, x, y, w, 16) \ +HVTAP(ssse3, 16, x, y, w, 16) + +HVTAPSSE2(4, 4, 8) +HVTAPSSE2(4, 6, 8) +HVTAPSSE2(6, 4, 8) +HVTAPSSE2(6, 6, 8) +HVTAPSSE2(6, 6, 16) + +HVTAP(ssse3, 16, 4, 4, 4, 8) +HVTAP(ssse3, 16, 4, 6, 4, 8) +HVTAP(ssse3, 16, 6, 4, 4, 8) +HVTAP(ssse3, 16, 6, 6, 4, 8) + +#define HVBILIN(OPT, ALIGN, SIZE, MAXHEIGHT) \ +static void ff_put_vp8_bilinear ## SIZE ## _hv_ ## OPT( \ + uint8_t *dst, ptrdiff_t dststride, uint8_t *src, \ + ptrdiff_t srcstride, int height, int mx, int my) \ +{ \ + LOCAL_ALIGNED(ALIGN, uint8_t, tmp, [SIZE * (MAXHEIGHT + 2)]); \ + ff_put_vp8_bilinear ## SIZE ## _h_ ## OPT( \ + tmp, SIZE, src, srcstride, height + 1, mx, my); \ + ff_put_vp8_bilinear ## SIZE ## _v_ ## OPT( \ + dst, dststride, tmp, SIZE, height, mx, my); \ +} + +HVBILIN(mmxext, 8, 4, 8) +#if ARCH_X86_32 +HVBILIN(mmxext, 8, 8, 16) +HVBILIN(mmxext, 8, 16, 16) +#endif +HVBILIN(sse2, 8, 8, 16) +HVBILIN(sse2, 8, 16, 16) +HVBILIN(ssse3, 8, 4, 8) +HVBILIN(ssse3, 8, 8, 16) +HVBILIN(ssse3, 8, 16, 16) + +void ff_vp8_idct_dc_add_mmx(uint8_t *dst, int16_t block[16], + ptrdiff_t stride); +void ff_vp8_idct_dc_add_sse2(uint8_t *dst, int16_t block[16], + ptrdiff_t stride); +void ff_vp8_idct_dc_add_sse4(uint8_t *dst, int16_t block[16], + ptrdiff_t stride); +void ff_vp8_idct_dc_add4y_mmx(uint8_t *dst, int16_t block[4][16], + ptrdiff_t stride); +void ff_vp8_idct_dc_add4y_sse2(uint8_t *dst, int16_t block[4][16], + ptrdiff_t stride); +void ff_vp8_idct_dc_add4uv_mmx(uint8_t *dst, int16_t block[2][16], + ptrdiff_t stride); +void ff_vp8_luma_dc_wht_mmx(int16_t block[4][4][16], int16_t dc[16]); +void ff_vp8_luma_dc_wht_sse(int16_t block[4][4][16], int16_t dc[16]); +void ff_vp8_idct_add_mmx(uint8_t *dst, int16_t block[16], ptrdiff_t stride); +void ff_vp8_idct_add_sse(uint8_t *dst, int16_t block[16], ptrdiff_t stride); + +#define DECLARE_LOOP_FILTER(NAME) \ +void ff_vp8_v_loop_filter_simple_ ## NAME(uint8_t *dst, \ + ptrdiff_t stride, \ + int flim); \ +void ff_vp8_h_loop_filter_simple_ ## NAME(uint8_t *dst, \ + ptrdiff_t stride, \ + int flim); \ +void ff_vp8_v_loop_filter16y_inner_ ## NAME (uint8_t *dst, \ + ptrdiff_t stride, \ + int e, int i, int hvt); \ +void ff_vp8_h_loop_filter16y_inner_ ## NAME (uint8_t *dst, \ + ptrdiff_t stride, \ + int e, int i, int hvt); \ +void ff_vp8_v_loop_filter8uv_inner_ ## NAME (uint8_t *dstU, \ + uint8_t *dstV, \ + ptrdiff_t s, \ + int e, int i, int hvt); \ +void ff_vp8_h_loop_filter8uv_inner_ ## NAME (uint8_t *dstU, \ + uint8_t *dstV, \ + ptrdiff_t s, \ + int e, int i, int hvt); \ +void ff_vp8_v_loop_filter16y_mbedge_ ## NAME(uint8_t *dst, \ + ptrdiff_t stride, \ + int e, int i, int hvt); \ +void ff_vp8_h_loop_filter16y_mbedge_ ## NAME(uint8_t *dst, \ + ptrdiff_t stride, \ + int e, int i, int hvt); \ +void ff_vp8_v_loop_filter8uv_mbedge_ ## NAME(uint8_t *dstU, \ + uint8_t *dstV, \ + ptrdiff_t s, \ + int e, int i, int hvt); \ +void ff_vp8_h_loop_filter8uv_mbedge_ ## NAME(uint8_t *dstU, \ + uint8_t *dstV, \ + ptrdiff_t s, \ + int e, int i, int hvt); + +DECLARE_LOOP_FILTER(mmx) +DECLARE_LOOP_FILTER(mmxext) +DECLARE_LOOP_FILTER(sse2) +DECLARE_LOOP_FILTER(ssse3) +DECLARE_LOOP_FILTER(sse4) + +#endif /* HAVE_X86ASM */ + +#define VP8_LUMA_MC_FUNC(IDX, SIZE, OPT) \ + c->put_vp8_epel_pixels_tab[IDX][0][2] = ff_put_vp8_epel ## SIZE ## _h6_ ## OPT; \ + c->put_vp8_epel_pixels_tab[IDX][2][0] = ff_put_vp8_epel ## SIZE ## _v6_ ## OPT; \ + c->put_vp8_epel_pixels_tab[IDX][2][2] = ff_put_vp8_epel ## SIZE ## _h6v6_ ## OPT + +#define VP8_MC_FUNC(IDX, SIZE, OPT) \ + c->put_vp8_epel_pixels_tab[IDX][0][1] = ff_put_vp8_epel ## SIZE ## _h4_ ## OPT; \ + c->put_vp8_epel_pixels_tab[IDX][1][0] = ff_put_vp8_epel ## SIZE ## _v4_ ## OPT; \ + c->put_vp8_epel_pixels_tab[IDX][1][1] = ff_put_vp8_epel ## SIZE ## _h4v4_ ## OPT; \ + c->put_vp8_epel_pixels_tab[IDX][1][2] = ff_put_vp8_epel ## SIZE ## _h6v4_ ## OPT; \ + c->put_vp8_epel_pixels_tab[IDX][2][1] = ff_put_vp8_epel ## SIZE ## _h4v6_ ## OPT; \ + VP8_LUMA_MC_FUNC(IDX, SIZE, OPT) + +#define VP8_BILINEAR_MC_FUNC(IDX, SIZE, OPT) \ + c->put_vp8_bilinear_pixels_tab[IDX][0][1] = ff_put_vp8_bilinear ## SIZE ## _h_ ## OPT; \ + c->put_vp8_bilinear_pixels_tab[IDX][0][2] = ff_put_vp8_bilinear ## SIZE ## _h_ ## OPT; \ + c->put_vp8_bilinear_pixels_tab[IDX][1][0] = ff_put_vp8_bilinear ## SIZE ## _v_ ## OPT; \ + c->put_vp8_bilinear_pixels_tab[IDX][1][1] = ff_put_vp8_bilinear ## SIZE ## _hv_ ## OPT; \ + c->put_vp8_bilinear_pixels_tab[IDX][1][2] = ff_put_vp8_bilinear ## SIZE ## _hv_ ## OPT; \ + c->put_vp8_bilinear_pixels_tab[IDX][2][0] = ff_put_vp8_bilinear ## SIZE ## _v_ ## OPT; \ + c->put_vp8_bilinear_pixels_tab[IDX][2][1] = ff_put_vp8_bilinear ## SIZE ## _hv_ ## OPT; \ + c->put_vp8_bilinear_pixels_tab[IDX][2][2] = ff_put_vp8_bilinear ## SIZE ## _hv_ ## OPT + + +av_cold void ff_vp78dsp_init_x86(VP8DSPContext *c) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { +#if ARCH_X86_32 + c->put_vp8_epel_pixels_tab[0][0][0] = + c->put_vp8_bilinear_pixels_tab[0][0][0] = ff_put_vp8_pixels16_mmx; +#endif + c->put_vp8_epel_pixels_tab[1][0][0] = + c->put_vp8_bilinear_pixels_tab[1][0][0] = ff_put_vp8_pixels8_mmx; + } + + /* note that 4-tap width=16 functions are missing because w=16 + * is only used for luma, and luma is always a copy or sixtap. */ + if (EXTERNAL_MMXEXT(cpu_flags)) { + VP8_MC_FUNC(2, 4, mmxext); + VP8_BILINEAR_MC_FUNC(2, 4, mmxext); +#if ARCH_X86_32 + VP8_LUMA_MC_FUNC(0, 16, mmxext); + VP8_MC_FUNC(1, 8, mmxext); + VP8_BILINEAR_MC_FUNC(0, 16, mmxext); + VP8_BILINEAR_MC_FUNC(1, 8, mmxext); +#endif + } + + if (EXTERNAL_SSE(cpu_flags)) { + c->put_vp8_epel_pixels_tab[0][0][0] = + c->put_vp8_bilinear_pixels_tab[0][0][0] = ff_put_vp8_pixels16_sse; + } + + if (EXTERNAL_SSE2(cpu_flags) || EXTERNAL_SSE2_SLOW(cpu_flags)) { + VP8_LUMA_MC_FUNC(0, 16, sse2); + VP8_MC_FUNC(1, 8, sse2); + VP8_BILINEAR_MC_FUNC(0, 16, sse2); + VP8_BILINEAR_MC_FUNC(1, 8, sse2); + } + + if (EXTERNAL_SSSE3(cpu_flags)) { + VP8_LUMA_MC_FUNC(0, 16, ssse3); + VP8_MC_FUNC(1, 8, ssse3); + VP8_MC_FUNC(2, 4, ssse3); + VP8_BILINEAR_MC_FUNC(0, 16, ssse3); + VP8_BILINEAR_MC_FUNC(1, 8, ssse3); + VP8_BILINEAR_MC_FUNC(2, 4, ssse3); + } +#endif /* HAVE_X86ASM */ +} + +av_cold void ff_vp8dsp_init_x86(VP8DSPContext *c) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + c->vp8_idct_dc_add4uv = ff_vp8_idct_dc_add4uv_mmx; +#if ARCH_X86_32 + c->vp8_idct_dc_add = ff_vp8_idct_dc_add_mmx; + c->vp8_idct_dc_add4y = ff_vp8_idct_dc_add4y_mmx; + c->vp8_idct_add = ff_vp8_idct_add_mmx; + c->vp8_luma_dc_wht = ff_vp8_luma_dc_wht_mmx; + + c->vp8_v_loop_filter_simple = ff_vp8_v_loop_filter_simple_mmx; + c->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter_simple_mmx; + + c->vp8_v_loop_filter16y_inner = ff_vp8_v_loop_filter16y_inner_mmx; + c->vp8_h_loop_filter16y_inner = ff_vp8_h_loop_filter16y_inner_mmx; + c->vp8_v_loop_filter8uv_inner = ff_vp8_v_loop_filter8uv_inner_mmx; + c->vp8_h_loop_filter8uv_inner = ff_vp8_h_loop_filter8uv_inner_mmx; + + c->vp8_v_loop_filter16y = ff_vp8_v_loop_filter16y_mbedge_mmx; + c->vp8_h_loop_filter16y = ff_vp8_h_loop_filter16y_mbedge_mmx; + c->vp8_v_loop_filter8uv = ff_vp8_v_loop_filter8uv_mbedge_mmx; + c->vp8_h_loop_filter8uv = ff_vp8_h_loop_filter8uv_mbedge_mmx; +#endif + } + + /* note that 4-tap width=16 functions are missing because w=16 + * is only used for luma, and luma is always a copy or sixtap. */ + if (EXTERNAL_MMXEXT(cpu_flags)) { +#if ARCH_X86_32 + c->vp8_v_loop_filter_simple = ff_vp8_v_loop_filter_simple_mmxext; + c->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter_simple_mmxext; + + c->vp8_v_loop_filter16y_inner = ff_vp8_v_loop_filter16y_inner_mmxext; + c->vp8_h_loop_filter16y_inner = ff_vp8_h_loop_filter16y_inner_mmxext; + c->vp8_v_loop_filter8uv_inner = ff_vp8_v_loop_filter8uv_inner_mmxext; + c->vp8_h_loop_filter8uv_inner = ff_vp8_h_loop_filter8uv_inner_mmxext; + + c->vp8_v_loop_filter16y = ff_vp8_v_loop_filter16y_mbedge_mmxext; + c->vp8_h_loop_filter16y = ff_vp8_h_loop_filter16y_mbedge_mmxext; + c->vp8_v_loop_filter8uv = ff_vp8_v_loop_filter8uv_mbedge_mmxext; + c->vp8_h_loop_filter8uv = ff_vp8_h_loop_filter8uv_mbedge_mmxext; +#endif + } + + if (EXTERNAL_SSE(cpu_flags)) { + c->vp8_idct_add = ff_vp8_idct_add_sse; + c->vp8_luma_dc_wht = ff_vp8_luma_dc_wht_sse; + } + + if (EXTERNAL_SSE2(cpu_flags) || EXTERNAL_SSE2_SLOW(cpu_flags)) { + c->vp8_v_loop_filter_simple = ff_vp8_v_loop_filter_simple_sse2; + + c->vp8_v_loop_filter16y_inner = ff_vp8_v_loop_filter16y_inner_sse2; + c->vp8_v_loop_filter8uv_inner = ff_vp8_v_loop_filter8uv_inner_sse2; + + c->vp8_v_loop_filter16y = ff_vp8_v_loop_filter16y_mbedge_sse2; + c->vp8_v_loop_filter8uv = ff_vp8_v_loop_filter8uv_mbedge_sse2; + } + + if (EXTERNAL_SSE2(cpu_flags)) { + c->vp8_idct_dc_add = ff_vp8_idct_dc_add_sse2; + c->vp8_idct_dc_add4y = ff_vp8_idct_dc_add4y_sse2; + + c->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter_simple_sse2; + + c->vp8_h_loop_filter16y_inner = ff_vp8_h_loop_filter16y_inner_sse2; + c->vp8_h_loop_filter8uv_inner = ff_vp8_h_loop_filter8uv_inner_sse2; + + c->vp8_h_loop_filter16y = ff_vp8_h_loop_filter16y_mbedge_sse2; + c->vp8_h_loop_filter8uv = ff_vp8_h_loop_filter8uv_mbedge_sse2; + } + + if (EXTERNAL_SSSE3(cpu_flags)) { + c->vp8_v_loop_filter_simple = ff_vp8_v_loop_filter_simple_ssse3; + c->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter_simple_ssse3; + + c->vp8_v_loop_filter16y_inner = ff_vp8_v_loop_filter16y_inner_ssse3; + c->vp8_h_loop_filter16y_inner = ff_vp8_h_loop_filter16y_inner_ssse3; + c->vp8_v_loop_filter8uv_inner = ff_vp8_v_loop_filter8uv_inner_ssse3; + c->vp8_h_loop_filter8uv_inner = ff_vp8_h_loop_filter8uv_inner_ssse3; + + c->vp8_v_loop_filter16y = ff_vp8_v_loop_filter16y_mbedge_ssse3; + c->vp8_h_loop_filter16y = ff_vp8_h_loop_filter16y_mbedge_ssse3; + c->vp8_v_loop_filter8uv = ff_vp8_v_loop_filter8uv_mbedge_ssse3; + c->vp8_h_loop_filter8uv = ff_vp8_h_loop_filter8uv_mbedge_ssse3; + } + + if (EXTERNAL_SSE4(cpu_flags)) { + c->vp8_idct_dc_add = ff_vp8_idct_dc_add_sse4; + + c->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter_simple_sse4; + c->vp8_h_loop_filter16y = ff_vp8_h_loop_filter16y_mbedge_sse4; + c->vp8_h_loop_filter8uv = ff_vp8_h_loop_filter8uv_mbedge_sse4; + } +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init.c new file mode 100644 index 0000000000..837cce8508 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init.c @@ -0,0 +1,416 @@ +/* + * VP9 SIMD optimizations + * + * Copyright (c) 2013 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/mem.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/vp9dsp.h" +#include "libavcodec/x86/vp9dsp_init.h" + +#if HAVE_X86ASM + +decl_fpel_func(put, 4, , mmx); +decl_fpel_func(put, 8, , mmx); +decl_fpel_func(put, 16, , sse); +decl_fpel_func(put, 32, , sse); +decl_fpel_func(put, 64, , sse); +decl_fpel_func(avg, 4, _8, mmxext); +decl_fpel_func(avg, 8, _8, mmxext); +decl_fpel_func(avg, 16, _8, sse2); +decl_fpel_func(avg, 32, _8, sse2); +decl_fpel_func(avg, 64, _8, sse2); +decl_fpel_func(put, 32, , avx); +decl_fpel_func(put, 64, , avx); +decl_fpel_func(avg, 32, _8, avx2); +decl_fpel_func(avg, 64, _8, avx2); + +decl_mc_funcs(4, mmxext, int16_t, 8, 8); +decl_mc_funcs(8, sse2, int16_t, 8, 8); +decl_mc_funcs(4, ssse3, int8_t, 32, 8); +decl_mc_funcs(8, ssse3, int8_t, 32, 8); +#if ARCH_X86_64 +decl_mc_funcs(16, ssse3, int8_t, 32, 8); +decl_mc_funcs(32, avx2, int8_t, 32, 8); +#endif + +mc_rep_funcs(16, 8, 8, sse2, int16_t, 8, 8) +#if ARCH_X86_32 +mc_rep_funcs(16, 8, 8, ssse3, int8_t, 32, 8) +#endif +mc_rep_funcs(32, 16, 16, sse2, int16_t, 8, 8) +mc_rep_funcs(32, 16, 16, ssse3, int8_t, 32, 8) +mc_rep_funcs(64, 32, 32, sse2, int16_t, 8, 8) +mc_rep_funcs(64, 32, 32, ssse3, int8_t, 32, 8) +#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL +mc_rep_funcs(64, 32, 32, avx2, int8_t, 32, 8) +#endif + +extern const int8_t ff_filters_ssse3[3][15][4][32]; +extern const int16_t ff_filters_sse2[3][15][8][8]; + +filters_8tap_2d_fn2(put, 16, 8, 1, mmxext, sse2, sse2) +filters_8tap_2d_fn2(avg, 16, 8, 1, mmxext, sse2, sse2) +filters_8tap_2d_fn2(put, 16, 8, 1, ssse3, ssse3, ssse3) +filters_8tap_2d_fn2(avg, 16, 8, 1, ssse3, ssse3, ssse3) +#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL +filters_8tap_2d_fn(put, 64, 32, 8, 1, avx2, ssse3) +filters_8tap_2d_fn(put, 32, 32, 8, 1, avx2, ssse3) +filters_8tap_2d_fn(avg, 64, 32, 8, 1, avx2, ssse3) +filters_8tap_2d_fn(avg, 32, 32, 8, 1, avx2, ssse3) +#endif + +filters_8tap_1d_fn3(put, 8, mmxext, sse2, sse2) +filters_8tap_1d_fn3(avg, 8, mmxext, sse2, sse2) +filters_8tap_1d_fn3(put, 8, ssse3, ssse3, ssse3) +filters_8tap_1d_fn3(avg, 8, ssse3, ssse3, ssse3) +#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL +filters_8tap_1d_fn2(put, 64, 8, avx2, ssse3) +filters_8tap_1d_fn2(put, 32, 8, avx2, ssse3) +filters_8tap_1d_fn2(avg, 64, 8, avx2, ssse3) +filters_8tap_1d_fn2(avg, 32, 8, avx2, ssse3) +#endif + +#define itxfm_func(typea, typeb, size, opt) \ +void ff_vp9_##typea##_##typeb##_##size##x##size##_add_##opt(uint8_t *dst, ptrdiff_t stride, \ + int16_t *block, int eob) +#define itxfm_funcs(size, opt) \ +itxfm_func(idct, idct, size, opt); \ +itxfm_func(iadst, idct, size, opt); \ +itxfm_func(idct, iadst, size, opt); \ +itxfm_func(iadst, iadst, size, opt) + +itxfm_func(idct, idct, 4, mmxext); +itxfm_func(idct, iadst, 4, sse2); +itxfm_func(iadst, idct, 4, sse2); +itxfm_func(iadst, iadst, 4, sse2); +itxfm_funcs(4, ssse3); +itxfm_funcs(8, sse2); +itxfm_funcs(8, ssse3); +itxfm_funcs(8, avx); +itxfm_funcs(16, sse2); +itxfm_funcs(16, ssse3); +itxfm_funcs(16, avx); +itxfm_func(idct, idct, 32, sse2); +itxfm_func(idct, idct, 32, ssse3); +itxfm_func(idct, idct, 32, avx); +itxfm_func(iwht, iwht, 4, mmx); +itxfm_funcs(16, avx2); +itxfm_func(idct, idct, 32, avx2); + +#undef itxfm_func +#undef itxfm_funcs + +#define lpf_funcs(size1, size2, opt) \ +void ff_vp9_loop_filter_v_##size1##_##size2##_##opt(uint8_t *dst, ptrdiff_t stride, \ + int E, int I, int H); \ +void ff_vp9_loop_filter_h_##size1##_##size2##_##opt(uint8_t *dst, ptrdiff_t stride, \ + int E, int I, int H) + +lpf_funcs(4, 8, mmxext); +lpf_funcs(8, 8, mmxext); +lpf_funcs(16, 16, sse2); +lpf_funcs(16, 16, ssse3); +lpf_funcs(16, 16, avx); +lpf_funcs(44, 16, sse2); +lpf_funcs(44, 16, ssse3); +lpf_funcs(44, 16, avx); +lpf_funcs(84, 16, sse2); +lpf_funcs(84, 16, ssse3); +lpf_funcs(84, 16, avx); +lpf_funcs(48, 16, sse2); +lpf_funcs(48, 16, ssse3); +lpf_funcs(48, 16, avx); +lpf_funcs(88, 16, sse2); +lpf_funcs(88, 16, ssse3); +lpf_funcs(88, 16, avx); + +#undef lpf_funcs + +#define ipred_func(size, type, opt) \ +void ff_vp9_ipred_##type##_##size##x##size##_##opt(uint8_t *dst, ptrdiff_t stride, \ + const uint8_t *l, const uint8_t *a) + +ipred_func(8, v, mmx); + +#define ipred_dc_funcs(size, opt) \ +ipred_func(size, dc, opt); \ +ipred_func(size, dc_left, opt); \ +ipred_func(size, dc_top, opt) + +ipred_dc_funcs(4, mmxext); +ipred_dc_funcs(8, mmxext); + +#define ipred_dir_tm_funcs(size, opt) \ +ipred_func(size, tm, opt); \ +ipred_func(size, dl, opt); \ +ipred_func(size, dr, opt); \ +ipred_func(size, hd, opt); \ +ipred_func(size, hu, opt); \ +ipred_func(size, vl, opt); \ +ipred_func(size, vr, opt) + +ipred_dir_tm_funcs(4, mmxext); + +ipred_func(16, v, sse); +ipred_func(32, v, sse); + +ipred_dc_funcs(16, sse2); +ipred_dc_funcs(32, sse2); + +#define ipred_dir_tm_h_funcs(size, opt) \ +ipred_dir_tm_funcs(size, opt); \ +ipred_func(size, h, opt) + +ipred_dir_tm_h_funcs(8, sse2); +ipred_dir_tm_h_funcs(16, sse2); +ipred_dir_tm_h_funcs(32, sse2); + +ipred_func(4, h, sse2); + +#define ipred_all_funcs(size, opt) \ +ipred_dc_funcs(size, opt); \ +ipred_dir_tm_h_funcs(size, opt) + +// FIXME hd/vl_4x4_ssse3 does not exist +ipred_all_funcs(4, ssse3); +ipred_all_funcs(8, ssse3); +ipred_all_funcs(16, ssse3); +ipred_all_funcs(32, ssse3); + +ipred_dir_tm_h_funcs(8, avx); +ipred_dir_tm_h_funcs(16, avx); +ipred_dir_tm_h_funcs(32, avx); + +ipred_func(32, v, avx); + +ipred_dc_funcs(32, avx2); +ipred_func(32, h, avx2); +ipred_func(32, tm, avx2); + +#undef ipred_func +#undef ipred_dir_tm_h_funcs +#undef ipred_dir_tm_funcs +#undef ipred_dc_funcs + +#endif /* HAVE_X86ASM */ + +av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) +{ +#if HAVE_X86ASM + int cpu_flags; + + if (bpp == 10) { + ff_vp9dsp_init_10bpp_x86(dsp, bitexact); + return; + } else if (bpp == 12) { + ff_vp9dsp_init_12bpp_x86(dsp, bitexact); + return; + } + + cpu_flags = av_get_cpu_flags(); + +#define init_lpf(opt) do { \ + dsp->loop_filter_16[0] = ff_vp9_loop_filter_h_16_16_##opt; \ + dsp->loop_filter_16[1] = ff_vp9_loop_filter_v_16_16_##opt; \ + dsp->loop_filter_mix2[0][0][0] = ff_vp9_loop_filter_h_44_16_##opt; \ + dsp->loop_filter_mix2[0][0][1] = ff_vp9_loop_filter_v_44_16_##opt; \ + dsp->loop_filter_mix2[0][1][0] = ff_vp9_loop_filter_h_48_16_##opt; \ + dsp->loop_filter_mix2[0][1][1] = ff_vp9_loop_filter_v_48_16_##opt; \ + dsp->loop_filter_mix2[1][0][0] = ff_vp9_loop_filter_h_84_16_##opt; \ + dsp->loop_filter_mix2[1][0][1] = ff_vp9_loop_filter_v_84_16_##opt; \ + dsp->loop_filter_mix2[1][1][0] = ff_vp9_loop_filter_h_88_16_##opt; \ + dsp->loop_filter_mix2[1][1][1] = ff_vp9_loop_filter_v_88_16_##opt; \ +} while (0) + +#define init_ipred(sz, opt, t, e) \ + dsp->intra_pred[TX_##sz##X##sz][e##_PRED] = ff_vp9_ipred_##t##_##sz##x##sz##_##opt + +#define ff_vp9_ipred_hd_4x4_ssse3 ff_vp9_ipred_hd_4x4_mmxext +#define ff_vp9_ipred_vl_4x4_ssse3 ff_vp9_ipred_vl_4x4_mmxext +#define init_dir_tm_ipred(sz, opt) do { \ + init_ipred(sz, opt, dl, DIAG_DOWN_LEFT); \ + init_ipred(sz, opt, dr, DIAG_DOWN_RIGHT); \ + init_ipred(sz, opt, hd, HOR_DOWN); \ + init_ipred(sz, opt, vl, VERT_LEFT); \ + init_ipred(sz, opt, hu, HOR_UP); \ + init_ipred(sz, opt, tm, TM_VP8); \ + init_ipred(sz, opt, vr, VERT_RIGHT); \ +} while (0) +#define init_dir_tm_h_ipred(sz, opt) do { \ + init_dir_tm_ipred(sz, opt); \ + init_ipred(sz, opt, h, HOR); \ +} while (0) +#define init_dc_ipred(sz, opt) do { \ + init_ipred(sz, opt, dc, DC); \ + init_ipred(sz, opt, dc_left, LEFT_DC); \ + init_ipred(sz, opt, dc_top, TOP_DC); \ +} while (0) +#define init_all_ipred(sz, opt) do { \ + init_dc_ipred(sz, opt); \ + init_dir_tm_h_ipred(sz, opt); \ +} while (0) + + if (EXTERNAL_MMX(cpu_flags)) { + init_fpel_func(4, 0, 4, put, , mmx); + init_fpel_func(3, 0, 8, put, , mmx); + if (!bitexact) { + dsp->itxfm_add[4 /* lossless */][DCT_DCT] = + dsp->itxfm_add[4 /* lossless */][ADST_DCT] = + dsp->itxfm_add[4 /* lossless */][DCT_ADST] = + dsp->itxfm_add[4 /* lossless */][ADST_ADST] = ff_vp9_iwht_iwht_4x4_add_mmx; + } + init_ipred(8, mmx, v, VERT); + } + + if (EXTERNAL_MMXEXT(cpu_flags)) { + dsp->loop_filter_8[0][0] = ff_vp9_loop_filter_h_4_8_mmxext; + dsp->loop_filter_8[0][1] = ff_vp9_loop_filter_v_4_8_mmxext; + dsp->loop_filter_8[1][0] = ff_vp9_loop_filter_h_8_8_mmxext; + dsp->loop_filter_8[1][1] = ff_vp9_loop_filter_v_8_8_mmxext; + init_subpel2(4, 0, 4, put, 8, mmxext); + init_subpel2(4, 1, 4, avg, 8, mmxext); + init_fpel_func(4, 1, 4, avg, _8, mmxext); + init_fpel_func(3, 1, 8, avg, _8, mmxext); + dsp->itxfm_add[TX_4X4][DCT_DCT] = ff_vp9_idct_idct_4x4_add_mmxext; + init_dc_ipred(4, mmxext); + init_dc_ipred(8, mmxext); + init_dir_tm_ipred(4, mmxext); + } + + if (EXTERNAL_SSE(cpu_flags)) { + init_fpel_func(2, 0, 16, put, , sse); + init_fpel_func(1, 0, 32, put, , sse); + init_fpel_func(0, 0, 64, put, , sse); + init_ipred(16, sse, v, VERT); + init_ipred(32, sse, v, VERT); + } + + if (EXTERNAL_SSE2(cpu_flags)) { + init_subpel3_8to64(0, put, 8, sse2); + init_subpel3_8to64(1, avg, 8, sse2); + init_fpel_func(2, 1, 16, avg, _8, sse2); + init_fpel_func(1, 1, 32, avg, _8, sse2); + init_fpel_func(0, 1, 64, avg, _8, sse2); + init_lpf(sse2); + dsp->itxfm_add[TX_4X4][ADST_DCT] = ff_vp9_idct_iadst_4x4_add_sse2; + dsp->itxfm_add[TX_4X4][DCT_ADST] = ff_vp9_iadst_idct_4x4_add_sse2; + dsp->itxfm_add[TX_4X4][ADST_ADST] = ff_vp9_iadst_iadst_4x4_add_sse2; + dsp->itxfm_add[TX_8X8][DCT_DCT] = ff_vp9_idct_idct_8x8_add_sse2; + dsp->itxfm_add[TX_8X8][ADST_DCT] = ff_vp9_idct_iadst_8x8_add_sse2; + dsp->itxfm_add[TX_8X8][DCT_ADST] = ff_vp9_iadst_idct_8x8_add_sse2; + dsp->itxfm_add[TX_8X8][ADST_ADST] = ff_vp9_iadst_iadst_8x8_add_sse2; + dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_sse2; + dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_sse2; + dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_sse2; + dsp->itxfm_add[TX_16X16][ADST_ADST] = ff_vp9_iadst_iadst_16x16_add_sse2; + dsp->itxfm_add[TX_32X32][ADST_ADST] = + dsp->itxfm_add[TX_32X32][ADST_DCT] = + dsp->itxfm_add[TX_32X32][DCT_ADST] = + dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_sse2; + init_dc_ipred(16, sse2); + init_dc_ipred(32, sse2); + init_dir_tm_h_ipred(8, sse2); + init_dir_tm_h_ipred(16, sse2); + init_dir_tm_h_ipred(32, sse2); + init_ipred(4, sse2, h, HOR); + } + + if (EXTERNAL_SSSE3(cpu_flags)) { + init_subpel3(0, put, 8, ssse3); + init_subpel3(1, avg, 8, ssse3); + dsp->itxfm_add[TX_4X4][DCT_DCT] = ff_vp9_idct_idct_4x4_add_ssse3; + dsp->itxfm_add[TX_4X4][ADST_DCT] = ff_vp9_idct_iadst_4x4_add_ssse3; + dsp->itxfm_add[TX_4X4][DCT_ADST] = ff_vp9_iadst_idct_4x4_add_ssse3; + dsp->itxfm_add[TX_4X4][ADST_ADST] = ff_vp9_iadst_iadst_4x4_add_ssse3; + dsp->itxfm_add[TX_8X8][DCT_DCT] = ff_vp9_idct_idct_8x8_add_ssse3; + dsp->itxfm_add[TX_8X8][ADST_DCT] = ff_vp9_idct_iadst_8x8_add_ssse3; + dsp->itxfm_add[TX_8X8][DCT_ADST] = ff_vp9_iadst_idct_8x8_add_ssse3; + dsp->itxfm_add[TX_8X8][ADST_ADST] = ff_vp9_iadst_iadst_8x8_add_ssse3; + dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_ssse3; + dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_ssse3; + dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_ssse3; + dsp->itxfm_add[TX_16X16][ADST_ADST] = ff_vp9_iadst_iadst_16x16_add_ssse3; + dsp->itxfm_add[TX_32X32][ADST_ADST] = + dsp->itxfm_add[TX_32X32][ADST_DCT] = + dsp->itxfm_add[TX_32X32][DCT_ADST] = + dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_ssse3; + init_lpf(ssse3); + init_all_ipred(4, ssse3); + init_all_ipred(8, ssse3); + init_all_ipred(16, ssse3); + init_all_ipred(32, ssse3); + } + + if (EXTERNAL_AVX(cpu_flags)) { + dsp->itxfm_add[TX_8X8][DCT_DCT] = ff_vp9_idct_idct_8x8_add_avx; + dsp->itxfm_add[TX_8X8][ADST_DCT] = ff_vp9_idct_iadst_8x8_add_avx; + dsp->itxfm_add[TX_8X8][DCT_ADST] = ff_vp9_iadst_idct_8x8_add_avx; + dsp->itxfm_add[TX_8X8][ADST_ADST] = ff_vp9_iadst_iadst_8x8_add_avx; + dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_avx; + dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_avx; + dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_avx; + dsp->itxfm_add[TX_16X16][ADST_ADST] = ff_vp9_iadst_iadst_16x16_add_avx; + dsp->itxfm_add[TX_32X32][ADST_ADST] = + dsp->itxfm_add[TX_32X32][ADST_DCT] = + dsp->itxfm_add[TX_32X32][DCT_ADST] = + dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_avx; + init_lpf(avx); + init_dir_tm_h_ipred(8, avx); + init_dir_tm_h_ipred(16, avx); + init_dir_tm_h_ipred(32, avx); + } + if (EXTERNAL_AVX_FAST(cpu_flags)) { + init_fpel_func(1, 0, 32, put, , avx); + init_fpel_func(0, 0, 64, put, , avx); + init_ipred(32, avx, v, VERT); + } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + init_fpel_func(1, 1, 32, avg, _8, avx2); + init_fpel_func(0, 1, 64, avg, _8, avx2); + if (ARCH_X86_64) { +#if ARCH_X86_64 && HAVE_AVX2_EXTERNAL + dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_avx2; + dsp->itxfm_add[TX_16X16][ADST_DCT] = ff_vp9_idct_iadst_16x16_add_avx2; + dsp->itxfm_add[TX_16X16][DCT_ADST] = ff_vp9_iadst_idct_16x16_add_avx2; + dsp->itxfm_add[TX_16X16][ADST_ADST] = ff_vp9_iadst_iadst_16x16_add_avx2; + dsp->itxfm_add[TX_32X32][ADST_ADST] = + dsp->itxfm_add[TX_32X32][ADST_DCT] = + dsp->itxfm_add[TX_32X32][DCT_ADST] = + dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_avx2; + init_subpel3_32_64(0, put, 8, avx2); + init_subpel3_32_64(1, avg, 8, avx2); +#endif + } + init_dc_ipred(32, avx2); + init_ipred(32, avx2, h, HOR); + init_ipred(32, avx2, tm, TM_VP8); + } + +#undef init_fpel +#undef init_subpel1 +#undef init_subpel2 +#undef init_subpel3 + +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init.h new file mode 100644 index 0000000000..e410cab3a1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init.h @@ -0,0 +1,189 @@ +/* + * VP9 SIMD optimizations + * + * Copyright (c) 2013 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_X86_VP9DSP_INIT_H +#define AVCODEC_X86_VP9DSP_INIT_H + +#include "libavcodec/vp9dsp.h" + +// hack to force-expand BPC +#define cat(a, bpp, b) a##bpp##b + +#define decl_fpel_func(avg, sz, bpp, opt) \ +void ff_vp9_##avg##sz##bpp##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, int mx, int my) + +#define decl_mc_func(avg, sz, dir, opt, type, f_sz, bpp) \ +void ff_vp9_##avg##_8tap_1d_##dir##_##sz##_##bpp##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, const type (*filter)[f_sz]) + +#define decl_mc_funcs(sz, opt, type, fsz, bpp) \ +decl_mc_func(put, sz, h, opt, type, fsz, bpp); \ +decl_mc_func(avg, sz, h, opt, type, fsz, bpp); \ +decl_mc_func(put, sz, v, opt, type, fsz, bpp); \ +decl_mc_func(avg, sz, v, opt, type, fsz, bpp) + +#define decl_ipred_fn(type, sz, bpp, opt) \ +void ff_vp9_ipred_##type##_##sz##x##sz##_##bpp##_##opt(uint8_t *dst, \ + ptrdiff_t stride, \ + const uint8_t *l, \ + const uint8_t *a) + +#define decl_ipred_fns(type, bpp, opt4, opt8_16_32) \ +decl_ipred_fn(type, 4, bpp, opt4); \ +decl_ipred_fn(type, 8, bpp, opt8_16_32); \ +decl_ipred_fn(type, 16, bpp, opt8_16_32); \ +decl_ipred_fn(type, 32, bpp, opt8_16_32) + +#define decl_itxfm_func(typea, typeb, size, bpp, opt) \ +void cat(ff_vp9_##typea##_##typeb##_##size##x##size##_add_, bpp, _##opt)(uint8_t *dst, \ + ptrdiff_t stride, \ + int16_t *block, \ + int eob) + +#define decl_itxfm_funcs(size, bpp, opt) \ +decl_itxfm_func(idct, idct, size, bpp, opt); \ +decl_itxfm_func(iadst, idct, size, bpp, opt); \ +decl_itxfm_func(idct, iadst, size, bpp, opt); \ +decl_itxfm_func(iadst, iadst, size, bpp, opt) + +#define mc_rep_func(avg, sz, hsz, hszb, dir, opt, type, f_sz, bpp) \ +static av_always_inline void \ +ff_vp9_##avg##_8tap_1d_##dir##_##sz##_##bpp##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, const type (*filter)[f_sz]) \ +{ \ + ff_vp9_##avg##_8tap_1d_##dir##_##hsz##_##bpp##_##opt(dst, dst_stride, src, \ + src_stride, h, filter); \ + ff_vp9_##avg##_8tap_1d_##dir##_##hsz##_##bpp##_##opt(dst + hszb, dst_stride, src + hszb, \ + src_stride, h, filter); \ +} + +#define mc_rep_funcs(sz, hsz, hszb, opt, type, fsz, bpp) \ +mc_rep_func(put, sz, hsz, hszb, h, opt, type, fsz, bpp) \ +mc_rep_func(avg, sz, hsz, hszb, h, opt, type, fsz, bpp) \ +mc_rep_func(put, sz, hsz, hszb, v, opt, type, fsz, bpp) \ +mc_rep_func(avg, sz, hsz, hszb, v, opt, type, fsz, bpp) + +#define filter_8tap_1d_fn(op, sz, f, f_opt, fname, dir, dvar, bpp, opt) \ +static void op##_8tap_##fname##_##sz##dir##_##bpp##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, int mx, int my) \ +{ \ + ff_vp9_##op##_8tap_1d_##dir##_##sz##_##bpp##_##opt(dst, dst_stride, src, src_stride, \ + h, ff_filters_##f_opt[f][dvar - 1]); \ +} + +#define filters_8tap_1d_fn(op, sz, dir, dvar, bpp, opt, f_opt) \ +filter_8tap_1d_fn(op, sz, FILTER_8TAP_REGULAR, f_opt, regular, dir, dvar, bpp, opt) \ +filter_8tap_1d_fn(op, sz, FILTER_8TAP_SHARP, f_opt, sharp, dir, dvar, bpp, opt) \ +filter_8tap_1d_fn(op, sz, FILTER_8TAP_SMOOTH, f_opt, smooth, dir, dvar, bpp, opt) + +#define filters_8tap_1d_fn2(op, sz, bpp, opt, f_opt) \ +filters_8tap_1d_fn(op, sz, h, mx, bpp, opt, f_opt) \ +filters_8tap_1d_fn(op, sz, v, my, bpp, opt, f_opt) + +#define filters_8tap_1d_fn3(op, bpp, opt4, opt8, f_opt) \ +filters_8tap_1d_fn2(op, 64, bpp, opt8, f_opt) \ +filters_8tap_1d_fn2(op, 32, bpp, opt8, f_opt) \ +filters_8tap_1d_fn2(op, 16, bpp, opt8, f_opt) \ +filters_8tap_1d_fn2(op, 8, bpp, opt8, f_opt) \ +filters_8tap_1d_fn2(op, 4, bpp, opt4, f_opt) + +#define filter_8tap_2d_fn(op, sz, f, f_opt, fname, align, bpp, bytes, opt) \ +static void op##_8tap_##fname##_##sz##hv_##bpp##_##opt(uint8_t *dst, ptrdiff_t dst_stride, \ + const uint8_t *src, ptrdiff_t src_stride, \ + int h, int mx, int my) \ +{ \ + LOCAL_ALIGNED_##align(uint8_t, temp, [71 * 64 * bytes]); \ + ff_vp9_put_8tap_1d_h_##sz##_##bpp##_##opt(temp, 64 * bytes, src - 3 * src_stride, \ + src_stride, h + 7, \ + ff_filters_##f_opt[f][mx - 1]); \ + ff_vp9_##op##_8tap_1d_v_##sz##_##bpp##_##opt(dst, dst_stride, temp + 3 * bytes * 64, \ + 64 * bytes, h, \ + ff_filters_##f_opt[f][my - 1]); \ +} + +#define filters_8tap_2d_fn(op, sz, align, bpp, bytes, opt, f_opt) \ +filter_8tap_2d_fn(op, sz, FILTER_8TAP_REGULAR, f_opt, regular, align, bpp, bytes, opt) \ +filter_8tap_2d_fn(op, sz, FILTER_8TAP_SHARP, f_opt, sharp, align, bpp, bytes, opt) \ +filter_8tap_2d_fn(op, sz, FILTER_8TAP_SMOOTH, f_opt, smooth, align, bpp, bytes, opt) + +#define filters_8tap_2d_fn2(op, align, bpp, bytes, opt4, opt8, f_opt) \ +filters_8tap_2d_fn(op, 64, align, bpp, bytes, opt8, f_opt) \ +filters_8tap_2d_fn(op, 32, align, bpp, bytes, opt8, f_opt) \ +filters_8tap_2d_fn(op, 16, align, bpp, bytes, opt8, f_opt) \ +filters_8tap_2d_fn(op, 8, align, bpp, bytes, opt8, f_opt) \ +filters_8tap_2d_fn(op, 4, align, bpp, bytes, opt4, f_opt) + +#define init_fpel_func(idx1, idx2, sz, type, bpp, opt) \ + dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][0][0] = \ + dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][0][0] = \ + dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][0][0] = \ + dsp->mc[idx1][FILTER_BILINEAR ][idx2][0][0] = ff_vp9_##type##sz##bpp##_##opt + +#define init_subpel1(idx1, idx2, idxh, idxv, sz, dir, type, bpp, opt) \ + dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][idxh][idxv] = \ + type##_8tap_smooth_##sz##dir##_##bpp##_##opt; \ + dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][idxh][idxv] = \ + type##_8tap_regular_##sz##dir##_##bpp##_##opt; \ + dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][idxh][idxv] = \ + type##_8tap_sharp_##sz##dir##_##bpp##_##opt + +#define init_subpel2(idx1, idx2, sz, type, bpp, opt) \ + init_subpel1(idx1, idx2, 1, 1, sz, hv, type, bpp, opt); \ + init_subpel1(idx1, idx2, 0, 1, sz, v, type, bpp, opt); \ + init_subpel1(idx1, idx2, 1, 0, sz, h, type, bpp, opt) + +#define init_subpel3_32_64(idx, type, bpp, opt) \ + init_subpel2(0, idx, 64, type, bpp, opt); \ + init_subpel2(1, idx, 32, type, bpp, opt) + +#define init_subpel3_8to64(idx, type, bpp, opt) \ + init_subpel3_32_64(idx, type, bpp, opt); \ + init_subpel2(2, idx, 16, type, bpp, opt); \ + init_subpel2(3, idx, 8, type, bpp, opt) + +#define init_subpel3(idx, type, bpp, opt) \ + init_subpel3_8to64(idx, type, bpp, opt); \ + init_subpel2(4, idx, 4, type, bpp, opt) + +#define init_ipred_func(type, enum, sz, bpp, opt) \ + dsp->intra_pred[TX_##sz##X##sz][enum##_PRED] = \ + cat(ff_vp9_ipred_##type##_##sz##x##sz##_, bpp, _##opt) + +#define init_8_16_32_ipred_funcs(type, enum, bpp, opt) \ + init_ipred_func(type, enum, 8, bpp, opt); \ + init_ipred_func(type, enum, 16, bpp, opt); \ + init_ipred_func(type, enum, 32, bpp, opt) + +#define init_ipred_funcs(type, enum, bpp, opt) \ + init_ipred_func(type, enum, 4, bpp, opt); \ + init_8_16_32_ipred_funcs(type, enum, bpp, opt) + +void ff_vp9dsp_init_10bpp_x86(VP9DSPContext *dsp, int bitexact); +void ff_vp9dsp_init_12bpp_x86(VP9DSPContext *dsp, int bitexact); +void ff_vp9dsp_init_16bpp_x86(VP9DSPContext *dsp); + +#endif /* AVCODEC_X86_VP9DSP_INIT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_10bpp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_10bpp.c new file mode 100644 index 0000000000..2694c06cb2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_10bpp.c @@ -0,0 +1,25 @@ +/* + * VP9 SIMD optimizations + * + * Copyright (c) 2013 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define BPC 10 +#define INIT_FUNC ff_vp9dsp_init_10bpp_x86 +#include "vp9dsp_init_16bpp_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_12bpp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_12bpp.c new file mode 100644 index 0000000000..5da3bc1840 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_12bpp.c @@ -0,0 +1,25 @@ +/* + * VP9 SIMD optimizations + * + * Copyright (c) 2013 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define BPC 12 +#define INIT_FUNC ff_vp9dsp_init_12bpp_x86 +#include "vp9dsp_init_16bpp_template.c" diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_16bpp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_16bpp.c new file mode 100644 index 0000000000..60d10a12a3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_16bpp.c @@ -0,0 +1,149 @@ +/* + * VP9 SIMD optimizations + * + * Copyright (c) 2013 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/mem.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/vp9dsp.h" +#include "libavcodec/x86/vp9dsp_init.h" + +#if HAVE_X86ASM + +decl_fpel_func(put, 8, , mmx); +decl_fpel_func(avg, 8, _16, mmxext); +decl_fpel_func(put, 16, , sse); +decl_fpel_func(put, 32, , sse); +decl_fpel_func(put, 64, , sse); +decl_fpel_func(put, 128, , sse); +decl_fpel_func(avg, 16, _16, sse2); +decl_fpel_func(avg, 32, _16, sse2); +decl_fpel_func(avg, 64, _16, sse2); +decl_fpel_func(avg, 128, _16, sse2); +decl_fpel_func(put, 32, , avx); +decl_fpel_func(put, 64, , avx); +decl_fpel_func(put, 128, , avx); +decl_fpel_func(avg, 32, _16, avx2); +decl_fpel_func(avg, 64, _16, avx2); +decl_fpel_func(avg, 128, _16, avx2); + +decl_ipred_fns(v, 16, mmx, sse); +decl_ipred_fns(h, 16, mmxext, sse2); +decl_ipred_fns(dc, 16, mmxext, sse2); +decl_ipred_fns(dc_top, 16, mmxext, sse2); +decl_ipred_fns(dc_left, 16, mmxext, sse2); +decl_ipred_fn(dl, 16, 16, avx2); +decl_ipred_fn(dl, 32, 16, avx2); +decl_ipred_fn(dr, 16, 16, avx2); +decl_ipred_fn(dr, 32, 16, avx2); + +#define decl_ipred_dir_funcs(type) \ +decl_ipred_fns(type, 16, sse2, sse2); \ +decl_ipred_fns(type, 16, ssse3, ssse3); \ +decl_ipred_fns(type, 16, avx, avx) + +decl_ipred_dir_funcs(dl); +decl_ipred_dir_funcs(dr); +decl_ipred_dir_funcs(vl); +decl_ipred_dir_funcs(vr); +decl_ipred_dir_funcs(hu); +decl_ipred_dir_funcs(hd); +#endif /* HAVE_X86ASM */ + +av_cold void ff_vp9dsp_init_16bpp_x86(VP9DSPContext *dsp) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + init_fpel_func(4, 0, 8, put, , mmx); + init_ipred_func(v, VERT, 4, 16, mmx); + } + + if (EXTERNAL_MMXEXT(cpu_flags)) { + init_fpel_func(4, 1, 8, avg, _16, mmxext); + init_ipred_func(h, HOR, 4, 16, mmxext); + init_ipred_func(dc, DC, 4, 16, mmxext); + init_ipred_func(dc_top, TOP_DC, 4, 16, mmxext); + init_ipred_func(dc_left, LEFT_DC, 4, 16, mmxext); + } + + if (EXTERNAL_SSE(cpu_flags)) { + init_fpel_func(3, 0, 16, put, , sse); + init_fpel_func(2, 0, 32, put, , sse); + init_fpel_func(1, 0, 64, put, , sse); + init_fpel_func(0, 0, 128, put, , sse); + init_8_16_32_ipred_funcs(v, VERT, 16, sse); + } + + if (EXTERNAL_SSE2(cpu_flags)) { + init_fpel_func(3, 1, 16, avg, _16, sse2); + init_fpel_func(2, 1, 32, avg, _16, sse2); + init_fpel_func(1, 1, 64, avg, _16, sse2); + init_fpel_func(0, 1, 128, avg, _16, sse2); + init_8_16_32_ipred_funcs(h, HOR, 16, sse2); + init_8_16_32_ipred_funcs(dc, DC, 16, sse2); + init_8_16_32_ipred_funcs(dc_top, TOP_DC, 16, sse2); + init_8_16_32_ipred_funcs(dc_left, LEFT_DC, 16, sse2); + init_ipred_funcs(dl, DIAG_DOWN_LEFT, 16, sse2); + init_ipred_funcs(dr, DIAG_DOWN_RIGHT, 16, sse2); + init_ipred_funcs(vl, VERT_LEFT, 16, sse2); + init_ipred_funcs(vr, VERT_RIGHT, 16, sse2); + init_ipred_funcs(hu, HOR_UP, 16, sse2); + init_ipred_funcs(hd, HOR_DOWN, 16, sse2); + } + + if (EXTERNAL_SSSE3(cpu_flags)) { + init_ipred_funcs(dl, DIAG_DOWN_LEFT, 16, ssse3); + init_ipred_funcs(dr, DIAG_DOWN_RIGHT, 16, ssse3); + init_ipred_funcs(vl, VERT_LEFT, 16, ssse3); + init_ipred_funcs(vr, VERT_RIGHT, 16, ssse3); + init_ipred_funcs(hu, HOR_UP, 16, ssse3); + init_ipred_funcs(hd, HOR_DOWN, 16, ssse3); + } + + if (EXTERNAL_AVX_FAST(cpu_flags)) { + init_fpel_func(2, 0, 32, put, , avx); + init_fpel_func(1, 0, 64, put, , avx); + init_fpel_func(0, 0, 128, put, , avx); + init_ipred_funcs(dl, DIAG_DOWN_LEFT, 16, avx); + init_ipred_funcs(dr, DIAG_DOWN_RIGHT, 16, avx); + init_ipred_funcs(vl, VERT_LEFT, 16, avx); + init_ipred_funcs(vr, VERT_RIGHT, 16, avx); + init_ipred_funcs(hu, HOR_UP, 16, avx); + init_ipred_funcs(hd, HOR_DOWN, 16, avx); + } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + init_fpel_func(2, 1, 32, avg, _16, avx2); + init_fpel_func(1, 1, 64, avg, _16, avx2); + init_fpel_func(0, 1, 128, avg, _16, avx2); + init_ipred_func(dl, DIAG_DOWN_LEFT, 16, 16, avx2); + init_ipred_func(dl, DIAG_DOWN_LEFT, 32, 16, avx2); + init_ipred_func(dr, DIAG_DOWN_RIGHT, 16, 16, avx2); +#if ARCH_X86_64 + init_ipred_func(dr, DIAG_DOWN_RIGHT, 32, 16, avx2); +#endif + } + +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_16bpp_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_16bpp_template.c new file mode 100644 index 0000000000..b56afc7f50 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/vp9dsp_init_16bpp_template.c @@ -0,0 +1,240 @@ +/* + * VP9 SIMD optimizations + * + * Copyright (c) 2013 Ronald S. Bultje + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/mem.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/vp9dsp.h" +#include "libavcodec/x86/vp9dsp_init.h" + +#if HAVE_X86ASM + +extern const int16_t ff_filters_16bpp[3][15][4][16]; + +decl_mc_funcs(4, sse2, int16_t, 16, BPC); +decl_mc_funcs(8, sse2, int16_t, 16, BPC); +decl_mc_funcs(16, avx2, int16_t, 16, BPC); + +mc_rep_funcs(16, 8, 16, sse2, int16_t, 16, BPC) +mc_rep_funcs(32, 16, 32, sse2, int16_t, 16, BPC) +mc_rep_funcs(64, 32, 64, sse2, int16_t, 16, BPC) +#if HAVE_AVX2_EXTERNAL +mc_rep_funcs(32, 16, 32, avx2, int16_t, 16, BPC) +mc_rep_funcs(64, 32, 64, avx2, int16_t, 16, BPC) +#endif + +filters_8tap_2d_fn2(put, 16, BPC, 2, sse2, sse2, 16bpp) +filters_8tap_2d_fn2(avg, 16, BPC, 2, sse2, sse2, 16bpp) +#if HAVE_AVX2_EXTERNAL +filters_8tap_2d_fn(put, 64, 32, BPC, 2, avx2, 16bpp) +filters_8tap_2d_fn(avg, 64, 32, BPC, 2, avx2, 16bpp) +filters_8tap_2d_fn(put, 32, 32, BPC, 2, avx2, 16bpp) +filters_8tap_2d_fn(avg, 32, 32, BPC, 2, avx2, 16bpp) +filters_8tap_2d_fn(put, 16, 32, BPC, 2, avx2, 16bpp) +filters_8tap_2d_fn(avg, 16, 32, BPC, 2, avx2, 16bpp) +#endif + +filters_8tap_1d_fn3(put, BPC, sse2, sse2, 16bpp) +filters_8tap_1d_fn3(avg, BPC, sse2, sse2, 16bpp) +#if HAVE_AVX2_EXTERNAL +filters_8tap_1d_fn2(put, 64, BPC, avx2, 16bpp) +filters_8tap_1d_fn2(avg, 64, BPC, avx2, 16bpp) +filters_8tap_1d_fn2(put, 32, BPC, avx2, 16bpp) +filters_8tap_1d_fn2(avg, 32, BPC, avx2, 16bpp) +filters_8tap_1d_fn2(put, 16, BPC, avx2, 16bpp) +filters_8tap_1d_fn2(avg, 16, BPC, avx2, 16bpp) +#endif + +#define decl_lpf_func(dir, wd, bpp, opt) \ +void ff_vp9_loop_filter_##dir##_##wd##_##bpp##_##opt(uint8_t *dst, ptrdiff_t stride, \ + int E, int I, int H) + +#define decl_lpf_funcs(dir, wd, bpp) \ +decl_lpf_func(dir, wd, bpp, sse2); \ +decl_lpf_func(dir, wd, bpp, ssse3); \ +decl_lpf_func(dir, wd, bpp, avx) + +#define decl_lpf_funcs_wd(dir) \ +decl_lpf_funcs(dir, 4, BPC); \ +decl_lpf_funcs(dir, 8, BPC); \ +decl_lpf_funcs(dir, 16, BPC) + +decl_lpf_funcs_wd(h); +decl_lpf_funcs_wd(v); + +#define lpf_16_wrapper(dir, off, bpp, opt) \ +static void loop_filter_##dir##_16_##bpp##_##opt(uint8_t *dst, ptrdiff_t stride, \ + int E, int I, int H) \ +{ \ + ff_vp9_loop_filter_##dir##_16_##bpp##_##opt(dst, stride, E, I, H); \ + ff_vp9_loop_filter_##dir##_16_##bpp##_##opt(dst + off, stride, E, I, H); \ +} + +#define lpf_16_wrappers(bpp, opt) \ +lpf_16_wrapper(h, 8 * stride, bpp, opt) \ +lpf_16_wrapper(v, 16, bpp, opt) + +lpf_16_wrappers(BPC, sse2) +lpf_16_wrappers(BPC, ssse3) +lpf_16_wrappers(BPC, avx) + +#define lpf_mix2_wrapper(dir, off, wd1, wd2, bpp, opt) \ +static void loop_filter_##dir##_##wd1##wd2##_##bpp##_##opt(uint8_t *dst, ptrdiff_t stride, \ + int E, int I, int H) \ +{ \ + ff_vp9_loop_filter_##dir##_##wd1##_##bpp##_##opt(dst, stride, \ + E & 0xff, I & 0xff, H & 0xff); \ + ff_vp9_loop_filter_##dir##_##wd2##_##bpp##_##opt(dst + off, stride, \ + E >> 8, I >> 8, H >> 8); \ +} + +#define lpf_mix2_wrappers(wd1, wd2, bpp, opt) \ +lpf_mix2_wrapper(h, 8 * stride, wd1, wd2, bpp, opt) \ +lpf_mix2_wrapper(v, 16, wd1, wd2, bpp, opt) + +#define lpf_mix2_wrappers_set(bpp, opt) \ +lpf_mix2_wrappers(4, 4, bpp, opt) \ +lpf_mix2_wrappers(4, 8, bpp, opt) \ +lpf_mix2_wrappers(8, 4, bpp, opt) \ +lpf_mix2_wrappers(8, 8, bpp, opt) \ + +lpf_mix2_wrappers_set(BPC, sse2) +lpf_mix2_wrappers_set(BPC, ssse3) +lpf_mix2_wrappers_set(BPC, avx) + +decl_ipred_fns(tm, BPC, mmxext, sse2); + +decl_itxfm_func(iwht, iwht, 4, BPC, mmxext); +#if BPC == 10 +decl_itxfm_func(idct, idct, 4, BPC, mmxext); +decl_itxfm_funcs(4, BPC, ssse3); +#else +decl_itxfm_func(idct, idct, 4, BPC, sse2); +#endif +decl_itxfm_func(idct, iadst, 4, BPC, sse2); +decl_itxfm_func(iadst, idct, 4, BPC, sse2); +decl_itxfm_func(iadst, iadst, 4, BPC, sse2); +decl_itxfm_funcs(8, BPC, sse2); +decl_itxfm_funcs(16, BPC, sse2); +decl_itxfm_func(idct, idct, 32, BPC, sse2); +#endif /* HAVE_X86ASM */ + +av_cold void INIT_FUNC(VP9DSPContext *dsp, int bitexact) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + +#define init_lpf_8_func(idx1, idx2, dir, wd, bpp, opt) \ + dsp->loop_filter_8[idx1][idx2] = ff_vp9_loop_filter_##dir##_##wd##_##bpp##_##opt +#define init_lpf_16_func(idx, dir, bpp, opt) \ + dsp->loop_filter_16[idx] = loop_filter_##dir##_16_##bpp##_##opt +#define init_lpf_mix2_func(idx1, idx2, idx3, dir, wd1, wd2, bpp, opt) \ + dsp->loop_filter_mix2[idx1][idx2][idx3] = loop_filter_##dir##_##wd1##wd2##_##bpp##_##opt + +#define init_lpf_funcs(bpp, opt) \ + init_lpf_8_func(0, 0, h, 4, bpp, opt); \ + init_lpf_8_func(0, 1, v, 4, bpp, opt); \ + init_lpf_8_func(1, 0, h, 8, bpp, opt); \ + init_lpf_8_func(1, 1, v, 8, bpp, opt); \ + init_lpf_8_func(2, 0, h, 16, bpp, opt); \ + init_lpf_8_func(2, 1, v, 16, bpp, opt); \ + init_lpf_16_func(0, h, bpp, opt); \ + init_lpf_16_func(1, v, bpp, opt); \ + init_lpf_mix2_func(0, 0, 0, h, 4, 4, bpp, opt); \ + init_lpf_mix2_func(0, 1, 0, h, 4, 8, bpp, opt); \ + init_lpf_mix2_func(1, 0, 0, h, 8, 4, bpp, opt); \ + init_lpf_mix2_func(1, 1, 0, h, 8, 8, bpp, opt); \ + init_lpf_mix2_func(0, 0, 1, v, 4, 4, bpp, opt); \ + init_lpf_mix2_func(0, 1, 1, v, 4, 8, bpp, opt); \ + init_lpf_mix2_func(1, 0, 1, v, 8, 4, bpp, opt); \ + init_lpf_mix2_func(1, 1, 1, v, 8, 8, bpp, opt) + +#define init_itx_func(idxa, idxb, typea, typeb, size, bpp, opt) \ + dsp->itxfm_add[idxa][idxb] = \ + cat(ff_vp9_##typea##_##typeb##_##size##x##size##_add_, bpp, _##opt); +#define init_itx_func_one(idx, typea, typeb, size, bpp, opt) \ + init_itx_func(idx, DCT_DCT, typea, typeb, size, bpp, opt); \ + init_itx_func(idx, ADST_DCT, typea, typeb, size, bpp, opt); \ + init_itx_func(idx, DCT_ADST, typea, typeb, size, bpp, opt); \ + init_itx_func(idx, ADST_ADST, typea, typeb, size, bpp, opt) +#define init_itx_funcs(idx, size, bpp, opt) \ + init_itx_func(idx, DCT_DCT, idct, idct, size, bpp, opt); \ + init_itx_func(idx, ADST_DCT, idct, iadst, size, bpp, opt); \ + init_itx_func(idx, DCT_ADST, iadst, idct, size, bpp, opt); \ + init_itx_func(idx, ADST_ADST, iadst, iadst, size, bpp, opt); \ + + if (EXTERNAL_MMXEXT(cpu_flags)) { + init_ipred_func(tm, TM_VP8, 4, BPC, mmxext); + if (!bitexact) { + init_itx_func_one(4 /* lossless */, iwht, iwht, 4, BPC, mmxext); +#if BPC == 10 + init_itx_func(TX_4X4, DCT_DCT, idct, idct, 4, 10, mmxext); +#endif + } + } + + if (EXTERNAL_SSE2(cpu_flags)) { + init_subpel3(0, put, BPC, sse2); + init_subpel3(1, avg, BPC, sse2); + init_lpf_funcs(BPC, sse2); + init_8_16_32_ipred_funcs(tm, TM_VP8, BPC, sse2); +#if BPC == 10 + if (!bitexact) { + init_itx_func(TX_4X4, ADST_DCT, idct, iadst, 4, 10, sse2); + init_itx_func(TX_4X4, DCT_ADST, iadst, idct, 4, 10, sse2); + init_itx_func(TX_4X4, ADST_ADST, iadst, iadst, 4, 10, sse2); + } +#else + init_itx_funcs(TX_4X4, 4, 12, sse2); +#endif + init_itx_funcs(TX_8X8, 8, BPC, sse2); + init_itx_funcs(TX_16X16, 16, BPC, sse2); + init_itx_func_one(TX_32X32, idct, idct, 32, BPC, sse2); + } + + if (EXTERNAL_SSSE3(cpu_flags)) { + init_lpf_funcs(BPC, ssse3); +#if BPC == 10 + if (!bitexact) { + init_itx_funcs(TX_4X4, 4, BPC, ssse3); + } +#endif + } + + if (EXTERNAL_AVX(cpu_flags)) { + init_lpf_funcs(BPC, avx); + } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { +#if HAVE_AVX2_EXTERNAL + init_subpel3_32_64(0, put, BPC, avx2); + init_subpel3_32_64(1, avg, BPC, avx2); + init_subpel2(2, 0, 16, put, BPC, avx2); + init_subpel2(2, 1, 16, avg, BPC, avx2); +#endif + } + +#endif /* HAVE_X86ASM */ + + ff_vp9dsp_init_16bpp_x86(dsp); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/xvididct.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/xvididct.h new file mode 100644 index 0000000000..edb5ebfd31 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/xvididct.h @@ -0,0 +1,44 @@ +/* + * XVID MPEG-4 VIDEO CODEC + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * header for Xvid IDCT functions + */ + +#ifndef AVCODEC_X86_XVIDIDCT_H +#define AVCODEC_X86_XVIDIDCT_H + +#include +#include + +void ff_xvid_idct_mmx(short *block); +void ff_xvid_idct_mmx_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_xvid_idct_mmx_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block); + +void ff_xvid_idct_mmxext(short *block); +void ff_xvid_idct_mmxext_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_xvid_idct_mmxext_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block); + +void ff_xvid_idct_sse2(short *block); +void ff_xvid_idct_put_sse2(uint8_t *dest, ptrdiff_t line_size, short *block); +void ff_xvid_idct_add_sse2(uint8_t *dest, ptrdiff_t line_size, short *block); + +#endif /* AVCODEC_X86_XVIDIDCT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/xvididct_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/xvididct_init.c new file mode 100644 index 0000000000..a91b416b74 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/xvididct_init.c @@ -0,0 +1,89 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/idctdsp.h" +#include "libavcodec/xvididct.h" + +#include "idctdsp.h" +#include "xvididct.h" + +#if ARCH_X86_32 && HAVE_X86ASM +static void xvid_idct_mmx_put(uint8_t *dest, ptrdiff_t line_size, short *block) +{ + ff_xvid_idct_mmx(block); + ff_put_pixels_clamped_mmx(block, dest, line_size); +} + +static void xvid_idct_mmx_add(uint8_t *dest, ptrdiff_t line_size, short *block) +{ + ff_xvid_idct_mmx(block); + ff_add_pixels_clamped_mmx(block, dest, line_size); +} + +static void xvid_idct_mmxext_put(uint8_t *dest, ptrdiff_t line_size, short *block) +{ + ff_xvid_idct_mmxext(block); + ff_put_pixels_clamped_mmx(block, dest, line_size); +} + +static void xvid_idct_mmxext_add(uint8_t *dest, ptrdiff_t line_size, short *block) +{ + ff_xvid_idct_mmxext(block); + ff_add_pixels_clamped_mmx(block, dest, line_size); +} +#endif + +av_cold void ff_xvid_idct_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, + unsigned high_bit_depth) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + + if (high_bit_depth || + !(avctx->idct_algo == FF_IDCT_AUTO || + avctx->idct_algo == FF_IDCT_XVID)) + return; + +#if ARCH_X86_32 + if (EXTERNAL_MMX(cpu_flags)) { + c->idct_put = xvid_idct_mmx_put; + c->idct_add = xvid_idct_mmx_add; + c->idct = ff_xvid_idct_mmx; + c->perm_type = FF_IDCT_PERM_NONE; + } + + if (EXTERNAL_MMXEXT(cpu_flags)) { + c->idct_put = xvid_idct_mmxext_put; + c->idct_add = xvid_idct_mmxext_add; + c->idct = ff_xvid_idct_mmxext; + c->perm_type = FF_IDCT_PERM_NONE; + } +#endif + + if (EXTERNAL_SSE2(cpu_flags)) { + c->idct_put = ff_xvid_idct_put_sse2; + c->idct_add = ff_xvid_idct_add_sse2; + c->idct = ff_xvid_idct_sse2; + c->perm_type = FF_IDCT_PERM_SSE2; + } +#endif /* HAVE_X86ASM */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xiph.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xiph.c new file mode 100644 index 0000000000..d072224b4a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xiph.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007 The FFmpeg Project + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/intreadwrite.h" +#include "xiph.h" + +int avpriv_split_xiph_headers(const uint8_t *extradata, int extradata_size, + int first_header_size, const uint8_t *header_start[3], + int header_len[3]) +{ + int i; + + if (extradata_size >= 6 && AV_RB16(extradata) == first_header_size) { + int overall_len = 6; + for (i=0; i<3; i++) { + header_len[i] = AV_RB16(extradata); + extradata += 2; + header_start[i] = extradata; + extradata += header_len[i]; + if (overall_len > extradata_size - header_len[i]) + return -1; + overall_len += header_len[i]; + } + } else if (extradata_size >= 3 && extradata_size < INT_MAX - 0x1ff && extradata[0] == 2) { + int overall_len = 3; + extradata++; + for (i=0; i<2; i++, extradata++) { + header_len[i] = 0; + for (; overall_len < extradata_size && *extradata==0xff; extradata++) { + header_len[i] += 0xff; + overall_len += 0xff + 1; + } + header_len[i] += *extradata; + overall_len += *extradata; + if (overall_len > extradata_size) + return -1; + } + header_len[2] = extradata_size - overall_len; + header_start[0] = extradata; + header_start[1] = header_start[0] + header_len[0]; + header_start[2] = header_start[1] + header_len[1]; + } else { + return -1; + } + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xiph.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xiph.h new file mode 100644 index 0000000000..1741a51b65 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xiph.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2007 The FFmpeg Project + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_XIPH_H +#define AVCODEC_XIPH_H + +#include "libavutil/common.h" + +/** + * Split a single extradata buffer into the three headers that most + * Xiph codecs use. (e.g. Theora and Vorbis) + * Works both with Matroska's packing and lavc's packing. + * + * @param[in] extradata The single chunk that combines all three headers + * @param[in] extradata_size The size of the extradata buffer + * @param[in] first_header_size The size of the first header, used to + * differentiate between the Matroska packing and lavc packing. + * @param[out] header_start Pointers to the start of the three separate headers. + * @param[out] header_len The sizes of each of the three headers. + * @return On error a negative value is returned, on success zero. + */ +int avpriv_split_xiph_headers(const uint8_t *extradata, int extradata_size, + int first_header_size, const uint8_t *header_start[3], + int header_len[3]); + +#endif /* AVCODEC_XIPH_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xvmc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xvmc.h new file mode 100644 index 0000000000..465ee78d6e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/xvmc.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2003 Ivan Kalvachev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_XVMC_H +#define AVCODEC_XVMC_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_xvmc + * Public libavcodec XvMC header. + */ + +#include + +#include "libavutil/attributes.h" +#include "version.h" +#include "avcodec.h" + +/** + * @defgroup lavc_codec_hwaccel_xvmc XvMC + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define AV_XVMC_ID 0x1DC711C0 /**< special value to ensure that regular pixel routines haven't corrupted the struct + the number is 1337 speak for the letters IDCT MCo (motion compensation) */ + +struct attribute_deprecated xvmc_pix_fmt { + /** The field contains the special constant value AV_XVMC_ID. + It is used as a test that the application correctly uses the API, + and that there is no corruption caused by pixel routines. + - application - set during initialization + - libavcodec - unchanged + */ + int xvmc_id; + + /** Pointer to the block array allocated by XvMCCreateBlocks(). + The array has to be freed by XvMCDestroyBlocks(). + Each group of 64 values represents one data block of differential + pixel information (in MoCo mode) or coefficients for IDCT. + - application - set the pointer during initialization + - libavcodec - fills coefficients/pixel data into the array + */ + short* data_blocks; + + /** Pointer to the macroblock description array allocated by + XvMCCreateMacroBlocks() and freed by XvMCDestroyMacroBlocks(). + - application - set the pointer during initialization + - libavcodec - fills description data into the array + */ + XvMCMacroBlock* mv_blocks; + + /** Number of macroblock descriptions that can be stored in the mv_blocks + array. + - application - set during initialization + - libavcodec - unchanged + */ + int allocated_mv_blocks; + + /** Number of blocks that can be stored at once in the data_blocks array. + - application - set during initialization + - libavcodec - unchanged + */ + int allocated_data_blocks; + + /** Indicate that the hardware would interpret data_blocks as IDCT + coefficients and perform IDCT on them. + - application - set during initialization + - libavcodec - unchanged + */ + int idct; + + /** In MoCo mode it indicates that intra macroblocks are assumed to be in + unsigned format; same as the XVMC_INTRA_UNSIGNED flag. + - application - set during initialization + - libavcodec - unchanged + */ + int unsigned_intra; + + /** Pointer to the surface allocated by XvMCCreateSurface(). + It has to be freed by XvMCDestroySurface() on application exit. + It identifies the frame and its state on the video hardware. + - application - set during initialization + - libavcodec - unchanged + */ + XvMCSurface* p_surface; + +/** Set by the decoder before calling ff_draw_horiz_band(), + needed by the XvMCRenderSurface function. */ +//@{ + /** Pointer to the surface used as past reference + - application - unchanged + - libavcodec - set + */ + XvMCSurface* p_past_surface; + + /** Pointer to the surface used as future reference + - application - unchanged + - libavcodec - set + */ + XvMCSurface* p_future_surface; + + /** top/bottom field or frame + - application - unchanged + - libavcodec - set + */ + unsigned int picture_structure; + + /** XVMC_SECOND_FIELD - 1st or 2nd field in the sequence + - application - unchanged + - libavcodec - set + */ + unsigned int flags; +//}@ + + /** Number of macroblock descriptions in the mv_blocks array + that have already been passed to the hardware. + - application - zeroes it on get_buffer(). + A successful ff_draw_horiz_band() may increment it + with filled_mb_block_num or zero both. + - libavcodec - unchanged + */ + int start_mv_blocks_num; + + /** Number of new macroblock descriptions in the mv_blocks array (after + start_mv_blocks_num) that are filled by libavcodec and have to be + passed to the hardware. + - application - zeroes it on get_buffer() or after successful + ff_draw_horiz_band(). + - libavcodec - increment with one of each stored MB + */ + int filled_mv_blocks_num; + + /** Number of the next free data block; one data block consists of + 64 short values in the data_blocks array. + All blocks before this one have already been claimed by placing their + position into the corresponding block description structure field, + that are part of the mv_blocks array. + - application - zeroes it on get_buffer(). + A successful ff_draw_horiz_band() may zero it together + with start_mb_blocks_num. + - libavcodec - each decoded macroblock increases it by the number + of coded blocks it contains. + */ + int next_free_data_block_num; +}; + +/** + * @} + */ + +#endif /* AVCODEC_XVMC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/alldevices.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/alldevices.c new file mode 100644 index 0000000000..8633433254 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/alldevices.c @@ -0,0 +1,68 @@ +/* + * Register all the grabbing devices. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/thread.h" +#include "libavformat/internal.h" +#include "avdevice.h" + +/* devices */ +extern AVInputFormat ff_alsa_demuxer; +extern AVOutputFormat ff_alsa_muxer; +extern AVInputFormat ff_android_camera_demuxer; +extern AVInputFormat ff_avfoundation_demuxer; +extern AVInputFormat ff_bktr_demuxer; +extern AVOutputFormat ff_caca_muxer; +extern AVInputFormat ff_decklink_demuxer; +extern AVOutputFormat ff_decklink_muxer; +extern AVInputFormat ff_dshow_demuxer; +extern AVInputFormat ff_fbdev_demuxer; +extern AVOutputFormat ff_fbdev_muxer; +extern AVInputFormat ff_gdigrab_demuxer; +extern AVInputFormat ff_iec61883_demuxer; +extern AVInputFormat ff_jack_demuxer; +extern AVInputFormat ff_kmsgrab_demuxer; +extern AVInputFormat ff_lavfi_demuxer; +extern AVInputFormat ff_openal_demuxer; +extern AVOutputFormat ff_opengl_muxer; +extern AVInputFormat ff_oss_demuxer; +extern AVOutputFormat ff_oss_muxer; +extern AVInputFormat ff_pulse_demuxer; +extern AVOutputFormat ff_pulse_muxer; +extern AVOutputFormat ff_sdl2_muxer; +extern AVInputFormat ff_sndio_demuxer; +extern AVOutputFormat ff_sndio_muxer; +extern AVInputFormat ff_v4l2_demuxer; +extern AVOutputFormat ff_v4l2_muxer; +extern AVInputFormat ff_vfwcap_demuxer; +extern AVInputFormat ff_xcbgrab_demuxer; +extern AVOutputFormat ff_xv_muxer; + +/* external libraries */ +extern AVInputFormat ff_libcdio_demuxer; +extern AVInputFormat ff_libdc1394_demuxer; + +#include "libavdevice/outdev_list.c" +#include "libavdevice/indev_list.c" + +void avdevice_register_all(void) +{ + avpriv_register_devices(outdev_list, indev_list); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/indev_list.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/indev_list.c new file mode 100644 index 0000000000..03ffb4036d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/indev_list.c @@ -0,0 +1,2 @@ +static const AVInputFormat * const indev_list[] = { + NULL }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/outdev_list.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/outdev_list.c new file mode 100644 index 0000000000..d1b87ed7b5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavdevice/outdev_list.c @@ -0,0 +1,2 @@ +static const AVOutputFormat * const outdev_list[] = { + NULL }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/allfilters.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/allfilters.c new file mode 100644 index 0000000000..04a3df7d56 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/allfilters.c @@ -0,0 +1,536 @@ +/* + * filter registration + * Copyright (c) 2008 Vitor Sessak + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/thread.h" +#include "avfilter.h" +#include "config.h" + +extern AVFilter ff_af_abench; +extern AVFilter ff_af_acompressor; +extern AVFilter ff_af_acontrast; +extern AVFilter ff_af_acopy; +extern AVFilter ff_af_acue; +extern AVFilter ff_af_acrossfade; +extern AVFilter ff_af_acrossover; +extern AVFilter ff_af_acrusher; +extern AVFilter ff_af_adeclick; +extern AVFilter ff_af_adeclip; +extern AVFilter ff_af_adelay; +extern AVFilter ff_af_aderivative; +extern AVFilter ff_af_aecho; +extern AVFilter ff_af_aemphasis; +extern AVFilter ff_af_aeval; +extern AVFilter ff_af_afade; +extern AVFilter ff_af_afftdn; +extern AVFilter ff_af_afftfilt; +extern AVFilter ff_af_afir; +extern AVFilter ff_af_aformat; +extern AVFilter ff_af_agate; +extern AVFilter ff_af_aiir; +extern AVFilter ff_af_aintegral; +extern AVFilter ff_af_ainterleave; +extern AVFilter ff_af_alimiter; +extern AVFilter ff_af_allpass; +extern AVFilter ff_af_aloop; +extern AVFilter ff_af_amerge; +extern AVFilter ff_af_ametadata; +extern AVFilter ff_af_amix; +extern AVFilter ff_af_amultiply; +extern AVFilter ff_af_anequalizer; +extern AVFilter ff_af_anlmdn; +extern AVFilter ff_af_anull; +extern AVFilter ff_af_apad; +extern AVFilter ff_af_aperms; +extern AVFilter ff_af_aphaser; +extern AVFilter ff_af_apulsator; +extern AVFilter ff_af_arealtime; +extern AVFilter ff_af_aresample; +extern AVFilter ff_af_areverse; +extern AVFilter ff_af_aselect; +extern AVFilter ff_af_asendcmd; +extern AVFilter ff_af_asetnsamples; +extern AVFilter ff_af_asetpts; +extern AVFilter ff_af_asetrate; +extern AVFilter ff_af_asettb; +extern AVFilter ff_af_ashowinfo; +extern AVFilter ff_af_asidedata; +extern AVFilter ff_af_asoftclip; +extern AVFilter ff_af_asplit; +extern AVFilter ff_af_asr; +extern AVFilter ff_af_astats; +extern AVFilter ff_af_astreamselect; +extern AVFilter ff_af_atempo; +extern AVFilter ff_af_atrim; +extern AVFilter ff_af_azmq; +extern AVFilter ff_af_bandpass; +extern AVFilter ff_af_bandreject; +extern AVFilter ff_af_bass; +extern AVFilter ff_af_biquad; +extern AVFilter ff_af_bs2b; +extern AVFilter ff_af_channelmap; +extern AVFilter ff_af_channelsplit; +extern AVFilter ff_af_chorus; +extern AVFilter ff_af_compand; +extern AVFilter ff_af_compensationdelay; +extern AVFilter ff_af_crossfeed; +extern AVFilter ff_af_crystalizer; +extern AVFilter ff_af_dcshift; +extern AVFilter ff_af_deesser; +extern AVFilter ff_af_drmeter; +extern AVFilter ff_af_dynaudnorm; +extern AVFilter ff_af_earwax; +extern AVFilter ff_af_ebur128; +extern AVFilter ff_af_equalizer; +extern AVFilter ff_af_extrastereo; +extern AVFilter ff_af_firequalizer; +extern AVFilter ff_af_flanger; +extern AVFilter ff_af_haas; +extern AVFilter ff_af_hdcd; +extern AVFilter ff_af_headphone; +extern AVFilter ff_af_highpass; +extern AVFilter ff_af_highshelf; +extern AVFilter ff_af_join; +extern AVFilter ff_af_ladspa; +extern AVFilter ff_af_loudnorm; +extern AVFilter ff_af_lowpass; +extern AVFilter ff_af_lowshelf; +extern AVFilter ff_af_lv2; +extern AVFilter ff_af_mcompand; +extern AVFilter ff_af_pan; +extern AVFilter ff_af_replaygain; +extern AVFilter ff_af_resample; +extern AVFilter ff_af_rubberband; +extern AVFilter ff_af_sidechaincompress; +extern AVFilter ff_af_sidechaingate; +extern AVFilter ff_af_silencedetect; +extern AVFilter ff_af_silenceremove; +extern AVFilter ff_af_sofalizer; +extern AVFilter ff_af_stereotools; +extern AVFilter ff_af_stereowiden; +extern AVFilter ff_af_superequalizer; +extern AVFilter ff_af_surround; +extern AVFilter ff_af_treble; +extern AVFilter ff_af_tremolo; +extern AVFilter ff_af_vibrato; +extern AVFilter ff_af_volume; +extern AVFilter ff_af_volumedetect; + +extern AVFilter ff_asrc_aevalsrc; +extern AVFilter ff_asrc_anoisesrc; +extern AVFilter ff_asrc_anullsrc; +extern AVFilter ff_asrc_flite; +extern AVFilter ff_asrc_hilbert; +extern AVFilter ff_asrc_sinc; +extern AVFilter ff_asrc_sine; + +extern AVFilter ff_asink_anullsink; + +extern AVFilter ff_vf_alphaextract; +extern AVFilter ff_vf_alphamerge; +extern AVFilter ff_vf_amplify; +extern AVFilter ff_vf_ass; +extern AVFilter ff_vf_atadenoise; +extern AVFilter ff_vf_avgblur; +extern AVFilter ff_vf_avgblur_opencl; +extern AVFilter ff_vf_bbox; +extern AVFilter ff_vf_bench; +extern AVFilter ff_vf_bitplanenoise; +extern AVFilter ff_vf_blackdetect; +extern AVFilter ff_vf_blackframe; +extern AVFilter ff_vf_blend; +extern AVFilter ff_vf_bm3d; +extern AVFilter ff_vf_boxblur; +extern AVFilter ff_vf_boxblur_opencl; +extern AVFilter ff_vf_bwdif; +extern AVFilter ff_vf_chromahold; +extern AVFilter ff_vf_chromakey; +extern AVFilter ff_vf_chromashift; +extern AVFilter ff_vf_ciescope; +extern AVFilter ff_vf_codecview; +extern AVFilter ff_vf_colorbalance; +extern AVFilter ff_vf_colorchannelmixer; +extern AVFilter ff_vf_colorkey; +extern AVFilter ff_vf_colorkey_opencl; +extern AVFilter ff_vf_colorhold; +extern AVFilter ff_vf_colorlevels; +extern AVFilter ff_vf_colormatrix; +extern AVFilter ff_vf_colorspace; +extern AVFilter ff_vf_convolution; +extern AVFilter ff_vf_convolution_opencl; +extern AVFilter ff_vf_convolve; +extern AVFilter ff_vf_copy; +extern AVFilter ff_vf_coreimage; +extern AVFilter ff_vf_cover_rect; +extern AVFilter ff_vf_crop; +extern AVFilter ff_vf_cropdetect; +extern AVFilter ff_vf_cue; +extern AVFilter ff_vf_curves; +extern AVFilter ff_vf_datascope; +extern AVFilter ff_vf_dctdnoiz; +extern AVFilter ff_vf_deband; +extern AVFilter ff_vf_deblock; +extern AVFilter ff_vf_decimate; +extern AVFilter ff_vf_deconvolve; +extern AVFilter ff_vf_dedot; +extern AVFilter ff_vf_deflate; +extern AVFilter ff_vf_deflicker; +extern AVFilter ff_vf_deinterlace_qsv; +extern AVFilter ff_vf_deinterlace_vaapi; +extern AVFilter ff_vf_dejudder; +extern AVFilter ff_vf_delogo; +extern AVFilter ff_vf_denoise_vaapi; +extern AVFilter ff_vf_derain; +extern AVFilter ff_vf_deshake; +extern AVFilter ff_vf_despill; +extern AVFilter ff_vf_detelecine; +extern AVFilter ff_vf_dilation; +extern AVFilter ff_vf_dilation_opencl; +extern AVFilter ff_vf_displace; +extern AVFilter ff_vf_doubleweave; +extern AVFilter ff_vf_drawbox; +extern AVFilter ff_vf_drawgraph; +extern AVFilter ff_vf_drawgrid; +extern AVFilter ff_vf_drawtext; +extern AVFilter ff_vf_edgedetect; +extern AVFilter ff_vf_elbg; +extern AVFilter ff_vf_entropy; +extern AVFilter ff_vf_eq; +extern AVFilter ff_vf_erosion; +extern AVFilter ff_vf_erosion_opencl; +extern AVFilter ff_vf_extractplanes; +extern AVFilter ff_vf_fade; +extern AVFilter ff_vf_fftdnoiz; +extern AVFilter ff_vf_fftfilt; +extern AVFilter ff_vf_field; +extern AVFilter ff_vf_fieldhint; +extern AVFilter ff_vf_fieldmatch; +extern AVFilter ff_vf_fieldorder; +extern AVFilter ff_vf_fillborders; +extern AVFilter ff_vf_find_rect; +extern AVFilter ff_vf_floodfill; +extern AVFilter ff_vf_format; +extern AVFilter ff_vf_fps; +extern AVFilter ff_vf_framepack; +extern AVFilter ff_vf_framerate; +extern AVFilter ff_vf_framestep; +extern AVFilter ff_vf_freezedetect; +extern AVFilter ff_vf_frei0r; +extern AVFilter ff_vf_fspp; +extern AVFilter ff_vf_gblur; +extern AVFilter ff_vf_geq; +extern AVFilter ff_vf_gradfun; +extern AVFilter ff_vf_graphmonitor; +extern AVFilter ff_vf_greyedge; +extern AVFilter ff_vf_haldclut; +extern AVFilter ff_vf_hflip; +extern AVFilter ff_vf_histeq; +extern AVFilter ff_vf_histogram; +extern AVFilter ff_vf_hqdn3d; +extern AVFilter ff_vf_hqx; +extern AVFilter ff_vf_hstack; +extern AVFilter ff_vf_hue; +extern AVFilter ff_vf_hwdownload; +extern AVFilter ff_vf_hwmap; +extern AVFilter ff_vf_hwupload; +extern AVFilter ff_vf_hwupload_cuda; +extern AVFilter ff_vf_hysteresis; +extern AVFilter ff_vf_idet; +extern AVFilter ff_vf_il; +extern AVFilter ff_vf_inflate; +extern AVFilter ff_vf_interlace; +extern AVFilter ff_vf_interleave; +extern AVFilter ff_vf_kerndeint; +extern AVFilter ff_vf_lagfun; +extern AVFilter ff_vf_lenscorrection; +extern AVFilter ff_vf_lensfun; +extern AVFilter ff_vf_libvmaf; +extern AVFilter ff_vf_limiter; +extern AVFilter ff_vf_loop; +extern AVFilter ff_vf_lumakey; +extern AVFilter ff_vf_lut; +extern AVFilter ff_vf_lut1d; +extern AVFilter ff_vf_lut2; +extern AVFilter ff_vf_lut3d; +extern AVFilter ff_vf_lutrgb; +extern AVFilter ff_vf_lutyuv; +extern AVFilter ff_vf_maskedclamp; +extern AVFilter ff_vf_maskedmerge; +extern AVFilter ff_vf_maskfun; +extern AVFilter ff_vf_mcdeint; +extern AVFilter ff_vf_mergeplanes; +extern AVFilter ff_vf_mestimate; +extern AVFilter ff_vf_metadata; +extern AVFilter ff_vf_midequalizer; +extern AVFilter ff_vf_minterpolate; +extern AVFilter ff_vf_mix; +extern AVFilter ff_vf_mpdecimate; +extern AVFilter ff_vf_negate; +extern AVFilter ff_vf_nlmeans; +extern AVFilter ff_vf_nlmeans_opencl; +extern AVFilter ff_vf_nnedi; +extern AVFilter ff_vf_noformat; +extern AVFilter ff_vf_noise; +extern AVFilter ff_vf_normalize; +extern AVFilter ff_vf_null; +extern AVFilter ff_vf_ocr; +extern AVFilter ff_vf_ocv; +extern AVFilter ff_vf_oscilloscope; +extern AVFilter ff_vf_overlay; +extern AVFilter ff_vf_overlay_opencl; +extern AVFilter ff_vf_overlay_qsv; +extern AVFilter ff_vf_owdenoise; +extern AVFilter ff_vf_pad; +extern AVFilter ff_vf_palettegen; +extern AVFilter ff_vf_paletteuse; +extern AVFilter ff_vf_perms; +extern AVFilter ff_vf_perspective; +extern AVFilter ff_vf_phase; +extern AVFilter ff_vf_pixdesctest; +extern AVFilter ff_vf_pixscope; +extern AVFilter ff_vf_pp; +extern AVFilter ff_vf_pp7; +extern AVFilter ff_vf_premultiply; +extern AVFilter ff_vf_prewitt; +extern AVFilter ff_vf_prewitt_opencl; +extern AVFilter ff_vf_procamp_vaapi; +extern AVFilter ff_vf_program_opencl; +extern AVFilter ff_vf_pseudocolor; +extern AVFilter ff_vf_psnr; +extern AVFilter ff_vf_pullup; +extern AVFilter ff_vf_qp; +extern AVFilter ff_vf_random; +extern AVFilter ff_vf_readeia608; +extern AVFilter ff_vf_readvitc; +extern AVFilter ff_vf_realtime; +extern AVFilter ff_vf_remap; +extern AVFilter ff_vf_removegrain; +extern AVFilter ff_vf_removelogo; +extern AVFilter ff_vf_repeatfields; +extern AVFilter ff_vf_reverse; +extern AVFilter ff_vf_rgbashift; +extern AVFilter ff_vf_roberts; +extern AVFilter ff_vf_roberts_opencl; +extern AVFilter ff_vf_rotate; +extern AVFilter ff_vf_sab; +extern AVFilter ff_vf_scale; +extern AVFilter ff_vf_scale_cuda; +extern AVFilter ff_vf_scale_npp; +extern AVFilter ff_vf_scale_qsv; +extern AVFilter ff_vf_scale_vaapi; +extern AVFilter ff_vf_scale2ref; +extern AVFilter ff_vf_select; +extern AVFilter ff_vf_selectivecolor; +extern AVFilter ff_vf_sendcmd; +extern AVFilter ff_vf_separatefields; +extern AVFilter ff_vf_setdar; +extern AVFilter ff_vf_setfield; +extern AVFilter ff_vf_setparams; +extern AVFilter ff_vf_setpts; +extern AVFilter ff_vf_setrange; +extern AVFilter ff_vf_setsar; +extern AVFilter ff_vf_settb; +extern AVFilter ff_vf_sharpness_vaapi; +extern AVFilter ff_vf_showinfo; +extern AVFilter ff_vf_showpalette; +extern AVFilter ff_vf_shuffleframes; +extern AVFilter ff_vf_shuffleplanes; +extern AVFilter ff_vf_sidedata; +extern AVFilter ff_vf_signalstats; +extern AVFilter ff_vf_signature; +extern AVFilter ff_vf_smartblur; +extern AVFilter ff_vf_sobel; +extern AVFilter ff_vf_sobel_opencl; +extern AVFilter ff_vf_split; +extern AVFilter ff_vf_spp; +extern AVFilter ff_vf_sr; +extern AVFilter ff_vf_ssim; +extern AVFilter ff_vf_stereo3d; +extern AVFilter ff_vf_streamselect; +extern AVFilter ff_vf_subtitles; +extern AVFilter ff_vf_super2xsai; +extern AVFilter ff_vf_swaprect; +extern AVFilter ff_vf_swapuv; +extern AVFilter ff_vf_tblend; +extern AVFilter ff_vf_telecine; +extern AVFilter ff_vf_threshold; +extern AVFilter ff_vf_thumbnail; +extern AVFilter ff_vf_thumbnail_cuda; +extern AVFilter ff_vf_tile; +extern AVFilter ff_vf_tinterlace; +extern AVFilter ff_vf_tlut2; +extern AVFilter ff_vf_tmix; +extern AVFilter ff_vf_tonemap; +extern AVFilter ff_vf_tonemap_opencl; +extern AVFilter ff_vf_tpad; +extern AVFilter ff_vf_transpose; +extern AVFilter ff_vf_transpose_npp; +extern AVFilter ff_vf_transpose_opencl; +extern AVFilter ff_vf_transpose_vaapi; +extern AVFilter ff_vf_trim; +extern AVFilter ff_vf_unpremultiply; +extern AVFilter ff_vf_unsharp; +extern AVFilter ff_vf_unsharp_opencl; +extern AVFilter ff_vf_uspp; +extern AVFilter ff_vf_vaguedenoiser; +extern AVFilter ff_vf_vectorscope; +extern AVFilter ff_vf_vflip; +extern AVFilter ff_vf_vfrdet; +extern AVFilter ff_vf_vibrance; +extern AVFilter ff_vf_vidstabdetect; +extern AVFilter ff_vf_vidstabtransform; +extern AVFilter ff_vf_vignette; +extern AVFilter ff_vf_vmafmotion; +extern AVFilter ff_vf_vpp_qsv; +extern AVFilter ff_vf_vstack; +extern AVFilter ff_vf_w3fdif; +extern AVFilter ff_vf_waveform; +extern AVFilter ff_vf_weave; +extern AVFilter ff_vf_xbr; +extern AVFilter ff_vf_xmedian; +extern AVFilter ff_vf_xstack; +extern AVFilter ff_vf_yadif; +extern AVFilter ff_vf_yadif_cuda; +extern AVFilter ff_vf_zmq; +extern AVFilter ff_vf_zoompan; +extern AVFilter ff_vf_zscale; + +extern AVFilter ff_vsrc_allrgb; +extern AVFilter ff_vsrc_allyuv; +extern AVFilter ff_vsrc_cellauto; +extern AVFilter ff_vsrc_color; +extern AVFilter ff_vsrc_coreimagesrc; +extern AVFilter ff_vsrc_frei0r_src; +extern AVFilter ff_vsrc_haldclutsrc; +extern AVFilter ff_vsrc_life; +extern AVFilter ff_vsrc_mandelbrot; +extern AVFilter ff_vsrc_mptestsrc; +extern AVFilter ff_vsrc_nullsrc; +extern AVFilter ff_vsrc_openclsrc; +extern AVFilter ff_vsrc_pal75bars; +extern AVFilter ff_vsrc_pal100bars; +extern AVFilter ff_vsrc_rgbtestsrc; +extern AVFilter ff_vsrc_smptebars; +extern AVFilter ff_vsrc_smptehdbars; +extern AVFilter ff_vsrc_testsrc; +extern AVFilter ff_vsrc_testsrc2; +extern AVFilter ff_vsrc_yuvtestsrc; + +extern AVFilter ff_vsink_nullsink; + +/* multimedia filters */ +extern AVFilter ff_avf_abitscope; +extern AVFilter ff_avf_adrawgraph; +extern AVFilter ff_avf_agraphmonitor; +extern AVFilter ff_avf_ahistogram; +extern AVFilter ff_avf_aphasemeter; +extern AVFilter ff_avf_avectorscope; +extern AVFilter ff_avf_concat; +extern AVFilter ff_avf_showcqt; +extern AVFilter ff_avf_showfreqs; +extern AVFilter ff_avf_showspatial; +extern AVFilter ff_avf_showspectrum; +extern AVFilter ff_avf_showspectrumpic; +extern AVFilter ff_avf_showvolume; +extern AVFilter ff_avf_showwaves; +extern AVFilter ff_avf_showwavespic; +extern AVFilter ff_vaf_spectrumsynth; + +/* multimedia sources */ +extern AVFilter ff_avsrc_amovie; +extern AVFilter ff_avsrc_movie; + +/* those filters are part of public or internal API, + * they are formatted to not be found by the grep + * as they are manually added again (due to their 'names' + * being the same while having different 'types'). */ +extern AVFilter ff_asrc_abuffer; +extern AVFilter ff_vsrc_buffer; +extern AVFilter ff_asink_abuffer; +extern AVFilter ff_vsink_buffer; +extern AVFilter ff_af_afifo; +extern AVFilter ff_vf_fifo; + +#include "libavfilter/filter_list.c" + + +const AVFilter *av_filter_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVFilter *f = filter_list[i]; + + if (f) + *opaque = (void*)(i + 1); + + return f; +} + +const AVFilter *avfilter_get_by_name(const char *name) +{ + const AVFilter *f = NULL; + void *opaque = 0; + + if (!name) + return NULL; + + while ((f = av_filter_iterate(&opaque))) + if (!strcmp(f->name, name)) + return (AVFilter *)f; + + return NULL; +} + + +#if FF_API_NEXT +FF_DISABLE_DEPRECATION_WARNINGS +static AVOnce av_filter_next_init = AV_ONCE_INIT; + +static void av_filter_init_next(void) +{ + AVFilter *prev = NULL, *p; + void *i = 0; + while ((p = (AVFilter*)av_filter_iterate(&i))) { + if (prev) + prev->next = p; + prev = p; + } +} + +void avfilter_register_all(void) +{ + ff_thread_once(&av_filter_next_init, av_filter_init_next); +} + +int avfilter_register(AVFilter *filter) +{ + ff_thread_once(&av_filter_next_init, av_filter_init_next); + + return 0; +} + +const AVFilter *avfilter_next(const AVFilter *prev) +{ + ff_thread_once(&av_filter_next_init, av_filter_init_next); + + return prev ? prev->next : filter_list[0]; +} + +FF_ENABLE_DEPRECATION_WARNINGS +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/avfilter.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/avfilter.h new file mode 100644 index 0000000000..9d70e7118b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/avfilter.h @@ -0,0 +1,1168 @@ +/* + * filter layer + * Copyright (c) 2007 Bobby Bingham + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_AVFILTER_H +#define AVFILTER_AVFILTER_H + +/** + * @file + * @ingroup lavfi + * Main libavfilter public API header + */ + +/** + * @defgroup lavfi libavfilter + * Graph-based frame editing library. + * + * @{ + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/avutil.h" +#include "libavutil/buffer.h" +#include "libavutil/dict.h" +#include "libavutil/frame.h" +#include "libavutil/log.h" +#include "libavutil/samplefmt.h" +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" + +#include "libavfilter/version.h" + +/** + * Return the LIBAVFILTER_VERSION_INT constant. + */ +unsigned avfilter_version(void); + +/** + * Return the libavfilter build-time configuration. + */ +const char *avfilter_configuration(void); + +/** + * Return the libavfilter license. + */ +const char *avfilter_license(void); + +typedef struct AVFilterContext AVFilterContext; +typedef struct AVFilterLink AVFilterLink; +typedef struct AVFilterPad AVFilterPad; +typedef struct AVFilterFormats AVFilterFormats; + +/** + * Get the number of elements in a NULL-terminated array of AVFilterPads (e.g. + * AVFilter.inputs/outputs). + */ +int avfilter_pad_count(const AVFilterPad *pads); + +/** + * Get the name of an AVFilterPad. + * + * @param pads an array of AVFilterPads + * @param pad_idx index of the pad in the array it; is the caller's + * responsibility to ensure the index is valid + * + * @return name of the pad_idx'th pad in pads + */ +const char *avfilter_pad_get_name(const AVFilterPad *pads, int pad_idx); + +/** + * Get the type of an AVFilterPad. + * + * @param pads an array of AVFilterPads + * @param pad_idx index of the pad in the array; it is the caller's + * responsibility to ensure the index is valid + * + * @return type of the pad_idx'th pad in pads + */ +enum AVMediaType avfilter_pad_get_type(const AVFilterPad *pads, int pad_idx); + +/** + * The number of the filter inputs is not determined just by AVFilter.inputs. + * The filter might add additional inputs during initialization depending on the + * options supplied to it. + */ +#define AVFILTER_FLAG_DYNAMIC_INPUTS (1 << 0) +/** + * The number of the filter outputs is not determined just by AVFilter.outputs. + * The filter might add additional outputs during initialization depending on + * the options supplied to it. + */ +#define AVFILTER_FLAG_DYNAMIC_OUTPUTS (1 << 1) +/** + * The filter supports multithreading by splitting frames into multiple parts + * and processing them concurrently. + */ +#define AVFILTER_FLAG_SLICE_THREADS (1 << 2) +/** + * Some filters support a generic "enable" expression option that can be used + * to enable or disable a filter in the timeline. Filters supporting this + * option have this flag set. When the enable expression is false, the default + * no-op filter_frame() function is called in place of the filter_frame() + * callback defined on each input pad, thus the frame is passed unchanged to + * the next filters. + */ +#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC (1 << 16) +/** + * Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will + * have its filter_frame() callback(s) called as usual even when the enable + * expression is false. The filter will disable filtering within the + * filter_frame() callback(s) itself, for example executing code depending on + * the AVFilterContext->is_disabled value. + */ +#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL (1 << 17) +/** + * Handy mask to test whether the filter supports or no the timeline feature + * (internally or generically). + */ +#define AVFILTER_FLAG_SUPPORT_TIMELINE (AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL) + +/** + * Filter definition. This defines the pads a filter contains, and all the + * callback functions used to interact with the filter. + */ +typedef struct AVFilter { + /** + * Filter name. Must be non-NULL and unique among filters. + */ + const char *name; + + /** + * A description of the filter. May be NULL. + * + * You should use the NULL_IF_CONFIG_SMALL() macro to define it. + */ + const char *description; + + /** + * List of inputs, terminated by a zeroed element. + * + * NULL if there are no (static) inputs. Instances of filters with + * AVFILTER_FLAG_DYNAMIC_INPUTS set may have more inputs than present in + * this list. + */ + const AVFilterPad *inputs; + /** + * List of outputs, terminated by a zeroed element. + * + * NULL if there are no (static) outputs. Instances of filters with + * AVFILTER_FLAG_DYNAMIC_OUTPUTS set may have more outputs than present in + * this list. + */ + const AVFilterPad *outputs; + + /** + * A class for the private data, used to declare filter private AVOptions. + * This field is NULL for filters that do not declare any options. + * + * If this field is non-NULL, the first member of the filter private data + * must be a pointer to AVClass, which will be set by libavfilter generic + * code to this class. + */ + const AVClass *priv_class; + + /** + * A combination of AVFILTER_FLAG_* + */ + int flags; + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavfilter and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + + /** + * Filter pre-initialization function + * + * This callback will be called immediately after the filter context is + * allocated, to allow allocating and initing sub-objects. + * + * If this callback is not NULL, the uninit callback will be called on + * allocation failure. + * + * @return 0 on success, + * AVERROR code on failure (but the code will be + * dropped and treated as ENOMEM by the calling code) + */ + int (*preinit)(AVFilterContext *ctx); + + /** + * Filter initialization function. + * + * This callback will be called only once during the filter lifetime, after + * all the options have been set, but before links between filters are + * established and format negotiation is done. + * + * Basic filter initialization should be done here. Filters with dynamic + * inputs and/or outputs should create those inputs/outputs here based on + * provided options. No more changes to this filter's inputs/outputs can be + * done after this callback. + * + * This callback must not assume that the filter links exist or frame + * parameters are known. + * + * @ref AVFilter.uninit "uninit" is guaranteed to be called even if + * initialization fails, so this callback does not have to clean up on + * failure. + * + * @return 0 on success, a negative AVERROR on failure + */ + int (*init)(AVFilterContext *ctx); + + /** + * Should be set instead of @ref AVFilter.init "init" by the filters that + * want to pass a dictionary of AVOptions to nested contexts that are + * allocated during init. + * + * On return, the options dict should be freed and replaced with one that + * contains all the options which could not be processed by this filter (or + * with NULL if all the options were processed). + * + * Otherwise the semantics is the same as for @ref AVFilter.init "init". + */ + int (*init_dict)(AVFilterContext *ctx, AVDictionary **options); + + /** + * Filter uninitialization function. + * + * Called only once right before the filter is freed. Should deallocate any + * memory held by the filter, release any buffer references, etc. It does + * not need to deallocate the AVFilterContext.priv memory itself. + * + * This callback may be called even if @ref AVFilter.init "init" was not + * called or failed, so it must be prepared to handle such a situation. + */ + void (*uninit)(AVFilterContext *ctx); + + /** + * Query formats supported by the filter on its inputs and outputs. + * + * This callback is called after the filter is initialized (so the inputs + * and outputs are fixed), shortly before the format negotiation. This + * callback may be called more than once. + * + * This callback must set AVFilterLink.out_formats on every input link and + * AVFilterLink.in_formats on every output link to a list of pixel/sample + * formats that the filter supports on that link. For audio links, this + * filter must also set @ref AVFilterLink.in_samplerates "in_samplerates" / + * @ref AVFilterLink.out_samplerates "out_samplerates" and + * @ref AVFilterLink.in_channel_layouts "in_channel_layouts" / + * @ref AVFilterLink.out_channel_layouts "out_channel_layouts" analogously. + * + * This callback may be NULL for filters with one input, in which case + * libavfilter assumes that it supports all input formats and preserves + * them on output. + * + * @return zero on success, a negative value corresponding to an + * AVERROR code otherwise + */ + int (*query_formats)(AVFilterContext *); + + int priv_size; ///< size of private data to allocate for the filter + + int flags_internal; ///< Additional flags for avfilter internal use only. + + /** + * Used by the filter registration system. Must not be touched by any other + * code. + */ + struct AVFilter *next; + + /** + * Make the filter instance process a command. + * + * @param cmd the command to process, for handling simplicity all commands must be alphanumeric only + * @param arg the argument for the command + * @param res a buffer with size res_size where the filter(s) can return a response. This must not change when the command is not supported. + * @param flags if AVFILTER_CMD_FLAG_FAST is set and the command would be + * time consuming then a filter should treat it like an unsupported command + * + * @returns >=0 on success otherwise an error code. + * AVERROR(ENOSYS) on unsupported commands + */ + int (*process_command)(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags); + + /** + * Filter initialization function, alternative to the init() + * callback. Args contains the user-supplied parameters, opaque is + * used for providing binary data. + */ + int (*init_opaque)(AVFilterContext *ctx, void *opaque); + + /** + * Filter activation function. + * + * Called when any processing is needed from the filter, instead of any + * filter_frame and request_frame on pads. + * + * The function must examine inlinks and outlinks and perform a single + * step of processing. If there is nothing to do, the function must do + * nothing and not return an error. If more steps are or may be + * possible, it must use ff_filter_set_ready() to schedule another + * activation. + */ + int (*activate)(AVFilterContext *ctx); +} AVFilter; + +/** + * Process multiple parts of the frame concurrently. + */ +#define AVFILTER_THREAD_SLICE (1 << 0) + +typedef struct AVFilterInternal AVFilterInternal; + +/** An instance of a filter */ +struct AVFilterContext { + const AVClass *av_class; ///< needed for av_log() and filters common options + + const AVFilter *filter; ///< the AVFilter of which this is an instance + + char *name; ///< name of this filter instance + + AVFilterPad *input_pads; ///< array of input pads + AVFilterLink **inputs; ///< array of pointers to input links + unsigned nb_inputs; ///< number of input pads + + AVFilterPad *output_pads; ///< array of output pads + AVFilterLink **outputs; ///< array of pointers to output links + unsigned nb_outputs; ///< number of output pads + + void *priv; ///< private data for use by the filter + + struct AVFilterGraph *graph; ///< filtergraph this filter belongs to + + /** + * Type of multithreading being allowed/used. A combination of + * AVFILTER_THREAD_* flags. + * + * May be set by the caller before initializing the filter to forbid some + * or all kinds of multithreading for this filter. The default is allowing + * everything. + * + * When the filter is initialized, this field is combined using bit AND with + * AVFilterGraph.thread_type to get the final mask used for determining + * allowed threading types. I.e. a threading type needs to be set in both + * to be allowed. + * + * After the filter is initialized, libavfilter sets this field to the + * threading type that is actually used (0 for no multithreading). + */ + int thread_type; + + /** + * An opaque struct for libavfilter internal use. + */ + AVFilterInternal *internal; + + struct AVFilterCommand *command_queue; + + char *enable_str; ///< enable expression string + void *enable; ///< parsed expression (AVExpr*) + double *var_values; ///< variable values for the enable expression + int is_disabled; ///< the enabled state from the last expression evaluation + + /** + * For filters which will create hardware frames, sets the device the + * filter should create them in. All other filters will ignore this field: + * in particular, a filter which consumes or processes hardware frames will + * instead use the hw_frames_ctx field in AVFilterLink to carry the + * hardware context information. + */ + AVBufferRef *hw_device_ctx; + + /** + * Max number of threads allowed in this filter instance. + * If <= 0, its value is ignored. + * Overrides global number of threads set per filter graph. + */ + int nb_threads; + + /** + * Ready status of the filter. + * A non-0 value means that the filter needs activating; + * a higher value suggests a more urgent activation. + */ + unsigned ready; + + /** + * Sets the number of extra hardware frames which the filter will + * allocate on its output links for use in following filters or by + * the caller. + * + * Some hardware filters require all frames that they will use for + * output to be defined in advance before filtering starts. For such + * filters, any hardware frame pools used for output must therefore be + * of fixed size. The extra frames set here are on top of any number + * that the filter needs internally in order to operate normally. + * + * This field must be set before the graph containing this filter is + * configured. + */ + int extra_hw_frames; +}; + +/** + * A link between two filters. This contains pointers to the source and + * destination filters between which this link exists, and the indexes of + * the pads involved. In addition, this link also contains the parameters + * which have been negotiated and agreed upon between the filter, such as + * image dimensions, format, etc. + * + * Applications must not normally access the link structure directly. + * Use the buffersrc and buffersink API instead. + * In the future, access to the header may be reserved for filters + * implementation. + */ +struct AVFilterLink { + AVFilterContext *src; ///< source filter + AVFilterPad *srcpad; ///< output pad on the source filter + + AVFilterContext *dst; ///< dest filter + AVFilterPad *dstpad; ///< input pad on the dest filter + + enum AVMediaType type; ///< filter media type + + /* These parameters apply only to video */ + int w; ///< agreed upon image width + int h; ///< agreed upon image height + AVRational sample_aspect_ratio; ///< agreed upon sample aspect ratio + /* These parameters apply only to audio */ + uint64_t channel_layout; ///< channel layout of current buffer (see libavutil/channel_layout.h) + int sample_rate; ///< samples per second + + int format; ///< agreed upon media format + + /** + * Define the time base used by the PTS of the frames/samples + * which will pass through this link. + * During the configuration stage, each filter is supposed to + * change only the output timebase, while the timebase of the + * input link is assumed to be an unchangeable property. + */ + AVRational time_base; + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavfilter and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + /** + * Lists of formats and channel layouts supported by the input and output + * filters respectively. These lists are used for negotiating the format + * to actually be used, which will be loaded into the format and + * channel_layout members, above, when chosen. + * + */ + AVFilterFormats *in_formats; + AVFilterFormats *out_formats; + + /** + * Lists of channel layouts and sample rates used for automatic + * negotiation. + */ + AVFilterFormats *in_samplerates; + AVFilterFormats *out_samplerates; + struct AVFilterChannelLayouts *in_channel_layouts; + struct AVFilterChannelLayouts *out_channel_layouts; + + /** + * Audio only, the destination filter sets this to a non-zero value to + * request that buffers with the given number of samples should be sent to + * it. AVFilterPad.needs_fifo must also be set on the corresponding input + * pad. + * Last buffer before EOF will be padded with silence. + */ + int request_samples; + + /** stage of the initialization of the link properties (dimensions, etc) */ + enum { + AVLINK_UNINIT = 0, ///< not started + AVLINK_STARTINIT, ///< started, but incomplete + AVLINK_INIT ///< complete + } init_state; + + /** + * Graph the filter belongs to. + */ + struct AVFilterGraph *graph; + + /** + * Current timestamp of the link, as defined by the most recent + * frame(s), in link time_base units. + */ + int64_t current_pts; + + /** + * Current timestamp of the link, as defined by the most recent + * frame(s), in AV_TIME_BASE units. + */ + int64_t current_pts_us; + + /** + * Index in the age array. + */ + int age_index; + + /** + * Frame rate of the stream on the link, or 1/0 if unknown or variable; + * if left to 0/0, will be automatically copied from the first input + * of the source filter if it exists. + * + * Sources should set it to the best estimation of the real frame rate. + * If the source frame rate is unknown or variable, set this to 1/0. + * Filters should update it if necessary depending on their function. + * Sinks can use it to set a default output frame rate. + * It is similar to the r_frame_rate field in AVStream. + */ + AVRational frame_rate; + + /** + * Buffer partially filled with samples to achieve a fixed/minimum size. + */ + AVFrame *partial_buf; + + /** + * Size of the partial buffer to allocate. + * Must be between min_samples and max_samples. + */ + int partial_buf_size; + + /** + * Minimum number of samples to filter at once. If filter_frame() is + * called with fewer samples, it will accumulate them in partial_buf. + * This field and the related ones must not be changed after filtering + * has started. + * If 0, all related fields are ignored. + */ + int min_samples; + + /** + * Maximum number of samples to filter at once. If filter_frame() is + * called with more samples, it will split them. + */ + int max_samples; + + /** + * Number of channels. + */ + int channels; + + /** + * Link processing flags. + */ + unsigned flags; + + /** + * Number of past frames sent through the link. + */ + int64_t frame_count_in, frame_count_out; + + /** + * A pointer to a FFFramePool struct. + */ + void *frame_pool; + + /** + * True if a frame is currently wanted on the output of this filter. + * Set when ff_request_frame() is called by the output, + * cleared when a frame is filtered. + */ + int frame_wanted_out; + + /** + * For hwaccel pixel formats, this should be a reference to the + * AVHWFramesContext describing the frames. + */ + AVBufferRef *hw_frames_ctx; + +#ifndef FF_INTERNAL_FIELDS + + /** + * Internal structure members. + * The fields below this limit are internal for libavfilter's use + * and must in no way be accessed by applications. + */ + char reserved[0xF000]; + +#else /* FF_INTERNAL_FIELDS */ + + /** + * Queue of frames waiting to be filtered. + */ + FFFrameQueue fifo; + + /** + * If set, the source filter can not generate a frame as is. + * The goal is to avoid repeatedly calling the request_frame() method on + * the same link. + */ + int frame_blocked_in; + + /** + * Link input status. + * If not zero, all attempts of filter_frame will fail with the + * corresponding code. + */ + int status_in; + + /** + * Timestamp of the input status change. + */ + int64_t status_in_pts; + + /** + * Link output status. + * If not zero, all attempts of request_frame will fail with the + * corresponding code. + */ + int status_out; + +#endif /* FF_INTERNAL_FIELDS */ + +}; + +/** + * Link two filters together. + * + * @param src the source filter + * @param srcpad index of the output pad on the source filter + * @param dst the destination filter + * @param dstpad index of the input pad on the destination filter + * @return zero on success + */ +int avfilter_link(AVFilterContext *src, unsigned srcpad, + AVFilterContext *dst, unsigned dstpad); + +/** + * Free the link in *link, and set its pointer to NULL. + */ +void avfilter_link_free(AVFilterLink **link); + +#if FF_API_FILTER_GET_SET +/** + * Get the number of channels of a link. + * @deprecated Use av_buffersink_get_channels() + */ +attribute_deprecated +int avfilter_link_get_channels(AVFilterLink *link); +#endif + +/** + * Set the closed field of a link. + * @deprecated applications are not supposed to mess with links, they should + * close the sinks. + */ +attribute_deprecated +void avfilter_link_set_closed(AVFilterLink *link, int closed); + +/** + * Negotiate the media format, dimensions, etc of all inputs to a filter. + * + * @param filter the filter to negotiate the properties for its inputs + * @return zero on successful negotiation + */ +int avfilter_config_links(AVFilterContext *filter); + +#define AVFILTER_CMD_FLAG_ONE 1 ///< Stop once a filter understood the command (for target=all for example), fast filters are favored automatically +#define AVFILTER_CMD_FLAG_FAST 2 ///< Only execute command when its fast (like a video out that supports contrast adjustment in hw) + +/** + * Make the filter instance process a command. + * It is recommended to use avfilter_graph_send_command(). + */ +int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags); + +/** + * Iterate over all registered filters. + * + * @param opaque a pointer where libavfilter will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered filter or NULL when the iteration is + * finished + */ +const AVFilter *av_filter_iterate(void **opaque); + +#if FF_API_NEXT +/** Initialize the filter system. Register all builtin filters. */ +attribute_deprecated +void avfilter_register_all(void); + +/** + * Register a filter. This is only needed if you plan to use + * avfilter_get_by_name later to lookup the AVFilter structure by name. A + * filter can still by instantiated with avfilter_graph_alloc_filter even if it + * is not registered. + * + * @param filter the filter to register + * @return 0 if the registration was successful, a negative value + * otherwise + */ +attribute_deprecated +int avfilter_register(AVFilter *filter); + +/** + * Iterate over all registered filters. + * @return If prev is non-NULL, next registered filter after prev or NULL if + * prev is the last filter. If prev is NULL, return the first registered filter. + */ +attribute_deprecated +const AVFilter *avfilter_next(const AVFilter *prev); +#endif + +/** + * Get a filter definition matching the given name. + * + * @param name the filter name to find + * @return the filter definition, if any matching one is registered. + * NULL if none found. + */ +const AVFilter *avfilter_get_by_name(const char *name); + + +/** + * Initialize a filter with the supplied parameters. + * + * @param ctx uninitialized filter context to initialize + * @param args Options to initialize the filter with. This must be a + * ':'-separated list of options in the 'key=value' form. + * May be NULL if the options have been set directly using the + * AVOptions API or there are no options that need to be set. + * @return 0 on success, a negative AVERROR on failure + */ +int avfilter_init_str(AVFilterContext *ctx, const char *args); + +/** + * Initialize a filter with the supplied dictionary of options. + * + * @param ctx uninitialized filter context to initialize + * @param options An AVDictionary filled with options for this filter. On + * return this parameter will be destroyed and replaced with + * a dict containing options that were not found. This dictionary + * must be freed by the caller. + * May be NULL, then this function is equivalent to + * avfilter_init_str() with the second parameter set to NULL. + * @return 0 on success, a negative AVERROR on failure + * + * @note This function and avfilter_init_str() do essentially the same thing, + * the difference is in manner in which the options are passed. It is up to the + * calling code to choose whichever is more preferable. The two functions also + * behave differently when some of the provided options are not declared as + * supported by the filter. In such a case, avfilter_init_str() will fail, but + * this function will leave those extra options in the options AVDictionary and + * continue as usual. + */ +int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options); + +/** + * Free a filter context. This will also remove the filter from its + * filtergraph's list of filters. + * + * @param filter the filter to free + */ +void avfilter_free(AVFilterContext *filter); + +/** + * Insert a filter in the middle of an existing link. + * + * @param link the link into which the filter should be inserted + * @param filt the filter to be inserted + * @param filt_srcpad_idx the input pad on the filter to connect + * @param filt_dstpad_idx the output pad on the filter to connect + * @return zero on success + */ +int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt, + unsigned filt_srcpad_idx, unsigned filt_dstpad_idx); + +/** + * @return AVClass for AVFilterContext. + * + * @see av_opt_find(). + */ +const AVClass *avfilter_get_class(void); + +typedef struct AVFilterGraphInternal AVFilterGraphInternal; + +/** + * A function pointer passed to the @ref AVFilterGraph.execute callback to be + * executed multiple times, possibly in parallel. + * + * @param ctx the filter context the job belongs to + * @param arg an opaque parameter passed through from @ref + * AVFilterGraph.execute + * @param jobnr the index of the job being executed + * @param nb_jobs the total number of jobs + * + * @return 0 on success, a negative AVERROR on error + */ +typedef int (avfilter_action_func)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); + +/** + * A function executing multiple jobs, possibly in parallel. + * + * @param ctx the filter context to which the jobs belong + * @param func the function to be called multiple times + * @param arg the argument to be passed to func + * @param ret a nb_jobs-sized array to be filled with return values from each + * invocation of func + * @param nb_jobs the number of jobs to execute + * + * @return 0 on success, a negative AVERROR on error + */ +typedef int (avfilter_execute_func)(AVFilterContext *ctx, avfilter_action_func *func, + void *arg, int *ret, int nb_jobs); + +typedef struct AVFilterGraph { + const AVClass *av_class; + AVFilterContext **filters; + unsigned nb_filters; + + char *scale_sws_opts; ///< sws options to use for the auto-inserted scale filters +#if FF_API_LAVR_OPTS + attribute_deprecated char *resample_lavr_opts; ///< libavresample options to use for the auto-inserted resample filters +#endif + + /** + * Type of multithreading allowed for filters in this graph. A combination + * of AVFILTER_THREAD_* flags. + * + * May be set by the caller at any point, the setting will apply to all + * filters initialized after that. The default is allowing everything. + * + * When a filter in this graph is initialized, this field is combined using + * bit AND with AVFilterContext.thread_type to get the final mask used for + * determining allowed threading types. I.e. a threading type needs to be + * set in both to be allowed. + */ + int thread_type; + + /** + * Maximum number of threads used by filters in this graph. May be set by + * the caller before adding any filters to the filtergraph. Zero (the + * default) means that the number of threads is determined automatically. + */ + int nb_threads; + + /** + * Opaque object for libavfilter internal use. + */ + AVFilterGraphInternal *internal; + + /** + * Opaque user data. May be set by the caller to an arbitrary value, e.g. to + * be used from callbacks like @ref AVFilterGraph.execute. + * Libavfilter will not touch this field in any way. + */ + void *opaque; + + /** + * This callback may be set by the caller immediately after allocating the + * graph and before adding any filters to it, to provide a custom + * multithreading implementation. + * + * If set, filters with slice threading capability will call this callback + * to execute multiple jobs in parallel. + * + * If this field is left unset, libavfilter will use its internal + * implementation, which may or may not be multithreaded depending on the + * platform and build options. + */ + avfilter_execute_func *execute; + + char *aresample_swr_opts; ///< swr options to use for the auto-inserted aresample filters, Access ONLY through AVOptions + + /** + * Private fields + * + * The following fields are for internal use only. + * Their type, offset, number and semantic can change without notice. + */ + + AVFilterLink **sink_links; + int sink_links_count; + + unsigned disable_auto_convert; +} AVFilterGraph; + +/** + * Allocate a filter graph. + * + * @return the allocated filter graph on success or NULL. + */ +AVFilterGraph *avfilter_graph_alloc(void); + +/** + * Create a new filter instance in a filter graph. + * + * @param graph graph in which the new filter will be used + * @param filter the filter to create an instance of + * @param name Name to give to the new instance (will be copied to + * AVFilterContext.name). This may be used by the caller to identify + * different filters, libavfilter itself assigns no semantics to + * this parameter. May be NULL. + * + * @return the context of the newly created filter instance (note that it is + * also retrievable directly through AVFilterGraph.filters or with + * avfilter_graph_get_filter()) on success or NULL on failure. + */ +AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph, + const AVFilter *filter, + const char *name); + +/** + * Get a filter instance identified by instance name from graph. + * + * @param graph filter graph to search through. + * @param name filter instance name (should be unique in the graph). + * @return the pointer to the found filter instance or NULL if it + * cannot be found. + */ +AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name); + +/** + * Create and add a filter instance into an existing graph. + * The filter instance is created from the filter filt and inited + * with the parameters args and opaque. + * + * In case of success put in *filt_ctx the pointer to the created + * filter instance, otherwise set *filt_ctx to NULL. + * + * @param name the instance name to give to the created filter instance + * @param graph_ctx the filter graph + * @return a negative AVERROR error code in case of failure, a non + * negative value otherwise + */ +int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt, + const char *name, const char *args, void *opaque, + AVFilterGraph *graph_ctx); + +/** + * Enable or disable automatic format conversion inside the graph. + * + * Note that format conversion can still happen inside explicitly inserted + * scale and aresample filters. + * + * @param flags any of the AVFILTER_AUTO_CONVERT_* constants + */ +void avfilter_graph_set_auto_convert(AVFilterGraph *graph, unsigned flags); + +enum { + AVFILTER_AUTO_CONVERT_ALL = 0, /**< all automatic conversions enabled */ + AVFILTER_AUTO_CONVERT_NONE = -1, /**< all automatic conversions disabled */ +}; + +/** + * Check validity and configure all the links and formats in the graph. + * + * @param graphctx the filter graph + * @param log_ctx context used for logging + * @return >= 0 in case of success, a negative AVERROR code otherwise + */ +int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx); + +/** + * Free a graph, destroy its links, and set *graph to NULL. + * If *graph is NULL, do nothing. + */ +void avfilter_graph_free(AVFilterGraph **graph); + +/** + * A linked-list of the inputs/outputs of the filter chain. + * + * This is mainly useful for avfilter_graph_parse() / avfilter_graph_parse2(), + * where it is used to communicate open (unlinked) inputs and outputs from and + * to the caller. + * This struct specifies, per each not connected pad contained in the graph, the + * filter context and the pad index required for establishing a link. + */ +typedef struct AVFilterInOut { + /** unique name for this input/output in the list */ + char *name; + + /** filter context associated to this input/output */ + AVFilterContext *filter_ctx; + + /** index of the filt_ctx pad to use for linking */ + int pad_idx; + + /** next input/input in the list, NULL if this is the last */ + struct AVFilterInOut *next; +} AVFilterInOut; + +/** + * Allocate a single AVFilterInOut entry. + * Must be freed with avfilter_inout_free(). + * @return allocated AVFilterInOut on success, NULL on failure. + */ +AVFilterInOut *avfilter_inout_alloc(void); + +/** + * Free the supplied list of AVFilterInOut and set *inout to NULL. + * If *inout is NULL, do nothing. + */ +void avfilter_inout_free(AVFilterInOut **inout); + +/** + * Add a graph described by a string to a graph. + * + * @note The caller must provide the lists of inputs and outputs, + * which therefore must be known before calling the function. + * + * @note The inputs parameter describes inputs of the already existing + * part of the graph; i.e. from the point of view of the newly created + * part, they are outputs. Similarly the outputs parameter describes + * outputs of the already existing filters, which are provided as + * inputs to the parsed filters. + * + * @param graph the filter graph where to link the parsed graph context + * @param filters string to be parsed + * @param inputs linked list to the inputs of the graph + * @param outputs linked list to the outputs of the graph + * @return zero on success, a negative AVERROR code on error + */ +int avfilter_graph_parse(AVFilterGraph *graph, const char *filters, + AVFilterInOut *inputs, AVFilterInOut *outputs, + void *log_ctx); + +/** + * Add a graph described by a string to a graph. + * + * In the graph filters description, if the input label of the first + * filter is not specified, "in" is assumed; if the output label of + * the last filter is not specified, "out" is assumed. + * + * @param graph the filter graph where to link the parsed graph context + * @param filters string to be parsed + * @param inputs pointer to a linked list to the inputs of the graph, may be NULL. + * If non-NULL, *inputs is updated to contain the list of open inputs + * after the parsing, should be freed with avfilter_inout_free(). + * @param outputs pointer to a linked list to the outputs of the graph, may be NULL. + * If non-NULL, *outputs is updated to contain the list of open outputs + * after the parsing, should be freed with avfilter_inout_free(). + * @return non negative on success, a negative AVERROR code on error + */ +int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters, + AVFilterInOut **inputs, AVFilterInOut **outputs, + void *log_ctx); + +/** + * Add a graph described by a string to a graph. + * + * @param[in] graph the filter graph where to link the parsed graph context + * @param[in] filters string to be parsed + * @param[out] inputs a linked list of all free (unlinked) inputs of the + * parsed graph will be returned here. It is to be freed + * by the caller using avfilter_inout_free(). + * @param[out] outputs a linked list of all free (unlinked) outputs of the + * parsed graph will be returned here. It is to be freed by the + * caller using avfilter_inout_free(). + * @return zero on success, a negative AVERROR code on error + * + * @note This function returns the inputs and outputs that are left + * unlinked after parsing the graph and the caller then deals with + * them. + * @note This function makes no reference whatsoever to already + * existing parts of the graph and the inputs parameter will on return + * contain inputs of the newly parsed part of the graph. Analogously + * the outputs parameter will contain outputs of the newly created + * filters. + */ +int avfilter_graph_parse2(AVFilterGraph *graph, const char *filters, + AVFilterInOut **inputs, + AVFilterInOut **outputs); + +/** + * Send a command to one or more filter instances. + * + * @param graph the filter graph + * @param target the filter(s) to which the command should be sent + * "all" sends to all filters + * otherwise it can be a filter or filter instance name + * which will send the command to all matching filters. + * @param cmd the command to send, for handling simplicity all commands must be alphanumeric only + * @param arg the argument for the command + * @param res a buffer with size res_size where the filter(s) can return a response. + * + * @returns >=0 on success otherwise an error code. + * AVERROR(ENOSYS) on unsupported commands + */ +int avfilter_graph_send_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, char *res, int res_len, int flags); + +/** + * Queue a command for one or more filter instances. + * + * @param graph the filter graph + * @param target the filter(s) to which the command should be sent + * "all" sends to all filters + * otherwise it can be a filter or filter instance name + * which will send the command to all matching filters. + * @param cmd the command to sent, for handling simplicity all commands must be alphanumeric only + * @param arg the argument for the command + * @param ts time at which the command should be sent to the filter + * + * @note As this executes commands after this function returns, no return code + * from the filter is provided, also AVFILTER_CMD_FLAG_ONE is not supported. + */ +int avfilter_graph_queue_command(AVFilterGraph *graph, const char *target, const char *cmd, const char *arg, int flags, double ts); + + +/** + * Dump a graph into a human-readable string representation. + * + * @param graph the graph to dump + * @param options formatting options; currently ignored + * @return a string, or NULL in case of memory allocation failure; + * the string must be freed using av_free + */ +char *avfilter_graph_dump(AVFilterGraph *graph, const char *options); + +/** + * Request a frame on the oldest sink link. + * + * If the request returns AVERROR_EOF, try the next. + * + * Note that this function is not meant to be the sole scheduling mechanism + * of a filtergraph, only a convenience function to help drain a filtergraph + * in a balanced way under normal circumstances. + * + * Also note that AVERROR_EOF does not mean that frames did not arrive on + * some of the sinks during the process. + * When there are multiple sink links, in case the requested link + * returns an EOF, this may cause a filter to flush pending frames + * which are sent to another sink link, although unrequested. + * + * @return the return value of ff_request_frame(), + * or AVERROR_EOF if all links returned AVERROR_EOF + */ +int avfilter_graph_request_oldest(AVFilterGraph *graph); + +/** + * @} + */ + +#endif /* AVFILTER_AVFILTER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/bufferqueue.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/bufferqueue.h new file mode 100644 index 0000000000..f5e5df2d72 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/bufferqueue.h @@ -0,0 +1,121 @@ +/* + * Generic buffer queue + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_BUFFERQUEUE_H +#define AVFILTER_BUFFERQUEUE_H + +/** + * FFBufQueue: simple AVFrame queue API + * + * Note: this API is not thread-safe. Concurrent access to the same queue + * must be protected by a mutex or any synchronization mechanism. + */ + +/** + * Maximum size of the queue. + * + * This value can be overridden by definying it before including this + * header. + * Powers of 2 are recommended. + */ +#ifndef FF_BUFQUEUE_SIZE +#define FF_BUFQUEUE_SIZE 64 +#endif + +#include "avfilter.h" +#include "libavutil/avassert.h" + +/** + * Structure holding the queue + */ +struct FFBufQueue { + AVFrame *queue[FF_BUFQUEUE_SIZE]; + unsigned short head; + unsigned short available; /**< number of available buffers */ +}; + +#define BUCKET(i) queue->queue[(queue->head + (i)) % FF_BUFQUEUE_SIZE] + +/** + * Test if a buffer queue is full. + */ +static inline int ff_bufqueue_is_full(struct FFBufQueue *queue) +{ + return queue->available == FF_BUFQUEUE_SIZE; +} + +/** + * Add a buffer to the queue. + * + * If the queue is already full, then the current last buffer is dropped + * (and unrefed) with a warning before adding the new buffer. + */ +static inline void ff_bufqueue_add(void *log, struct FFBufQueue *queue, + AVFrame *buf) +{ + if (ff_bufqueue_is_full(queue)) { + av_log(log, AV_LOG_WARNING, "Buffer queue overflow, dropping.\n"); + av_frame_free(&BUCKET(--queue->available)); + } + BUCKET(queue->available++) = buf; +} + +/** + * Get a buffer from the queue without altering it. + * + * Buffer with index 0 is the first buffer in the queue. + * Return NULL if the queue has not enough buffers. + */ +static inline AVFrame *ff_bufqueue_peek(struct FFBufQueue *queue, + unsigned index) +{ + return index < queue->available ? BUCKET(index) : NULL; +} + +/** + * Get the first buffer from the queue and remove it. + * + * Do not use on an empty queue. + */ +static inline AVFrame *ff_bufqueue_get(struct FFBufQueue *queue) +{ + AVFrame *ret = queue->queue[queue->head]; + av_assert0(queue->available); + queue->available--; + queue->queue[queue->head] = NULL; + queue->head = (queue->head + 1) % FF_BUFQUEUE_SIZE; + return ret; +} + +/** + * Unref and remove all buffers from the queue. + */ +static inline void ff_bufqueue_discard_all(struct FFBufQueue *queue) +{ + while (queue->available) { + AVFrame *buf = ff_bufqueue_get(queue); + av_frame_free(&buf); + } +} + +#undef BUCKET + +#endif /* AVFILTER_BUFFERQUEUE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/filter_list.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/filter_list.c new file mode 100644 index 0000000000..9a55cb886c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/filter_list.c @@ -0,0 +1,6 @@ +static const AVFilter * const filter_list[] = { + &ff_asrc_abuffer, + &ff_vsrc_buffer, + &ff_asink_abuffer, + &ff_vsink_buffer, + NULL }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/version.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/version.h new file mode 100644 index 0000000000..cc5b23b70b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/version.h @@ -0,0 +1,66 @@ +/* + * Version macros. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_VERSION_H +#define AVFILTER_VERSION_H + +/** + * @file + * @ingroup lavfi + * Libavfilter version macros + */ + +#include "libavutil/version.h" + +#define LIBAVFILTER_VERSION_MAJOR 7 +#define LIBAVFILTER_VERSION_MINOR 57 +#define LIBAVFILTER_VERSION_MICRO 100 + + +#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ + LIBAVFILTER_VERSION_MINOR, \ + LIBAVFILTER_VERSION_MICRO) +#define LIBAVFILTER_VERSION AV_VERSION(LIBAVFILTER_VERSION_MAJOR, \ + LIBAVFILTER_VERSION_MINOR, \ + LIBAVFILTER_VERSION_MICRO) +#define LIBAVFILTER_BUILD LIBAVFILTER_VERSION_INT + +#define LIBAVFILTER_IDENT "Lavfi" AV_STRINGIFY(LIBAVFILTER_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ + +#ifndef FF_API_OLD_FILTER_OPTS_ERROR +#define FF_API_OLD_FILTER_OPTS_ERROR (LIBAVFILTER_VERSION_MAJOR < 8) +#endif +#ifndef FF_API_LAVR_OPTS +#define FF_API_LAVR_OPTS (LIBAVFILTER_VERSION_MAJOR < 8) +#endif +#ifndef FF_API_FILTER_GET_SET +#define FF_API_FILTER_GET_SET (LIBAVFILTER_VERSION_MAJOR < 8) +#endif +#ifndef FF_API_NEXT +#define FF_API_NEXT (LIBAVFILTER_VERSION_MAJOR < 8) +#endif + +#endif /* AVFILTER_VERSION_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/window_func.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/window_func.h new file mode 100644 index 0000000000..1de8f1fbdb --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavfilter/window_func.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2015 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef AVFILTER_WINDOW_FUNC_H +#define AVFILTER_WINDOW_FUNC_H + +#include +#include "libavutil/avassert.h" + +enum WindowFunc { WFUNC_RECT, WFUNC_HANNING, WFUNC_HAMMING, WFUNC_BLACKMAN, + WFUNC_BARTLETT, WFUNC_WELCH, WFUNC_FLATTOP, + WFUNC_BHARRIS, WFUNC_BNUTTALL, WFUNC_SINE, WFUNC_NUTTALL, + WFUNC_BHANN, WFUNC_LANCZOS, WFUNC_GAUSS, WFUNC_TUKEY, + WFUNC_DOLPH, WFUNC_CAUCHY, WFUNC_PARZEN, WFUNC_POISSON, + WFUNC_BOHMAN, + NB_WFUNC }; + +static inline void generate_window_func(float *lut, int N, int win_func, + float *overlap) +{ + int n; + + switch (win_func) { + case WFUNC_RECT: + for (n = 0; n < N; n++) + lut[n] = 1.; + *overlap = 0.; + break; + case WFUNC_BARTLETT: + for (n = 0; n < N; n++) + lut[n] = 1.-fabs((n-(N-1)/2.)/((N-1)/2.)); + *overlap = 0.5; + break; + case WFUNC_HANNING: + for (n = 0; n < N; n++) + lut[n] = .5*(1-cos(2*M_PI*n/(N-1))); + *overlap = 0.5; + break; + case WFUNC_HAMMING: + for (n = 0; n < N; n++) + lut[n] = .54-.46*cos(2*M_PI*n/(N-1)); + *overlap = 0.5; + break; + case WFUNC_BLACKMAN: + for (n = 0; n < N; n++) + lut[n] = .42659-.49656*cos(2*M_PI*n/(N-1))+.076849*cos(4*M_PI*n/(N-1)); + *overlap = 0.661; + break; + case WFUNC_WELCH: + for (n = 0; n < N; n++) + lut[n] = 1.-(n-(N-1)/2.)/((N-1)/2.)*(n-(N-1)/2.)/((N-1)/2.); + *overlap = 0.293; + break; + case WFUNC_FLATTOP: + for (n = 0; n < N; n++) + lut[n] = 1.-1.985844164102*cos( 2*M_PI*n/(N-1))+1.791176438506*cos( 4*M_PI*n/(N-1))- + 1.282075284005*cos( 6*M_PI*n/(N-1))+0.667777530266*cos( 8*M_PI*n/(N-1))- + 0.240160796576*cos(10*M_PI*n/(N-1))+0.056656381764*cos(12*M_PI*n/(N-1))- + 0.008134974479*cos(14*M_PI*n/(N-1))+0.000624544650*cos(16*M_PI*n/(N-1))- + 0.000019808998*cos(18*M_PI*n/(N-1))+0.000000132974*cos(20*M_PI*n/(N-1)); + *overlap = 0.841; + break; + case WFUNC_BHARRIS: + for (n = 0; n < N; n++) + lut[n] = 0.35875-0.48829*cos(2*M_PI*n/(N-1))+0.14128*cos(4*M_PI*n/(N-1))-0.01168*cos(6*M_PI*n/(N-1)); + *overlap = 0.661; + break; + case WFUNC_BNUTTALL: + for (n = 0; n < N; n++) + lut[n] = 0.3635819-0.4891775*cos(2*M_PI*n/(N-1))+0.1365995*cos(4*M_PI*n/(N-1))-0.0106411*cos(6*M_PI*n/(N-1)); + *overlap = 0.661; + break; + case WFUNC_BHANN: + for (n = 0; n < N; n++) + lut[n] = 0.62-0.48*fabs(n/(double)(N-1)-.5)-0.38*cos(2*M_PI*n/(N-1)); + *overlap = 0.5; + break; + case WFUNC_SINE: + for (n = 0; n < N; n++) + lut[n] = sin(M_PI*n/(N-1)); + *overlap = 0.75; + break; + case WFUNC_NUTTALL: + for (n = 0; n < N; n++) + lut[n] = 0.355768-0.487396*cos(2*M_PI*n/(N-1))+0.144232*cos(4*M_PI*n/(N-1))-0.012604*cos(6*M_PI*n/(N-1)); + *overlap = 0.663; + break; + case WFUNC_LANCZOS: + #define SINC(x) (!(x)) ? 1 : sin(M_PI * (x))/(M_PI * (x)); + for (n = 0; n < N; n++) + lut[n] = SINC((2.*n)/(N-1)-1); + *overlap = 0.75; + break; + case WFUNC_GAUSS: + #define SQR(x) ((x)*(x)) + for (n = 0; n < N; n++) + lut[n] = exp(-0.5 * SQR((n-(N-1)/2)/(0.4*(N-1)/2.f))); + *overlap = 0.75; + break; + case WFUNC_TUKEY: + for (n = 0; n < N; n++) { + float M = (N-1)/2.; + + if (FFABS(n - M) >= 0.3 * M) { + lut[n] = 0.5 * (1 + cos((M_PI*(FFABS(n - M) - 0.3 * M))/((1 - 0.3) * M))); + } else { + lut[n] = 1; + } + } + *overlap = 0.33; + break; + case WFUNC_DOLPH: { + double b = cosh(7.6009022095419887 / (N-1)), sum, t, c, norm = 0; + int j; + for (c = 1 - 1 / (b*b), n = (N-1) / 2; n >= 0; --n) { + for (sum = !n, b = t = j = 1; j <= n && sum != t; b *= (n-j) * (1./j), ++j) + t = sum, sum += (b *= c * (N - n - j) * (1./j)); + sum /= (N - 1 - n), sum /= (norm = norm ? norm : sum); + lut[n] = sum; + lut[N - 1 - n] = sum; + } + *overlap = 0.5;} + break; + case WFUNC_CAUCHY: + for (n = 0; n < N; n++) { + double x = 2 * ((n / (double)(N - 1)) - .5); + + if (x <= -.5 || x >= .5) { + lut[n] = 0; + } else { + lut[n] = FFMIN(1, fabs(1/(1+4*16*x*x))); + } + } + *overlap = 0.75; + break; + case WFUNC_PARZEN: + for (n = 0; n < N; n++) { + double x = 2 * ((n / (double)(N - 1)) - .5); + + if (x > 0.25 && x <= 0.5) { + lut[n] = -2 * powf(-1 + 2 * x, 3); + } else if (x >= -.5 && x < -.25) { + lut[n] = 2 * powf(1 + 2 * x, 3); + } else if (x >= -.25 && x < 0) { + lut[n] = 1 - 24 * x * x - 48 * x * x * x; + } else if (x >= 0 && x <= .25) { + lut[n] = 1 - 24 * x * x + 48 * x * x * x; + } else { + lut[n] = 0; + } + } + *overlap = 0.75; + break; + case WFUNC_POISSON: + for (n = 0; n < N; n++) { + double x = 2 * ((n / (double)(N - 1)) - .5); + + if (x >= 0 && x <= .5) { + lut[n] = exp(-6*x); + } else if (x < 0 && x >= -.5) { + lut[n] = exp(6*x); + } else { + lut[n] = 0; + } + } + *overlap = 0.75; + break; + case WFUNC_BOHMAN: + for (n = 0; n < N; n++) { + double x = 2 * ((n / (double)(N - 1))) - 1.; + + lut[n] = (1 - fabs(x)) * cos(M_PI*fabs(x)) + 1./M_PI*sin(M_PI*fabs(x)); + } + *overlap = 0.75; + break; + default: + av_assert0(0); + } +} + +#endif /* AVFILTER_WINDOW_FUNC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/allformats.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/allformats.c new file mode 100644 index 0000000000..cd00834807 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/allformats.c @@ -0,0 +1,641 @@ +/* + * Register all the formats and protocols + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/thread.h" +#include "libavformat/internal.h" +#include "avformat.h" +#include "rtp.h" +#include "rdt.h" +#include "url.h" +#include "version.h" + +/* (de)muxers */ +extern AVOutputFormat ff_a64_muxer; +extern AVInputFormat ff_aa_demuxer; +extern AVInputFormat ff_aac_demuxer; +extern AVInputFormat ff_ac3_demuxer; +extern AVOutputFormat ff_ac3_muxer; +extern AVInputFormat ff_acm_demuxer; +extern AVInputFormat ff_act_demuxer; +extern AVInputFormat ff_adf_demuxer; +extern AVInputFormat ff_adp_demuxer; +extern AVInputFormat ff_ads_demuxer; +extern AVOutputFormat ff_adts_muxer; +extern AVInputFormat ff_adx_demuxer; +extern AVOutputFormat ff_adx_muxer; +extern AVInputFormat ff_aea_demuxer; +extern AVInputFormat ff_afc_demuxer; +extern AVInputFormat ff_aiff_demuxer; +extern AVOutputFormat ff_aiff_muxer; +extern AVInputFormat ff_aix_demuxer; +extern AVInputFormat ff_amr_demuxer; +extern AVOutputFormat ff_amr_muxer; +extern AVInputFormat ff_amrnb_demuxer; +extern AVInputFormat ff_amrwb_demuxer; +extern AVInputFormat ff_anm_demuxer; +extern AVInputFormat ff_apc_demuxer; +extern AVInputFormat ff_ape_demuxer; +extern AVInputFormat ff_apng_demuxer; +extern AVOutputFormat ff_apng_muxer; +extern AVInputFormat ff_aptx_demuxer; +extern AVOutputFormat ff_aptx_muxer; +extern AVInputFormat ff_aptx_hd_demuxer; +extern AVOutputFormat ff_aptx_hd_muxer; +extern AVInputFormat ff_aqtitle_demuxer; +extern AVInputFormat ff_asf_demuxer; +extern AVOutputFormat ff_asf_muxer; +extern AVInputFormat ff_asf_o_demuxer; +extern AVInputFormat ff_ass_demuxer; +extern AVOutputFormat ff_ass_muxer; +extern AVInputFormat ff_ast_demuxer; +extern AVOutputFormat ff_ast_muxer; +extern AVOutputFormat ff_asf_stream_muxer; +extern AVInputFormat ff_au_demuxer; +extern AVOutputFormat ff_au_muxer; +extern AVInputFormat ff_avi_demuxer; +extern AVOutputFormat ff_avi_muxer; +extern AVInputFormat ff_avisynth_demuxer; +extern AVOutputFormat ff_avm2_muxer; +extern AVInputFormat ff_avr_demuxer; +extern AVInputFormat ff_avs_demuxer; +extern AVInputFormat ff_avs2_demuxer; +extern AVOutputFormat ff_avs2_muxer; +extern AVInputFormat ff_bethsoftvid_demuxer; +extern AVInputFormat ff_bfi_demuxer; +extern AVInputFormat ff_bintext_demuxer; +extern AVInputFormat ff_bink_demuxer; +extern AVInputFormat ff_bit_demuxer; +extern AVOutputFormat ff_bit_muxer; +extern AVInputFormat ff_bmv_demuxer; +extern AVInputFormat ff_bfstm_demuxer; +extern AVInputFormat ff_brstm_demuxer; +extern AVInputFormat ff_boa_demuxer; +extern AVInputFormat ff_c93_demuxer; +extern AVInputFormat ff_caf_demuxer; +extern AVOutputFormat ff_caf_muxer; +extern AVInputFormat ff_cavsvideo_demuxer; +extern AVOutputFormat ff_cavsvideo_muxer; +extern AVInputFormat ff_cdg_demuxer; +extern AVInputFormat ff_cdxl_demuxer; +extern AVInputFormat ff_cine_demuxer; +extern AVInputFormat ff_codec2_demuxer; +extern AVOutputFormat ff_codec2_muxer; +extern AVInputFormat ff_codec2raw_demuxer; +extern AVOutputFormat ff_codec2raw_muxer; +extern AVInputFormat ff_concat_demuxer; +extern AVOutputFormat ff_crc_muxer; +extern AVInputFormat ff_dash_demuxer; +extern AVOutputFormat ff_dash_muxer; +extern AVInputFormat ff_data_demuxer; +extern AVOutputFormat ff_data_muxer; +extern AVInputFormat ff_daud_demuxer; +extern AVOutputFormat ff_daud_muxer; +extern AVInputFormat ff_dcstr_demuxer; +extern AVInputFormat ff_dfa_demuxer; +extern AVInputFormat ff_dhav_demuxer; +extern AVInputFormat ff_dirac_demuxer; +extern AVOutputFormat ff_dirac_muxer; +extern AVInputFormat ff_dnxhd_demuxer; +extern AVOutputFormat ff_dnxhd_muxer; +extern AVInputFormat ff_dsf_demuxer; +extern AVInputFormat ff_dsicin_demuxer; +extern AVInputFormat ff_dss_demuxer; +extern AVInputFormat ff_dts_demuxer; +extern AVOutputFormat ff_dts_muxer; +extern AVInputFormat ff_dtshd_demuxer; +extern AVInputFormat ff_dv_demuxer; +extern AVOutputFormat ff_dv_muxer; +extern AVInputFormat ff_dvbsub_demuxer; +extern AVInputFormat ff_dvbtxt_demuxer; +extern AVInputFormat ff_dxa_demuxer; +extern AVInputFormat ff_ea_demuxer; +extern AVInputFormat ff_ea_cdata_demuxer; +extern AVInputFormat ff_eac3_demuxer; +extern AVOutputFormat ff_eac3_muxer; +extern AVInputFormat ff_epaf_demuxer; +extern AVOutputFormat ff_f4v_muxer; +extern AVInputFormat ff_ffmetadata_demuxer; +extern AVOutputFormat ff_ffmetadata_muxer; +extern AVOutputFormat ff_fifo_muxer; +extern AVOutputFormat ff_fifo_test_muxer; +extern AVInputFormat ff_filmstrip_demuxer; +extern AVOutputFormat ff_filmstrip_muxer; +extern AVInputFormat ff_fits_demuxer; +extern AVOutputFormat ff_fits_muxer; +extern AVInputFormat ff_flac_demuxer; +extern AVOutputFormat ff_flac_muxer; +extern AVInputFormat ff_flic_demuxer; +extern AVInputFormat ff_flv_demuxer; +extern AVOutputFormat ff_flv_muxer; +extern AVInputFormat ff_live_flv_demuxer; +extern AVInputFormat ff_fourxm_demuxer; +extern AVOutputFormat ff_framecrc_muxer; +extern AVOutputFormat ff_framehash_muxer; +extern AVOutputFormat ff_framemd5_muxer; +extern AVInputFormat ff_frm_demuxer; +extern AVInputFormat ff_fsb_demuxer; +extern AVInputFormat ff_g722_demuxer; +extern AVOutputFormat ff_g722_muxer; +extern AVInputFormat ff_g723_1_demuxer; +extern AVOutputFormat ff_g723_1_muxer; +extern AVInputFormat ff_g726_demuxer; +extern AVOutputFormat ff_g726_muxer; +extern AVInputFormat ff_g726le_demuxer; +extern AVOutputFormat ff_g726le_muxer; +extern AVInputFormat ff_g729_demuxer; +extern AVInputFormat ff_gdv_demuxer; +extern AVInputFormat ff_genh_demuxer; +extern AVInputFormat ff_gif_demuxer; +extern AVOutputFormat ff_gif_muxer; +extern AVInputFormat ff_gsm_demuxer; +extern AVOutputFormat ff_gsm_muxer; +extern AVInputFormat ff_gxf_demuxer; +extern AVOutputFormat ff_gxf_muxer; +extern AVInputFormat ff_h261_demuxer; +extern AVOutputFormat ff_h261_muxer; +extern AVInputFormat ff_h263_demuxer; +extern AVOutputFormat ff_h263_muxer; +extern AVInputFormat ff_h264_demuxer; +extern AVOutputFormat ff_h264_muxer; +extern AVOutputFormat ff_hash_muxer; +extern AVInputFormat ff_hcom_demuxer; +extern AVOutputFormat ff_hds_muxer; +extern AVInputFormat ff_hevc_demuxer; +extern AVOutputFormat ff_hevc_muxer; +extern AVInputFormat ff_hls_demuxer; +extern AVOutputFormat ff_hls_muxer; +extern AVInputFormat ff_hnm_demuxer; +extern AVInputFormat ff_ico_demuxer; +extern AVOutputFormat ff_ico_muxer; +extern AVInputFormat ff_idcin_demuxer; +extern AVInputFormat ff_idf_demuxer; +extern AVInputFormat ff_iff_demuxer; +extern AVInputFormat ff_ifv_demuxer; +extern AVInputFormat ff_ilbc_demuxer; +extern AVOutputFormat ff_ilbc_muxer; +extern AVInputFormat ff_image2_demuxer; +extern AVOutputFormat ff_image2_muxer; +extern AVInputFormat ff_image2pipe_demuxer; +extern AVOutputFormat ff_image2pipe_muxer; +extern AVInputFormat ff_image2_alias_pix_demuxer; +extern AVInputFormat ff_image2_brender_pix_demuxer; +extern AVInputFormat ff_ingenient_demuxer; +extern AVInputFormat ff_ipmovie_demuxer; +extern AVOutputFormat ff_ipod_muxer; +extern AVInputFormat ff_ircam_demuxer; +extern AVOutputFormat ff_ircam_muxer; +extern AVOutputFormat ff_ismv_muxer; +extern AVInputFormat ff_iss_demuxer; +extern AVInputFormat ff_iv8_demuxer; +extern AVInputFormat ff_ivf_demuxer; +extern AVOutputFormat ff_ivf_muxer; +extern AVInputFormat ff_ivr_demuxer; +extern AVInputFormat ff_jacosub_demuxer; +extern AVOutputFormat ff_jacosub_muxer; +extern AVInputFormat ff_jv_demuxer; +extern AVInputFormat ff_kux_demuxer; +extern AVOutputFormat ff_latm_muxer; +extern AVInputFormat ff_lmlm4_demuxer; +extern AVInputFormat ff_loas_demuxer; +extern AVInputFormat ff_lrc_demuxer; +extern AVOutputFormat ff_lrc_muxer; +extern AVInputFormat ff_lvf_demuxer; +extern AVInputFormat ff_lxf_demuxer; +extern AVInputFormat ff_m4v_demuxer; +extern AVOutputFormat ff_m4v_muxer; +extern AVOutputFormat ff_md5_muxer; +extern AVInputFormat ff_matroska_demuxer; +extern AVOutputFormat ff_matroska_muxer; +extern AVOutputFormat ff_matroska_audio_muxer; +extern AVInputFormat ff_mgsts_demuxer; +extern AVInputFormat ff_microdvd_demuxer; +extern AVOutputFormat ff_microdvd_muxer; +extern AVInputFormat ff_mjpeg_demuxer; +extern AVOutputFormat ff_mjpeg_muxer; +extern AVInputFormat ff_mjpeg_2000_demuxer; +extern AVInputFormat ff_mlp_demuxer; +extern AVOutputFormat ff_mlp_muxer; +extern AVInputFormat ff_mlv_demuxer; +extern AVInputFormat ff_mm_demuxer; +extern AVInputFormat ff_mmf_demuxer; +extern AVOutputFormat ff_mmf_muxer; +extern AVInputFormat ff_mov_demuxer; +extern AVOutputFormat ff_mov_muxer; +extern AVOutputFormat ff_mp2_muxer; +extern AVInputFormat ff_mp3_demuxer; +extern AVOutputFormat ff_mp3_muxer; +extern AVOutputFormat ff_mp4_muxer; +extern AVInputFormat ff_mpc_demuxer; +extern AVInputFormat ff_mpc8_demuxer; +extern AVOutputFormat ff_mpeg1system_muxer; +extern AVOutputFormat ff_mpeg1vcd_muxer; +extern AVOutputFormat ff_mpeg1video_muxer; +extern AVOutputFormat ff_mpeg2dvd_muxer; +extern AVOutputFormat ff_mpeg2svcd_muxer; +extern AVOutputFormat ff_mpeg2video_muxer; +extern AVOutputFormat ff_mpeg2vob_muxer; +extern AVInputFormat ff_mpegps_demuxer; +extern AVInputFormat ff_mpegts_demuxer; +extern AVOutputFormat ff_mpegts_muxer; +extern AVInputFormat ff_mpegtsraw_demuxer; +extern AVInputFormat ff_mpegvideo_demuxer; +extern AVInputFormat ff_mpjpeg_demuxer; +extern AVOutputFormat ff_mpjpeg_muxer; +extern AVInputFormat ff_mpl2_demuxer; +extern AVInputFormat ff_mpsub_demuxer; +extern AVInputFormat ff_msf_demuxer; +extern AVInputFormat ff_msnwc_tcp_demuxer; +extern AVInputFormat ff_mtaf_demuxer; +extern AVInputFormat ff_mtv_demuxer; +extern AVInputFormat ff_musx_demuxer; +extern AVInputFormat ff_mv_demuxer; +extern AVInputFormat ff_mvi_demuxer; +extern AVInputFormat ff_mxf_demuxer; +extern AVOutputFormat ff_mxf_muxer; +extern AVOutputFormat ff_mxf_d10_muxer; +extern AVOutputFormat ff_mxf_opatom_muxer; +extern AVInputFormat ff_mxg_demuxer; +extern AVInputFormat ff_nc_demuxer; +extern AVInputFormat ff_nistsphere_demuxer; +extern AVInputFormat ff_nsp_demuxer; +extern AVInputFormat ff_nsv_demuxer; +extern AVOutputFormat ff_null_muxer; +extern AVInputFormat ff_nut_demuxer; +extern AVOutputFormat ff_nut_muxer; +extern AVInputFormat ff_nuv_demuxer; +extern AVOutputFormat ff_oga_muxer; +extern AVInputFormat ff_ogg_demuxer; +extern AVOutputFormat ff_ogg_muxer; +extern AVOutputFormat ff_ogv_muxer; +extern AVInputFormat ff_oma_demuxer; +extern AVOutputFormat ff_oma_muxer; +extern AVOutputFormat ff_opus_muxer; +extern AVInputFormat ff_paf_demuxer; +extern AVInputFormat ff_pcm_alaw_demuxer; +extern AVOutputFormat ff_pcm_alaw_muxer; +extern AVInputFormat ff_pcm_mulaw_demuxer; +extern AVOutputFormat ff_pcm_mulaw_muxer; +extern AVInputFormat ff_pcm_vidc_demuxer; +extern AVOutputFormat ff_pcm_vidc_muxer; +extern AVInputFormat ff_pcm_f64be_demuxer; +extern AVOutputFormat ff_pcm_f64be_muxer; +extern AVInputFormat ff_pcm_f64le_demuxer; +extern AVOutputFormat ff_pcm_f64le_muxer; +extern AVInputFormat ff_pcm_f32be_demuxer; +extern AVOutputFormat ff_pcm_f32be_muxer; +extern AVInputFormat ff_pcm_f32le_demuxer; +extern AVOutputFormat ff_pcm_f32le_muxer; +extern AVInputFormat ff_pcm_s32be_demuxer; +extern AVOutputFormat ff_pcm_s32be_muxer; +extern AVInputFormat ff_pcm_s32le_demuxer; +extern AVOutputFormat ff_pcm_s32le_muxer; +extern AVInputFormat ff_pcm_s24be_demuxer; +extern AVOutputFormat ff_pcm_s24be_muxer; +extern AVInputFormat ff_pcm_s24le_demuxer; +extern AVOutputFormat ff_pcm_s24le_muxer; +extern AVInputFormat ff_pcm_s16be_demuxer; +extern AVOutputFormat ff_pcm_s16be_muxer; +extern AVInputFormat ff_pcm_s16le_demuxer; +extern AVOutputFormat ff_pcm_s16le_muxer; +extern AVInputFormat ff_pcm_s8_demuxer; +extern AVOutputFormat ff_pcm_s8_muxer; +extern AVInputFormat ff_pcm_u32be_demuxer; +extern AVOutputFormat ff_pcm_u32be_muxer; +extern AVInputFormat ff_pcm_u32le_demuxer; +extern AVOutputFormat ff_pcm_u32le_muxer; +extern AVInputFormat ff_pcm_u24be_demuxer; +extern AVOutputFormat ff_pcm_u24be_muxer; +extern AVInputFormat ff_pcm_u24le_demuxer; +extern AVOutputFormat ff_pcm_u24le_muxer; +extern AVInputFormat ff_pcm_u16be_demuxer; +extern AVOutputFormat ff_pcm_u16be_muxer; +extern AVInputFormat ff_pcm_u16le_demuxer; +extern AVOutputFormat ff_pcm_u16le_muxer; +extern AVInputFormat ff_pcm_u8_demuxer; +extern AVOutputFormat ff_pcm_u8_muxer; +extern AVInputFormat ff_pjs_demuxer; +extern AVInputFormat ff_pmp_demuxer; +extern AVOutputFormat ff_psp_muxer; +extern AVInputFormat ff_pva_demuxer; +extern AVInputFormat ff_pvf_demuxer; +extern AVInputFormat ff_qcp_demuxer; +extern AVInputFormat ff_r3d_demuxer; +extern AVInputFormat ff_rawvideo_demuxer; +extern AVOutputFormat ff_rawvideo_muxer; +extern AVInputFormat ff_realtext_demuxer; +extern AVInputFormat ff_redspark_demuxer; +extern AVInputFormat ff_rl2_demuxer; +extern AVInputFormat ff_rm_demuxer; +extern AVOutputFormat ff_rm_muxer; +extern AVInputFormat ff_roq_demuxer; +extern AVOutputFormat ff_roq_muxer; +extern AVInputFormat ff_rpl_demuxer; +extern AVInputFormat ff_rsd_demuxer; +extern AVInputFormat ff_rso_demuxer; +extern AVOutputFormat ff_rso_muxer; +extern AVInputFormat ff_rtp_demuxer; +extern AVOutputFormat ff_rtp_muxer; +extern AVOutputFormat ff_rtp_mpegts_muxer; +extern AVInputFormat ff_rtsp_demuxer; +extern AVOutputFormat ff_rtsp_muxer; +extern AVInputFormat ff_s337m_demuxer; +extern AVInputFormat ff_sami_demuxer; +extern AVInputFormat ff_sap_demuxer; +extern AVOutputFormat ff_sap_muxer; +extern AVInputFormat ff_sbc_demuxer; +extern AVOutputFormat ff_sbc_muxer; +extern AVInputFormat ff_sbg_demuxer; +extern AVInputFormat ff_scc_demuxer; +extern AVOutputFormat ff_scc_muxer; +extern AVInputFormat ff_sdp_demuxer; +extern AVInputFormat ff_sdr2_demuxer; +extern AVInputFormat ff_sds_demuxer; +extern AVInputFormat ff_sdx_demuxer; +extern AVInputFormat ff_segafilm_demuxer; +extern AVOutputFormat ff_segafilm_muxer; +extern AVOutputFormat ff_segment_muxer; +extern AVOutputFormat ff_stream_segment_muxer; +extern AVInputFormat ff_ser_demuxer; +extern AVInputFormat ff_shorten_demuxer; +extern AVInputFormat ff_siff_demuxer; +extern AVOutputFormat ff_singlejpeg_muxer; +extern AVInputFormat ff_sln_demuxer; +extern AVInputFormat ff_smacker_demuxer; +extern AVInputFormat ff_smjpeg_demuxer; +extern AVOutputFormat ff_smjpeg_muxer; +extern AVOutputFormat ff_smoothstreaming_muxer; +extern AVInputFormat ff_smush_demuxer; +extern AVInputFormat ff_sol_demuxer; +extern AVInputFormat ff_sox_demuxer; +extern AVOutputFormat ff_sox_muxer; +extern AVOutputFormat ff_spx_muxer; +extern AVInputFormat ff_spdif_demuxer; +extern AVOutputFormat ff_spdif_muxer; +extern AVInputFormat ff_srt_demuxer; +extern AVOutputFormat ff_srt_muxer; +extern AVInputFormat ff_str_demuxer; +extern AVInputFormat ff_stl_demuxer; +extern AVInputFormat ff_subviewer1_demuxer; +extern AVInputFormat ff_subviewer_demuxer; +extern AVInputFormat ff_sup_demuxer; +extern AVOutputFormat ff_sup_muxer; +extern AVInputFormat ff_svag_demuxer; +extern AVInputFormat ff_swf_demuxer; +extern AVOutputFormat ff_swf_muxer; +extern AVInputFormat ff_tak_demuxer; +extern AVOutputFormat ff_tee_muxer; +extern AVInputFormat ff_tedcaptions_demuxer; +extern AVOutputFormat ff_tg2_muxer; +extern AVOutputFormat ff_tgp_muxer; +extern AVInputFormat ff_thp_demuxer; +extern AVInputFormat ff_threedostr_demuxer; +extern AVInputFormat ff_tiertexseq_demuxer; +extern AVOutputFormat ff_mkvtimestamp_v2_muxer; +extern AVInputFormat ff_tmv_demuxer; +extern AVInputFormat ff_truehd_demuxer; +extern AVOutputFormat ff_truehd_muxer; +extern AVInputFormat ff_tta_demuxer; +extern AVOutputFormat ff_tta_muxer; +extern AVInputFormat ff_txd_demuxer; +extern AVInputFormat ff_tty_demuxer; +extern AVInputFormat ff_ty_demuxer; +extern AVOutputFormat ff_uncodedframecrc_muxer; +extern AVInputFormat ff_v210_demuxer; +extern AVInputFormat ff_v210x_demuxer; +extern AVInputFormat ff_vag_demuxer; +extern AVInputFormat ff_vc1_demuxer; +extern AVOutputFormat ff_vc1_muxer; +extern AVInputFormat ff_vc1t_demuxer; +extern AVOutputFormat ff_vc1t_muxer; +extern AVInputFormat ff_vividas_demuxer; +extern AVInputFormat ff_vivo_demuxer; +extern AVInputFormat ff_vmd_demuxer; +extern AVInputFormat ff_vobsub_demuxer; +extern AVInputFormat ff_voc_demuxer; +extern AVOutputFormat ff_voc_muxer; +extern AVInputFormat ff_vpk_demuxer; +extern AVInputFormat ff_vplayer_demuxer; +extern AVInputFormat ff_vqf_demuxer; +extern AVInputFormat ff_w64_demuxer; +extern AVOutputFormat ff_w64_muxer; +extern AVInputFormat ff_wav_demuxer; +extern AVOutputFormat ff_wav_muxer; +extern AVInputFormat ff_wc3_demuxer; +extern AVOutputFormat ff_webm_muxer; +extern AVInputFormat ff_webm_dash_manifest_demuxer; +extern AVOutputFormat ff_webm_dash_manifest_muxer; +extern AVOutputFormat ff_webm_chunk_muxer; +extern AVOutputFormat ff_webp_muxer; +extern AVInputFormat ff_webvtt_demuxer; +extern AVOutputFormat ff_webvtt_muxer; +extern AVInputFormat ff_wsaud_demuxer; +extern AVInputFormat ff_wsd_demuxer; +extern AVInputFormat ff_wsvqa_demuxer; +extern AVInputFormat ff_wtv_demuxer; +extern AVOutputFormat ff_wtv_muxer; +extern AVInputFormat ff_wve_demuxer; +extern AVInputFormat ff_wv_demuxer; +extern AVOutputFormat ff_wv_muxer; +extern AVInputFormat ff_xa_demuxer; +extern AVInputFormat ff_xbin_demuxer; +extern AVInputFormat ff_xmv_demuxer; +extern AVInputFormat ff_xvag_demuxer; +extern AVInputFormat ff_xwma_demuxer; +extern AVInputFormat ff_yop_demuxer; +extern AVInputFormat ff_yuv4mpegpipe_demuxer; +extern AVOutputFormat ff_yuv4mpegpipe_muxer; +/* image demuxers */ +extern AVInputFormat ff_image_bmp_pipe_demuxer; +extern AVInputFormat ff_image_dds_pipe_demuxer; +extern AVInputFormat ff_image_dpx_pipe_demuxer; +extern AVInputFormat ff_image_exr_pipe_demuxer; +extern AVInputFormat ff_image_gif_pipe_demuxer; +extern AVInputFormat ff_image_j2k_pipe_demuxer; +extern AVInputFormat ff_image_jpeg_pipe_demuxer; +extern AVInputFormat ff_image_jpegls_pipe_demuxer; +extern AVInputFormat ff_image_pam_pipe_demuxer; +extern AVInputFormat ff_image_pbm_pipe_demuxer; +extern AVInputFormat ff_image_pcx_pipe_demuxer; +extern AVInputFormat ff_image_pgmyuv_pipe_demuxer; +extern AVInputFormat ff_image_pgm_pipe_demuxer; +extern AVInputFormat ff_image_pictor_pipe_demuxer; +extern AVInputFormat ff_image_png_pipe_demuxer; +extern AVInputFormat ff_image_ppm_pipe_demuxer; +extern AVInputFormat ff_image_psd_pipe_demuxer; +extern AVInputFormat ff_image_qdraw_pipe_demuxer; +extern AVInputFormat ff_image_sgi_pipe_demuxer; +extern AVInputFormat ff_image_svg_pipe_demuxer; +extern AVInputFormat ff_image_sunrast_pipe_demuxer; +extern AVInputFormat ff_image_tiff_pipe_demuxer; +extern AVInputFormat ff_image_webp_pipe_demuxer; +extern AVInputFormat ff_image_xpm_pipe_demuxer; +extern AVInputFormat ff_image_xwd_pipe_demuxer; + +/* external libraries */ +extern AVOutputFormat ff_chromaprint_muxer; +extern AVInputFormat ff_libgme_demuxer; +extern AVInputFormat ff_libmodplug_demuxer; +extern AVInputFormat ff_libopenmpt_demuxer; +extern AVInputFormat ff_vapoursynth_demuxer; + +#include "libavformat/muxer_list.c" +#include "libavformat/demuxer_list.c" + +static const AVInputFormat * const *indev_list = NULL; +static const AVOutputFormat * const *outdev_list = NULL; + +const AVOutputFormat *av_muxer_iterate(void **opaque) +{ + static const uintptr_t size = sizeof(muxer_list)/sizeof(muxer_list[0]) - 1; + uintptr_t i = (uintptr_t)*opaque; + const AVOutputFormat *f = NULL; + + if (i < size) { + f = muxer_list[i]; + } else if (indev_list) { + f = outdev_list[i - size]; + } + + if (f) + *opaque = (void*)(i + 1); + return f; +} + +const AVInputFormat *av_demuxer_iterate(void **opaque) +{ + static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1; + uintptr_t i = (uintptr_t)*opaque; + const AVInputFormat *f = NULL; + + if (i < size) { + f = demuxer_list[i]; + } else if (outdev_list) { + f = indev_list[i - size]; + } + + if (f) + *opaque = (void*)(i + 1); + return f; +} + +static AVMutex avpriv_register_devices_mutex = AV_MUTEX_INITIALIZER; + +#if FF_API_NEXT +FF_DISABLE_DEPRECATION_WARNINGS +static AVOnce av_format_next_init = AV_ONCE_INIT; + +static void av_format_init_next(void) +{ + AVOutputFormat *prevout = NULL, *out; + AVInputFormat *previn = NULL, *in; + + ff_mutex_lock(&avpriv_register_devices_mutex); + + for (int i = 0; (out = (AVOutputFormat*)muxer_list[i]); i++) { + if (prevout) + prevout->next = out; + prevout = out; + } + + if (outdev_list) { + for (int i = 0; (out = (AVOutputFormat*)outdev_list[i]); i++) { + if (prevout) + prevout->next = out; + prevout = out; + } + } + + for (int i = 0; (in = (AVInputFormat*)demuxer_list[i]); i++) { + if (previn) + previn->next = in; + previn = in; + } + + if (indev_list) { + for (int i = 0; (in = (AVInputFormat*)indev_list[i]); i++) { + if (previn) + previn->next = in; + previn = in; + } + } + + ff_mutex_unlock(&avpriv_register_devices_mutex); +} + +AVInputFormat *av_iformat_next(const AVInputFormat *f) +{ + ff_thread_once(&av_format_next_init, av_format_init_next); + + if (f) +#if FF_API_AVIOFORMAT + return f->next; +#else + return (AVInputFormat *) f->next; +#endif + else { + void *opaque = NULL; + return (AVInputFormat *)av_demuxer_iterate(&opaque); + } +} + +AVOutputFormat *av_oformat_next(const AVOutputFormat *f) +{ + ff_thread_once(&av_format_next_init, av_format_init_next); + + if (f) +#if FF_API_AVIOFORMAT + return f->next; +#else + return (AVOutputFormat *) f->next; +#endif + else { + void *opaque = NULL; + return (AVOutputFormat *)av_muxer_iterate(&opaque); + } +} + +void av_register_all(void) +{ + ff_thread_once(&av_format_next_init, av_format_init_next); +} + +void av_register_input_format(AVInputFormat *format) +{ + ff_thread_once(&av_format_next_init, av_format_init_next); +} + +void av_register_output_format(AVOutputFormat *format) +{ + ff_thread_once(&av_format_next_init, av_format_init_next); +} +FF_ENABLE_DEPRECATION_WARNINGS +#endif + +void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[]) +{ + ff_mutex_lock(&avpriv_register_devices_mutex); + outdev_list = o; + indev_list = i; + ff_mutex_unlock(&avpriv_register_devices_mutex); +#if FF_API_NEXT + av_format_init_next(); +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/demuxer_list.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/demuxer_list.c new file mode 100644 index 0000000000..1c8fb117fa --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/demuxer_list.c @@ -0,0 +1,2 @@ +static const AVInputFormat * const demuxer_list[] = { + NULL }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/muxer_list.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/muxer_list.c new file mode 100644 index 0000000000..f36d9499c6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/muxer_list.c @@ -0,0 +1,2 @@ +static const AVOutputFormat * const muxer_list[] = { + NULL }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/protocol_list.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/protocol_list.c new file mode 100644 index 0000000000..247e1e4c3a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/protocol_list.c @@ -0,0 +1,2 @@ +static const URLProtocol * const url_protocols[] = { + NULL }; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/protocols.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/protocols.c new file mode 100644 index 0000000000..ad95659795 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavformat/protocols.c @@ -0,0 +1,131 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/avstring.h" +#include "libavutil/mem.h" + +#include "url.h" + +extern const URLProtocol ff_async_protocol; +extern const URLProtocol ff_bluray_protocol; +extern const URLProtocol ff_cache_protocol; +extern const URLProtocol ff_concat_protocol; +extern const URLProtocol ff_crypto_protocol; +extern const URLProtocol ff_data_protocol; +extern const URLProtocol ff_ffrtmpcrypt_protocol; +extern const URLProtocol ff_ffrtmphttp_protocol; +extern const URLProtocol ff_file_protocol; +extern const URLProtocol ff_ftp_protocol; +extern const URLProtocol ff_gopher_protocol; +extern const URLProtocol ff_hls_protocol; +extern const URLProtocol ff_http_protocol; +extern const URLProtocol ff_httpproxy_protocol; +extern const URLProtocol ff_https_protocol; +extern const URLProtocol ff_icecast_protocol; +extern const URLProtocol ff_mmsh_protocol; +extern const URLProtocol ff_mmst_protocol; +extern const URLProtocol ff_md5_protocol; +extern const URLProtocol ff_pipe_protocol; +extern const URLProtocol ff_prompeg_protocol; +extern const URLProtocol ff_rtmp_protocol; +extern const URLProtocol ff_rtmpe_protocol; +extern const URLProtocol ff_rtmps_protocol; +extern const URLProtocol ff_rtmpt_protocol; +extern const URLProtocol ff_rtmpte_protocol; +extern const URLProtocol ff_rtmpts_protocol; +extern const URLProtocol ff_rtp_protocol; +extern const URLProtocol ff_sctp_protocol; +extern const URLProtocol ff_srtp_protocol; +extern const URLProtocol ff_subfile_protocol; +extern const URLProtocol ff_tee_protocol; +extern const URLProtocol ff_tcp_protocol; +extern const URLProtocol ff_tls_protocol; +extern const URLProtocol ff_udp_protocol; +extern const URLProtocol ff_udplite_protocol; +extern const URLProtocol ff_unix_protocol; +extern const URLProtocol ff_librtmp_protocol; +extern const URLProtocol ff_librtmpe_protocol; +extern const URLProtocol ff_librtmps_protocol; +extern const URLProtocol ff_librtmpt_protocol; +extern const URLProtocol ff_librtmpte_protocol; +extern const URLProtocol ff_libsrt_protocol; +extern const URLProtocol ff_libssh_protocol; +extern const URLProtocol ff_libsmbclient_protocol; + +#include "libavformat/protocol_list.c" + +const AVClass *ff_urlcontext_child_class_next(const AVClass *prev) +{ + int i; + + /* find the protocol that corresponds to prev */ + for (i = 0; prev && url_protocols[i]; i++) { + if (url_protocols[i]->priv_data_class == prev) { + i++; + break; + } + } + + /* find next protocol with priv options */ + for (; url_protocols[i]; i++) + if (url_protocols[i]->priv_data_class) + return url_protocols[i]->priv_data_class; + return NULL; +} + + +const char *avio_enum_protocols(void **opaque, int output) +{ + const URLProtocol **p = *opaque; + + p = p ? p + 1 : url_protocols; + *opaque = p; + if (!*p) { + *opaque = NULL; + return NULL; + } + if ((output && (*p)->url_write) || (!output && (*p)->url_read)) + return (*p)->name; + return avio_enum_protocols(opaque, output); +} + +const URLProtocol **ffurl_get_protocols(const char *whitelist, + const char *blacklist) +{ + const URLProtocol **ret; + int i, ret_idx = 0; + + ret = av_mallocz_array(FF_ARRAY_ELEMS(url_protocols), sizeof(*ret)); + if (!ret) + return NULL; + + for (i = 0; url_protocols[i]; i++) { + const URLProtocol *up = url_protocols[i]; + + if (whitelist && *whitelist && !av_match_name(up->name, whitelist)) + continue; + if (blacklist && *blacklist && av_match_name(up->name, blacklist)) + continue; + + ret[ret_idx++] = up; + } + + return ret; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/Makefile new file mode 100644 index 0000000000..8a7a44e4b5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/Makefile @@ -0,0 +1,250 @@ +NAME = avutil +DESC = FFmpeg utility library + +HEADERS = adler32.h \ + aes.h \ + aes_ctr.h \ + attributes.h \ + audio_fifo.h \ + avassert.h \ + avstring.h \ + avutil.h \ + base64.h \ + blowfish.h \ + bprint.h \ + bswap.h \ + buffer.h \ + cast5.h \ + camellia.h \ + channel_layout.h \ + common.h \ + cpu.h \ + crc.h \ + des.h \ + dict.h \ + display.h \ + downmix_info.h \ + encryption_info.h \ + error.h \ + eval.h \ + fifo.h \ + file.h \ + frame.h \ + hash.h \ + hdr_dynamic_metadata.h \ + hmac.h \ + hwcontext.h \ + hwcontext_cuda.h \ + hwcontext_d3d11va.h \ + hwcontext_drm.h \ + hwcontext_dxva2.h \ + hwcontext_qsv.h \ + hwcontext_mediacodec.h \ + hwcontext_vaapi.h \ + hwcontext_videotoolbox.h \ + hwcontext_vdpau.h \ + imgutils.h \ + intfloat.h \ + intreadwrite.h \ + lfg.h \ + log.h \ + macros.h \ + mathematics.h \ + mastering_display_metadata.h \ + md5.h \ + mem.h \ + motion_vector.h \ + murmur3.h \ + opt.h \ + parseutils.h \ + pixdesc.h \ + pixelutils.h \ + pixfmt.h \ + random_seed.h \ + rc4.h \ + rational.h \ + replaygain.h \ + ripemd.h \ + samplefmt.h \ + sha.h \ + sha512.h \ + spherical.h \ + stereo3d.h \ + threadmessage.h \ + time.h \ + timecode.h \ + timestamp.h \ + tree.h \ + twofish.h \ + version.h \ + xtea.h \ + tea.h \ + tx.h \ + +HEADERS-$(CONFIG_LZO) += lzo.h + +ARCH_HEADERS = bswap.h \ + intmath.h \ + intreadwrite.h \ + timer.h \ + +BUILT_HEADERS = avconfig.h \ + ffversion.h + +OBJS = adler32.o \ + aes.o \ + aes_ctr.o \ + audio_fifo.o \ + avstring.o \ + avsscanf.o \ + base64.o \ + blowfish.o \ + bprint.o \ + buffer.o \ + cast5.o \ + camellia.o \ + channel_layout.o \ + color_utils.o \ + cpu.o \ + crc.o \ + des.o \ + dict.o \ + display.o \ + downmix_info.o \ + encryption_info.o \ + error.o \ + eval.o \ + fifo.o \ + file.o \ + file_open.o \ + float_dsp.o \ + fixed_dsp.o \ + frame.o \ + hash.o \ + hdr_dynamic_metadata.o \ + hmac.o \ + hwcontext.o \ + imgutils.o \ + integer.o \ + intmath.o \ + lfg.o \ + lls.o \ + log.o \ + log2_tab.o \ + mathematics.o \ + mastering_display_metadata.o \ + md5.o \ + mem.o \ + murmur3.o \ + opt.o \ + parseutils.o \ + pixdesc.o \ + pixelutils.o \ + random_seed.o \ + rational.o \ + reverse.o \ + rc4.o \ + ripemd.o \ + samplefmt.o \ + sha.o \ + sha512.o \ + slicethread.o \ + spherical.o \ + stereo3d.o \ + threadmessage.o \ + time.o \ + timecode.o \ + tree.o \ + twofish.o \ + utils.o \ + xga_font_data.o \ + xtea.o \ + tea.o \ + tx.o \ + +OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o +OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o +OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o +OBJS-$(CONFIG_LIBDRM) += hwcontext_drm.o +OBJS-$(CONFIG_LZO) += lzo.o +OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o +OBJS-$(CONFIG_OPENCL) += hwcontext_opencl.o +OBJS-$(CONFIG_QSV) += hwcontext_qsv.o +OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o +OBJS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.o +OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o + +OBJS += $(COMPAT_OBJS:%=../compat/%) + +# Windows resource file +SLIBOBJS-$(HAVE_GNU_WINDRES) += avutilres.o + +SKIPHEADERS-$(HAVE_CUDA_H) += hwcontext_cuda.h +SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h \ + cuda_check.h +SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h +SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h +SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h +SKIPHEADERS-$(CONFIG_OPENCL) += hwcontext_opencl.h +SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h +SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.h +SKIPHEADERS-$(CONFIG_VDPAU) += hwcontext_vdpau.h + +TESTPROGS = adler32 \ + aes \ + aes_ctr \ + audio_fifo \ + avstring \ + base64 \ + blowfish \ + bprint \ + cast5 \ + camellia \ + color_utils \ + cpu \ + crc \ + des \ + dict \ + display \ + encryption_info \ + error \ + eval \ + file \ + fifo \ + hash \ + hmac \ + hwdevice \ + integer \ + imgutils \ + lfg \ + lls \ + log \ + md5 \ + murmur3 \ + opt \ + pca \ + parseutils \ + pixdesc \ + pixelutils \ + pixfmt_best \ + random_seed \ + rational \ + ripemd \ + sha \ + sha512 \ + softfloat \ + tree \ + twofish \ + utf8 \ + xtea \ + tea \ + +TESTPROGS-$(HAVE_THREADS) += cpu_init +TESTPROGS-$(HAVE_LZO1X_999_COMPRESS) += lzo + +TOOLS = crypto_bench ffhash ffeval ffescape + +tools/crypto_bench$(EXESUF): ELIBS += $(if $(VERSUS),$(subst +, -l,+$(VERSUS)),) +tools/crypto_bench$(EXESUF): CFLAGS += -DUSE_EXT_LIBS=0$(if $(VERSUS),$(subst +,+USE_,+$(VERSUS)),) + +$(SUBDIR)tests/lzo$(EXESUF): ELIBS = -llzo2 diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/bswap.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/bswap.h new file mode 100644 index 0000000000..1e735c52cf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/bswap.h @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AARCH64_BSWAP_H +#define AVUTIL_AARCH64_BSWAP_H + +#include +#include "config.h" +#include "libavutil/attributes.h" + +#if HAVE_INLINE_ASM + +#define av_bswap16 av_bswap16 +static av_always_inline av_const unsigned av_bswap16(unsigned x) +{ + __asm__("rev16 %w0, %w0" : "+r"(x)); + return x; +} + +#define av_bswap32 av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + __asm__("rev %w0, %w0" : "+r"(x)); + return x; +} + +#define av_bswap64 av_bswap64 +static av_always_inline av_const uint64_t av_bswap64(uint64_t x) +{ + __asm__("rev %0, %0" : "+r"(x)); + return x; +} + +#endif /* HAVE_INLINE_ASM */ +#endif /* AVUTIL_AARCH64_BSWAP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/cpu.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/cpu.c new file mode 100644 index 0000000000..cc641da576 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/cpu.c @@ -0,0 +1,38 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" +#include "config.h" + +int ff_get_cpu_flags_aarch64(void) +{ + return AV_CPU_FLAG_ARMV8 * HAVE_ARMV8 | + AV_CPU_FLAG_NEON * HAVE_NEON | + AV_CPU_FLAG_VFP * HAVE_VFP; +} + +size_t ff_get_cpu_max_align_aarch64(void) +{ + int flags = av_get_cpu_flags(); + + if (flags & AV_CPU_FLAG_NEON) + return 16; + + return 8; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/cpu.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/cpu.h new file mode 100644 index 0000000000..2ee3f9323a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/cpu.h @@ -0,0 +1,29 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AARCH64_CPU_H +#define AVUTIL_AARCH64_CPU_H + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" + +#define have_armv8(flags) CPUEXT(flags, ARMV8) +#define have_neon(flags) CPUEXT(flags, NEON) +#define have_vfp(flags) CPUEXT(flags, VFP) + +#endif /* AVUTIL_AARCH64_CPU_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/float_dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/float_dsp_init.c new file mode 100644 index 0000000000..4325071821 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/float_dsp_init.c @@ -0,0 +1,69 @@ +/* + * ARM NEON optimised Float DSP functions + * Copyright (c) 2008 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/float_dsp.h" +#include "cpu.h" + +void ff_vector_fmul_neon(float *dst, const float *src0, const float *src1, + int len); + +void ff_vector_fmac_scalar_neon(float *dst, const float *src, float mul, + int len); + +void ff_vector_fmul_scalar_neon(float *dst, const float *src, float mul, + int len); + +void ff_vector_dmul_scalar_neon(double *dst, const double *src, double mul, + int len); + +void ff_vector_fmul_window_neon(float *dst, const float *src0, + const float *src1, const float *win, int len); + +void ff_vector_fmul_add_neon(float *dst, const float *src0, const float *src1, + const float *src2, int len); + +void ff_vector_fmul_reverse_neon(float *dst, const float *src0, + const float *src1, int len); + +void ff_butterflies_float_neon(float *v1, float *v2, int len); + +float ff_scalarproduct_float_neon(const float *v1, const float *v2, int len); + +av_cold void ff_float_dsp_init_aarch64(AVFloatDSPContext *fdsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + fdsp->butterflies_float = ff_butterflies_float_neon; + fdsp->scalarproduct_float = ff_scalarproduct_float_neon; + fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_neon; + fdsp->vector_fmul = ff_vector_fmul_neon; + fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_neon; + fdsp->vector_fmul_add = ff_vector_fmul_add_neon; + fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_neon; + fdsp->vector_fmul_scalar = ff_vector_fmul_scalar_neon; + fdsp->vector_fmul_window = ff_vector_fmul_window_neon; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/neontest.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/neontest.h new file mode 100644 index 0000000000..2d0fc19994 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/neontest.h @@ -0,0 +1,70 @@ +/* + * check NEON registers for clobbering + * Copyright (c) 2008 Ramiro Polla + * Copyright (c) 2013 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AARCH64_NEONTEST_H +#define AVUTIL_AARCH64_NEONTEST_H + +#include +#include +#include +#include +#include + +#include "libavutil/bswap.h" + +#define storeneonregs(mem) \ + __asm__ volatile( \ + "stp d8, d9, [%0]\n\t" \ + "stp d10, d11, [%0, #16]\n\t" \ + "stp d12, d13, [%0, #32]\n\t" \ + "stp d14, d15, [%0, #48]\n\t" \ + :: "r"(mem) : "memory") + +#define testneonclobbers(func, ctx, ...) \ + uint64_t neon[2][8]; \ + int ret; \ + storeneonregs(neon[0]); \ + ret = __real_ ## func(ctx, __VA_ARGS__); \ + storeneonregs(neon[1]); \ + if (memcmp(neon[0], neon[1], sizeof(neon[0]))) { \ + int i; \ + av_log(ctx, AV_LOG_ERROR, \ + "NEON REGS CLOBBERED IN %s!\n", #func); \ + for (i = 0; i < 8; i ++) \ + if (neon[0][i] != neon[1][i]) { \ + av_log(ctx, AV_LOG_ERROR, \ + "d%-2d = %016"PRIx64"\n", \ + 8 + i, av_bswap64(neon[0][i])); \ + av_log(ctx, AV_LOG_ERROR, \ + " -> %016"PRIx64"\n", \ + av_bswap64(neon[1][i])); \ + } \ + abort(); \ + } \ + return ret + +#define wrap(func) \ +int __real_ ## func; \ +int __wrap_ ## func; \ +int __wrap_ ## func + +#endif /* AVUTIL_AARCH64_NEONTEST_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/timer.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/timer.h new file mode 100644 index 0000000000..b570039416 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/timer.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015 Janne Grunau + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AARCH64_TIMER_H +#define AVUTIL_AARCH64_TIMER_H + +#include +#include "config.h" + +#if HAVE_INLINE_ASM + +#define AV_READ_TIME read_time + +static inline uint64_t read_time(void) +{ + uint64_t cycle_counter; + __asm__ volatile( + "isb \t\n" + "mrs %0, pmccntr_el0 " + : "=r"(cycle_counter) :: "memory" ); + + return cycle_counter; +} + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVUTIL_AARCH64_TIMER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/adler32.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/adler32.c new file mode 100644 index 0000000000..c87d5e261c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/adler32.c @@ -0,0 +1,97 @@ +/* + * Compute the Adler-32 checksum of a data stream. + * This is a modified version based on adler32.c from the zlib library. + * + * Copyright (C) 1995 Mark Adler + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/** + * @file + * Computes the Adler-32 checksum of a data stream + * + * This is a modified version based on adler32.c from the zlib library. + * @author Mark Adler + * @ingroup lavu_adler32 + */ + +#include "config.h" +#include "adler32.h" +#include "common.h" +#include "intreadwrite.h" + +#define BASE 65521L /* largest prime smaller than 65536 */ + +#define DO1(buf) { s1 += *buf++; s2 += s1; } +#define DO4(buf) DO1(buf); DO1(buf); DO1(buf); DO1(buf); +#define DO16(buf) DO4(buf); DO4(buf); DO4(buf); DO4(buf); + +unsigned long av_adler32_update(unsigned long adler, const uint8_t * buf, + unsigned int len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = adler >> 16; + + while (len > 0) { +#if HAVE_FAST_64BIT && HAVE_FAST_UNALIGNED && !CONFIG_SMALL + unsigned len2 = FFMIN((len-1) & ~7, 23*8); + if (len2) { + uint64_t a1= 0; + uint64_t a2= 0; + uint64_t b1= 0; + uint64_t b2= 0; + len -= len2; + s2 += s1*len2; + while (len2 >= 8) { + uint64_t v = AV_RN64(buf); + a2 += a1; + b2 += b1; + a1 += v &0x00FF00FF00FF00FF; + b1 += (v>>8)&0x00FF00FF00FF00FF; + len2 -= 8; + buf+=8; + } + + //We combine the 8 interleaved adler32 checksums without overflows + //Decreasing the number of iterations would allow below code to be + //simplified but would likely be slower due to the fewer iterations + //of the inner loop + s1 += ((a1+b1)*0x1000100010001)>>48; + s2 += ((((a2&0xFFFF0000FFFF)+(b2&0xFFFF0000FFFF)+((a2>>16)&0xFFFF0000FFFF)+((b2>>16)&0xFFFF0000FFFF))*0x800000008)>>32) +#if HAVE_BIGENDIAN + + 2*((b1*0x1000200030004)>>48) + + ((a1*0x1000100010001)>>48) + + 2*((a1*0x0000100020003)>>48); +#else + + 2*((a1*0x4000300020001)>>48) + + ((b1*0x1000100010001)>>48) + + 2*((b1*0x3000200010000)>>48); +#endif + } +#else + while (len > 4 && s2 < (1U << 31)) { + DO4(buf); + len -= 4; + } +#endif + DO1(buf); len--; + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/adler32.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/adler32.h new file mode 100644 index 0000000000..a1f035b734 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/adler32.h @@ -0,0 +1,60 @@ +/* + * copyright (c) 2006 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_adler32 + * Public header for Adler-32 hash function implementation. + */ + +#ifndef AVUTIL_ADLER32_H +#define AVUTIL_ADLER32_H + +#include +#include "attributes.h" + +/** + * @defgroup lavu_adler32 Adler-32 + * @ingroup lavu_hash + * Adler-32 hash function implementation. + * + * @{ + */ + +/** + * Calculate the Adler32 checksum of a buffer. + * + * Passing the return value to a subsequent av_adler32_update() call + * allows the checksum of multiple buffers to be calculated as though + * they were concatenated. + * + * @param adler initial checksum value + * @param buf pointer to input buffer + * @param len size of input buffer + * @return updated checksum + */ +unsigned long av_adler32_update(unsigned long adler, const uint8_t *buf, + unsigned int len) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_ADLER32_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes.c new file mode 100644 index 0000000000..397ea77389 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes.c @@ -0,0 +1,268 @@ +/* + * copyright (c) 2007 Michael Niedermayer + * + * some optimization ideas from aes128.c by Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "common.h" +#include "aes.h" +#include "aes_internal.h" +#include "intreadwrite.h" +#include "timer.h" + +const int av_aes_size= sizeof(AVAES); + +struct AVAES *av_aes_alloc(void) +{ + return av_mallocz(sizeof(struct AVAES)); +} + +static const uint8_t rcon[10] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 +}; + +static uint8_t sbox[256]; +static uint8_t inv_sbox[256]; +#if CONFIG_SMALL +static uint32_t enc_multbl[1][256]; +static uint32_t dec_multbl[1][256]; +#else +static uint32_t enc_multbl[4][256]; +static uint32_t dec_multbl[4][256]; +#endif + +#if HAVE_BIGENDIAN +# define ROT(x, s) (((x) >> (s)) | ((x) << (32-(s)))) +#else +# define ROT(x, s) (((x) << (s)) | ((x) >> (32-(s)))) +#endif + +static inline void addkey(av_aes_block *dst, const av_aes_block *src, + const av_aes_block *round_key) +{ + dst->u64[0] = src->u64[0] ^ round_key->u64[0]; + dst->u64[1] = src->u64[1] ^ round_key->u64[1]; +} + +static inline void addkey_s(av_aes_block *dst, const uint8_t *src, + const av_aes_block *round_key) +{ + dst->u64[0] = AV_RN64(src) ^ round_key->u64[0]; + dst->u64[1] = AV_RN64(src + 8) ^ round_key->u64[1]; +} + +static inline void addkey_d(uint8_t *dst, const av_aes_block *src, + const av_aes_block *round_key) +{ + AV_WN64(dst, src->u64[0] ^ round_key->u64[0]); + AV_WN64(dst + 8, src->u64[1] ^ round_key->u64[1]); +} + +static void subshift(av_aes_block s0[2], int s, const uint8_t *box) +{ + av_aes_block *s1 = (av_aes_block *) (s0[0].u8 - s); + av_aes_block *s3 = (av_aes_block *) (s0[0].u8 + s); + + s0[0].u8[ 0] = box[s0[1].u8[ 0]]; + s0[0].u8[ 4] = box[s0[1].u8[ 4]]; + s0[0].u8[ 8] = box[s0[1].u8[ 8]]; + s0[0].u8[12] = box[s0[1].u8[12]]; + s1[0].u8[ 3] = box[s1[1].u8[ 7]]; + s1[0].u8[ 7] = box[s1[1].u8[11]]; + s1[0].u8[11] = box[s1[1].u8[15]]; + s1[0].u8[15] = box[s1[1].u8[ 3]]; + s0[0].u8[ 2] = box[s0[1].u8[10]]; + s0[0].u8[10] = box[s0[1].u8[ 2]]; + s0[0].u8[ 6] = box[s0[1].u8[14]]; + s0[0].u8[14] = box[s0[1].u8[ 6]]; + s3[0].u8[ 1] = box[s3[1].u8[13]]; + s3[0].u8[13] = box[s3[1].u8[ 9]]; + s3[0].u8[ 9] = box[s3[1].u8[ 5]]; + s3[0].u8[ 5] = box[s3[1].u8[ 1]]; +} + +static inline int mix_core(uint32_t multbl[][256], int a, int b, int c, int d) +{ +#if CONFIG_SMALL + return multbl[0][a] ^ ROT(multbl[0][b], 8) ^ ROT(multbl[0][c], 16) ^ ROT(multbl[0][d], 24); +#else + return multbl[0][a] ^ multbl[1][b] ^ multbl[2][c] ^ multbl[3][d]; +#endif +} + +static inline void mix(av_aes_block state[2], uint32_t multbl[][256], int s1, int s3) +{ + uint8_t (*src)[4] = state[1].u8x4; + state[0].u32[0] = mix_core(multbl, src[0][0], src[s1 ][1], src[2][2], src[s3 ][3]); + state[0].u32[1] = mix_core(multbl, src[1][0], src[s3 - 1][1], src[3][2], src[s1 - 1][3]); + state[0].u32[2] = mix_core(multbl, src[2][0], src[s3 ][1], src[0][2], src[s1 ][3]); + state[0].u32[3] = mix_core(multbl, src[3][0], src[s1 - 1][1], src[1][2], src[s3 - 1][3]); +} + +static inline void aes_crypt(AVAES *a, int s, const uint8_t *sbox, + uint32_t multbl[][256]) +{ + int r; + + for (r = a->rounds - 1; r > 0; r--) { + mix(a->state, multbl, 3 - s, 1 + s); + addkey(&a->state[1], &a->state[0], &a->round_key[r]); + } + + subshift(&a->state[0], s, sbox); +} + +static void aes_encrypt(AVAES *a, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int rounds) +{ + while (count--) { + addkey_s(&a->state[1], src, &a->round_key[rounds]); + if (iv) + addkey_s(&a->state[1], iv, &a->state[1]); + aes_crypt(a, 2, sbox, enc_multbl); + addkey_d(dst, &a->state[0], &a->round_key[0]); + if (iv) + memcpy(iv, dst, 16); + src += 16; + dst += 16; + } +} + +static void aes_decrypt(AVAES *a, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int rounds) +{ + while (count--) { + addkey_s(&a->state[1], src, &a->round_key[rounds]); + aes_crypt(a, 0, inv_sbox, dec_multbl); + if (iv) { + addkey_s(&a->state[0], iv, &a->state[0]); + memcpy(iv, src, 16); + } + addkey_d(dst, &a->state[0], &a->round_key[0]); + src += 16; + dst += 16; + } +} + +void av_aes_crypt(AVAES *a, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt) +{ + a->crypt(a, dst, src, count, iv, a->rounds); +} + +static void init_multbl2(uint32_t tbl[][256], const int c[4], + const uint8_t *log8, const uint8_t *alog8, + const uint8_t *sbox) +{ + int i; + + for (i = 0; i < 256; i++) { + int x = sbox[i]; + if (x) { + int k, l, m, n; + x = log8[x]; + k = alog8[x + log8[c[0]]]; + l = alog8[x + log8[c[1]]]; + m = alog8[x + log8[c[2]]]; + n = alog8[x + log8[c[3]]]; + tbl[0][i] = AV_NE(MKBETAG(k, l, m, n), MKTAG(k, l, m, n)); +#if !CONFIG_SMALL + tbl[1][i] = ROT(tbl[0][i], 8); + tbl[2][i] = ROT(tbl[0][i], 16); + tbl[3][i] = ROT(tbl[0][i], 24); +#endif + } + } +} + +// this is based on the reference AES code by Paulo Barreto and Vincent Rijmen +int av_aes_init(AVAES *a, const uint8_t *key, int key_bits, int decrypt) +{ + int i, j, t, rconpointer = 0; + uint8_t tk[8][4]; + int KC = key_bits >> 5; + int rounds = KC + 6; + uint8_t log8[256]; + uint8_t alog8[512]; + + a->crypt = decrypt ? aes_decrypt : aes_encrypt; + + if (!enc_multbl[FF_ARRAY_ELEMS(enc_multbl) - 1][FF_ARRAY_ELEMS(enc_multbl[0]) - 1]) { + j = 1; + for (i = 0; i < 255; i++) { + alog8[i] = alog8[i + 255] = j; + log8[j] = i; + j ^= j + j; + if (j > 255) + j ^= 0x11B; + } + for (i = 0; i < 256; i++) { + j = i ? alog8[255 - log8[i]] : 0; + j ^= (j << 1) ^ (j << 2) ^ (j << 3) ^ (j << 4); + j = (j ^ (j >> 8) ^ 99) & 255; + inv_sbox[j] = i; + sbox[i] = j; + } + init_multbl2(dec_multbl, (const int[4]) { 0xe, 0x9, 0xd, 0xb }, + log8, alog8, inv_sbox); + init_multbl2(enc_multbl, (const int[4]) { 0x2, 0x1, 0x1, 0x3 }, + log8, alog8, sbox); + } + + if (key_bits != 128 && key_bits != 192 && key_bits != 256) + return AVERROR(EINVAL); + + a->rounds = rounds; + + memcpy(tk, key, KC * 4); + memcpy(a->round_key[0].u8, key, KC * 4); + + for (t = KC * 4; t < (rounds + 1) * 16; t += KC * 4) { + for (i = 0; i < 4; i++) + tk[0][i] ^= sbox[tk[KC - 1][(i + 1) & 3]]; + tk[0][0] ^= rcon[rconpointer++]; + + for (j = 1; j < KC; j++) { + if (KC != 8 || j != KC >> 1) + for (i = 0; i < 4; i++) + tk[j][i] ^= tk[j - 1][i]; + else + for (i = 0; i < 4; i++) + tk[j][i] ^= sbox[tk[j - 1][i]]; + } + + memcpy(a->round_key[0].u8 + t, tk, KC * 4); + } + + if (decrypt) { + for (i = 1; i < rounds; i++) { + av_aes_block tmp[3]; + tmp[2] = a->round_key[i]; + subshift(&tmp[1], 0, sbox); + mix(tmp, dec_multbl, 1, 3); + a->round_key[i] = tmp[0]; + } + } else { + for (i = 0; i < (rounds + 1) >> 1; i++) + FFSWAP(av_aes_block, a->round_key[i], a->round_key[rounds - i]); + } + + return 0; +} + diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes.h new file mode 100644 index 0000000000..09efbda107 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes.h @@ -0,0 +1,65 @@ +/* + * copyright (c) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_H +#define AVUTIL_AES_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_aes AES + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_aes_size; + +struct AVAES; + +/** + * Allocate an AVAES context. + */ +struct AVAES *av_aes_alloc(void); + +/** + * Initialize an AVAES context. + * @param key_bits 128, 192 or 256 + * @param decrypt 0 for encryption, 1 for decryption + */ +int av_aes_init(struct AVAES *a, const uint8_t *key, int key_bits, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * @param count number of 16 byte blocks + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_aes_crypt(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_AES_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_ctr.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_ctr.c new file mode 100644 index 0000000000..0c2e86785f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_ctr.c @@ -0,0 +1,135 @@ +/* + * AES-CTR cipher + * Copyright (c) 2015 Eran Kornblau + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "common.h" +#include "aes_ctr.h" +#include "aes.h" +#include "random_seed.h" + +#define AES_BLOCK_SIZE (16) + +typedef struct AVAESCTR { + struct AVAES* aes; + uint8_t counter[AES_BLOCK_SIZE]; + uint8_t encrypted_counter[AES_BLOCK_SIZE]; + int block_offset; +} AVAESCTR; + +struct AVAESCTR *av_aes_ctr_alloc(void) +{ + return av_mallocz(sizeof(struct AVAESCTR)); +} + +void av_aes_ctr_set_iv(struct AVAESCTR *a, const uint8_t* iv) +{ + memcpy(a->counter, iv, AES_CTR_IV_SIZE); + memset(a->counter + AES_CTR_IV_SIZE, 0, sizeof(a->counter) - AES_CTR_IV_SIZE); + a->block_offset = 0; +} + +void av_aes_ctr_set_full_iv(struct AVAESCTR *a, const uint8_t* iv) +{ + memcpy(a->counter, iv, sizeof(a->counter)); + a->block_offset = 0; +} + +const uint8_t* av_aes_ctr_get_iv(struct AVAESCTR *a) +{ + return a->counter; +} + +void av_aes_ctr_set_random_iv(struct AVAESCTR *a) +{ + uint32_t iv[2]; + + iv[0] = av_get_random_seed(); + iv[1] = av_get_random_seed(); + + av_aes_ctr_set_iv(a, (uint8_t*)iv); +} + +int av_aes_ctr_init(struct AVAESCTR *a, const uint8_t *key) +{ + a->aes = av_aes_alloc(); + if (!a->aes) { + return AVERROR(ENOMEM); + } + + av_aes_init(a->aes, key, 128, 0); + + memset(a->counter, 0, sizeof(a->counter)); + a->block_offset = 0; + + return 0; +} + +void av_aes_ctr_free(struct AVAESCTR *a) +{ + if (a) { + av_freep(&a->aes); + av_free(a); + } +} + +static void av_aes_ctr_increment_be64(uint8_t* counter) +{ + uint8_t* cur_pos; + + for (cur_pos = counter + 7; cur_pos >= counter; cur_pos--) { + (*cur_pos)++; + if (*cur_pos != 0) { + break; + } + } +} + +void av_aes_ctr_increment_iv(struct AVAESCTR *a) +{ + av_aes_ctr_increment_be64(a->counter); + memset(a->counter + AES_CTR_IV_SIZE, 0, sizeof(a->counter) - AES_CTR_IV_SIZE); + a->block_offset = 0; +} + +void av_aes_ctr_crypt(struct AVAESCTR *a, uint8_t *dst, const uint8_t *src, int count) +{ + const uint8_t* src_end = src + count; + const uint8_t* cur_end_pos; + uint8_t* encrypted_counter_pos; + + while (src < src_end) { + if (a->block_offset == 0) { + av_aes_crypt(a->aes, a->encrypted_counter, a->counter, 1, NULL, 0); + + av_aes_ctr_increment_be64(a->counter + 8); + } + + encrypted_counter_pos = a->encrypted_counter + a->block_offset; + cur_end_pos = src + AES_BLOCK_SIZE - a->block_offset; + cur_end_pos = FFMIN(cur_end_pos, src_end); + + a->block_offset += cur_end_pos - src; + a->block_offset &= (AES_BLOCK_SIZE - 1); + + while (src < cur_end_pos) { + *dst++ = *src++ ^ *encrypted_counter_pos++; + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_ctr.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_ctr.h new file mode 100644 index 0000000000..e4aae126a7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_ctr.h @@ -0,0 +1,88 @@ +/* + * AES-CTR cipher + * Copyright (c) 2015 Eran Kornblau + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_CTR_H +#define AVUTIL_AES_CTR_H + +#include + +#include "attributes.h" +#include "version.h" + +#define AES_CTR_KEY_SIZE (16) +#define AES_CTR_IV_SIZE (8) + +struct AVAESCTR; + +/** + * Allocate an AVAESCTR context. + */ +struct AVAESCTR *av_aes_ctr_alloc(void); + +/** + * Initialize an AVAESCTR context. + * @param key encryption key, must have a length of AES_CTR_KEY_SIZE + */ +int av_aes_ctr_init(struct AVAESCTR *a, const uint8_t *key); + +/** + * Release an AVAESCTR context. + */ +void av_aes_ctr_free(struct AVAESCTR *a); + +/** + * Process a buffer using a previously initialized context. + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param size the size of src and dst + */ +void av_aes_ctr_crypt(struct AVAESCTR *a, uint8_t *dst, const uint8_t *src, int size); + +/** + * Get the current iv + */ +const uint8_t* av_aes_ctr_get_iv(struct AVAESCTR *a); + +/** + * Generate a random iv + */ +void av_aes_ctr_set_random_iv(struct AVAESCTR *a); + +/** + * Forcefully change the 8-byte iv + */ +void av_aes_ctr_set_iv(struct AVAESCTR *a, const uint8_t* iv); + +/** + * Forcefully change the "full" 16-byte iv, including the counter + */ +void av_aes_ctr_set_full_iv(struct AVAESCTR *a, const uint8_t* iv); + +/** + * Increment the top 64 bit of the iv (performed after each frame) + */ +void av_aes_ctr_increment_iv(struct AVAESCTR *a); + +/** + * @} + */ + +#endif /* AVUTIL_AES_CTR_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_internal.h new file mode 100644 index 0000000000..494425878d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aes_internal.h @@ -0,0 +1,43 @@ +/* + * copyright (c) 2015 Rodger Combs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_INTERNAL_H +#define AVUTIL_AES_INTERNAL_H + +#include "mem.h" +#include + +typedef union { + uint64_t u64[2]; + uint32_t u32[4]; + uint8_t u8x4[4][4]; + uint8_t u8[16]; +} av_aes_block; + +typedef struct AVAES { + // Note: round_key[16] is accessed in the init code, but this only + // overwrites state, which does not matter (see also commit ba554c0). + DECLARE_ALIGNED(16, av_aes_block, round_key)[15]; + DECLARE_ALIGNED(16, av_aes_block, state)[2]; + int rounds; + void (*crypt)(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int rounds); +} AVAES; + +#endif /* AVUTIL_AES_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/bswap.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/bswap.h new file mode 100644 index 0000000000..611ff0ad5b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/bswap.h @@ -0,0 +1,67 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_BSWAP_H +#define AVUTIL_ARM_BSWAP_H + +#include +#include "config.h" +#include "libavutil/attributes.h" + +#ifdef __ARMCC_VERSION + +#if HAVE_ARMV6 +#define av_bswap32 av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return __rev(x); +} +#endif /* HAVE_ARMV6 */ + +#elif HAVE_INLINE_ASM + +#if HAVE_ARMV6_INLINE +#define av_bswap16 av_bswap16 +static av_always_inline av_const unsigned av_bswap16(unsigned x) +{ + __asm__("rev16 %0, %0" : "+r"(x)); + return x; +} +#endif + +#if AV_GCC_VERSION_AT_MOST(4,4) +#define av_bswap32 av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ +#if HAVE_ARMV6_INLINE + __asm__("rev %0, %0" : "+r"(x)); +#else + uint32_t t; + __asm__ ("eor %1, %0, %0, ror #16 \n\t" + "bic %1, %1, #0xFF0000 \n\t" + "mov %0, %0, ror #8 \n\t" + "eor %0, %0, %1, lsr #8 \n\t" + : "+r"(x), "=&r"(t)); +#endif /* HAVE_ARMV6_INLINE */ + return x; +} +#endif /* AV_GCC_VERSION_AT_MOST(4,4) */ + +#endif /* __ARMCC_VERSION */ + +#endif /* AVUTIL_ARM_BSWAP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/cpu.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/cpu.c new file mode 100644 index 0000000000..81e85e2525 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/cpu.c @@ -0,0 +1,170 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" +#include "config.h" + +#define CORE_FLAG(f) \ + (AV_CPU_FLAG_ ## f * (HAVE_ ## f ## _EXTERNAL || HAVE_ ## f ## _INLINE)) + +#define CORE_CPU_FLAGS \ + (CORE_FLAG(ARMV5TE) | \ + CORE_FLAG(ARMV6) | \ + CORE_FLAG(ARMV6T2) | \ + CORE_FLAG(VFP) | \ + CORE_FLAG(VFPV3) | \ + CORE_FLAG(NEON)) + +#if defined __linux__ || defined __ANDROID__ + +#include +#include +#include +#include "libavutil/avstring.h" + +#define AT_HWCAP 16 + +/* Relevant HWCAP values from kernel headers */ +#define HWCAP_VFP (1 << 6) +#define HWCAP_EDSP (1 << 7) +#define HWCAP_THUMBEE (1 << 11) +#define HWCAP_NEON (1 << 12) +#define HWCAP_VFPv3 (1 << 13) +#define HWCAP_TLS (1 << 15) + +static int get_hwcap(uint32_t *hwcap) +{ + struct { uint32_t a_type; uint32_t a_val; } auxv; + FILE *f = fopen("/proc/self/auxv", "r"); + int err = -1; + + if (!f) + return -1; + + while (fread(&auxv, sizeof(auxv), 1, f) > 0) { + if (auxv.a_type == AT_HWCAP) { + *hwcap = auxv.a_val; + err = 0; + break; + } + } + + fclose(f); + return err; +} + +static int get_cpuinfo(uint32_t *hwcap) +{ + FILE *f = fopen("/proc/cpuinfo", "r"); + char buf[200]; + + if (!f) + return -1; + + *hwcap = 0; + while (fgets(buf, sizeof(buf), f)) { + if (av_strstart(buf, "Features", NULL)) { + if (strstr(buf, " edsp ")) + *hwcap |= HWCAP_EDSP; + if (strstr(buf, " tls ")) + *hwcap |= HWCAP_TLS; + if (strstr(buf, " thumbee ")) + *hwcap |= HWCAP_THUMBEE; + if (strstr(buf, " vfp ")) + *hwcap |= HWCAP_VFP; + if (strstr(buf, " vfpv3 ")) + *hwcap |= HWCAP_VFPv3; + if (strstr(buf, " neon ") || strstr(buf, " asimd ")) + *hwcap |= HWCAP_NEON; + if (strstr(buf, " fp ")) // Listed on 64 bit ARMv8 kernels + *hwcap |= HWCAP_VFP | HWCAP_VFPv3; + break; + } + } + fclose(f); + return 0; +} + +int ff_get_cpu_flags_arm(void) +{ + int flags = CORE_CPU_FLAGS; + uint32_t hwcap; + + if (get_hwcap(&hwcap) < 0) + if (get_cpuinfo(&hwcap) < 0) + return flags; + +#define check_cap(cap, flag) do { \ + if (hwcap & HWCAP_ ## cap) \ + flags |= AV_CPU_FLAG_ ## flag; \ + } while (0) + + /* No flags explicitly indicate v6 or v6T2 so check others which + imply support. */ + check_cap(EDSP, ARMV5TE); + check_cap(TLS, ARMV6); + check_cap(THUMBEE, ARMV6T2); + check_cap(VFP, VFP); + check_cap(VFPv3, VFPV3); + check_cap(NEON, NEON); + + /* The v6 checks above are not reliable so let higher flags + trickle down. */ + if (flags & (AV_CPU_FLAG_VFPV3 | AV_CPU_FLAG_NEON)) + flags |= AV_CPU_FLAG_ARMV6T2; + else if (flags & (AV_CPU_FLAG_ARMV6T2 | AV_CPU_FLAG_ARMV6)) + /* Some functions use the 'setend' instruction which is deprecated on ARMv8 + * and serializing on some ARMv7 cores. This ensures such functions + * are only enabled on ARMv6. */ + flags |= AV_CPU_FLAG_SETEND; + + if (flags & AV_CPU_FLAG_ARMV6T2) + flags |= AV_CPU_FLAG_ARMV6; + + /* set the virtual VFPv2 vector mode flag */ + if ((flags & AV_CPU_FLAG_VFP) && !(flags & (AV_CPU_FLAG_VFPV3 | AV_CPU_FLAG_NEON))) + flags |= AV_CPU_FLAG_VFP_VM; + + return flags; +} + +#else + +int ff_get_cpu_flags_arm(void) +{ + return AV_CPU_FLAG_ARMV5TE * HAVE_ARMV5TE | + AV_CPU_FLAG_ARMV6 * HAVE_ARMV6 | + AV_CPU_FLAG_ARMV6T2 * HAVE_ARMV6T2 | + AV_CPU_FLAG_VFP * HAVE_VFP | + AV_CPU_FLAG_VFPV3 * HAVE_VFPV3 | + AV_CPU_FLAG_NEON * HAVE_NEON | + AV_CPU_FLAG_SETEND * !(HAVE_NEON | HAVE_VFPV3); +} + +#endif + +size_t ff_get_cpu_max_align_arm(void) +{ + int flags = av_get_cpu_flags(); + + if (flags & AV_CPU_FLAG_NEON) + return 16; + + return 8; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/cpu.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/cpu.h new file mode 100644 index 0000000000..1d6cc65dc4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/cpu.h @@ -0,0 +1,38 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_CPU_H +#define AVUTIL_ARM_CPU_H + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" + +#define have_armv5te(flags) CPUEXT(flags, ARMV5TE) +#define have_armv6(flags) CPUEXT(flags, ARMV6) +#define have_armv6t2(flags) CPUEXT(flags, ARMV6T2) +#define have_vfp(flags) CPUEXT(flags, VFP) +#define have_vfpv3(flags) CPUEXT(flags, VFPV3) +#define have_neon(flags) CPUEXT(flags, NEON) +#define have_setend(flags) CPUEXT(flags, SETEND) + +/* some functions use the VFPv2 vector mode which is deprecated in ARMv7-A + * and might trap on such CPU depending on the OS configuration */ +#define have_vfp_vm(flags) \ + (HAVE_VFP && ((flags) & AV_CPU_FLAG_VFP_VM)) + +#endif /* AVUTIL_ARM_CPU_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_arm.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_arm.h new file mode 100644 index 0000000000..fe311cc0d2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_arm.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2009 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_FLOAT_DSP_ARM_H +#define AVUTIL_ARM_FLOAT_DSP_ARM_H + +#include "libavutil/float_dsp.h" + +void ff_float_dsp_init_vfp(AVFloatDSPContext *fdsp, int cpu_flags); +void ff_float_dsp_init_neon(AVFloatDSPContext *fdsp); + +#endif /* AVUTIL_ARM_FLOAT_DSP_ARM_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_arm.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_arm.c new file mode 100644 index 0000000000..678762862e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_arm.c @@ -0,0 +1,32 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/float_dsp.h" +#include "cpu.h" +#include "float_dsp_arm.h" + +av_cold void ff_float_dsp_init_arm(AVFloatDSPContext *fdsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_vfp(cpu_flags)) + ff_float_dsp_init_vfp(fdsp, cpu_flags); + if (have_neon(cpu_flags)) + ff_float_dsp_init_neon(fdsp); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_neon.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_neon.c new file mode 100644 index 0000000000..689aa77c7b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_neon.c @@ -0,0 +1,59 @@ +/* + * ARM NEON optimised Float DSP functions + * Copyright (c) 2008 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/float_dsp.h" +#include "float_dsp_arm.h" + +void ff_vector_fmul_neon(float *dst, const float *src0, const float *src1, int len); + +void ff_vector_fmac_scalar_neon(float *dst, const float *src, float mul, + int len); + +void ff_vector_fmul_scalar_neon(float *dst, const float *src, float mul, + int len); + +void ff_vector_fmul_window_neon(float *dst, const float *src0, + const float *src1, const float *win, int len); + +void ff_vector_fmul_add_neon(float *dst, const float *src0, const float *src1, + const float *src2, int len); + +void ff_vector_fmul_reverse_neon(float *dst, const float *src0, + const float *src1, int len); + +void ff_butterflies_float_neon(float *v1, float *v2, int len); + +float ff_scalarproduct_float_neon(const float *v1, const float *v2, int len); + +av_cold void ff_float_dsp_init_neon(AVFloatDSPContext *fdsp) +{ + fdsp->vector_fmul = ff_vector_fmul_neon; + fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_neon; + fdsp->vector_fmul_scalar = ff_vector_fmul_scalar_neon; + fdsp->vector_fmul_window = ff_vector_fmul_window_neon; + fdsp->vector_fmul_add = ff_vector_fmul_add_neon; + fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_neon; + fdsp->butterflies_float = ff_butterflies_float_neon; + fdsp->scalarproduct_float = ff_scalarproduct_float_neon; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_vfp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_vfp.c new file mode 100644 index 0000000000..05873e7e37 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/float_dsp_init_vfp.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008 Siarhei Siamashka + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/float_dsp.h" +#include "cpu.h" +#include "float_dsp_arm.h" + +void ff_vector_fmul_vfp(float *dst, const float *src0, const float *src1, + int len); + +void ff_vector_fmul_window_vfp(float *dst, const float *src0, + const float *src1, const float *win, int len); + +void ff_vector_fmul_reverse_vfp(float *dst, const float *src0, + const float *src1, int len); + +void ff_butterflies_float_vfp(float *av_restrict v1, float *av_restrict v2, int len); + +av_cold void ff_float_dsp_init_vfp(AVFloatDSPContext *fdsp, int cpu_flags) +{ + if (have_vfp_vm(cpu_flags)) { + fdsp->vector_fmul = ff_vector_fmul_vfp; + fdsp->vector_fmul_window = ff_vector_fmul_window_vfp; + } + fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_vfp; + if (have_vfp_vm(cpu_flags)) + fdsp->butterflies_float = ff_butterflies_float_vfp; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/intmath.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/intmath.h new file mode 100644 index 0000000000..5311a7d52b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/intmath.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2010 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_INTMATH_H +#define AVUTIL_ARM_INTMATH_H + +#include + +#include "config.h" +#include "libavutil/attributes.h" + +#if HAVE_INLINE_ASM + +#if HAVE_ARMV6_INLINE + +#define av_clip_uint8 av_clip_uint8_arm +static av_always_inline av_const int av_clip_uint8_arm(int a) +{ + int x; + __asm__ ("usat %0, #8, %1" : "=r"(x) : "r"(a)); + return x; +} + +#define av_clip_int8 av_clip_int8_arm +static av_always_inline av_const int av_clip_int8_arm(int a) +{ + int x; + __asm__ ("ssat %0, #8, %1" : "=r"(x) : "r"(a)); + return x; +} + +#define av_clip_uint16 av_clip_uint16_arm +static av_always_inline av_const int av_clip_uint16_arm(int a) +{ + int x; + __asm__ ("usat %0, #16, %1" : "=r"(x) : "r"(a)); + return x; +} + +#define av_clip_int16 av_clip_int16_arm +static av_always_inline av_const int av_clip_int16_arm(int a) +{ + int x; + __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); + return x; +} + +#define av_clip_intp2 av_clip_intp2_arm +static av_always_inline av_const int av_clip_intp2_arm(int a, int p) +{ + unsigned x; + __asm__ ("ssat %0, %2, %1" : "=r"(x) : "r"(a), "i"(p+1)); + return x; +} + +#define av_clip_uintp2 av_clip_uintp2_arm +static av_always_inline av_const unsigned av_clip_uintp2_arm(int a, int p) +{ + unsigned x; + __asm__ ("usat %0, %2, %1" : "=r"(x) : "r"(a), "i"(p)); + return x; +} + +#define av_sat_add32 av_sat_add32_arm +static av_always_inline int av_sat_add32_arm(int a, int b) +{ + int r; + __asm__ ("qadd %0, %1, %2" : "=r"(r) : "r"(a), "r"(b)); + return r; +} + +#define av_sat_dadd32 av_sat_dadd32_arm +static av_always_inline int av_sat_dadd32_arm(int a, int b) +{ + int r; + __asm__ ("qdadd %0, %1, %2" : "=r"(r) : "r"(a), "r"(b)); + return r; +} + +#define av_sat_sub32 av_sat_sub32_arm +static av_always_inline int av_sat_sub32_arm(int a, int b) +{ + int r; + __asm__ ("qsub %0, %1, %2" : "=r"(r) : "r"(a), "r"(b)); + return r; +} + +#define av_sat_dsub32 av_sat_dsub32_arm +static av_always_inline int av_sat_dsub32_arm(int a, int b) +{ + int r; + __asm__ ("qdsub %0, %1, %2" : "=r"(r) : "r"(a), "r"(b)); + return r; +} + +#endif /* HAVE_ARMV6_INLINE */ + +#if HAVE_ASM_MOD_Q + +#define av_clipl_int32 av_clipl_int32_arm +static av_always_inline av_const int32_t av_clipl_int32_arm(int64_t a) +{ + int x, y; + __asm__ ("adds %1, %R2, %Q2, lsr #31 \n\t" + "itet ne \n\t" + "mvnne %1, #1<<31 \n\t" + "moveq %0, %Q2 \n\t" + "eorne %0, %1, %R2, asr #31 \n\t" + : "=r"(x), "=&r"(y) : "r"(a) : "cc"); + return x; +} + +#endif /* HAVE_ASM_MOD_Q */ + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVUTIL_ARM_INTMATH_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/intreadwrite.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/intreadwrite.h new file mode 100644 index 0000000000..60fc860cbb --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/intreadwrite.h @@ -0,0 +1,91 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_INTREADWRITE_H +#define AVUTIL_ARM_INTREADWRITE_H + +#include +#include "config.h" +#include "libavutil/attributes.h" + +#if HAVE_FAST_UNALIGNED && HAVE_INLINE_ASM && AV_GCC_VERSION_AT_MOST(4,6) + +#define AV_RN16 AV_RN16 +static av_always_inline unsigned AV_RN16(const void *p) +{ + const uint8_t *q = p; + unsigned v; +#if AV_GCC_VERSION_AT_MOST(4,5) + __asm__ ("ldrh %0, %1" : "=r"(v) : "m"(*(const uint16_t *)q)); +#elif defined __thumb__ + __asm__ ("ldrh %0, %1" : "=r"(v) : "m"(q[0]), "m"(q[1])); +#else + __asm__ ("ldrh %0, %1" : "=r"(v) : "Uq"(q[0]), "m"(q[1])); +#endif + return v; +} + +#define AV_WN16 AV_WN16 +static av_always_inline void AV_WN16(void *p, uint16_t v) +{ + __asm__ ("strh %1, %0" : "=m"(*(uint16_t *)p) : "r"(v)); +} + +#define AV_RN32 AV_RN32 +static av_always_inline uint32_t AV_RN32(const void *p) +{ + const struct __attribute__((packed)) { uint32_t v; } *q = p; + uint32_t v; + __asm__ ("ldr %0, %1" : "=r"(v) : "m"(*q)); + return v; +} + +#define AV_WN32 AV_WN32 +static av_always_inline void AV_WN32(void *p, uint32_t v) +{ + __asm__ ("str %1, %0" : "=m"(*(uint32_t *)p) : "r"(v)); +} + +#if HAVE_ASM_MOD_Q + +#define AV_RN64 AV_RN64 +static av_always_inline uint64_t AV_RN64(const void *p) +{ + const struct __attribute__((packed)) { uint32_t v; } *q = p; + uint64_t v; + __asm__ ("ldr %Q0, %1 \n\t" + "ldr %R0, %2 \n\t" + : "=&r"(v) + : "m"(q[0]), "m"(q[1])); + return v; +} + +#define AV_WN64 AV_WN64 +static av_always_inline void AV_WN64(void *p, uint64_t v) +{ + __asm__ ("str %Q2, %0 \n\t" + "str %R2, %1 \n\t" + : "=m"(*(uint32_t*)p), "=m"(*((uint32_t*)p+1)) + : "r"(v)); +} + +#endif /* HAVE_ASM_MOD_Q */ + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVUTIL_ARM_INTREADWRITE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/neontest.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/neontest.h new file mode 100644 index 0000000000..d75ab8380b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/neontest.h @@ -0,0 +1,67 @@ +/* + * check NEON registers for clobbering + * Copyright (c) 2008 Ramiro Polla + * Copyright (c) 2013 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_NEONTEST_H +#define AVUTIL_ARM_NEONTEST_H + +#include +#include +#include +#include +#include + +#include "libavutil/bswap.h" + +#define storeneonregs(mem) \ + __asm__ volatile( \ + "vstm %0, {d8-d15}\n\t" \ + :: "r"(mem) : "memory") + +#define testneonclobbers(func, ctx, ...) \ + uint64_t neon[2][8]; \ + int ret; \ + storeneonregs(neon[0]); \ + ret = __real_ ## func(ctx, __VA_ARGS__); \ + storeneonregs(neon[1]); \ + if (memcmp(neon[0], neon[1], sizeof(neon[0]))) { \ + int i; \ + av_log(ctx, AV_LOG_ERROR, \ + "NEON REGS CLOBBERED IN %s!\n", #func); \ + for (i = 0; i < 8; i ++) \ + if (neon[0][i] != neon[1][i]) { \ + av_log(ctx, AV_LOG_ERROR, \ + "d%-2d = %016"PRIx64"\n", \ + 8 + i, av_bswap64(neon[0][i])); \ + av_log(ctx, AV_LOG_ERROR, \ + " -> %016"PRIx64"\n", \ + av_bswap64(neon[1][i])); \ + } \ + abort(); \ + } \ + return ret + +#define wrap(func) \ +int __real_ ## func; \ +int __wrap_ ## func; \ +int __wrap_ ## func + +#endif /* AVUTIL_ARM_NEONTEST_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/timer.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/timer.h new file mode 100644 index 0000000000..5e8bc8edd0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/timer.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2009 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_TIMER_H +#define AVUTIL_ARM_TIMER_H + +#include +#include "config.h" + +#if HAVE_INLINE_ASM && defined(__ARM_ARCH_7A__) + +#define AV_READ_TIME read_time + +static inline uint64_t read_time(void) +{ + unsigned cc; + __asm__ volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r"(cc)); + return cc; +} + +#endif /* HAVE_INLINE_ASM && __ARM_ARCH_7A__ */ + +#endif /* AVUTIL_ARM_TIMER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/attributes.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/attributes.h new file mode 100644 index 0000000000..ced108aa2c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/attributes.h @@ -0,0 +1,167 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Macro definitions for various function/variable attributes + */ + +#ifndef AVUTIL_ATTRIBUTES_H +#define AVUTIL_ATTRIBUTES_H + +#ifdef __GNUC__ +# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +# define AV_GCC_VERSION_AT_MOST(x,y) (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y)) +#else +# define AV_GCC_VERSION_AT_LEAST(x,y) 0 +# define AV_GCC_VERSION_AT_MOST(x,y) 0 +#endif + +#ifndef av_always_inline +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_always_inline __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +# define av_always_inline __forceinline +#else +# define av_always_inline inline +#endif +#endif + +#ifndef av_extern_inline +#if defined(__ICL) && __ICL >= 1210 || defined(__GNUC_STDC_INLINE__) +# define av_extern_inline extern inline +#else +# define av_extern_inline inline +#endif +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,4) +# define av_warn_unused_result __attribute__((warn_unused_result)) +#else +# define av_warn_unused_result +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_noinline __attribute__((noinline)) +#elif defined(_MSC_VER) +# define av_noinline __declspec(noinline) +#else +# define av_noinline +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) +# define av_pure __attribute__((pure)) +#else +# define av_pure +#endif + +#if AV_GCC_VERSION_AT_LEAST(2,6) || defined(__clang__) +# define av_const __attribute__((const)) +#else +# define av_const +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,3) || defined(__clang__) +# define av_cold __attribute__((cold)) +#else +# define av_cold +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,1) && !defined(__llvm__) +# define av_flatten __attribute__((flatten)) +#else +# define av_flatten +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define attribute_deprecated __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define attribute_deprecated __declspec(deprecated) +#else +# define attribute_deprecated +#endif + +/** + * Disable warnings about deprecated features + * This is useful for sections of code kept for backward compatibility and + * scheduled for removal. + */ +#ifndef AV_NOWARN_DEPRECATED +#if AV_GCC_VERSION_AT_LEAST(4,6) +# define AV_NOWARN_DEPRECATED(code) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \ + code \ + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +# define AV_NOWARN_DEPRECATED(code) \ + __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) \ + code; \ + __pragma(warning(pop)) +#else +# define AV_NOWARN_DEPRECATED(code) code +#endif +#endif + +#if defined(__GNUC__) || defined(__clang__) +# define av_unused __attribute__((unused)) +#else +# define av_unused +#endif + +/** + * Mark a variable as used and prevent the compiler from optimizing it + * away. This is useful for variables accessed only from inline + * assembler without the compiler being aware. + */ +#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) +# define av_used __attribute__((used)) +#else +# define av_used +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,3) || defined(__clang__) +# define av_alias __attribute__((may_alias)) +#else +# define av_alias +#endif + +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__INTEL_COMPILER) +# define av_uninit(x) x=x +#else +# define av_uninit(x) x +#endif + +#if defined(__GNUC__) || defined(__clang__) +# define av_builtin_constant_p __builtin_constant_p +# define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos))) +#else +# define av_builtin_constant_p(x) 0 +# define av_printf_format(fmtpos, attrpos) +#endif + +#if AV_GCC_VERSION_AT_LEAST(2,5) || defined(__clang__) +# define av_noreturn __attribute__((noreturn)) +#else +# define av_noreturn +#endif + +#endif /* AVUTIL_ATTRIBUTES_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/audio_fifo.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/audio_fifo.c new file mode 100644 index 0000000000..1bf75ced54 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/audio_fifo.c @@ -0,0 +1,236 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO + */ + +#include "avutil.h" +#include "audio_fifo.h" +#include "common.h" +#include "fifo.h" +#include "mem.h" +#include "samplefmt.h" + +struct AVAudioFifo { + AVFifoBuffer **buf; /**< single buffer for interleaved, per-channel buffers for planar */ + int nb_buffers; /**< number of buffers */ + int nb_samples; /**< number of samples currently in the FIFO */ + int allocated_samples; /**< current allocated size, in samples */ + + int channels; /**< number of channels */ + enum AVSampleFormat sample_fmt; /**< sample format */ + int sample_size; /**< size, in bytes, of one sample in a buffer */ +}; + +void av_audio_fifo_free(AVAudioFifo *af) +{ + if (af) { + if (af->buf) { + int i; + for (i = 0; i < af->nb_buffers; i++) { + av_fifo_freep(&af->buf[i]); + } + av_freep(&af->buf); + } + av_free(af); + } +} + +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples) +{ + AVAudioFifo *af; + int buf_size, i; + + /* get channel buffer size (also validates parameters) */ + if (av_samples_get_buffer_size(&buf_size, channels, nb_samples, sample_fmt, 1) < 0) + return NULL; + + af = av_mallocz(sizeof(*af)); + if (!af) + return NULL; + + af->channels = channels; + af->sample_fmt = sample_fmt; + af->sample_size = buf_size / nb_samples; + af->nb_buffers = av_sample_fmt_is_planar(sample_fmt) ? channels : 1; + + af->buf = av_mallocz_array(af->nb_buffers, sizeof(*af->buf)); + if (!af->buf) + goto error; + + for (i = 0; i < af->nb_buffers; i++) { + af->buf[i] = av_fifo_alloc(buf_size); + if (!af->buf[i]) + goto error; + } + af->allocated_samples = nb_samples; + + return af; + +error: + av_audio_fifo_free(af); + return NULL; +} + +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples) +{ + int i, ret, buf_size; + + if ((ret = av_samples_get_buffer_size(&buf_size, af->channels, nb_samples, + af->sample_fmt, 1)) < 0) + return ret; + + for (i = 0; i < af->nb_buffers; i++) { + if ((ret = av_fifo_realloc2(af->buf[i], buf_size)) < 0) + return ret; + } + af->allocated_samples = nb_samples; + return 0; +} + +int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples) +{ + int i, ret, size; + + /* automatically reallocate buffers if needed */ + if (av_audio_fifo_space(af) < nb_samples) { + int current_size = av_audio_fifo_size(af); + /* check for integer overflow in new size calculation */ + if (INT_MAX / 2 - current_size < nb_samples) + return AVERROR(EINVAL); + /* reallocate buffers */ + if ((ret = av_audio_fifo_realloc(af, 2 * (current_size + nb_samples))) < 0) + return ret; + } + + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) { + ret = av_fifo_generic_write(af->buf[i], data[i], size, NULL); + if (ret != size) + return AVERROR_BUG; + } + af->nb_samples += nb_samples; + + return nb_samples; +} + +int av_audio_fifo_peek(AVAudioFifo *af, void **data, int nb_samples) +{ + int i, ret, size; + + if (nb_samples < 0) + return AVERROR(EINVAL); + nb_samples = FFMIN(nb_samples, af->nb_samples); + if (!nb_samples) + return 0; + + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) { + if ((ret = av_fifo_generic_peek(af->buf[i], data[i], size, NULL)) < 0) + return AVERROR_BUG; + } + + return nb_samples; +} + +int av_audio_fifo_peek_at(AVAudioFifo *af, void **data, int nb_samples, int offset) +{ + int i, ret, size; + + if (offset < 0 || offset >= af->nb_samples) + return AVERROR(EINVAL); + if (nb_samples < 0) + return AVERROR(EINVAL); + nb_samples = FFMIN(nb_samples, af->nb_samples); + if (!nb_samples) + return 0; + if (offset > af->nb_samples - nb_samples) + return AVERROR(EINVAL); + + offset *= af->sample_size; + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) { + if ((ret = av_fifo_generic_peek_at(af->buf[i], data[i], offset, size, NULL)) < 0) + return AVERROR_BUG; + } + + return nb_samples; +} + +int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples) +{ + int i, size; + + if (nb_samples < 0) + return AVERROR(EINVAL); + nb_samples = FFMIN(nb_samples, af->nb_samples); + if (!nb_samples) + return 0; + + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) { + if (av_fifo_generic_read(af->buf[i], data[i], size, NULL) < 0) + return AVERROR_BUG; + } + af->nb_samples -= nb_samples; + + return nb_samples; +} + +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples) +{ + int i, size; + + if (nb_samples < 0) + return AVERROR(EINVAL); + nb_samples = FFMIN(nb_samples, af->nb_samples); + + if (nb_samples) { + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) + av_fifo_drain(af->buf[i], size); + af->nb_samples -= nb_samples; + } + return 0; +} + +void av_audio_fifo_reset(AVAudioFifo *af) +{ + int i; + + for (i = 0; i < af->nb_buffers; i++) + av_fifo_reset(af->buf[i]); + + af->nb_samples = 0; +} + +int av_audio_fifo_size(AVAudioFifo *af) +{ + return af->nb_samples; +} + +int av_audio_fifo_space(AVAudioFifo *af) +{ + return af->allocated_samples - af->nb_samples; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/audio_fifo.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/audio_fifo.h new file mode 100644 index 0000000000..d8a9194a8d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/audio_fifo.h @@ -0,0 +1,187 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO Buffer + */ + +#ifndef AVUTIL_AUDIO_FIFO_H +#define AVUTIL_AUDIO_FIFO_H + +#include "avutil.h" +#include "fifo.h" +#include "samplefmt.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_audiofifo Audio FIFO Buffer + * @{ + */ + +/** + * Context for an Audio FIFO Buffer. + * + * - Operates at the sample level rather than the byte level. + * - Supports multiple channels with either planar or packed sample format. + * - Automatic reallocation when writing to a full buffer. + */ +typedef struct AVAudioFifo AVAudioFifo; + +/** + * Free an AVAudioFifo. + * + * @param af AVAudioFifo to free + */ +void av_audio_fifo_free(AVAudioFifo *af); + +/** + * Allocate an AVAudioFifo. + * + * @param sample_fmt sample format + * @param channels number of channels + * @param nb_samples initial allocation size, in samples + * @return newly allocated AVAudioFifo, or NULL on error + */ +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples); + +/** + * Reallocate an AVAudioFifo. + * + * @param af AVAudioFifo to reallocate + * @param nb_samples new allocation size, in samples + * @return 0 if OK, or negative AVERROR code on failure + */ +av_warn_unused_result +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples); + +/** + * Write data to an AVAudioFifo. + * + * The AVAudioFifo will be reallocated automatically if the available space + * is less than nb_samples. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to write to + * @param data audio data plane pointers + * @param nb_samples number of samples to write + * @return number of samples actually written, or negative AVERROR + * code on failure. If successful, the number of samples + * actually written will always be nb_samples. + */ +int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Peek data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to peek + * @return number of samples actually peek, or negative AVERROR code + * on failure. The number of samples actually peek will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_peek(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Peek data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to peek + * @param offset offset from current read position + * @return number of samples actually peek, or negative AVERROR code + * on failure. The number of samples actually peek will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_peek_at(AVAudioFifo *af, void **data, int nb_samples, int offset); + +/** + * Read data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to read + * @return number of samples actually read, or negative AVERROR code + * on failure. The number of samples actually read will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Drain data from an AVAudioFifo. + * + * Removes the data without reading it. + * + * @param af AVAudioFifo to drain + * @param nb_samples number of samples to drain + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples); + +/** + * Reset the AVAudioFifo buffer. + * + * This empties all data in the buffer. + * + * @param af AVAudioFifo to reset + */ +void av_audio_fifo_reset(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for reading. + * + * @param af the AVAudioFifo to query + * @return number of samples available for reading + */ +int av_audio_fifo_size(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for writing. + * + * @param af the AVAudioFifo to query + * @return number of samples available for writing + */ +int av_audio_fifo_space(AVAudioFifo *af); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_AUDIO_FIFO_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avassert.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avassert.h new file mode 100644 index 0000000000..9abeadea4a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avassert.h @@ -0,0 +1,75 @@ +/* + * copyright (c) 2010 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple assert() macros that are a bit more flexible than ISO C assert(). + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_AVASSERT_H +#define AVUTIL_AVASSERT_H + +#include +#include "avutil.h" +#include "log.h" + +/** + * assert() equivalent, that is always enabled. + */ +#define av_assert0(cond) do { \ + if (!(cond)) { \ + av_log(NULL, AV_LOG_PANIC, "Assertion %s failed at %s:%d\n", \ + AV_STRINGIFY(cond), __FILE__, __LINE__); \ + abort(); \ + } \ +} while (0) + + +/** + * assert() equivalent, that does not lie in speed critical code. + * These asserts() thus can be enabled without fearing speed loss. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0 +#define av_assert1(cond) av_assert0(cond) +#else +#define av_assert1(cond) ((void)0) +#endif + + +/** + * assert() equivalent, that does lie in speed critical code. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 +#define av_assert2(cond) av_assert0(cond) +#define av_assert2_fpu() av_assert0_fpu() +#else +#define av_assert2(cond) ((void)0) +#define av_assert2_fpu() ((void)0) +#endif + +/** + * Assert that floating point operations can be executed. + * + * This will av_assert0() that the cpu is not in MMX state on X86 + */ +void av_assert0_fpu(void); + +#endif /* AVUTIL_AVASSERT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avconfig.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avconfig.h new file mode 100644 index 0000000000..c289fbb551 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avconfig.h @@ -0,0 +1,6 @@ +/* Generated by ffmpeg configure */ +#ifndef AVUTIL_AVCONFIG_H +#define AVUTIL_AVCONFIG_H +#define AV_HAVE_BIGENDIAN 0 +#define AV_HAVE_FAST_UNALIGNED 1 +#endif /* AVUTIL_AVCONFIG_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avsscanf.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avsscanf.c new file mode 100644 index 0000000000..1c85412fd4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avsscanf.c @@ -0,0 +1,970 @@ +/* + * Copyright (c) 2005-2014 Rich Felker, et al. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "mem.h" +#include "avassert.h" +#include "avstring.h" +#include "bprint.h" + +typedef struct FFFILE { + size_t buf_size; + unsigned char *buf; + unsigned char *rpos, *rend; + unsigned char *shend; + ptrdiff_t shlim, shcnt; + void *cookie; + size_t (*read)(struct FFFILE *, unsigned char *, size_t); +} FFFILE; + +#define SIZE_hh -2 +#define SIZE_h -1 +#define SIZE_def 0 +#define SIZE_l 1 +#define SIZE_L 2 +#define SIZE_ll 3 + +#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->buf)) + +static int fftoread(FFFILE *f) +{ + f->rpos = f->rend = f->buf + f->buf_size; + return 0; +} + +static size_t ffstring_read(FFFILE *f, unsigned char *buf, size_t len) +{ + char *src = f->cookie; + size_t k = len+256; + char *end = memchr(src, 0, k); + + if (end) k = end-src; + if (k < len) len = k; + memcpy(buf, src, len); + f->rpos = (void *)(src+len); + f->rend = (void *)(src+k); + f->cookie = src+k; + + return len; +} + +static int ffuflow(FFFILE *f) +{ + unsigned char c; + if (!fftoread(f) && f->read(f, &c, 1)==1) return c; + return EOF; +} + +static void ffshlim(FFFILE *f, ptrdiff_t lim) +{ + f->shlim = lim; + f->shcnt = f->buf - f->rpos; + /* If lim is nonzero, rend must be a valid pointer. */ + if (lim && f->rend - f->rpos > lim) + f->shend = f->rpos + lim; + else + f->shend = f->rend; +} + +static int ffshgetc(FFFILE *f) +{ + int c; + ptrdiff_t cnt = shcnt(f); + if (f->shlim && cnt >= f->shlim || (c=ffuflow(f)) < 0) { + f->shcnt = f->buf - f->rpos + cnt; + f->shend = 0; + return EOF; + } + cnt++; + if (f->shlim && f->rend - f->rpos > f->shlim - cnt) + f->shend = f->rpos + (f->shlim - cnt); + else + f->shend = f->rend; + f->shcnt = f->buf - f->rpos + cnt; + if (f->rpos[-1] != c) f->rpos[-1] = c; + return c; +} + +#define shlim(f, lim) ffshlim((f), (lim)) +#define shgetc(f) (((f)->rpos != (f)->shend) ? *(f)->rpos++ : ffshgetc(f)) +#define shunget(f) ((f)->shend ? (void)(f)->rpos-- : (void)0) + +static const unsigned char table[] = { -1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +}; + +static unsigned long long ffintscan(FFFILE *f, unsigned base, int pok, unsigned long long lim) +{ + const unsigned char *val = table+1; + int c, neg=0; + unsigned x; + unsigned long long y; + if (base > 36 || base == 1) { + errno = EINVAL; + return 0; + } + while (av_isspace((c=shgetc(f)))); + if (c=='+' || c=='-') { + neg = -(c=='-'); + c = shgetc(f); + } + if ((base == 0 || base == 16) && c=='0') { + c = shgetc(f); + if ((c|32)=='x') { + c = shgetc(f); + if (val[c]>=16) { + shunget(f); + if (pok) shunget(f); + else shlim(f, 0); + return 0; + } + base = 16; + } else if (base == 0) { + base = 8; + } + } else { + if (base == 0) base = 10; + if (val[c] >= base) { + shunget(f); + shlim(f, 0); + errno = EINVAL; + return 0; + } + } + if (base == 10) { + for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f)) + x = x*10 + (c-'0'); + for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f)) + y = y*10 + (c-'0'); + if (c-'0'>=10U) goto done; + } else if (!(base & base-1)) { + int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7]; + for (x=0; val[c]>bs; c=shgetc(f)) + y = y<=lim) { + if (!(lim&1) && !neg) { + errno = ERANGE; + return lim-1; + } else if (y>lim) { + errno = ERANGE; + return lim; + } + } + return (y^neg)-neg; +} + +static long long scanexp(FFFILE *f, int pok) +{ + int c; + int x; + long long y; + int neg = 0; + + c = shgetc(f); + if (c=='+' || c=='-') { + neg = (c=='-'); + c = shgetc(f); + if (c-'0'>=10U && pok) shunget(f); + } + if (c-'0'>=10U) { + shunget(f); + return LLONG_MIN; + } + for (x=0; c-'0'<10U && x=0) { + shunget(f); + } + if (!gotdig) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + + /* Handle zero specially to avoid nasty special cases later */ + if (!x[0]) return sign * 0.0; + + /* Optimize small integers (w/no exponent) and over/under-flow */ + if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0)) + return sign * (double)x[0]; + if (lrp > -emin/2) { + errno = ERANGE; + return sign * DBL_MAX * DBL_MAX; + } + if (lrp < emin-2*DBL_MANT_DIG) { + errno = ERANGE; + return sign * DBL_MIN * DBL_MIN; + } + + /* Align incomplete final B1B digit */ + if (j) { + for (; j<9; j++) x[k]*=10; + k++; + j=0; + } + + a = 0; + z = k; + e2 = 0; + rp = lrp; + + /* Optimize small to mid-size integers (even in exp. notation) */ + if (lnz<9 && lnz<=rp && rp < 18) { + int bitlim; + if (rp == 9) return sign * (double)x[0]; + if (rp < 9) return sign * (double)x[0] / p10s[8-rp]; + bitlim = bits-3*(int)(rp-9); + if (bitlim>30 || x[0]>>bitlim==0) + return sign * (double)x[0] * p10s[rp-10]; + } + + /* Drop trailing zeros */ + for (; !x[z-1]; z--); + + /* Align radix point to B1B digit boundary */ + if (rp % 9) { + int rpm9 = rp>=0 ? rp%9 : rp%9+9; + int p10 = p10s[8-rpm9]; + uint32_t carry = 0; + for (k=a; k!=z; k++) { + uint32_t tmp = x[k] % p10; + x[k] = x[k]/p10 + carry; + carry = 1000000000/p10 * tmp; + if (k==a && !x[k]) { + a = (a+1 & MASK); + rp -= 9; + } + } + if (carry) x[z++] = carry; + rp += 9-rpm9; + } + + /* Upscale until desired number of bits are left of radix point */ + while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a] 1000000000) { + carry = tmp / 1000000000; + x[k] = tmp % 1000000000; + } else { + carry = 0; + x[k] = tmp; + } + if (k==(z-1 & MASK) && k!=a && !x[k]) z = k; + if (k==a) break; + } + if (carry) { + rp += 9; + a = (a-1 & MASK); + if (a == z) { + z = (z-1 & MASK); + x[z-1 & MASK] |= x[z]; + } + x[a] = carry; + } + } + + /* Downscale until exactly number of bits are left of radix point */ + for (;;) { + uint32_t carry = 0; + int sh = 1; + for (i=0; i th[i]) break; + } + if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break; + /* FIXME: find a way to compute optimal sh */ + if (rp > 9+9*LD_B1B_DIG) sh = 9; + e2 += sh; + for (k=a; k!=z; k=(k+1 & MASK)) { + uint32_t tmp = x[k] & (1<>sh) + carry; + carry = (1000000000>>sh) * tmp; + if (k==a && !x[k]) { + a = (a+1 & MASK); + i--; + rp -= 9; + } + } + if (carry) { + if ((z+1 & MASK) != a) { + x[z] = carry; + z = (z+1 & MASK); + } else x[z-1 & MASK] |= 1; + } + } + + /* Assemble desired bits into floating point variable */ + for (y=i=0; i DBL_MANT_DIG+e2-emin) { + bits = DBL_MANT_DIG+e2-emin; + if (bits<0) bits=0; + denormal = 1; + } + + /* Calculate bias term to force rounding, move out lower bits */ + if (bits < DBL_MANT_DIG) { + bias = copysign(scalbn(1, 2*DBL_MANT_DIG-bits-1), y); + frac = fmod(y, scalbn(1, DBL_MANT_DIG-bits)); + y -= frac; + y += bias; + } + + /* Process tail of decimal input so it can affect rounding */ + if ((a+i & MASK) != z) { + uint32_t t = x[a+i & MASK]; + if (t < 500000000 && (t || (a+i+1 & MASK) != z)) + frac += 0.25*sign; + else if (t > 500000000) + frac += 0.75*sign; + else if (t == 500000000) { + if ((a+i+1 & MASK) == z) + frac += 0.5*sign; + else + frac += 0.75*sign; + } + if (DBL_MANT_DIG-bits >= 2 && !fmod(frac, 1)) + frac++; + } + + y += frac; + y -= bias; + + if ((e2+DBL_MANT_DIG & INT_MAX) > emax-5) { + if (fabs(y) >= pow(2, DBL_MANT_DIG)) { + if (denormal && bits==DBL_MANT_DIG+e2-emin) + denormal = 0; + y *= 0.5; + e2++; + } + if (e2+DBL_MANT_DIG>emax || (denormal && frac)) + errno = ERANGE; + } + + return scalbn(y, e2); +} + +static double hexfloat(FFFILE *f, int bits, int emin, int sign, int pok) +{ + uint32_t x = 0; + double y = 0; + double scale = 1; + double bias = 0; + int gottail = 0, gotrad = 0, gotdig = 0; + long long rp = 0; + long long dc = 0; + long long e2 = 0; + int d; + int c; + + c = shgetc(f); + + /* Skip leading zeros */ + for (; c=='0'; c = shgetc(f)) + gotdig = 1; + + if (c=='.') { + gotrad = 1; + c = shgetc(f); + /* Count zeros after the radix point before significand */ + for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1; + } + + for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) { + if (c=='.') { + if (gotrad) break; + rp = dc; + gotrad = 1; + } else { + gotdig = 1; + if (c > '9') d = (c|32)+10-'a'; + else d = c-'0'; + if (dc<8) { + x = x*16 + d; + } else if (dc < DBL_MANT_DIG/4+1) { + y += d*(scale/=16); + } else if (d && !gottail) { + y += 0.5*scale; + gottail = 1; + } + dc++; + } + } + if (!gotdig) { + shunget(f); + if (pok) { + shunget(f); + if (gotrad) shunget(f); + } else { + shlim(f, 0); + } + return sign * 0.0; + } + if (!gotrad) rp = dc; + while (dc<8) x *= 16, dc++; + if ((c|32)=='p') { + e2 = scanexp(f, pok); + if (e2 == LLONG_MIN) { + if (pok) { + shunget(f); + } else { + shlim(f, 0); + return 0; + } + e2 = 0; + } + } else { + shunget(f); + } + e2 += 4*rp - 32; + + if (!x) return sign * 0.0; + if (e2 > -emin) { + errno = ERANGE; + return sign * DBL_MAX * DBL_MAX; + } + if (e2 < emin-2*DBL_MANT_DIG) { + errno = ERANGE; + return sign * DBL_MIN * DBL_MIN; + } + + while (x < 0x80000000) { + if (y>=0.5) { + x += x + 1; + y += y - 1; + } else { + x += x; + y += y; + } + e2--; + } + + if (bits > 32+e2-emin) { + bits = 32+e2-emin; + if (bits<0) bits=0; + } + + if (bits < DBL_MANT_DIG) + bias = copysign(scalbn(1, 32+DBL_MANT_DIG-bits-1), sign); + + if (bits<32 && y && !(x&1)) x++, y=0; + + y = bias + sign*(double)x + sign*y; + y -= bias; + + if (!y) errno = ERANGE; + + return scalbn(y, e2); +} + +static double fffloatscan(FFFILE *f, int prec, int pok) +{ + int sign = 1; + size_t i; + int bits; + int emin; + int c; + + switch (prec) { + case 0: + bits = FLT_MANT_DIG; + emin = FLT_MIN_EXP-bits; + break; + case 1: + bits = DBL_MANT_DIG; + emin = DBL_MIN_EXP-bits; + break; + case 2: + bits = DBL_MANT_DIG; + emin = DBL_MIN_EXP-bits; + break; + default: + return 0; + } + + while (av_isspace((c = shgetc(f)))); + + if (c=='+' || c=='-') { + sign -= 2*(c=='-'); + c = shgetc(f); + } + + for (i=0; i<8 && (c|32)=="infinity"[i]; i++) + if (i<7) c = shgetc(f); + if (i==3 || i==8 || (i>3 && pok)) { + if (i!=8) { + shunget(f); + if (pok) for (; i>3; i--) shunget(f); + } + return sign * INFINITY; + } + if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++) + if (i<2) c = shgetc(f); + if (i==3) { + if (shgetc(f) != '(') { + shunget(f); + return NAN; + } + for (i=1; ; i++) { + c = shgetc(f); + if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_') + continue; + if (c==')') return NAN; + shunget(f); + if (!pok) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + while (i--) shunget(f); + return NAN; + } + return NAN; + } + + if (i) { + shunget(f); + errno = EINVAL; + shlim(f, 0); + return 0; + } + + if (c=='0') { + c = shgetc(f); + if ((c|32) == 'x') + return hexfloat(f, bits, emin, sign, pok); + shunget(f); + c = '0'; + } + + return decfloat(f, c, bits, emin, sign, pok); +} + +static void *arg_n(va_list ap, unsigned int n) +{ + void *p; + unsigned int i; + va_list ap2; + va_copy(ap2, ap); + for (i=n; i>1; i--) va_arg(ap2, void *); + p = va_arg(ap2, void *); + va_end(ap2); + return p; +} + +static void store_int(void *dest, int size, unsigned long long i) +{ + if (!dest) return; + switch (size) { + case SIZE_hh: + *(char *)dest = i; + break; + case SIZE_h: + *(short *)dest = i; + break; + case SIZE_def: + *(int *)dest = i; + break; + case SIZE_l: + *(long *)dest = i; + break; + case SIZE_ll: + *(long long *)dest = i; + break; + } +} + +static int ff_vfscanf(FFFILE *f, const char *fmt, va_list ap) +{ + int width; + int size; + int base; + const unsigned char *p; + int c, t; + char *s; + void *dest=NULL; + int invert; + int matches=0; + unsigned long long x; + double y; + ptrdiff_t pos = 0; + unsigned char scanset[257]; + size_t i; + + for (p=(const unsigned char *)fmt; *p; p++) { + + if (av_isspace(*p)) { + while (av_isspace(p[1])) p++; + shlim(f, 0); + while (av_isspace(shgetc(f))); + shunget(f); + pos += shcnt(f); + continue; + } + if (*p != '%' || p[1] == '%') { + shlim(f, 0); + if (*p == '%') { + p++; + while (av_isspace((c=shgetc(f)))); + } else { + c = shgetc(f); + } + if (c!=*p) { + shunget(f); + if (c<0) goto input_fail; + goto match_fail; + } + pos += shcnt(f); + continue; + } + + p++; + if (*p=='*') { + dest = 0; p++; + } else if (av_isdigit(*p) && p[1]=='$') { + dest = arg_n(ap, *p-'0'); p+=2; + } else { + dest = va_arg(ap, void *); + } + + for (width=0; av_isdigit(*p); p++) { + width = 10*width + *p - '0'; + } + + if (*p=='m') { + s = 0; + p++; + } + + size = SIZE_def; + switch (*p++) { + case 'h': + if (*p == 'h') p++, size = SIZE_hh; + else size = SIZE_h; + break; + case 'l': + if (*p == 'l') p++, size = SIZE_ll; + else size = SIZE_l; + break; + case 'j': + size = SIZE_ll; + break; + case 'z': + case 't': + size = SIZE_l; + break; + case 'L': + size = SIZE_L; + break; + case 'd': case 'i': case 'o': case 'u': case 'x': + case 'a': case 'e': case 'f': case 'g': + case 'A': case 'E': case 'F': case 'G': case 'X': + case 's': case 'c': case '[': + case 'S': case 'C': + case 'p': case 'n': + p--; + break; + default: + goto fmt_fail; + } + + t = *p; + + /* C or S */ + if ((t&0x2f) == 3) { + t |= 32; + size = SIZE_l; + } + + switch (t) { + case 'c': + if (width < 1) width = 1; + case '[': + break; + case 'n': + store_int(dest, size, pos); + /* do not increment match count, etc! */ + continue; + default: + shlim(f, 0); + while (av_isspace(shgetc(f))); + shunget(f); + pos += shcnt(f); + } + + shlim(f, width); + if (shgetc(f) < 0) goto input_fail; + shunget(f); + + switch (t) { + case 's': + case 'c': + case '[': + if (t == 'c' || t == 's') { + memset(scanset, -1, sizeof scanset); + scanset[0] = 0; + if (t == 's') { + scanset[1 + '\t'] = 0; + scanset[1 + '\n'] = 0; + scanset[1 + '\v'] = 0; + scanset[1 + '\f'] = 0; + scanset[1 + '\r'] = 0; + scanset[1 + ' ' ] = 0; + } + } else { + if (*++p == '^') p++, invert = 1; + else invert = 0; + memset(scanset, invert, sizeof scanset); + scanset[0] = 0; + if (*p == '-') p++, scanset[1+'-'] = 1-invert; + else if (*p == ']') p++, scanset[1+']'] = 1-invert; + for (; *p != ']'; p++) { + if (!*p) goto fmt_fail; + if (*p=='-' && p[1] && p[1] != ']') + for (c=p++[-1]; c<*p; c++) + scanset[1+c] = 1-invert; + scanset[1+*p] = 1-invert; + } + } + s = 0; + i = 0; + if ((s = dest)) { + while (scanset[(c=shgetc(f))+1]) + s[i++] = c; + } else { + while (scanset[(c=shgetc(f))+1]); + } + shunget(f); + if (!shcnt(f)) goto match_fail; + if (t == 'c' && shcnt(f) != width) goto match_fail; + if (t != 'c') { + if (s) s[i] = 0; + } + break; + case 'p': + case 'X': + case 'x': + base = 16; + goto int_common; + case 'o': + base = 8; + goto int_common; + case 'd': + case 'u': + base = 10; + goto int_common; + case 'i': + base = 0; +int_common: + x = ffintscan(f, base, 0, ULLONG_MAX); + if (!shcnt(f)) + goto match_fail; + if (t=='p' && dest) + *(void **)dest = (void *)(uintptr_t)x; + else + store_int(dest, size, x); + break; + case 'a': case 'A': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + y = fffloatscan(f, size, 0); + if (!shcnt(f)) + goto match_fail; + if (dest) { + switch (size) { + case SIZE_def: + *(float *)dest = y; + break; + case SIZE_l: + *(double *)dest = y; + break; + case SIZE_L: + *(double *)dest = y; + break; + } + } + break; + } + + pos += shcnt(f); + if (dest) matches++; + } + if (0) { +fmt_fail: +input_fail: + if (!matches) matches--; + } +match_fail: + return matches; +} + +static int ff_vsscanf(const char *s, const char *fmt, va_list ap) +{ + FFFILE f = { + .buf = (void *)s, .cookie = (void *)s, + .read = ffstring_read, + }; + + return ff_vfscanf(&f, fmt, ap); +} + +int av_sscanf(const char *string, const char *format, ...) +{ + int ret; + va_list ap; + va_start(ap, format); + ret = ff_vsscanf(string, format, ap); + va_end(ap); + return ret; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avstring.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avstring.c new file mode 100644 index 0000000000..4c068f5bc5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avstring.c @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * Copyright (c) 2007 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "mem.h" +#include "avassert.h" +#include "avstring.h" +#include "bprint.h" + +int av_strstart(const char *str, const char *pfx, const char **ptr) +{ + while (*pfx && *pfx == *str) { + pfx++; + str++; + } + if (!*pfx && ptr) + *ptr = str; + return !*pfx; +} + +int av_stristart(const char *str, const char *pfx, const char **ptr) +{ + while (*pfx && av_toupper((unsigned)*pfx) == av_toupper((unsigned)*str)) { + pfx++; + str++; + } + if (!*pfx && ptr) + *ptr = str; + return !*pfx; +} + +char *av_stristr(const char *s1, const char *s2) +{ + if (!*s2) + return (char*)(intptr_t)s1; + + do + if (av_stristart(s1, s2, NULL)) + return (char*)(intptr_t)s1; + while (*s1++); + + return NULL; +} + +char *av_strnstr(const char *haystack, const char *needle, size_t hay_length) +{ + size_t needle_len = strlen(needle); + if (!needle_len) + return (char*)haystack; + while (hay_length >= needle_len) { + hay_length--; + if (!memcmp(haystack, needle, needle_len)) + return (char*)haystack; + haystack++; + } + return NULL; +} + +size_t av_strlcpy(char *dst, const char *src, size_t size) +{ + size_t len = 0; + while (++len < size && *src) + *dst++ = *src++; + if (len <= size) + *dst = 0; + return len + strlen(src) - 1; +} + +size_t av_strlcat(char *dst, const char *src, size_t size) +{ + size_t len = strlen(dst); + if (size <= len + 1) + return len + strlen(src); + return len + av_strlcpy(dst + len, src, size - len); +} + +size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) +{ + size_t len = strlen(dst); + va_list vl; + + va_start(vl, fmt); + len += vsnprintf(dst + len, size > len ? size - len : 0, fmt, vl); + va_end(vl); + + return len; +} + +char *av_asprintf(const char *fmt, ...) +{ + char *p = NULL; + va_list va; + int len; + + va_start(va, fmt); + len = vsnprintf(NULL, 0, fmt, va); + va_end(va); + if (len < 0) + goto end; + + p = av_malloc(len + 1); + if (!p) + goto end; + + va_start(va, fmt); + len = vsnprintf(p, len + 1, fmt, va); + va_end(va); + if (len < 0) + av_freep(&p); + +end: + return p; +} + +char *av_d2str(double d) +{ + char *str = av_malloc(16); + if (str) + snprintf(str, 16, "%f", d); + return str; +} + +#define WHITESPACES " \n\t\r" + +char *av_get_token(const char **buf, const char *term) +{ + char *out = av_malloc(strlen(*buf) + 1); + char *ret = out, *end = out; + const char *p = *buf; + if (!out) + return NULL; + p += strspn(p, WHITESPACES); + + while (*p && !strspn(p, term)) { + char c = *p++; + if (c == '\\' && *p) { + *out++ = *p++; + end = out; + } else if (c == '\'') { + while (*p && *p != '\'') + *out++ = *p++; + if (*p) { + p++; + end = out; + } + } else { + *out++ = c; + } + } + + do + *out-- = 0; + while (out >= end && strspn(out, WHITESPACES)); + + *buf = p; + + return ret; +} + +char *av_strtok(char *s, const char *delim, char **saveptr) +{ + char *tok; + + if (!s && !(s = *saveptr)) + return NULL; + + /* skip leading delimiters */ + s += strspn(s, delim); + + /* s now points to the first non delimiter char, or to the end of the string */ + if (!*s) { + *saveptr = NULL; + return NULL; + } + tok = s++; + + /* skip non delimiters */ + s += strcspn(s, delim); + if (*s) { + *s = 0; + *saveptr = s+1; + } else { + *saveptr = NULL; + } + + return tok; +} + +int av_strcasecmp(const char *a, const char *b) +{ + uint8_t c1, c2; + do { + c1 = av_tolower(*a++); + c2 = av_tolower(*b++); + } while (c1 && c1 == c2); + return c1 - c2; +} + +int av_strncasecmp(const char *a, const char *b, size_t n) +{ + uint8_t c1, c2; + if (n <= 0) + return 0; + do { + c1 = av_tolower(*a++); + c2 = av_tolower(*b++); + } while (--n && c1 && c1 == c2); + return c1 - c2; +} + +char *av_strireplace(const char *str, const char *from, const char *to) +{ + char *ret = NULL; + const char *pstr2, *pstr = str; + size_t tolen = strlen(to), fromlen = strlen(from); + AVBPrint pbuf; + + av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); + while ((pstr2 = av_stristr(pstr, from))) { + av_bprint_append_data(&pbuf, pstr, pstr2 - pstr); + pstr = pstr2 + fromlen; + av_bprint_append_data(&pbuf, to, tolen); + } + av_bprint_append_data(&pbuf, pstr, strlen(pstr)); + if (!av_bprint_is_complete(&pbuf)) { + av_bprint_finalize(&pbuf, NULL); + } else { + av_bprint_finalize(&pbuf, &ret); + } + + return ret; +} + +const char *av_basename(const char *path) +{ + char *p = strrchr(path, '/'); + +#if HAVE_DOS_PATHS + char *q = strrchr(path, '\\'); + char *d = strchr(path, ':'); + + p = FFMAX3(p, q, d); +#endif + + if (!p) + return path; + + return p + 1; +} + +const char *av_dirname(char *path) +{ + char *p = strrchr(path, '/'); + +#if HAVE_DOS_PATHS + char *q = strrchr(path, '\\'); + char *d = strchr(path, ':'); + + d = d ? d + 1 : d; + + p = FFMAX3(p, q, d); +#endif + + if (!p) + return "."; + + *p = '\0'; + + return path; +} + +char *av_append_path_component(const char *path, const char *component) +{ + size_t p_len, c_len; + char *fullpath; + + if (!path) + return av_strdup(component); + if (!component) + return av_strdup(path); + + p_len = strlen(path); + c_len = strlen(component); + if (p_len > SIZE_MAX - c_len || p_len + c_len > SIZE_MAX - 2) + return NULL; + fullpath = av_malloc(p_len + c_len + 2); + if (fullpath) { + if (p_len) { + av_strlcpy(fullpath, path, p_len + 1); + if (c_len) { + if (fullpath[p_len - 1] != '/' && component[0] != '/') + fullpath[p_len++] = '/'; + else if (fullpath[p_len - 1] == '/' && component[0] == '/') + p_len--; + } + } + av_strlcpy(&fullpath[p_len], component, c_len + 1); + fullpath[p_len + c_len] = 0; + } + return fullpath; +} + +int av_escape(char **dst, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags) +{ + AVBPrint dstbuf; + + av_bprint_init(&dstbuf, 1, AV_BPRINT_SIZE_UNLIMITED); + av_bprint_escape(&dstbuf, src, special_chars, mode, flags); + + if (!av_bprint_is_complete(&dstbuf)) { + av_bprint_finalize(&dstbuf, NULL); + return AVERROR(ENOMEM); + } else { + av_bprint_finalize(&dstbuf, dst); + return dstbuf.len; + } +} + +int av_match_name(const char *name, const char *names) +{ + const char *p; + int len, namelen; + + if (!name || !names) + return 0; + + namelen = strlen(name); + while (*names) { + int negate = '-' == *names; + p = strchr(names, ','); + if (!p) + p = names + strlen(names); + names += negate; + len = FFMAX(p - names, namelen); + if (!av_strncasecmp(name, names, len) || !strncmp("ALL", names, FFMAX(3, p - names))) + return !negate; + names = p + (*p == ','); + } + return 0; +} + +int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, + unsigned int flags) +{ + const uint8_t *p = *bufp; + uint32_t top; + uint64_t code; + int ret = 0, tail_len; + uint32_t overlong_encoding_mins[6] = { + 0x00000000, 0x00000080, 0x00000800, 0x00010000, 0x00200000, 0x04000000, + }; + + if (p >= buf_end) + return 0; + + code = *p++; + + /* first sequence byte starts with 10, or is 1111-1110 or 1111-1111, + which is not admitted */ + if ((code & 0xc0) == 0x80 || code >= 0xFE) { + ret = AVERROR(EILSEQ); + goto end; + } + top = (code & 128) >> 1; + + tail_len = 0; + while (code & top) { + int tmp; + tail_len++; + if (p >= buf_end) { + (*bufp) ++; + return AVERROR(EILSEQ); /* incomplete sequence */ + } + + /* we assume the byte to be in the form 10xx-xxxx */ + tmp = *p++ - 128; /* strip leading 1 */ + if (tmp>>6) { + (*bufp) ++; + return AVERROR(EILSEQ); + } + code = (code<<6) + tmp; + top <<= 5; + } + code &= (top << 1) - 1; + + /* check for overlong encodings */ + av_assert0(tail_len <= 5); + if (code < overlong_encoding_mins[tail_len]) { + ret = AVERROR(EILSEQ); + goto end; + } + + if (code >= 1U<<31) { + ret = AVERROR(EILSEQ); /* out-of-range value */ + goto end; + } + + *codep = code; + + if (code > 0x10FFFF && + !(flags & AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES)) + ret = AVERROR(EILSEQ); + if (code < 0x20 && code != 0x9 && code != 0xA && code != 0xD && + flags & AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES) + ret = AVERROR(EILSEQ); + if (code >= 0xD800 && code <= 0xDFFF && + !(flags & AV_UTF8_FLAG_ACCEPT_SURROGATES)) + ret = AVERROR(EILSEQ); + if ((code == 0xFFFE || code == 0xFFFF) && + !(flags & AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS)) + ret = AVERROR(EILSEQ); + +end: + *bufp = p; + return ret; +} + +int av_match_list(const char *name, const char *list, char separator) +{ + const char *p, *q; + + for (p = name; p && *p; ) { + for (q = list; q && *q; ) { + int k; + for (k = 0; p[k] == q[k] || (p[k]*q[k] == 0 && p[k]+q[k] == separator); k++) + if (k && (!p[k] || p[k] == separator)) + return 1; + q = strchr(q, separator); + q += !!q; + } + p = strchr(p, separator); + p += !!p; + } + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avstring.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avstring.h new file mode 100644 index 0000000000..37dd4e2da0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avstring.h @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2007 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVSTRING_H +#define AVUTIL_AVSTRING_H + +#include +#include +#include "attributes.h" + +/** + * @addtogroup lavu_string + * @{ + */ + +/** + * Return non-zero if pfx is a prefix of str. If it is, *ptr is set to + * the address of the first character in str after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_strstart(const char *str, const char *pfx, const char **ptr); + +/** + * Return non-zero if pfx is a prefix of str independent of case. If + * it is, *ptr is set to the address of the first character in str + * after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_stristart(const char *str, const char *pfx, const char **ptr); + +/** + * Locate the first case-independent occurrence in the string haystack + * of the string needle. A zero-length string needle is considered to + * match at the start of haystack. + * + * This function is a case-insensitive version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_stristr(const char *haystack, const char *needle); + +/** + * Locate the first occurrence of the string needle in the string haystack + * where not more than hay_length characters are searched. A zero-length + * string needle is considered to match at the start of haystack. + * + * This function is a length-limited version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @param hay_length length of string to search in + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_strnstr(const char *haystack, const char *needle, size_t hay_length); + +/** + * Copy the string src to dst, but no more than size - 1 bytes, and + * null-terminate dst. + * + * This function is the same as BSD strlcpy(). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the length of src + * + * @warning since the return value is the length of src, src absolutely + * _must_ be a properly 0-terminated string, otherwise this will read beyond + * the end of the buffer and possibly crash. + */ +size_t av_strlcpy(char *dst, const char *src, size_t size); + +/** + * Append the string src to the string dst, but to a total length of + * no more than size - 1 bytes, and null-terminate dst. + * + * This function is similar to BSD strlcat(), but differs when + * size <= strlen(dst). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the total length of src and dst + * + * @warning since the return value use the length of src and dst, these + * absolutely _must_ be a properly 0-terminated strings, otherwise this + * will read beyond the end of the buffer and possibly crash. + */ +size_t av_strlcat(char *dst, const char *src, size_t size); + +/** + * Append output to a string, according to a format. Never write out of + * the destination buffer, and always put a terminating 0 within + * the buffer. + * @param dst destination buffer (string to which the output is + * appended) + * @param size total size of the destination buffer + * @param fmt printf-compatible format string, specifying how the + * following parameters are used + * @return the length of the string that would have been generated + * if enough space had been available + */ +size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) av_printf_format(3, 4); + +/** + * Get the count of continuous non zero chars starting from the beginning. + * + * @param len maximum number of characters to check in the string, that + * is the maximum value which is returned by the function + */ +static inline size_t av_strnlen(const char *s, size_t len) +{ + size_t i; + for (i = 0; i < len && s[i]; i++) + ; + return i; +} + +/** + * Print arguments following specified format into a large enough auto + * allocated buffer. It is similar to GNU asprintf(). + * @param fmt printf-compatible format string, specifying how the + * following parameters are used. + * @return the allocated string + * @note You have to free the string yourself with av_free(). + */ +char *av_asprintf(const char *fmt, ...) av_printf_format(1, 2); + +/** + * Convert a number to an av_malloced string. + */ +char *av_d2str(double d); + +/** + * Unescape the given string until a non escaped terminating char, + * and return the token corresponding to the unescaped string. + * + * The normal \ and ' escaping is supported. Leading and trailing + * whitespaces are removed, unless they are escaped with '\' or are + * enclosed between ''. + * + * @param buf the buffer to parse, buf will be updated to point to the + * terminating char + * @param term a 0-terminated list of terminating chars + * @return the malloced unescaped string, which must be av_freed by + * the user, NULL in case of allocation failure + */ +char *av_get_token(const char **buf, const char *term); + +/** + * Split the string into several tokens which can be accessed by + * successive calls to av_strtok(). + * + * A token is defined as a sequence of characters not belonging to the + * set specified in delim. + * + * On the first call to av_strtok(), s should point to the string to + * parse, and the value of saveptr is ignored. In subsequent calls, s + * should be NULL, and saveptr should be unchanged since the previous + * call. + * + * This function is similar to strtok_r() defined in POSIX.1. + * + * @param s the string to parse, may be NULL + * @param delim 0-terminated list of token delimiters, must be non-NULL + * @param saveptr user-provided pointer which points to stored + * information necessary for av_strtok() to continue scanning the same + * string. saveptr is updated to point to the next character after the + * first delimiter found, or to NULL if the string was terminated + * @return the found token, or NULL when no token is found + */ +char *av_strtok(char *s, const char *delim, char **saveptr); + +/** + * Locale-independent conversion of ASCII isdigit. + */ +static inline av_const int av_isdigit(int c) +{ + return c >= '0' && c <= '9'; +} + +/** + * Locale-independent conversion of ASCII isgraph. + */ +static inline av_const int av_isgraph(int c) +{ + return c > 32 && c < 127; +} + +/** + * Locale-independent conversion of ASCII isspace. + */ +static inline av_const int av_isspace(int c) +{ + return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || + c == '\v'; +} + +/** + * Locale-independent conversion of ASCII characters to uppercase. + */ +static inline av_const int av_toupper(int c) +{ + if (c >= 'a' && c <= 'z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII characters to lowercase. + */ +static inline av_const int av_tolower(int c) +{ + if (c >= 'A' && c <= 'Z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII isxdigit. + */ +static inline av_const int av_isxdigit(int c) +{ + c = av_tolower(c); + return av_isdigit(c) || (c >= 'a' && c <= 'f'); +} + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strcasecmp(const char *a, const char *b); + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strncasecmp(const char *a, const char *b, size_t n); + +/** + * Locale-independent strings replace. + * @note This means only ASCII-range characters are replace + */ +char *av_strireplace(const char *str, const char *from, const char *to); + +/** + * Thread safe basename. + * @param path the path, on DOS both \ and / are considered separators. + * @return pointer to the basename substring. + */ +const char *av_basename(const char *path); + +/** + * Thread safe dirname. + * @param path the path, on DOS both \ and / are considered separators. + * @return the path with the separator replaced by the string terminator or ".". + * @note the function may change the input string. + */ +const char *av_dirname(char *path); + +/** + * Match instances of a name in a comma-separated list of names. + * List entries are checked from the start to the end of the names list, + * the first match ends further processing. If an entry prefixed with '-' + * matches, then 0 is returned. The "ALL" list entry is considered to + * match all names. + * + * @param name Name to look for. + * @param names List of names. + * @return 1 on match, 0 otherwise. + */ +int av_match_name(const char *name, const char *names); + +/** + * Append path component to the existing path. + * Path separator '/' is placed between when needed. + * Resulting string have to be freed with av_free(). + * @param path base path + * @param component component to be appended + * @return new path or NULL on error. + */ +char *av_append_path_component(const char *path, const char *component); + +enum AVEscapeMode { + AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. + AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. + AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. +}; + +/** + * Consider spaces special and escape them even in the middle of the + * string. + * + * This is equivalent to adding the whitespace characters to the special + * characters lists, except it is guaranteed to use the exact same list + * of whitespace characters as the rest of libavutil. + */ +#define AV_ESCAPE_FLAG_WHITESPACE (1 << 0) + +/** + * Escape only specified special characters. + * Without this flag, escape also any characters that may be considered + * special by av_get_token(), such as the single quote. + */ +#define AV_ESCAPE_FLAG_STRICT (1 << 1) + +/** + * Escape string in src, and put the escaped string in an allocated + * string in *dst, which must be freed with av_free(). + * + * @param dst pointer where an allocated string is put + * @param src string to escape, must be non-NULL + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros + * @return the length of the allocated string, or a negative error code in case of error + * @see av_bprint_escape() + */ +av_warn_unused_result +int av_escape(char **dst, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#define AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES 1 ///< accept codepoints over 0x10FFFF +#define AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS 2 ///< accept non-characters - 0xFFFE and 0xFFFF +#define AV_UTF8_FLAG_ACCEPT_SURROGATES 4 ///< accept UTF-16 surrogates codes +#define AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES 8 ///< exclude control codes not accepted by XML + +#define AV_UTF8_FLAG_ACCEPT_ALL \ + AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES + +/** + * Read and decode a single UTF-8 code point (character) from the + * buffer in *buf, and update *buf to point to the next byte to + * decode. + * + * In case of an invalid byte sequence, the pointer will be updated to + * the next byte after the invalid sequence and the function will + * return an error code. + * + * Depending on the specified flags, the function will also fail in + * case the decoded code point does not belong to a valid range. + * + * @note For speed-relevant code a carefully implemented use of + * GET_UTF8() may be preferred. + * + * @param codep pointer used to return the parsed code in case of success. + * The value in *codep is set even in case the range check fails. + * @param bufp pointer to the address the first byte of the sequence + * to decode, updated by the function to point to the + * byte next after the decoded sequence + * @param buf_end pointer to the end of the buffer, points to the next + * byte past the last in the buffer. This is used to + * avoid buffer overreads (in case of an unfinished + * UTF-8 sequence towards the end of the buffer). + * @param flags a collection of AV_UTF8_FLAG_* flags + * @return >= 0 in case a sequence was successfully read, a negative + * value in case of invalid sequence + */ +av_warn_unused_result +int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, + unsigned int flags); + +/** + * Check if a name is in a list. + * @returns 0 if not found, or the 1 based index where it has been found in the + * list. + */ +int av_match_list(const char *name, const char *list, char separator); + +/** + * See libc sscanf manual for more information. + * Locale-independent sscanf implementation. + */ +int av_sscanf(const char *string, const char *format, ...); + +/** + * @} + */ + +#endif /* AVUTIL_AVSTRING_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avutil.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avutil.h new file mode 100644 index 0000000000..4d633156d1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/avutil.h @@ -0,0 +1,365 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVUTIL_H +#define AVUTIL_AVUTIL_H + +/** + * @file + * @ingroup lavu + * Convenience header that includes @ref lavu "libavutil"'s core. + */ + +/** + * @mainpage + * + * @section ffmpeg_intro Introduction + * + * This document describes the usage of the different libraries + * provided by FFmpeg. + * + * @li @ref libavc "libavcodec" encoding/decoding library + * @li @ref lavfi "libavfilter" graph-based frame editing library + * @li @ref libavf "libavformat" I/O and muxing/demuxing library + * @li @ref lavd "libavdevice" special devices muxing/demuxing library + * @li @ref lavu "libavutil" common utility library + * @li @ref lswr "libswresample" audio resampling, format conversion and mixing + * @li @ref lpp "libpostproc" post processing library + * @li @ref libsws "libswscale" color conversion and scaling library + * + * @section ffmpeg_versioning Versioning and compatibility + * + * Each of the FFmpeg libraries contains a version.h header, which defines a + * major, minor and micro version number with the + * LIBRARYNAME_VERSION_{MAJOR,MINOR,MICRO} macros. The major version + * number is incremented with backward incompatible changes - e.g. removing + * parts of the public API, reordering public struct members, etc. The minor + * version number is incremented for backward compatible API changes or major + * new features - e.g. adding a new public function or a new decoder. The micro + * version number is incremented for smaller changes that a calling program + * might still want to check for - e.g. changing behavior in a previously + * unspecified situation. + * + * FFmpeg guarantees backward API and ABI compatibility for each library as long + * as its major version number is unchanged. This means that no public symbols + * will be removed or renamed. Types and names of the public struct members and + * values of public macros and enums will remain the same (unless they were + * explicitly declared as not part of the public API). Documented behavior will + * not change. + * + * In other words, any correct program that works with a given FFmpeg snapshot + * should work just as well without any changes with any later snapshot with the + * same major versions. This applies to both rebuilding the program against new + * FFmpeg versions or to replacing the dynamic FFmpeg libraries that a program + * links against. + * + * However, new public symbols may be added and new members may be appended to + * public structs whose size is not part of public ABI (most public structs in + * FFmpeg). New macros and enum values may be added. Behavior in undocumented + * situations may change slightly (and be documented). All those are accompanied + * by an entry in doc/APIchanges and incrementing either the minor or micro + * version number. + */ + +/** + * @defgroup lavu libavutil + * Common code shared across all FFmpeg libraries. + * + * @note + * libavutil is designed to be modular. In most cases, in order to use the + * functions provided by one component of libavutil you must explicitly include + * the specific header containing that feature. If you are only using + * media-related components, you could simply include libavutil/avutil.h, which + * brings in most of the "core" components. + * + * @{ + * + * @defgroup lavu_crypto Crypto and Hashing + * + * @{ + * @} + * + * @defgroup lavu_math Mathematics + * @{ + * + * @} + * + * @defgroup lavu_string String Manipulation + * + * @{ + * + * @} + * + * @defgroup lavu_mem Memory Management + * + * @{ + * + * @} + * + * @defgroup lavu_data Data Structures + * @{ + * + * @} + * + * @defgroup lavu_video Video related + * + * @{ + * + * @} + * + * @defgroup lavu_audio Audio related + * + * @{ + * + * @} + * + * @defgroup lavu_error Error Codes + * + * @{ + * + * @} + * + * @defgroup lavu_log Logging Facility + * + * @{ + * + * @} + * + * @defgroup lavu_misc Other + * + * @{ + * + * @defgroup preproc_misc Preprocessor String Macros + * + * @{ + * + * @} + * + * @defgroup version_utils Library Version Macros + * + * @{ + * + * @} + */ + + +/** + * @addtogroup lavu_ver + * @{ + */ + +/** + * Return the LIBAVUTIL_VERSION_INT constant. + */ +unsigned avutil_version(void); + +/** + * Return an informative version string. This usually is the actual release + * version number or a git commit description. This string has no fixed format + * and can change any time. It should never be parsed by code. + */ +const char *av_version_info(void); + +/** + * Return the libavutil build-time configuration. + */ +const char *avutil_configuration(void); + +/** + * Return the libavutil license. + */ +const char *avutil_license(void); + +/** + * @} + */ + +/** + * @addtogroup lavu_media Media Type + * @brief Media Type + */ + +enum AVMediaType { + AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA + AVMEDIA_TYPE_VIDEO, + AVMEDIA_TYPE_AUDIO, + AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous + AVMEDIA_TYPE_SUBTITLE, + AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse + AVMEDIA_TYPE_NB +}; + +/** + * Return a string describing the media_type enum, NULL if media_type + * is unknown. + */ +const char *av_get_media_type_string(enum AVMediaType media_type); + +/** + * @defgroup lavu_const Constants + * @{ + * + * @defgroup lavu_enc Encoding specific + * + * @note those definition should move to avcodec + * @{ + */ + +#define FF_LAMBDA_SHIFT 7 +#define FF_LAMBDA_SCALE (1< +#include "libavutil/version.h" +#include "libavutil/ffversion.h" +#include "config.h" + +1 VERSIONINFO +FILEVERSION LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO, 0 +PRODUCTVERSION LIBAVUTIL_VERSION_MAJOR, LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO, 0 +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_DLL +{ + BLOCK "StringFileInfo" + { + BLOCK "040904B0" + { + VALUE "CompanyName", "FFmpeg Project" + VALUE "FileDescription", "FFmpeg utility library" + VALUE "FileVersion", AV_STRINGIFY(LIBAVUTIL_VERSION) + VALUE "InternalName", "libavutil" + VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project" + VALUE "OriginalFilename", "avutil" BUILDSUF "-" AV_STRINGIFY(LIBAVUTIL_VERSION_MAJOR) SLIBSUF + VALUE "ProductName", "FFmpeg" + VALUE "ProductVersion", FFMPEG_VERSION + } + } + + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 0x04B0 + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/base64.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/base64.c new file mode 100644 index 0000000000..25ae8c411c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/base64.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief Base64 encode/decode + * @author Ryan Martell (with lots of Michael) + */ + +#include "common.h" +#include "base64.h" +#include "intreadwrite.h" +#include "timer.h" + +/* ---------------- private code */ +static const uint8_t map2[256] = +{ + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, + + 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, + 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + + 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +#define BASE64_DEC_STEP(i) do { \ + bits = map2[in[i]]; \ + if (bits & 0x80) \ + goto out ## i; \ + v = i ? (v << 6) + bits : bits; \ +} while(0) + +int av_base64_decode(uint8_t *out, const char *in_str, int out_size) +{ + uint8_t *dst = out; + uint8_t *end = out + out_size; + // no sign extension + const uint8_t *in = in_str; + unsigned bits = 0xff; + unsigned v; + + while (end - dst > 3) { + BASE64_DEC_STEP(0); + BASE64_DEC_STEP(1); + BASE64_DEC_STEP(2); + BASE64_DEC_STEP(3); + // Using AV_WB32 directly confuses compiler + v = av_be2ne32(v << 8); + AV_WN32(dst, v); + dst += 3; + in += 4; + } + if (end - dst) { + BASE64_DEC_STEP(0); + BASE64_DEC_STEP(1); + BASE64_DEC_STEP(2); + BASE64_DEC_STEP(3); + *dst++ = v >> 16; + if (end - dst) + *dst++ = v >> 8; + if (end - dst) + *dst++ = v; + in += 4; + } + while (1) { + BASE64_DEC_STEP(0); + in++; + BASE64_DEC_STEP(0); + in++; + BASE64_DEC_STEP(0); + in++; + BASE64_DEC_STEP(0); + in++; + } + +out3: + *dst++ = v >> 10; + v <<= 2; +out2: + *dst++ = v >> 4; +out1: +out0: + return bits & 1 ? AVERROR_INVALIDDATA : dst - out; +} + +/***************************************************************************** +* b64_encode: Stolen from VLC's http.c. +* Simplified by Michael. +* Fixed edge cases and made it work from data (vs. strings) by Ryan. +*****************************************************************************/ + +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size) +{ + static const char b64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + char *ret, *dst; + unsigned i_bits = 0; + int i_shift = 0; + int bytes_remaining = in_size; + + if (in_size >= UINT_MAX / 4 || + out_size < AV_BASE64_SIZE(in_size)) + return NULL; + ret = dst = out; + while (bytes_remaining > 3) { + i_bits = AV_RB32(in); + in += 3; bytes_remaining -= 3; + *dst++ = b64[ i_bits>>26 ]; + *dst++ = b64[(i_bits>>20) & 0x3F]; + *dst++ = b64[(i_bits>>14) & 0x3F]; + *dst++ = b64[(i_bits>>8 ) & 0x3F]; + } + i_bits = 0; + while (bytes_remaining) { + i_bits = (i_bits << 8) + *in++; + bytes_remaining--; + i_shift += 8; + } + while (i_shift > 0) { + *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f]; + i_shift -= 6; + } + while ((dst - ret) & 3) + *dst++ = '='; + *dst = '\0'; + + return ret; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/base64.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/base64.h new file mode 100644 index 0000000000..2954c12d42 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/base64.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BASE64_H +#define AVUTIL_BASE64_H + +#include + +/** + * @defgroup lavu_base64 Base64 + * @ingroup lavu_crypto + * @{ + */ + +/** + * Decode a base64-encoded string. + * + * @param out buffer for decoded data + * @param in null-terminated input string + * @param out_size size in bytes of the out buffer, must be at + * least 3/4 of the length of in, that is AV_BASE64_DECODE_SIZE(strlen(in)) + * @return number of bytes written, or a negative value in case of + * invalid input + */ +int av_base64_decode(uint8_t *out, const char *in, int out_size); + +/** + * Calculate the output size in bytes needed to decode a base64 string + * with length x to a data buffer. + */ +#define AV_BASE64_DECODE_SIZE(x) ((x) * 3LL / 4) + +/** + * Encode data to base64 and null-terminate. + * + * @param out buffer for encoded data + * @param out_size size in bytes of the out buffer (including the + * null terminator), must be at least AV_BASE64_SIZE(in_size) + * @param in input buffer containing the data to encode + * @param in_size size in bytes of the in buffer + * @return out or NULL in case of error + */ +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size); + +/** + * Calculate the output size needed to base64-encode x bytes to a + * null-terminated string. + */ +#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) + + /** + * @} + */ + +#endif /* AVUTIL_BASE64_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/blowfish.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/blowfish.c new file mode 100644 index 0000000000..abc0e03d4d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/blowfish.c @@ -0,0 +1,424 @@ +/* + * Blowfish algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * loosely based on Paul Kocher's implementation + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avutil.h" +#include "common.h" +#include "intreadwrite.h" +#include "mem.h" +#include "blowfish.h" + +static const uint32_t orig_p[AV_BF_ROUNDS + 2] = { + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, + 0x9216D5D9, 0x8979FB1B +}; + +static const uint32_t orig_s[4][256] = { + { 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, + 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, + 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, + 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, + 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, + 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, + 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, + 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, + 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, + 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, + 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, + 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, + 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, + 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, + 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, + 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, + 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, + 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, + 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, + 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, + 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, + 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, + 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, + 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, + 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, + 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, + 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, + 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, + 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, + 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, + 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, + 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, + 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, + 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, + 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, + 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, + 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, + 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, + 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, + 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, + 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, + 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, + 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A }, + { 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, + 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, + 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, + 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, + 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, + 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, + 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, + 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, + 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, + 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, + 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, + 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, + 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, + 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, + 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, + 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, + 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, + 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, + 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, + 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, + 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, + 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, + 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, + 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, + 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, + 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, + 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, + 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, + 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, + 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, + 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, + 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, + 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, + 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, + 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, + 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, + 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, + 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, + 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, + 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, + 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, + 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, + 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 }, + { 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, + 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, + 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, + 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, + 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, + 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, + 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, + 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, + 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, + 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, + 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, + 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, + 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, + 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, + 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, + 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, + 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, + 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, + 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, + 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, + 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, + 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, + 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, + 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, + 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, + 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, + 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, + 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, + 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, + 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, + 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, + 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, + 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, + 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, + 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, + 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, + 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, + 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, + 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, + 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, + 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, + 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, + 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 }, + { 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, + 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, + 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, + 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, + 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, + 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, + 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, + 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, + 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, + 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, + 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, + 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, + 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, + 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, + 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, + 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, + 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, + 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, + 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, + 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, + 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, + 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, + 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, + 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, + 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, + 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, + 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, + 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, + 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, + 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, + 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, + 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, + 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, + 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, + 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, + 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, + 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, + 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, + 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, + 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, + 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, + 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, + 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 } +}; + +#define F(Xl, Xr, P) \ + Xr ^=((( ctx->s[0][ Xl >> 24 ] \ + + ctx->s[1][(Xl >> 16) & 0xFF])\ + ^ ctx->s[2][(Xl >> 8) & 0xFF])\ + + ctx->s[3][ Xl & 0xFF])\ + ^ P; + +AVBlowfish *av_blowfish_alloc(void) +{ + return av_mallocz(sizeof(struct AVBlowfish)); +} + +av_cold void av_blowfish_init(AVBlowfish *ctx, const uint8_t *key, int key_len) +{ + uint32_t data, data_l, data_r; + int i, j, k; + + memcpy(ctx->s, orig_s, sizeof(orig_s)); + + j = 0; + for (i = 0; i < AV_BF_ROUNDS + 2; ++i) { + data = 0; + for (k = 0; k < 4; k++) { + data = (data << 8) | key[j]; + if (++j >= key_len) + j = 0; + } + ctx->p[i] = orig_p[i] ^ data; + } + + data_l = data_r = 0; + + for (i = 0; i < AV_BF_ROUNDS + 2; i += 2) { + av_blowfish_crypt_ecb(ctx, &data_l, &data_r, 0); + ctx->p[i] = data_l; + ctx->p[i + 1] = data_r; + } + + for (i = 0; i < 4; ++i) { + for (j = 0; j < 256; j += 2) { + av_blowfish_crypt_ecb(ctx, &data_l, &data_r, 0); + ctx->s[i][j] = data_l; + ctx->s[i][j + 1] = data_r; + } + } +} + +void av_blowfish_crypt_ecb(AVBlowfish *ctx, uint32_t *xl, uint32_t *xr, + int decrypt) +{ + uint32_t Xl, Xr; + int i; + + Xl = *xl; + Xr = *xr; + + if (decrypt) { + Xl ^= ctx->p[AV_BF_ROUNDS + 1]; + for (i = AV_BF_ROUNDS; i > 0; i-=2) { + F(Xl, Xr, ctx->p[i ]); + F(Xr, Xl, ctx->p[i-1]); + } + + Xr ^= ctx->p[0]; + } else { + Xl ^= ctx->p[0]; + for (i = 1; i < AV_BF_ROUNDS+1; i+=2){ + F(Xl, Xr, ctx->p[i ]); + F(Xr, Xl, ctx->p[i+1]); + } + + Xr ^= ctx->p[AV_BF_ROUNDS + 1]; + } + + *xl = Xr; + *xr = Xl; +} + +void av_blowfish_crypt(AVBlowfish *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt) +{ + uint32_t v0, v1; + int i; + + if (decrypt) { + while (count--) { + v0 = AV_RB32(src); + v1 = AV_RB32(src + 4); + + av_blowfish_crypt_ecb(ctx, &v0, &v1, decrypt); + + if (iv) { + v0 ^= AV_RB32(iv); + v1 ^= AV_RB32(iv + 4); + memcpy(iv, src, 8); + } + + AV_WB32(dst, v0); + AV_WB32(dst + 4, v1); + + src += 8; + dst += 8; + } + } else { + while (count--) { + if (iv) { + for (i = 0; i < 8; i++) + dst[i] = src[i] ^ iv[i]; + v0 = AV_RB32(dst); + v1 = AV_RB32(dst + 4); + } else { + v0 = AV_RB32(src); + v1 = AV_RB32(src + 4); + } + + av_blowfish_crypt_ecb(ctx, &v0, &v1, decrypt); + + AV_WB32(dst, v0); + AV_WB32(dst + 4, v1); + + if (iv) + memcpy(iv, dst, 8); + + src += 8; + dst += 8; + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/blowfish.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/blowfish.h new file mode 100644 index 0000000000..9e289a40da --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/blowfish.h @@ -0,0 +1,82 @@ +/* + * Blowfish algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BLOWFISH_H +#define AVUTIL_BLOWFISH_H + +#include + +/** + * @defgroup lavu_blowfish Blowfish + * @ingroup lavu_crypto + * @{ + */ + +#define AV_BF_ROUNDS 16 + +typedef struct AVBlowfish { + uint32_t p[AV_BF_ROUNDS + 2]; + uint32_t s[4][256]; +} AVBlowfish; + +/** + * Allocate an AVBlowfish context. + */ +AVBlowfish *av_blowfish_alloc(void); + +/** + * Initialize an AVBlowfish context. + * + * @param ctx an AVBlowfish context + * @param key a key + * @param key_len length of the key + */ +void av_blowfish_init(struct AVBlowfish *ctx, const uint8_t *key, int key_len); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param xl left four bytes halves of input to be encrypted + * @param xr right four bytes halves of input to be encrypted + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt_ecb(struct AVBlowfish *ctx, uint32_t *xl, uint32_t *xr, + int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt(struct AVBlowfish *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_BLOWFISH_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bprint.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bprint.c new file mode 100644 index 0000000000..2f059c5ba6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bprint.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include "avassert.h" +#include "avstring.h" +#include "bprint.h" +#include "common.h" +#include "compat/va_copy.h" +#include "error.h" +#include "mem.h" + +#define av_bprint_room(buf) ((buf)->size - FFMIN((buf)->len, (buf)->size)) +#define av_bprint_is_allocated(buf) ((buf)->str != (buf)->reserved_internal_buffer) + +static int av_bprint_alloc(AVBPrint *buf, unsigned room) +{ + char *old_str, *new_str; + unsigned min_size, new_size; + + if (buf->size == buf->size_max) + return AVERROR(EIO); + if (!av_bprint_is_complete(buf)) + return AVERROR_INVALIDDATA; /* it is already truncated anyway */ + min_size = buf->len + 1 + FFMIN(UINT_MAX - buf->len - 1, room); + new_size = buf->size > buf->size_max / 2 ? buf->size_max : buf->size * 2; + if (new_size < min_size) + new_size = FFMIN(buf->size_max, min_size); + old_str = av_bprint_is_allocated(buf) ? buf->str : NULL; + new_str = av_realloc(old_str, new_size); + if (!new_str) + return AVERROR(ENOMEM); + if (!old_str) + memcpy(new_str, buf->str, buf->len + 1); + buf->str = new_str; + buf->size = new_size; + return 0; +} + +static void av_bprint_grow(AVBPrint *buf, unsigned extra_len) +{ + /* arbitrary margin to avoid small overflows */ + extra_len = FFMIN(extra_len, UINT_MAX - 5 - buf->len); + buf->len += extra_len; + if (buf->size) + buf->str[FFMIN(buf->len, buf->size - 1)] = 0; +} + +void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max) +{ + unsigned size_auto = (char *)buf + sizeof(*buf) - + buf->reserved_internal_buffer; + + if (size_max == 1) + size_max = size_auto; + buf->str = buf->reserved_internal_buffer; + buf->len = 0; + buf->size = FFMIN(size_auto, size_max); + buf->size_max = size_max; + *buf->str = 0; + if (size_init > buf->size) + av_bprint_alloc(buf, size_init - 1); +} + +void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size) +{ + buf->str = buffer; + buf->len = 0; + buf->size = size; + buf->size_max = size; + *buf->str = 0; +} + +void av_bprintf(AVBPrint *buf, const char *fmt, ...) +{ + unsigned room; + char *dst; + va_list vl; + int extra_len; + + while (1) { + room = av_bprint_room(buf); + dst = room ? buf->str + buf->len : NULL; + va_start(vl, fmt); + extra_len = vsnprintf(dst, room, fmt, vl); + va_end(vl); + if (extra_len <= 0) + return; + if (extra_len < room) + break; + if (av_bprint_alloc(buf, extra_len)) + break; + } + av_bprint_grow(buf, extra_len); +} + +void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg) +{ + unsigned room; + char *dst; + int extra_len; + va_list vl; + + while (1) { + room = av_bprint_room(buf); + dst = room ? buf->str + buf->len : NULL; + va_copy(vl, vl_arg); + extra_len = vsnprintf(dst, room, fmt, vl); + va_end(vl); + if (extra_len <= 0) + return; + if (extra_len < room) + break; + if (av_bprint_alloc(buf, extra_len)) + break; + } + av_bprint_grow(buf, extra_len); +} + +void av_bprint_chars(AVBPrint *buf, char c, unsigned n) +{ + unsigned room, real_n; + + while (1) { + room = av_bprint_room(buf); + if (n < room) + break; + if (av_bprint_alloc(buf, n)) + break; + } + if (room) { + real_n = FFMIN(n, room - 1); + memset(buf->str + buf->len, c, real_n); + } + av_bprint_grow(buf, n); +} + +void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size) +{ + unsigned room, real_n; + + while (1) { + room = av_bprint_room(buf); + if (size < room) + break; + if (av_bprint_alloc(buf, size)) + break; + } + if (room) { + real_n = FFMIN(size, room - 1); + memcpy(buf->str + buf->len, data, real_n); + } + av_bprint_grow(buf, size); +} + +void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm) +{ + unsigned room; + size_t l; + + if (!*fmt) + return; + while (1) { + room = av_bprint_room(buf); + if (room && (l = strftime(buf->str + buf->len, room, fmt, tm))) + break; + /* strftime does not tell us how much room it would need: let us + retry with twice as much until the buffer is large enough */ + room = !room ? strlen(fmt) + 1 : + room <= INT_MAX / 2 ? room * 2 : INT_MAX; + if (av_bprint_alloc(buf, room)) { + /* impossible to grow, try to manage something useful anyway */ + room = av_bprint_room(buf); + if (room < 1024) { + /* if strftime fails because the buffer has (almost) reached + its maximum size, let us try in a local buffer; 1k should + be enough to format any real date+time string */ + char buf2[1024]; + if ((l = strftime(buf2, sizeof(buf2), fmt, tm))) { + av_bprintf(buf, "%s", buf2); + return; + } + } + if (room) { + /* if anything else failed and the buffer is not already + truncated, let us add a stock string and force truncation */ + static const char txt[] = "[truncated strftime output]"; + memset(buf->str + buf->len, '!', room); + memcpy(buf->str + buf->len, txt, FFMIN(sizeof(txt) - 1, room)); + av_bprint_grow(buf, room); /* force truncation */ + } + return; + } + } + av_bprint_grow(buf, l); +} + +void av_bprint_get_buffer(AVBPrint *buf, unsigned size, + unsigned char **mem, unsigned *actual_size) +{ + if (size > av_bprint_room(buf)) + av_bprint_alloc(buf, size); + *actual_size = av_bprint_room(buf); + *mem = *actual_size ? buf->str + buf->len : NULL; +} + +void av_bprint_clear(AVBPrint *buf) +{ + if (buf->len) { + *buf->str = 0; + buf->len = 0; + } +} + +int av_bprint_finalize(AVBPrint *buf, char **ret_str) +{ + unsigned real_size = FFMIN(buf->len + 1, buf->size); + char *str; + int ret = 0; + + if (ret_str) { + if (av_bprint_is_allocated(buf)) { + str = av_realloc(buf->str, real_size); + if (!str) + str = buf->str; + buf->str = NULL; + } else { + str = av_malloc(real_size); + if (str) + memcpy(str, buf->str, real_size); + else + ret = AVERROR(ENOMEM); + } + *ret_str = str; + } else { + if (av_bprint_is_allocated(buf)) + av_freep(&buf->str); + } + buf->size = real_size; + return ret; +} + +#define WHITESPACES " \n\t\r" + +void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags) +{ + const char *src0 = src; + + if (mode == AV_ESCAPE_MODE_AUTO) + mode = AV_ESCAPE_MODE_BACKSLASH; /* TODO: implement a heuristic */ + + switch (mode) { + case AV_ESCAPE_MODE_QUOTE: + /* enclose the string between '' */ + av_bprint_chars(dstbuf, '\'', 1); + for (; *src; src++) { + if (*src == '\'') + av_bprintf(dstbuf, "'\\''"); + else + av_bprint_chars(dstbuf, *src, 1); + } + av_bprint_chars(dstbuf, '\'', 1); + break; + + /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */ + default: + /* \-escape characters */ + for (; *src; src++) { + int is_first_last = src == src0 || !*(src+1); + int is_ws = !!strchr(WHITESPACES, *src); + int is_strictly_special = special_chars && strchr(special_chars, *src); + int is_special = + is_strictly_special || strchr("'\\", *src) || + (is_ws && (flags & AV_ESCAPE_FLAG_WHITESPACE)); + + if (is_strictly_special || + (!(flags & AV_ESCAPE_FLAG_STRICT) && + (is_special || (is_ws && is_first_last)))) + av_bprint_chars(dstbuf, '\\', 1); + av_bprint_chars(dstbuf, *src, 1); + } + break; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bprint.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bprint.h new file mode 100644 index 0000000000..c09b1ac1e1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bprint.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BPRINT_H +#define AVUTIL_BPRINT_H + +#include + +#include "attributes.h" +#include "avstring.h" + +/** + * Define a structure with extra padding to a fixed size + * This helps ensuring binary compatibility with future versions. + */ + +#define FF_PAD_STRUCTURE(name, size, ...) \ +struct ff_pad_helper_##name { __VA_ARGS__ }; \ +typedef struct name { \ + __VA_ARGS__ \ + char reserved_padding[size - sizeof(struct ff_pad_helper_##name)]; \ +} name; + +/** + * Buffer to print data progressively + * + * The string buffer grows as necessary and is always 0-terminated. + * The content of the string is never accessed, and thus is + * encoding-agnostic and can even hold binary data. + * + * Small buffers are kept in the structure itself, and thus require no + * memory allocation at all (unless the contents of the buffer is needed + * after the structure goes out of scope). This is almost as lightweight as + * declaring a local "char buf[512]". + * + * The length of the string can go beyond the allocated size: the buffer is + * then truncated, but the functions still keep account of the actual total + * length. + * + * In other words, buf->len can be greater than buf->size and records the + * total length of what would have been to the buffer if there had been + * enough memory. + * + * Append operations do not need to be tested for failure: if a memory + * allocation fails, data stop being appended to the buffer, but the length + * is still updated. This situation can be tested with + * av_bprint_is_complete(). + * + * The size_max field determines several possible behaviours: + * + * size_max = -1 (= UINT_MAX) or any large value will let the buffer be + * reallocated as necessary, with an amortized linear cost. + * + * size_max = 0 prevents writing anything to the buffer: only the total + * length is computed. The write operations can then possibly be repeated in + * a buffer with exactly the necessary size + * (using size_init = size_max = len + 1). + * + * size_max = 1 is automatically replaced by the exact size available in the + * structure itself, thus ensuring no dynamic memory allocation. The + * internal buffer is large enough to hold a reasonable paragraph of text, + * such as the current paragraph. + */ + +FF_PAD_STRUCTURE(AVBPrint, 1024, + char *str; /**< string so far */ + unsigned len; /**< length so far */ + unsigned size; /**< allocated memory */ + unsigned size_max; /**< maximum allocated memory */ + char reserved_internal_buffer[1]; +) + +/** + * Convenience macros for special values for av_bprint_init() size_max + * parameter. + */ +#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1) +#define AV_BPRINT_SIZE_AUTOMATIC 1 +#define AV_BPRINT_SIZE_COUNT_ONLY 0 + +/** + * Init a print buffer. + * + * @param buf buffer to init + * @param size_init initial size (including the final 0) + * @param size_max maximum size; + * 0 means do not write anything, just count the length; + * 1 is replaced by the maximum value for automatic storage; + * any large value means that the internal buffer will be + * reallocated as needed up to that limit; -1 is converted to + * UINT_MAX, the largest limit possible. + * Check also AV_BPRINT_SIZE_* macros. + */ +void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max); + +/** + * Init a print buffer using a pre-existing buffer. + * + * The buffer will not be reallocated. + * + * @param buf buffer structure to init + * @param buffer byte buffer to use for the string data + * @param size size of buffer + */ +void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size); + +/** + * Append a formatted string to a print buffer. + */ +void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3); + +/** + * Append a formatted string to a print buffer. + */ +void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg); + +/** + * Append char c n times to a print buffer. + */ +void av_bprint_chars(AVBPrint *buf, char c, unsigned n); + +/** + * Append data to a print buffer. + * + * param buf bprint buffer to use + * param data pointer to data + * param size size of data + */ +void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size); + +struct tm; +/** + * Append a formatted date and time to a print buffer. + * + * param buf bprint buffer to use + * param fmt date and time format string, see strftime() + * param tm broken-down time structure to translate + * + * @note due to poor design of the standard strftime function, it may + * produce poor results if the format string expands to a very long text and + * the bprint buffer is near the limit stated by the size_max option. + */ +void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm); + +/** + * Allocate bytes in the buffer for external use. + * + * @param[in] buf buffer structure + * @param[in] size required size + * @param[out] mem pointer to the memory area + * @param[out] actual_size size of the memory area after allocation; + * can be larger or smaller than size + */ +void av_bprint_get_buffer(AVBPrint *buf, unsigned size, + unsigned char **mem, unsigned *actual_size); + +/** + * Reset the string to "" but keep internal allocated data. + */ +void av_bprint_clear(AVBPrint *buf); + +/** + * Test if the print buffer is complete (not truncated). + * + * It may have been truncated due to a memory allocation failure + * or the size_max limit (compare size and size_max if necessary). + */ +static inline int av_bprint_is_complete(const AVBPrint *buf) +{ + return buf->len < buf->size; +} + +/** + * Finalize a print buffer. + * + * The print buffer can no longer be used afterwards, + * but the len and size fields are still valid. + * + * @arg[out] ret_str if not NULL, used to return a permanent copy of the + * buffer contents, or NULL if memory allocation fails; + * if NULL, the buffer is discarded and freed + * @return 0 for success or error code (probably AVERROR(ENOMEM)) + */ +int av_bprint_finalize(AVBPrint *buf, char **ret_str); + +/** + * Escape the content in src and append it to dstbuf. + * + * @param dstbuf already inited destination bprint buffer + * @param src string containing the text to escape + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros + */ +void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#endif /* AVUTIL_BPRINT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bswap.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bswap.h new file mode 100644 index 0000000000..91cb79538d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/bswap.h @@ -0,0 +1,109 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * byte swapping routines + */ + +#ifndef AVUTIL_BSWAP_H +#define AVUTIL_BSWAP_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_AARCH64 +# include "aarch64/bswap.h" +#elif ARCH_ARM +# include "arm/bswap.h" +#elif ARCH_AVR32 +# include "avr32/bswap.h" +#elif ARCH_SH4 +# include "sh4/bswap.h" +#elif ARCH_X86 +# include "x86/bswap.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) +#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) +#define AV_BSWAP64C(x) (AV_BSWAP32C(x) << 32 | AV_BSWAP32C((x) >> 32)) + +#define AV_BSWAPC(s, x) AV_BSWAP##s##C(x) + +#ifndef av_bswap16 +static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +{ + x= (x>>8) | (x<<8); + return x; +} +#endif + +#ifndef av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return AV_BSWAP32C(x); +} +#endif + +#ifndef av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + return (uint64_t)av_bswap32(x) << 32 | av_bswap32(x >> 32); +} +#endif + +// be2ne ... big-endian to native-endian +// le2ne ... little-endian to native-endian + +#if AV_HAVE_BIGENDIAN +#define av_be2ne16(x) (x) +#define av_be2ne32(x) (x) +#define av_be2ne64(x) (x) +#define av_le2ne16(x) av_bswap16(x) +#define av_le2ne32(x) av_bswap32(x) +#define av_le2ne64(x) av_bswap64(x) +#define AV_BE2NEC(s, x) (x) +#define AV_LE2NEC(s, x) AV_BSWAPC(s, x) +#else +#define av_be2ne16(x) av_bswap16(x) +#define av_be2ne32(x) av_bswap32(x) +#define av_be2ne64(x) av_bswap64(x) +#define av_le2ne16(x) (x) +#define av_le2ne32(x) (x) +#define av_le2ne64(x) (x) +#define AV_BE2NEC(s, x) AV_BSWAPC(s, x) +#define AV_LE2NEC(s, x) (x) +#endif + +#define AV_BE2NE16C(x) AV_BE2NEC(16, x) +#define AV_BE2NE32C(x) AV_BE2NEC(32, x) +#define AV_BE2NE64C(x) AV_BE2NEC(64, x) +#define AV_LE2NE16C(x) AV_LE2NEC(16, x) +#define AV_LE2NE32C(x) AV_LE2NEC(32, x) +#define AV_LE2NE64C(x) AV_LE2NEC(64, x) + +#endif /* AVUTIL_BSWAP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer.c new file mode 100644 index 0000000000..8d1aa5fa84 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer.c @@ -0,0 +1,357 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "buffer_internal.h" +#include "common.h" +#include "mem.h" +#include "thread.h" + +AVBufferRef *av_buffer_create(uint8_t *data, int size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags) +{ + AVBufferRef *ref = NULL; + AVBuffer *buf = NULL; + + buf = av_mallocz(sizeof(*buf)); + if (!buf) + return NULL; + + buf->data = data; + buf->size = size; + buf->free = free ? free : av_buffer_default_free; + buf->opaque = opaque; + + atomic_init(&buf->refcount, 1); + + if (flags & AV_BUFFER_FLAG_READONLY) + buf->flags |= BUFFER_FLAG_READONLY; + + ref = av_mallocz(sizeof(*ref)); + if (!ref) { + av_freep(&buf); + return NULL; + } + + ref->buffer = buf; + ref->data = data; + ref->size = size; + + return ref; +} + +void av_buffer_default_free(void *opaque, uint8_t *data) +{ + av_free(data); +} + +AVBufferRef *av_buffer_alloc(int size) +{ + AVBufferRef *ret = NULL; + uint8_t *data = NULL; + + data = av_malloc(size); + if (!data) + return NULL; + + ret = av_buffer_create(data, size, av_buffer_default_free, NULL, 0); + if (!ret) + av_freep(&data); + + return ret; +} + +AVBufferRef *av_buffer_allocz(int size) +{ + AVBufferRef *ret = av_buffer_alloc(size); + if (!ret) + return NULL; + + memset(ret->data, 0, size); + return ret; +} + +AVBufferRef *av_buffer_ref(AVBufferRef *buf) +{ + AVBufferRef *ret = av_mallocz(sizeof(*ret)); + + if (!ret) + return NULL; + + *ret = *buf; + + atomic_fetch_add_explicit(&buf->buffer->refcount, 1, memory_order_relaxed); + + return ret; +} + +static void buffer_replace(AVBufferRef **dst, AVBufferRef **src) +{ + AVBuffer *b; + + b = (*dst)->buffer; + + if (src) { + **dst = **src; + av_freep(src); + } else + av_freep(dst); + + if (atomic_fetch_add_explicit(&b->refcount, -1, memory_order_acq_rel) == 1) { + b->free(b->opaque, b->data); + av_freep(&b); + } +} + +void av_buffer_unref(AVBufferRef **buf) +{ + if (!buf || !*buf) + return; + + buffer_replace(buf, NULL); +} + +int av_buffer_is_writable(const AVBufferRef *buf) +{ + if (buf->buffer->flags & AV_BUFFER_FLAG_READONLY) + return 0; + + return atomic_load(&buf->buffer->refcount) == 1; +} + +void *av_buffer_get_opaque(const AVBufferRef *buf) +{ + return buf->buffer->opaque; +} + +int av_buffer_get_ref_count(const AVBufferRef *buf) +{ + return atomic_load(&buf->buffer->refcount); +} + +int av_buffer_make_writable(AVBufferRef **pbuf) +{ + AVBufferRef *newbuf, *buf = *pbuf; + + if (av_buffer_is_writable(buf)) + return 0; + + newbuf = av_buffer_alloc(buf->size); + if (!newbuf) + return AVERROR(ENOMEM); + + memcpy(newbuf->data, buf->data, buf->size); + + buffer_replace(pbuf, &newbuf); + + return 0; +} + +int av_buffer_realloc(AVBufferRef **pbuf, int size) +{ + AVBufferRef *buf = *pbuf; + uint8_t *tmp; + + if (!buf) { + /* allocate a new buffer with av_realloc(), so it will be reallocatable + * later */ + uint8_t *data = av_realloc(NULL, size); + if (!data) + return AVERROR(ENOMEM); + + buf = av_buffer_create(data, size, av_buffer_default_free, NULL, 0); + if (!buf) { + av_freep(&data); + return AVERROR(ENOMEM); + } + + buf->buffer->flags |= BUFFER_FLAG_REALLOCATABLE; + *pbuf = buf; + + return 0; + } else if (buf->size == size) + return 0; + + if (!(buf->buffer->flags & BUFFER_FLAG_REALLOCATABLE) || + !av_buffer_is_writable(buf) || buf->data != buf->buffer->data) { + /* cannot realloc, allocate a new reallocable buffer and copy data */ + AVBufferRef *new = NULL; + + av_buffer_realloc(&new, size); + if (!new) + return AVERROR(ENOMEM); + + memcpy(new->data, buf->data, FFMIN(size, buf->size)); + + buffer_replace(pbuf, &new); + return 0; + } + + tmp = av_realloc(buf->buffer->data, size); + if (!tmp) + return AVERROR(ENOMEM); + + buf->buffer->data = buf->data = tmp; + buf->buffer->size = buf->size = size; + return 0; +} + +AVBufferPool *av_buffer_pool_init2(int size, void *opaque, + AVBufferRef* (*alloc)(void *opaque, int size), + void (*pool_free)(void *opaque)) +{ + AVBufferPool *pool = av_mallocz(sizeof(*pool)); + if (!pool) + return NULL; + + ff_mutex_init(&pool->mutex, NULL); + + pool->size = size; + pool->opaque = opaque; + pool->alloc2 = alloc; + pool->pool_free = pool_free; + + atomic_init(&pool->refcount, 1); + + return pool; +} + +AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)) +{ + AVBufferPool *pool = av_mallocz(sizeof(*pool)); + if (!pool) + return NULL; + + ff_mutex_init(&pool->mutex, NULL); + + pool->size = size; + pool->alloc = alloc ? alloc : av_buffer_alloc; + + atomic_init(&pool->refcount, 1); + + return pool; +} + +/* + * This function gets called when the pool has been uninited and + * all the buffers returned to it. + */ +static void buffer_pool_free(AVBufferPool *pool) +{ + while (pool->pool) { + BufferPoolEntry *buf = pool->pool; + pool->pool = buf->next; + + buf->free(buf->opaque, buf->data); + av_freep(&buf); + } + ff_mutex_destroy(&pool->mutex); + + if (pool->pool_free) + pool->pool_free(pool->opaque); + + av_freep(&pool); +} + +void av_buffer_pool_uninit(AVBufferPool **ppool) +{ + AVBufferPool *pool; + + if (!ppool || !*ppool) + return; + pool = *ppool; + *ppool = NULL; + + if (atomic_fetch_add_explicit(&pool->refcount, -1, memory_order_acq_rel) == 1) + buffer_pool_free(pool); +} + +static void pool_release_buffer(void *opaque, uint8_t *data) +{ + BufferPoolEntry *buf = opaque; + AVBufferPool *pool = buf->pool; + + if(CONFIG_MEMORY_POISONING) + memset(buf->data, FF_MEMORY_POISON, pool->size); + + ff_mutex_lock(&pool->mutex); + buf->next = pool->pool; + pool->pool = buf; + ff_mutex_unlock(&pool->mutex); + + if (atomic_fetch_add_explicit(&pool->refcount, -1, memory_order_acq_rel) == 1) + buffer_pool_free(pool); +} + +/* allocate a new buffer and override its free() callback so that + * it is returned to the pool on free */ +static AVBufferRef *pool_alloc_buffer(AVBufferPool *pool) +{ + BufferPoolEntry *buf; + AVBufferRef *ret; + + ret = pool->alloc2 ? pool->alloc2(pool->opaque, pool->size) : + pool->alloc(pool->size); + if (!ret) + return NULL; + + buf = av_mallocz(sizeof(*buf)); + if (!buf) { + av_buffer_unref(&ret); + return NULL; + } + + buf->data = ret->buffer->data; + buf->opaque = ret->buffer->opaque; + buf->free = ret->buffer->free; + buf->pool = pool; + + ret->buffer->opaque = buf; + ret->buffer->free = pool_release_buffer; + + return ret; +} + +AVBufferRef *av_buffer_pool_get(AVBufferPool *pool) +{ + AVBufferRef *ret; + BufferPoolEntry *buf; + + ff_mutex_lock(&pool->mutex); + buf = pool->pool; + if (buf) { + ret = av_buffer_create(buf->data, pool->size, pool_release_buffer, + buf, 0); + if (ret) { + pool->pool = buf->next; + buf->next = NULL; + } + } else { + ret = pool_alloc_buffer(pool); + } + ff_mutex_unlock(&pool->mutex); + + if (ret) + atomic_fetch_add_explicit(&pool->refcount, 1, memory_order_relaxed); + + return ret; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer.h new file mode 100644 index 0000000000..73b6bd0b14 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer.h @@ -0,0 +1,291 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_buffer + * refcounted data buffer API + */ + +#ifndef AVUTIL_BUFFER_H +#define AVUTIL_BUFFER_H + +#include + +/** + * @defgroup lavu_buffer AVBuffer + * @ingroup lavu_data + * + * @{ + * AVBuffer is an API for reference-counted data buffers. + * + * There are two core objects in this API -- AVBuffer and AVBufferRef. AVBuffer + * represents the data buffer itself; it is opaque and not meant to be accessed + * by the caller directly, but only through AVBufferRef. However, the caller may + * e.g. compare two AVBuffer pointers to check whether two different references + * are describing the same data buffer. AVBufferRef represents a single + * reference to an AVBuffer and it is the object that may be manipulated by the + * caller directly. + * + * There are two functions provided for creating a new AVBuffer with a single + * reference -- av_buffer_alloc() to just allocate a new buffer, and + * av_buffer_create() to wrap an existing array in an AVBuffer. From an existing + * reference, additional references may be created with av_buffer_ref(). + * Use av_buffer_unref() to free a reference (this will automatically free the + * data once all the references are freed). + * + * The convention throughout this API and the rest of FFmpeg is such that the + * buffer is considered writable if there exists only one reference to it (and + * it has not been marked as read-only). The av_buffer_is_writable() function is + * provided to check whether this is true and av_buffer_make_writable() will + * automatically create a new writable buffer when necessary. + * Of course nothing prevents the calling code from violating this convention, + * however that is safe only when all the existing references are under its + * control. + * + * @note Referencing and unreferencing the buffers is thread-safe and thus + * may be done from multiple threads simultaneously without any need for + * additional locking. + * + * @note Two different references to the same buffer can point to different + * parts of the buffer (i.e. their AVBufferRef.data will not be equal). + */ + +/** + * A reference counted buffer type. It is opaque and is meant to be used through + * references (AVBufferRef). + */ +typedef struct AVBuffer AVBuffer; + +/** + * A reference to a data buffer. + * + * The size of this struct is not a part of the public ABI and it is not meant + * to be allocated directly. + */ +typedef struct AVBufferRef { + AVBuffer *buffer; + + /** + * The data buffer. It is considered writable if and only if + * this is the only reference to the buffer, in which case + * av_buffer_is_writable() returns 1. + */ + uint8_t *data; + /** + * Size of data in bytes. + */ + int size; +} AVBufferRef; + +/** + * Allocate an AVBuffer of the given size using av_malloc(). + * + * @return an AVBufferRef of given size or NULL when out of memory + */ +AVBufferRef *av_buffer_alloc(int size); + +/** + * Same as av_buffer_alloc(), except the returned buffer will be initialized + * to zero. + */ +AVBufferRef *av_buffer_allocz(int size); + +/** + * Always treat the buffer as read-only, even when it has only one + * reference. + */ +#define AV_BUFFER_FLAG_READONLY (1 << 0) + +/** + * Create an AVBuffer from an existing array. + * + * If this function is successful, data is owned by the AVBuffer. The caller may + * only access data through the returned AVBufferRef and references derived from + * it. + * If this function fails, data is left untouched. + * @param data data array + * @param size size of data in bytes + * @param free a callback for freeing this buffer's data + * @param opaque parameter to be got for processing or passed to free + * @param flags a combination of AV_BUFFER_FLAG_* + * + * @return an AVBufferRef referring to data on success, NULL on failure. + */ +AVBufferRef *av_buffer_create(uint8_t *data, int size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags); + +/** + * Default free callback, which calls av_free() on the buffer data. + * This function is meant to be passed to av_buffer_create(), not called + * directly. + */ +void av_buffer_default_free(void *opaque, uint8_t *data); + +/** + * Create a new reference to an AVBuffer. + * + * @return a new AVBufferRef referring to the same AVBuffer as buf or NULL on + * failure. + */ +AVBufferRef *av_buffer_ref(AVBufferRef *buf); + +/** + * Free a given reference and automatically free the buffer if there are no more + * references to it. + * + * @param buf the reference to be freed. The pointer is set to NULL on return. + */ +void av_buffer_unref(AVBufferRef **buf); + +/** + * @return 1 if the caller may write to the data referred to by buf (which is + * true if and only if buf is the only reference to the underlying AVBuffer). + * Return 0 otherwise. + * A positive answer is valid until av_buffer_ref() is called on buf. + */ +int av_buffer_is_writable(const AVBufferRef *buf); + +/** + * @return the opaque parameter set by av_buffer_create. + */ +void *av_buffer_get_opaque(const AVBufferRef *buf); + +int av_buffer_get_ref_count(const AVBufferRef *buf); + +/** + * Create a writable reference from a given buffer reference, avoiding data copy + * if possible. + * + * @param buf buffer reference to make writable. On success, buf is either left + * untouched, or it is unreferenced and a new writable AVBufferRef is + * written in its place. On failure, buf is left untouched. + * @return 0 on success, a negative AVERROR on failure. + */ +int av_buffer_make_writable(AVBufferRef **buf); + +/** + * Reallocate a given buffer. + * + * @param buf a buffer reference to reallocate. On success, buf will be + * unreferenced and a new reference with the required size will be + * written in its place. On failure buf will be left untouched. *buf + * may be NULL, then a new buffer is allocated. + * @param size required new buffer size. + * @return 0 on success, a negative AVERROR on failure. + * + * @note the buffer is actually reallocated with av_realloc() only if it was + * initially allocated through av_buffer_realloc(NULL) and there is only one + * reference to it (i.e. the one passed to this function). In all other cases + * a new buffer is allocated and the data is copied. + */ +int av_buffer_realloc(AVBufferRef **buf, int size); + +/** + * @} + */ + +/** + * @defgroup lavu_bufferpool AVBufferPool + * @ingroup lavu_data + * + * @{ + * AVBufferPool is an API for a lock-free thread-safe pool of AVBuffers. + * + * Frequently allocating and freeing large buffers may be slow. AVBufferPool is + * meant to solve this in cases when the caller needs a set of buffers of the + * same size (the most obvious use case being buffers for raw video or audio + * frames). + * + * At the beginning, the user must call av_buffer_pool_init() to create the + * buffer pool. Then whenever a buffer is needed, call av_buffer_pool_get() to + * get a reference to a new buffer, similar to av_buffer_alloc(). This new + * reference works in all aspects the same way as the one created by + * av_buffer_alloc(). However, when the last reference to this buffer is + * unreferenced, it is returned to the pool instead of being freed and will be + * reused for subsequent av_buffer_pool_get() calls. + * + * When the caller is done with the pool and no longer needs to allocate any new + * buffers, av_buffer_pool_uninit() must be called to mark the pool as freeable. + * Once all the buffers are released, it will automatically be freed. + * + * Allocating and releasing buffers with this API is thread-safe as long as + * either the default alloc callback is used, or the user-supplied one is + * thread-safe. + */ + +/** + * The buffer pool. This structure is opaque and not meant to be accessed + * directly. It is allocated with av_buffer_pool_init() and freed with + * av_buffer_pool_uninit(). + */ +typedef struct AVBufferPool AVBufferPool; + +/** + * Allocate and initialize a buffer pool. + * + * @param size size of each buffer in this pool + * @param alloc a function that will be used to allocate new buffers when the + * pool is empty. May be NULL, then the default allocator will be used + * (av_buffer_alloc()). + * @return newly created buffer pool on success, NULL on error. + */ +AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)); + +/** + * Allocate and initialize a buffer pool with a more complex allocator. + * + * @param size size of each buffer in this pool + * @param opaque arbitrary user data used by the allocator + * @param alloc a function that will be used to allocate new buffers when the + * pool is empty. + * @param pool_free a function that will be called immediately before the pool + * is freed. I.e. after av_buffer_pool_uninit() is called + * by the caller and all the frames are returned to the pool + * and freed. It is intended to uninitialize the user opaque + * data. + * @return newly created buffer pool on success, NULL on error. + */ +AVBufferPool *av_buffer_pool_init2(int size, void *opaque, + AVBufferRef* (*alloc)(void *opaque, int size), + void (*pool_free)(void *opaque)); + +/** + * Mark the pool as being available for freeing. It will actually be freed only + * once all the allocated buffers associated with the pool are released. Thus it + * is safe to call this function while some of the allocated buffers are still + * in use. + * + * @param pool pointer to the pool to be freed. It will be set to NULL. + */ +void av_buffer_pool_uninit(AVBufferPool **pool); + +/** + * Allocate a new AVBuffer, reusing an old buffer from the pool when available. + * This function may be called simultaneously from multiple threads. + * + * @return a reference to the new buffer on success, NULL on error. + */ +AVBufferRef *av_buffer_pool_get(AVBufferPool *pool); + +/** + * @} + */ + +#endif /* AVUTIL_BUFFER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer_internal.h new file mode 100644 index 0000000000..54b67047e5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/buffer_internal.h @@ -0,0 +1,98 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BUFFER_INTERNAL_H +#define AVUTIL_BUFFER_INTERNAL_H + +#include +#include + +#include "buffer.h" +#include "thread.h" + +/** + * The buffer is always treated as read-only. + */ +#define BUFFER_FLAG_READONLY (1 << 0) +/** + * The buffer was av_realloc()ed, so it is reallocatable. + */ +#define BUFFER_FLAG_REALLOCATABLE (1 << 1) + +struct AVBuffer { + uint8_t *data; /**< data described by this buffer */ + int size; /**< size of data in bytes */ + + /** + * number of existing AVBufferRef instances referring to this buffer + */ + atomic_uint refcount; + + /** + * a callback for freeing the data + */ + void (*free)(void *opaque, uint8_t *data); + + /** + * an opaque pointer, to be used by the freeing callback + */ + void *opaque; + + /** + * A combination of BUFFER_FLAG_* + */ + int flags; +}; + +typedef struct BufferPoolEntry { + uint8_t *data; + + /* + * Backups of the original opaque/free of the AVBuffer corresponding to + * data. They will be used to free the buffer when the pool is freed. + */ + void *opaque; + void (*free)(void *opaque, uint8_t *data); + + AVBufferPool *pool; + struct BufferPoolEntry *next; +} BufferPoolEntry; + +struct AVBufferPool { + AVMutex mutex; + BufferPoolEntry *pool; + + /* + * This is used to track when the pool is to be freed. + * The pointer to the pool itself held by the caller is considered to + * be one reference. Each buffer requested by the caller increases refcount + * by one, returning the buffer to the pool decreases it by one. + * refcount reaches zero when the buffer has been uninited AND all the + * buffers have been released, then it's safe to free the pool and all + * the buffers in it. + */ + atomic_uint refcount; + + int size; + void *opaque; + AVBufferRef* (*alloc)(int size); + AVBufferRef* (*alloc2)(void *opaque, int size); + void (*pool_free)(void *opaque); +}; + +#endif /* AVUTIL_BUFFER_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/camellia.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/camellia.c new file mode 100644 index 0000000000..f33ee9babc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/camellia.c @@ -0,0 +1,412 @@ +/* + * An implementation of the CAMELLIA algorithm as mentioned in RFC3713 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "camellia.h" +#include "common.h" +#include "intreadwrite.h" +#include "attributes.h" + +#define LR32(x,c) ((x) << (c) | (x) >> (32 - (c))) +#define RR32(x,c) ((x) >> (c) | (x) << (32 - (c))) + +#define MASK8 0xff +#define MASK32 0xffffffff +#define MASK64 0xffffffffffffffff + +#define Sigma1 0xA09E667F3BCC908B +#define Sigma2 0xB67AE8584CAA73B2 +#define Sigma3 0xC6EF372FE94F82BE +#define Sigma4 0x54FF53A5F1D36F1C +#define Sigma5 0x10E527FADE682D1D +#define Sigma6 0xB05688C2B3E6C1FD + +static uint64_t SP[8][256]; + +typedef struct AVCAMELLIA { + uint64_t Kw[4]; + uint64_t Ke[6]; + uint64_t K[24]; + int key_bits; +} AVCAMELLIA; + +static const uint8_t SBOX1[256] = { +112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, +134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, +166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, +139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, +223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, +254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, +170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, +135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, +233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, +120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, +114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158 +}; + +static const uint8_t SBOX2[256] = { +224, 5, 88, 217, 103, 78, 129, 203, 201, 11, 174, 106, 213, 24, 93, 130, + 70, 223, 214, 39, 138, 50, 75, 66, 219, 28, 158, 156, 58, 202, 37, 123, + 13, 113, 95, 31, 248, 215, 62, 157, 124, 96, 185, 190, 188, 139, 22, 52, + 77, 195, 114, 149, 171, 142, 186, 122, 179, 2, 180, 173, 162, 172, 216, 154, + 23, 26, 53, 204, 247, 153, 97, 90, 232, 36, 86, 64, 225, 99, 9, 51, +191, 152, 151, 133, 104, 252, 236, 10, 218, 111, 83, 98, 163, 46, 8, 175, + 40, 176, 116, 194, 189, 54, 34, 56, 100, 30, 57, 44, 166, 48, 229, 68, +253, 136, 159, 101, 135, 107, 244, 35, 72, 16, 209, 81, 192, 249, 210, 160, + 85, 161, 65, 250, 67, 19, 196, 47, 168, 182, 60, 43, 193, 255, 200, 165, + 32, 137, 0, 144, 71, 239, 234, 183, 21, 6, 205, 181, 18, 126, 187, 41, + 15, 184, 7, 4, 155, 148, 33, 102, 230, 206, 237, 231, 59, 254, 127, 197, +164, 55, 177, 76, 145, 110, 141, 118, 3, 45, 222, 150, 38, 125, 198, 92, +211, 242, 79, 25, 63, 220, 121, 29, 82, 235, 243, 109, 94, 251, 105, 178, +240, 49, 12, 212, 207, 140, 226, 117, 169, 74, 87, 132, 17, 69, 27, 245, +228, 14, 115, 170, 241, 221, 89, 20, 108, 146, 84, 208, 120, 112, 227, 73, +128, 80, 167, 246, 119, 147, 134, 131, 42, 199, 91, 233, 238, 143, 1, 61 +}; + +static const uint8_t SBOX3[256] = { + 56, 65, 22, 118, 217, 147, 96, 242, 114, 194, 171, 154, 117, 6, 87, 160, +145, 247, 181, 201, 162, 140, 210, 144, 246, 7, 167, 39, 142, 178, 73, 222, + 67, 92, 215, 199, 62, 245, 143, 103, 31, 24, 110, 175, 47, 226, 133, 13, + 83, 240, 156, 101, 234, 163, 174, 158, 236, 128, 45, 107, 168, 43, 54, 166, +197, 134, 77, 51, 253, 102, 88, 150, 58, 9, 149, 16, 120, 216, 66, 204, +239, 38, 229, 97, 26, 63, 59, 130, 182, 219, 212, 152, 232, 139, 2, 235, + 10, 44, 29, 176, 111, 141, 136, 14, 25, 135, 78, 11, 169, 12, 121, 17, +127, 34, 231, 89, 225, 218, 61, 200, 18, 4, 116, 84, 48, 126, 180, 40, + 85, 104, 80, 190, 208, 196, 49, 203, 42, 173, 15, 202, 112, 255, 50, 105, + 8, 98, 0, 36, 209, 251, 186, 237, 69, 129, 115, 109, 132, 159, 238, 74, +195, 46, 193, 1, 230, 37, 72, 153, 185, 179, 123, 249, 206, 191, 223, 113, + 41, 205, 108, 19, 100, 155, 99, 157, 192, 75, 183, 165, 137, 95, 177, 23, +244, 188, 211, 70, 207, 55, 94, 71, 148, 250, 252, 91, 151, 254, 90, 172, + 60, 76, 3, 53, 243, 35, 184, 93, 106, 146, 213, 33, 68, 81, 198, 125, + 57, 131, 220, 170, 124, 119, 86, 5, 27, 164, 21, 52, 30, 28, 248, 82, + 32, 20, 233, 189, 221, 228, 161, 224, 138, 241, 214, 122, 187, 227, 64, 79 +}; + +static const uint8_t SBOX4[256] = { +112, 44, 179, 192, 228, 87, 234, 174, 35, 107, 69, 165, 237, 79, 29, 146, +134, 175, 124, 31, 62, 220, 94, 11, 166, 57, 213, 93, 217, 90, 81, 108, +139, 154, 251, 176, 116, 43, 240, 132, 223, 203, 52, 118, 109, 169, 209, 4, + 20, 58, 222, 17, 50, 156, 83, 242, 254, 207, 195, 122, 36, 232, 96, 105, +170, 160, 161, 98, 84, 30, 224, 100, 16, 0, 163, 117, 138, 230, 9, 221, +135, 131, 205, 144, 115, 246, 157, 191, 82, 216, 200, 198, 129, 111, 19, 99, +233, 167, 159, 188, 41, 249, 47, 180, 120, 6, 231, 113, 212, 171, 136, 141, +114, 185, 248, 172, 54, 42, 60, 241, 64, 211, 187, 67, 21, 173, 119, 128, +130, 236, 39, 229, 133, 53, 12, 65, 239, 147, 25, 33, 14, 78, 101, 189, +184, 143, 235, 206, 48, 95, 197, 26, 225, 202, 71, 61, 1, 214, 86, 77, + 13, 102, 204, 45, 18, 32, 177, 153, 76, 194, 126, 5, 183, 49, 23, 215, + 88, 97, 27, 28, 15, 22, 24, 34, 68, 178, 181, 145, 8, 168, 252, 80, +208, 125, 137, 151, 91, 149, 255, 210, 196, 72, 247, 219, 3, 218, 63, 148, + 92, 2, 74, 51, 103, 243, 127, 226, 155, 38, 55, 59, 150, 75, 190, 46, +121, 140, 110, 142, 245, 182, 253, 89, 152, 106, 70, 186, 37, 66, 162, 250, + 7, 85, 238, 10, 73, 104, 56, 164, 40, 123, 201, 193, 227, 244, 199, 158 +}; + +const int av_camellia_size = sizeof(AVCAMELLIA); + +static void LR128(uint64_t d[2], const uint64_t K[2], int x) +{ + int i = 0; + if (64 <= x && x < 128) { + i = 1; + x -= 64; + } + if (x <= 0 || x >= 128) { + d[0] = K[i]; + d[1] = K[!i]; + return; + } + d[0] = (K[i] << x | K[!i] >> (64 - x)); + d[1] = (K[!i] << x | K[i] >> (64 - x)); +} + +static uint64_t F(uint64_t F_IN, uint64_t KE) +{ + KE ^= F_IN; + F_IN=SP[0][KE >> 56]^SP[1][(KE >> 48) & MASK8]^SP[2][(KE >> 40) & MASK8]^SP[3][(KE >> 32) & MASK8]^SP[4][(KE >> 24) & MASK8]^SP[5][(KE >> 16) & MASK8]^SP[6][(KE >> 8) & MASK8]^SP[7][KE & MASK8]; + return F_IN; +} + +static uint64_t FL(uint64_t FL_IN, uint64_t KE) +{ + uint32_t x1, x2, k1, k2; + x1 = FL_IN >> 32; + x2 = FL_IN & MASK32; + k1 = KE >> 32; + k2 = KE & MASK32; + x2 = x2 ^ LR32((x1 & k1), 1); + x1 = x1 ^ (x2 | k2); + return ((uint64_t)x1 << 32) | (uint64_t)x2; +} + +static uint64_t FLINV(uint64_t FLINV_IN, uint64_t KE) +{ + uint32_t x1, x2, k1, k2; + x1 = FLINV_IN >> 32; + x2 = FLINV_IN & MASK32; + k1 = KE >> 32; + k2 = KE & MASK32; + x1 = x1 ^ (x2 | k2); + x2 = x2 ^ LR32((x1 & k1), 1); + return ((uint64_t)x1 << 32) | (uint64_t)x2; +} + +static const uint8_t shifts[2][12] = { + {0, 15, 15, 45, 45, 60, 94, 94, 111}, + {0, 15, 15, 30, 45, 45, 60, 60, 77, 94, 94, 111} +}; + +static const uint8_t vars[2][12] = { + {2, 0, 2, 0, 2, 2, 0, 2, 0}, + {3, 1, 2, 3, 0, 2, 1, 3, 0, 1, 2, 0} +}; + +static void generate_round_keys(AVCAMELLIA *cs, uint64_t Kl[2], uint64_t Kr[2], uint64_t Ka[2], uint64_t Kb[2]) +{ + int i; + uint64_t *Kd[4], d[2]; + Kd[0] = Kl; + Kd[1] = Kr; + Kd[2] = Ka; + Kd[3] = Kb; + cs->Kw[0] = Kl[0]; + cs->Kw[1] = Kl[1]; + if (cs->key_bits == 128) { + for (i = 0; i < 9; i++) { + LR128(d, Kd[vars[0][i]], shifts[0][i]); + cs->K[2*i] = d[0]; + cs->K[2*i+1] = d[1]; + } + LR128(d, Kd[0], 60); + cs->K[9] = d[1]; + LR128(d, Kd[2], 30); + cs->Ke[0] = d[0]; + cs->Ke[1] = d[1]; + LR128(d, Kd[0], 77); + cs->Ke[2] = d[0]; + cs->Ke[3] = d[1]; + LR128(d, Kd[2], 111); + cs->Kw[2] = d[0]; + cs->Kw[3] = d[1]; + } else { + for (i = 0; i < 12; i++) { + LR128(d, Kd[vars[1][i]], shifts[1][i]); + cs->K[2*i] = d[0]; + cs->K[2*i+1] = d[1]; + } + LR128(d, Kd[1], 30); + cs->Ke[0] = d[0]; + cs->Ke[1] = d[1]; + LR128(d, Kd[0], 60); + cs->Ke[2] = d[0]; + cs->Ke[3] = d[1]; + LR128(d, Kd[2], 77); + cs->Ke[4] = d[0]; + cs->Ke[5] = d[1]; + LR128(d, Kd[3], 111); + cs->Kw[2] = d[0]; + cs->Kw[3] = d[1]; + } +} + +static void camellia_encrypt(AVCAMELLIA *cs, uint8_t *dst, const uint8_t *src) +{ + uint64_t D1, D2; + D1 = AV_RB64(src); + D2 = AV_RB64(src + 8); + D1 ^= cs->Kw[0]; + D2 ^= cs->Kw[1]; + D2 ^= F(D1, cs->K[0]); + D1 ^= F(D2, cs->K[1]); + D2 ^= F(D1, cs->K[2]); + D1 ^= F(D2, cs->K[3]); + D2 ^= F(D1, cs->K[4]); + D1 ^= F(D2, cs->K[5]); + D1 = FL(D1, cs->Ke[0]); + D2 = FLINV(D2, cs->Ke[1]); + D2 ^= F(D1, cs->K[6]); + D1 ^= F(D2, cs->K[7]); + D2 ^= F(D1, cs->K[8]); + D1 ^= F(D2, cs->K[9]); + D2 ^= F(D1, cs->K[10]); + D1 ^= F(D2, cs->K[11]); + D1 = FL(D1, cs->Ke[2]); + D2 = FLINV(D2, cs->Ke[3]); + D2 ^= F(D1, cs->K[12]); + D1 ^= F(D2, cs->K[13]); + D2 ^= F(D1, cs->K[14]); + D1 ^= F(D2, cs->K[15]); + D2 ^= F(D1, cs->K[16]); + D1 ^= F(D2, cs->K[17]); + if (cs->key_bits != 128) { + D1 = FL(D1, cs->Ke[4]); + D2 = FLINV(D2, cs->Ke[5]); + D2 ^= F(D1, cs->K[18]); + D1 ^= F(D2, cs->K[19]); + D2 ^= F(D1, cs->K[20]); + D1 ^= F(D2, cs->K[21]); + D2 ^= F(D1, cs->K[22]); + D1 ^= F(D2, cs->K[23]); + } + D2 ^= cs->Kw[2]; + D1 ^= cs->Kw[3]; + AV_WB64(dst, D2); + AV_WB64(dst + 8, D1); +} + +static void camellia_decrypt(AVCAMELLIA *cs, uint8_t *dst, const uint8_t *src, uint8_t *iv) +{ + uint64_t D1, D2; + D1 = AV_RB64(src); + D2 = AV_RB64(src + 8); + D1 ^= cs->Kw[2]; + D2 ^= cs->Kw[3]; + if (cs->key_bits != 128) { + D2 ^= F(D1, cs->K[23]); + D1 ^= F(D2, cs->K[22]); + D2 ^= F(D1, cs->K[21]); + D1 ^= F(D2, cs->K[20]); + D2 ^= F(D1, cs->K[19]); + D1 ^= F(D2, cs->K[18]); + D1 = FL(D1, cs->Ke[5]); + D2 = FLINV(D2, cs->Ke[4]); + } + D2 ^= F(D1, cs->K[17]); + D1 ^= F(D2, cs->K[16]); + D2 ^= F(D1, cs->K[15]); + D1 ^= F(D2, cs->K[14]); + D2 ^= F(D1, cs->K[13]); + D1 ^= F(D2, cs->K[12]); + D1 = FL(D1, cs->Ke[3]); + D2 = FLINV(D2, cs->Ke[2]); + D2 ^= F(D1, cs->K[11]); + D1 ^= F(D2, cs->K[10]); + D2 ^= F(D1, cs->K[9]); + D1 ^= F(D2, cs->K[8]); + D2 ^= F(D1, cs->K[7]); + D1 ^= F(D2, cs->K[6]); + D1 = FL(D1, cs->Ke[1]); + D2 = FLINV(D2, cs->Ke[0]); + D2 ^= F(D1, cs->K[5]); + D1 ^= F(D2, cs->K[4]); + D2 ^= F(D1, cs->K[3]); + D1 ^= F(D2, cs->K[2]); + D2 ^= F(D1, cs->K[1]); + D1 ^= F(D2, cs->K[0]); + D2 ^= cs->Kw[0]; + D1 ^= cs->Kw[1]; + if (iv) { + D2 ^= AV_RB64(iv); + D1 ^= AV_RB64(iv + 8); + memcpy(iv, src, 16); + } + AV_WB64(dst, D2); + AV_WB64(dst + 8, D1); +} + +static void computeSP(void) +{ + uint64_t z; + int i; + for (i = 0; i < 256; i++) { + z = SBOX1[i]; + SP[0][i] = (z << 56) ^ (z << 48) ^ (z << 40) ^ (z << 24) ^ z; + SP[7][i] = (z << 56) ^ (z << 48) ^ (z << 40) ^ (z << 24) ^ (z << 16) ^ (z << 8); + z = SBOX2[i]; + SP[1][i] = (z << 48) ^ (z << 40) ^ (z << 32) ^ (z << 24) ^ (z << 16); + SP[4][i] = (z << 48) ^ (z << 40) ^ (z << 32) ^ (z << 16) ^ (z << 8) ^ z; + z = SBOX3[i]; + SP[2][i] = (z << 56) ^ (z << 40) ^ (z << 32) ^ (z << 16) ^ (z << 8); + SP[5][i] = (z << 56) ^ (z << 40) ^ (z << 32) ^ (z << 24) ^ (z << 8) ^ z; + z = SBOX4[i]; + SP[3][i] = (z << 56) ^ (z << 48) ^ (z << 32) ^ (z << 8) ^ z; + SP[6][i] = (z << 56) ^ (z << 48) ^ (z << 32) ^ (z << 24) ^ (z << 16) ^ z; + } +} + +struct AVCAMELLIA *av_camellia_alloc(void) +{ + return av_mallocz(sizeof(struct AVCAMELLIA)); +} + +av_cold int av_camellia_init(AVCAMELLIA *cs, const uint8_t *key, int key_bits) +{ + uint64_t Kl[2], Kr[2], Ka[2], Kb[2]; + uint64_t D1, D2; + if (key_bits != 128 && key_bits != 192 && key_bits != 256) + return AVERROR(EINVAL); + memset(Kb, 0, sizeof(Kb)); + memset(Kr, 0, sizeof(Kr)); + cs->key_bits = key_bits; + Kl[0] = AV_RB64(key); + Kl[1] = AV_RB64(key + 8); + if (key_bits == 192) { + Kr[0] = AV_RB64(key + 16); + Kr[1] = ~Kr[0]; + } else if (key_bits == 256) { + Kr[0] = AV_RB64(key + 16); + Kr[1] = AV_RB64(key + 24); + } + computeSP(); + D1 = Kl[0] ^ Kr[0]; + D2 = Kl[1] ^ Kr[1]; + D2 ^= F(D1, Sigma1); + D1 ^= F(D2, Sigma2); + D1 ^= Kl[0]; + D2 ^= Kl[1]; + D2 ^= F(D1, Sigma3); + D1 ^= F(D2, Sigma4); + Ka[0] = D1; + Ka[1] = D2; + if (key_bits != 128) { + D1 = Ka[0] ^ Kr[0]; + D2 = Ka[1] ^ Kr[1]; + D2 ^= F(D1, Sigma5); + D1 ^= F(D2, Sigma6); + Kb[0] = D1; + Kb[1] = D2; + } + generate_round_keys(cs, Kl, Kr, Ka, Kb); + return 0; +} + +void av_camellia_crypt(AVCAMELLIA *cs, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt) +{ + int i; + while (count--) { + if (decrypt) { + camellia_decrypt(cs, dst, src, iv); + } else { + if (iv) { + for (i = 0; i < 16; i++) + dst[i] = src[i] ^ iv[i]; + camellia_encrypt(cs, dst, dst); + memcpy(iv, dst, 16); + } else { + camellia_encrypt(cs, dst, src); + } + } + src = src + 16; + dst = dst + 16; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/camellia.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/camellia.h new file mode 100644 index 0000000000..e674c9b9a4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/camellia.h @@ -0,0 +1,70 @@ +/* + * An implementation of the CAMELLIA algorithm as mentioned in RFC3713 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CAMELLIA_H +#define AVUTIL_CAMELLIA_H + +#include + + +/** + * @file + * @brief Public header for libavutil CAMELLIA algorithm + * @defgroup lavu_camellia CAMELLIA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_camellia_size; + +struct AVCAMELLIA; + +/** + * Allocate an AVCAMELLIA context + * To free the struct: av_free(ptr) + */ +struct AVCAMELLIA *av_camellia_alloc(void); + +/** + * Initialize an AVCAMELLIA context. + * + * @param ctx an AVCAMELLIA context + * @param key a key of 16, 24, 32 bytes used for encryption/decryption + * @param key_bits number of keybits: possible are 128, 192, 256 + */ +int av_camellia_init(struct AVCAMELLIA *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVCAMELLIA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 16 byte blocks + * @paran iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_camellia_crypt(struct AVCAMELLIA *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t* iv, int decrypt); + +/** + * @} + */ +#endif /* AVUTIL_CAMELLIA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cast5.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cast5.c new file mode 100644 index 0000000000..445eb55c12 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cast5.c @@ -0,0 +1,507 @@ +/* + * An implementation of the CAST128 algorithm as mentioned in RFC2144 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "cast5.h" +#include "common.h" +#include "intreadwrite.h" +#include "attributes.h" + +#define IA(x) ((x) >> 24) +#define IB(x) (((x) >> 16) & 0xff) +#define IC(x) (((x) >> 8) & 0xff) +#define ID(x) ((x) & 0xff) + +#define LR(x, c) (((x) << (c)) | ((x) >> (32 - (c)))) + +#define F3(l, r, i) \ + do { \ + I = LR(cs->Km[i] - r, cs->Kr[i]); \ + f = ((S1[IA(I)] + S2[IB(I)]) ^ S3[IC(I)]) - S4[ID(I)]; \ + l = f ^ l; \ + } while (0) + +#define F2(l, r, i) \ + do { \ + I = LR(cs->Km[i] ^ r, cs->Kr[i]); \ + f = ((S1[IA(I)] - S2[IB(I)]) + S3[IC(I)]) ^ S4[ID(I)]; \ + l = f ^ l; \ + } while (0) + +#define F1(l, r, i) \ + do { \ + I = LR(cs->Km[i] + r, cs->Kr[i]); \ + f = ((S1[IA(I)] ^ S2[IB(I)]) - S3[IC(I)]) + S4[ID(I)]; \ + l = f ^ l; \ + } while (0) + +#define COMPUTE_Z \ + do { \ + z[0] = x[0] ^ S5[IB(x[3])] ^ S6[ID(x[3])] ^ S7[IA(x[3])] ^ S8[IC(x[3])] ^ S7[IA(x[2])]; \ + z[1] = x[2] ^ S5[IA(z[0])] ^ S6[IC(z[0])] ^ S7[IB(z[0])] ^ S8[ID(z[0])] ^ S8[IC(x[2])]; \ + z[2] = x[3] ^ S5[ID(z[1])] ^ S6[IC(z[1])] ^ S7[IB(z[1])] ^ S8[IA(z[1])] ^ S5[IB(x[2])]; \ + z[3] = x[1] ^ S5[IC(z[2])] ^ S6[IB(z[2])] ^ S7[ID(z[2])] ^ S8[IA(z[2])] ^ S6[ID(x[2])]; \ + } while (0) + +#define COMPUTE_X \ + do { \ + x[0] = z[2] ^ S5[IB(z[1])] ^ S6[ID(z[1])] ^ S7[IA(z[1])] ^ S8[IC(z[1])] ^ S7[IA(z[0])]; \ + x[1] = z[0] ^ S5[IA(x[0])] ^ S6[IC(x[0])] ^ S7[IB(x[0])] ^ S8[ID(x[0])] ^ S8[IC(z[0])]; \ + x[2] = z[1] ^ S5[ID(x[1])] ^ S6[IC(x[1])] ^ S7[IB(x[1])] ^ S8[IA(x[1])] ^ S5[IB(z[0])]; \ + x[3] = z[3] ^ S5[IC(x[2])] ^ S6[IB(x[2])] ^ S7[ID(x[2])] ^ S8[IA(x[2])] ^ S6[ID(z[0])]; \ + } while (0) + + +typedef struct AVCAST5 { + uint32_t Km[17]; + uint32_t Kr[17]; + int rounds; +} AVCAST5; + +const int av_cast5_size = sizeof(AVCAST5); + +static const uint32_t S1[256] = { + 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, + 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, + 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, + 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, + 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, + 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, + 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, + 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, + 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, + 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, + 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, + 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, + 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, + 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, + 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, + 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, + 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, + 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, + 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, + 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, + 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, + 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, + 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, + 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, + 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, + 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, + 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, + 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, + 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, + 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, + 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, + 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf +}; + +static const uint32_t S2[256] = { + 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, + 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, + 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, + 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, + 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, + 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, + 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, + 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, + 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, + 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, + 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, + 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, + 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, + 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, + 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, + 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, + 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, + 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, + 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, + 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, + 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, + 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, + 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, + 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, + 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, + 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, + 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, + 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, + 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, + 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, + 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, + 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 +}; + +static const uint32_t S3[256] = { + 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, + 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, + 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, + 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, + 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, + 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, + 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, + 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, + 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, + 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, + 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, + 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, + 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, + 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, + 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, + 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, + 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, + 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, + 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, + 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, + 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, + 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, + 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, + 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, + 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, + 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, + 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, + 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, + 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, + 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, + 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, + 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 +}; + +static const uint32_t S4[256] = { + 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, + 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, + 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, + 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, + 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, + 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, + 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, + 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, + 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, + 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, + 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, + 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, + 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, + 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, + 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, + 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, + 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, + 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, + 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, + 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, + 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, + 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, + 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, + 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, + 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, + 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, + 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, + 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, + 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, + 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, + 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, + 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 +}; + +static const uint32_t S5[256] = { + 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, + 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, + 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, + 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, + 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, + 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, + 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, + 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, + 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, + 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, + 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, + 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, + 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, + 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, + 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, + 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, + 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, + 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, + 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, + 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, + 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, + 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, + 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, + 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, + 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, + 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, + 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, + 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, + 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, + 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, + 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, + 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4 +}; + +static const uint32_t S6[256] = { + 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, + 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, + 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, + 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, + 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, + 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, + 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, + 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, + 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, + 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, + 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, + 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, + 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, + 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, + 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, + 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, + 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, + 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, + 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, + 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, + 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, + 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, + 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, + 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, + 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, + 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, + 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, + 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, + 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, + 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, + 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, + 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f +}; + +static const uint32_t S7[256] = { + 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, + 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, + 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, + 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, + 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, + 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, + 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, + 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, + 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, + 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, + 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, + 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, + 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, + 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, + 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, + 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, + 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, + 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, + 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, + 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, + 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, + 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, + 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, + 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, + 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, + 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, + 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, + 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, + 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, + 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, + 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, + 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3 +}; + +static const uint32_t S8[256] = { + 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, + 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, + 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, + 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, + 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, + 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, + 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, + 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, + 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, + 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, + 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, + 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, + 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, + 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, + 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, + 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, + 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, + 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, + 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, + 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, + 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, + 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, + 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, + 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, + 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, + 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, + 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, + 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, + 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, + 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, + 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, + 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e +}; + +static void generate_round_keys(int rnds, uint32_t* K, uint32_t* x, uint32_t* z) +{ + COMPUTE_Z; + + K[1] = S5[IA(z[2])] ^ S6[IB(z[2])] ^ S7[ID(z[1])] ^ S8[IC(z[1])] ^ S5[IC(z[0])]; + K[2] = S5[IC(z[2])] ^ S6[ID(z[2])] ^ S7[IB(z[1])] ^ S8[IA(z[1])] ^ S6[IC(z[1])]; + K[3] = S5[IA(z[3])] ^ S6[IB(z[3])] ^ S7[ID(z[0])] ^ S8[IC(z[0])] ^ S7[IB(z[2])]; + K[4] = S5[IC(z[3])] ^ S6[ID(z[3])] ^ S7[IB(z[0])] ^ S8[IA(z[0])] ^ S8[IA(z[3])]; + + COMPUTE_X; + + K[5] = S5[ID(x[0])] ^ S6[IC(x[0])] ^ S7[IA(x[3])] ^ S8[IB(x[3])] ^ S5[IA(x[2])]; + K[6] = S5[IB(x[0])] ^ S6[IA(x[0])] ^ S7[IC(x[3])] ^ S8[ID(x[3])] ^ S6[IB(x[3])]; + K[7] = S5[ID(x[1])] ^ S6[IC(x[1])] ^ S7[IA(x[2])] ^ S8[IB(x[2])] ^ S7[ID(x[0])]; + K[8] = S5[IB(x[1])] ^ S6[IA(x[1])] ^ S7[IC(x[2])] ^ S8[ID(x[2])] ^ S8[ID(x[1])]; + + COMPUTE_Z; + + K[9] = S5[ID(z[0])] ^ S6[IC(z[0])] ^ S7[IA(z[3])] ^ S8[IB(z[3])] ^ S5[IB(z[2])]; + K[10] = S5[IB(z[0])] ^ S6[IA(z[0])] ^ S7[IC(z[3])] ^ S8[ID(z[3])] ^ S6[IA(z[3])]; + K[11] = S5[ID(z[1])] ^ S6[IC(z[1])] ^ S7[IA(z[2])] ^ S8[IB(z[2])] ^ S7[IC(z[0])]; + K[12] = S5[IB(z[1])] ^ S6[IA(z[1])] ^ S7[IC(z[2])] ^ S8[ID(z[2])] ^ S8[IC(z[1])]; + + COMPUTE_X; + + if (rnds == 16) { + K[13] = S5[IA(x[2])] ^ S6[IB(x[2])] ^ S7[ID(x[1])] ^ S8[IC(x[1])] ^ S5[ID(x[0])]; + K[14] = S5[IC(x[2])] ^ S6[ID(x[2])] ^ S7[IB(x[1])] ^ S8[IA(x[1])] ^ S6[ID(x[1])]; + K[15] = S5[IA(x[3])] ^ S6[IB(x[3])] ^ S7[ID(x[0])] ^ S8[IC(x[0])] ^ S7[IA(x[2])]; + K[16] = S5[IC(x[3])] ^ S6[ID(x[3])] ^ S7[IB(x[0])] ^ S8[IA(x[0])] ^ S8[IB(x[3])]; + } +} + +static void encipher(AVCAST5* cs, uint8_t* dst, const uint8_t* src) +{ + uint32_t r, l, f, I; + l = AV_RB32(src); + r = AV_RB32(src + 4); + F1(l, r, 1); + F2(r, l, 2); + F3(l, r, 3); + F1(r, l, 4); + F2(l, r, 5); + F3(r, l, 6); + F1(l, r, 7); + F2(r, l, 8); + F3(l, r, 9); + F1(r, l, 10); + F2(l, r, 11); + F3(r, l, 12); + if (cs->rounds == 16) { + F1(l, r, 13); + F2(r, l, 14); + F3(l, r, 15); + F1(r, l, 16); + } + AV_WB32(dst, r); + AV_WB32(dst + 4, l); +} + +static void decipher(AVCAST5* cs, uint8_t* dst, const uint8_t* src, uint8_t *iv) +{ + uint32_t f, I, r, l; + l = AV_RB32(src); + r = AV_RB32(src + 4); + if (cs->rounds == 16) { + F1(l, r, 16); + F3(r, l, 15); + F2(l, r, 14); + F1(r, l, 13); + } + F3(l, r, 12); + F2(r, l, 11); + F1(l, r, 10); + F3(r, l, 9); + F2(l, r, 8); + F1(r, l, 7); + F3(l, r, 6); + F2(r, l, 5); + F1(l, r, 4); + F3(r, l, 3); + F2(l, r, 2); + F1(r, l, 1); + if (iv) { + r ^= AV_RB32(iv); + l ^= AV_RB32(iv + 4); + memcpy(iv, src, 8); + } + AV_WB32(dst, r); + AV_WB32(dst + 4, l); +} + +struct AVCAST5 *av_cast5_alloc(void) +{ + return av_mallocz(sizeof(struct AVCAST5)); +} + +av_cold int av_cast5_init(AVCAST5* cs, const uint8_t *key, int key_bits) +{ + uint8_t newKey[16]; + int i; + uint32_t p[4], q[4]; + if (key_bits % 8 || key_bits < 40 || key_bits > 128) + return AVERROR(EINVAL); + memset(newKey, 0, sizeof(newKey)); + memcpy(newKey, key, key_bits >> 3); + + cs->rounds = key_bits <= 80 ? 12 : 16; + for (i = 0; i < 4; i++) + q[i] = AV_RB32(newKey + (4 * i)); + generate_round_keys(cs->rounds, cs->Km, q, p); + generate_round_keys(cs->rounds, cs->Kr, q, p); + for (i = 0; i <= cs->rounds; i++) + cs->Kr[i] = cs->Kr[i] & 0x1f; + return 0; +} + +void av_cast5_crypt2(AVCAST5* cs, uint8_t* dst, const uint8_t* src, int count, uint8_t *iv, int decrypt) +{ + int i; + while (count--) { + if (decrypt) { + decipher(cs, dst, src, iv); + } else { + if (iv) { + for (i = 0; i < 8; i++) + dst[i] = src[i] ^ iv[i]; + encipher(cs, dst, dst); + memcpy(iv, dst, 8); + } else { + encipher(cs, dst, src); + } + } + src = src + 8; + dst = dst + 8; + } +} +void av_cast5_crypt(AVCAST5* cs, uint8_t* dst, const uint8_t* src, int count, int decrypt) +{ + while (count--) { + if (decrypt){ + decipher(cs, dst, src, NULL); + } else { + encipher(cs, dst, src); + } + src = src + 8; + dst = dst + 8; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cast5.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cast5.h new file mode 100644 index 0000000000..ad5b347e68 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cast5.h @@ -0,0 +1,80 @@ +/* + * An implementation of the CAST128 algorithm as mentioned in RFC2144 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CAST5_H +#define AVUTIL_CAST5_H + +#include + + +/** + * @file + * @brief Public header for libavutil CAST5 algorithm + * @defgroup lavu_cast5 CAST5 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_cast5_size; + +struct AVCAST5; + +/** + * Allocate an AVCAST5 context + * To free the struct: av_free(ptr) + */ +struct AVCAST5 *av_cast5_alloc(void); +/** + * Initialize an AVCAST5 context. + * + * @param ctx an AVCAST5 context + * @param key a key of 5,6,...16 bytes used for encryption/decryption + * @param key_bits number of keybits: possible are 40,48,...,128 + * @return 0 on success, less than 0 on failure + */ +int av_cast5_init(struct AVCAST5 *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, ECB mode only + * + * @param ctx an AVCAST5 context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_cast5_crypt(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVCAST5 context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_cast5_crypt2(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); +/** + * @} + */ +#endif /* AVUTIL_CAST5_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/channel_layout.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/channel_layout.c new file mode 100644 index 0000000000..3bd5ee29b7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/channel_layout.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio channel layout utility functions + */ + +#include + +#include "avstring.h" +#include "avutil.h" +#include "channel_layout.h" +#include "bprint.h" +#include "common.h" + +struct channel_name { + const char *name; + const char *description; +}; + +static const struct channel_name channel_names[] = { + [0] = { "FL", "front left" }, + [1] = { "FR", "front right" }, + [2] = { "FC", "front center" }, + [3] = { "LFE", "low frequency" }, + [4] = { "BL", "back left" }, + [5] = { "BR", "back right" }, + [6] = { "FLC", "front left-of-center" }, + [7] = { "FRC", "front right-of-center" }, + [8] = { "BC", "back center" }, + [9] = { "SL", "side left" }, + [10] = { "SR", "side right" }, + [11] = { "TC", "top center" }, + [12] = { "TFL", "top front left" }, + [13] = { "TFC", "top front center" }, + [14] = { "TFR", "top front right" }, + [15] = { "TBL", "top back left" }, + [16] = { "TBC", "top back center" }, + [17] = { "TBR", "top back right" }, + [29] = { "DL", "downmix left" }, + [30] = { "DR", "downmix right" }, + [31] = { "WL", "wide left" }, + [32] = { "WR", "wide right" }, + [33] = { "SDL", "surround direct left" }, + [34] = { "SDR", "surround direct right" }, + [35] = { "LFE2", "low frequency 2" }, +}; + +static const char *get_channel_name(int channel_id) +{ + if (channel_id < 0 || channel_id >= FF_ARRAY_ELEMS(channel_names)) + return NULL; + return channel_names[channel_id].name; +} + +static const struct { + const char *name; + int nb_channels; + uint64_t layout; +} channel_layout_map[] = { + { "mono", 1, AV_CH_LAYOUT_MONO }, + { "stereo", 2, AV_CH_LAYOUT_STEREO }, + { "2.1", 3, AV_CH_LAYOUT_2POINT1 }, + { "3.0", 3, AV_CH_LAYOUT_SURROUND }, + { "3.0(back)", 3, AV_CH_LAYOUT_2_1 }, + { "4.0", 4, AV_CH_LAYOUT_4POINT0 }, + { "quad", 4, AV_CH_LAYOUT_QUAD }, + { "quad(side)", 4, AV_CH_LAYOUT_2_2 }, + { "3.1", 4, AV_CH_LAYOUT_3POINT1 }, + { "5.0", 5, AV_CH_LAYOUT_5POINT0_BACK }, + { "5.0(side)", 5, AV_CH_LAYOUT_5POINT0 }, + { "4.1", 5, AV_CH_LAYOUT_4POINT1 }, + { "5.1", 6, AV_CH_LAYOUT_5POINT1_BACK }, + { "5.1(side)", 6, AV_CH_LAYOUT_5POINT1 }, + { "6.0", 6, AV_CH_LAYOUT_6POINT0 }, + { "6.0(front)", 6, AV_CH_LAYOUT_6POINT0_FRONT }, + { "hexagonal", 6, AV_CH_LAYOUT_HEXAGONAL }, + { "6.1", 7, AV_CH_LAYOUT_6POINT1 }, + { "6.1(back)", 7, AV_CH_LAYOUT_6POINT1_BACK }, + { "6.1(front)", 7, AV_CH_LAYOUT_6POINT1_FRONT }, + { "7.0", 7, AV_CH_LAYOUT_7POINT0 }, + { "7.0(front)", 7, AV_CH_LAYOUT_7POINT0_FRONT }, + { "7.1", 8, AV_CH_LAYOUT_7POINT1 }, + { "7.1(wide)", 8, AV_CH_LAYOUT_7POINT1_WIDE_BACK }, + { "7.1(wide-side)", 8, AV_CH_LAYOUT_7POINT1_WIDE }, + { "octagonal", 8, AV_CH_LAYOUT_OCTAGONAL }, + { "hexadecagonal", 16, AV_CH_LAYOUT_HEXADECAGONAL }, + { "downmix", 2, AV_CH_LAYOUT_STEREO_DOWNMIX, }, +}; + +static uint64_t get_channel_layout_single(const char *name, int name_len) +{ + int i; + char *end; + int64_t layout; + + for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) { + if (strlen(channel_layout_map[i].name) == name_len && + !memcmp(channel_layout_map[i].name, name, name_len)) + return channel_layout_map[i].layout; + } + for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) + if (channel_names[i].name && + strlen(channel_names[i].name) == name_len && + !memcmp(channel_names[i].name, name, name_len)) + return (int64_t)1 << i; + + errno = 0; + i = strtol(name, &end, 10); + + if (!errno && (end + 1 - name == name_len && *end == 'c')) + return av_get_default_channel_layout(i); + + errno = 0; + layout = strtoll(name, &end, 0); + if (!errno && end - name == name_len) + return FFMAX(layout, 0); + return 0; +} + +uint64_t av_get_channel_layout(const char *name) +{ + const char *n, *e; + const char *name_end = name + strlen(name); + int64_t layout = 0, layout_single; + + for (n = name; n < name_end; n = e + 1) { + for (e = n; e < name_end && *e != '+' && *e != '|'; e++); + layout_single = get_channel_layout_single(n, e - n); + if (!layout_single) + return 0; + layout |= layout_single; + } + return layout; +} + +int av_get_extended_channel_layout(const char *name, uint64_t* channel_layout, int* nb_channels) +{ + int nb = 0; + char *end; + uint64_t layout = av_get_channel_layout(name); + + if (layout) { + *channel_layout = layout; + *nb_channels = av_get_channel_layout_nb_channels(layout); + return 0; + } + + nb = strtol(name, &end, 10); + if (!errno && *end == 'C' && *(end + 1) == '\0' && nb > 0 && nb < 64) { + *channel_layout = 0; + *nb_channels = nb; + return 0; + } + + return AVERROR(EINVAL); +} + +void av_bprint_channel_layout(struct AVBPrint *bp, + int nb_channels, uint64_t channel_layout) +{ + int i; + + if (nb_channels <= 0) + nb_channels = av_get_channel_layout_nb_channels(channel_layout); + + for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) + if (nb_channels == channel_layout_map[i].nb_channels && + channel_layout == channel_layout_map[i].layout) { + av_bprintf(bp, "%s", channel_layout_map[i].name); + return; + } + + av_bprintf(bp, "%d channels", nb_channels); + if (channel_layout) { + int i, ch; + av_bprintf(bp, " ("); + for (i = 0, ch = 0; i < 64; i++) { + if ((channel_layout & (UINT64_C(1) << i))) { + const char *name = get_channel_name(i); + if (name) { + if (ch > 0) + av_bprintf(bp, "+"); + av_bprintf(bp, "%s", name); + } + ch++; + } + } + av_bprintf(bp, ")"); + } +} + +void av_get_channel_layout_string(char *buf, int buf_size, + int nb_channels, uint64_t channel_layout) +{ + AVBPrint bp; + + av_bprint_init_for_buffer(&bp, buf, buf_size); + av_bprint_channel_layout(&bp, nb_channels, channel_layout); +} + +int av_get_channel_layout_nb_channels(uint64_t channel_layout) +{ + return av_popcount64(channel_layout); +} + +int64_t av_get_default_channel_layout(int nb_channels) { + int i; + for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) + if (nb_channels == channel_layout_map[i].nb_channels) + return channel_layout_map[i].layout; + return 0; +} + +int av_get_channel_layout_channel_index(uint64_t channel_layout, + uint64_t channel) +{ + if (!(channel_layout & channel) || + av_get_channel_layout_nb_channels(channel) != 1) + return AVERROR(EINVAL); + channel_layout &= channel - 1; + return av_get_channel_layout_nb_channels(channel_layout); +} + +const char *av_get_channel_name(uint64_t channel) +{ + int i; + if (av_get_channel_layout_nb_channels(channel) != 1) + return NULL; + for (i = 0; i < 64; i++) + if ((1ULL<= FF_ARRAY_ELEMS(channel_layout_map)) + return AVERROR_EOF; + if (layout) *layout = channel_layout_map[index].layout; + if (name) *name = channel_layout_map[index].name; + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/channel_layout.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/channel_layout.h new file mode 100644 index 0000000000..50bb8f03c5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/channel_layout.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2006 Michael Niedermayer + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CHANNEL_LAYOUT_H +#define AVUTIL_CHANNEL_LAYOUT_H + +#include + +/** + * @file + * audio channel layout utility functions + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup channel_masks Audio channel masks + * + * A channel layout is a 64-bits integer with a bit set for every channel. + * The number of bits set must be equal to the number of channels. + * The value 0 means that the channel layout is not known. + * @note this data structure is not powerful enough to handle channels + * combinations that have the same channel multiple times, such as + * dual-mono. + * + * @{ + */ +#define AV_CH_FRONT_LEFT 0x00000001 +#define AV_CH_FRONT_RIGHT 0x00000002 +#define AV_CH_FRONT_CENTER 0x00000004 +#define AV_CH_LOW_FREQUENCY 0x00000008 +#define AV_CH_BACK_LEFT 0x00000010 +#define AV_CH_BACK_RIGHT 0x00000020 +#define AV_CH_FRONT_LEFT_OF_CENTER 0x00000040 +#define AV_CH_FRONT_RIGHT_OF_CENTER 0x00000080 +#define AV_CH_BACK_CENTER 0x00000100 +#define AV_CH_SIDE_LEFT 0x00000200 +#define AV_CH_SIDE_RIGHT 0x00000400 +#define AV_CH_TOP_CENTER 0x00000800 +#define AV_CH_TOP_FRONT_LEFT 0x00001000 +#define AV_CH_TOP_FRONT_CENTER 0x00002000 +#define AV_CH_TOP_FRONT_RIGHT 0x00004000 +#define AV_CH_TOP_BACK_LEFT 0x00008000 +#define AV_CH_TOP_BACK_CENTER 0x00010000 +#define AV_CH_TOP_BACK_RIGHT 0x00020000 +#define AV_CH_STEREO_LEFT 0x20000000 ///< Stereo downmix. +#define AV_CH_STEREO_RIGHT 0x40000000 ///< See AV_CH_STEREO_LEFT. +#define AV_CH_WIDE_LEFT 0x0000000080000000ULL +#define AV_CH_WIDE_RIGHT 0x0000000100000000ULL +#define AV_CH_SURROUND_DIRECT_LEFT 0x0000000200000000ULL +#define AV_CH_SURROUND_DIRECT_RIGHT 0x0000000400000000ULL +#define AV_CH_LOW_FREQUENCY_2 0x0000000800000000ULL + +/** Channel mask value used for AVCodecContext.request_channel_layout + to indicate that the user requests the channel order of the decoder output + to be the native codec channel order. */ +#define AV_CH_LAYOUT_NATIVE 0x8000000000000000ULL + +/** + * @} + * @defgroup channel_mask_c Audio channel layouts + * @{ + * */ +#define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) +#define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_3POINT1 (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_4POINT1 (AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_2 (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_5POINT1 (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_6POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT0_FRONT (AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_HEXAGONAL (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_FRONT (AV_CH_LAYOUT_6POINT0_FRONT|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_7POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT0_FRONT (AV_CH_LAYOUT_5POINT0|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT1_WIDE (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1_WIDE_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_OCTAGONAL (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_HEXADECAGONAL (AV_CH_LAYOUT_OCTAGONAL|AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT|AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_RIGHT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_FRONT_CENTER|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT) +#define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT) + +enum AVMatrixEncoding { + AV_MATRIX_ENCODING_NONE, + AV_MATRIX_ENCODING_DOLBY, + AV_MATRIX_ENCODING_DPLII, + AV_MATRIX_ENCODING_DPLIIX, + AV_MATRIX_ENCODING_DPLIIZ, + AV_MATRIX_ENCODING_DOLBYEX, + AV_MATRIX_ENCODING_DOLBYHEADPHONE, + AV_MATRIX_ENCODING_NB +}; + +/** + * Return a channel layout id that matches name, or 0 if no match is found. + * + * name can be one or several of the following notations, + * separated by '+' or '|': + * - the name of an usual channel layout (mono, stereo, 4.0, quad, 5.0, + * 5.0(side), 5.1, 5.1(side), 7.1, 7.1(wide), downmix); + * - the name of a single channel (FL, FR, FC, LFE, BL, BR, FLC, FRC, BC, + * SL, SR, TC, TFL, TFC, TFR, TBL, TBC, TBR, DL, DR); + * - a number of channels, in decimal, followed by 'c', yielding + * the default channel layout for that number of channels (@see + * av_get_default_channel_layout); + * - a channel layout mask, in hexadecimal starting with "0x" (see the + * AV_CH_* macros). + * + * Example: "stereo+FC" = "2c+FC" = "2c+1c" = "0x7" + */ +uint64_t av_get_channel_layout(const char *name); + +/** + * Return a channel layout and the number of channels based on the specified name. + * + * This function is similar to (@see av_get_channel_layout), but can also parse + * unknown channel layout specifications. + * + * @param[in] name channel layout specification string + * @param[out] channel_layout parsed channel layout (0 if unknown) + * @param[out] nb_channels number of channels + * + * @return 0 on success, AVERROR(EINVAL) if the parsing fails. + */ +int av_get_extended_channel_layout(const char *name, uint64_t* channel_layout, int* nb_channels); + +/** + * Return a description of a channel layout. + * If nb_channels is <= 0, it is guessed from the channel_layout. + * + * @param buf put here the string containing the channel layout + * @param buf_size size in bytes of the buffer + */ +void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout); + +struct AVBPrint; +/** + * Append a description of a channel layout to a bprint buffer. + */ +void av_bprint_channel_layout(struct AVBPrint *bp, int nb_channels, uint64_t channel_layout); + +/** + * Return the number of channels in the channel layout. + */ +int av_get_channel_layout_nb_channels(uint64_t channel_layout); + +/** + * Return default channel layout for a given number of channels. + */ +int64_t av_get_default_channel_layout(int nb_channels); + +/** + * Get the index of a channel in channel_layout. + * + * @param channel a channel layout describing exactly one channel which must be + * present in channel_layout. + * + * @return index of channel in channel_layout on success, a negative AVERROR + * on error. + */ +int av_get_channel_layout_channel_index(uint64_t channel_layout, + uint64_t channel); + +/** + * Get the channel with the given index in channel_layout. + */ +uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index); + +/** + * Get the name of a given channel. + * + * @return channel name on success, NULL on error. + */ +const char *av_get_channel_name(uint64_t channel); + +/** + * Get the description of a given channel. + * + * @param channel a channel layout with a single channel + * @return channel description on success, NULL on error + */ +const char *av_get_channel_description(uint64_t channel); + +/** + * Get the value and name of a standard channel layout. + * + * @param[in] index index in an internal list, starting at 0 + * @param[out] layout channel layout mask + * @param[out] name name of the layout + * @return 0 if the layout exists, + * <0 if index is beyond the limits + */ +int av_get_standard_channel_layout(unsigned index, uint64_t *layout, + const char **name); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_CHANNEL_LAYOUT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/color_utils.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/color_utils.c new file mode 100644 index 0000000000..eb8bc7b5fc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/color_utils.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2015 Kevin Wheatley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "common.h" +#include "libavutil/color_utils.h" +#include "libavutil/pixfmt.h" + +double avpriv_get_gamma_from_trc(enum AVColorTransferCharacteristic trc) +{ + double gamma; + switch (trc) { + case AVCOL_TRC_BT709: + case AVCOL_TRC_SMPTE170M: + case AVCOL_TRC_SMPTE240M: + case AVCOL_TRC_BT1361_ECG: + case AVCOL_TRC_BT2020_10: + case AVCOL_TRC_BT2020_12: + /* these share a segmented TRC, but gamma 1.961 is a close + approximation, and also more correct for decoding content */ + gamma = 1.961; + break; + case AVCOL_TRC_GAMMA22: + case AVCOL_TRC_IEC61966_2_1: + gamma = 2.2; + break; + case AVCOL_TRC_GAMMA28: + gamma = 2.8; + break; + case AVCOL_TRC_LINEAR: + gamma = 1.0; + break; + default: + gamma = 0.0; // Unknown value representation + } + return gamma; +} + +#define BT709_alpha 1.099296826809442 +#define BT709_beta 0.018053968510807 + +static double avpriv_trc_bt709(double Lc) +{ + const double a = BT709_alpha; + const double b = BT709_beta; + + return (0.0 > Lc) ? 0.0 + : ( b > Lc) ? 4.500 * Lc + : a * pow(Lc, 0.45) - (a - 1.0); +} + +static double avpriv_trc_gamma22(double Lc) +{ + return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.2); +} + +static double avpriv_trc_gamma28(double Lc) +{ + return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.8); +} + +static double avpriv_trc_smpte240M(double Lc) +{ + const double a = 1.1115; + const double b = 0.0228; + + return (0.0 > Lc) ? 0.0 + : ( b > Lc) ? 4.000 * Lc + : a * pow(Lc, 0.45) - (a - 1.0); +} + +static double avpriv_trc_linear(double Lc) +{ + return Lc; +} + +static double avpriv_trc_log(double Lc) +{ + return (0.01 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.0; +} + +static double avpriv_trc_log_sqrt(double Lc) +{ + // sqrt(10) / 1000 + return (0.00316227766 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.5; +} + +static double avpriv_trc_iec61966_2_4(double Lc) +{ + const double a = BT709_alpha; + const double b = BT709_beta; + + return (-b >= Lc) ? -a * pow(-Lc, 0.45) + (a - 1.0) + : ( b > Lc) ? 4.500 * Lc + : a * pow( Lc, 0.45) - (a - 1.0); +} + +static double avpriv_trc_bt1361(double Lc) +{ + const double a = BT709_alpha; + const double b = BT709_beta; + + return (-0.0045 >= Lc) ? -(a * pow(-4.0 * Lc, 0.45) + (a - 1.0)) / 4.0 + : ( b > Lc) ? 4.500 * Lc + : a * pow( Lc, 0.45) - (a - 1.0); +} + +static double avpriv_trc_iec61966_2_1(double Lc) +{ + const double a = 1.055; + const double b = 0.0031308; + + return (0.0 > Lc) ? 0.0 + : ( b > Lc) ? 12.92 * Lc + : a * pow(Lc, 1.0 / 2.4) - (a - 1.0); +} + +static double avpriv_trc_smpte_st2084(double Lc) +{ + const double c1 = 3424.0 / 4096.0; // c3-c2 + 1 + const double c2 = 32.0 * 2413.0 / 4096.0; + const double c3 = 32.0 * 2392.0 / 4096.0; + const double m = 128.0 * 2523.0 / 4096.0; + const double n = 0.25 * 2610.0 / 4096.0; + const double L = Lc / 10000.0; + const double Ln = pow(L, n); + + return (0.0 > Lc) ? 0.0 + : pow((c1 + c2 * Ln) / (1.0 + c3 * Ln), m); + +} + +static double avpriv_trc_smpte_st428_1(double Lc) +{ + return (0.0 > Lc) ? 0.0 + : pow(48.0 * Lc / 52.37, 1.0 / 2.6); +} + + +static double avpriv_trc_arib_std_b67(double Lc) { + // The function uses the definition from HEVC, which assumes that the peak + // white is input level = 1. (this is equivalent to scaling E = Lc * 12 and + // using the definition from the ARIB STD-B67 spec) + const double a = 0.17883277; + const double b = 0.28466892; + const double c = 0.55991073; + return (0.0 > Lc) ? 0.0 : + (Lc <= 1.0 / 12.0 ? sqrt(3.0 * Lc) : a * log(12.0 * Lc - b) + c); +} + +avpriv_trc_function avpriv_get_trc_function_from_trc(enum AVColorTransferCharacteristic trc) +{ + avpriv_trc_function func = NULL; + switch (trc) { + case AVCOL_TRC_BT709: + case AVCOL_TRC_SMPTE170M: + case AVCOL_TRC_BT2020_10: + case AVCOL_TRC_BT2020_12: + func = avpriv_trc_bt709; + break; + + case AVCOL_TRC_GAMMA22: + func = avpriv_trc_gamma22; + break; + case AVCOL_TRC_GAMMA28: + func = avpriv_trc_gamma28; + break; + + case AVCOL_TRC_SMPTE240M: + func = avpriv_trc_smpte240M; + break; + + case AVCOL_TRC_LINEAR: + func = avpriv_trc_linear; + break; + + case AVCOL_TRC_LOG: + func = avpriv_trc_log; + break; + + case AVCOL_TRC_LOG_SQRT: + func = avpriv_trc_log_sqrt; + break; + + case AVCOL_TRC_IEC61966_2_4: + func = avpriv_trc_iec61966_2_4; + break; + + case AVCOL_TRC_BT1361_ECG: + func = avpriv_trc_bt1361; + break; + + case AVCOL_TRC_IEC61966_2_1: + func = avpriv_trc_iec61966_2_1; + break; + + case AVCOL_TRC_SMPTEST2084: + func = avpriv_trc_smpte_st2084; + break; + + case AVCOL_TRC_SMPTEST428_1: + func = avpriv_trc_smpte_st428_1; + break; + + case AVCOL_TRC_ARIB_STD_B67: + func = avpriv_trc_arib_std_b67; + break; + + case AVCOL_TRC_RESERVED0: + case AVCOL_TRC_UNSPECIFIED: + case AVCOL_TRC_RESERVED: + default: + break; + } + return func; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/color_utils.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/color_utils.h new file mode 100644 index 0000000000..9529006452 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/color_utils.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015 Kevin Wheatley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_COLOR_UTILS_H +#define AVUTIL_COLOR_UTILS_H + + +#include "libavutil/pixfmt.h" + +/** + * Determine a suitable 'gamma' value to match the supplied + * AVColorTransferCharacteristic. + * + * See Apple Technical Note TN2257 (https://developer.apple.com/library/mac/technotes/tn2257/_index.html) + * + * @return Will return an approximation to the simple gamma function matching + * the supplied Transfer Characteristic, Will return 0.0 for any + * we cannot reasonably match against. + */ +double avpriv_get_gamma_from_trc(enum AVColorTransferCharacteristic trc); + + +typedef double (*avpriv_trc_function)(double); + +/** + * Determine the function needed to apply the given + * AVColorTransferCharacteristic to linear input. + * + * The function returned should expect a nominal domain and range of [0.0-1.0] + * values outside of this range maybe valid depending on the chosen + * characteristic function. + * + * @return Will return pointer to the function matching the + * supplied Transfer Characteristic. If unspecified will + * return NULL: + */ +avpriv_trc_function avpriv_get_trc_function_from_trc(enum AVColorTransferCharacteristic trc); + +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/colorspace.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/colorspace.h new file mode 100644 index 0000000000..ef6f6107d6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/colorspace.h @@ -0,0 +1,150 @@ +/* + * Colorspace conversion defines + * Copyright (c) 2001, 2002, 2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Various defines for YUV<->RGB conversion + */ + +#ifndef AVUTIL_COLORSPACE_H +#define AVUTIL_COLORSPACE_H + +#define SCALEBITS 10 +#define ONE_HALF (1 << (SCALEBITS - 1)) +#define FIX(x) ((int) ((x) * (1<> SCALEBITS];\ + g = cm[(y + g_add) >> SCALEBITS];\ + b = cm[(y + b_add) >> SCALEBITS];\ +} + +#define YUV_TO_RGB1(cb1, cr1)\ +{\ + cb = (cb1) - 128;\ + cr = (cr1) - 128;\ + r_add = FIX(1.40200) * cr + ONE_HALF;\ + g_add = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;\ + b_add = FIX(1.77200) * cb + ONE_HALF;\ +} + +#define YUV_TO_RGB2(r, g, b, y1)\ +{\ + y = (y1) << SCALEBITS;\ + r = cm[(y + r_add) >> SCALEBITS];\ + g = cm[(y + g_add) >> SCALEBITS];\ + b = cm[(y + b_add) >> SCALEBITS];\ +} + +#define Y_CCIR_TO_JPEG(y)\ + cm[((y) * FIX(255.0/219.0) + (ONE_HALF - 16 * FIX(255.0/219.0))) >> SCALEBITS] + +#define Y_JPEG_TO_CCIR(y)\ + (((y) * FIX(219.0/255.0) + (ONE_HALF + (16 << SCALEBITS))) >> SCALEBITS) + +#define C_CCIR_TO_JPEG(y)\ + cm[(((y) - 128) * FIX(127.0/112.0) + (ONE_HALF + (128 << SCALEBITS))) >> SCALEBITS] + +/* NOTE: the clamp is really necessary! */ +static inline int C_JPEG_TO_CCIR(int y) { + y = (((y - 128) * FIX(112.0/127.0) + (ONE_HALF + (128 << SCALEBITS))) >> SCALEBITS); + if (y < 16) + y = 16; + return y; +} + + +#define RGB_TO_Y_CCIR(r, g, b) \ +((FIX(0.29900*219.0/255.0) * (r) + FIX(0.58700*219.0/255.0) * (g) + \ + FIX(0.11400*219.0/255.0) * (b) + (ONE_HALF + (16 << SCALEBITS))) >> SCALEBITS) + +#define RGB_TO_U_CCIR(r1, g1, b1, shift)\ +(((- FIX(0.16874*224.0/255.0) * r1 - FIX(0.33126*224.0/255.0) * g1 + \ + FIX(0.50000*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) + +#define RGB_TO_V_CCIR(r1, g1, b1, shift)\ +(((FIX(0.50000*224.0/255.0) * r1 - FIX(0.41869*224.0/255.0) * g1 - \ + FIX(0.08131*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) + +#define RGB_TO_Y_JPEG(r, g, b) \ +(FFMIN((FIX(0.29900) * (r) + FIX(0.58700) * (g) + \ + FIX(0.11400) * (b) + (ONE_HALF)) >> SCALEBITS, 255)) + +#define RGB_TO_U_JPEG(r1, g1, b1)\ +(((- FIX(0.16874) * r1 - FIX(0.33126) * g1 + \ + FIX(0.50000) * b1 + (ONE_HALF) - 1) >> (SCALEBITS)) + 128) + +#define RGB_TO_V_JPEG(r1, g1, b1)\ +(((FIX(0.50000) * r1 - FIX(0.41869) * g1 - \ + FIX(0.08131) * b1 + (ONE_HALF) - 1) >> (SCALEBITS)) + 128) + +// Conversion macros for 8-bit RGB to YUV +// Derived from ITU-R BT.709-6 (06/2015) Item 3.5 +// https://www.itu.int/rec/R-REC-BT.709-6-201506-I/en + +#define RGB_TO_Y_BT709(r, g, b) \ +((FIX(0.21260*219.0/255.0) * (r) + FIX(0.71520*219.0/255.0) * (g) + \ + FIX(0.07220*219.0/255.0) * (b) + (ONE_HALF + (16 << SCALEBITS))) >> SCALEBITS) + +#define RGB_TO_U_BT709(r1, g1, b1, shift)\ +(((- FIX(0.11457*224.0/255.0) * r1 - FIX(0.38543*224.0/255.0) * g1 + \ + FIX(0.50000*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) + +#define RGB_TO_V_BT709(r1, g1, b1, shift)\ +(((FIX(0.50000*224.0/255.0) * r1 - FIX(0.45415*224.0/255.0) * g1 - \ + FIX(0.04585*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) + +#define RGB_TO_Y_BT709_FULL(r, g, b) \ +(FFMIN((FIX(0.21260) * (r) + FIX(0.71520) * (g) + \ + FIX(0.07220) * (b) + (ONE_HALF)) >> SCALEBITS, 255)) + +#define RGB_TO_U_BT709_FULL(r1, g1, b1)\ +(((- FIX(0.11457) * r1 - FIX(0.38543) * g1 + \ + FIX(0.50000) * b1 + (ONE_HALF) - 1) >> (SCALEBITS)) + 128) + +#define RGB_TO_V_BT709_FULL(r1, g1, b1)\ +(((FIX(0.50000) * r1 - FIX(0.45415) * g1 - \ + FIX(0.04585) * b1 + (ONE_HALF) - 1) >> (SCALEBITS)) + 128) + +#endif /* AVUTIL_COLORSPACE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/common.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/common.h new file mode 100644 index 0000000000..8db0291170 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/common.h @@ -0,0 +1,560 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal and external API header + */ + +#ifndef AVUTIL_COMMON_H +#define AVUTIL_COMMON_H + +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C) +#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "attributes.h" +#include "macros.h" +#include "version.h" +#include "libavutil/avconfig.h" + +#if AV_HAVE_BIGENDIAN +# define AV_NE(be, le) (be) +#else +# define AV_NE(be, le) (le) +#endif + +//rounded division & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +/* Fast a/(1<=0 and b>=0 */ +#define AV_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \ + : ((a) + (1<<(b)) - 1) >> (b)) +/* Backwards compat. */ +#define FF_CEIL_RSHIFT AV_CEIL_RSHIFT + +#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b)) +#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b)) + +/** + * Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they + * are not representable as absolute values of their type. This is the same + * as with *abs() + * @see FFNABS() + */ +#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) +#define FFSIGN(a) ((a) > 0 ? 1 : -1) + +/** + * Negative Absolute value. + * this works for all integers of all types. + * As with many macros, this evaluates its argument twice, it thus must not have + * a sideeffect, that is FFNABS(x++) has undefined behavior. + */ +#define FFNABS(a) ((a) <= 0 ? (a) : (-(a))) + +/** + * Comparator. + * For two numerical expressions x and y, gives 1 if x > y, -1 if x < y, and 0 + * if x == y. This is useful for instance in a qsort comparator callback. + * Furthermore, compilers are able to optimize this to branchless code, and + * there is no risk of overflow with signed types. + * As with many macros, this evaluates its argument multiple times, it thus + * must not have a side-effect. + */ +#define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) +#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) + +#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) +#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) + +/* misc math functions */ + +#ifdef HAVE_AV_CONFIG_H +# include "config.h" +# include "intmath.h" +#endif + +/* Pull in unguarded fallback defines at the end of this file. */ +#include "common.h" + +#ifndef av_log2 +av_const int av_log2(unsigned v); +#endif + +#ifndef av_log2_16bit +av_const int av_log2_16bit(unsigned v); +#endif + +/** + * Clip a signed integer value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int av_clip_c(int a, int amin, int amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a signed 64bit integer value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a signed integer value into the 0-255 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint8_t av_clip_uint8_c(int a) +{ + if (a&(~0xFF)) return (~a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -128,127 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int8_t av_clip_int8_c(int a) +{ + if ((a+0x80U) & ~0xFF) return (a>>31) ^ 0x7F; + else return a; +} + +/** + * Clip a signed integer value into the 0-65535 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint16_t av_clip_uint16_c(int a) +{ + if (a&(~0xFFFF)) return (~a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -32768,32767 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int16_t av_clip_int16_c(int a) +{ + if ((a+0x8000U) & ~0xFFFF) return (a>>31) ^ 0x7FFF; + else return a; +} + +/** + * Clip a signed 64-bit integer value into the -2147483648,2147483647 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int32_t av_clipl_int32_c(int64_t a) +{ + if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF); + else return (int32_t)a; +} + +/** + * Clip a signed integer into the -(2^p),(2^p-1) range. + * @param a value to clip + * @param p bit position to clip at + * @return clipped value + */ +static av_always_inline av_const int av_clip_intp2_c(int a, int p) +{ + if (((unsigned)a + (1 << p)) & ~((2 << p) - 1)) + return (a >> 31) ^ ((1 << p) - 1); + else + return a; +} + +/** + * Clip a signed integer to an unsigned power of two range. + * @param a value to clip + * @param p bit position to clip at + * @return clipped value + */ +static av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p) +{ + if (a & ~((1<> 31 & ((1<= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a double value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const double av_clipd_c(double a, double amin, double amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** Compute ceil(log2(x)). + * @param x value used to compute ceil(log2(x)) + * @return computed ceiling of log2(x) + */ +static av_always_inline av_const int av_ceil_log2_c(int x) +{ + return av_log2((x - 1) << 1); +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount_c(uint32_t x) +{ + x -= (x >> 1) & 0x55555555; + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x += x >> 8; + return (x + (x >> 16)) & 0x3F; +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount64_c(uint64_t x) +{ + return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32)); +} + +static av_always_inline av_const int av_parity_c(uint32_t v) +{ + return av_popcount(v) & 1; +} + +#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24)) +#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24)) + +/** + * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_BYTE Expression reading one byte from the input. + * Evaluated up to 7 times (4 for the currently + * assigned Unicode range). With a memory buffer + * input, this could be *ptr++. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + * + * @warning ERROR should not contain a loop control statement which + * could interact with the internal while loop, and should force an + * exit from the macro code (e.g. through a goto or a return) in order + * to prevent undefined results. + */ +#define GET_UTF8(val, GET_BYTE, ERROR)\ + val= (GET_BYTE);\ + {\ + uint32_t top = (val & 128) >> 1;\ + if ((val & 0xc0) == 0x80 || val >= 0xFE)\ + ERROR\ + while (val & top) {\ + int tmp= (GET_BYTE) - 128;\ + if(tmp>>6)\ + ERROR\ + val= (val<<6) + tmp;\ + top <<= 5;\ + }\ + val &= (top << 1) - 1;\ + } + +/** + * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_16BIT Expression returning two bytes of UTF-16 data converted + * to native byte order. Evaluated one or two times. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + */ +#define GET_UTF16(val, GET_16BIT, ERROR)\ + val = GET_16BIT;\ + {\ + unsigned int hi = val - 0xD800;\ + if (hi < 0x800) {\ + val = GET_16BIT - 0xDC00;\ + if (val > 0x3FFU || hi > 0x3FFU)\ + ERROR\ + val += (hi<<10) + 0x10000;\ + }\ + }\ + +/** + * @def PUT_UTF8(val, tmp, PUT_BYTE) + * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long). + * @param val is an input-only argument and should be of type uint32_t. It holds + * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If + * val is given as a function it is executed only once. + * @param tmp is a temporary variable and should be of type uint8_t. It + * represents an intermediate value during conversion that is to be + * output by PUT_BYTE. + * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination. + * It could be a function or a statement, and uses tmp as the input byte. + * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be + * executed up to 4 times for values in the valid UTF-8 range and up to + * 7 times in the general case, depending on the length of the converted + * Unicode character. + */ +#define PUT_UTF8(val, tmp, PUT_BYTE)\ + {\ + int bytes, shift;\ + uint32_t in = val;\ + if (in < 0x80) {\ + tmp = in;\ + PUT_BYTE\ + } else {\ + bytes = (av_log2(in) + 4) / 5;\ + shift = (bytes - 1) * 6;\ + tmp = (256 - (256 >> bytes)) | (in >> shift);\ + PUT_BYTE\ + while (shift >= 6) {\ + shift -= 6;\ + tmp = 0x80 | ((in >> shift) & 0x3f);\ + PUT_BYTE\ + }\ + }\ + } + +/** + * @def PUT_UTF16(val, tmp, PUT_16BIT) + * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes). + * @param val is an input-only argument and should be of type uint32_t. It holds + * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If + * val is given as a function it is executed only once. + * @param tmp is a temporary variable and should be of type uint16_t. It + * represents an intermediate value during conversion that is to be + * output by PUT_16BIT. + * @param PUT_16BIT writes the converted UTF-16 data to any proper destination + * in desired endianness. It could be a function or a statement, and uses tmp + * as the input byte. For example, PUT_BYTE could be "*output++ = tmp;" + * PUT_BYTE will be executed 1 or 2 times depending on input character. + */ +#define PUT_UTF16(val, tmp, PUT_16BIT)\ + {\ + uint32_t in = val;\ + if (in < 0x10000) {\ + tmp = in;\ + PUT_16BIT\ + } else {\ + tmp = 0xD800 | ((in - 0x10000) >> 10);\ + PUT_16BIT\ + tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\ + PUT_16BIT\ + }\ + }\ + + + +#include "mem.h" + +#ifdef HAVE_AV_CONFIG_H +# include "internal.h" +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* AVUTIL_COMMON_H */ + +/* + * The following definitions are outside the multiple inclusion guard + * to ensure they are immediately available in intmath.h. + */ + +#ifndef av_ceil_log2 +# define av_ceil_log2 av_ceil_log2_c +#endif +#ifndef av_clip +# define av_clip av_clip_c +#endif +#ifndef av_clip64 +# define av_clip64 av_clip64_c +#endif +#ifndef av_clip_uint8 +# define av_clip_uint8 av_clip_uint8_c +#endif +#ifndef av_clip_int8 +# define av_clip_int8 av_clip_int8_c +#endif +#ifndef av_clip_uint16 +# define av_clip_uint16 av_clip_uint16_c +#endif +#ifndef av_clip_int16 +# define av_clip_int16 av_clip_int16_c +#endif +#ifndef av_clipl_int32 +# define av_clipl_int32 av_clipl_int32_c +#endif +#ifndef av_clip_intp2 +# define av_clip_intp2 av_clip_intp2_c +#endif +#ifndef av_clip_uintp2 +# define av_clip_uintp2 av_clip_uintp2_c +#endif +#ifndef av_mod_uintp2 +# define av_mod_uintp2 av_mod_uintp2_c +#endif +#ifndef av_sat_add32 +# define av_sat_add32 av_sat_add32_c +#endif +#ifndef av_sat_dadd32 +# define av_sat_dadd32 av_sat_dadd32_c +#endif +#ifndef av_sat_sub32 +# define av_sat_sub32 av_sat_sub32_c +#endif +#ifndef av_sat_dsub32 +# define av_sat_dsub32 av_sat_dsub32_c +#endif +#ifndef av_clipf +# define av_clipf av_clipf_c +#endif +#ifndef av_clipd +# define av_clipd av_clipd_c +#endif +#ifndef av_popcount +# define av_popcount av_popcount_c +#endif +#ifndef av_popcount64 +# define av_popcount64 av_popcount64_c +#endif +#ifndef av_parity +# define av_parity av_parity_c +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu.c new file mode 100644 index 0000000000..6548cc3042 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu.c @@ -0,0 +1,321 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "attributes.h" +#include "cpu.h" +#include "cpu_internal.h" +#include "config.h" +#include "opt.h" +#include "common.h" + +#if HAVE_SCHED_GETAFFINITY +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif +#include +#endif +#if HAVE_GETPROCESSAFFINITYMASK || HAVE_WINRT +#include +#endif +#if HAVE_SYSCTL +#if HAVE_SYS_PARAM_H +#include +#endif +#include +#include +#endif +#if HAVE_UNISTD_H +#include +#endif + +static atomic_int cpu_flags = ATOMIC_VAR_INIT(-1); + +static int get_cpu_flags(void) +{ + if (ARCH_AARCH64) + return ff_get_cpu_flags_aarch64(); + if (ARCH_ARM) + return ff_get_cpu_flags_arm(); + if (ARCH_PPC) + return ff_get_cpu_flags_ppc(); + if (ARCH_X86) + return ff_get_cpu_flags_x86(); + return 0; +} + +void av_force_cpu_flags(int arg){ + if (ARCH_X86 && + (arg & ( AV_CPU_FLAG_3DNOW | + AV_CPU_FLAG_3DNOWEXT | + AV_CPU_FLAG_MMXEXT | + AV_CPU_FLAG_SSE | + AV_CPU_FLAG_SSE2 | + AV_CPU_FLAG_SSE2SLOW | + AV_CPU_FLAG_SSE3 | + AV_CPU_FLAG_SSE3SLOW | + AV_CPU_FLAG_SSSE3 | + AV_CPU_FLAG_SSE4 | + AV_CPU_FLAG_SSE42 | + AV_CPU_FLAG_AVX | + AV_CPU_FLAG_AVXSLOW | + AV_CPU_FLAG_XOP | + AV_CPU_FLAG_FMA3 | + AV_CPU_FLAG_FMA4 | + AV_CPU_FLAG_AVX2 | + AV_CPU_FLAG_AVX512 )) + && !(arg & AV_CPU_FLAG_MMX)) { + av_log(NULL, AV_LOG_WARNING, "MMX implied by specified flags\n"); + arg |= AV_CPU_FLAG_MMX; + } + + atomic_store_explicit(&cpu_flags, arg, memory_order_relaxed); +} + +int av_get_cpu_flags(void) +{ + int flags = atomic_load_explicit(&cpu_flags, memory_order_relaxed); + if (flags == -1) { + flags = get_cpu_flags(); + atomic_store_explicit(&cpu_flags, flags, memory_order_relaxed); + } + return flags; +} + +void av_set_cpu_flags_mask(int mask) +{ + atomic_store_explicit(&cpu_flags, get_cpu_flags() & mask, + memory_order_relaxed); +} + +int av_parse_cpu_flags(const char *s) +{ +#define CPUFLAG_MMXEXT (AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMXEXT | AV_CPU_FLAG_CMOV) +#define CPUFLAG_3DNOW (AV_CPU_FLAG_3DNOW | AV_CPU_FLAG_MMX) +#define CPUFLAG_3DNOWEXT (AV_CPU_FLAG_3DNOWEXT | CPUFLAG_3DNOW) +#define CPUFLAG_SSE (AV_CPU_FLAG_SSE | CPUFLAG_MMXEXT) +#define CPUFLAG_SSE2 (AV_CPU_FLAG_SSE2 | CPUFLAG_SSE) +#define CPUFLAG_SSE2SLOW (AV_CPU_FLAG_SSE2SLOW | CPUFLAG_SSE2) +#define CPUFLAG_SSE3 (AV_CPU_FLAG_SSE3 | CPUFLAG_SSE2) +#define CPUFLAG_SSE3SLOW (AV_CPU_FLAG_SSE3SLOW | CPUFLAG_SSE3) +#define CPUFLAG_SSSE3 (AV_CPU_FLAG_SSSE3 | CPUFLAG_SSE3) +#define CPUFLAG_SSE4 (AV_CPU_FLAG_SSE4 | CPUFLAG_SSSE3) +#define CPUFLAG_SSE42 (AV_CPU_FLAG_SSE42 | CPUFLAG_SSE4) +#define CPUFLAG_AVX (AV_CPU_FLAG_AVX | CPUFLAG_SSE42) +#define CPUFLAG_AVXSLOW (AV_CPU_FLAG_AVXSLOW | CPUFLAG_AVX) +#define CPUFLAG_XOP (AV_CPU_FLAG_XOP | CPUFLAG_AVX) +#define CPUFLAG_FMA3 (AV_CPU_FLAG_FMA3 | CPUFLAG_AVX) +#define CPUFLAG_FMA4 (AV_CPU_FLAG_FMA4 | CPUFLAG_AVX) +#define CPUFLAG_AVX2 (AV_CPU_FLAG_AVX2 | CPUFLAG_AVX) +#define CPUFLAG_BMI2 (AV_CPU_FLAG_BMI2 | AV_CPU_FLAG_BMI1) +#define CPUFLAG_AESNI (AV_CPU_FLAG_AESNI | CPUFLAG_SSE42) +#define CPUFLAG_AVX512 (AV_CPU_FLAG_AVX512 | CPUFLAG_AVX2) + static const AVOption cpuflags_opts[] = { + { "flags" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" }, +#if ARCH_PPC + { "altivec" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ALTIVEC }, .unit = "flags" }, +#elif ARCH_X86 + { "mmx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX }, .unit = "flags" }, + { "mmxext" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_MMXEXT }, .unit = "flags" }, + { "sse" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE }, .unit = "flags" }, + { "sse2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE2 }, .unit = "flags" }, + { "sse2slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE2SLOW }, .unit = "flags" }, + { "sse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE3 }, .unit = "flags" }, + { "sse3slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE3SLOW }, .unit = "flags" }, + { "ssse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSSE3 }, .unit = "flags" }, + { "atom" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ATOM }, .unit = "flags" }, + { "sse4.1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE4 }, .unit = "flags" }, + { "sse4.2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_SSE42 }, .unit = "flags" }, + { "avx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_AVX }, .unit = "flags" }, + { "avxslow" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_AVXSLOW }, .unit = "flags" }, + { "xop" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_XOP }, .unit = "flags" }, + { "fma3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_FMA3 }, .unit = "flags" }, + { "fma4" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_FMA4 }, .unit = "flags" }, + { "avx2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_AVX2 }, .unit = "flags" }, + { "bmi1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_BMI1 }, .unit = "flags" }, + { "bmi2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_BMI2 }, .unit = "flags" }, + { "3dnow" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_3DNOW }, .unit = "flags" }, + { "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_3DNOWEXT }, .unit = "flags" }, + { "cmov", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_CMOV }, .unit = "flags" }, + { "aesni" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_AESNI }, .unit = "flags" }, + { "avx512" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_AVX512 }, .unit = "flags" }, +#elif ARCH_ARM + { "armv5te", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV5TE }, .unit = "flags" }, + { "armv6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6 }, .unit = "flags" }, + { "armv6t2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6T2 }, .unit = "flags" }, + { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, + { "vfp_vm", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP_VM }, .unit = "flags" }, + { "vfpv3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFPV3 }, .unit = "flags" }, + { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, +#elif ARCH_AARCH64 + { "armv8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV8 }, .unit = "flags" }, + { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, + { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, +#endif + { NULL }, + }; + static const AVClass class = { + .class_name = "cpuflags", + .item_name = av_default_item_name, + .option = cpuflags_opts, + .version = LIBAVUTIL_VERSION_INT, + }; + + int flags = 0, ret; + const AVClass *pclass = &class; + + if ((ret = av_opt_eval_flags(&pclass, &cpuflags_opts[0], s, &flags)) < 0) + return ret; + + return flags & INT_MAX; +} + +int av_parse_cpu_caps(unsigned *flags, const char *s) +{ + static const AVOption cpuflags_opts[] = { + { "flags" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" }, +#if ARCH_PPC + { "altivec" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ALTIVEC }, .unit = "flags" }, +#elif ARCH_X86 + { "mmx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX }, .unit = "flags" }, + { "mmx2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX2 }, .unit = "flags" }, + { "mmxext" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX2 }, .unit = "flags" }, + { "sse" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE }, .unit = "flags" }, + { "sse2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE2 }, .unit = "flags" }, + { "sse2slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE2SLOW }, .unit = "flags" }, + { "sse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE3 }, .unit = "flags" }, + { "sse3slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE3SLOW }, .unit = "flags" }, + { "ssse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSSE3 }, .unit = "flags" }, + { "atom" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ATOM }, .unit = "flags" }, + { "sse4.1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE4 }, .unit = "flags" }, + { "sse4.2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE42 }, .unit = "flags" }, + { "avx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX }, .unit = "flags" }, + { "avxslow" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVXSLOW }, .unit = "flags" }, + { "xop" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_XOP }, .unit = "flags" }, + { "fma3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_FMA3 }, .unit = "flags" }, + { "fma4" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_FMA4 }, .unit = "flags" }, + { "avx2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX2 }, .unit = "flags" }, + { "bmi1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_BMI1 }, .unit = "flags" }, + { "bmi2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_BMI2 }, .unit = "flags" }, + { "3dnow" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_3DNOW }, .unit = "flags" }, + { "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_3DNOWEXT }, .unit = "flags" }, + { "cmov", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_CMOV }, .unit = "flags" }, + { "aesni", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AESNI }, .unit = "flags" }, + { "avx512" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX512 }, .unit = "flags" }, + +#define CPU_FLAG_P2 AV_CPU_FLAG_CMOV | AV_CPU_FLAG_MMX +#define CPU_FLAG_P3 CPU_FLAG_P2 | AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_SSE +#define CPU_FLAG_P4 CPU_FLAG_P3| AV_CPU_FLAG_SSE2 + { "pentium2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P2 }, .unit = "flags" }, + { "pentium3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P3 }, .unit = "flags" }, + { "pentium4", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P4 }, .unit = "flags" }, + +#define CPU_FLAG_K62 AV_CPU_FLAG_MMX | AV_CPU_FLAG_3DNOW +#define CPU_FLAG_ATHLON CPU_FLAG_K62 | AV_CPU_FLAG_CMOV | AV_CPU_FLAG_3DNOWEXT | AV_CPU_FLAG_MMX2 +#define CPU_FLAG_ATHLONXP CPU_FLAG_ATHLON | AV_CPU_FLAG_SSE +#define CPU_FLAG_K8 CPU_FLAG_ATHLONXP | AV_CPU_FLAG_SSE2 + { "k6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX }, .unit = "flags" }, + { "k62", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_K62 }, .unit = "flags" }, + { "athlon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_ATHLON }, .unit = "flags" }, + { "athlonxp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_ATHLONXP }, .unit = "flags" }, + { "k8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_K8 }, .unit = "flags" }, +#elif ARCH_ARM + { "armv5te", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV5TE }, .unit = "flags" }, + { "armv6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6 }, .unit = "flags" }, + { "armv6t2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6T2 }, .unit = "flags" }, + { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, + { "vfp_vm", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP_VM }, .unit = "flags" }, + { "vfpv3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFPV3 }, .unit = "flags" }, + { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, + { "setend", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SETEND }, .unit = "flags" }, +#elif ARCH_AARCH64 + { "armv8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV8 }, .unit = "flags" }, + { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, + { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, +#endif + { NULL }, + }; + static const AVClass class = { + .class_name = "cpuflags", + .item_name = av_default_item_name, + .option = cpuflags_opts, + .version = LIBAVUTIL_VERSION_INT, + }; + const AVClass *pclass = &class; + + return av_opt_eval_flags(&pclass, &cpuflags_opts[0], s, flags); +} + +int av_cpu_count(void) +{ + static volatile int printed; + + int nb_cpus = 1; +#if HAVE_WINRT + SYSTEM_INFO sysinfo; +#endif +#if HAVE_SCHED_GETAFFINITY && defined(CPU_COUNT) + cpu_set_t cpuset; + + CPU_ZERO(&cpuset); + + if (!sched_getaffinity(0, sizeof(cpuset), &cpuset)) + nb_cpus = CPU_COUNT(&cpuset); +#elif HAVE_GETPROCESSAFFINITYMASK + DWORD_PTR proc_aff, sys_aff; + if (GetProcessAffinityMask(GetCurrentProcess(), &proc_aff, &sys_aff)) + nb_cpus = av_popcount64(proc_aff); +#elif HAVE_SYSCTL && defined(HW_NCPU) + int mib[2] = { CTL_HW, HW_NCPU }; + size_t len = sizeof(nb_cpus); + + if (sysctl(mib, 2, &nb_cpus, &len, NULL, 0) == -1) + nb_cpus = 0; +#elif HAVE_SYSCONF && defined(_SC_NPROC_ONLN) + nb_cpus = sysconf(_SC_NPROC_ONLN); +#elif HAVE_SYSCONF && defined(_SC_NPROCESSORS_ONLN) + nb_cpus = sysconf(_SC_NPROCESSORS_ONLN); +#elif HAVE_WINRT + GetNativeSystemInfo(&sysinfo); + nb_cpus = sysinfo.dwNumberOfProcessors; +#endif + + if (!printed) { + av_log(NULL, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus); + printed = 1; + } + + return nb_cpus; +} + +size_t av_cpu_max_align(void) +{ + if (ARCH_AARCH64) + return ff_get_cpu_max_align_aarch64(); + if (ARCH_ARM) + return ff_get_cpu_max_align_arm(); + if (ARCH_PPC) + return ff_get_cpu_max_align_ppc(); + if (ARCH_X86) + return ff_get_cpu_max_align_x86(); + + return 8; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu.h new file mode 100644 index 0000000000..8bb9eb606b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CPU_H +#define AVUTIL_CPU_H + +#include + +#include "attributes.h" + +#define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */ + + /* lower 16 bits - CPU features */ +#define AV_CPU_FLAG_MMX 0x0001 ///< standard MMX +#define AV_CPU_FLAG_MMXEXT 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_3DNOW 0x0004 ///< AMD 3DNOW +#define AV_CPU_FLAG_SSE 0x0008 ///< SSE functions +#define AV_CPU_FLAG_SSE2 0x0010 ///< PIV SSE2 functions +#define AV_CPU_FLAG_SSE2SLOW 0x40000000 ///< SSE2 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_3DNOWEXT 0x0020 ///< AMD 3DNowExt +#define AV_CPU_FLAG_SSE3 0x0040 ///< Prescott SSE3 functions +#define AV_CPU_FLAG_SSE3SLOW 0x20000000 ///< SSE3 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_SSSE3 0x0080 ///< Conroe SSSE3 functions +#define AV_CPU_FLAG_SSSE3SLOW 0x4000000 ///< SSSE3 supported, but usually not faster +#define AV_CPU_FLAG_ATOM 0x10000000 ///< Atom processor, some SSSE3 instructions are slower +#define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions +#define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions +#define AV_CPU_FLAG_AESNI 0x80000 ///< Advanced Encryption Standard functions +#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_AVXSLOW 0x8000000 ///< AVX supported, but slow when using YMM registers (e.g. Bulldozer) +#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions +#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions +#define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction +#define AV_CPU_FLAG_AVX2 0x8000 ///< AVX2 functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_FMA3 0x10000 ///< Haswell FMA3 functions +#define AV_CPU_FLAG_BMI1 0x20000 ///< Bit Manipulation Instruction Set 1 +#define AV_CPU_FLAG_BMI2 0x40000 ///< Bit Manipulation Instruction Set 2 +#define AV_CPU_FLAG_AVX512 0x100000 ///< AVX-512 functions: requires OS support even if YMM/ZMM registers aren't used + +#define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard +#define AV_CPU_FLAG_VSX 0x0002 ///< ISA 2.06 +#define AV_CPU_FLAG_POWER8 0x0004 ///< ISA 2.07 + +#define AV_CPU_FLAG_ARMV5TE (1 << 0) +#define AV_CPU_FLAG_ARMV6 (1 << 1) +#define AV_CPU_FLAG_ARMV6T2 (1 << 2) +#define AV_CPU_FLAG_VFP (1 << 3) +#define AV_CPU_FLAG_VFPV3 (1 << 4) +#define AV_CPU_FLAG_NEON (1 << 5) +#define AV_CPU_FLAG_ARMV8 (1 << 6) +#define AV_CPU_FLAG_VFP_VM (1 << 7) ///< VFPv2 vector mode, deprecated in ARMv7-A and unavailable in various CPUs implementations +#define AV_CPU_FLAG_SETEND (1 <<16) + +/** + * Return the flags which specify extensions supported by the CPU. + * The returned value is affected by av_force_cpu_flags() if that was used + * before. So av_get_cpu_flags() can easily be used in an application to + * detect the enabled cpu flags. + */ +int av_get_cpu_flags(void); + +/** + * Disables cpu detection and forces the specified flags. + * -1 is a special case that disables forcing of specific flags. + */ +void av_force_cpu_flags(int flags); + +/** + * Set a mask on flags returned by av_get_cpu_flags(). + * This function is mainly useful for testing. + * Please use av_force_cpu_flags() and av_get_cpu_flags() instead which are more flexible + */ +attribute_deprecated void av_set_cpu_flags_mask(int mask); + +/** + * Parse CPU flags from a string. + * + * The returned flags contain the specified flags as well as related unspecified flags. + * + * This function exists only for compatibility with libav. + * Please use av_parse_cpu_caps() when possible. + * @return a combination of AV_CPU_* flags, negative on error. + */ +attribute_deprecated +int av_parse_cpu_flags(const char *s); + +/** + * Parse CPU caps from a string and update the given AV_CPU_* flags based on that. + * + * @return negative on error. + */ +int av_parse_cpu_caps(unsigned *flags, const char *s); + +/** + * @return the number of logical CPU cores present. + */ +int av_cpu_count(void); + +/** + * Get the maximum data alignment that may be required by FFmpeg. + * + * Note that this is affected by the build configuration and the CPU flags mask, + * so e.g. if the CPU supports AVX, but libavutil has been built with + * --disable-avx or the AV_CPU_FLAG_AVX flag has been disabled through + * av_set_cpu_flags_mask(), then this function will behave as if AVX is not + * present. + */ +size_t av_cpu_max_align(void); + +#endif /* AVUTIL_CPU_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu_internal.h new file mode 100644 index 0000000000..37122d1c5f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/cpu_internal.h @@ -0,0 +1,54 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CPU_INTERNAL_H +#define AVUTIL_CPU_INTERNAL_H + +#include "config.h" + +#include "cpu.h" + +#define CPUEXT_SUFFIX(flags, suffix, cpuext) \ + (HAVE_ ## cpuext ## suffix && ((flags) & AV_CPU_FLAG_ ## cpuext)) + +#define CPUEXT_SUFFIX_FAST2(flags, suffix, cpuext, slow_cpuext) \ + (HAVE_ ## cpuext ## suffix && ((flags) & AV_CPU_FLAG_ ## cpuext) && \ + !((flags) & AV_CPU_FLAG_ ## slow_cpuext ## SLOW)) + +#define CPUEXT_SUFFIX_SLOW2(flags, suffix, cpuext, slow_cpuext) \ + (HAVE_ ## cpuext ## suffix && ((flags) & AV_CPU_FLAG_ ## cpuext) && \ + ((flags) & AV_CPU_FLAG_ ## slow_cpuext ## SLOW)) + +#define CPUEXT_SUFFIX_FAST(flags, suffix, cpuext) CPUEXT_SUFFIX_FAST2(flags, suffix, cpuext, cpuext) +#define CPUEXT_SUFFIX_SLOW(flags, suffix, cpuext) CPUEXT_SUFFIX_SLOW2(flags, suffix, cpuext, cpuext) + +#define CPUEXT(flags, cpuext) CPUEXT_SUFFIX(flags, , cpuext) +#define CPUEXT_FAST(flags, cpuext) CPUEXT_SUFFIX_FAST(flags, , cpuext) +#define CPUEXT_SLOW(flags, cpuext) CPUEXT_SUFFIX_SLOW(flags, , cpuext) + +int ff_get_cpu_flags_aarch64(void); +int ff_get_cpu_flags_arm(void); +int ff_get_cpu_flags_ppc(void); +int ff_get_cpu_flags_x86(void); + +size_t ff_get_cpu_max_align_aarch64(void); +size_t ff_get_cpu_max_align_arm(void); +size_t ff_get_cpu_max_align_ppc(void); +size_t ff_get_cpu_max_align_x86(void); + +#endif /* AVUTIL_CPU_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/crc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/crc.c new file mode 100644 index 0000000000..c45ea63a62 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/crc.c @@ -0,0 +1,415 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "thread.h" +#include "avassert.h" +#include "bswap.h" +#include "common.h" +#include "crc.h" + +#if CONFIG_HARDCODED_TABLES +static const AVCRC av_crc_table[AV_CRC_MAX][257] = { + [AV_CRC_8_ATM] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, + 0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9, + 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, + 0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE, + 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, + 0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80, + 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, + 0xDD, 0xDA, 0xD3, 0xD4, 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10, + 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, + 0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE, 0xA9, 0xA0, 0xA7, + 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, + 0xFA, 0xFD, 0xF4, 0xF3, 0x01 + }, + [AV_CRC_8_EBU] = { + 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, 0xE8, 0xF5, 0xD2, 0xCF, + 0x9C, 0x81, 0xA6, 0xBB, 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E, + 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76, 0x87, 0x9A, 0xBD, 0xA0, + 0xF3, 0xEE, 0xC9, 0xD4, 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C, + 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19, 0xA2, 0xBF, 0x98, 0x85, + 0xD6, 0xCB, 0xEC, 0xF1, 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40, + 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8, 0xDE, 0xC3, 0xE4, 0xF9, + 0xAA, 0xB7, 0x90, 0x8D, 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65, + 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7, 0x7C, 0x61, 0x46, 0x5B, + 0x08, 0x15, 0x32, 0x2F, 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A, + 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2, 0x26, 0x3B, 0x1C, 0x01, + 0x52, 0x4F, 0x68, 0x75, 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D, + 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8, 0x03, 0x1E, 0x39, 0x24, + 0x77, 0x6A, 0x4D, 0x50, 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2, + 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A, 0x6C, 0x71, 0x56, 0x4B, + 0x18, 0x05, 0x22, 0x3F, 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7, + 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66, 0xDD, 0xC0, 0xE7, 0xFA, + 0xA9, 0xB4, 0x93, 0x8E, 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB, + 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43, 0xB2, 0xAF, 0x88, 0x95, + 0xC6, 0xDB, 0xFC, 0xE1, 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09, + 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C, 0x97, 0x8A, 0xAD, 0xB0, + 0xE3, 0xFE, 0xD9, 0xC4, 0x01 + }, + [AV_CRC_16_ANSI] = { + 0x0000, 0x0580, 0x0F80, 0x0A00, 0x1B80, 0x1E00, 0x1400, 0x1180, + 0x3380, 0x3600, 0x3C00, 0x3980, 0x2800, 0x2D80, 0x2780, 0x2200, + 0x6380, 0x6600, 0x6C00, 0x6980, 0x7800, 0x7D80, 0x7780, 0x7200, + 0x5000, 0x5580, 0x5F80, 0x5A00, 0x4B80, 0x4E00, 0x4400, 0x4180, + 0xC380, 0xC600, 0xCC00, 0xC980, 0xD800, 0xDD80, 0xD780, 0xD200, + 0xF000, 0xF580, 0xFF80, 0xFA00, 0xEB80, 0xEE00, 0xE400, 0xE180, + 0xA000, 0xA580, 0xAF80, 0xAA00, 0xBB80, 0xBE00, 0xB400, 0xB180, + 0x9380, 0x9600, 0x9C00, 0x9980, 0x8800, 0x8D80, 0x8780, 0x8200, + 0x8381, 0x8601, 0x8C01, 0x8981, 0x9801, 0x9D81, 0x9781, 0x9201, + 0xB001, 0xB581, 0xBF81, 0xBA01, 0xAB81, 0xAE01, 0xA401, 0xA181, + 0xE001, 0xE581, 0xEF81, 0xEA01, 0xFB81, 0xFE01, 0xF401, 0xF181, + 0xD381, 0xD601, 0xDC01, 0xD981, 0xC801, 0xCD81, 0xC781, 0xC201, + 0x4001, 0x4581, 0x4F81, 0x4A01, 0x5B81, 0x5E01, 0x5401, 0x5181, + 0x7381, 0x7601, 0x7C01, 0x7981, 0x6801, 0x6D81, 0x6781, 0x6201, + 0x2381, 0x2601, 0x2C01, 0x2981, 0x3801, 0x3D81, 0x3781, 0x3201, + 0x1001, 0x1581, 0x1F81, 0x1A01, 0x0B81, 0x0E01, 0x0401, 0x0181, + 0x0383, 0x0603, 0x0C03, 0x0983, 0x1803, 0x1D83, 0x1783, 0x1203, + 0x3003, 0x3583, 0x3F83, 0x3A03, 0x2B83, 0x2E03, 0x2403, 0x2183, + 0x6003, 0x6583, 0x6F83, 0x6A03, 0x7B83, 0x7E03, 0x7403, 0x7183, + 0x5383, 0x5603, 0x5C03, 0x5983, 0x4803, 0x4D83, 0x4783, 0x4203, + 0xC003, 0xC583, 0xCF83, 0xCA03, 0xDB83, 0xDE03, 0xD403, 0xD183, + 0xF383, 0xF603, 0xFC03, 0xF983, 0xE803, 0xED83, 0xE783, 0xE203, + 0xA383, 0xA603, 0xAC03, 0xA983, 0xB803, 0xBD83, 0xB783, 0xB203, + 0x9003, 0x9583, 0x9F83, 0x9A03, 0x8B83, 0x8E03, 0x8403, 0x8183, + 0x8002, 0x8582, 0x8F82, 0x8A02, 0x9B82, 0x9E02, 0x9402, 0x9182, + 0xB382, 0xB602, 0xBC02, 0xB982, 0xA802, 0xAD82, 0xA782, 0xA202, + 0xE382, 0xE602, 0xEC02, 0xE982, 0xF802, 0xFD82, 0xF782, 0xF202, + 0xD002, 0xD582, 0xDF82, 0xDA02, 0xCB82, 0xCE02, 0xC402, 0xC182, + 0x4382, 0x4602, 0x4C02, 0x4982, 0x5802, 0x5D82, 0x5782, 0x5202, + 0x7002, 0x7582, 0x7F82, 0x7A02, 0x6B82, 0x6E02, 0x6402, 0x6182, + 0x2002, 0x2582, 0x2F82, 0x2A02, 0x3B82, 0x3E02, 0x3402, 0x3182, + 0x1382, 0x1602, 0x1C02, 0x1982, 0x0802, 0x0D82, 0x0782, 0x0202, + 0x0001 + }, + [AV_CRC_16_CCITT] = { + 0x0000, 0x2110, 0x4220, 0x6330, 0x8440, 0xA550, 0xC660, 0xE770, + 0x0881, 0x2991, 0x4AA1, 0x6BB1, 0x8CC1, 0xADD1, 0xCEE1, 0xEFF1, + 0x3112, 0x1002, 0x7332, 0x5222, 0xB552, 0x9442, 0xF772, 0xD662, + 0x3993, 0x1883, 0x7BB3, 0x5AA3, 0xBDD3, 0x9CC3, 0xFFF3, 0xDEE3, + 0x6224, 0x4334, 0x2004, 0x0114, 0xE664, 0xC774, 0xA444, 0x8554, + 0x6AA5, 0x4BB5, 0x2885, 0x0995, 0xEEE5, 0xCFF5, 0xACC5, 0x8DD5, + 0x5336, 0x7226, 0x1116, 0x3006, 0xD776, 0xF666, 0x9556, 0xB446, + 0x5BB7, 0x7AA7, 0x1997, 0x3887, 0xDFF7, 0xFEE7, 0x9DD7, 0xBCC7, + 0xC448, 0xE558, 0x8668, 0xA778, 0x4008, 0x6118, 0x0228, 0x2338, + 0xCCC9, 0xEDD9, 0x8EE9, 0xAFF9, 0x4889, 0x6999, 0x0AA9, 0x2BB9, + 0xF55A, 0xD44A, 0xB77A, 0x966A, 0x711A, 0x500A, 0x333A, 0x122A, + 0xFDDB, 0xDCCB, 0xBFFB, 0x9EEB, 0x799B, 0x588B, 0x3BBB, 0x1AAB, + 0xA66C, 0x877C, 0xE44C, 0xC55C, 0x222C, 0x033C, 0x600C, 0x411C, + 0xAEED, 0x8FFD, 0xECCD, 0xCDDD, 0x2AAD, 0x0BBD, 0x688D, 0x499D, + 0x977E, 0xB66E, 0xD55E, 0xF44E, 0x133E, 0x322E, 0x511E, 0x700E, + 0x9FFF, 0xBEEF, 0xDDDF, 0xFCCF, 0x1BBF, 0x3AAF, 0x599F, 0x788F, + 0x8891, 0xA981, 0xCAB1, 0xEBA1, 0x0CD1, 0x2DC1, 0x4EF1, 0x6FE1, + 0x8010, 0xA100, 0xC230, 0xE320, 0x0450, 0x2540, 0x4670, 0x6760, + 0xB983, 0x9893, 0xFBA3, 0xDAB3, 0x3DC3, 0x1CD3, 0x7FE3, 0x5EF3, + 0xB102, 0x9012, 0xF322, 0xD232, 0x3542, 0x1452, 0x7762, 0x5672, + 0xEAB5, 0xCBA5, 0xA895, 0x8985, 0x6EF5, 0x4FE5, 0x2CD5, 0x0DC5, + 0xE234, 0xC324, 0xA014, 0x8104, 0x6674, 0x4764, 0x2454, 0x0544, + 0xDBA7, 0xFAB7, 0x9987, 0xB897, 0x5FE7, 0x7EF7, 0x1DC7, 0x3CD7, + 0xD326, 0xF236, 0x9106, 0xB016, 0x5766, 0x7676, 0x1546, 0x3456, + 0x4CD9, 0x6DC9, 0x0EF9, 0x2FE9, 0xC899, 0xE989, 0x8AB9, 0xABA9, + 0x4458, 0x6548, 0x0678, 0x2768, 0xC018, 0xE108, 0x8238, 0xA328, + 0x7DCB, 0x5CDB, 0x3FEB, 0x1EFB, 0xF98B, 0xD89B, 0xBBAB, 0x9ABB, + 0x754A, 0x545A, 0x376A, 0x167A, 0xF10A, 0xD01A, 0xB32A, 0x923A, + 0x2EFD, 0x0FED, 0x6CDD, 0x4DCD, 0xAABD, 0x8BAD, 0xE89D, 0xC98D, + 0x267C, 0x076C, 0x645C, 0x454C, 0xA23C, 0x832C, 0xE01C, 0xC10C, + 0x1FEF, 0x3EFF, 0x5DCF, 0x7CDF, 0x9BAF, 0xBABF, 0xD98F, 0xF89F, + 0x176E, 0x367E, 0x554E, 0x745E, 0x932E, 0xB23E, 0xD10E, 0xF01E, + 0x0001 + }, + [AV_CRC_24_IEEE] = { + 0x000000, 0xFB4C86, 0x0DD58A, 0xF6990C, 0xE1E693, 0x1AAA15, 0xEC3319, + 0x177F9F, 0x3981A1, 0xC2CD27, 0x34542B, 0xCF18AD, 0xD86732, 0x232BB4, + 0xD5B2B8, 0x2EFE3E, 0x894EC5, 0x720243, 0x849B4F, 0x7FD7C9, 0x68A856, + 0x93E4D0, 0x657DDC, 0x9E315A, 0xB0CF64, 0x4B83E2, 0xBD1AEE, 0x465668, + 0x5129F7, 0xAA6571, 0x5CFC7D, 0xA7B0FB, 0xE9D10C, 0x129D8A, 0xE40486, + 0x1F4800, 0x08379F, 0xF37B19, 0x05E215, 0xFEAE93, 0xD050AD, 0x2B1C2B, + 0xDD8527, 0x26C9A1, 0x31B63E, 0xCAFAB8, 0x3C63B4, 0xC72F32, 0x609FC9, + 0x9BD34F, 0x6D4A43, 0x9606C5, 0x81795A, 0x7A35DC, 0x8CACD0, 0x77E056, + 0x591E68, 0xA252EE, 0x54CBE2, 0xAF8764, 0xB8F8FB, 0x43B47D, 0xB52D71, + 0x4E61F7, 0xD2A319, 0x29EF9F, 0xDF7693, 0x243A15, 0x33458A, 0xC8090C, + 0x3E9000, 0xC5DC86, 0xEB22B8, 0x106E3E, 0xE6F732, 0x1DBBB4, 0x0AC42B, + 0xF188AD, 0x0711A1, 0xFC5D27, 0x5BEDDC, 0xA0A15A, 0x563856, 0xAD74D0, + 0xBA0B4F, 0x4147C9, 0xB7DEC5, 0x4C9243, 0x626C7D, 0x9920FB, 0x6FB9F7, + 0x94F571, 0x838AEE, 0x78C668, 0x8E5F64, 0x7513E2, 0x3B7215, 0xC03E93, + 0x36A79F, 0xCDEB19, 0xDA9486, 0x21D800, 0xD7410C, 0x2C0D8A, 0x02F3B4, + 0xF9BF32, 0x0F263E, 0xF46AB8, 0xE31527, 0x1859A1, 0xEEC0AD, 0x158C2B, + 0xB23CD0, 0x497056, 0xBFE95A, 0x44A5DC, 0x53DA43, 0xA896C5, 0x5E0FC9, + 0xA5434F, 0x8BBD71, 0x70F1F7, 0x8668FB, 0x7D247D, 0x6A5BE2, 0x911764, + 0x678E68, 0x9CC2EE, 0xA44733, 0x5F0BB5, 0xA992B9, 0x52DE3F, 0x45A1A0, + 0xBEED26, 0x48742A, 0xB338AC, 0x9DC692, 0x668A14, 0x901318, 0x6B5F9E, + 0x7C2001, 0x876C87, 0x71F58B, 0x8AB90D, 0x2D09F6, 0xD64570, 0x20DC7C, + 0xDB90FA, 0xCCEF65, 0x37A3E3, 0xC13AEF, 0x3A7669, 0x148857, 0xEFC4D1, + 0x195DDD, 0xE2115B, 0xF56EC4, 0x0E2242, 0xF8BB4E, 0x03F7C8, 0x4D963F, + 0xB6DAB9, 0x4043B5, 0xBB0F33, 0xAC70AC, 0x573C2A, 0xA1A526, 0x5AE9A0, + 0x74179E, 0x8F5B18, 0x79C214, 0x828E92, 0x95F10D, 0x6EBD8B, 0x982487, + 0x636801, 0xC4D8FA, 0x3F947C, 0xC90D70, 0x3241F6, 0x253E69, 0xDE72EF, + 0x28EBE3, 0xD3A765, 0xFD595B, 0x0615DD, 0xF08CD1, 0x0BC057, 0x1CBFC8, + 0xE7F34E, 0x116A42, 0xEA26C4, 0x76E42A, 0x8DA8AC, 0x7B31A0, 0x807D26, + 0x9702B9, 0x6C4E3F, 0x9AD733, 0x619BB5, 0x4F658B, 0xB4290D, 0x42B001, + 0xB9FC87, 0xAE8318, 0x55CF9E, 0xA35692, 0x581A14, 0xFFAAEF, 0x04E669, + 0xF27F65, 0x0933E3, 0x1E4C7C, 0xE500FA, 0x1399F6, 0xE8D570, 0xC62B4E, + 0x3D67C8, 0xCBFEC4, 0x30B242, 0x27CDDD, 0xDC815B, 0x2A1857, 0xD154D1, + 0x9F3526, 0x6479A0, 0x92E0AC, 0x69AC2A, 0x7ED3B5, 0x859F33, 0x73063F, + 0x884AB9, 0xA6B487, 0x5DF801, 0xAB610D, 0x502D8B, 0x475214, 0xBC1E92, + 0x4A879E, 0xB1CB18, 0x167BE3, 0xED3765, 0x1BAE69, 0xE0E2EF, 0xF79D70, + 0x0CD1F6, 0xFA48FA, 0x01047C, 0x2FFA42, 0xD4B6C4, 0x222FC8, 0xD9634E, + 0xCE1CD1, 0x355057, 0xC3C95B, 0x3885DD, 0x000001, + }, + [AV_CRC_32_IEEE] = { + 0x00000000, 0xB71DC104, 0x6E3B8209, 0xD926430D, 0xDC760413, 0x6B6BC517, + 0xB24D861A, 0x0550471E, 0xB8ED0826, 0x0FF0C922, 0xD6D68A2F, 0x61CB4B2B, + 0x649B0C35, 0xD386CD31, 0x0AA08E3C, 0xBDBD4F38, 0x70DB114C, 0xC7C6D048, + 0x1EE09345, 0xA9FD5241, 0xACAD155F, 0x1BB0D45B, 0xC2969756, 0x758B5652, + 0xC836196A, 0x7F2BD86E, 0xA60D9B63, 0x11105A67, 0x14401D79, 0xA35DDC7D, + 0x7A7B9F70, 0xCD665E74, 0xE0B62398, 0x57ABE29C, 0x8E8DA191, 0x39906095, + 0x3CC0278B, 0x8BDDE68F, 0x52FBA582, 0xE5E66486, 0x585B2BBE, 0xEF46EABA, + 0x3660A9B7, 0x817D68B3, 0x842D2FAD, 0x3330EEA9, 0xEA16ADA4, 0x5D0B6CA0, + 0x906D32D4, 0x2770F3D0, 0xFE56B0DD, 0x494B71D9, 0x4C1B36C7, 0xFB06F7C3, + 0x2220B4CE, 0x953D75CA, 0x28803AF2, 0x9F9DFBF6, 0x46BBB8FB, 0xF1A679FF, + 0xF4F63EE1, 0x43EBFFE5, 0x9ACDBCE8, 0x2DD07DEC, 0x77708634, 0xC06D4730, + 0x194B043D, 0xAE56C539, 0xAB068227, 0x1C1B4323, 0xC53D002E, 0x7220C12A, + 0xCF9D8E12, 0x78804F16, 0xA1A60C1B, 0x16BBCD1F, 0x13EB8A01, 0xA4F64B05, + 0x7DD00808, 0xCACDC90C, 0x07AB9778, 0xB0B6567C, 0x69901571, 0xDE8DD475, + 0xDBDD936B, 0x6CC0526F, 0xB5E61162, 0x02FBD066, 0xBF469F5E, 0x085B5E5A, + 0xD17D1D57, 0x6660DC53, 0x63309B4D, 0xD42D5A49, 0x0D0B1944, 0xBA16D840, + 0x97C6A5AC, 0x20DB64A8, 0xF9FD27A5, 0x4EE0E6A1, 0x4BB0A1BF, 0xFCAD60BB, + 0x258B23B6, 0x9296E2B2, 0x2F2BAD8A, 0x98366C8E, 0x41102F83, 0xF60DEE87, + 0xF35DA999, 0x4440689D, 0x9D662B90, 0x2A7BEA94, 0xE71DB4E0, 0x500075E4, + 0x892636E9, 0x3E3BF7ED, 0x3B6BB0F3, 0x8C7671F7, 0x555032FA, 0xE24DF3FE, + 0x5FF0BCC6, 0xE8ED7DC2, 0x31CB3ECF, 0x86D6FFCB, 0x8386B8D5, 0x349B79D1, + 0xEDBD3ADC, 0x5AA0FBD8, 0xEEE00C69, 0x59FDCD6D, 0x80DB8E60, 0x37C64F64, + 0x3296087A, 0x858BC97E, 0x5CAD8A73, 0xEBB04B77, 0x560D044F, 0xE110C54B, + 0x38368646, 0x8F2B4742, 0x8A7B005C, 0x3D66C158, 0xE4408255, 0x535D4351, + 0x9E3B1D25, 0x2926DC21, 0xF0009F2C, 0x471D5E28, 0x424D1936, 0xF550D832, + 0x2C769B3F, 0x9B6B5A3B, 0x26D61503, 0x91CBD407, 0x48ED970A, 0xFFF0560E, + 0xFAA01110, 0x4DBDD014, 0x949B9319, 0x2386521D, 0x0E562FF1, 0xB94BEEF5, + 0x606DADF8, 0xD7706CFC, 0xD2202BE2, 0x653DEAE6, 0xBC1BA9EB, 0x0B0668EF, + 0xB6BB27D7, 0x01A6E6D3, 0xD880A5DE, 0x6F9D64DA, 0x6ACD23C4, 0xDDD0E2C0, + 0x04F6A1CD, 0xB3EB60C9, 0x7E8D3EBD, 0xC990FFB9, 0x10B6BCB4, 0xA7AB7DB0, + 0xA2FB3AAE, 0x15E6FBAA, 0xCCC0B8A7, 0x7BDD79A3, 0xC660369B, 0x717DF79F, + 0xA85BB492, 0x1F467596, 0x1A163288, 0xAD0BF38C, 0x742DB081, 0xC3307185, + 0x99908A5D, 0x2E8D4B59, 0xF7AB0854, 0x40B6C950, 0x45E68E4E, 0xF2FB4F4A, + 0x2BDD0C47, 0x9CC0CD43, 0x217D827B, 0x9660437F, 0x4F460072, 0xF85BC176, + 0xFD0B8668, 0x4A16476C, 0x93300461, 0x242DC565, 0xE94B9B11, 0x5E565A15, + 0x87701918, 0x306DD81C, 0x353D9F02, 0x82205E06, 0x5B061D0B, 0xEC1BDC0F, + 0x51A69337, 0xE6BB5233, 0x3F9D113E, 0x8880D03A, 0x8DD09724, 0x3ACD5620, + 0xE3EB152D, 0x54F6D429, 0x7926A9C5, 0xCE3B68C1, 0x171D2BCC, 0xA000EAC8, + 0xA550ADD6, 0x124D6CD2, 0xCB6B2FDF, 0x7C76EEDB, 0xC1CBA1E3, 0x76D660E7, + 0xAFF023EA, 0x18EDE2EE, 0x1DBDA5F0, 0xAAA064F4, 0x738627F9, 0xC49BE6FD, + 0x09FDB889, 0xBEE0798D, 0x67C63A80, 0xD0DBFB84, 0xD58BBC9A, 0x62967D9E, + 0xBBB03E93, 0x0CADFF97, 0xB110B0AF, 0x060D71AB, 0xDF2B32A6, 0x6836F3A2, + 0x6D66B4BC, 0xDA7B75B8, 0x035D36B5, 0xB440F7B1, 0x00000001 + }, + [AV_CRC_32_IEEE_LE] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, 0x00000001 + }, + [AV_CRC_16_ANSI_LE] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040, + 0x0001 + }, +}; +#else +#if CONFIG_SMALL +#define CRC_TABLE_SIZE 257 +#else +#define CRC_TABLE_SIZE 1024 +#endif +static AVCRC av_crc_table[AV_CRC_MAX][CRC_TABLE_SIZE]; + +#define DECLARE_CRC_INIT_TABLE_ONCE(id, le, bits, poly) \ +static AVOnce id ## _once_control = AV_ONCE_INIT; \ +static void id ## _init_table_once(void) \ +{ \ + av_assert0(av_crc_init(av_crc_table[id], le, bits, poly, sizeof(av_crc_table[id])) >= 0); \ +} + +#define CRC_INIT_TABLE_ONCE(id) ff_thread_once(&id ## _once_control, id ## _init_table_once) + +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_8_ATM, 0, 8, 0x07) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_8_EBU, 0, 8, 0x1D) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI, 0, 16, 0x8005) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_CCITT, 0, 16, 0x1021) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_24_IEEE, 0, 24, 0x864CFB) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE, 0, 32, 0x04C11DB7) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE_LE, 1, 32, 0xEDB88320) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI_LE, 1, 16, 0xA001) +#endif + +int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size) +{ + unsigned i, j; + uint32_t c; + + if (bits < 8 || bits > 32 || poly >= (1LL << bits)) + return AVERROR(EINVAL); + if (ctx_size != sizeof(AVCRC) * 257 && ctx_size != sizeof(AVCRC) * 1024) + return AVERROR(EINVAL); + + for (i = 0; i < 256; i++) { + if (le) { + for (c = i, j = 0; j < 8; j++) + c = (c >> 1) ^ (poly & (-(c & 1))); + ctx[i] = c; + } else { + for (c = i << 24, j = 0; j < 8; j++) + c = (c << 1) ^ ((poly << (32 - bits)) & (((int32_t) c) >> 31)); + ctx[i] = av_bswap32(c); + } + } + ctx[256] = 1; +#if !CONFIG_SMALL + if (ctx_size >= sizeof(AVCRC) * 1024) + for (i = 0; i < 256; i++) + for (j = 0; j < 3; j++) + ctx[256 * (j + 1) + i] = + (ctx[256 * j + i] >> 8) ^ ctx[ctx[256 * j + i] & 0xFF]; +#endif + + return 0; +} + +const AVCRC *av_crc_get_table(AVCRCId crc_id) +{ +#if !CONFIG_HARDCODED_TABLES + switch (crc_id) { + case AV_CRC_8_ATM: CRC_INIT_TABLE_ONCE(AV_CRC_8_ATM); break; + case AV_CRC_8_EBU: CRC_INIT_TABLE_ONCE(AV_CRC_8_EBU); break; + case AV_CRC_16_ANSI: CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI); break; + case AV_CRC_16_CCITT: CRC_INIT_TABLE_ONCE(AV_CRC_16_CCITT); break; + case AV_CRC_24_IEEE: CRC_INIT_TABLE_ONCE(AV_CRC_24_IEEE); break; + case AV_CRC_32_IEEE: CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE); break; + case AV_CRC_32_IEEE_LE: CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE_LE); break; + case AV_CRC_16_ANSI_LE: CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI_LE); break; + default: av_assert0(0); + } +#endif + return av_crc_table[crc_id]; +} + +uint32_t av_crc(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) +{ + const uint8_t *end = buffer + length; + +#if !CONFIG_SMALL + if (!ctx[256]) { + while (((intptr_t) buffer & 3) && buffer < end) + crc = ctx[((uint8_t) crc) ^ *buffer++] ^ (crc >> 8); + + while (buffer < end - 3) { + crc ^= av_le2ne32(*(const uint32_t *) buffer); buffer += 4; + crc = ctx[3 * 256 + ( crc & 0xFF)] ^ + ctx[2 * 256 + ((crc >> 8 ) & 0xFF)] ^ + ctx[1 * 256 + ((crc >> 16) & 0xFF)] ^ + ctx[0 * 256 + ((crc >> 24) )]; + } + } +#endif + while (buffer < end) + crc = ctx[((uint8_t) crc) ^ *buffer++] ^ (crc >> 8); + + return crc; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/crc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/crc.h new file mode 100644 index 0000000000..47e22b4c78 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/crc.h @@ -0,0 +1,100 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_crc32 + * Public header for CRC hash function implementation. + */ + +#ifndef AVUTIL_CRC_H +#define AVUTIL_CRC_H + +#include +#include +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_crc32 CRC + * @ingroup lavu_hash + * CRC (Cyclic Redundancy Check) hash function implementation. + * + * This module supports numerous CRC polynomials, in addition to the most + * widely used CRC-32-IEEE. See @ref AVCRCId for a list of available + * polynomials. + * + * @{ + */ + +typedef uint32_t AVCRC; + +typedef enum { + AV_CRC_8_ATM, + AV_CRC_16_ANSI, + AV_CRC_16_CCITT, + AV_CRC_32_IEEE, + AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */ + AV_CRC_16_ANSI_LE, /*< reversed bitorder version of AV_CRC_16_ANSI */ + AV_CRC_24_IEEE, + AV_CRC_8_EBU, + AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ +}AVCRCId; + +/** + * Initialize a CRC table. + * @param ctx must be an array of size sizeof(AVCRC)*257 or sizeof(AVCRC)*1024 + * @param le If 1, the lowest bit represents the coefficient for the highest + * exponent of the corresponding polynomial (both for poly and + * actual CRC). + * If 0, you must swap the CRC parameter and the result of av_crc + * if you need the standard representation (can be simplified in + * most cases to e.g. bswap16): + * av_bswap32(crc << (32-bits)) + * @param bits number of bits for the CRC + * @param poly generator polynomial without the x**bits coefficient, in the + * representation as specified by le + * @param ctx_size size of ctx in bytes + * @return <0 on failure + */ +int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size); + +/** + * Get an initialized standard CRC table. + * @param crc_id ID of a standard CRC + * @return a pointer to the CRC table or NULL on failure + */ +const AVCRC *av_crc_get_table(AVCRCId crc_id); + +/** + * Calculate the CRC of a block. + * @param crc CRC of previous blocks if any or initial value for CRC + * @return CRC updated with the data from the given block + * + * @see av_crc_init() "le" parameter + */ +uint32_t av_crc(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_CRC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/des.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/des.c new file mode 100644 index 0000000000..6957666184 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/des.c @@ -0,0 +1,331 @@ +/* + * DES encryption/decryption + * Copyright (c) 2007 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "avutil.h" +#include "common.h" +#include "intreadwrite.h" +#include "mem.h" +#include "des.h" + +#define T(a, b, c, d, e, f, g, h) 64 - a, 64 - b, 64 - c, 64 - d, 64 - e, 64 - f, 64 - g, 64 - h +static const uint8_t IP_shuffle[] = { + T(58, 50, 42, 34, 26, 18, 10, 2), + T(60, 52, 44, 36, 28, 20, 12, 4), + T(62, 54, 46, 38, 30, 22, 14, 6), + T(64, 56, 48, 40, 32, 24, 16, 8), + T(57, 49, 41, 33, 25, 17, 9, 1), + T(59, 51, 43, 35, 27, 19, 11, 3), + T(61, 53, 45, 37, 29, 21, 13, 5), + T(63, 55, 47, 39, 31, 23, 15, 7) +}; +#undef T + +#if CONFIG_SMALL || defined(GENTABLES) +#define T(a, b, c, d) 32 - a, 32 - b, 32 - c, 32 - d +static const uint8_t P_shuffle[] = { + T(16, 7, 20, 21), + T(29, 12, 28, 17), + T( 1, 15, 23, 26), + T( 5, 18, 31, 10), + T( 2, 8, 24, 14), + T(32, 27, 3, 9), + T(19, 13, 30, 6), + T(22, 11, 4, 25) +}; +#undef T +#endif + +#define T(a, b, c, d, e, f, g) 64 - a, 64 - b, 64 - c, 64 - d, 64 - e, 64 - f, 64 - g +static const uint8_t PC1_shuffle[] = { + T(57, 49, 41, 33, 25, 17, 9), + T( 1, 58, 50, 42, 34, 26, 18), + T(10, 2, 59, 51, 43, 35, 27), + T(19, 11, 3, 60, 52, 44, 36), + T(63, 55, 47, 39, 31, 23, 15), + T( 7, 62, 54, 46, 38, 30, 22), + T(14, 6, 61, 53, 45, 37, 29), + T(21, 13, 5, 28, 20, 12, 4) +}; +#undef T + +#define T(a, b, c, d, e, f) 56 - a, 56 - b, 56 - c, 56 - d, 56 - e, 56 - f +static const uint8_t PC2_shuffle[] = { + T(14, 17, 11, 24, 1, 5), + T( 3, 28, 15, 6, 21, 10), + T(23, 19, 12, 4, 26, 8), + T(16, 7, 27, 20, 13, 2), + T(41, 52, 31, 37, 47, 55), + T(30, 40, 51, 45, 33, 48), + T(44, 49, 39, 56, 34, 53), + T(46, 42, 50, 36, 29, 32) +}; +#undef T + +#if CONFIG_SMALL +static const uint8_t S_boxes[8][32] = { + { 0x0e, 0xf4, 0x7d, 0x41, 0xe2, 0x2f, 0xdb, 0x18, 0xa3, 0x6a, 0xc6, 0xbc, 0x95, 0x59, 0x30, 0x87, + 0xf4, 0xc1, 0x8e, 0x28, 0x4d, 0x96, 0x12, 0x7b, 0x5f, 0xbc, 0x39, 0xe7, 0xa3, 0x0a, 0x65, 0xd0, }, + { 0x3f, 0xd1, 0x48, 0x7e, 0xf6, 0x2b, 0x83, 0xe4, 0xc9, 0x07, 0x12, 0xad, 0x6c, 0x90, 0xb5, 0x5a, + 0xd0, 0x8e, 0xa7, 0x1b, 0x3a, 0xf4, 0x4d, 0x21, 0xb5, 0x68, 0x7c, 0xc6, 0x09, 0x53, 0xe2, 0x9f, }, + { 0xda, 0x70, 0x09, 0x9e, 0x36, 0x43, 0x6f, 0xa5, 0x21, 0x8d, 0x5c, 0xe7, 0xcb, 0xb4, 0xf2, 0x18, + 0x1d, 0xa6, 0xd4, 0x09, 0x68, 0x9f, 0x83, 0x70, 0x4b, 0xf1, 0xe2, 0x3c, 0xb5, 0x5a, 0x2e, 0xc7, }, + { 0xd7, 0x8d, 0xbe, 0x53, 0x60, 0xf6, 0x09, 0x3a, 0x41, 0x72, 0x28, 0xc5, 0x1b, 0xac, 0xe4, 0x9f, + 0x3a, 0xf6, 0x09, 0x60, 0xac, 0x1b, 0xd7, 0x8d, 0x9f, 0x41, 0x53, 0xbe, 0xc5, 0x72, 0x28, 0xe4, }, + { 0xe2, 0xbc, 0x24, 0xc1, 0x47, 0x7a, 0xdb, 0x16, 0x58, 0x05, 0xf3, 0xaf, 0x3d, 0x90, 0x8e, 0x69, + 0xb4, 0x82, 0xc1, 0x7b, 0x1a, 0xed, 0x27, 0xd8, 0x6f, 0xf9, 0x0c, 0x95, 0xa6, 0x43, 0x50, 0x3e, }, + { 0xac, 0xf1, 0x4a, 0x2f, 0x79, 0xc2, 0x96, 0x58, 0x60, 0x1d, 0xd3, 0xe4, 0x0e, 0xb7, 0x35, 0x8b, + 0x49, 0x3e, 0x2f, 0xc5, 0x92, 0x58, 0xfc, 0xa3, 0xb7, 0xe0, 0x14, 0x7a, 0x61, 0x0d, 0x8b, 0xd6, }, + { 0xd4, 0x0b, 0xb2, 0x7e, 0x4f, 0x90, 0x18, 0xad, 0xe3, 0x3c, 0x59, 0xc7, 0x25, 0xfa, 0x86, 0x61, + 0x61, 0xb4, 0xdb, 0x8d, 0x1c, 0x43, 0xa7, 0x7e, 0x9a, 0x5f, 0x06, 0xf8, 0xe0, 0x25, 0x39, 0xc2, }, + { 0x1d, 0xf2, 0xd8, 0x84, 0xa6, 0x3f, 0x7b, 0x41, 0xca, 0x59, 0x63, 0xbe, 0x05, 0xe0, 0x9c, 0x27, + 0x27, 0x1b, 0xe4, 0x71, 0x49, 0xac, 0x8e, 0xd2, 0xf0, 0xc6, 0x9a, 0x0d, 0x3f, 0x53, 0x65, 0xb8, + } +}; +#else +/** + * This table contains the results of applying both the S-box and P-shuffle. + * It can be regenerated by compiling tests/des.c with "-DCONFIG_SMALL -DGENTABLES". + */ +static const uint32_t S_boxes_P_shuffle[8][64] = { + { 0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000, + 0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002, + 0x00000202, 0x00800200, 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202, + 0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202, 0x00008202, 0x00800000, + 0x00008000, 0x00808202, 0x00000002, 0x00808000, 0x00808200, 0x00800000, 0x00800000, 0x00000200, + 0x00808002, 0x00008000, 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202, + 0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202, 0x00008202, 0x00808200, + 0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002, }, + { 0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010, + 0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010, + 0x00084000, 0x00080010, 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000, + 0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000, 0x40080000, 0x00004010, + 0x00000000, 0x00084010, 0x40080010, 0x00080000, 0x40004010, 0x40080000, 0x40084000, 0x00004000, + 0x40080000, 0x40004000, 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000, + 0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010, 0x40000010, 0x00080010, + 0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000, }, + { 0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100, + 0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104, + 0x04000000, 0x00000004, 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104, + 0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104, 0x00000100, 0x04000000, + 0x04010100, 0x04000000, 0x00010004, 0x00000104, 0x00010000, 0x04010100, 0x04000100, 0x00000000, + 0x00000100, 0x00010004, 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004, + 0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104, 0x00010100, 0x04000004, + 0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100, }, + { 0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000, + 0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000, + 0x80000000, 0x00001000, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040, + 0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040, 0x80401040, 0x80000040, + 0x00400040, 0x80400000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00000000, 0x00401000, + 0x00001040, 0x00400040, 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040, + 0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000, 0x00401040, 0x80400040, + 0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040, }, + { 0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000, + 0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000, + 0x01000000, 0x20040000, 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080, + 0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000, 0x21000000, 0x00040080, + 0x00040000, 0x21000080, 0x00000080, 0x01000000, 0x20000000, 0x01040000, 0x21000080, 0x20040080, + 0x01000080, 0x20000000, 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000, + 0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000, 0x20040000, 0x21000000, + 0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080, }, + { 0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000, + 0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008, + 0x00000000, 0x00200008, 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008, + 0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000, 0x10202000, 0x10000000, + 0x10002000, 0x00000008, 0x10200008, 0x00202000, 0x10202008, 0x00200000, 0x00002008, 0x10000008, + 0x00200000, 0x10002000, 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000, + 0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000, 0x10200000, 0x00202008, + 0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008, }, + { 0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400, + 0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401, + 0x02000400, 0x00100401, 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001, + 0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001, 0x02000000, 0x00100400, + 0x02000000, 0x00100400, 0x00100000, 0x02000401, 0x02000401, 0x02100001, 0x02100001, 0x00000001, + 0x00100001, 0x02000000, 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400, + 0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000, 0x00000001, 0x02100401, + 0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001, }, + { 0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000, + 0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020, + 0x08020000, 0x08000020, 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800, + 0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800, 0x00020820, 0x00020000, + 0x00020820, 0x00020000, 0x08020800, 0x00000800, 0x00000020, 0x08020020, 0x00000800, 0x00020820, + 0x08000800, 0x00000020, 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820, + 0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800, 0x08000820, 0x00000000, + 0x08020820, 0x00020800, 0x00020800, 0x00000820, 0x00000820, 0x00020020, 0x08000000, 0x08020800, }, +}; +#endif + +static uint64_t shuffle(uint64_t in, const uint8_t *shuffle, int shuffle_len) +{ + int i; + uint64_t res = 0; + for (i = 0; i < shuffle_len; i++) + res += res + ((in >> *shuffle++) & 1); + return res; +} + +static uint64_t shuffle_inv(uint64_t in, const uint8_t *shuffle, int shuffle_len) +{ + int i; + uint64_t res = 0; + shuffle += shuffle_len - 1; + for (i = 0; i < shuffle_len; i++) { + res |= (in & 1) << *shuffle--; + in >>= 1; + } + return res; +} + +static uint32_t f_func(uint32_t r, uint64_t k) +{ + int i; + uint32_t out = 0; + // rotate to get first part of E-shuffle in the lowest 6 bits + r = (r << 1) | (r >> 31); + // apply S-boxes, those compress the data again from 8 * 6 to 8 * 4 bits + for (i = 7; i >= 0; i--) { + uint8_t tmp = (r ^ k) & 0x3f; +#if CONFIG_SMALL + uint8_t v = S_boxes[i][tmp >> 1]; + if (tmp & 1) + v >>= 4; + out = (out >> 4) | (v << 28); +#else + out |= S_boxes_P_shuffle[i][tmp]; +#endif + // get next 6 bits of E-shuffle and round key k into the lowest bits + r = (r >> 4) | (r << 28); + k >>= 6; + } +#if CONFIG_SMALL + out = shuffle(out, P_shuffle, sizeof(P_shuffle)); +#endif + return out; +} + +/** + * @brief rotate the two halves of the expanded 56 bit key each 1 bit left + * + * Note: the specification calls this "shift", so I kept it although + * it is confusing. + */ +static uint64_t key_shift_left(uint64_t CDn) +{ + uint64_t carries = (CDn >> 27) & 0x10000001; + CDn <<= 1; + CDn &= ~0x10000001; + CDn |= carries; + return CDn; +} + +static void gen_roundkeys(uint64_t K[16], uint64_t key) +{ + int i; + // discard parity bits from key and shuffle it into C and D parts + uint64_t CDn = shuffle(key, PC1_shuffle, sizeof(PC1_shuffle)); + // generate round keys + for (i = 0; i < 16; i++) { + CDn = key_shift_left(CDn); + if (i > 1 && i != 8 && i != 15) + CDn = key_shift_left(CDn); + K[i] = shuffle(CDn, PC2_shuffle, sizeof(PC2_shuffle)); + } +} + +static uint64_t des_encdec(uint64_t in, uint64_t K[16], int decrypt) +{ + int i; + // used to apply round keys in reverse order for decryption + decrypt = decrypt ? 15 : 0; + // shuffle irrelevant to security but to ease hardware implementations + in = shuffle(in, IP_shuffle, sizeof(IP_shuffle)); + for (i = 0; i < 16; i++) { + uint32_t f_res; + f_res = f_func(in, K[decrypt ^ i]); + in = (in << 32) | (in >> 32); + in ^= f_res; + } + in = (in << 32) | (in >> 32); + // reverse shuffle used to ease hardware implementations + in = shuffle_inv(in, IP_shuffle, sizeof(IP_shuffle)); + return in; +} + +AVDES *av_des_alloc(void) +{ + return av_mallocz(sizeof(struct AVDES)); +} + +int av_des_init(AVDES *d, const uint8_t *key, int key_bits, av_unused int decrypt) { + if (key_bits != 64 && key_bits != 192) + return AVERROR(EINVAL); + d->triple_des = key_bits > 64; + gen_roundkeys(d->round_keys[0], AV_RB64(key)); + if (d->triple_des) { + gen_roundkeys(d->round_keys[1], AV_RB64(key + 8)); + gen_roundkeys(d->round_keys[2], AV_RB64(key + 16)); + } + return 0; +} + +static void av_des_crypt_mac(AVDES *d, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt, int mac) +{ + uint64_t iv_val = iv ? AV_RB64(iv) : 0; + while (count-- > 0) { + uint64_t dst_val; + uint64_t src_val = src ? AV_RB64(src) : 0; + if (decrypt) { + uint64_t tmp = src_val; + if (d->triple_des) { + src_val = des_encdec(src_val, d->round_keys[2], 1); + src_val = des_encdec(src_val, d->round_keys[1], 0); + } + dst_val = des_encdec(src_val, d->round_keys[0], 1) ^ iv_val; + iv_val = iv ? tmp : 0; + } else { + dst_val = des_encdec(src_val ^ iv_val, d->round_keys[0], 0); + if (d->triple_des) { + dst_val = des_encdec(dst_val, d->round_keys[1], 1); + dst_val = des_encdec(dst_val, d->round_keys[2], 0); + } + iv_val = iv ? dst_val : 0; + } + AV_WB64(dst, dst_val); + src += 8; + if (!mac) + dst += 8; + } + if (iv) + AV_WB64(iv, iv_val); +} + +void av_des_crypt(AVDES *d, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt) +{ + av_des_crypt_mac(d, dst, src, count, iv, decrypt, 0); +} + +void av_des_mac(AVDES *d, uint8_t *dst, const uint8_t *src, int count) +{ + av_des_crypt_mac(d, dst, src, count, (uint8_t[8]) { 0 }, 0, 1); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/des.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/des.h new file mode 100644 index 0000000000..4cf11f5bca --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/des.h @@ -0,0 +1,77 @@ +/* + * DES encryption/decryption + * Copyright (c) 2007 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DES_H +#define AVUTIL_DES_H + +#include + +/** + * @defgroup lavu_des DES + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVDES { + uint64_t round_keys[3][16]; + int triple_des; +} AVDES; + +/** + * Allocate an AVDES context. + */ +AVDES *av_des_alloc(void); + +/** + * @brief Initializes an AVDES context. + * + * @param key_bits must be 64 or 192 + * @param decrypt 0 for encryption/CBC-MAC, 1 for decryption + * @return zero on success, negative value otherwise + */ +int av_des_init(struct AVDES *d, const uint8_t *key, int key_bits, int decrypt); + +/** + * @brief Encrypts / decrypts using the DES algorithm. + * + * @param count number of 8 byte blocks + * @param dst destination array, can be equal to src, must be 8-byte aligned + * @param src source array, can be equal to dst, must be 8-byte aligned, may be NULL + * @param iv initialization vector for CBC mode, if NULL then ECB will be used, + * must be 8-byte aligned + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_des_crypt(struct AVDES *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @brief Calculates CBC-MAC using the DES algorithm. + * + * @param count number of 8 byte blocks + * @param dst destination array, can be equal to src, must be 8-byte aligned + * @param src source array, can be equal to dst, must be 8-byte aligned, may be NULL + */ +void av_des_mac(struct AVDES *d, uint8_t *dst, const uint8_t *src, int count); + +/** + * @} + */ + +#endif /* AVUTIL_DES_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dict.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dict.c new file mode 100644 index 0000000000..0ea71386e5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dict.c @@ -0,0 +1,272 @@ +/* + * copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "avstring.h" +#include "dict.h" +#include "internal.h" +#include "mem.h" +#include "time_internal.h" +#include "bprint.h" + +struct AVDictionary { + int count; + AVDictionaryEntry *elems; +}; + +int av_dict_count(const AVDictionary *m) +{ + return m ? m->count : 0; +} + +AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key, + const AVDictionaryEntry *prev, int flags) +{ + unsigned int i, j; + + if (!m) + return NULL; + + if (prev) + i = prev - m->elems + 1; + else + i = 0; + + for (; i < m->count; i++) { + const char *s = m->elems[i].key; + if (flags & AV_DICT_MATCH_CASE) + for (j = 0; s[j] == key[j] && key[j]; j++) + ; + else + for (j = 0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++) + ; + if (key[j]) + continue; + if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX)) + continue; + return &m->elems[i]; + } + return NULL; +} + +int av_dict_set(AVDictionary **pm, const char *key, const char *value, + int flags) +{ + AVDictionary *m = *pm; + AVDictionaryEntry *tag = NULL; + char *oldval = NULL, *copy_key = NULL, *copy_value = NULL; + + if (!(flags & AV_DICT_MULTIKEY)) { + tag = av_dict_get(m, key, NULL, flags); + } + if (flags & AV_DICT_DONT_STRDUP_KEY) + copy_key = (void *)key; + else + copy_key = av_strdup(key); + if (flags & AV_DICT_DONT_STRDUP_VAL) + copy_value = (void *)value; + else if (copy_key) + copy_value = av_strdup(value); + if (!m) + m = *pm = av_mallocz(sizeof(*m)); + if (!m || (key && !copy_key) || (value && !copy_value)) + goto err_out; + + if (tag) { + if (flags & AV_DICT_DONT_OVERWRITE) { + av_free(copy_key); + av_free(copy_value); + return 0; + } + if (flags & AV_DICT_APPEND) + oldval = tag->value; + else + av_free(tag->value); + av_free(tag->key); + *tag = m->elems[--m->count]; + } else if (copy_value) { + AVDictionaryEntry *tmp = av_realloc(m->elems, + (m->count + 1) * sizeof(*m->elems)); + if (!tmp) + goto err_out; + m->elems = tmp; + } + if (copy_value) { + m->elems[m->count].key = copy_key; + m->elems[m->count].value = copy_value; + if (oldval && flags & AV_DICT_APPEND) { + size_t len = strlen(oldval) + strlen(copy_value) + 1; + char *newval = av_mallocz(len); + if (!newval) + goto err_out; + av_strlcat(newval, oldval, len); + av_freep(&oldval); + av_strlcat(newval, copy_value, len); + m->elems[m->count].value = newval; + av_freep(©_value); + } + m->count++; + } else { + av_freep(©_key); + } + if (!m->count) { + av_freep(&m->elems); + av_freep(pm); + } + + return 0; + +err_out: + if (m && !m->count) { + av_freep(&m->elems); + av_freep(pm); + } + av_free(copy_key); + av_free(copy_value); + return AVERROR(ENOMEM); +} + +int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, + int flags) +{ + char valuestr[22]; + snprintf(valuestr, sizeof(valuestr), "%"PRId64, value); + flags &= ~AV_DICT_DONT_STRDUP_VAL; + return av_dict_set(pm, key, valuestr, flags); +} + +static int parse_key_value_pair(AVDictionary **pm, const char **buf, + const char *key_val_sep, const char *pairs_sep, + int flags) +{ + char *key = av_get_token(buf, key_val_sep); + char *val = NULL; + int ret; + + if (key && *key && strspn(*buf, key_val_sep)) { + (*buf)++; + val = av_get_token(buf, pairs_sep); + } + + if (key && *key && val && *val) + ret = av_dict_set(pm, key, val, flags); + else + ret = AVERROR(EINVAL); + + av_freep(&key); + av_freep(&val); + + return ret; +} + +int av_dict_parse_string(AVDictionary **pm, const char *str, + const char *key_val_sep, const char *pairs_sep, + int flags) +{ + int ret; + + if (!str) + return 0; + + /* ignore STRDUP flags */ + flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + + while (*str) { + if ((ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0) + return ret; + + if (*str) + str++; + } + + return 0; +} + +void av_dict_free(AVDictionary **pm) +{ + AVDictionary *m = *pm; + + if (m) { + while (m->count--) { + av_freep(&m->elems[m->count].key); + av_freep(&m->elems[m->count].value); + } + av_freep(&m->elems); + } + av_freep(pm); +} + +int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags) +{ + AVDictionaryEntry *t = NULL; + + while ((t = av_dict_get(src, "", t, AV_DICT_IGNORE_SUFFIX))) { + int ret = av_dict_set(dst, t->key, t->value, flags); + if (ret < 0) + return ret; + } + + return 0; +} + +int av_dict_get_string(const AVDictionary *m, char **buffer, + const char key_val_sep, const char pairs_sep) +{ + AVDictionaryEntry *t = NULL; + AVBPrint bprint; + int cnt = 0; + char special_chars[] = {pairs_sep, key_val_sep, '\0'}; + + if (!buffer || pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep || + pairs_sep == '\\' || key_val_sep == '\\') + return AVERROR(EINVAL); + + if (!av_dict_count(m)) { + *buffer = av_strdup(""); + return *buffer ? 0 : AVERROR(ENOMEM); + } + + av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); + while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) { + if (cnt++) + av_bprint_append_data(&bprint, &pairs_sep, 1); + av_bprint_escape(&bprint, t->key, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); + av_bprint_append_data(&bprint, &key_val_sep, 1); + av_bprint_escape(&bprint, t->value, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); + } + return av_bprint_finalize(&bprint, buffer); +} + +int avpriv_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp) +{ + time_t seconds = timestamp / 1000000; + struct tm *ptm, tmbuf; + ptm = gmtime_r(&seconds, &tmbuf); + if (ptm) { + char buf[32]; + if (!strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", ptm)) + return AVERROR_EXTERNAL; + av_strlcatf(buf, sizeof(buf), ".%06dZ", (int)(timestamp % 1000000)); + return av_dict_set(dict, key, buf, 0); + } else { + return AVERROR_EXTERNAL; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dict.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dict.h new file mode 100644 index 0000000000..118f1f00ed --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dict.h @@ -0,0 +1,200 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Public dictionary API. + * @deprecated + * AVDictionary is provided for compatibility with libav. It is both in + * implementation as well as API inefficient. It does not scale and is + * extremely slow with large dictionaries. + * It is recommended that new code uses our tree container from tree.c/h + * where applicable, which uses AVL trees to achieve O(log n) performance. + */ + +#ifndef AVUTIL_DICT_H +#define AVUTIL_DICT_H + +#include + +#include "version.h" + +/** + * @addtogroup lavu_dict AVDictionary + * @ingroup lavu_data + * + * @brief Simple key:value store + * + * @{ + * Dictionaries are used for storing key:value pairs. To create + * an AVDictionary, simply pass an address of a NULL pointer to + * av_dict_set(). NULL can be used as an empty dictionary wherever + * a pointer to an AVDictionary is required. + * Use av_dict_get() to retrieve an entry or iterate over all + * entries and finally av_dict_free() to free the dictionary + * and all its contents. + * + @code + AVDictionary *d = NULL; // "create" an empty dictionary + AVDictionaryEntry *t = NULL; + + av_dict_set(&d, "foo", "bar", 0); // add an entry + + char *k = av_strdup("key"); // if your strings are already allocated, + char *v = av_strdup("value"); // you can avoid copying them like this + av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + + while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) { + <....> // iterate over all entries in d + } + av_dict_free(&d); + @endcode + */ + +#define AV_DICT_MATCH_CASE 1 /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */ +#define AV_DICT_IGNORE_SUFFIX 2 /**< Return first entry in a dictionary whose first part corresponds to the search key, + ignoring the suffix of the found key string. Only relevant in av_dict_get(). */ +#define AV_DICT_DONT_STRDUP_KEY 4 /**< Take ownership of a key that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_STRDUP_VAL 8 /**< Take ownership of a value that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_OVERWRITE 16 ///< Don't overwrite existing entries. +#define AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no + delimiter is added, the strings are simply concatenated. */ +#define AV_DICT_MULTIKEY 64 /**< Allow to store several equal keys in the dictionary */ + +typedef struct AVDictionaryEntry { + char *key; + char *value; +} AVDictionaryEntry; + +typedef struct AVDictionary AVDictionary; + +/** + * Get a dictionary entry with matching key. + * + * The returned entry key or value must not be changed, or it will + * cause undefined behavior. + * + * To iterate through all the dictionary entries, you can set the matching key + * to the null string "" and set the AV_DICT_IGNORE_SUFFIX flag. + * + * @param prev Set to the previous matching element to find the next. + * If set to NULL the first matching element is returned. + * @param key matching key + * @param flags a collection of AV_DICT_* flags controlling how the entry is retrieved + * @return found entry or NULL in case no matching entry was found in the dictionary + */ +AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key, + const AVDictionaryEntry *prev, int flags); + +/** + * Get number of entries in dictionary. + * + * @param m dictionary + * @return number of entries in dictionary + */ +int av_dict_count(const AVDictionary *m); + +/** + * Set the given entry in *pm, overwriting an existing entry. + * + * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set, + * these arguments will be freed on error. + * + * Warning: Adding a new entry to a dictionary invalidates all existing entries + * previously returned with av_dict_get. + * + * @param pm pointer to a pointer to a dictionary struct. If *pm is NULL + * a dictionary struct is allocated and put in *pm. + * @param key entry key to add to *pm (will either be av_strduped or added as a new key depending on flags) + * @param value entry value to add to *pm (will be av_strduped or added as a new key depending on flags). + * Passing a NULL value will cause an existing entry to be deleted. + * @return >= 0 on success otherwise an error code <0 + */ +int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags); + +/** + * Convenience wrapper for av_dict_set that converts the value to a string + * and stores it. + * + * Note: If AV_DICT_DONT_STRDUP_KEY is set, key will be freed on error. + */ +int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags); + +/** + * Parse the key/value pairs list and add the parsed entries to a dictionary. + * + * In case of failure, all the successfully set entries are stored in + * *pm. You may need to manually free the created dictionary. + * + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @param flags flags to use when adding to dictionary. + * AV_DICT_DONT_STRDUP_KEY and AV_DICT_DONT_STRDUP_VAL + * are ignored since the key/value tokens will always + * be duplicated. + * @return 0 on success, negative AVERROR code on failure + */ +int av_dict_parse_string(AVDictionary **pm, const char *str, + const char *key_val_sep, const char *pairs_sep, + int flags); + +/** + * Copy entries from one AVDictionary struct into another. + * @param dst pointer to a pointer to a AVDictionary struct. If *dst is NULL, + * this function will allocate a struct for you and put it in *dst + * @param src pointer to source AVDictionary struct + * @param flags flags to use when setting entries in *dst + * @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag + * @return 0 on success, negative AVERROR code on failure. If dst was allocated + * by this function, callers should free the associated memory. + */ +int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags); + +/** + * Free all the memory allocated for an AVDictionary struct + * and all keys and values. + */ +void av_dict_free(AVDictionary **m); + +/** + * Get dictionary entries as a string. + * + * Create a string containing dictionary's entries. + * Such string may be passed back to av_dict_parse_string(). + * @note String is escaped with backslashes ('\'). + * + * @param[in] m dictionary + * @param[out] buffer Pointer to buffer that will be allocated with string containg entries. + * Buffer must be freed by the caller when is no longer needed. + * @param[in] key_val_sep character used to separate key from value + * @param[in] pairs_sep character used to separate two pairs from each other + * @return >= 0 on success, negative on error + * @warning Separators cannot be neither '\\' nor '\0'. They also cannot be the same. + */ +int av_dict_get_string(const AVDictionary *m, char **buffer, + const char key_val_sep, const char pairs_sep); + +/** + * @} + */ + +#endif /* AVUTIL_DICT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/display.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/display.c new file mode 100644 index 0000000000..a0076e067b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/display.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "display.h" +#include "mathematics.h" + +// fixed point to double +#define CONV_FP(x) ((double) (x)) / (1 << 16) + +// double to fixed point +#define CONV_DB(x) (int32_t) ((x) * (1 << 16)) + +double av_display_rotation_get(const int32_t matrix[9]) +{ + double rotation, scale[2]; + + scale[0] = hypot(CONV_FP(matrix[0]), CONV_FP(matrix[3])); + scale[1] = hypot(CONV_FP(matrix[1]), CONV_FP(matrix[4])); + + if (scale[0] == 0.0 || scale[1] == 0.0) + return NAN; + + rotation = atan2(CONV_FP(matrix[1]) / scale[1], + CONV_FP(matrix[0]) / scale[0]) * 180 / M_PI; + + return -rotation; +} + +void av_display_rotation_set(int32_t matrix[9], double angle) +{ + double radians = -angle * M_PI / 180.0f; + double c = cos(radians); + double s = sin(radians); + + memset(matrix, 0, 9 * sizeof(int32_t)); + + matrix[0] = CONV_DB(c); + matrix[1] = CONV_DB(-s); + matrix[3] = CONV_DB(s); + matrix[4] = CONV_DB(c); + matrix[8] = 1 << 30; +} + +void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip) +{ + int i; + const int flip[] = { 1 - 2 * (!!hflip), 1 - 2 * (!!vflip), 1 }; + + if (hflip || vflip) + for (i = 0; i < 9; i++) + matrix[i] *= flip[i % 3]; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/display.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/display.h new file mode 100644 index 0000000000..515adad795 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/display.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2014 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Display matrix + */ + +#ifndef AVUTIL_DISPLAY_H +#define AVUTIL_DISPLAY_H + +#include +#include "common.h" + +/** + * @addtogroup lavu_video + * @{ + * + * @defgroup lavu_video_display Display transformation matrix functions + * @{ + */ + +/** + * @addtogroup lavu_video_display + * The display transformation matrix specifies an affine transformation that + * should be applied to video frames for correct presentation. It is compatible + * with the matrices stored in the ISO/IEC 14496-12 container format. + * + * The data is a 3x3 matrix represented as a 9-element array: + * + * @code{.unparsed} + * | a b u | + * (a, b, u, c, d, v, x, y, w) -> | c d v | + * | x y w | + * @endcode + * + * All numbers are stored in native endianness, as 16.16 fixed-point values, + * except for u, v and w, which are stored as 2.30 fixed-point values. + * + * The transformation maps a point (p, q) in the source (pre-transformation) + * frame to the point (p', q') in the destination (post-transformation) frame as + * follows: + * + * @code{.unparsed} + * | a b u | + * (p, q, 1) . | c d v | = z * (p', q', 1) + * | x y w | + * @endcode + * + * The transformation can also be more explicitly written in components as + * follows: + * + * @code{.unparsed} + * p' = (a * p + c * q + x) / z; + * q' = (b * p + d * q + y) / z; + * z = u * p + v * q + w + * @endcode + */ + +/** + * Extract the rotation component of the transformation matrix. + * + * @param matrix the transformation matrix + * @return the angle (in degrees) by which the transformation rotates the frame + * counterclockwise. The angle will be in range [-180.0, 180.0], + * or NaN if the matrix is singular. + * + * @note floating point numbers are inherently inexact, so callers are + * recommended to round the return value to nearest integer before use. + */ +double av_display_rotation_get(const int32_t matrix[9]); + +/** + * Initialize a transformation matrix describing a pure counterclockwise + * rotation by the specified angle (in degrees). + * + * @param matrix an allocated transformation matrix (will be fully overwritten + * by this function) + * @param angle rotation angle in degrees. + */ +void av_display_rotation_set(int32_t matrix[9], double angle); + +/** + * Flip the input matrix horizontally and/or vertically. + * + * @param matrix an allocated transformation matrix + * @param hflip whether the matrix should be flipped horizontally + * @param vflip whether the matrix should be flipped vertically + */ +void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_DISPLAY_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/downmix_info.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/downmix_info.c new file mode 100644 index 0000000000..c634c6a79f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/downmix_info.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Tim Walker + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "downmix_info.h" +#include "frame.h" + +AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data; + + side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_DOWNMIX_INFO); + + if (!side_data) + side_data = av_frame_new_side_data(frame, AV_FRAME_DATA_DOWNMIX_INFO, + sizeof(AVDownmixInfo)); + + if (!side_data) + return NULL; + + return (AVDownmixInfo*)side_data->data; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/downmix_info.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/downmix_info.h new file mode 100644 index 0000000000..221cf5bf9b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/downmix_info.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 Tim Walker + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DOWNMIX_INFO_H +#define AVUTIL_DOWNMIX_INFO_H + +#include "frame.h" + +/** + * @file + * audio downmix medatata + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup downmix_info Audio downmix metadata + * @{ + */ + +/** + * Possible downmix types. + */ +enum AVDownmixType { + AV_DOWNMIX_TYPE_UNKNOWN, /**< Not indicated. */ + AV_DOWNMIX_TYPE_LORO, /**< Lo/Ro 2-channel downmix (Stereo). */ + AV_DOWNMIX_TYPE_LTRT, /**< Lt/Rt 2-channel downmix, Dolby Surround compatible. */ + AV_DOWNMIX_TYPE_DPLII, /**< Lt/Rt 2-channel downmix, Dolby Pro Logic II compatible. */ + AV_DOWNMIX_TYPE_NB /**< Number of downmix types. Not part of ABI. */ +}; + +/** + * This structure describes optional metadata relevant to a downmix procedure. + * + * All fields are set by the decoder to the value indicated in the audio + * bitstream (if present), or to a "sane" default otherwise. + */ +typedef struct AVDownmixInfo { + /** + * Type of downmix preferred by the mastering engineer. + */ + enum AVDownmixType preferred_downmix_type; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during a regular downmix. + */ + double center_mix_level; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during an Lt/Rt compatible downmix. + */ + double center_mix_level_ltrt; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during a regular downmix. + */ + double surround_mix_level; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during an Lt/Rt compatible downmix. + */ + double surround_mix_level_ltrt; + + /** + * Absolute scale factor representing the level at which the LFE data is + * mixed into L/R channels during downmixing. + */ + double lfe_mix_level; +} AVDownmixInfo; + +/** + * Get a frame's AV_FRAME_DATA_DOWNMIX_INFO side data for editing. + * + * If the side data is absent, it is created and added to the frame. + * + * @param frame the frame for which the side data is to be obtained or created + * + * @return the AVDownmixInfo structure to be edited by the caller, or NULL if + * the structure cannot be allocated. + */ +AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame); + +/** + * @} + */ + +/** + * @} + */ + +#endif /* AVUTIL_DOWNMIX_INFO_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dynarray.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dynarray.h new file mode 100644 index 0000000000..3a7e146422 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/dynarray.h @@ -0,0 +1,70 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DYNARRAY_H +#define AVUTIL_DYNARRAY_H + +#include "log.h" +#include "mem.h" + +/** + * Add an element to a dynamic array. + * + * The array is reallocated when its number of elements reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the size is incremented. + * + * @param av_size_max maximum size of the array, usually the MAX macro of + * the type of the size + * @param av_elt_size size of the elements in the array, in bytes + * @param av_array pointer to the array, must be a lvalue + * @param av_size size of the array, must be an integer lvalue + * @param av_success statement to execute on success; at this point, the + * size variable is not yet incremented + * @param av_failure statement to execute on failure; if this happens, the + * array and size are not changed; the statement can end + * with a return or a goto + */ +#define FF_DYNARRAY_ADD(av_size_max, av_elt_size, av_array, av_size, \ + av_success, av_failure) \ + do { \ + size_t av_size_new = (av_size); \ + if (!((av_size) & ((av_size) - 1))) { \ + av_size_new = (av_size) ? (av_size) << 1 : 1; \ + if (av_size_new > (av_size_max) / (av_elt_size)) { \ + av_size_new = 0; \ + } else { \ + void *av_array_new = \ + av_realloc((av_array), av_size_new * (av_elt_size)); \ + if (!av_array_new) \ + av_size_new = 0; \ + else \ + (av_array) = av_array_new; \ + } \ + } \ + if (av_size_new) { \ + { av_success } \ + (av_size)++; \ + } else { \ + av_failure \ + } \ + } while (0) + +#endif /* AVUTIL_DYNARRAY_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/encryption_info.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/encryption_info.c new file mode 100644 index 0000000000..812c704776 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/encryption_info.c @@ -0,0 +1,339 @@ +/** + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "encryption_info.h" +#include "mem.h" +#include "intreadwrite.h" + +#define FF_ENCRYPTION_INFO_EXTRA 24 + +// The format of the AVEncryptionInfo side data: +// u32be scheme +// u32be crypt_byte_block +// u32be skip_byte_block +// u32be key_id_size +// u32be iv_size +// u32be subsample_count +// u8[key_id_size] key_id +// u8[iv_size] iv +// { +// u32be bytes_of_clear_data +// u32be bytes_of_protected_data +// }[subsample_count] + +AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size) +{ + AVEncryptionInfo *info; + + info = av_mallocz(sizeof(*info)); + if (!info) + return NULL; + + info->key_id = av_mallocz(key_id_size); + info->key_id_size = key_id_size; + info->iv = av_mallocz(iv_size); + info->iv_size = iv_size; + info->subsamples = av_mallocz_array(subsample_count, sizeof(*info->subsamples)); + info->subsample_count = subsample_count; + + // Allow info->subsamples to be NULL if there are no subsamples. + if (!info->key_id || !info->iv || (!info->subsamples && subsample_count)) { + av_encryption_info_free(info); + return NULL; + } + + return info; +} + +AVEncryptionInfo *av_encryption_info_clone(const AVEncryptionInfo *info) +{ + AVEncryptionInfo *ret; + + ret = av_encryption_info_alloc(info->subsample_count, info->key_id_size, info->iv_size); + if (!ret) + return NULL; + + ret->scheme = info->scheme; + ret->crypt_byte_block = info->crypt_byte_block; + ret->skip_byte_block = info->skip_byte_block; + memcpy(ret->iv, info->iv, info->iv_size); + memcpy(ret->key_id, info->key_id, info->key_id_size); + memcpy(ret->subsamples, info->subsamples, sizeof(*info->subsamples) * info->subsample_count); + return ret; +} + +void av_encryption_info_free(AVEncryptionInfo *info) +{ + if (info) { + av_free(info->key_id); + av_free(info->iv); + av_free(info->subsamples); + av_free(info); + } +} + +AVEncryptionInfo *av_encryption_info_get_side_data(const uint8_t* buffer, size_t size) +{ + AVEncryptionInfo *info; + uint64_t key_id_size, iv_size, subsample_count, i; + + if (!buffer || size < FF_ENCRYPTION_INFO_EXTRA) + return NULL; + + key_id_size = AV_RB32(buffer + 12); + iv_size = AV_RB32(buffer + 16); + subsample_count = AV_RB32(buffer + 20); + + if (size < FF_ENCRYPTION_INFO_EXTRA + key_id_size + iv_size + subsample_count * 8) + return NULL; + + info = av_encryption_info_alloc(subsample_count, key_id_size, iv_size); + if (!info) + return NULL; + + info->scheme = AV_RB32(buffer); + info->crypt_byte_block = AV_RB32(buffer + 4); + info->skip_byte_block = AV_RB32(buffer + 8); + memcpy(info->key_id, buffer + 24, key_id_size); + memcpy(info->iv, buffer + key_id_size + 24, iv_size); + + buffer += key_id_size + iv_size + 24; + for (i = 0; i < subsample_count; i++) { + info->subsamples[i].bytes_of_clear_data = AV_RB32(buffer); + info->subsamples[i].bytes_of_protected_data = AV_RB32(buffer + 4); + buffer += 8; + } + + return info; +} + +uint8_t *av_encryption_info_add_side_data(const AVEncryptionInfo *info, size_t *size) +{ + uint8_t *buffer, *cur_buffer; + uint32_t i; + + if (UINT32_MAX - FF_ENCRYPTION_INFO_EXTRA < info->key_id_size || + UINT32_MAX - FF_ENCRYPTION_INFO_EXTRA - info->key_id_size < info->iv_size || + (UINT32_MAX - FF_ENCRYPTION_INFO_EXTRA - info->key_id_size - info->iv_size) / 8 < info->subsample_count) { + return NULL; + } + + *size = FF_ENCRYPTION_INFO_EXTRA + info->key_id_size + info->iv_size + + (info->subsample_count * 8); + cur_buffer = buffer = av_malloc(*size); + if (!buffer) + return NULL; + + AV_WB32(cur_buffer, info->scheme); + AV_WB32(cur_buffer + 4, info->crypt_byte_block); + AV_WB32(cur_buffer + 8, info->skip_byte_block); + AV_WB32(cur_buffer + 12, info->key_id_size); + AV_WB32(cur_buffer + 16, info->iv_size); + AV_WB32(cur_buffer + 20, info->subsample_count); + cur_buffer += 24; + memcpy(cur_buffer, info->key_id, info->key_id_size); + cur_buffer += info->key_id_size; + memcpy(cur_buffer, info->iv, info->iv_size); + cur_buffer += info->iv_size; + for (i = 0; i < info->subsample_count; i++) { + AV_WB32(cur_buffer, info->subsamples[i].bytes_of_clear_data); + AV_WB32(cur_buffer + 4, info->subsamples[i].bytes_of_protected_data); + cur_buffer += 8; + } + + return buffer; +} + +// The format of the AVEncryptionInitInfo side data: +// u32be init_info_count +// { +// u32be system_id_size +// u32be num_key_ids +// u32be key_id_size +// u32be data_size +// u8[system_id_size] system_id +// u8[key_id_size][num_key_id] key_ids +// u8[data_size] data +// }[init_info_count] + +#define FF_ENCRYPTION_INIT_INFO_EXTRA 16 + +AVEncryptionInitInfo *av_encryption_init_info_alloc( + uint32_t system_id_size, uint32_t num_key_ids, uint32_t key_id_size, uint32_t data_size) +{ + AVEncryptionInitInfo *info; + uint32_t i; + + info = av_mallocz(sizeof(*info)); + if (!info) + return NULL; + + info->system_id = av_mallocz(system_id_size); + info->system_id_size = system_id_size; + info->key_ids = key_id_size ? av_mallocz_array(num_key_ids, sizeof(*info->key_ids)) : NULL; + info->num_key_ids = num_key_ids; + info->key_id_size = key_id_size; + info->data = av_mallocz(data_size); + info->data_size = data_size; + + // Allow pointers to be NULL if the size is 0. + if ((!info->system_id && system_id_size) || (!info->data && data_size) || + (!info->key_ids && num_key_ids && key_id_size)) { + av_encryption_init_info_free(info); + return NULL; + } + + if (key_id_size) { + for (i = 0; i < num_key_ids; i++) { + info->key_ids[i] = av_mallocz(key_id_size); + if (!info->key_ids[i]) { + av_encryption_init_info_free(info); + return NULL; + } + } + } + + return info; +} + +void av_encryption_init_info_free(AVEncryptionInitInfo *info) +{ + uint32_t i; + if (info) { + for (i = 0; i < info->num_key_ids; i++) { + av_free(info->key_ids[i]); + } + av_encryption_init_info_free(info->next); + av_free(info->system_id); + av_free(info->key_ids); + av_free(info->data); + av_free(info); + } +} + +AVEncryptionInitInfo *av_encryption_init_info_get_side_data( + const uint8_t *side_data, size_t side_data_size) +{ + // |ret| tracks the front of the list, |info| tracks the back. + AVEncryptionInitInfo *ret = NULL, *info, *temp_info; + uint64_t system_id_size, num_key_ids, key_id_size, data_size, i, j; + uint64_t init_info_count; + + if (!side_data || side_data_size < 4) + return NULL; + + init_info_count = AV_RB32(side_data); + side_data += 4; + side_data_size -= 4; + for (i = 0; i < init_info_count; i++) { + if (side_data_size < FF_ENCRYPTION_INIT_INFO_EXTRA) { + av_encryption_init_info_free(ret); + return NULL; + } + + system_id_size = AV_RB32(side_data); + num_key_ids = AV_RB32(side_data + 4); + key_id_size = AV_RB32(side_data + 8); + data_size = AV_RB32(side_data + 12); + + // UINT32_MAX + UINT32_MAX + UINT32_MAX * UINT32_MAX == UINT64_MAX + if (side_data_size - FF_ENCRYPTION_INIT_INFO_EXTRA < system_id_size + data_size + num_key_ids * key_id_size) { + av_encryption_init_info_free(ret); + return NULL; + } + side_data += FF_ENCRYPTION_INIT_INFO_EXTRA; + side_data_size -= FF_ENCRYPTION_INIT_INFO_EXTRA; + + temp_info = av_encryption_init_info_alloc(system_id_size, num_key_ids, key_id_size, data_size); + if (!temp_info) { + av_encryption_init_info_free(ret); + return NULL; + } + if (i == 0) { + info = ret = temp_info; + } else { + info->next = temp_info; + info = temp_info; + } + + memcpy(info->system_id, side_data, system_id_size); + side_data += system_id_size; + side_data_size -= system_id_size; + for (j = 0; j < num_key_ids; j++) { + memcpy(info->key_ids[j], side_data, key_id_size); + side_data += key_id_size; + side_data_size -= key_id_size; + } + memcpy(info->data, side_data, data_size); + side_data += data_size; + side_data_size -= data_size; + } + + return ret; +} + +uint8_t *av_encryption_init_info_add_side_data(const AVEncryptionInitInfo *info, size_t *side_data_size) +{ + const AVEncryptionInitInfo *cur_info; + uint8_t *buffer, *cur_buffer; + uint32_t i, init_info_count; + uint64_t temp_side_data_size; + + temp_side_data_size = 4; + init_info_count = 0; + for (cur_info = info; cur_info; cur_info = cur_info->next) { + temp_side_data_size += (uint64_t)FF_ENCRYPTION_INIT_INFO_EXTRA + cur_info->system_id_size + cur_info->data_size; + if (init_info_count == UINT32_MAX || temp_side_data_size > UINT32_MAX) { + return NULL; + } + init_info_count++; + + if (cur_info->num_key_ids) { + temp_side_data_size += (uint64_t)cur_info->num_key_ids * cur_info->key_id_size; + if (temp_side_data_size > UINT32_MAX) { + return NULL; + } + } + } + *side_data_size = temp_side_data_size; + + cur_buffer = buffer = av_malloc(*side_data_size); + if (!buffer) + return NULL; + + AV_WB32(cur_buffer, init_info_count); + cur_buffer += 4; + for (cur_info = info; cur_info; cur_info = cur_info->next) { + AV_WB32(cur_buffer, cur_info->system_id_size); + AV_WB32(cur_buffer + 4, cur_info->num_key_ids); + AV_WB32(cur_buffer + 8, cur_info->key_id_size); + AV_WB32(cur_buffer + 12, cur_info->data_size); + cur_buffer += 16; + + memcpy(cur_buffer, cur_info->system_id, cur_info->system_id_size); + cur_buffer += cur_info->system_id_size; + for (i = 0; i < cur_info->num_key_ids; i++) { + memcpy(cur_buffer, cur_info->key_ids[i], cur_info->key_id_size); + cur_buffer += cur_info->key_id_size; + } + memcpy(cur_buffer, cur_info->data, cur_info->data_size); + cur_buffer += cur_info->data_size; + } + + return buffer; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/encryption_info.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/encryption_info.h new file mode 100644 index 0000000000..8fe7ebfe43 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/encryption_info.h @@ -0,0 +1,205 @@ +/** + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ENCRYPTION_INFO_H +#define AVUTIL_ENCRYPTION_INFO_H + +#include +#include + +typedef struct AVSubsampleEncryptionInfo { + /** The number of bytes that are clear. */ + unsigned int bytes_of_clear_data; + + /** + * The number of bytes that are protected. If using pattern encryption, + * the pattern applies to only the protected bytes; if not using pattern + * encryption, all these bytes are encrypted. + */ + unsigned int bytes_of_protected_data; +} AVSubsampleEncryptionInfo; + +/** + * This describes encryption info for a packet. This contains frame-specific + * info for how to decrypt the packet before passing it to the decoder. + * + * The size of this struct is not part of the public ABI. + */ +typedef struct AVEncryptionInfo { + /** The fourcc encryption scheme, in big-endian byte order. */ + uint32_t scheme; + + /** + * Only used for pattern encryption. This is the number of 16-byte blocks + * that are encrypted. + */ + uint32_t crypt_byte_block; + + /** + * Only used for pattern encryption. This is the number of 16-byte blocks + * that are clear. + */ + uint32_t skip_byte_block; + + /** + * The ID of the key used to encrypt the packet. This should always be + * 16 bytes long, but may be changed in the future. + */ + uint8_t *key_id; + uint32_t key_id_size; + + /** + * The initialization vector. This may have been zero-filled to be the + * correct block size. This should always be 16 bytes long, but may be + * changed in the future. + */ + uint8_t *iv; + uint32_t iv_size; + + /** + * An array of subsample encryption info specifying how parts of the sample + * are encrypted. If there are no subsamples, then the whole sample is + * encrypted. + */ + AVSubsampleEncryptionInfo *subsamples; + uint32_t subsample_count; +} AVEncryptionInfo; + +/** + * This describes info used to initialize an encryption key system. + * + * The size of this struct is not part of the public ABI. + */ +typedef struct AVEncryptionInitInfo { + /** + * A unique identifier for the key system this is for, can be NULL if it + * is not known. This should always be 16 bytes, but may change in the + * future. + */ + uint8_t* system_id; + uint32_t system_id_size; + + /** + * An array of key IDs this initialization data is for. All IDs are the + * same length. Can be NULL if there are no known key IDs. + */ + uint8_t** key_ids; + /** The number of key IDs. */ + uint32_t num_key_ids; + /** + * The number of bytes in each key ID. This should always be 16, but may + * change in the future. + */ + uint32_t key_id_size; + + /** + * Key-system specific initialization data. This data is copied directly + * from the file and the format depends on the specific key system. This + * can be NULL if there is no initialization data; in that case, there + * will be at least one key ID. + */ + uint8_t* data; + uint32_t data_size; + + /** + * An optional pointer to the next initialization info in the list. + */ + struct AVEncryptionInitInfo *next; +} AVEncryptionInitInfo; + +/** + * Allocates an AVEncryptionInfo structure and sub-pointers to hold the given + * number of subsamples. This will allocate pointers for the key ID, IV, + * and subsample entries, set the size members, and zero-initialize the rest. + * + * @param subsample_count The number of subsamples. + * @param key_id_size The number of bytes in the key ID, should be 16. + * @param iv_size The number of bytes in the IV, should be 16. + * + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size); + +/** + * Allocates an AVEncryptionInfo structure with a copy of the given data. + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_clone(const AVEncryptionInfo *info); + +/** + * Frees the given encryption info object. This MUST NOT be used to free the + * side-data data pointer, that should use normal side-data methods. + */ +void av_encryption_info_free(AVEncryptionInfo *info); + +/** + * Creates a copy of the AVEncryptionInfo that is contained in the given side + * data. The resulting object should be passed to av_encryption_info_free() + * when done. + * + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_get_side_data(const uint8_t *side_data, size_t side_data_size); + +/** + * Allocates and initializes side data that holds a copy of the given encryption + * info. The resulting pointer should be either freed using av_free or given + * to av_packet_add_side_data(). + * + * @return The new side-data pointer, or NULL. + */ +uint8_t *av_encryption_info_add_side_data( + const AVEncryptionInfo *info, size_t *side_data_size); + + +/** + * Allocates an AVEncryptionInitInfo structure and sub-pointers to hold the + * given sizes. This will allocate pointers and set all the fields. + * + * @return The new AVEncryptionInitInfo structure, or NULL on error. + */ +AVEncryptionInitInfo *av_encryption_init_info_alloc( + uint32_t system_id_size, uint32_t num_key_ids, uint32_t key_id_size, uint32_t data_size); + +/** + * Frees the given encryption init info object. This MUST NOT be used to free + * the side-data data pointer, that should use normal side-data methods. + */ +void av_encryption_init_info_free(AVEncryptionInitInfo* info); + +/** + * Creates a copy of the AVEncryptionInitInfo that is contained in the given + * side data. The resulting object should be passed to + * av_encryption_init_info_free() when done. + * + * @return The new AVEncryptionInitInfo structure, or NULL on error. + */ +AVEncryptionInitInfo *av_encryption_init_info_get_side_data( + const uint8_t* side_data, size_t side_data_size); + +/** + * Allocates and initializes side data that holds a copy of the given encryption + * init info. The resulting pointer should be either freed using av_free or + * given to av_packet_add_side_data(). + * + * @return The new side-data pointer, or NULL. + */ +uint8_t *av_encryption_init_info_add_side_data( + const AVEncryptionInitInfo *info, size_t *side_data_size); + +#endif /* AVUTIL_ENCRYPTION_INFO_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/error.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/error.c new file mode 100644 index 0000000000..b96304837b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/error.c @@ -0,0 +1,129 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#undef _GNU_SOURCE +#define _XOPEN_SOURCE 600 /* XSI-compliant version of strerror_r */ +#include "avutil.h" +#include "avstring.h" +#include "common.h" + +struct error_entry { + int num; + const char *tag; + const char *str; +}; + +#define ERROR_TAG(tag) AVERROR_##tag, #tag +#define EERROR_TAG(tag) AVERROR(tag), #tag +#define AVERROR_INPUT_AND_OUTPUT_CHANGED (AVERROR_INPUT_CHANGED | AVERROR_OUTPUT_CHANGED) +static const struct error_entry error_entries[] = { + { ERROR_TAG(BSF_NOT_FOUND), "Bitstream filter not found" }, + { ERROR_TAG(BUG), "Internal bug, should not have happened" }, + { ERROR_TAG(BUG2), "Internal bug, should not have happened" }, + { ERROR_TAG(BUFFER_TOO_SMALL), "Buffer too small" }, + { ERROR_TAG(DECODER_NOT_FOUND), "Decoder not found" }, + { ERROR_TAG(DEMUXER_NOT_FOUND), "Demuxer not found" }, + { ERROR_TAG(ENCODER_NOT_FOUND), "Encoder not found" }, + { ERROR_TAG(EOF), "End of file" }, + { ERROR_TAG(EXIT), "Immediate exit requested" }, + { ERROR_TAG(EXTERNAL), "Generic error in an external library" }, + { ERROR_TAG(FILTER_NOT_FOUND), "Filter not found" }, + { ERROR_TAG(INPUT_CHANGED), "Input changed" }, + { ERROR_TAG(INVALIDDATA), "Invalid data found when processing input" }, + { ERROR_TAG(MUXER_NOT_FOUND), "Muxer not found" }, + { ERROR_TAG(OPTION_NOT_FOUND), "Option not found" }, + { ERROR_TAG(OUTPUT_CHANGED), "Output changed" }, + { ERROR_TAG(PATCHWELCOME), "Not yet implemented in FFmpeg, patches welcome" }, + { ERROR_TAG(PROTOCOL_NOT_FOUND), "Protocol not found" }, + { ERROR_TAG(STREAM_NOT_FOUND), "Stream not found" }, + { ERROR_TAG(UNKNOWN), "Unknown error occurred" }, + { ERROR_TAG(EXPERIMENTAL), "Experimental feature" }, + { ERROR_TAG(INPUT_AND_OUTPUT_CHANGED), "Input and output changed" }, + { ERROR_TAG(HTTP_BAD_REQUEST), "Server returned 400 Bad Request" }, + { ERROR_TAG(HTTP_UNAUTHORIZED), "Server returned 401 Unauthorized (authorization failed)" }, + { ERROR_TAG(HTTP_FORBIDDEN), "Server returned 403 Forbidden (access denied)" }, + { ERROR_TAG(HTTP_NOT_FOUND), "Server returned 404 Not Found" }, + { ERROR_TAG(HTTP_OTHER_4XX), "Server returned 4XX Client Error, but not one of 40{0,1,3,4}" }, + { ERROR_TAG(HTTP_SERVER_ERROR), "Server returned 5XX Server Error reply" }, +#if !HAVE_STRERROR_R + { EERROR_TAG(E2BIG), "Argument list too long" }, + { EERROR_TAG(EACCES), "Permission denied" }, + { EERROR_TAG(EAGAIN), "Resource temporarily unavailable" }, + { EERROR_TAG(EBADF), "Bad file descriptor" }, + { EERROR_TAG(EBUSY), "Device or resource busy" }, + { EERROR_TAG(ECHILD), "No child processes" }, + { EERROR_TAG(EDEADLK), "Resource deadlock avoided" }, + { EERROR_TAG(EDOM), "Numerical argument out of domain" }, + { EERROR_TAG(EEXIST), "File exists" }, + { EERROR_TAG(EFAULT), "Bad address" }, + { EERROR_TAG(EFBIG), "File too large" }, + { EERROR_TAG(EILSEQ), "Illegal byte sequence" }, + { EERROR_TAG(EINTR), "Interrupted system call" }, + { EERROR_TAG(EINVAL), "Invalid argument" }, + { EERROR_TAG(EIO), "I/O error" }, + { EERROR_TAG(EISDIR), "Is a directory" }, + { EERROR_TAG(EMFILE), "Too many open files" }, + { EERROR_TAG(EMLINK), "Too many links" }, + { EERROR_TAG(ENAMETOOLONG), "File name too long" }, + { EERROR_TAG(ENFILE), "Too many open files in system" }, + { EERROR_TAG(ENODEV), "No such device" }, + { EERROR_TAG(ENOENT), "No such file or directory" }, + { EERROR_TAG(ENOEXEC), "Exec format error" }, + { EERROR_TAG(ENOLCK), "No locks available" }, + { EERROR_TAG(ENOMEM), "Cannot allocate memory" }, + { EERROR_TAG(ENOSPC), "No space left on device" }, + { EERROR_TAG(ENOSYS), "Function not implemented" }, + { EERROR_TAG(ENOTDIR), "Not a directory" }, + { EERROR_TAG(ENOTEMPTY), "Directory not empty" }, + { EERROR_TAG(ENOTTY), "Inappropriate I/O control operation" }, + { EERROR_TAG(ENXIO), "No such device or address" }, + { EERROR_TAG(EPERM), "Operation not permitted" }, + { EERROR_TAG(EPIPE), "Broken pipe" }, + { EERROR_TAG(ERANGE), "Result too large" }, + { EERROR_TAG(EROFS), "Read-only file system" }, + { EERROR_TAG(ESPIPE), "Illegal seek" }, + { EERROR_TAG(ESRCH), "No such process" }, + { EERROR_TAG(EXDEV), "Cross-device link" }, +#endif +}; + +int av_strerror(int errnum, char *errbuf, size_t errbuf_size) +{ + int ret = 0, i; + const struct error_entry *entry = NULL; + + for (i = 0; i < FF_ARRAY_ELEMS(error_entries); i++) { + if (errnum == error_entries[i].num) { + entry = &error_entries[i]; + break; + } + } + if (entry) { + av_strlcpy(errbuf, entry->str, errbuf_size); + } else { +#if HAVE_STRERROR_R + ret = AVERROR(strerror_r(AVUNERROR(errnum), errbuf, errbuf_size)); +#else + ret = -1; +#endif + if (ret < 0) + snprintf(errbuf, errbuf_size, "Error number %d occurred", errnum); + } + + return ret; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/error.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/error.h new file mode 100644 index 0000000000..71df4da353 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/error.h @@ -0,0 +1,126 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * error code definitions + */ + +#ifndef AVUTIL_ERROR_H +#define AVUTIL_ERROR_H + +#include +#include + +/** + * @addtogroup lavu_error + * + * @{ + */ + + +/* error handling */ +#if EDOM > 0 +#define AVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. +#define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. +#else +/* Some platforms have E* and errno already negated. */ +#define AVERROR(e) (e) +#define AVUNERROR(e) (e) +#endif + +#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d)) + +#define AVERROR_BSF_NOT_FOUND FFERRTAG(0xF8,'B','S','F') ///< Bitstream filter not found +#define AVERROR_BUG FFERRTAG( 'B','U','G','!') ///< Internal bug, also see AVERROR_BUG2 +#define AVERROR_BUFFER_TOO_SMALL FFERRTAG( 'B','U','F','S') ///< Buffer too small +#define AVERROR_DECODER_NOT_FOUND FFERRTAG(0xF8,'D','E','C') ///< Decoder not found +#define AVERROR_DEMUXER_NOT_FOUND FFERRTAG(0xF8,'D','E','M') ///< Demuxer not found +#define AVERROR_ENCODER_NOT_FOUND FFERRTAG(0xF8,'E','N','C') ///< Encoder not found +#define AVERROR_EOF FFERRTAG( 'E','O','F',' ') ///< End of file +#define AVERROR_EXIT FFERRTAG( 'E','X','I','T') ///< Immediate exit was requested; the called function should not be restarted +#define AVERROR_EXTERNAL FFERRTAG( 'E','X','T',' ') ///< Generic error in an external library +#define AVERROR_FILTER_NOT_FOUND FFERRTAG(0xF8,'F','I','L') ///< Filter not found +#define AVERROR_INVALIDDATA FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input +#define AVERROR_MUXER_NOT_FOUND FFERRTAG(0xF8,'M','U','X') ///< Muxer not found +#define AVERROR_OPTION_NOT_FOUND FFERRTAG(0xF8,'O','P','T') ///< Option not found +#define AVERROR_PATCHWELCOME FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome +#define AVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found + +#define AVERROR_STREAM_NOT_FOUND FFERRTAG(0xF8,'S','T','R') ///< Stream not found +/** + * This is semantically identical to AVERROR_BUG + * it has been introduced in Libav after our AVERROR_BUG and with a modified value. + */ +#define AVERROR_BUG2 FFERRTAG( 'B','U','G',' ') +#define AVERROR_UNKNOWN FFERRTAG( 'U','N','K','N') ///< Unknown error, typically from an external library +#define AVERROR_EXPERIMENTAL (-0x2bb2afa8) ///< Requested feature is flagged experimental. Set strict_std_compliance if you really want to use it. +#define AVERROR_INPUT_CHANGED (-0x636e6701) ///< Input changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_OUTPUT_CHANGED) +#define AVERROR_OUTPUT_CHANGED (-0x636e6702) ///< Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED) +/* HTTP & RTSP errors */ +#define AVERROR_HTTP_BAD_REQUEST FFERRTAG(0xF8,'4','0','0') +#define AVERROR_HTTP_UNAUTHORIZED FFERRTAG(0xF8,'4','0','1') +#define AVERROR_HTTP_FORBIDDEN FFERRTAG(0xF8,'4','0','3') +#define AVERROR_HTTP_NOT_FOUND FFERRTAG(0xF8,'4','0','4') +#define AVERROR_HTTP_OTHER_4XX FFERRTAG(0xF8,'4','X','X') +#define AVERROR_HTTP_SERVER_ERROR FFERRTAG(0xF8,'5','X','X') + +#define AV_ERROR_MAX_STRING_SIZE 64 + +/** + * Put a description of the AVERROR code errnum in errbuf. + * In case of failure the global variable errno is set to indicate the + * error. Even in case of failure av_strerror() will print a generic + * error message indicating the errnum provided to errbuf. + * + * @param errnum error code to describe + * @param errbuf buffer to which description is written + * @param errbuf_size the size in bytes of errbuf + * @return 0 on success, a negative value if a description for errnum + * cannot be found + */ +int av_strerror(int errnum, char *errbuf, size_t errbuf_size); + +/** + * Fill the provided buffer with a string containing an error string + * corresponding to the AVERROR code errnum. + * + * @param errbuf a buffer + * @param errbuf_size size in bytes of errbuf + * @param errnum error code to describe + * @return the buffer in input, filled with the error description + * @see av_strerror() + */ +static inline char *av_make_error_string(char *errbuf, size_t errbuf_size, int errnum) +{ + av_strerror(errnum, errbuf, errbuf_size); + return errbuf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_err2str(errnum) \ + av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum) + +/** + * @} + */ + +#endif /* AVUTIL_ERROR_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/eval.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/eval.c new file mode 100644 index 0000000000..5da9a6d83b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/eval.c @@ -0,0 +1,760 @@ +/* + * Copyright (c) 2002-2006 Michael Niedermayer + * Copyright (c) 2006 Oded Shimon + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple arithmetic expression evaluator. + * + * see http://joe.hotchkiss.com/programming/eval/eval.html + */ + +#include +#include "attributes.h" +#include "avutil.h" +#include "common.h" +#include "eval.h" +#include "ffmath.h" +#include "internal.h" +#include "log.h" +#include "mathematics.h" +#include "time.h" +#include "avstring.h" +#include "timer.h" +#include "reverse.h" + +typedef struct Parser { + const AVClass *class; + int stack_index; + char *s; + const double *const_values; + const char * const *const_names; // NULL terminated + double (* const *funcs1)(void *, double a); // NULL terminated + const char * const *func1_names; // NULL terminated + double (* const *funcs2)(void *, double a, double b); // NULL terminated + const char * const *func2_names; // NULL terminated + void *opaque; + int log_offset; + void *log_ctx; +#define VARS 10 + double *var; +} Parser; + +static const AVClass eval_class = { + .class_name = "Eval", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(Parser, log_offset), + .parent_log_context_offset = offsetof(Parser, log_ctx), +}; + +static const struct { + double bin_val; + double dec_val; + int8_t exp; +} si_prefixes['z' - 'E' + 1] = { + ['y'-'E']= { 8.271806125530276749e-25, 1e-24, -24 }, + ['z'-'E']= { 8.4703294725430034e-22, 1e-21, -21 }, + ['a'-'E']= { 8.6736173798840355e-19, 1e-18, -18 }, + ['f'-'E']= { 8.8817841970012523e-16, 1e-15, -15 }, + ['p'-'E']= { 9.0949470177292824e-13, 1e-12, -12 }, + ['n'-'E']= { 9.3132257461547852e-10, 1e-9, -9 }, + ['u'-'E']= { 9.5367431640625e-7, 1e-6, -6 }, + ['m'-'E']= { 9.765625e-4, 1e-3, -3 }, + ['c'-'E']= { 9.8431332023036951e-3, 1e-2, -2 }, + ['d'-'E']= { 9.921256574801246e-2, 1e-1, -1 }, + ['h'-'E']= { 1.0159366732596479e2, 1e2, 2 }, + ['k'-'E']= { 1.024e3, 1e3, 3 }, + ['K'-'E']= { 1.024e3, 1e3, 3 }, + ['M'-'E']= { 1.048576e6, 1e6, 6 }, + ['G'-'E']= { 1.073741824e9, 1e9, 9 }, + ['T'-'E']= { 1.099511627776e12, 1e12, 12 }, + ['P'-'E']= { 1.125899906842624e15, 1e15, 15 }, + ['E'-'E']= { 1.152921504606847e18, 1e18, 18 }, + ['Z'-'E']= { 1.1805916207174113e21, 1e21, 21 }, + ['Y'-'E']= { 1.2089258196146292e24, 1e24, 24 }, +}; + +static const struct { + const char *name; + double value; +} constants[] = { + { "E", M_E }, + { "PI", M_PI }, + { "PHI", M_PHI }, + { "QP2LAMBDA", FF_QP2LAMBDA }, +}; + +double av_strtod(const char *numstr, char **tail) +{ + double d; + char *next; + if(numstr[0]=='0' && (numstr[1]|0x20)=='x') { + d = strtoul(numstr, &next, 16); + } else + d = strtod(numstr, &next); + /* if parsing succeeded, check for and interpret postfixes */ + if (next!=numstr) { + if (next[0] == 'd' && next[1] == 'B') { + /* treat dB as decibels instead of decibytes */ + d = ff_exp10(d / 20); + next += 2; + } else if (*next >= 'E' && *next <= 'z') { + int e= si_prefixes[*next - 'E'].exp; + if (e) { + if (next[1] == 'i') { + d*= si_prefixes[*next - 'E'].bin_val; + next+=2; + } else { + d*= si_prefixes[*next - 'E'].dec_val; + next++; + } + } + } + + if (*next=='B') { + d*=8; + next++; + } + } + /* if requested, fill in tail with the position after the last parsed + character */ + if (tail) + *tail = next; + return d; +} + +#define IS_IDENTIFIER_CHAR(c) ((c) - '0' <= 9U || (c) - 'a' <= 25U || (c) - 'A' <= 25U || (c) == '_') + +static int strmatch(const char *s, const char *prefix) +{ + int i; + for (i=0; prefix[i]; i++) { + if (prefix[i] != s[i]) return 0; + } + /* return 1 only if the s identifier is terminated */ + return !IS_IDENTIFIER_CHAR(s[i]); +} + +struct AVExpr { + enum { + e_value, e_const, e_func0, e_func1, e_func2, + e_squish, e_gauss, e_ld, e_isnan, e_isinf, + e_mod, e_max, e_min, e_eq, e_gt, e_gte, e_lte, e_lt, + e_pow, e_mul, e_div, e_add, + e_last, e_st, e_while, e_taylor, e_root, e_floor, e_ceil, e_trunc, e_round, + e_sqrt, e_not, e_random, e_hypot, e_gcd, + e_if, e_ifnot, e_print, e_bitand, e_bitor, e_between, e_clip, e_atan2, e_lerp, + } type; + double value; // is sign in other types + union { + int const_index; + double (*func0)(double); + double (*func1)(void *, double); + double (*func2)(void *, double, double); + } a; + struct AVExpr *param[3]; + double *var; +}; + +static double etime(double v) +{ + return av_gettime() * 0.000001; +} + +static double eval_expr(Parser *p, AVExpr *e) +{ + switch (e->type) { + case e_value: return e->value; + case e_const: return e->value * p->const_values[e->a.const_index]; + case e_func0: return e->value * e->a.func0(eval_expr(p, e->param[0])); + case e_func1: return e->value * e->a.func1(p->opaque, eval_expr(p, e->param[0])); + case e_func2: return e->value * e->a.func2(p->opaque, eval_expr(p, e->param[0]), eval_expr(p, e->param[1])); + case e_squish: return 1/(1+exp(4*eval_expr(p, e->param[0]))); + case e_gauss: { double d = eval_expr(p, e->param[0]); return exp(-d*d/2)/sqrt(2*M_PI); } + case e_ld: return e->value * p->var[av_clip(eval_expr(p, e->param[0]), 0, VARS-1)]; + case e_isnan: return e->value * !!isnan(eval_expr(p, e->param[0])); + case e_isinf: return e->value * !!isinf(eval_expr(p, e->param[0])); + case e_floor: return e->value * floor(eval_expr(p, e->param[0])); + case e_ceil : return e->value * ceil (eval_expr(p, e->param[0])); + case e_trunc: return e->value * trunc(eval_expr(p, e->param[0])); + case e_round: return e->value * round(eval_expr(p, e->param[0])); + case e_sqrt: return e->value * sqrt (eval_expr(p, e->param[0])); + case e_not: return e->value * (eval_expr(p, e->param[0]) == 0); + case e_if: return e->value * (eval_expr(p, e->param[0]) ? eval_expr(p, e->param[1]) : + e->param[2] ? eval_expr(p, e->param[2]) : 0); + case e_ifnot: return e->value * (!eval_expr(p, e->param[0]) ? eval_expr(p, e->param[1]) : + e->param[2] ? eval_expr(p, e->param[2]) : 0); + case e_clip: { + double x = eval_expr(p, e->param[0]); + double min = eval_expr(p, e->param[1]), max = eval_expr(p, e->param[2]); + if (isnan(min) || isnan(max) || isnan(x) || min > max) + return NAN; + return e->value * av_clipd(eval_expr(p, e->param[0]), min, max); + } + case e_between: { + double d = eval_expr(p, e->param[0]); + return e->value * (d >= eval_expr(p, e->param[1]) && + d <= eval_expr(p, e->param[2])); + } + case e_lerp: { + double v0 = eval_expr(p, e->param[0]); + double v1 = eval_expr(p, e->param[1]); + double f = eval_expr(p, e->param[2]); + return v0 + (v1 - v0) * f; + } + case e_print: { + double x = eval_expr(p, e->param[0]); + int level = e->param[1] ? av_clip(eval_expr(p, e->param[1]), INT_MIN, INT_MAX) : AV_LOG_INFO; + av_log(p, level, "%f\n", x); + return x; + } + case e_random:{ + int idx= av_clip(eval_expr(p, e->param[0]), 0, VARS-1); + uint64_t r= isnan(p->var[idx]) ? 0 : p->var[idx]; + r= r*1664525+1013904223; + p->var[idx]= r; + return e->value * (r * (1.0/UINT64_MAX)); + } + case e_while: { + double d = NAN; + while (eval_expr(p, e->param[0])) + d=eval_expr(p, e->param[1]); + return d; + } + case e_taylor: { + double t = 1, d = 0, v; + double x = eval_expr(p, e->param[1]); + int id = e->param[2] ? av_clip(eval_expr(p, e->param[2]), 0, VARS-1) : 0; + int i; + double var0 = p->var[id]; + for(i=0; i<1000; i++) { + double ld = d; + p->var[id] = i; + v = eval_expr(p, e->param[0]); + d += t*v; + if(ld==d && v) + break; + t *= x / (i+1); + } + p->var[id] = var0; + return d; + } + case e_root: { + int i, j; + double low = -1, high = -1, v, low_v = -DBL_MAX, high_v = DBL_MAX; + double var0 = p->var[0]; + double x_max = eval_expr(p, e->param[1]); + for(i=-1; i<1024; i++) { + if(i<255) { + p->var[0] = ff_reverse[i&255]*x_max/255; + } else { + p->var[0] = x_max*pow(0.9, i-255); + if (i&1) p->var[0] *= -1; + if (i&2) p->var[0] += low; + else p->var[0] += high; + } + v = eval_expr(p, e->param[0]); + if (v<=0 && v>low_v) { + low = p->var[0]; + low_v = v; + } + if (v>=0 && vvar[0]; + high_v = v; + } + if (low>=0 && high>=0){ + for (j=0; j<1000; j++) { + p->var[0] = (low+high)*0.5; + if (low == p->var[0] || high == p->var[0]) + break; + v = eval_expr(p, e->param[0]); + if (v<=0) low = p->var[0]; + if (v>=0) high= p->var[0]; + if (isnan(v)) { + low = high = v; + break; + } + } + break; + } + } + p->var[0] = var0; + return -low_vparam[0]); + double d2 = eval_expr(p, e->param[1]); + switch (e->type) { + case e_mod: return e->value * (d - floor((!CONFIG_FTRAPV || d2) ? d / d2 : d * INFINITY) * d2); + case e_gcd: return e->value * av_gcd(d,d2); + case e_max: return e->value * (d > d2 ? d : d2); + case e_min: return e->value * (d < d2 ? d : d2); + case e_eq: return e->value * (d == d2 ? 1.0 : 0.0); + case e_gt: return e->value * (d > d2 ? 1.0 : 0.0); + case e_gte: return e->value * (d >= d2 ? 1.0 : 0.0); + case e_lt: return e->value * (d < d2 ? 1.0 : 0.0); + case e_lte: return e->value * (d <= d2 ? 1.0 : 0.0); + case e_pow: return e->value * pow(d, d2); + case e_mul: return e->value * (d * d2); + case e_div: return e->value * ((!CONFIG_FTRAPV || d2 ) ? (d / d2) : d * INFINITY); + case e_add: return e->value * (d + d2); + case e_last:return e->value * d2; + case e_st : return e->value * (p->var[av_clip(d, 0, VARS-1)]= d2); + case e_hypot:return e->value * hypot(d, d2); + case e_atan2:return e->value * atan2(d, d2); + case e_bitand: return isnan(d) || isnan(d2) ? NAN : e->value * ((long int)d & (long int)d2); + case e_bitor: return isnan(d) || isnan(d2) ? NAN : e->value * ((long int)d | (long int)d2); + } + } + } + return NAN; +} + +static int parse_expr(AVExpr **e, Parser *p); + +void av_expr_free(AVExpr *e) +{ + if (!e) return; + av_expr_free(e->param[0]); + av_expr_free(e->param[1]); + av_expr_free(e->param[2]); + av_freep(&e->var); + av_freep(&e); +} + +static int parse_primary(AVExpr **e, Parser *p) +{ + AVExpr *d = av_mallocz(sizeof(AVExpr)); + char *next = p->s, *s0 = p->s; + int ret, i; + + if (!d) + return AVERROR(ENOMEM); + + /* number */ + d->value = av_strtod(p->s, &next); + if (next != p->s) { + d->type = e_value; + p->s= next; + *e = d; + return 0; + } + d->value = 1; + + /* named constants */ + for (i=0; p->const_names && p->const_names[i]; i++) { + if (strmatch(p->s, p->const_names[i])) { + p->s+= strlen(p->const_names[i]); + d->type = e_const; + d->a.const_index = i; + *e = d; + return 0; + } + } + for (i = 0; i < FF_ARRAY_ELEMS(constants); i++) { + if (strmatch(p->s, constants[i].name)) { + p->s += strlen(constants[i].name); + d->type = e_value; + d->value = constants[i].value; + *e = d; + return 0; + } + } + + p->s= strchr(p->s, '('); + if (!p->s) { + av_log(p, AV_LOG_ERROR, "Undefined constant or missing '(' in '%s'\n", s0); + p->s= next; + av_expr_free(d); + return AVERROR(EINVAL); + } + p->s++; // "(" + if (*next == '(') { // special case do-nothing + av_freep(&d); + if ((ret = parse_expr(&d, p)) < 0) + return ret; + if (p->s[0] != ')') { + av_log(p, AV_LOG_ERROR, "Missing ')' in '%s'\n", s0); + av_expr_free(d); + return AVERROR(EINVAL); + } + p->s++; // ")" + *e = d; + return 0; + } + if ((ret = parse_expr(&(d->param[0]), p)) < 0) { + av_expr_free(d); + return ret; + } + if (p->s[0]== ',') { + p->s++; // "," + parse_expr(&d->param[1], p); + } + if (p->s[0]== ',') { + p->s++; // "," + parse_expr(&d->param[2], p); + } + if (p->s[0] != ')') { + av_log(p, AV_LOG_ERROR, "Missing ')' or too many args in '%s'\n", s0); + av_expr_free(d); + return AVERROR(EINVAL); + } + p->s++; // ")" + + d->type = e_func0; + if (strmatch(next, "sinh" )) d->a.func0 = sinh; + else if (strmatch(next, "cosh" )) d->a.func0 = cosh; + else if (strmatch(next, "tanh" )) d->a.func0 = tanh; + else if (strmatch(next, "sin" )) d->a.func0 = sin; + else if (strmatch(next, "cos" )) d->a.func0 = cos; + else if (strmatch(next, "tan" )) d->a.func0 = tan; + else if (strmatch(next, "atan" )) d->a.func0 = atan; + else if (strmatch(next, "asin" )) d->a.func0 = asin; + else if (strmatch(next, "acos" )) d->a.func0 = acos; + else if (strmatch(next, "exp" )) d->a.func0 = exp; + else if (strmatch(next, "log" )) d->a.func0 = log; + else if (strmatch(next, "abs" )) d->a.func0 = fabs; + else if (strmatch(next, "time" )) d->a.func0 = etime; + else if (strmatch(next, "squish")) d->type = e_squish; + else if (strmatch(next, "gauss" )) d->type = e_gauss; + else if (strmatch(next, "mod" )) d->type = e_mod; + else if (strmatch(next, "max" )) d->type = e_max; + else if (strmatch(next, "min" )) d->type = e_min; + else if (strmatch(next, "eq" )) d->type = e_eq; + else if (strmatch(next, "gte" )) d->type = e_gte; + else if (strmatch(next, "gt" )) d->type = e_gt; + else if (strmatch(next, "lte" )) d->type = e_lte; + else if (strmatch(next, "lt" )) d->type = e_lt; + else if (strmatch(next, "ld" )) d->type = e_ld; + else if (strmatch(next, "isnan" )) d->type = e_isnan; + else if (strmatch(next, "isinf" )) d->type = e_isinf; + else if (strmatch(next, "st" )) d->type = e_st; + else if (strmatch(next, "while" )) d->type = e_while; + else if (strmatch(next, "taylor")) d->type = e_taylor; + else if (strmatch(next, "root" )) d->type = e_root; + else if (strmatch(next, "floor" )) d->type = e_floor; + else if (strmatch(next, "ceil" )) d->type = e_ceil; + else if (strmatch(next, "trunc" )) d->type = e_trunc; + else if (strmatch(next, "round" )) d->type = e_round; + else if (strmatch(next, "sqrt" )) d->type = e_sqrt; + else if (strmatch(next, "not" )) d->type = e_not; + else if (strmatch(next, "pow" )) d->type = e_pow; + else if (strmatch(next, "print" )) d->type = e_print; + else if (strmatch(next, "random")) d->type = e_random; + else if (strmatch(next, "hypot" )) d->type = e_hypot; + else if (strmatch(next, "gcd" )) d->type = e_gcd; + else if (strmatch(next, "if" )) d->type = e_if; + else if (strmatch(next, "ifnot" )) d->type = e_ifnot; + else if (strmatch(next, "bitand")) d->type = e_bitand; + else if (strmatch(next, "bitor" )) d->type = e_bitor; + else if (strmatch(next, "between"))d->type = e_between; + else if (strmatch(next, "clip" )) d->type = e_clip; + else if (strmatch(next, "atan2" )) d->type = e_atan2; + else if (strmatch(next, "lerp" )) d->type = e_lerp; + else { + for (i=0; p->func1_names && p->func1_names[i]; i++) { + if (strmatch(next, p->func1_names[i])) { + d->a.func1 = p->funcs1[i]; + d->type = e_func1; + *e = d; + return 0; + } + } + + for (i=0; p->func2_names && p->func2_names[i]; i++) { + if (strmatch(next, p->func2_names[i])) { + d->a.func2 = p->funcs2[i]; + d->type = e_func2; + *e = d; + return 0; + } + } + + av_log(p, AV_LOG_ERROR, "Unknown function in '%s'\n", s0); + av_expr_free(d); + return AVERROR(EINVAL); + } + + *e = d; + return 0; +} + +static AVExpr *make_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1) +{ + AVExpr *e = av_mallocz(sizeof(AVExpr)); + if (!e) + return NULL; + e->type =type ; + e->value =value ; + e->param[0] =p0 ; + e->param[1] =p1 ; + return e; +} + +static int parse_pow(AVExpr **e, Parser *p, int *sign) +{ + *sign= (*p->s == '+') - (*p->s == '-'); + p->s += *sign&1; + return parse_primary(e, p); +} + +static int parse_dB(AVExpr **e, Parser *p, int *sign) +{ + /* do not filter out the negative sign when parsing a dB value. + for example, -3dB is not the same as -(3dB) */ + if (*p->s == '-') { + char *next; + double av_unused ignored = strtod(p->s, &next); + if (next != p->s && next[0] == 'd' && next[1] == 'B') { + *sign = 0; + return parse_primary(e, p); + } + } + return parse_pow(e, p, sign); +} + +static int parse_factor(AVExpr **e, Parser *p) +{ + int sign, sign2, ret; + AVExpr *e0, *e1, *e2; + if ((ret = parse_dB(&e0, p, &sign)) < 0) + return ret; + while(p->s[0]=='^'){ + e1 = e0; + p->s++; + if ((ret = parse_dB(&e2, p, &sign2)) < 0) { + av_expr_free(e1); + return ret; + } + e0 = make_eval_expr(e_pow, 1, e1, e2); + if (!e0) { + av_expr_free(e1); + av_expr_free(e2); + return AVERROR(ENOMEM); + } + if (e0->param[1]) e0->param[1]->value *= (sign2|1); + } + if (e0) e0->value *= (sign|1); + + *e = e0; + return 0; +} + +static int parse_term(AVExpr **e, Parser *p) +{ + int ret; + AVExpr *e0, *e1, *e2; + if ((ret = parse_factor(&e0, p)) < 0) + return ret; + while (p->s[0]=='*' || p->s[0]=='/') { + int c= *p->s++; + e1 = e0; + if ((ret = parse_factor(&e2, p)) < 0) { + av_expr_free(e1); + return ret; + } + e0 = make_eval_expr(c == '*' ? e_mul : e_div, 1, e1, e2); + if (!e0) { + av_expr_free(e1); + av_expr_free(e2); + return AVERROR(ENOMEM); + } + } + *e = e0; + return 0; +} + +static int parse_subexpr(AVExpr **e, Parser *p) +{ + int ret; + AVExpr *e0, *e1, *e2; + if ((ret = parse_term(&e0, p)) < 0) + return ret; + while (*p->s == '+' || *p->s == '-') { + e1 = e0; + if ((ret = parse_term(&e2, p)) < 0) { + av_expr_free(e1); + return ret; + } + e0 = make_eval_expr(e_add, 1, e1, e2); + if (!e0) { + av_expr_free(e1); + av_expr_free(e2); + return AVERROR(ENOMEM); + } + }; + + *e = e0; + return 0; +} + +static int parse_expr(AVExpr **e, Parser *p) +{ + int ret; + AVExpr *e0, *e1, *e2; + if (p->stack_index <= 0) //protect against stack overflows + return AVERROR(EINVAL); + p->stack_index--; + + if ((ret = parse_subexpr(&e0, p)) < 0) + return ret; + while (*p->s == ';') { + p->s++; + e1 = e0; + if ((ret = parse_subexpr(&e2, p)) < 0) { + av_expr_free(e1); + return ret; + } + e0 = make_eval_expr(e_last, 1, e1, e2); + if (!e0) { + av_expr_free(e1); + av_expr_free(e2); + return AVERROR(ENOMEM); + } + }; + + p->stack_index++; + *e = e0; + return 0; +} + +static int verify_expr(AVExpr *e) +{ + if (!e) return 0; + switch (e->type) { + case e_value: + case e_const: return 1; + case e_func0: + case e_func1: + case e_squish: + case e_ld: + case e_gauss: + case e_isnan: + case e_isinf: + case e_floor: + case e_ceil: + case e_trunc: + case e_round: + case e_sqrt: + case e_not: + case e_random: + return verify_expr(e->param[0]) && !e->param[1]; + case e_print: + return verify_expr(e->param[0]) + && (!e->param[1] || verify_expr(e->param[1])); + case e_if: + case e_ifnot: + case e_taylor: + return verify_expr(e->param[0]) && verify_expr(e->param[1]) + && (!e->param[2] || verify_expr(e->param[2])); + case e_between: + case e_clip: + case e_lerp: + return verify_expr(e->param[0]) && + verify_expr(e->param[1]) && + verify_expr(e->param[2]); + default: return verify_expr(e->param[0]) && verify_expr(e->param[1]) && !e->param[2]; + } +} + +int av_expr_parse(AVExpr **expr, const char *s, + const char * const *const_names, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + int log_offset, void *log_ctx) +{ + Parser p = { 0 }; + AVExpr *e = NULL; + char *w = av_malloc(strlen(s) + 1); + char *wp = w; + const char *s0 = s; + int ret = 0; + + if (!w) + return AVERROR(ENOMEM); + + while (*s) + if (!av_isspace(*s++)) *wp++ = s[-1]; + *wp++ = 0; + + p.class = &eval_class; + p.stack_index=100; + p.s= w; + p.const_names = const_names; + p.funcs1 = funcs1; + p.func1_names = func1_names; + p.funcs2 = funcs2; + p.func2_names = func2_names; + p.log_offset = log_offset; + p.log_ctx = log_ctx; + + if ((ret = parse_expr(&e, &p)) < 0) + goto end; + if (*p.s) { + av_log(&p, AV_LOG_ERROR, "Invalid chars '%s' at the end of expression '%s'\n", p.s, s0); + ret = AVERROR(EINVAL); + goto end; + } + if (!verify_expr(e)) { + ret = AVERROR(EINVAL); + goto end; + } + e->var= av_mallocz(sizeof(double) *VARS); + if (!e->var) { + ret = AVERROR(ENOMEM); + goto end; + } + *expr = e; + e = NULL; +end: + av_expr_free(e); + av_free(w); + return ret; +} + +double av_expr_eval(AVExpr *e, const double *const_values, void *opaque) +{ + Parser p = { 0 }; + p.var= e->var; + + p.const_values = const_values; + p.opaque = opaque; + return eval_expr(&p, e); +} + +int av_expr_parse_and_eval(double *d, const char *s, + const char * const *const_names, const double *const_values, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + void *opaque, int log_offset, void *log_ctx) +{ + AVExpr *e = NULL; + int ret = av_expr_parse(&e, s, const_names, func1_names, funcs1, func2_names, funcs2, log_offset, log_ctx); + + if (ret < 0) { + *d = NAN; + return ret; + } + *d = av_expr_eval(e, const_values, opaque); + av_expr_free(e); + return isnan(*d) ? AVERROR(EINVAL) : 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/eval.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/eval.h new file mode 100644 index 0000000000..dacd22b96e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/eval.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple arithmetic expression evaluator + */ + +#ifndef AVUTIL_EVAL_H +#define AVUTIL_EVAL_H + +#include "avutil.h" + +typedef struct AVExpr AVExpr; + +/** + * Parse and evaluate an expression. + * Note, this is significantly slower than av_expr_eval(). + * + * @param res a pointer to a double where is put the result value of + * the expression, or NAN in case of error + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param const_values a zero terminated array of values for the identifiers from const_names + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse_and_eval(double *res, const char *s, + const char * const *const_names, const double *const_values, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + void *opaque, int log_offset, void *log_ctx); + +/** + * Parse an expression. + * + * @param expr a pointer where is put an AVExpr containing the parsed + * value in case of successful parsing, or NULL otherwise. + * The pointed to AVExpr must be freed with av_expr_free() by the user + * when it is not needed anymore. + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse(AVExpr **expr, const char *s, + const char * const *const_names, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + int log_offset, void *log_ctx); + +/** + * Evaluate a previously parsed expression. + * + * @param const_values a zero terminated array of values for the identifiers from av_expr_parse() const_names + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @return the value of the expression + */ +double av_expr_eval(AVExpr *e, const double *const_values, void *opaque); + +/** + * Free a parsed expression previously created with av_expr_parse(). + */ +void av_expr_free(AVExpr *e); + +/** + * Parse the string in numstr and return its value as a double. If + * the string is empty, contains only whitespaces, or does not contain + * an initial substring that has the expected syntax for a + * floating-point number, no conversion is performed. In this case, + * returns a value of zero and the value returned in tail is the value + * of numstr. + * + * @param numstr a string representing a number, may contain one of + * the International System number postfixes, for example 'K', 'M', + * 'G'. If 'i' is appended after the postfix, powers of 2 are used + * instead of powers of 10. The 'B' postfix multiplies the value by + * 8, and can be appended after another postfix or used alone. This + * allows using for example 'KB', 'MiB', 'G' and 'B' as postfix. + * @param tail if non-NULL puts here the pointer to the char next + * after the last parsed character + */ +double av_strtod(const char *numstr, char **tail); + +#endif /* AVUTIL_EVAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffmath.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffmath.h new file mode 100644 index 0000000000..aad1347f26 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffmath.h @@ -0,0 +1,67 @@ +/* + * copyright (c) 2016 Ganesh Ajjanagadde + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * internal math functions header + */ + +#ifndef AVUTIL_FFMATH_H +#define AVUTIL_FFMATH_H + +#include "attributes.h" +#include "libm.h" + +/** + * Compute 10^x for floating point values. Note: this function is by no means + * "correctly rounded", and is meant as a fast, reasonably accurate approximation. + * For instance, maximum relative error for the double precision variant is + * ~ 1e-13 for very small and very large values. + * This is ~2x faster than GNU libm's approach, which is still off by 2ulp on + * some inputs. + * @param x exponent + * @return 10^x + */ +static av_always_inline double ff_exp10(double x) +{ + return exp2(M_LOG2_10 * x); +} + +static av_always_inline float ff_exp10f(float x) +{ + return exp2f(M_LOG2_10 * x); +} + +/** + * Compute x^y for floating point x, y. Note: this function is faster than the + * libm variant due to mainly 2 reasons: + * 1. It does not handle any edge cases. In particular, this is only guaranteed + * to work correctly for x > 0. + * 2. It is not as accurate as a standard nearly "correctly rounded" libm variant. + * @param x base + * @param y exponent + * @return x^y + */ +static av_always_inline float ff_fast_powf(float x, float y) +{ + return expf(logf(x) * y); +} + +#endif /* AVUTIL_FFMATH_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffversion.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffversion.h new file mode 100644 index 0000000000..723c7d4244 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffversion.h @@ -0,0 +1,5 @@ +/* Automatically generated by version.sh, do not manually edit! */ +#ifndef AVUTIL_FFVERSION_H +#define AVUTIL_FFVERSION_H +#define FFMPEG_VERSION "" +#endif /* AVUTIL_FFVERSION_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fifo.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fifo.c new file mode 100644 index 0000000000..1060aedf13 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fifo.c @@ -0,0 +1,240 @@ +/* + * a very simple circular buffer FIFO implementation + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * Copyright (c) 2006 Roman Shaposhnik + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avassert.h" +#include "common.h" +#include "fifo.h" + +static AVFifoBuffer *fifo_alloc_common(void *buffer, size_t size) +{ + AVFifoBuffer *f; + if (!buffer) + return NULL; + f = av_mallocz(sizeof(AVFifoBuffer)); + if (!f) { + av_free(buffer); + return NULL; + } + f->buffer = buffer; + f->end = f->buffer + size; + av_fifo_reset(f); + return f; +} + +AVFifoBuffer *av_fifo_alloc(unsigned int size) +{ + void *buffer = av_malloc(size); + return fifo_alloc_common(buffer, size); +} + +AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size) +{ + void *buffer = av_malloc_array(nmemb, size); + return fifo_alloc_common(buffer, nmemb * size); +} + +void av_fifo_free(AVFifoBuffer *f) +{ + if (f) { + av_freep(&f->buffer); + av_free(f); + } +} + +void av_fifo_freep(AVFifoBuffer **f) +{ + if (f) { + av_fifo_free(*f); + *f = NULL; + } +} + +void av_fifo_reset(AVFifoBuffer *f) +{ + f->wptr = f->rptr = f->buffer; + f->wndx = f->rndx = 0; +} + +int av_fifo_size(const AVFifoBuffer *f) +{ + return (uint32_t)(f->wndx - f->rndx); +} + +int av_fifo_space(const AVFifoBuffer *f) +{ + return f->end - f->buffer - av_fifo_size(f); +} + +int av_fifo_realloc2(AVFifoBuffer *f, unsigned int new_size) +{ + unsigned int old_size = f->end - f->buffer; + + if (old_size < new_size) { + int len = av_fifo_size(f); + AVFifoBuffer *f2 = av_fifo_alloc(new_size); + + if (!f2) + return AVERROR(ENOMEM); + av_fifo_generic_read(f, f2->buffer, len, NULL); + f2->wptr += len; + f2->wndx += len; + av_free(f->buffer); + *f = *f2; + av_free(f2); + } + return 0; +} + +int av_fifo_grow(AVFifoBuffer *f, unsigned int size) +{ + unsigned int old_size = f->end - f->buffer; + if(size + (unsigned)av_fifo_size(f) < size) + return AVERROR(EINVAL); + + size += av_fifo_size(f); + + if (old_size < size) + return av_fifo_realloc2(f, FFMAX(size, 2*old_size)); + return 0; +} + +/* src must NOT be const as it can be a context for func that may need + * updating (like a pointer or byte counter) */ +int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, + int (*func)(void *, void *, int)) +{ + int total = size; + uint32_t wndx= f->wndx; + uint8_t *wptr= f->wptr; + + do { + int len = FFMIN(f->end - wptr, size); + if (func) { + len = func(src, wptr, len); + if (len <= 0) + break; + } else { + memcpy(wptr, src, len); + src = (uint8_t *)src + len; + } +// Write memory barrier needed for SMP here in theory + wptr += len; + if (wptr >= f->end) + wptr = f->buffer; + wndx += len; + size -= len; + } while (size > 0); + f->wndx= wndx; + f->wptr= wptr; + return total - size; +} + +int av_fifo_generic_peek_at(AVFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int)) +{ + uint8_t *rptr = f->rptr; + + av_assert2(offset >= 0); + + /* + * *ndx are indexes modulo 2^32, they are intended to overflow, + * to handle *ndx greater than 4gb. + */ + av_assert2(buf_size + (unsigned)offset <= f->wndx - f->rndx); + + if (offset >= f->end - rptr) + rptr += offset - (f->end - f->buffer); + else + rptr += offset; + + while (buf_size > 0) { + int len; + + if (rptr >= f->end) + rptr -= f->end - f->buffer; + + len = FFMIN(f->end - rptr, buf_size); + if (func) + func(dest, rptr, len); + else { + memcpy(dest, rptr, len); + dest = (uint8_t *)dest + len; + } + + buf_size -= len; + rptr += len; + } + + return 0; +} + +int av_fifo_generic_peek(AVFifoBuffer *f, void *dest, int buf_size, + void (*func)(void *, void *, int)) +{ +// Read memory barrier needed for SMP here in theory + uint8_t *rptr = f->rptr; + + do { + int len = FFMIN(f->end - rptr, buf_size); + if (func) + func(dest, rptr, len); + else { + memcpy(dest, rptr, len); + dest = (uint8_t *)dest + len; + } +// memory barrier needed for SMP here in theory + rptr += len; + if (rptr >= f->end) + rptr -= f->end - f->buffer; + buf_size -= len; + } while (buf_size > 0); + + return 0; +} + +int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, + void (*func)(void *, void *, int)) +{ +// Read memory barrier needed for SMP here in theory + do { + int len = FFMIN(f->end - f->rptr, buf_size); + if (func) + func(dest, f->rptr, len); + else { + memcpy(dest, f->rptr, len); + dest = (uint8_t *)dest + len; + } +// memory barrier needed for SMP here in theory + av_fifo_drain(f, len); + buf_size -= len; + } while (buf_size > 0); + return 0; +} + +/** Discard data from the FIFO. */ +void av_fifo_drain(AVFifoBuffer *f, int size) +{ + av_assert2(av_fifo_size(f) >= size); + f->rptr += size; + if (f->rptr >= f->end) + f->rptr -= f->end - f->buffer; + f->rndx += size; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fifo.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fifo.h new file mode 100644 index 0000000000..dc7bc6f0dd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fifo.h @@ -0,0 +1,179 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * a very simple circular buffer FIFO implementation + */ + +#ifndef AVUTIL_FIFO_H +#define AVUTIL_FIFO_H + +#include +#include "avutil.h" +#include "attributes.h" + +typedef struct AVFifoBuffer { + uint8_t *buffer; + uint8_t *rptr, *wptr, *end; + uint32_t rndx, wndx; +} AVFifoBuffer; + +/** + * Initialize an AVFifoBuffer. + * @param size of FIFO + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc(unsigned int size); + +/** + * Initialize an AVFifoBuffer. + * @param nmemb number of elements + * @param size size of the single element + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size); + +/** + * Free an AVFifoBuffer. + * @param f AVFifoBuffer to free + */ +void av_fifo_free(AVFifoBuffer *f); + +/** + * Free an AVFifoBuffer and reset pointer to NULL. + * @param f AVFifoBuffer to free + */ +void av_fifo_freep(AVFifoBuffer **f); + +/** + * Reset the AVFifoBuffer to the state right after av_fifo_alloc, in particular it is emptied. + * @param f AVFifoBuffer to reset + */ +void av_fifo_reset(AVFifoBuffer *f); + +/** + * Return the amount of data in bytes in the AVFifoBuffer, that is the + * amount of data you can read from it. + * @param f AVFifoBuffer to read from + * @return size + */ +int av_fifo_size(const AVFifoBuffer *f); + +/** + * Return the amount of space in bytes in the AVFifoBuffer, that is the + * amount of data you can write into it. + * @param f AVFifoBuffer to write into + * @return size + */ +int av_fifo_space(const AVFifoBuffer *f); + +/** + * Feed data at specific position from an AVFifoBuffer to a user-supplied callback. + * Similar as av_fifo_gereric_read but without discarding data. + * @param f AVFifoBuffer to read from + * @param offset offset from current read position + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_peek_at(AVFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from an AVFifoBuffer to a user-supplied callback. + * Similar as av_fifo_gereric_read but without discarding data. + * @param f AVFifoBuffer to read from + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_peek(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from an AVFifoBuffer to a user-supplied callback. + * @param f AVFifoBuffer to read from + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from a user-supplied callback to an AVFifoBuffer. + * @param f AVFifoBuffer to write to + * @param src data source; non-const since it may be used as a + * modifiable context by the function defined in func + * @param size number of bytes to write + * @param func generic write function; the first parameter is src, + * the second is dest_buf, the third is dest_buf_size. + * func must return the number of bytes written to dest_buf, or <= 0 to + * indicate no more data available to write. + * If func is NULL, src is interpreted as a simple byte array for source data. + * @return the number of bytes written to the FIFO + */ +int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int)); + +/** + * Resize an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * + * @param f AVFifoBuffer to resize + * @param size new AVFifoBuffer size in bytes + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_realloc2(AVFifoBuffer *f, unsigned int size); + +/** + * Enlarge an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * The new fifo size may be larger than the requested size. + * + * @param f AVFifoBuffer to resize + * @param additional_space the amount of space in bytes to allocate in addition to av_fifo_size() + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_grow(AVFifoBuffer *f, unsigned int additional_space); + +/** + * Read and discard the specified amount of data from an AVFifoBuffer. + * @param f AVFifoBuffer to read from + * @param size amount of data to read in bytes + */ +void av_fifo_drain(AVFifoBuffer *f, int size); + +/** + * Return a pointer to the data stored in a FIFO buffer at a certain offset. + * The FIFO buffer is not modified. + * + * @param f AVFifoBuffer to peek at, f must be non-NULL + * @param offs an offset in bytes, its absolute value must be less + * than the used buffer size or the returned pointer will + * point outside to the buffer data. + * The used buffer size can be checked with av_fifo_size(). + */ +static inline uint8_t *av_fifo_peek2(const AVFifoBuffer *f, int offs) +{ + uint8_t *ptr = f->rptr + offs; + if (ptr >= f->end) + ptr = f->buffer + (ptr - f->end); + else if (ptr < f->buffer) + ptr = f->end - (f->buffer - ptr); + return ptr; +} + +#endif /* AVUTIL_FIFO_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file.c new file mode 100644 index 0000000000..d946085b28 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file.c @@ -0,0 +1,154 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "file.h" +#include "internal.h" +#include "log.h" +#include "mem.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_IO_H +#include +#endif +#if HAVE_MMAP +#include +#elif HAVE_MAPVIEWOFFILE +#include +#endif + +typedef struct FileLogContext { + const AVClass *class; + int log_offset; + void *log_ctx; +} FileLogContext; + +static const AVClass file_log_ctx_class = { + .class_name = "FILE", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(FileLogContext, log_offset), + .parent_log_context_offset = offsetof(FileLogContext, log_ctx), +}; + +int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, + int log_offset, void *log_ctx) +{ + FileLogContext file_log_ctx = { &file_log_ctx_class, log_offset, log_ctx }; + int err, fd = avpriv_open(filename, O_RDONLY); + struct stat st; + av_unused void *ptr; + off_t off_size; + char errbuf[128]; + *bufptr = NULL; + + if (fd < 0) { + err = AVERROR(errno); + av_strerror(err, errbuf, sizeof(errbuf)); + av_log(&file_log_ctx, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename, errbuf); + return err; + } + + if (fstat(fd, &st) < 0) { + err = AVERROR(errno); + av_strerror(err, errbuf, sizeof(errbuf)); + av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in fstat(): %s\n", errbuf); + close(fd); + return err; + } + + off_size = st.st_size; + if (off_size > SIZE_MAX) { + av_log(&file_log_ctx, AV_LOG_ERROR, + "File size for file '%s' is too big\n", filename); + close(fd); + return AVERROR(EINVAL); + } + *size = off_size; + + if (!*size) { + *bufptr = NULL; + goto out; + } + +#if HAVE_MMAP + ptr = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (ptr == MAP_FAILED) { + err = AVERROR(errno); + av_strerror(err, errbuf, sizeof(errbuf)); + av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in mmap(): %s\n", errbuf); + close(fd); + return err; + } + *bufptr = ptr; +#elif HAVE_MAPVIEWOFFILE + { + HANDLE mh, fh = (HANDLE)_get_osfhandle(fd); + + mh = CreateFileMapping(fh, NULL, PAGE_READONLY, 0, 0, NULL); + if (!mh) { + av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in CreateFileMapping()\n"); + close(fd); + return -1; + } + + ptr = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, *size); + CloseHandle(mh); + if (!ptr) { + av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in MapViewOfFile()\n"); + close(fd); + return -1; + } + + *bufptr = ptr; + } +#else + *bufptr = av_malloc(*size); + if (!*bufptr) { + av_log(&file_log_ctx, AV_LOG_ERROR, "Memory allocation error occurred\n"); + close(fd); + return AVERROR(ENOMEM); + } + read(fd, *bufptr, *size); +#endif + +out: + close(fd); + return 0; +} + +void av_file_unmap(uint8_t *bufptr, size_t size) +{ + if (!size) + return; +#if HAVE_MMAP + munmap(bufptr, size); +#elif HAVE_MAPVIEWOFFILE + UnmapViewOfFile(bufptr); +#else + av_free(bufptr); +#endif +} + +int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx) { + return avpriv_tempfile(prefix, filename, log_offset, log_ctx); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file.h new file mode 100644 index 0000000000..3ef4a6022c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file.h @@ -0,0 +1,71 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FILE_H +#define AVUTIL_FILE_H + +#include + +#include "avutil.h" + +/** + * @file + * Misc file utilities. + */ + +/** + * Read the file with name filename, and put its content in a newly + * allocated buffer or map it with mmap() when available. + * In case of success set *bufptr to the read or mmapped buffer, and + * *size to the size in bytes of the buffer in *bufptr. + * Unlike mmap this function succeeds with zero sized files, in this + * case *bufptr will be set to NULL and *size will be set to 0. + * The returned buffer must be released with av_file_unmap(). + * + * @param log_offset loglevel offset used for logging + * @param log_ctx context used for logging + * @return a non negative number in case of success, a negative value + * corresponding to an AVERROR error code in case of failure + */ +av_warn_unused_result +int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, + int log_offset, void *log_ctx); + +/** + * Unmap or free the buffer bufptr created by av_file_map(). + * + * @param size size in bytes of bufptr, must be the same as returned + * by av_file_map() + */ +void av_file_unmap(uint8_t *bufptr, size_t size); + +/** + * Wrapper to work around the lack of mkstemp() on mingw. + * Also, tries to create file in /tmp first, if possible. + * *prefix can be a character constant; *filename will be allocated internally. + * @return file descriptor of opened file (or negative value corresponding to an + * AVERROR code on error) + * and opened file name in **filename. + * @note On very old libcs it is necessary to set a secure umask before + * calling this, av_tempfile() can't call umask itself as it is used in + * libraries and could interfere with the calling application. + * @deprecated as fd numbers cannot be passed saftely between libs on some platforms + */ +int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx); + +#endif /* AVUTIL_FILE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file_open.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file_open.c new file mode 100644 index 0000000000..cc302f2f76 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/file_open.c @@ -0,0 +1,190 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "internal.h" +#include "mem.h" +#include +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_IO_H +#include +#endif + +#ifdef _WIN32 +#undef open +#undef lseek +#undef stat +#undef fstat +#include +#include +#include +#include "wchar_filename.h" + +static int win32_open(const char *filename_utf8, int oflag, int pmode) +{ + int fd; + wchar_t *filename_w; + + /* convert UTF-8 to wide chars */ + if (utf8towchar(filename_utf8, &filename_w)) + return -1; + if (!filename_w) + goto fallback; + + fd = _wsopen(filename_w, oflag, SH_DENYNO, pmode); + av_freep(&filename_w); + + if (fd != -1 || (oflag & O_CREAT)) + return fd; + +fallback: + /* filename may be in CP_ACP */ + return _sopen(filename_utf8, oflag, SH_DENYNO, pmode); +} +#define open win32_open +#endif + +int avpriv_open(const char *filename, int flags, ...) +{ + int fd; + unsigned int mode = 0; + va_list ap; + + va_start(ap, flags); + if (flags & O_CREAT) + mode = va_arg(ap, unsigned int); + va_end(ap); + +#ifdef O_CLOEXEC + flags |= O_CLOEXEC; +#endif +#ifdef O_NOINHERIT + flags |= O_NOINHERIT; +#endif + + fd = open(filename, flags, mode); +#if HAVE_FCNTL + if (fd != -1) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n"); + } +#endif + + return fd; +} + +typedef struct FileLogContext { + const AVClass *class; + int log_offset; + void *log_ctx; +} FileLogContext; + +static const AVClass file_log_ctx_class = { + .class_name = "TEMPFILE", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(FileLogContext, log_offset), + .parent_log_context_offset = offsetof(FileLogContext, log_ctx), +}; + +int avpriv_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx) +{ + FileLogContext file_log_ctx = { &file_log_ctx_class, log_offset, log_ctx }; + int fd = -1; +#if !HAVE_MKSTEMP + void *ptr= tempnam(NULL, prefix); + if(!ptr) + ptr= tempnam(".", prefix); + *filename = av_strdup(ptr); +#undef free + free(ptr); +#else + size_t len = strlen(prefix) + 12; /* room for "/tmp/" and "XXXXXX\0" */ + *filename = av_malloc(len); +#endif + /* -----common section-----*/ + if (!*filename) { + av_log(&file_log_ctx, AV_LOG_ERROR, "ff_tempfile: Cannot allocate file name\n"); + return AVERROR(ENOMEM); + } +#if !HAVE_MKSTEMP +# ifndef O_BINARY +# define O_BINARY 0 +# endif +# ifndef O_EXCL +# define O_EXCL 0 +# endif + fd = open(*filename, O_RDWR | O_BINARY | O_CREAT | O_EXCL, 0600); +#else + snprintf(*filename, len, "/tmp/%sXXXXXX", prefix); + fd = mkstemp(*filename); +#if defined(_WIN32) || defined (__ANDROID__) || defined(__DJGPP__) + if (fd < 0) { + snprintf(*filename, len, "./%sXXXXXX", prefix); + fd = mkstemp(*filename); + } +#endif +#endif + /* -----common section-----*/ + if (fd < 0) { + int err = AVERROR(errno); + av_log(&file_log_ctx, AV_LOG_ERROR, "ff_tempfile: Cannot open temporary file %s\n", *filename); + av_freep(filename); + return err; + } + return fd; /* success */ +} + +FILE *av_fopen_utf8(const char *path, const char *mode) +{ + int fd; + int access; + const char *m = mode; + + switch (*m++) { + case 'r': access = O_RDONLY; break; + case 'w': access = O_CREAT|O_WRONLY|O_TRUNC; break; + case 'a': access = O_CREAT|O_WRONLY|O_APPEND; break; + default : + errno = EINVAL; + return NULL; + } + while (*m) { + if (*m == '+') { + access &= ~(O_RDONLY | O_WRONLY); + access |= O_RDWR; + } else if (*m == 'b') { +#ifdef O_BINARY + access |= O_BINARY; +#endif + } else if (*m) { + errno = EINVAL; + return NULL; + } + m++; + } + fd = avpriv_open(path, access, 0666); + if (fd == -1) + return NULL; + return fdopen(fd, mode); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fixed_dsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fixed_dsp.c new file mode 100644 index 0000000000..8c018581df --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fixed_dsp.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2012 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Nedeljko Babic (nedeljko.babic imgtec com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "fixed_dsp.h" + +static void vector_fmul_add_c(int *dst, const int *src0, const int *src1, const int *src2, int len){ + int i; + int64_t accu; + + for (i=0; i> 31); + } +} + +static void vector_fmul_reverse_c(int *dst, const int *src0, const int *src1, int len) +{ + int i; + int64_t accu; + + src1 += len-1; + for (i=0; i> 31); + } +} + +static void vector_fmul_window_scaled_c(int16_t *dst, const int32_t *src0, + const int32_t *src1, const int32_t *win, + int len, uint8_t bits) +{ + int32_t s0, s1, wi, wj, i,j, round; + + dst += len; + win += len; + src0+= len; + round = bits? 1 << (bits-1) : 0; + + for (i=-len, j=len-1; i<0; i++, j--) { + s0 = src0[i]; + s1 = src1[j]; + wi = win[i]; + wj = win[j]; + dst[i] = av_clip_int16(((((int64_t)s0*wj - (int64_t)s1*wi + 0x40000000) >> 31) + round) >> bits); + dst[j] = av_clip_int16(((((int64_t)s0*wi + (int64_t)s1*wj + 0x40000000) >> 31) + round) >> bits); + } +} + +static void vector_fmul_window_c(int32_t *dst, const int32_t *src0, + const int32_t *src1, const int32_t *win, + int len) +{ + int32_t s0, s1, wi, wj, i, j; + + dst += len; + win += len; + src0+= len; + + for (i=-len, j=len-1; i<0; i++, j--) { + s0 = src0[i]; + s1 = src1[j]; + wi = win[i]; + wj = win[j]; + dst[i] = ((int64_t)s0*wj - (int64_t)s1*wi + 0x40000000) >> 31; + dst[j] = ((int64_t)s0*wi + (int64_t)s1*wj + 0x40000000) >> 31; + } +} + +static void vector_fmul_c(int *dst, const int *src0, const int *src1, int len) +{ + int i; + int64_t accu; + + for (i = 0; i < len; i++){ + accu = (int64_t)src0[i] * src1[i]; + dst[i] = (int)((accu+0x40000000) >> 31); + } +} + +static int scalarproduct_fixed_c(const int *v1, const int *v2, int len) +{ + /** p is initialized with 0x40000000 so that the proper rounding will occur + * at the end */ + int64_t p = 0x40000000; + int i; + + for (i = 0; i < len; i++) + p += (int64_t)v1[i] * v2[i]; + + return (int)(p >> 31); +} + +static void butterflies_fixed_c(int *v1, int *v2, int len) +{ + int i; + + for (i = 0; i < len; i++){ + int t = v1[i] - v2[i]; + v1[i] += v2[i]; + v2[i] = t; + } +} + +AVFixedDSPContext * avpriv_alloc_fixed_dsp(int bit_exact) +{ + AVFixedDSPContext * fdsp = av_malloc(sizeof(AVFixedDSPContext)); + + if (!fdsp) + return NULL; + + fdsp->vector_fmul_window_scaled = vector_fmul_window_scaled_c; + fdsp->vector_fmul_window = vector_fmul_window_c; + fdsp->vector_fmul = vector_fmul_c; + fdsp->vector_fmul_add = vector_fmul_add_c; + fdsp->vector_fmul_reverse = vector_fmul_reverse_c; + fdsp->butterflies_fixed = butterflies_fixed_c; + fdsp->scalarproduct_fixed = scalarproduct_fixed_c; + + if (ARCH_X86) + ff_fixed_dsp_init_x86(fdsp); + + return fdsp; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fixed_dsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fixed_dsp.h new file mode 100644 index 0000000000..f554cb5038 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/fixed_dsp.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2012 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Nedeljko Babic (nbabic@mips.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FIXED_DSP_H +#define AVUTIL_FIXED_DSP_H + +#include +#include "attributes.h" +#include "common.h" +#include "libavcodec/mathops.h" + +typedef struct AVFixedDSPContext { + /* Assume len is a multiple of 16, and arrays are 32-byte aligned */ + /* Results of multiplications are scaled down by 31 bit (and rounded) if not + * stated otherwise */ + + /** + * Overlap/add with window function. + * Result is scaled down by "bits" bits. + * Used primarily by MDCT-based audio codecs. + * Source and destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 16-byte aligned + * @param src0 first source vector + * constraints: 16-byte aligned + * @param src1 second source vector + * constraints: 16-byte aligned + * @param win half-window vector + * constraints: 16-byte aligned + * @param len length of vector + * constraints: multiple of 4 + * @param bits scaling parameter + * + */ + void (*vector_fmul_window_scaled)(int16_t *dst, const int32_t *src0, const int32_t *src1, const int32_t *win, int len, uint8_t bits); + + /** + * Overlap/add with window function. + * Used primarily by MDCT-based audio codecs. + * Source and destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src0 first source vector + * constraints: 16-byte aligned + * @param src1 second source vector + * constraints: 16-byte aligned + * @param win half-window vector + * constraints: 16-byte aligned + * @param len length of vector + * constraints: multiple of 4 + */ + void (*vector_fmul_window)(int32_t *dst, const int32_t *src0, const int32_t *src1, const int32_t *win, int len); + + /** + * Fixed-point multiplication that calculates the entry wise product of two + * vectors of integers and stores the result in a vector of integers. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul)(int *dst, const int *src0, const int *src1, + int len); + + void (*vector_fmul_reverse)(int *dst, const int *src0, const int *src1, int len); + /** + * Calculate the entry wise product of two vectors of integers, add a third vector of + * integers and store the result in a vector of integers. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param src2 third input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul_add)(int *dst, const int *src0, const int *src1, + const int *src2, int len); + + /** + * Calculate the scalar product of two vectors of integers. + * + * @param v1 first vector, 16-byte aligned + * @param v2 second vector, 16-byte aligned + * @param len length of vectors, multiple of 4 + * + * @return sum of elementwise products + */ + int (*scalarproduct_fixed)(const int *v1, const int *v2, int len); + + /** + * Calculate the sum and difference of two vectors of integers. + * + * @param v1 first input vector, sum output, 16-byte aligned + * @param v2 second input vector, difference output, 16-byte aligned + * @param len length of vectors, multiple of 4 + */ + void (*butterflies_fixed)(int *av_restrict v1, int *av_restrict v2, int len); +} AVFixedDSPContext; + +/** + * Allocate and initialize a fixed DSP context. + * note: should be freed with a av_free call when no longer needed. + * + * @param strict setting to non-zero avoids using functions which may not be IEEE-754 compliant + */ +AVFixedDSPContext * avpriv_alloc_fixed_dsp(int strict); + +void ff_fixed_dsp_init_x86(AVFixedDSPContext *fdsp); + +/** + * Calculate the square root + * + * @param x input fixed point number + * + * @param bits format of fixed point number (32 - bits).bits + * + * note: input is normalized to (0, 1) fixed point value + */ + +static av_always_inline int fixed_sqrt(int x, int bits) +{ + int retval, bit_mask, guess, square, i; + int64_t accu; + int shift1 = 30 - bits; + int shift2 = bits - 15; + + if (shift1 > 0) retval = ff_sqrt(x << shift1); + else retval = ff_sqrt(x >> -shift1); + + if (shift2 > 0) { + retval = retval << shift2; + bit_mask = (1 << (shift2 - 1)); + + for (i=0; i> bits); + if (x >= square) + retval += bit_mask; + bit_mask >>= 1; + } + + } + else retval >>= (-shift2); + + return retval; +} + +#endif /* AVUTIL_FIXED_DSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/float_dsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/float_dsp.c new file mode 100644 index 0000000000..6e28d71b57 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/float_dsp.c @@ -0,0 +1,164 @@ +/* + * Copyright 2005 Balatoni Denes + * Copyright 2006 Loren Merritt + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "attributes.h" +#include "float_dsp.h" +#include "mem.h" + +static void vector_fmul_c(float *dst, const float *src0, const float *src1, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] = src0[i] * src1[i]; +} + +static void vector_dmul_c(double *dst, const double *src0, const double *src1, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] = src0[i] * src1[i]; +} + +static void vector_fmac_scalar_c(float *dst, const float *src, float mul, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] += src[i] * mul; +} + +static void vector_dmac_scalar_c(double *dst, const double *src, double mul, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] += src[i] * mul; +} + +static void vector_fmul_scalar_c(float *dst, const float *src, float mul, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] = src[i] * mul; +} + +static void vector_dmul_scalar_c(double *dst, const double *src, double mul, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] = src[i] * mul; +} + +static void vector_fmul_window_c(float *dst, const float *src0, + const float *src1, const float *win, int len) +{ + int i, j; + + dst += len; + win += len; + src0 += len; + + for (i = -len, j = len - 1; i < 0; i++, j--) { + float s0 = src0[i]; + float s1 = src1[j]; + float wi = win[i]; + float wj = win[j]; + dst[i] = s0 * wj - s1 * wi; + dst[j] = s0 * wi + s1 * wj; + } +} + +static void vector_fmul_add_c(float *dst, const float *src0, const float *src1, + const float *src2, int len){ + int i; + + for (i = 0; i < len; i++) + dst[i] = src0[i] * src1[i] + src2[i]; +} + +static void vector_fmul_reverse_c(float *dst, const float *src0, + const float *src1, int len) +{ + int i; + + src1 += len-1; + for (i = 0; i < len; i++) + dst[i] = src0[i] * src1[-i]; +} + +static void butterflies_float_c(float *av_restrict v1, float *av_restrict v2, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + float t = v1[i] - v2[i]; + v1[i] += v2[i]; + v2[i] = t; + } +} + +float avpriv_scalarproduct_float_c(const float *v1, const float *v2, int len) +{ + float p = 0.0; + int i; + + for (i = 0; i < len; i++) + p += v1[i] * v2[i]; + + return p; +} + +av_cold AVFloatDSPContext *avpriv_float_dsp_alloc(int bit_exact) +{ + AVFloatDSPContext *fdsp = av_mallocz(sizeof(AVFloatDSPContext)); + if (!fdsp) + return NULL; + + fdsp->vector_fmul = vector_fmul_c; + fdsp->vector_dmul = vector_dmul_c; + fdsp->vector_fmac_scalar = vector_fmac_scalar_c; + fdsp->vector_fmul_scalar = vector_fmul_scalar_c; + fdsp->vector_dmac_scalar = vector_dmac_scalar_c; + fdsp->vector_dmul_scalar = vector_dmul_scalar_c; + fdsp->vector_fmul_window = vector_fmul_window_c; + fdsp->vector_fmul_add = vector_fmul_add_c; + fdsp->vector_fmul_reverse = vector_fmul_reverse_c; + fdsp->butterflies_float = butterflies_float_c; + fdsp->scalarproduct_float = avpriv_scalarproduct_float_c; + + if (ARCH_AARCH64) + ff_float_dsp_init_aarch64(fdsp); + if (ARCH_ARM) + ff_float_dsp_init_arm(fdsp); + if (ARCH_PPC) + ff_float_dsp_init_ppc(fdsp, bit_exact); + if (ARCH_X86) + ff_float_dsp_init_x86(fdsp); + if (ARCH_MIPS) + ff_float_dsp_init_mips(fdsp); + return fdsp; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/float_dsp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/float_dsp.h new file mode 100644 index 0000000000..9c664592bd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/float_dsp.h @@ -0,0 +1,218 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FLOAT_DSP_H +#define AVUTIL_FLOAT_DSP_H + +#include "config.h" + +typedef struct AVFloatDSPContext { + /** + * Calculate the entry wise product of two vectors of floats and store the result in + * a vector of floats. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul)(float *dst, const float *src0, const float *src1, + int len); + + /** + * Multiply a vector of floats by a scalar float and add to + * destination vector. Source and destination vectors must + * overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src input vector + * constraints: 32-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 16 + */ + void (*vector_fmac_scalar)(float *dst, const float *src, float mul, + int len); + + /** + * Multiply a vector of doubles by a scalar double and add to + * destination vector. Source and destination vectors must + * overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src input vector + * constraints: 32-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 16 + */ + void (*vector_dmac_scalar)(double *dst, const double *src, double mul, + int len); + + /** + * Multiply a vector of floats by a scalar float. Source and + * destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 16-byte aligned + * @param src input vector + * constraints: 16-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 4 + */ + void (*vector_fmul_scalar)(float *dst, const float *src, float mul, + int len); + + /** + * Multiply a vector of double by a scalar double. Source and + * destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src input vector + * constraints: 32-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 8 + */ + void (*vector_dmul_scalar)(double *dst, const double *src, double mul, + int len); + + /** + * Overlap/add with window function. + * Used primarily by MDCT-based audio codecs. + * Source and destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 16-byte aligned + * @param src0 first source vector + * constraints: 16-byte aligned + * @param src1 second source vector + * constraints: 16-byte aligned + * @param win half-window vector + * constraints: 16-byte aligned + * @param len length of vector + * constraints: multiple of 4 + */ + void (*vector_fmul_window)(float *dst, const float *src0, + const float *src1, const float *win, int len); + + /** + * Calculate the entry wise product of two vectors of floats, add a third vector of + * floats and store the result in a vector of floats. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param src2 third input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul_add)(float *dst, const float *src0, const float *src1, + const float *src2, int len); + + /** + * Calculate the entry wise product of two vectors of floats, and store the result + * in a vector of floats. The second vector of floats is iterated over + * in reverse order. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul_reverse)(float *dst, const float *src0, + const float *src1, int len); + + /** + * Calculate the sum and difference of two vectors of floats. + * + * @param v1 first input vector, sum output, 16-byte aligned + * @param v2 second input vector, difference output, 16-byte aligned + * @param len length of vectors, multiple of 4 + */ + void (*butterflies_float)(float *av_restrict v1, float *av_restrict v2, int len); + + /** + * Calculate the scalar product of two vectors of floats. + * + * @param v1 first vector, 16-byte aligned + * @param v2 second vector, 16-byte aligned + * @param len length of vectors, multiple of 4 + * + * @return sum of elementwise products + */ + float (*scalarproduct_float)(const float *v1, const float *v2, int len); + + /** + * Calculate the entry wise product of two vectors of doubles and store the result in + * a vector of doubles. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_dmul)(double *dst, const double *src0, const double *src1, + int len); +} AVFloatDSPContext; + +/** + * Return the scalar product of two vectors. + * + * @param v1 first input vector + * @param v2 first input vector + * @param len number of elements + * + * @return sum of elementwise products + */ +float avpriv_scalarproduct_float_c(const float *v1, const float *v2, int len); + +void ff_float_dsp_init_aarch64(AVFloatDSPContext *fdsp); +void ff_float_dsp_init_arm(AVFloatDSPContext *fdsp); +void ff_float_dsp_init_ppc(AVFloatDSPContext *fdsp, int strict); +void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp); +void ff_float_dsp_init_mips(AVFloatDSPContext *fdsp); + +/** + * Allocate a float DSP context. + * + * @param strict setting to non-zero avoids using functions which may not be IEEE-754 compliant + */ +AVFloatDSPContext *avpriv_float_dsp_alloc(int strict); + +#endif /* AVUTIL_FLOAT_DSP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/frame.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/frame.c new file mode 100644 index 0000000000..dcf1fc3d17 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/frame.c @@ -0,0 +1,947 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "channel_layout.h" +#include "avassert.h" +#include "buffer.h" +#include "common.h" +#include "dict.h" +#include "frame.h" +#include "imgutils.h" +#include "mem.h" +#include "samplefmt.h" + +#if FF_API_FRAME_GET_SET +MAKE_ACCESSORS(AVFrame, frame, int64_t, best_effort_timestamp) +MAKE_ACCESSORS(AVFrame, frame, int64_t, pkt_duration) +MAKE_ACCESSORS(AVFrame, frame, int64_t, pkt_pos) +MAKE_ACCESSORS(AVFrame, frame, int64_t, channel_layout) +MAKE_ACCESSORS(AVFrame, frame, int, channels) +MAKE_ACCESSORS(AVFrame, frame, int, sample_rate) +MAKE_ACCESSORS(AVFrame, frame, AVDictionary *, metadata) +MAKE_ACCESSORS(AVFrame, frame, int, decode_error_flags) +MAKE_ACCESSORS(AVFrame, frame, int, pkt_size) +MAKE_ACCESSORS(AVFrame, frame, enum AVColorSpace, colorspace) +MAKE_ACCESSORS(AVFrame, frame, enum AVColorRange, color_range) +#endif + +#define CHECK_CHANNELS_CONSISTENCY(frame) \ + av_assert2(!(frame)->channel_layout || \ + (frame)->channels == \ + av_get_channel_layout_nb_channels((frame)->channel_layout)) + +#if FF_API_FRAME_QP +struct qp_properties { + int stride; + int type; +}; + +int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int qp_type) +{ + struct qp_properties *p; + AVFrameSideData *sd; + AVBufferRef *ref; + +FF_DISABLE_DEPRECATION_WARNINGS + av_buffer_unref(&f->qp_table_buf); + + f->qp_table_buf = buf; + f->qscale_table = buf->data; + f->qstride = stride; + f->qscale_type = qp_type; +FF_ENABLE_DEPRECATION_WARNINGS + + av_frame_remove_side_data(f, AV_FRAME_DATA_QP_TABLE_PROPERTIES); + av_frame_remove_side_data(f, AV_FRAME_DATA_QP_TABLE_DATA); + + ref = av_buffer_ref(buf); + if (!av_frame_new_side_data_from_buf(f, AV_FRAME_DATA_QP_TABLE_DATA, ref)) { + av_buffer_unref(&ref); + return AVERROR(ENOMEM); + } + + sd = av_frame_new_side_data(f, AV_FRAME_DATA_QP_TABLE_PROPERTIES, + sizeof(struct qp_properties)); + if (!sd) + return AVERROR(ENOMEM); + + p = (struct qp_properties *)sd->data; + p->stride = stride; + p->type = qp_type; + + return 0; +} + +int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type) +{ + AVBufferRef *buf = NULL; + + *stride = 0; + *type = 0; + +FF_DISABLE_DEPRECATION_WARNINGS + if (f->qp_table_buf) { + *stride = f->qstride; + *type = f->qscale_type; + buf = f->qp_table_buf; +FF_ENABLE_DEPRECATION_WARNINGS + } else { + AVFrameSideData *sd; + struct qp_properties *p; + sd = av_frame_get_side_data(f, AV_FRAME_DATA_QP_TABLE_PROPERTIES); + if (!sd) + return NULL; + p = (struct qp_properties *)sd->data; + sd = av_frame_get_side_data(f, AV_FRAME_DATA_QP_TABLE_DATA); + if (!sd) + return NULL; + *stride = p->stride; + *type = p->type; + buf = sd->buf; + } + + return buf ? buf->data : NULL; +} +#endif + +const char *av_get_colorspace_name(enum AVColorSpace val) +{ + static const char * const name[] = { + [AVCOL_SPC_RGB] = "GBR", + [AVCOL_SPC_BT709] = "bt709", + [AVCOL_SPC_FCC] = "fcc", + [AVCOL_SPC_BT470BG] = "bt470bg", + [AVCOL_SPC_SMPTE170M] = "smpte170m", + [AVCOL_SPC_SMPTE240M] = "smpte240m", + [AVCOL_SPC_YCOCG] = "YCgCo", + }; + if ((unsigned)val >= FF_ARRAY_ELEMS(name)) + return NULL; + return name[val]; +} + +static void get_frame_defaults(AVFrame *frame) +{ + if (frame->extended_data != frame->data) + av_freep(&frame->extended_data); + + memset(frame, 0, sizeof(*frame)); + + frame->pts = + frame->pkt_dts = AV_NOPTS_VALUE; +#if FF_API_PKT_PTS +FF_DISABLE_DEPRECATION_WARNINGS + frame->pkt_pts = AV_NOPTS_VALUE; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + frame->best_effort_timestamp = AV_NOPTS_VALUE; + frame->pkt_duration = 0; + frame->pkt_pos = -1; + frame->pkt_size = -1; + frame->key_frame = 1; + frame->sample_aspect_ratio = (AVRational){ 0, 1 }; + frame->format = -1; /* unknown */ + frame->extended_data = frame->data; + frame->color_primaries = AVCOL_PRI_UNSPECIFIED; + frame->color_trc = AVCOL_TRC_UNSPECIFIED; + frame->colorspace = AVCOL_SPC_UNSPECIFIED; + frame->color_range = AVCOL_RANGE_UNSPECIFIED; + frame->chroma_location = AVCHROMA_LOC_UNSPECIFIED; + frame->flags = 0; +} + +static void free_side_data(AVFrameSideData **ptr_sd) +{ + AVFrameSideData *sd = *ptr_sd; + + av_buffer_unref(&sd->buf); + av_dict_free(&sd->metadata); + av_freep(ptr_sd); +} + +static void wipe_side_data(AVFrame *frame) +{ + int i; + + for (i = 0; i < frame->nb_side_data; i++) { + free_side_data(&frame->side_data[i]); + } + frame->nb_side_data = 0; + + av_freep(&frame->side_data); +} + +AVFrame *av_frame_alloc(void) +{ + AVFrame *frame = av_mallocz(sizeof(*frame)); + + if (!frame) + return NULL; + + frame->extended_data = NULL; + get_frame_defaults(frame); + + return frame; +} + +void av_frame_free(AVFrame **frame) +{ + if (!frame || !*frame) + return; + + av_frame_unref(*frame); + av_freep(frame); +} + +static int get_video_buffer(AVFrame *frame, int align) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int ret, i, padded_height; + int plane_padding = FFMAX(16 + 16/*STRIDE_ALIGN*/, align); + + if (!desc) + return AVERROR(EINVAL); + + if ((ret = av_image_check_size(frame->width, frame->height, 0, NULL)) < 0) + return ret; + + if (!frame->linesize[0]) { + if (align <= 0) + align = 32; /* STRIDE_ALIGN. Should be av_cpu_max_align() */ + + for(i=1; i<=align; i+=i) { + ret = av_image_fill_linesizes(frame->linesize, frame->format, + FFALIGN(frame->width, i)); + if (ret < 0) + return ret; + if (!(frame->linesize[0] & (align-1))) + break; + } + + for (i = 0; i < 4 && frame->linesize[i]; i++) + frame->linesize[i] = FFALIGN(frame->linesize[i], align); + } + + padded_height = FFALIGN(frame->height, 32); + if ((ret = av_image_fill_pointers(frame->data, frame->format, padded_height, + NULL, frame->linesize)) < 0) + return ret; + + frame->buf[0] = av_buffer_alloc(ret + 4*plane_padding); + if (!frame->buf[0]) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if ((ret = av_image_fill_pointers(frame->data, frame->format, padded_height, + frame->buf[0]->data, frame->linesize)) < 0) + goto fail; + + for (i = 1; i < 4; i++) { + if (frame->data[i]) + frame->data[i] += i * plane_padding; + } + + frame->extended_data = frame->data; + + return 0; +fail: + av_frame_unref(frame); + return ret; +} + +static int get_audio_buffer(AVFrame *frame, int align) +{ + int channels; + int planar = av_sample_fmt_is_planar(frame->format); + int planes; + int ret, i; + + if (!frame->channels) + frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout); + + channels = frame->channels; + planes = planar ? channels : 1; + + CHECK_CHANNELS_CONSISTENCY(frame); + if (!frame->linesize[0]) { + ret = av_samples_get_buffer_size(&frame->linesize[0], channels, + frame->nb_samples, frame->format, + align); + if (ret < 0) + return ret; + } + + if (planes > AV_NUM_DATA_POINTERS) { + frame->extended_data = av_mallocz_array(planes, + sizeof(*frame->extended_data)); + frame->extended_buf = av_mallocz_array((planes - AV_NUM_DATA_POINTERS), + sizeof(*frame->extended_buf)); + if (!frame->extended_data || !frame->extended_buf) { + av_freep(&frame->extended_data); + av_freep(&frame->extended_buf); + return AVERROR(ENOMEM); + } + frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS; + } else + frame->extended_data = frame->data; + + for (i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) { + frame->buf[i] = av_buffer_alloc(frame->linesize[0]); + if (!frame->buf[i]) { + av_frame_unref(frame); + return AVERROR(ENOMEM); + } + frame->extended_data[i] = frame->data[i] = frame->buf[i]->data; + } + for (i = 0; i < planes - AV_NUM_DATA_POINTERS; i++) { + frame->extended_buf[i] = av_buffer_alloc(frame->linesize[0]); + if (!frame->extended_buf[i]) { + av_frame_unref(frame); + return AVERROR(ENOMEM); + } + frame->extended_data[i + AV_NUM_DATA_POINTERS] = frame->extended_buf[i]->data; + } + return 0; + +} + +int av_frame_get_buffer(AVFrame *frame, int align) +{ + if (frame->format < 0) + return AVERROR(EINVAL); + + if (frame->width > 0 && frame->height > 0) + return get_video_buffer(frame, align); + else if (frame->nb_samples > 0 && (frame->channel_layout || frame->channels > 0)) + return get_audio_buffer(frame, align); + + return AVERROR(EINVAL); +} + +static int frame_copy_props(AVFrame *dst, const AVFrame *src, int force_copy) +{ + int i; + + dst->key_frame = src->key_frame; + dst->pict_type = src->pict_type; + dst->sample_aspect_ratio = src->sample_aspect_ratio; + dst->crop_top = src->crop_top; + dst->crop_bottom = src->crop_bottom; + dst->crop_left = src->crop_left; + dst->crop_right = src->crop_right; + dst->pts = src->pts; + dst->repeat_pict = src->repeat_pict; + dst->interlaced_frame = src->interlaced_frame; + dst->top_field_first = src->top_field_first; + dst->palette_has_changed = src->palette_has_changed; + dst->sample_rate = src->sample_rate; + dst->opaque = src->opaque; +#if FF_API_PKT_PTS +FF_DISABLE_DEPRECATION_WARNINGS + dst->pkt_pts = src->pkt_pts; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + dst->pkt_dts = src->pkt_dts; + dst->pkt_pos = src->pkt_pos; + dst->pkt_size = src->pkt_size; + dst->pkt_duration = src->pkt_duration; + dst->reordered_opaque = src->reordered_opaque; + dst->quality = src->quality; + dst->best_effort_timestamp = src->best_effort_timestamp; + dst->coded_picture_number = src->coded_picture_number; + dst->display_picture_number = src->display_picture_number; + dst->flags = src->flags; + dst->decode_error_flags = src->decode_error_flags; + dst->color_primaries = src->color_primaries; + dst->color_trc = src->color_trc; + dst->colorspace = src->colorspace; + dst->color_range = src->color_range; + dst->chroma_location = src->chroma_location; + + av_dict_copy(&dst->metadata, src->metadata, 0); + +#if FF_API_ERROR_FRAME +FF_DISABLE_DEPRECATION_WARNINGS + memcpy(dst->error, src->error, sizeof(dst->error)); +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + for (i = 0; i < src->nb_side_data; i++) { + const AVFrameSideData *sd_src = src->side_data[i]; + AVFrameSideData *sd_dst; + if ( sd_src->type == AV_FRAME_DATA_PANSCAN + && (src->width != dst->width || src->height != dst->height)) + continue; + if (force_copy) { + sd_dst = av_frame_new_side_data(dst, sd_src->type, + sd_src->size); + if (!sd_dst) { + wipe_side_data(dst); + return AVERROR(ENOMEM); + } + memcpy(sd_dst->data, sd_src->data, sd_src->size); + } else { + AVBufferRef *ref = av_buffer_ref(sd_src->buf); + sd_dst = av_frame_new_side_data_from_buf(dst, sd_src->type, ref); + if (!sd_dst) { + av_buffer_unref(&ref); + wipe_side_data(dst); + return AVERROR(ENOMEM); + } + } + av_dict_copy(&sd_dst->metadata, sd_src->metadata, 0); + } + +#if FF_API_FRAME_QP +FF_DISABLE_DEPRECATION_WARNINGS + dst->qscale_table = NULL; + dst->qstride = 0; + dst->qscale_type = 0; + av_buffer_unref(&dst->qp_table_buf); + if (src->qp_table_buf) { + dst->qp_table_buf = av_buffer_ref(src->qp_table_buf); + if (dst->qp_table_buf) { + dst->qscale_table = dst->qp_table_buf->data; + dst->qstride = src->qstride; + dst->qscale_type = src->qscale_type; + } + } +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + av_buffer_unref(&dst->opaque_ref); + av_buffer_unref(&dst->private_ref); + if (src->opaque_ref) { + dst->opaque_ref = av_buffer_ref(src->opaque_ref); + if (!dst->opaque_ref) + return AVERROR(ENOMEM); + } + if (src->private_ref) { + dst->private_ref = av_buffer_ref(src->private_ref); + if (!dst->private_ref) + return AVERROR(ENOMEM); + } + return 0; +} + +int av_frame_ref(AVFrame *dst, const AVFrame *src) +{ + int i, ret = 0; + + av_assert1(dst->width == 0 && dst->height == 0); + av_assert1(dst->channels == 0); + + dst->format = src->format; + dst->width = src->width; + dst->height = src->height; + dst->channels = src->channels; + dst->channel_layout = src->channel_layout; + dst->nb_samples = src->nb_samples; + + ret = frame_copy_props(dst, src, 0); + if (ret < 0) + return ret; + + /* duplicate the frame data if it's not refcounted */ + if (!src->buf[0]) { + ret = av_frame_get_buffer(dst, 32); + if (ret < 0) + return ret; + + ret = av_frame_copy(dst, src); + if (ret < 0) + av_frame_unref(dst); + + return ret; + } + + /* ref the buffers */ + for (i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) { + if (!src->buf[i]) + continue; + dst->buf[i] = av_buffer_ref(src->buf[i]); + if (!dst->buf[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + if (src->extended_buf) { + dst->extended_buf = av_mallocz_array(sizeof(*dst->extended_buf), + src->nb_extended_buf); + if (!dst->extended_buf) { + ret = AVERROR(ENOMEM); + goto fail; + } + dst->nb_extended_buf = src->nb_extended_buf; + + for (i = 0; i < src->nb_extended_buf; i++) { + dst->extended_buf[i] = av_buffer_ref(src->extended_buf[i]); + if (!dst->extended_buf[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + } + + if (src->hw_frames_ctx) { + dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx); + if (!dst->hw_frames_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + /* duplicate extended data */ + if (src->extended_data != src->data) { + int ch = src->channels; + + if (!ch) { + ret = AVERROR(EINVAL); + goto fail; + } + CHECK_CHANNELS_CONSISTENCY(src); + + dst->extended_data = av_malloc_array(sizeof(*dst->extended_data), ch); + if (!dst->extended_data) { + ret = AVERROR(ENOMEM); + goto fail; + } + memcpy(dst->extended_data, src->extended_data, sizeof(*src->extended_data) * ch); + } else + dst->extended_data = dst->data; + + memcpy(dst->data, src->data, sizeof(src->data)); + memcpy(dst->linesize, src->linesize, sizeof(src->linesize)); + + return 0; + +fail: + av_frame_unref(dst); + return ret; +} + +AVFrame *av_frame_clone(const AVFrame *src) +{ + AVFrame *ret = av_frame_alloc(); + + if (!ret) + return NULL; + + if (av_frame_ref(ret, src) < 0) + av_frame_free(&ret); + + return ret; +} + +void av_frame_unref(AVFrame *frame) +{ + int i; + + if (!frame) + return; + + wipe_side_data(frame); + + for (i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) + av_buffer_unref(&frame->buf[i]); + for (i = 0; i < frame->nb_extended_buf; i++) + av_buffer_unref(&frame->extended_buf[i]); + av_freep(&frame->extended_buf); + av_dict_free(&frame->metadata); +#if FF_API_FRAME_QP +FF_DISABLE_DEPRECATION_WARNINGS + av_buffer_unref(&frame->qp_table_buf); +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + av_buffer_unref(&frame->hw_frames_ctx); + + av_buffer_unref(&frame->opaque_ref); + av_buffer_unref(&frame->private_ref); + + get_frame_defaults(frame); +} + +void av_frame_move_ref(AVFrame *dst, AVFrame *src) +{ + av_assert1(dst->width == 0 && dst->height == 0); + av_assert1(dst->channels == 0); + + *dst = *src; + if (src->extended_data == src->data) + dst->extended_data = dst->data; + memset(src, 0, sizeof(*src)); + get_frame_defaults(src); +} + +int av_frame_is_writable(AVFrame *frame) +{ + int i, ret = 1; + + /* assume non-refcounted frames are not writable */ + if (!frame->buf[0]) + return 0; + + for (i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) + if (frame->buf[i]) + ret &= !!av_buffer_is_writable(frame->buf[i]); + for (i = 0; i < frame->nb_extended_buf; i++) + ret &= !!av_buffer_is_writable(frame->extended_buf[i]); + + return ret; +} + +int av_frame_make_writable(AVFrame *frame) +{ + AVFrame tmp; + int ret; + + if (!frame->buf[0]) + return AVERROR(EINVAL); + + if (av_frame_is_writable(frame)) + return 0; + + memset(&tmp, 0, sizeof(tmp)); + tmp.format = frame->format; + tmp.width = frame->width; + tmp.height = frame->height; + tmp.channels = frame->channels; + tmp.channel_layout = frame->channel_layout; + tmp.nb_samples = frame->nb_samples; + ret = av_frame_get_buffer(&tmp, 32); + if (ret < 0) + return ret; + + ret = av_frame_copy(&tmp, frame); + if (ret < 0) { + av_frame_unref(&tmp); + return ret; + } + + ret = av_frame_copy_props(&tmp, frame); + if (ret < 0) { + av_frame_unref(&tmp); + return ret; + } + + av_frame_unref(frame); + + *frame = tmp; + if (tmp.data == tmp.extended_data) + frame->extended_data = frame->data; + + return 0; +} + +int av_frame_copy_props(AVFrame *dst, const AVFrame *src) +{ + return frame_copy_props(dst, src, 1); +} + +AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane) +{ + uint8_t *data; + int planes, i; + + if (frame->nb_samples) { + int channels = frame->channels; + if (!channels) + return NULL; + CHECK_CHANNELS_CONSISTENCY(frame); + planes = av_sample_fmt_is_planar(frame->format) ? channels : 1; + } else + planes = 4; + + if (plane < 0 || plane >= planes || !frame->extended_data[plane]) + return NULL; + data = frame->extended_data[plane]; + + for (i = 0; i < FF_ARRAY_ELEMS(frame->buf) && frame->buf[i]; i++) { + AVBufferRef *buf = frame->buf[i]; + if (data >= buf->data && data < buf->data + buf->size) + return buf; + } + for (i = 0; i < frame->nb_extended_buf; i++) { + AVBufferRef *buf = frame->extended_buf[i]; + if (data >= buf->data && data < buf->data + buf->size) + return buf; + } + return NULL; +} + +AVFrameSideData *av_frame_new_side_data_from_buf(AVFrame *frame, + enum AVFrameSideDataType type, + AVBufferRef *buf) +{ + AVFrameSideData *ret, **tmp; + + if (!buf) + return NULL; + + if (frame->nb_side_data > INT_MAX / sizeof(*frame->side_data) - 1) + return NULL; + + tmp = av_realloc(frame->side_data, + (frame->nb_side_data + 1) * sizeof(*frame->side_data)); + if (!tmp) + return NULL; + frame->side_data = tmp; + + ret = av_mallocz(sizeof(*ret)); + if (!ret) + return NULL; + + ret->buf = buf; + ret->data = ret->buf->data; + ret->size = buf->size; + ret->type = type; + + frame->side_data[frame->nb_side_data++] = ret; + + return ret; +} + +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + int size) +{ + AVFrameSideData *ret; + AVBufferRef *buf = av_buffer_alloc(size); + ret = av_frame_new_side_data_from_buf(frame, type, buf); + if (!ret) + av_buffer_unref(&buf); + return ret; +} + +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type) +{ + int i; + + for (i = 0; i < frame->nb_side_data; i++) { + if (frame->side_data[i]->type == type) + return frame->side_data[i]; + } + return NULL; +} + +static int frame_copy_video(AVFrame *dst, const AVFrame *src) +{ + const uint8_t *src_data[4]; + int i, planes; + + if (dst->width < src->width || + dst->height < src->height) + return AVERROR(EINVAL); + + planes = av_pix_fmt_count_planes(dst->format); + for (i = 0; i < planes; i++) + if (!dst->data[i] || !src->data[i]) + return AVERROR(EINVAL); + + memcpy(src_data, src->data, sizeof(src_data)); + av_image_copy(dst->data, dst->linesize, + src_data, src->linesize, + dst->format, src->width, src->height); + + return 0; +} + +static int frame_copy_audio(AVFrame *dst, const AVFrame *src) +{ + int planar = av_sample_fmt_is_planar(dst->format); + int channels = dst->channels; + int planes = planar ? channels : 1; + int i; + + if (dst->nb_samples != src->nb_samples || + dst->channels != src->channels || + dst->channel_layout != src->channel_layout) + return AVERROR(EINVAL); + + CHECK_CHANNELS_CONSISTENCY(src); + + for (i = 0; i < planes; i++) + if (!dst->extended_data[i] || !src->extended_data[i]) + return AVERROR(EINVAL); + + av_samples_copy(dst->extended_data, src->extended_data, 0, 0, + dst->nb_samples, channels, dst->format); + + return 0; +} + +int av_frame_copy(AVFrame *dst, const AVFrame *src) +{ + if (dst->format != src->format || dst->format < 0) + return AVERROR(EINVAL); + + if (dst->width > 0 && dst->height > 0) + return frame_copy_video(dst, src); + else if (dst->nb_samples > 0 && dst->channels > 0) + return frame_copy_audio(dst, src); + + return AVERROR(EINVAL); +} + +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type) +{ + int i; + + for (i = 0; i < frame->nb_side_data; i++) { + AVFrameSideData *sd = frame->side_data[i]; + if (sd->type == type) { + free_side_data(&frame->side_data[i]); + frame->side_data[i] = frame->side_data[frame->nb_side_data - 1]; + frame->nb_side_data--; + } + } +} + +const char *av_frame_side_data_name(enum AVFrameSideDataType type) +{ + switch(type) { + case AV_FRAME_DATA_PANSCAN: return "AVPanScan"; + case AV_FRAME_DATA_A53_CC: return "ATSC A53 Part 4 Closed Captions"; + case AV_FRAME_DATA_STEREO3D: return "Stereo 3D"; + case AV_FRAME_DATA_MATRIXENCODING: return "AVMatrixEncoding"; + case AV_FRAME_DATA_DOWNMIX_INFO: return "Metadata relevant to a downmix procedure"; + case AV_FRAME_DATA_REPLAYGAIN: return "AVReplayGain"; + case AV_FRAME_DATA_DISPLAYMATRIX: return "3x3 displaymatrix"; + case AV_FRAME_DATA_AFD: return "Active format description"; + case AV_FRAME_DATA_MOTION_VECTORS: return "Motion vectors"; + case AV_FRAME_DATA_SKIP_SAMPLES: return "Skip samples"; + case AV_FRAME_DATA_AUDIO_SERVICE_TYPE: return "Audio service type"; + case AV_FRAME_DATA_MASTERING_DISPLAY_METADATA: return "Mastering display metadata"; + case AV_FRAME_DATA_CONTENT_LIGHT_LEVEL: return "Content light level metadata"; + case AV_FRAME_DATA_GOP_TIMECODE: return "GOP timecode"; + case AV_FRAME_DATA_S12M_TIMECODE: return "SMPTE 12-1 timecode"; + case AV_FRAME_DATA_SPHERICAL: return "Spherical Mapping"; + case AV_FRAME_DATA_ICC_PROFILE: return "ICC profile"; +#if FF_API_FRAME_QP + case AV_FRAME_DATA_QP_TABLE_PROPERTIES: return "QP table properties"; + case AV_FRAME_DATA_QP_TABLE_DATA: return "QP table data"; +#endif + case AV_FRAME_DATA_DYNAMIC_HDR_PLUS: return "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)"; + case AV_FRAME_DATA_REGIONS_OF_INTEREST: return "Regions Of Interest"; + } + return NULL; +} + +static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame, + const AVPixFmtDescriptor *desc) +{ + int i, j; + + for (i = 0; frame->data[i]; i++) { + const AVComponentDescriptor *comp = NULL; + int shift_x = (i == 1 || i == 2) ? desc->log2_chroma_w : 0; + int shift_y = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; + + if (desc->flags & (AV_PIX_FMT_FLAG_PAL | FF_PSEUDOPAL) && i == 1) { + offsets[i] = 0; + break; + } + + /* find any component descriptor for this plane */ + for (j = 0; j < desc->nb_components; j++) { + if (desc->comp[j].plane == i) { + comp = &desc->comp[j]; + break; + } + } + if (!comp) + return AVERROR_BUG; + + offsets[i] = (frame->crop_top >> shift_y) * frame->linesize[i] + + (frame->crop_left >> shift_x) * comp->step; + } + + return 0; +} + +int av_frame_apply_cropping(AVFrame *frame, int flags) +{ + const AVPixFmtDescriptor *desc; + size_t offsets[4]; + int i; + + if (!(frame->width > 0 && frame->height > 0)) + return AVERROR(EINVAL); + + if (frame->crop_left >= INT_MAX - frame->crop_right || + frame->crop_top >= INT_MAX - frame->crop_bottom || + (frame->crop_left + frame->crop_right) >= frame->width || + (frame->crop_top + frame->crop_bottom) >= frame->height) + return AVERROR(ERANGE); + + desc = av_pix_fmt_desc_get(frame->format); + if (!desc) + return AVERROR_BUG; + + /* Apply just the right/bottom cropping for hwaccel formats. Bitstream + * formats cannot be easily handled here either (and corresponding decoders + * should not export any cropping anyway), so do the same for those as well. + * */ + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL)) { + frame->width -= frame->crop_right; + frame->height -= frame->crop_bottom; + frame->crop_right = 0; + frame->crop_bottom = 0; + return 0; + } + + /* calculate the offsets for each plane */ + calc_cropping_offsets(offsets, frame, desc); + + /* adjust the offsets to avoid breaking alignment */ + if (!(flags & AV_FRAME_CROP_UNALIGNED)) { + int log2_crop_align = frame->crop_left ? ff_ctz(frame->crop_left) : INT_MAX; + int min_log2_align = INT_MAX; + + for (i = 0; frame->data[i]; i++) { + int log2_align = offsets[i] ? ff_ctz(offsets[i]) : INT_MAX; + min_log2_align = FFMIN(log2_align, min_log2_align); + } + + /* we assume, and it should always be true, that the data alignment is + * related to the cropping alignment by a constant power-of-2 factor */ + if (log2_crop_align < min_log2_align) + return AVERROR_BUG; + + if (min_log2_align < 5) { + frame->crop_left &= ~((1 << (5 + log2_crop_align - min_log2_align)) - 1); + calc_cropping_offsets(offsets, frame, desc); + } + } + + for (i = 0; frame->data[i]; i++) + frame->data[i] += offsets[i]; + + frame->width -= (frame->crop_left + frame->crop_right); + frame->height -= (frame->crop_top + frame->crop_bottom); + frame->crop_left = 0; + frame->crop_right = 0; + frame->crop_top = 0; + frame->crop_bottom = 0; + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/frame.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/frame.h new file mode 100644 index 0000000000..5d3231e7bb --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/frame.h @@ -0,0 +1,971 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_frame + * reference-counted frame API + */ + +#ifndef AVUTIL_FRAME_H +#define AVUTIL_FRAME_H + +#include +#include + +#include "avutil.h" +#include "buffer.h" +#include "dict.h" +#include "rational.h" +#include "samplefmt.h" +#include "pixfmt.h" +#include "version.h" + + +/** + * @defgroup lavu_frame AVFrame + * @ingroup lavu_data + * + * @{ + * AVFrame is an abstraction for reference-counted raw multimedia data. + */ + +enum AVFrameSideDataType { + /** + * The data is the AVPanScan struct defined in libavcodec. + */ + AV_FRAME_DATA_PANSCAN, + /** + * ATSC A53 Part 4 Closed Captions. + * A53 CC bitstream is stored as uint8_t in AVFrameSideData.data. + * The number of bytes of CC data is AVFrameSideData.size. + */ + AV_FRAME_DATA_A53_CC, + /** + * Stereoscopic 3d metadata. + * The data is the AVStereo3D struct defined in libavutil/stereo3d.h. + */ + AV_FRAME_DATA_STEREO3D, + /** + * The data is the AVMatrixEncoding enum defined in libavutil/channel_layout.h. + */ + AV_FRAME_DATA_MATRIXENCODING, + /** + * Metadata relevant to a downmix procedure. + * The data is the AVDownmixInfo struct defined in libavutil/downmix_info.h. + */ + AV_FRAME_DATA_DOWNMIX_INFO, + /** + * ReplayGain information in the form of the AVReplayGain struct. + */ + AV_FRAME_DATA_REPLAYGAIN, + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the frame for correct + * presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_FRAME_DATA_DISPLAYMATRIX, + /** + * Active Format Description data consisting of a single byte as specified + * in ETSI TS 101 154 using AVActiveFormatDescription enum. + */ + AV_FRAME_DATA_AFD, + /** + * Motion vectors exported by some codecs (on demand through the export_mvs + * flag set in the libavcodec AVCodecContext flags2 option). + * The data is the AVMotionVector struct defined in + * libavutil/motion_vector.h. + */ + AV_FRAME_DATA_MOTION_VECTORS, + /** + * Recommmends skipping the specified number of samples. This is exported + * only if the "skip_manual" AVOption is set in libavcodec. + * This has the same format as AV_PKT_DATA_SKIP_SAMPLES. + * @code + * u32le number of samples to skip from start of this packet + * u32le number of samples to skip from end of this packet + * u8 reason for start skip + * u8 reason for end skip (0=padding silence, 1=convergence) + * @endcode + */ + AV_FRAME_DATA_SKIP_SAMPLES, + /** + * This side data must be associated with an audio frame and corresponds to + * enum AVAudioServiceType defined in avcodec.h. + */ + AV_FRAME_DATA_AUDIO_SERVICE_TYPE, + /** + * Mastering display metadata associated with a video frame. The payload is + * an AVMasteringDisplayMetadata type and contains information about the + * mastering display color volume. + */ + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA, + /** + * The GOP timecode in 25 bit timecode format. Data format is 64-bit integer. + * This is set on the first frame of a GOP that has a temporal reference of 0. + */ + AV_FRAME_DATA_GOP_TIMECODE, + + /** + * The data represents the AVSphericalMapping structure defined in + * libavutil/spherical.h. + */ + AV_FRAME_DATA_SPHERICAL, + + /** + * Content light level (based on CTA-861.3). This payload contains data in + * the form of the AVContentLightMetadata struct. + */ + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + + /** + * The data contains an ICC profile as an opaque octet buffer following the + * format described by ISO 15076-1 with an optional name defined in the + * metadata key entry "name". + */ + AV_FRAME_DATA_ICC_PROFILE, + +#if FF_API_FRAME_QP + /** + * Implementation-specific description of the format of AV_FRAME_QP_TABLE_DATA. + * The contents of this side data are undocumented and internal; use + * av_frame_set_qp_table() and av_frame_get_qp_table() to access this in a + * meaningful way instead. + */ + AV_FRAME_DATA_QP_TABLE_PROPERTIES, + + /** + * Raw QP table data. Its format is described by + * AV_FRAME_DATA_QP_TABLE_PROPERTIES. Use av_frame_set_qp_table() and + * av_frame_get_qp_table() to access this instead. + */ + AV_FRAME_DATA_QP_TABLE_DATA, +#endif + + /** + * Timecode which conforms to SMPTE ST 12-1. The data is an array of 4 uint32_t + * where the first uint32_t describes how many (1-3) of the other timecodes are used. + * The timecode format is described in the av_timecode_get_smpte_from_framenum() + * function in libavutil/timecode.c. + */ + AV_FRAME_DATA_S12M_TIMECODE, + + /** + * HDR dynamic metadata associated with a video frame. The payload is + * an AVDynamicHDRPlus type and contains information for color + * volume transform - application 4 of SMPTE 2094-40:2016 standard. + */ + AV_FRAME_DATA_DYNAMIC_HDR_PLUS, + + /** + * Regions Of Interest, the data is an array of AVRegionOfInterest type, the number of + * array element is implied by AVFrameSideData.size / AVRegionOfInterest.self_size. + */ + AV_FRAME_DATA_REGIONS_OF_INTEREST, +}; + +enum AVActiveFormatDescription { + AV_AFD_SAME = 8, + AV_AFD_4_3 = 9, + AV_AFD_16_9 = 10, + AV_AFD_14_9 = 11, + AV_AFD_4_3_SP_14_9 = 13, + AV_AFD_16_9_SP_14_9 = 14, + AV_AFD_SP_4_3 = 15, +}; + + +/** + * Structure to hold side data for an AVFrame. + * + * sizeof(AVFrameSideData) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + */ +typedef struct AVFrameSideData { + enum AVFrameSideDataType type; + uint8_t *data; + int size; + AVDictionary *metadata; + AVBufferRef *buf; +} AVFrameSideData; + +/** + * Structure describing a single Region Of Interest. + * + * When multiple regions are defined in a single side-data block, they + * should be ordered from most to least important - some encoders are only + * capable of supporting a limited number of distinct regions, so will have + * to truncate the list. + * + * When overlapping regions are defined, the first region containing a given + * area of the frame applies. + */ +typedef struct AVRegionOfInterest { + /** + * Must be set to the size of this data structure (that is, + * sizeof(AVRegionOfInterest)). + */ + uint32_t self_size; + /** + * Distance in pixels from the top edge of the frame to the top and + * bottom edges and from the left edge of the frame to the left and + * right edges of the rectangle defining this region of interest. + * + * The constraints on a region are encoder dependent, so the region + * actually affected may be slightly larger for alignment or other + * reasons. + */ + int top; + int bottom; + int left; + int right; + /** + * Quantisation offset. + * + * Must be in the range -1 to +1. A value of zero indicates no quality + * change. A negative value asks for better quality (less quantisation), + * while a positive value asks for worse quality (greater quantisation). + * + * The range is calibrated so that the extreme values indicate the + * largest possible offset - if the rest of the frame is encoded with the + * worst possible quality, an offset of -1 indicates that this region + * should be encoded with the best possible quality anyway. Intermediate + * values are then interpolated in some codec-dependent way. + * + * For example, in 10-bit H.264 the quantisation parameter varies between + * -12 and 51. A typical qoffset value of -1/10 therefore indicates that + * this region should be encoded with a QP around one-tenth of the full + * range better than the rest of the frame. So, if most of the frame + * were to be encoded with a QP of around 30, this region would get a QP + * of around 24 (an offset of approximately -1/10 * (51 - -12) = -6.3). + * An extreme value of -1 would indicate that this region should be + * encoded with the best possible quality regardless of the treatment of + * the rest of the frame - that is, should be encoded at a QP of -12. + */ + AVRational qoffset; +} AVRegionOfInterest; + +/** + * This structure describes decoded (raw) audio or video data. + * + * AVFrame must be allocated using av_frame_alloc(). Note that this only + * allocates the AVFrame itself, the buffers for the data must be managed + * through other means (see below). + * AVFrame must be freed with av_frame_free(). + * + * AVFrame is typically allocated once and then reused multiple times to hold + * different data (e.g. a single AVFrame to hold frames received from a + * decoder). In such a case, av_frame_unref() will free any references held by + * the frame and reset it to its original clean state before it + * is reused again. + * + * The data described by an AVFrame is usually reference counted through the + * AVBuffer API. The underlying buffer references are stored in AVFrame.buf / + * AVFrame.extended_buf. An AVFrame is considered to be reference counted if at + * least one reference is set, i.e. if AVFrame.buf[0] != NULL. In such a case, + * every single data plane must be contained in one of the buffers in + * AVFrame.buf or AVFrame.extended_buf. + * There may be a single buffer for all the data, or one separate buffer for + * each plane, or anything in between. + * + * sizeof(AVFrame) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + * + * Fields can be accessed through AVOptions, the name string used, matches the + * C structure field name for fields accessible through AVOptions. The AVClass + * for AVFrame can be obtained from avcodec_get_frame_class() + */ +typedef struct AVFrame { +#define AV_NUM_DATA_POINTERS 8 + /** + * pointer to the picture/channel planes. + * This might be different from the first allocated byte + * + * Some decoders access areas outside 0,0 - width,height, please + * see avcodec_align_dimensions2(). Some filters and swscale can read + * up to 16 bytes beyond the planes, if these filters are to be used, + * then 16 extra bytes must be allocated. + * + * NOTE: Except for hwaccel formats, pointers not needed by the format + * MUST be set to NULL. + */ + uint8_t *data[AV_NUM_DATA_POINTERS]; + + /** + * For video, size in bytes of each picture line. + * For audio, size in bytes of each plane. + * + * For audio, only linesize[0] may be set. For planar audio, each channel + * plane must be the same size. + * + * For video the linesizes should be multiples of the CPUs alignment + * preference, this is 16 or 32 for modern desktop CPUs. + * Some code requires such alignment other code can be slower without + * correct alignment, for yet other it makes no difference. + * + * @note The linesize may be larger than the size of usable data -- there + * may be extra padding present for performance reasons. + */ + int linesize[AV_NUM_DATA_POINTERS]; + + /** + * pointers to the data planes/channels. + * + * For video, this should simply point to data[]. + * + * For planar audio, each channel has a separate data pointer, and + * linesize[0] contains the size of each channel buffer. + * For packed audio, there is just one data pointer, and linesize[0] + * contains the total size of the buffer for all channels. + * + * Note: Both data and extended_data should always be set in a valid frame, + * but for planar audio with more channels that can fit in data, + * extended_data must be used in order to access all channels. + */ + uint8_t **extended_data; + + /** + * @name Video dimensions + * Video frames only. The coded dimensions (in pixels) of the video frame, + * i.e. the size of the rectangle that contains some well-defined values. + * + * @note The part of the frame intended for display/presentation is further + * restricted by the @ref cropping "Cropping rectangle". + * @{ + */ + int width, height; + /** + * @} + */ + + /** + * number of audio samples (per channel) described by this frame + */ + int nb_samples; + + /** + * format of the frame, -1 if unknown or unset + * Values correspond to enum AVPixelFormat for video frames, + * enum AVSampleFormat for audio) + */ + int format; + + /** + * 1 -> keyframe, 0-> not + */ + int key_frame; + + /** + * Picture type of the frame. + */ + enum AVPictureType pict_type; + + /** + * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified. + */ + AVRational sample_aspect_ratio; + + /** + * Presentation timestamp in time_base units (time when frame should be shown to user). + */ + int64_t pts; + +#if FF_API_PKT_PTS + /** + * PTS copied from the AVPacket that was decoded to produce this frame. + * @deprecated use the pts field instead + */ + attribute_deprecated + int64_t pkt_pts; +#endif + + /** + * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used) + * This is also the Presentation time of this AVFrame calculated from + * only AVPacket.dts values without pts values. + */ + int64_t pkt_dts; + + /** + * picture number in bitstream order + */ + int coded_picture_number; + /** + * picture number in display order + */ + int display_picture_number; + + /** + * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) + */ + int quality; + + /** + * for some private data of the user + */ + void *opaque; + +#if FF_API_ERROR_FRAME + /** + * @deprecated unused + */ + attribute_deprecated + uint64_t error[AV_NUM_DATA_POINTERS]; +#endif + + /** + * When decoding, this signals how much the picture must be delayed. + * extra_delay = repeat_pict / (2*fps) + */ + int repeat_pict; + + /** + * The content of the picture is interlaced. + */ + int interlaced_frame; + + /** + * If the content is interlaced, is top field displayed first. + */ + int top_field_first; + + /** + * Tell user application that palette has changed from previous frame. + */ + int palette_has_changed; + + /** + * reordered opaque 64 bits (generally an integer or a double precision float + * PTS but can be anything). + * The user sets AVCodecContext.reordered_opaque to represent the input at + * that time, + * the decoder reorders values as needed and sets AVFrame.reordered_opaque + * to exactly one of the values provided by the user through AVCodecContext.reordered_opaque + */ + int64_t reordered_opaque; + + /** + * Sample rate of the audio data. + */ + int sample_rate; + + /** + * Channel layout of the audio data. + */ + uint64_t channel_layout; + + /** + * AVBuffer references backing the data for this frame. If all elements of + * this array are NULL, then this frame is not reference counted. This array + * must be filled contiguously -- if buf[i] is non-NULL then buf[j] must + * also be non-NULL for all j < i. + * + * There may be at most one AVBuffer per data plane, so for video this array + * always contains all the references. For planar audio with more than + * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in + * this array. Then the extra AVBufferRef pointers are stored in the + * extended_buf array. + */ + AVBufferRef *buf[AV_NUM_DATA_POINTERS]; + + /** + * For planar audio which requires more than AV_NUM_DATA_POINTERS + * AVBufferRef pointers, this array will hold all the references which + * cannot fit into AVFrame.buf. + * + * Note that this is different from AVFrame.extended_data, which always + * contains all the pointers. This array only contains the extra pointers, + * which cannot fit into AVFrame.buf. + * + * This array is always allocated using av_malloc() by whoever constructs + * the frame. It is freed in av_frame_unref(). + */ + AVBufferRef **extended_buf; + /** + * Number of elements in extended_buf. + */ + int nb_extended_buf; + + AVFrameSideData **side_data; + int nb_side_data; + +/** + * @defgroup lavu_frame_flags AV_FRAME_FLAGS + * @ingroup lavu_frame + * Flags describing additional frame properties. + * + * @{ + */ + +/** + * The frame data may be corrupted, e.g. due to decoding errors. + */ +#define AV_FRAME_FLAG_CORRUPT (1 << 0) +/** + * A flag to mark the frames which need to be decoded, but shouldn't be output. + */ +#define AV_FRAME_FLAG_DISCARD (1 << 2) +/** + * @} + */ + + /** + * Frame flags, a combination of @ref lavu_frame_flags + */ + int flags; + + /** + * MPEG vs JPEG YUV range. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + enum AVColorPrimaries color_primaries; + + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + enum AVChromaLocation chroma_location; + + /** + * frame timestamp estimated using various heuristics, in stream time base + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int64_t best_effort_timestamp; + + /** + * reordered pos from the last AVPacket that has been input into the decoder + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_pos; + + /** + * duration of the corresponding packet, expressed in + * AVStream->time_base units, 0 if unknown. + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_duration; + + /** + * metadata. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVDictionary *metadata; + + /** + * decode error flags of the frame, set to a combination of + * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there + * were errors during the decoding. + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int decode_error_flags; +#define FF_DECODE_ERROR_INVALID_BITSTREAM 1 +#define FF_DECODE_ERROR_MISSING_REFERENCE 2 +#define FF_DECODE_ERROR_CONCEALMENT_ACTIVE 4 +#define FF_DECODE_ERROR_DECODE_SLICES 8 + + /** + * number of audio channels, only used for audio. + * - encoding: unused + * - decoding: Read by user. + */ + int channels; + + /** + * size of the corresponding packet containing the compressed + * frame. + * It is set to a negative value if unknown. + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int pkt_size; + +#if FF_API_FRAME_QP + /** + * QP table + */ + attribute_deprecated + int8_t *qscale_table; + /** + * QP store stride + */ + attribute_deprecated + int qstride; + + attribute_deprecated + int qscale_type; + + attribute_deprecated + AVBufferRef *qp_table_buf; +#endif + /** + * For hwaccel-format frames, this should be a reference to the + * AVHWFramesContext describing the frame. + */ + AVBufferRef *hw_frames_ctx; + + /** + * AVBufferRef for free use by the API user. FFmpeg will never check the + * contents of the buffer ref. FFmpeg calls av_buffer_unref() on it when + * the frame is unreferenced. av_frame_copy_props() calls create a new + * reference with av_buffer_ref() for the target frame's opaque_ref field. + * + * This is unrelated to the opaque field, although it serves a similar + * purpose. + */ + AVBufferRef *opaque_ref; + + /** + * @anchor cropping + * @name Cropping + * Video frames only. The number of pixels to discard from the the + * top/bottom/left/right border of the frame to obtain the sub-rectangle of + * the frame intended for presentation. + * @{ + */ + size_t crop_top; + size_t crop_bottom; + size_t crop_left; + size_t crop_right; + /** + * @} + */ + + /** + * AVBufferRef for internal use by a single libav* library. + * Must not be used to transfer data between libraries. + * Has to be NULL when ownership of the frame leaves the respective library. + * + * Code outside the FFmpeg libs should never check or change the contents of the buffer ref. + * + * FFmpeg calls av_buffer_unref() on it when the frame is unreferenced. + * av_frame_copy_props() calls create a new reference with av_buffer_ref() + * for the target frame's private_ref field. + */ + AVBufferRef *private_ref; +} AVFrame; + +#if FF_API_FRAME_GET_SET +/** + * Accessors for some AVFrame fields. These used to be provided for ABI + * compatibility, and do not need to be used anymore. + */ +attribute_deprecated +int64_t av_frame_get_best_effort_timestamp(const AVFrame *frame); +attribute_deprecated +void av_frame_set_best_effort_timestamp(AVFrame *frame, int64_t val); +attribute_deprecated +int64_t av_frame_get_pkt_duration (const AVFrame *frame); +attribute_deprecated +void av_frame_set_pkt_duration (AVFrame *frame, int64_t val); +attribute_deprecated +int64_t av_frame_get_pkt_pos (const AVFrame *frame); +attribute_deprecated +void av_frame_set_pkt_pos (AVFrame *frame, int64_t val); +attribute_deprecated +int64_t av_frame_get_channel_layout (const AVFrame *frame); +attribute_deprecated +void av_frame_set_channel_layout (AVFrame *frame, int64_t val); +attribute_deprecated +int av_frame_get_channels (const AVFrame *frame); +attribute_deprecated +void av_frame_set_channels (AVFrame *frame, int val); +attribute_deprecated +int av_frame_get_sample_rate (const AVFrame *frame); +attribute_deprecated +void av_frame_set_sample_rate (AVFrame *frame, int val); +attribute_deprecated +AVDictionary *av_frame_get_metadata (const AVFrame *frame); +attribute_deprecated +void av_frame_set_metadata (AVFrame *frame, AVDictionary *val); +attribute_deprecated +int av_frame_get_decode_error_flags (const AVFrame *frame); +attribute_deprecated +void av_frame_set_decode_error_flags (AVFrame *frame, int val); +attribute_deprecated +int av_frame_get_pkt_size(const AVFrame *frame); +attribute_deprecated +void av_frame_set_pkt_size(AVFrame *frame, int val); +#if FF_API_FRAME_QP +attribute_deprecated +int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type); +attribute_deprecated +int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int type); +#endif +attribute_deprecated +enum AVColorSpace av_frame_get_colorspace(const AVFrame *frame); +attribute_deprecated +void av_frame_set_colorspace(AVFrame *frame, enum AVColorSpace val); +attribute_deprecated +enum AVColorRange av_frame_get_color_range(const AVFrame *frame); +attribute_deprecated +void av_frame_set_color_range(AVFrame *frame, enum AVColorRange val); +#endif + +/** + * Get the name of a colorspace. + * @return a static string identifying the colorspace; can be NULL. + */ +const char *av_get_colorspace_name(enum AVColorSpace val); + +/** + * Allocate an AVFrame and set its fields to default values. The resulting + * struct must be freed using av_frame_free(). + * + * @return An AVFrame filled with default values or NULL on failure. + * + * @note this only allocates the AVFrame itself, not the data buffers. Those + * must be allocated through other means, e.g. with av_frame_get_buffer() or + * manually. + */ +AVFrame *av_frame_alloc(void); + +/** + * Free the frame and any dynamically allocated objects in it, + * e.g. extended_data. If the frame is reference counted, it will be + * unreferenced first. + * + * @param frame frame to be freed. The pointer will be set to NULL. + */ +void av_frame_free(AVFrame **frame); + +/** + * Set up a new reference to the data described by the source frame. + * + * Copy frame properties from src to dst and create a new reference for each + * AVBufferRef from src. + * + * If src is not reference counted, new buffers are allocated and the data is + * copied. + * + * @warning: dst MUST have been either unreferenced with av_frame_unref(dst), + * or newly allocated with av_frame_alloc() before calling this + * function, or undefined behavior will occur. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_frame_ref(AVFrame *dst, const AVFrame *src); + +/** + * Create a new frame that references the same data as src. + * + * This is a shortcut for av_frame_alloc()+av_frame_ref(). + * + * @return newly created AVFrame on success, NULL on error. + */ +AVFrame *av_frame_clone(const AVFrame *src); + +/** + * Unreference all the buffers referenced by frame and reset the frame fields. + */ +void av_frame_unref(AVFrame *frame); + +/** + * Move everything contained in src to dst and reset src. + * + * @warning: dst is not unreferenced, but directly overwritten without reading + * or deallocating its contents. Call av_frame_unref(dst) manually + * before calling this function to ensure that no memory is leaked. + */ +void av_frame_move_ref(AVFrame *dst, AVFrame *src); + +/** + * Allocate new buffer(s) for audio or video data. + * + * The following fields must be set on frame before calling this function: + * - format (pixel format for video, sample format for audio) + * - width and height for video + * - nb_samples and channel_layout for audio + * + * This function will fill AVFrame.data and AVFrame.buf arrays and, if + * necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf. + * For planar formats, one buffer will be allocated for each plane. + * + * @warning: if frame already has been allocated, calling this function will + * leak memory. In addition, undefined behavior can occur in certain + * cases. + * + * @param frame frame in which to store the new buffers. + * @param align Required buffer size alignment. If equal to 0, alignment will be + * chosen automatically for the current CPU. It is highly + * recommended to pass 0 here unless you know what you are doing. + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_frame_get_buffer(AVFrame *frame, int align); + +/** + * Check if the frame data is writable. + * + * @return A positive value if the frame data is writable (which is true if and + * only if each of the underlying buffers has only one reference, namely the one + * stored in this frame). Return 0 otherwise. + * + * If 1 is returned the answer is valid until av_buffer_ref() is called on any + * of the underlying AVBufferRefs (e.g. through av_frame_ref() or directly). + * + * @see av_frame_make_writable(), av_buffer_is_writable() + */ +int av_frame_is_writable(AVFrame *frame); + +/** + * Ensure that the frame data is writable, avoiding data copy if possible. + * + * Do nothing if the frame is writable, allocate new buffers and copy the data + * if it is not. + * + * @return 0 on success, a negative AVERROR on error. + * + * @see av_frame_is_writable(), av_buffer_is_writable(), + * av_buffer_make_writable() + */ +int av_frame_make_writable(AVFrame *frame); + +/** + * Copy the frame data from src to dst. + * + * This function does not allocate anything, dst must be already initialized and + * allocated with the same parameters as src. + * + * This function only copies the frame data (i.e. the contents of the data / + * extended data arrays), not any other properties. + * + * @return >= 0 on success, a negative AVERROR on error. + */ +int av_frame_copy(AVFrame *dst, const AVFrame *src); + +/** + * Copy only "metadata" fields from src to dst. + * + * Metadata for the purpose of this function are those fields that do not affect + * the data layout in the buffers. E.g. pts, sample rate (for audio) or sample + * aspect ratio (for video), but not width/height or channel layout. + * Side data is also copied. + */ +int av_frame_copy_props(AVFrame *dst, const AVFrame *src); + +/** + * Get the buffer reference a given data plane is stored in. + * + * @param plane index of the data plane of interest in frame->extended_data. + * + * @return the buffer reference that contains the plane or NULL if the input + * frame is not valid. + */ +AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane); + +/** + * Add a new side data to a frame. + * + * @param frame a frame to which the side data should be added + * @param type type of the added side data + * @param size size of the side data + * + * @return newly added side data on success, NULL on error + */ +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + int size); + +/** + * Add a new side data to a frame from an existing AVBufferRef + * + * @param frame a frame to which the side data should be added + * @param type the type of the added side data + * @param buf an AVBufferRef to add as side data. The ownership of + * the reference is transferred to the frame. + * + * @return newly added side data on success, NULL on error. On failure + * the frame is unchanged and the AVBufferRef remains owned by + * the caller. + */ +AVFrameSideData *av_frame_new_side_data_from_buf(AVFrame *frame, + enum AVFrameSideDataType type, + AVBufferRef *buf); + +/** + * @return a pointer to the side data of a given type on success, NULL if there + * is no side data with such type in this frame. + */ +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type); + +/** + * If side data of the supplied type exists in the frame, free it and remove it + * from the frame. + */ +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type); + + +/** + * Flags for frame cropping. + */ +enum { + /** + * Apply the maximum possible cropping, even if it requires setting the + * AVFrame.data[] entries to unaligned pointers. Passing unaligned data + * to FFmpeg API is generally not allowed, and causes undefined behavior + * (such as crashes). You can pass unaligned data only to FFmpeg APIs that + * are explicitly documented to accept it. Use this flag only if you + * absolutely know what you are doing. + */ + AV_FRAME_CROP_UNALIGNED = 1 << 0, +}; + +/** + * Crop the given video AVFrame according to its crop_left/crop_top/crop_right/ + * crop_bottom fields. If cropping is successful, the function will adjust the + * data pointers and the width/height fields, and set the crop fields to 0. + * + * In all cases, the cropping boundaries will be rounded to the inherent + * alignment of the pixel format. In some cases, such as for opaque hwaccel + * formats, the left/top cropping is ignored. The crop fields are set to 0 even + * if the cropping was rounded or ignored. + * + * @param frame the frame which should be cropped + * @param flags Some combination of AV_FRAME_CROP_* flags, or 0. + * + * @return >= 0 on success, a negative AVERROR on error. If the cropping fields + * were invalid, AVERROR(ERANGE) is returned, and nothing is changed. + */ +int av_frame_apply_cropping(AVFrame *frame, int flags); + +/** + * @return a string identifying the side data type + */ +const char *av_frame_side_data_name(enum AVFrameSideDataType type); + +/** + * @} + */ + +#endif /* AVUTIL_FRAME_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hash.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hash.c new file mode 100644 index 0000000000..75edb6db78 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hash.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2013 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include "hash.h" + +#include "adler32.h" +#include "crc.h" +#include "md5.h" +#include "murmur3.h" +#include "ripemd.h" +#include "sha.h" +#include "sha512.h" + +#include "avstring.h" +#include "base64.h" +#include "error.h" +#include "intreadwrite.h" +#include "mem.h" + +enum hashtype { + MD5, + MURMUR3, + RIPEMD128, + RIPEMD160, + RIPEMD256, + RIPEMD320, + SHA160, + SHA224, + SHA256, + SHA512_224, + SHA512_256, + SHA384, + SHA512, + CRC32, + ADLER32, + NUM_HASHES +}; + +typedef struct AVHashContext { + void *ctx; + enum hashtype type; + const AVCRC *crctab; + uint32_t crc; +} AVHashContext; + +static const struct { + const char *name; + int size; +} hashdesc[] = { + [MD5] = {"MD5", 16}, + [MURMUR3] = {"murmur3", 16}, + [RIPEMD128] = {"RIPEMD128", 16}, + [RIPEMD160] = {"RIPEMD160", 20}, + [RIPEMD256] = {"RIPEMD256", 32}, + [RIPEMD320] = {"RIPEMD320", 40}, + [SHA160] = {"SHA160", 20}, + [SHA224] = {"SHA224", 28}, + [SHA256] = {"SHA256", 32}, + [SHA512_224] = {"SHA512/224", 28}, + [SHA512_256] = {"SHA512/256", 32}, + [SHA384] = {"SHA384", 48}, + [SHA512] = {"SHA512", 64}, + [CRC32] = {"CRC32", 4}, + [ADLER32] = {"adler32", 4}, +}; + +const char *av_hash_names(int i) +{ + if (i < 0 || i >= NUM_HASHES) return NULL; + return hashdesc[i].name; +} + +const char *av_hash_get_name(const AVHashContext *ctx) +{ + return hashdesc[ctx->type].name; +} + +int av_hash_get_size(const AVHashContext *ctx) +{ + return hashdesc[ctx->type].size; +} + +int av_hash_alloc(AVHashContext **ctx, const char *name) +{ + AVHashContext *res; + int i; + *ctx = NULL; + for (i = 0; i < NUM_HASHES; i++) + if (av_strcasecmp(name, hashdesc[i].name) == 0) + break; + if (i >= NUM_HASHES) return AVERROR(EINVAL); + res = av_mallocz(sizeof(*res)); + if (!res) return AVERROR(ENOMEM); + res->type = i; + switch (i) { + case MD5: res->ctx = av_md5_alloc(); break; + case MURMUR3: res->ctx = av_murmur3_alloc(); break; + case RIPEMD128: + case RIPEMD160: + case RIPEMD256: + case RIPEMD320: res->ctx = av_ripemd_alloc(); break; + case SHA160: + case SHA224: + case SHA256: res->ctx = av_sha_alloc(); break; + case SHA512_224: + case SHA512_256: + case SHA384: + case SHA512: res->ctx = av_sha512_alloc(); break; + case CRC32: res->crctab = av_crc_get_table(AV_CRC_32_IEEE_LE); break; + case ADLER32: break; + } + if (i != ADLER32 && i != CRC32 && !res->ctx) { + av_free(res); + return AVERROR(ENOMEM); + } + *ctx = res; + return 0; +} + +void av_hash_init(AVHashContext *ctx) +{ + switch (ctx->type) { + case MD5: av_md5_init(ctx->ctx); break; + case MURMUR3: av_murmur3_init(ctx->ctx); break; + case RIPEMD128: av_ripemd_init(ctx->ctx, 128); break; + case RIPEMD160: av_ripemd_init(ctx->ctx, 160); break; + case RIPEMD256: av_ripemd_init(ctx->ctx, 256); break; + case RIPEMD320: av_ripemd_init(ctx->ctx, 320); break; + case SHA160: av_sha_init(ctx->ctx, 160); break; + case SHA224: av_sha_init(ctx->ctx, 224); break; + case SHA256: av_sha_init(ctx->ctx, 256); break; + case SHA512_224: av_sha512_init(ctx->ctx, 224); break; + case SHA512_256: av_sha512_init(ctx->ctx, 256); break; + case SHA384: av_sha512_init(ctx->ctx, 384); break; + case SHA512: av_sha512_init(ctx->ctx, 512); break; + case CRC32: ctx->crc = UINT32_MAX; break; + case ADLER32: ctx->crc = 1; break; + } +} + +#if FF_API_CRYPTO_SIZE_T +void av_hash_update(AVHashContext *ctx, const uint8_t *src, int len) +#else +void av_hash_update(AVHashContext *ctx, const uint8_t *src, size_t len) +#endif +{ + switch (ctx->type) { + case MD5: av_md5_update(ctx->ctx, src, len); break; + case MURMUR3: av_murmur3_update(ctx->ctx, src, len); break; + case RIPEMD128: + case RIPEMD160: + case RIPEMD256: + case RIPEMD320: av_ripemd_update(ctx->ctx, src, len); break; + case SHA160: + case SHA224: + case SHA256: av_sha_update(ctx->ctx, src, len); break; + case SHA512_224: + case SHA512_256: + case SHA384: + case SHA512: av_sha512_update(ctx->ctx, src, len); break; + case CRC32: ctx->crc = av_crc(ctx->crctab, ctx->crc, src, len); break; + case ADLER32: ctx->crc = av_adler32_update(ctx->crc, src, len); break; + } +} + +void av_hash_final(AVHashContext *ctx, uint8_t *dst) +{ + switch (ctx->type) { + case MD5: av_md5_final(ctx->ctx, dst); break; + case MURMUR3: av_murmur3_final(ctx->ctx, dst); break; + case RIPEMD128: + case RIPEMD160: + case RIPEMD256: + case RIPEMD320: av_ripemd_final(ctx->ctx, dst); break; + case SHA160: + case SHA224: + case SHA256: av_sha_final(ctx->ctx, dst); break; + case SHA512_224: + case SHA512_256: + case SHA384: + case SHA512: av_sha512_final(ctx->ctx, dst); break; + case CRC32: AV_WB32(dst, ctx->crc ^ UINT32_MAX); break; + case ADLER32: AV_WB32(dst, ctx->crc); break; + } +} + +void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size) +{ + uint8_t buf[AV_HASH_MAX_SIZE]; + unsigned rsize = av_hash_get_size(ctx); + + av_hash_final(ctx, buf); + memcpy(dst, buf, FFMIN(size, rsize)); + if (size > rsize) + memset(dst + rsize, 0, size - rsize); +} + +void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size) +{ + uint8_t buf[AV_HASH_MAX_SIZE]; + unsigned rsize = av_hash_get_size(ctx), i; + + av_hash_final(ctx, buf); + for (i = 0; i < FFMIN(rsize, size / 2); i++) + snprintf(dst + i * 2, size - i * 2, "%02x", buf[i]); +} + +void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size) +{ + uint8_t buf[AV_HASH_MAX_SIZE], b64[AV_BASE64_SIZE(AV_HASH_MAX_SIZE)]; + unsigned rsize = av_hash_get_size(ctx), osize; + + av_hash_final(ctx, buf); + av_base64_encode(b64, sizeof(b64), buf, rsize); + osize = AV_BASE64_SIZE(rsize); + memcpy(dst, b64, FFMIN(osize, size)); + if (size < osize) + dst[size - 1] = 0; +} + +void av_hash_freep(AVHashContext **ctx) +{ + if (*ctx) + av_freep(&(*ctx)->ctx); + av_freep(ctx); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hash.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hash.h new file mode 100644 index 0000000000..7693e6bf0d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hash.h @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2013 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_hash_generic + * Generic hashing API + */ + +#ifndef AVUTIL_HASH_H +#define AVUTIL_HASH_H + +#include + +#include "version.h" + +/** + * @defgroup lavu_hash Hash Functions + * @ingroup lavu_crypto + * Hash functions useful in multimedia. + * + * Hash functions are widely used in multimedia, from error checking and + * concealment to internal regression testing. libavutil has efficient + * implementations of a variety of hash functions that may be useful for + * FFmpeg and other multimedia applications. + * + * @{ + * + * @defgroup lavu_hash_generic Generic Hashing API + * An abstraction layer for all hash functions supported by libavutil. + * + * If your application needs to support a wide range of different hash + * functions, then the Generic Hashing API is for you. It provides a generic, + * reusable API for @ref lavu_hash "all hash functions" implemented in libavutil. + * If you just need to use one particular hash function, use the @ref lavu_hash + * "individual hash" directly. + * + * @section Sample Code + * + * A basic template for using the Generic Hashing API follows: + * + * @code + * struct AVHashContext *ctx = NULL; + * const char *hash_name = NULL; + * uint8_t *output_buf = NULL; + * + * // Select from a string returned by av_hash_names() + * hash_name = ...; + * + * // Allocate a hash context + * ret = av_hash_alloc(&ctx, hash_name); + * if (ret < 0) + * return ret; + * + * // Initialize the hash context + * av_hash_init(ctx); + * + * // Update the hash context with data + * while (data_left) { + * av_hash_update(ctx, data, size); + * } + * + * // Now we have no more data, so it is time to finalize the hash and get the + * // output. But we need to first allocate an output buffer. Note that you can + * // use any memory allocation function, including malloc(), not just + * // av_malloc(). + * output_buf = av_malloc(av_hash_get_size(ctx)); + * if (!output_buf) + * return AVERROR(ENOMEM); + * + * // Finalize the hash context. + * // You can use any of the av_hash_final*() functions provided, for other + * // output formats. If you do so, be sure to adjust the memory allocation + * // above. See the function documentation below for the exact amount of extra + * // memory needed. + * av_hash_final(ctx, output_buffer); + * + * // Free the context + * av_hash_freep(&ctx); + * @endcode + * + * @section Hash Function-Specific Information + * If the CRC32 hash is selected, the #AV_CRC_32_IEEE polynomial will be + * used. + * + * If the Murmur3 hash is selected, the default seed will be used. See @ref + * lavu_murmur3_seedinfo "Murmur3" for more information. + * + * @{ + */ + +/** + * @example ffhash.c + * This example is a simple command line application that takes one or more + * arguments. It demonstrates a typical use of the hashing API with allocation, + * initialization, updating, and finalizing. + */ + +struct AVHashContext; + +/** + * Allocate a hash context for the algorithm specified by name. + * + * @return >= 0 for success, a negative error code for failure + * + * @note The context is not initialized after a call to this function; you must + * call av_hash_init() to do so. + */ +int av_hash_alloc(struct AVHashContext **ctx, const char *name); + +/** + * Get the names of available hash algorithms. + * + * This function can be used to enumerate the algorithms. + * + * @param[in] i Index of the hash algorithm, starting from 0 + * @return Pointer to a static string or `NULL` if `i` is out of range + */ +const char *av_hash_names(int i); + +/** + * Get the name of the algorithm corresponding to the given hash context. + */ +const char *av_hash_get_name(const struct AVHashContext *ctx); + +/** + * Maximum value that av_hash_get_size() will currently return. + * + * You can use this if you absolutely want or need to use static allocation for + * the output buffer and are fine with not supporting hashes newly added to + * libavutil without recompilation. + * + * @warning + * Adding new hashes with larger sizes, and increasing the macro while doing + * so, will not be considered an ABI change. To prevent your code from + * overflowing a buffer, either dynamically allocate the output buffer with + * av_hash_get_size(), or limit your use of the Hashing API to hashes that are + * already in FFmpeg during the time of compilation. + */ +#define AV_HASH_MAX_SIZE 64 + +/** + * Get the size of the resulting hash value in bytes. + * + * The maximum value this function will currently return is available as macro + * #AV_HASH_MAX_SIZE. + * + * @param[in] ctx Hash context + * @return Size of the hash value in bytes + */ +int av_hash_get_size(const struct AVHashContext *ctx); + +/** + * Initialize or reset a hash context. + * + * @param[in,out] ctx Hash context + */ +void av_hash_init(struct AVHashContext *ctx); + +/** + * Update a hash context with additional data. + * + * @param[in,out] ctx Hash context + * @param[in] src Data to be added to the hash context + * @param[in] len Size of the additional data + */ +#if FF_API_CRYPTO_SIZE_T +void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, int len); +#else +void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, size_t len); +#endif + +/** + * Finalize a hash context and compute the actual hash value. + * + * The minimum size of `dst` buffer is given by av_hash_get_size() or + * #AV_HASH_MAX_SIZE. The use of the latter macro is discouraged. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the final hash value will be stored + * + * @see av_hash_final_bin() provides an alternative API + */ +void av_hash_final(struct AVHashContext *ctx, uint8_t *dst); + +/** + * Finalize a hash context and store the actual hash value in a buffer. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * If `size` is smaller than the hash size (given by av_hash_get_size()), the + * hash is truncated; if size is larger, the buffer is padded with 0. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the final hash value will be stored + * @param[in] size Number of bytes to write to `dst` + */ +void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and store the hexadecimal representation of the + * actual hash value as a string. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * The string is always 0-terminated. + * + * If `size` is smaller than `2 * hash_size + 1`, where `hash_size` is the + * value returned by av_hash_get_size(), the string will be truncated. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the string will be stored + * @param[in] size Maximum number of bytes to write to `dst` + */ +void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and store the Base64 representation of the + * actual hash value as a string. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * The string is always 0-terminated. + * + * If `size` is smaller than AV_BASE64_SIZE(hash_size), where `hash_size` is + * the value returned by av_hash_get_size(), the string will be truncated. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the final hash value will be stored + * @param[in] size Maximum number of bytes to write to `dst` + */ +void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Free hash context and set hash context pointer to `NULL`. + * + * @param[in,out] ctx Pointer to hash context + */ +void av_hash_freep(struct AVHashContext **ctx); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_HASH_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hdr_dynamic_metadata.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hdr_dynamic_metadata.c new file mode 100644 index 0000000000..0fa1ee82de --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hdr_dynamic_metadata.c @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2018 Mohammad Izadi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hdr_dynamic_metadata.h" +#include "mem.h" + +AVDynamicHDRPlus *av_dynamic_hdr_plus_alloc(size_t *size) +{ + AVDynamicHDRPlus *hdr_plus = av_mallocz(sizeof(AVDynamicHDRPlus)); + if (!hdr_plus) + return NULL; + + if (size) + *size = sizeof(*hdr_plus); + + return hdr_plus; +} + +AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_DYNAMIC_HDR_PLUS, + sizeof(AVDynamicHDRPlus)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, sizeof(AVDynamicHDRPlus)); + + return (AVDynamicHDRPlus *)side_data->data; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hdr_dynamic_metadata.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hdr_dynamic_metadata.h new file mode 100644 index 0000000000..2d72de56ae --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hdr_dynamic_metadata.h @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2018 Mohammad Izadi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HDR_DYNAMIC_METADATA_H +#define AVUTIL_HDR_DYNAMIC_METADATA_H + +#include "frame.h" +#include "rational.h" + +/** + * Option for overlapping elliptical pixel selectors in an image. + */ +enum AVHDRPlusOverlapProcessOption { + AV_HDR_PLUS_OVERLAP_PROCESS_WEIGHTED_AVERAGING = 0, + AV_HDR_PLUS_OVERLAP_PROCESS_LAYERING = 1, +}; + +/** + * Represents the percentile at a specific percentage in + * a distribution. + */ +typedef struct AVHDRPlusPercentile { + /** + * The percentage value corresponding to a specific percentile linearized + * RGB value in the processing window in the scene. The value shall be in + * the range of 0 to100, inclusive. + */ + uint8_t percentage; + + /** + * The linearized maxRGB value at a specific percentile in the processing + * window in the scene. The value shall be in the range of 0 to 1, inclusive + * and in multiples of 0.00001. + */ + AVRational percentile; +} AVHDRPlusPercentile; + +/** + * Color transform parameters at a processing window in a dynamic metadata for + * SMPTE 2094-40. + */ +typedef struct AVHDRPlusColorTransformParams { + /** + * The relative x coordinate of the top left pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(width of Picture - 1). The value 1 corresponds + * to the absolute coordinate of width of Picture - 1. The value for + * first processing window shall be 0. + */ + AVRational window_upper_left_corner_x; + + /** + * The relative y coordinate of the top left pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(height of Picture - 1). The value 1 corresponds + * to the absolute coordinate of height of Picture - 1. The value for + * first processing window shall be 0. + */ + AVRational window_upper_left_corner_y; + + /** + * The relative x coordinate of the bottom right pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(width of Picture - 1). The value 1 corresponds + * to the absolute coordinate of width of Picture - 1. The value for + * first processing window shall be 1. + */ + AVRational window_lower_right_corner_x; + + /** + * The relative y coordinate of the bottom right pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(height of Picture - 1). The value 1 corresponds + * to the absolute coordinate of height of Picture - 1. The value for + * first processing window shall be 1. + */ + AVRational window_lower_right_corner_y; + + /** + * The x coordinate of the center position of the concentric internal and + * external ellipses of the elliptical pixel selector in the processing + * window. The value shall be in the range of 0 to (width of Picture - 1), + * inclusive and in multiples of 1 pixel. + */ + uint16_t center_of_ellipse_x; + + /** + * The y coordinate of the center position of the concentric internal and + * external ellipses of the elliptical pixel selector in the processing + * window. The value shall be in the range of 0 to (height of Picture - 1), + * inclusive and in multiples of 1 pixel. + */ + uint16_t center_of_ellipse_y; + + /** + * The clockwise rotation angle in degree of arc with respect to the + * positive direction of the x-axis of the concentric internal and external + * ellipses of the elliptical pixel selector in the processing window. The + * value shall be in the range of 0 to 180, inclusive and in multiples of 1. + */ + uint8_t rotation_angle; + + /** + * The semi-major axis value of the internal ellipse of the elliptical pixel + * selector in amount of pixels in the processing window. The value shall be + * in the range of 1 to 65535, inclusive and in multiples of 1 pixel. + */ + uint16_t semimajor_axis_internal_ellipse; + + /** + * The semi-major axis value of the external ellipse of the elliptical pixel + * selector in amount of pixels in the processing window. The value + * shall not be less than semimajor_axis_internal_ellipse of the current + * processing window. The value shall be in the range of 1 to 65535, + * inclusive and in multiples of 1 pixel. + */ + uint16_t semimajor_axis_external_ellipse; + + /** + * The semi-minor axis value of the external ellipse of the elliptical pixel + * selector in amount of pixels in the processing window. The value shall be + * in the range of 1 to 65535, inclusive and in multiples of 1 pixel. + */ + uint16_t semiminor_axis_external_ellipse; + + /** + * Overlap process option indicates one of the two methods of combining + * rendered pixels in the processing window in an image with at least one + * elliptical pixel selector. For overlapping elliptical pixel selectors + * in an image, overlap_process_option shall have the same value. + */ + enum AVHDRPlusOverlapProcessOption overlap_process_option; + + /** + * The maximum of the color components of linearized RGB values in the + * processing window in the scene. The values should be in the range of 0 to + * 1, inclusive and in multiples of 0.00001. maxscl[ 0 ], maxscl[ 1 ], and + * maxscl[ 2 ] are corresponding to R, G, B color components respectively. + */ + AVRational maxscl[3]; + + /** + * The average of linearized maxRGB values in the processing window in the + * scene. The value should be in the range of 0 to 1, inclusive and in + * multiples of 0.00001. + */ + AVRational average_maxrgb; + + /** + * The number of linearized maxRGB values at given percentiles in the + * processing window in the scene. The maximum value shall be 15. + */ + uint8_t num_distribution_maxrgb_percentiles; + + /** + * The linearized maxRGB values at given percentiles in the + * processing window in the scene. + */ + AVHDRPlusPercentile distribution_maxrgb[15]; + + /** + * The fraction of selected pixels in the image that contains the brightest + * pixel in the scene. The value shall be in the range of 0 to 1, inclusive + * and in multiples of 0.001. + */ + AVRational fraction_bright_pixels; + + /** + * This flag indicates that the metadata for the tone mapping function in + * the processing window is present (for value of 1). + */ + uint8_t tone_mapping_flag; + + /** + * The x coordinate of the separation point between the linear part and the + * curved part of the tone mapping function. The value shall be in the range + * of 0 to 1, excluding 0 and in multiples of 1/4095. + */ + AVRational knee_point_x; + + /** + * The y coordinate of the separation point between the linear part and the + * curved part of the tone mapping function. The value shall be in the range + * of 0 to 1, excluding 0 and in multiples of 1/4095. + */ + AVRational knee_point_y; + + /** + * The number of the intermediate anchor parameters of the tone mapping + * function in the processing window. The maximum value shall be 15. + */ + uint8_t num_bezier_curve_anchors; + + /** + * The intermediate anchor parameters of the tone mapping function in the + * processing window in the scene. The values should be in the range of 0 + * to 1, inclusive and in multiples of 1/1023. + */ + AVRational bezier_curve_anchors[15]; + + /** + * This flag shall be equal to 0 in bitstreams conforming to this version of + * this Specification. Other values are reserved for future use. + */ + uint8_t color_saturation_mapping_flag; + + /** + * The color saturation gain in the processing window in the scene. The + * value shall be in the range of 0 to 63/8, inclusive and in multiples of + * 1/8. The default value shall be 1. + */ + AVRational color_saturation_weight; +} AVHDRPlusColorTransformParams; + +/** + * This struct represents dynamic metadata for color volume transform - + * application 4 of SMPTE 2094-40:2016 standard. + * + * To be used as payload of a AVFrameSideData or AVPacketSideData with the + * appropriate type. + * + * @note The struct should be allocated with + * av_dynamic_hdr_plus_alloc() and its size is not a part of + * the public ABI. + */ +typedef struct AVDynamicHDRPlus { + /** + * Country code by Rec. ITU-T T.35 Annex A. The value shall be 0xB5. + */ + uint8_t itu_t_t35_country_code; + + /** + * Application version in the application defining document in ST-2094 + * suite. The value shall be set to 0. + */ + uint8_t application_version; + + /** + * The number of processing windows. The value shall be in the range + * of 1 to 3, inclusive. + */ + uint8_t num_windows; + + /** + * The color transform parameters for every processing window. + */ + AVHDRPlusColorTransformParams params[3]; + + /** + * The nominal maximum display luminance of the targeted system display, + * in units of 0.0001 candelas per square metre. The value shall be in + * the range of 0 to 10000, inclusive. + */ + AVRational targeted_system_display_maximum_luminance; + + /** + * This flag shall be equal to 0 in bit streams conforming to this version + * of this Specification. The value 1 is reserved for future use. + */ + uint8_t targeted_system_display_actual_peak_luminance_flag; + + /** + * The number of rows in the targeted system_display_actual_peak_luminance + * array. The value shall be in the range of 2 to 25, inclusive. + */ + uint8_t num_rows_targeted_system_display_actual_peak_luminance; + + /** + * The number of columns in the + * targeted_system_display_actual_peak_luminance array. The value shall be + * in the range of 2 to 25, inclusive. + */ + uint8_t num_cols_targeted_system_display_actual_peak_luminance; + + /** + * The normalized actual peak luminance of the targeted system display. The + * values should be in the range of 0 to 1, inclusive and in multiples of + * 1/15. + */ + AVRational targeted_system_display_actual_peak_luminance[25][25]; + + /** + * This flag shall be equal to 0 in bitstreams conforming to this version of + * this Specification. The value 1 is reserved for future use. + */ + uint8_t mastering_display_actual_peak_luminance_flag; + + /** + * The number of rows in the mastering_display_actual_peak_luminance array. + * The value shall be in the range of 2 to 25, inclusive. + */ + uint8_t num_rows_mastering_display_actual_peak_luminance; + + /** + * The number of columns in the mastering_display_actual_peak_luminance + * array. The value shall be in the range of 2 to 25, inclusive. + */ + uint8_t num_cols_mastering_display_actual_peak_luminance; + + /** + * The normalized actual peak luminance of the mastering display used for + * mastering the image essence. The values should be in the range of 0 to 1, + * inclusive and in multiples of 1/15. + */ + AVRational mastering_display_actual_peak_luminance[25][25]; +} AVDynamicHDRPlus; + +/** + * Allocate an AVDynamicHDRPlus structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVDynamicHDRPlus filled with default values or NULL + * on failure. + */ +AVDynamicHDRPlus *av_dynamic_hdr_plus_alloc(size_t *size); + +/** + * Allocate a complete AVDynamicHDRPlus and add it to the frame. + * @param frame The frame which side data is added to. + * + * @return The AVDynamicHDRPlus structure to be filled by caller or NULL + * on failure. + */ +AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_HDR_DYNAMIC_METADATA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hmac.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hmac.c new file mode 100644 index 0000000000..d064a105f4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hmac.c @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "attributes.h" +#include "hmac.h" +#include "md5.h" +#include "sha.h" +#include "sha512.h" +#include "mem.h" +#include "version.h" + +#define MAX_HASHLEN 64 +#define MAX_BLOCKLEN 128 + +typedef void (*hmac_final)(void *ctx, uint8_t *dst); +#if FF_API_CRYPTO_SIZE_T +typedef void (*hmac_update)(void *ctx, const uint8_t *src, int len); +#else +typedef void (*hmac_update)(void *ctx, const uint8_t *src, size_t len); +#endif +typedef void (*hmac_init)(void *ctx); + +struct AVHMAC { + void *hash; + int blocklen, hashlen; + hmac_final final; + hmac_update update; + hmac_init init; + uint8_t key[MAX_BLOCKLEN]; + int keylen; +}; + +#define DEFINE_SHA(bits) \ +static av_cold void sha ## bits ##_init(void *ctx) \ +{ \ + av_sha_init(ctx, bits); \ +} + +#define DEFINE_SHA512(bits) \ +static av_cold void sha ## bits ##_init(void *ctx) \ +{ \ + av_sha512_init(ctx, bits); \ +} + +DEFINE_SHA(160) +DEFINE_SHA(224) +DEFINE_SHA(256) +DEFINE_SHA512(384) +DEFINE_SHA512(512) + +AVHMAC *av_hmac_alloc(enum AVHMACType type) +{ + AVHMAC *c = av_mallocz(sizeof(*c)); + if (!c) + return NULL; + switch (type) { + case AV_HMAC_MD5: + c->blocklen = 64; + c->hashlen = 16; + c->init = (hmac_init) av_md5_init; + c->update = (hmac_update) av_md5_update; + c->final = (hmac_final) av_md5_final; + c->hash = av_md5_alloc(); + break; + case AV_HMAC_SHA1: + c->blocklen = 64; + c->hashlen = 20; + c->init = sha160_init; + c->update = (hmac_update) av_sha_update; + c->final = (hmac_final) av_sha_final; + c->hash = av_sha_alloc(); + break; + case AV_HMAC_SHA224: + c->blocklen = 64; + c->hashlen = 28; + c->init = sha224_init; + c->update = (hmac_update) av_sha_update; + c->final = (hmac_final) av_sha_final; + c->hash = av_sha_alloc(); + break; + case AV_HMAC_SHA256: + c->blocklen = 64; + c->hashlen = 32; + c->init = sha256_init; + c->update = (hmac_update) av_sha_update; + c->final = (hmac_final) av_sha_final; + c->hash = av_sha_alloc(); + break; + case AV_HMAC_SHA384: + c->blocklen = 128; + c->hashlen = 48; + c->init = sha384_init; + c->update = (hmac_update) av_sha512_update; + c->final = (hmac_final) av_sha512_final; + c->hash = av_sha512_alloc(); + break; + case AV_HMAC_SHA512: + c->blocklen = 128; + c->hashlen = 64; + c->init = sha512_init; + c->update = (hmac_update) av_sha512_update; + c->final = (hmac_final) av_sha512_final; + c->hash = av_sha512_alloc(); + break; + default: + av_free(c); + return NULL; + } + if (!c->hash) { + av_free(c); + return NULL; + } + return c; +} + +void av_hmac_free(AVHMAC *c) +{ + if (!c) + return; + av_freep(&c->hash); + av_free(c); +} + +void av_hmac_init(AVHMAC *c, const uint8_t *key, unsigned int keylen) +{ + int i; + uint8_t block[MAX_BLOCKLEN]; + if (keylen > c->blocklen) { + c->init(c->hash); + c->update(c->hash, key, keylen); + c->final(c->hash, c->key); + c->keylen = c->hashlen; + } else { + memcpy(c->key, key, keylen); + c->keylen = keylen; + } + c->init(c->hash); + for (i = 0; i < c->keylen; i++) + block[i] = c->key[i] ^ 0x36; + for (i = c->keylen; i < c->blocklen; i++) + block[i] = 0x36; + c->update(c->hash, block, c->blocklen); +} + +void av_hmac_update(AVHMAC *c, const uint8_t *data, unsigned int len) +{ + c->update(c->hash, data, len); +} + +int av_hmac_final(AVHMAC *c, uint8_t *out, unsigned int outlen) +{ + uint8_t block[MAX_BLOCKLEN]; + int i; + if (outlen < c->hashlen) + return AVERROR(EINVAL); + c->final(c->hash, out); + c->init(c->hash); + for (i = 0; i < c->keylen; i++) + block[i] = c->key[i] ^ 0x5C; + for (i = c->keylen; i < c->blocklen; i++) + block[i] = 0x5C; + c->update(c->hash, block, c->blocklen); + c->update(c->hash, out, c->hashlen); + c->final(c->hash, out); + return c->hashlen; +} + +int av_hmac_calc(AVHMAC *c, const uint8_t *data, unsigned int len, + const uint8_t *key, unsigned int keylen, + uint8_t *out, unsigned int outlen) +{ + av_hmac_init(c, key, keylen); + av_hmac_update(c, data, len); + return av_hmac_final(c, out, outlen); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hmac.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hmac.h new file mode 100644 index 0000000000..412e950719 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hmac.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HMAC_H +#define AVUTIL_HMAC_H + +#include + +#include "version.h" +/** + * @defgroup lavu_hmac HMAC + * @ingroup lavu_crypto + * @{ + */ + +enum AVHMACType { + AV_HMAC_MD5, + AV_HMAC_SHA1, + AV_HMAC_SHA224, + AV_HMAC_SHA256, + AV_HMAC_SHA384, + AV_HMAC_SHA512, +}; + +typedef struct AVHMAC AVHMAC; + +/** + * Allocate an AVHMAC context. + * @param type The hash function used for the HMAC. + */ +AVHMAC *av_hmac_alloc(enum AVHMACType type); + +/** + * Free an AVHMAC context. + * @param ctx The context to free, may be NULL + */ +void av_hmac_free(AVHMAC *ctx); + +/** + * Initialize an AVHMAC context with an authentication key. + * @param ctx The HMAC context + * @param key The authentication key + * @param keylen The length of the key, in bytes + */ +void av_hmac_init(AVHMAC *ctx, const uint8_t *key, unsigned int keylen); + +/** + * Hash data with the HMAC. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + */ +void av_hmac_update(AVHMAC *ctx, const uint8_t *data, unsigned int len); + +/** + * Finish hashing and output the HMAC digest. + * @param ctx The HMAC context + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_final(AVHMAC *ctx, uint8_t *out, unsigned int outlen); + +/** + * Hash an array of data with a key. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + * @param key The authentication key + * @param keylen The length of the key, in bytes + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_calc(AVHMAC *ctx, const uint8_t *data, unsigned int len, + const uint8_t *key, unsigned int keylen, + uint8_t *out, unsigned int outlen); + +/** + * @} + */ + +#endif /* AVUTIL_HMAC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext.c new file mode 100644 index 0000000000..f1e404ab20 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext.c @@ -0,0 +1,879 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "buffer.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_internal.h" +#include "imgutils.h" +#include "log.h" +#include "mem.h" +#include "pixdesc.h" +#include "pixfmt.h" + +static const HWContextType * const hw_table[] = { +#if CONFIG_CUDA + &ff_hwcontext_type_cuda, +#endif +#if CONFIG_D3D11VA + &ff_hwcontext_type_d3d11va, +#endif +#if CONFIG_LIBDRM + &ff_hwcontext_type_drm, +#endif +#if CONFIG_DXVA2 + &ff_hwcontext_type_dxva2, +#endif +#if CONFIG_OPENCL + &ff_hwcontext_type_opencl, +#endif +#if CONFIG_QSV + &ff_hwcontext_type_qsv, +#endif +#if CONFIG_VAAPI + &ff_hwcontext_type_vaapi, +#endif +#if CONFIG_VDPAU + &ff_hwcontext_type_vdpau, +#endif +#if CONFIG_VIDEOTOOLBOX + &ff_hwcontext_type_videotoolbox, +#endif +#if CONFIG_MEDIACODEC + &ff_hwcontext_type_mediacodec, +#endif + NULL, +}; + +static const char *const hw_type_names[] = { + [AV_HWDEVICE_TYPE_CUDA] = "cuda", + [AV_HWDEVICE_TYPE_DRM] = "drm", + [AV_HWDEVICE_TYPE_DXVA2] = "dxva2", + [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va", + [AV_HWDEVICE_TYPE_OPENCL] = "opencl", + [AV_HWDEVICE_TYPE_QSV] = "qsv", + [AV_HWDEVICE_TYPE_VAAPI] = "vaapi", + [AV_HWDEVICE_TYPE_VDPAU] = "vdpau", + [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox", + [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec", +}; + +enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name) +{ + int type; + for (type = 0; type < FF_ARRAY_ELEMS(hw_type_names); type++) { + if (hw_type_names[type] && !strcmp(hw_type_names[type], name)) + return type; + } + return AV_HWDEVICE_TYPE_NONE; +} + +const char *av_hwdevice_get_type_name(enum AVHWDeviceType type) +{ + if (type > AV_HWDEVICE_TYPE_NONE && + type < FF_ARRAY_ELEMS(hw_type_names)) + return hw_type_names[type]; + else + return NULL; +} + +enum AVHWDeviceType av_hwdevice_iterate_types(enum AVHWDeviceType prev) +{ + enum AVHWDeviceType next; + int i, set = 0; + for (i = 0; hw_table[i]; i++) { + if (prev != AV_HWDEVICE_TYPE_NONE && hw_table[i]->type <= prev) + continue; + if (!set || hw_table[i]->type < next) { + next = hw_table[i]->type; + set = 1; + } + } + return set ? next : AV_HWDEVICE_TYPE_NONE; +} + +static const AVClass hwdevice_ctx_class = { + .class_name = "AVHWDeviceContext", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +static void hwdevice_ctx_free(void *opaque, uint8_t *data) +{ + AVHWDeviceContext *ctx = (AVHWDeviceContext*)data; + + /* uninit might still want access the hw context and the user + * free() callback might destroy it, so uninit has to be called first */ + if (ctx->internal->hw_type->device_uninit) + ctx->internal->hw_type->device_uninit(ctx); + + if (ctx->free) + ctx->free(ctx); + + av_buffer_unref(&ctx->internal->source_device); + + av_freep(&ctx->hwctx); + av_freep(&ctx->internal->priv); + av_freep(&ctx->internal); + av_freep(&ctx); +} + +AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type) +{ + AVHWDeviceContext *ctx; + AVBufferRef *buf; + const HWContextType *hw_type = NULL; + int i; + + for (i = 0; hw_table[i]; i++) { + if (hw_table[i]->type == type) { + hw_type = hw_table[i]; + break; + } + } + if (!hw_type) + return NULL; + + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return NULL; + + ctx->internal = av_mallocz(sizeof(*ctx->internal)); + if (!ctx->internal) + goto fail; + + if (hw_type->device_priv_size) { + ctx->internal->priv = av_mallocz(hw_type->device_priv_size); + if (!ctx->internal->priv) + goto fail; + } + + if (hw_type->device_hwctx_size) { + ctx->hwctx = av_mallocz(hw_type->device_hwctx_size); + if (!ctx->hwctx) + goto fail; + } + + buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), + hwdevice_ctx_free, NULL, + AV_BUFFER_FLAG_READONLY); + if (!buf) + goto fail; + + ctx->type = type; + ctx->av_class = &hwdevice_ctx_class; + + ctx->internal->hw_type = hw_type; + + return buf; + +fail: + if (ctx->internal) + av_freep(&ctx->internal->priv); + av_freep(&ctx->internal); + av_freep(&ctx->hwctx); + av_freep(&ctx); + return NULL; +} + +int av_hwdevice_ctx_init(AVBufferRef *ref) +{ + AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data; + int ret; + + if (ctx->internal->hw_type->device_init) { + ret = ctx->internal->hw_type->device_init(ctx); + if (ret < 0) + goto fail; + } + + return 0; +fail: + if (ctx->internal->hw_type->device_uninit) + ctx->internal->hw_type->device_uninit(ctx); + return ret; +} + +static const AVClass hwframe_ctx_class = { + .class_name = "AVHWFramesContext", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +static void hwframe_ctx_free(void *opaque, uint8_t *data) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)data; + + if (ctx->internal->pool_internal) + av_buffer_pool_uninit(&ctx->internal->pool_internal); + + if (ctx->internal->hw_type->frames_uninit) + ctx->internal->hw_type->frames_uninit(ctx); + + if (ctx->free) + ctx->free(ctx); + + av_buffer_unref(&ctx->internal->source_frames); + + av_buffer_unref(&ctx->device_ref); + + av_freep(&ctx->hwctx); + av_freep(&ctx->internal->priv); + av_freep(&ctx->internal); + av_freep(&ctx); +} + +AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in) +{ + AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)device_ref_in->data; + const HWContextType *hw_type = device_ctx->internal->hw_type; + AVHWFramesContext *ctx; + AVBufferRef *buf, *device_ref = NULL; + + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return NULL; + + ctx->internal = av_mallocz(sizeof(*ctx->internal)); + if (!ctx->internal) + goto fail; + + if (hw_type->frames_priv_size) { + ctx->internal->priv = av_mallocz(hw_type->frames_priv_size); + if (!ctx->internal->priv) + goto fail; + } + + if (hw_type->frames_hwctx_size) { + ctx->hwctx = av_mallocz(hw_type->frames_hwctx_size); + if (!ctx->hwctx) + goto fail; + } + + device_ref = av_buffer_ref(device_ref_in); + if (!device_ref) + goto fail; + + buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), + hwframe_ctx_free, NULL, + AV_BUFFER_FLAG_READONLY); + if (!buf) + goto fail; + + ctx->av_class = &hwframe_ctx_class; + ctx->device_ref = device_ref; + ctx->device_ctx = device_ctx; + ctx->format = AV_PIX_FMT_NONE; + ctx->sw_format = AV_PIX_FMT_NONE; + + ctx->internal->hw_type = hw_type; + + return buf; + +fail: + if (device_ref) + av_buffer_unref(&device_ref); + if (ctx->internal) + av_freep(&ctx->internal->priv); + av_freep(&ctx->internal); + av_freep(&ctx->hwctx); + av_freep(&ctx); + return NULL; +} + +static int hwframe_pool_prealloc(AVBufferRef *ref) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data; + AVFrame **frames; + int i, ret = 0; + + frames = av_mallocz_array(ctx->initial_pool_size, sizeof(*frames)); + if (!frames) + return AVERROR(ENOMEM); + + for (i = 0; i < ctx->initial_pool_size; i++) { + frames[i] = av_frame_alloc(); + if (!frames[i]) + goto fail; + + ret = av_hwframe_get_buffer(ref, frames[i], 0); + if (ret < 0) + goto fail; + } + +fail: + for (i = 0; i < ctx->initial_pool_size; i++) + av_frame_free(&frames[i]); + av_freep(&frames); + + return ret; +} + +int av_hwframe_ctx_init(AVBufferRef *ref) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data; + const enum AVPixelFormat *pix_fmt; + int ret; + + if (ctx->internal->source_frames) { + /* A derived frame context is already initialised. */ + return 0; + } + + /* validate the pixel format */ + for (pix_fmt = ctx->internal->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) { + if (*pix_fmt == ctx->format) + break; + } + if (*pix_fmt == AV_PIX_FMT_NONE) { + av_log(ctx, AV_LOG_ERROR, + "The hardware pixel format '%s' is not supported by the device type '%s'\n", + av_get_pix_fmt_name(ctx->format), ctx->internal->hw_type->name); + return AVERROR(ENOSYS); + } + + /* validate the dimensions */ + ret = av_image_check_size(ctx->width, ctx->height, 0, ctx); + if (ret < 0) + return ret; + + /* format-specific init */ + if (ctx->internal->hw_type->frames_init) { + ret = ctx->internal->hw_type->frames_init(ctx); + if (ret < 0) + goto fail; + } + + if (ctx->internal->pool_internal && !ctx->pool) + ctx->pool = ctx->internal->pool_internal; + + /* preallocate the frames in the pool, if requested */ + if (ctx->initial_pool_size > 0) { + ret = hwframe_pool_prealloc(ref); + if (ret < 0) + goto fail; + } + + return 0; +fail: + if (ctx->internal->hw_type->frames_uninit) + ctx->internal->hw_type->frames_uninit(ctx); + return ret; +} + +int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats, int flags) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; + + if (!ctx->internal->hw_type->transfer_get_formats) + return AVERROR(ENOSYS); + + return ctx->internal->hw_type->transfer_get_formats(ctx, dir, formats); +} + +static int transfer_data_alloc(AVFrame *dst, const AVFrame *src, int flags) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)src->hw_frames_ctx->data; + AVFrame *frame_tmp; + int ret = 0; + + frame_tmp = av_frame_alloc(); + if (!frame_tmp) + return AVERROR(ENOMEM); + + /* if the format is set, use that + * otherwise pick the first supported one */ + if (dst->format >= 0) { + frame_tmp->format = dst->format; + } else { + enum AVPixelFormat *formats; + + ret = av_hwframe_transfer_get_formats(src->hw_frames_ctx, + AV_HWFRAME_TRANSFER_DIRECTION_FROM, + &formats, 0); + if (ret < 0) + goto fail; + frame_tmp->format = formats[0]; + av_freep(&formats); + } + frame_tmp->width = ctx->width; + frame_tmp->height = ctx->height; + + ret = av_frame_get_buffer(frame_tmp, 32); + if (ret < 0) + goto fail; + + ret = av_hwframe_transfer_data(frame_tmp, src, flags); + if (ret < 0) + goto fail; + + frame_tmp->width = src->width; + frame_tmp->height = src->height; + + av_frame_move_ref(dst, frame_tmp); + +fail: + av_frame_free(&frame_tmp); + return ret; +} + +int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags) +{ + AVHWFramesContext *ctx; + int ret; + + if (!dst->buf[0]) + return transfer_data_alloc(dst, src, flags); + + if (src->hw_frames_ctx) { + ctx = (AVHWFramesContext*)src->hw_frames_ctx->data; + + ret = ctx->internal->hw_type->transfer_data_from(ctx, dst, src); + if (ret < 0) + return ret; + } else if (dst->hw_frames_ctx) { + ctx = (AVHWFramesContext*)dst->hw_frames_ctx->data; + + ret = ctx->internal->hw_type->transfer_data_to(ctx, dst, src); + if (ret < 0) + return ret; + } else + return AVERROR(ENOSYS); + + return 0; +} + +int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; + int ret; + + if (ctx->internal->source_frames) { + // This is a derived frame context, so we allocate in the source + // and map the frame immediately. + AVFrame *src_frame; + + frame->format = ctx->format; + frame->hw_frames_ctx = av_buffer_ref(hwframe_ref); + if (!frame->hw_frames_ctx) + return AVERROR(ENOMEM); + + src_frame = av_frame_alloc(); + if (!src_frame) + return AVERROR(ENOMEM); + + ret = av_hwframe_get_buffer(ctx->internal->source_frames, + src_frame, 0); + if (ret < 0) { + av_frame_free(&src_frame); + return ret; + } + + ret = av_hwframe_map(frame, src_frame, + ctx->internal->source_allocation_map_flags); + if (ret) { + av_log(ctx, AV_LOG_ERROR, "Failed to map frame into derived " + "frame context: %d.\n", ret); + av_frame_free(&src_frame); + return ret; + } + + // Free the source frame immediately - the mapped frame still + // contains a reference to it. + av_frame_free(&src_frame); + + return 0; + } + + if (!ctx->internal->hw_type->frames_get_buffer) + return AVERROR(ENOSYS); + + if (!ctx->pool) + return AVERROR(EINVAL); + + frame->hw_frames_ctx = av_buffer_ref(hwframe_ref); + if (!frame->hw_frames_ctx) + return AVERROR(ENOMEM); + + ret = ctx->internal->hw_type->frames_get_buffer(ctx, frame); + if (ret < 0) { + av_buffer_unref(&frame->hw_frames_ctx); + return ret; + } + + return 0; +} + +void *av_hwdevice_hwconfig_alloc(AVBufferRef *ref) +{ + AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data; + const HWContextType *hw_type = ctx->internal->hw_type; + + if (hw_type->device_hwconfig_size == 0) + return NULL; + + return av_mallocz(hw_type->device_hwconfig_size); +} + +AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, + const void *hwconfig) +{ + AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data; + const HWContextType *hw_type = ctx->internal->hw_type; + AVHWFramesConstraints *constraints; + + if (!hw_type->frames_get_constraints) + return NULL; + + constraints = av_mallocz(sizeof(*constraints)); + if (!constraints) + return NULL; + + constraints->min_width = constraints->min_height = 0; + constraints->max_width = constraints->max_height = INT_MAX; + + if (hw_type->frames_get_constraints(ctx, hwconfig, constraints) >= 0) { + return constraints; + } else { + av_hwframe_constraints_free(&constraints); + return NULL; + } +} + +void av_hwframe_constraints_free(AVHWFramesConstraints **constraints) +{ + if (*constraints) { + av_freep(&(*constraints)->valid_hw_formats); + av_freep(&(*constraints)->valid_sw_formats); + } + av_freep(constraints); +} + +int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, + const char *device, AVDictionary *opts, int flags) +{ + AVBufferRef *device_ref = NULL; + AVHWDeviceContext *device_ctx; + int ret = 0; + + device_ref = av_hwdevice_ctx_alloc(type); + if (!device_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + device_ctx = (AVHWDeviceContext*)device_ref->data; + + if (!device_ctx->internal->hw_type->device_create) { + ret = AVERROR(ENOSYS); + goto fail; + } + + ret = device_ctx->internal->hw_type->device_create(device_ctx, device, + opts, flags); + if (ret < 0) + goto fail; + + ret = av_hwdevice_ctx_init(device_ref); + if (ret < 0) + goto fail; + + *pdevice_ref = device_ref; + return 0; +fail: + av_buffer_unref(&device_ref); + *pdevice_ref = NULL; + return ret; +} + +int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr, + enum AVHWDeviceType type, + AVBufferRef *src_ref, int flags) +{ + AVBufferRef *dst_ref = NULL, *tmp_ref; + AVHWDeviceContext *dst_ctx, *tmp_ctx; + int ret = 0; + + tmp_ref = src_ref; + while (tmp_ref) { + tmp_ctx = (AVHWDeviceContext*)tmp_ref->data; + if (tmp_ctx->type == type) { + dst_ref = av_buffer_ref(tmp_ref); + if (!dst_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + goto done; + } + tmp_ref = tmp_ctx->internal->source_device; + } + + dst_ref = av_hwdevice_ctx_alloc(type); + if (!dst_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + dst_ctx = (AVHWDeviceContext*)dst_ref->data; + + tmp_ref = src_ref; + while (tmp_ref) { + tmp_ctx = (AVHWDeviceContext*)tmp_ref->data; + if (dst_ctx->internal->hw_type->device_derive) { + ret = dst_ctx->internal->hw_type->device_derive(dst_ctx, + tmp_ctx, + flags); + if (ret == 0) { + dst_ctx->internal->source_device = av_buffer_ref(src_ref); + if (!dst_ctx->internal->source_device) { + ret = AVERROR(ENOMEM); + goto fail; + } + ret = av_hwdevice_ctx_init(dst_ref); + if (ret < 0) + goto fail; + goto done; + } + if (ret != AVERROR(ENOSYS)) + goto fail; + } + tmp_ref = tmp_ctx->internal->source_device; + } + + ret = AVERROR(ENOSYS); + goto fail; + +done: + *dst_ref_ptr = dst_ref; + return 0; + +fail: + av_buffer_unref(&dst_ref); + *dst_ref_ptr = NULL; + return ret; +} + +static void ff_hwframe_unmap(void *opaque, uint8_t *data) +{ + HWMapDescriptor *hwmap = (HWMapDescriptor*)data; + AVHWFramesContext *ctx = opaque; + + if (hwmap->unmap) + hwmap->unmap(ctx, hwmap); + + av_frame_free(&hwmap->source); + + av_buffer_unref(&hwmap->hw_frames_ctx); + + av_free(hwmap); +} + +int ff_hwframe_map_create(AVBufferRef *hwframe_ref, + AVFrame *dst, const AVFrame *src, + void (*unmap)(AVHWFramesContext *ctx, + HWMapDescriptor *hwmap), + void *priv) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; + HWMapDescriptor *hwmap; + int ret; + + hwmap = av_mallocz(sizeof(*hwmap)); + if (!hwmap) { + ret = AVERROR(ENOMEM); + goto fail; + } + + hwmap->source = av_frame_alloc(); + if (!hwmap->source) { + ret = AVERROR(ENOMEM); + goto fail; + } + ret = av_frame_ref(hwmap->source, src); + if (ret < 0) + goto fail; + + hwmap->hw_frames_ctx = av_buffer_ref(hwframe_ref); + if (!hwmap->hw_frames_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + + hwmap->unmap = unmap; + hwmap->priv = priv; + + dst->buf[0] = av_buffer_create((uint8_t*)hwmap, sizeof(*hwmap), + &ff_hwframe_unmap, ctx, 0); + if (!dst->buf[0]) { + ret = AVERROR(ENOMEM); + goto fail; + } + + return 0; + +fail: + if (hwmap) { + av_buffer_unref(&hwmap->hw_frames_ctx); + av_frame_free(&hwmap->source); + } + av_free(hwmap); + return ret; +} + +int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags) +{ + AVHWFramesContext *src_frames, *dst_frames; + HWMapDescriptor *hwmap; + int ret; + + if (src->hw_frames_ctx && dst->hw_frames_ctx) { + src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data; + dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data; + + if ((src_frames == dst_frames && + src->format == dst_frames->sw_format && + dst->format == dst_frames->format) || + (src_frames->internal->source_frames && + src_frames->internal->source_frames->data == + (uint8_t*)dst_frames)) { + // This is an unmap operation. We don't need to directly + // do anything here other than fill in the original frame, + // because the real unmap will be invoked when the last + // reference to the mapped frame disappears. + if (!src->buf[0]) { + av_log(src_frames, AV_LOG_ERROR, "Invalid mapping " + "found when attempting unmap.\n"); + return AVERROR(EINVAL); + } + hwmap = (HWMapDescriptor*)src->buf[0]->data; + av_frame_unref(dst); + return av_frame_ref(dst, hwmap->source); + } + } + + if (src->hw_frames_ctx) { + src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data; + + if (src_frames->format == src->format && + src_frames->internal->hw_type->map_from) { + ret = src_frames->internal->hw_type->map_from(src_frames, + dst, src, flags); + if (ret != AVERROR(ENOSYS)) + return ret; + } + } + + if (dst->hw_frames_ctx) { + dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data; + + if (dst_frames->format == dst->format && + dst_frames->internal->hw_type->map_to) { + ret = dst_frames->internal->hw_type->map_to(dst_frames, + dst, src, flags); + if (ret != AVERROR(ENOSYS)) + return ret; + } + } + + return AVERROR(ENOSYS); +} + +int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx, + enum AVPixelFormat format, + AVBufferRef *derived_device_ctx, + AVBufferRef *source_frame_ctx, + int flags) +{ + AVBufferRef *dst_ref = NULL; + AVHWFramesContext *dst = NULL; + AVHWFramesContext *src = (AVHWFramesContext*)source_frame_ctx->data; + int ret; + + if (src->internal->source_frames) { + AVHWFramesContext *src_src = + (AVHWFramesContext*)src->internal->source_frames->data; + AVHWDeviceContext *dst_dev = + (AVHWDeviceContext*)derived_device_ctx->data; + + if (src_src->device_ctx == dst_dev) { + // This is actually an unmapping, so we just return a + // reference to the source frame context. + *derived_frame_ctx = + av_buffer_ref(src->internal->source_frames); + if (!*derived_frame_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + return 0; + } + } + + dst_ref = av_hwframe_ctx_alloc(derived_device_ctx); + if (!dst_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + + dst = (AVHWFramesContext*)dst_ref->data; + + dst->format = format; + dst->sw_format = src->sw_format; + dst->width = src->width; + dst->height = src->height; + + dst->internal->source_frames = av_buffer_ref(source_frame_ctx); + if (!dst->internal->source_frames) { + ret = AVERROR(ENOMEM); + goto fail; + } + + dst->internal->source_allocation_map_flags = + flags & (AV_HWFRAME_MAP_READ | + AV_HWFRAME_MAP_WRITE | + AV_HWFRAME_MAP_OVERWRITE | + AV_HWFRAME_MAP_DIRECT); + + ret = AVERROR(ENOSYS); + if (src->internal->hw_type->frames_derive_from) + ret = src->internal->hw_type->frames_derive_from(dst, src, flags); + if (ret == AVERROR(ENOSYS) && + dst->internal->hw_type->frames_derive_to) + ret = dst->internal->hw_type->frames_derive_to(dst, src, flags); + if (ret == AVERROR(ENOSYS)) + ret = 0; + if (ret) + goto fail; + + *derived_frame_ctx = dst_ref; + return 0; + +fail: + if (dst) + av_buffer_unref(&dst->internal->source_frames); + av_buffer_unref(&dst_ref); + return ret; +} + +int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src) +{ + HWMapDescriptor *hwmap = (HWMapDescriptor*)dst->buf[0]->data; + av_frame_unref(hwmap->source); + return av_frame_ref(hwmap->source, src); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext.h new file mode 100644 index 0000000000..f5a4b62387 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext.h @@ -0,0 +1,584 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_H +#define AVUTIL_HWCONTEXT_H + +#include "buffer.h" +#include "frame.h" +#include "log.h" +#include "pixfmt.h" + +enum AVHWDeviceType { + AV_HWDEVICE_TYPE_NONE, + AV_HWDEVICE_TYPE_VDPAU, + AV_HWDEVICE_TYPE_CUDA, + AV_HWDEVICE_TYPE_VAAPI, + AV_HWDEVICE_TYPE_DXVA2, + AV_HWDEVICE_TYPE_QSV, + AV_HWDEVICE_TYPE_VIDEOTOOLBOX, + AV_HWDEVICE_TYPE_D3D11VA, + AV_HWDEVICE_TYPE_DRM, + AV_HWDEVICE_TYPE_OPENCL, + AV_HWDEVICE_TYPE_MEDIACODEC, +}; + +typedef struct AVHWDeviceInternal AVHWDeviceInternal; + +/** + * This struct aggregates all the (hardware/vendor-specific) "high-level" state, + * i.e. state that is not tied to a concrete processing configuration. + * E.g., in an API that supports hardware-accelerated encoding and decoding, + * this struct will (if possible) wrap the state that is common to both encoding + * and decoding and from which specific instances of encoders or decoders can be + * derived. + * + * This struct is reference-counted with the AVBuffer mechanism. The + * av_hwdevice_ctx_alloc() constructor yields a reference, whose data field + * points to the actual AVHWDeviceContext. Further objects derived from + * AVHWDeviceContext (such as AVHWFramesContext, describing a frame pool with + * specific properties) will hold an internal reference to it. After all the + * references are released, the AVHWDeviceContext itself will be freed, + * optionally invoking a user-specified callback for uninitializing the hardware + * state. + */ +typedef struct AVHWDeviceContext { + /** + * A class for logging. Set by av_hwdevice_ctx_alloc(). + */ + const AVClass *av_class; + + /** + * Private data used internally by libavutil. Must not be accessed in any + * way by the caller. + */ + AVHWDeviceInternal *internal; + + /** + * This field identifies the underlying API used for hardware access. + * + * This field is set when this struct is allocated and never changed + * afterwards. + */ + enum AVHWDeviceType type; + + /** + * The format-specific data, allocated and freed by libavutil along with + * this context. + * + * Should be cast by the user to the format-specific context defined in the + * corresponding header (hwcontext_*.h) and filled as described in the + * documentation before calling av_hwdevice_ctx_init(). + * + * After calling av_hwdevice_ctx_init() this struct should not be modified + * by the caller. + */ + void *hwctx; + + /** + * This field may be set by the caller before calling av_hwdevice_ctx_init(). + * + * If non-NULL, this callback will be called when the last reference to + * this context is unreferenced, immediately before it is freed. + * + * @note when other objects (e.g an AVHWFramesContext) are derived from this + * struct, this callback will be invoked after all such child objects + * are fully uninitialized and their respective destructors invoked. + */ + void (*free)(struct AVHWDeviceContext *ctx); + + /** + * Arbitrary user data, to be used e.g. by the free() callback. + */ + void *user_opaque; +} AVHWDeviceContext; + +typedef struct AVHWFramesInternal AVHWFramesInternal; + +/** + * This struct describes a set or pool of "hardware" frames (i.e. those with + * data not located in normal system memory). All the frames in the pool are + * assumed to be allocated in the same way and interchangeable. + * + * This struct is reference-counted with the AVBuffer mechanism and tied to a + * given AVHWDeviceContext instance. The av_hwframe_ctx_alloc() constructor + * yields a reference, whose data field points to the actual AVHWFramesContext + * struct. + */ +typedef struct AVHWFramesContext { + /** + * A class for logging. + */ + const AVClass *av_class; + + /** + * Private data used internally by libavutil. Must not be accessed in any + * way by the caller. + */ + AVHWFramesInternal *internal; + + /** + * A reference to the parent AVHWDeviceContext. This reference is owned and + * managed by the enclosing AVHWFramesContext, but the caller may derive + * additional references from it. + */ + AVBufferRef *device_ref; + + /** + * The parent AVHWDeviceContext. This is simply a pointer to + * device_ref->data provided for convenience. + * + * Set by libavutil in av_hwframe_ctx_init(). + */ + AVHWDeviceContext *device_ctx; + + /** + * The format-specific data, allocated and freed automatically along with + * this context. + * + * Should be cast by the user to the format-specific context defined in the + * corresponding header (hwframe_*.h) and filled as described in the + * documentation before calling av_hwframe_ctx_init(). + * + * After any frames using this context are created, the contents of this + * struct should not be modified by the caller. + */ + void *hwctx; + + /** + * This field may be set by the caller before calling av_hwframe_ctx_init(). + * + * If non-NULL, this callback will be called when the last reference to + * this context is unreferenced, immediately before it is freed. + */ + void (*free)(struct AVHWFramesContext *ctx); + + /** + * Arbitrary user data, to be used e.g. by the free() callback. + */ + void *user_opaque; + + /** + * A pool from which the frames are allocated by av_hwframe_get_buffer(). + * This field may be set by the caller before calling av_hwframe_ctx_init(). + * The buffers returned by calling av_buffer_pool_get() on this pool must + * have the properties described in the documentation in the corresponding hw + * type's header (hwcontext_*.h). The pool will be freed strictly before + * this struct's free() callback is invoked. + * + * This field may be NULL, then libavutil will attempt to allocate a pool + * internally. Note that certain device types enforce pools allocated at + * fixed size (frame count), which cannot be extended dynamically. In such a + * case, initial_pool_size must be set appropriately. + */ + AVBufferPool *pool; + + /** + * Initial size of the frame pool. If a device type does not support + * dynamically resizing the pool, then this is also the maximum pool size. + * + * May be set by the caller before calling av_hwframe_ctx_init(). Must be + * set if pool is NULL and the device type does not support dynamic pools. + */ + int initial_pool_size; + + /** + * The pixel format identifying the underlying HW surface type. + * + * Must be a hwaccel format, i.e. the corresponding descriptor must have the + * AV_PIX_FMT_FLAG_HWACCEL flag set. + * + * Must be set by the user before calling av_hwframe_ctx_init(). + */ + enum AVPixelFormat format; + + /** + * The pixel format identifying the actual data layout of the hardware + * frames. + * + * Must be set by the caller before calling av_hwframe_ctx_init(). + * + * @note when the underlying API does not provide the exact data layout, but + * only the colorspace/bit depth, this field should be set to the fully + * planar version of that format (e.g. for 8-bit 420 YUV it should be + * AV_PIX_FMT_YUV420P, not AV_PIX_FMT_NV12 or anything else). + */ + enum AVPixelFormat sw_format; + + /** + * The allocated dimensions of the frames in this pool. + * + * Must be set by the user before calling av_hwframe_ctx_init(). + */ + int width, height; +} AVHWFramesContext; + +/** + * Look up an AVHWDeviceType by name. + * + * @param name String name of the device type (case-insensitive). + * @return The type from enum AVHWDeviceType, or AV_HWDEVICE_TYPE_NONE if + * not found. + */ +enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name); + +/** Get the string name of an AVHWDeviceType. + * + * @param type Type from enum AVHWDeviceType. + * @return Pointer to a static string containing the name, or NULL if the type + * is not valid. + */ +const char *av_hwdevice_get_type_name(enum AVHWDeviceType type); + +/** + * Iterate over supported device types. + * + * @param type AV_HWDEVICE_TYPE_NONE initially, then the previous type + * returned by this function in subsequent iterations. + * @return The next usable device type from enum AVHWDeviceType, or + * AV_HWDEVICE_TYPE_NONE if there are no more. + */ +enum AVHWDeviceType av_hwdevice_iterate_types(enum AVHWDeviceType prev); + +/** + * Allocate an AVHWDeviceContext for a given hardware type. + * + * @param type the type of the hardware device to allocate. + * @return a reference to the newly created AVHWDeviceContext on success or NULL + * on failure. + */ +AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type); + +/** + * Finalize the device context before use. This function must be called after + * the context is filled with all the required information and before it is + * used in any way. + * + * @param ref a reference to the AVHWDeviceContext + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hwdevice_ctx_init(AVBufferRef *ref); + +/** + * Open a device of the specified type and create an AVHWDeviceContext for it. + * + * This is a convenience function intended to cover the simple cases. Callers + * who need to fine-tune device creation/management should open the device + * manually and then wrap it in an AVHWDeviceContext using + * av_hwdevice_ctx_alloc()/av_hwdevice_ctx_init(). + * + * The returned context is already initialized and ready for use, the caller + * should not call av_hwdevice_ctx_init() on it. The user_opaque/free fields of + * the created AVHWDeviceContext are set by this function and should not be + * touched by the caller. + * + * @param device_ctx On success, a reference to the newly-created device context + * will be written here. The reference is owned by the caller + * and must be released with av_buffer_unref() when no longer + * needed. On failure, NULL will be written to this pointer. + * @param type The type of the device to create. + * @param device A type-specific string identifying the device to open. + * @param opts A dictionary of additional (type-specific) options to use in + * opening the device. The dictionary remains owned by the caller. + * @param flags currently unused + * + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_hwdevice_ctx_create(AVBufferRef **device_ctx, enum AVHWDeviceType type, + const char *device, AVDictionary *opts, int flags); + +/** + * Create a new device of the specified type from an existing device. + * + * If the source device is a device of the target type or was originally + * derived from such a device (possibly through one or more intermediate + * devices of other types), then this will return a reference to the + * existing device of the same type as is requested. + * + * Otherwise, it will attempt to derive a new device from the given source + * device. If direct derivation to the new type is not implemented, it will + * attempt the same derivation from each ancestor of the source device in + * turn looking for an implemented derivation method. + * + * @param dst_ctx On success, a reference to the newly-created + * AVHWDeviceContext. + * @param type The type of the new device to create. + * @param src_ctx A reference to an existing AVHWDeviceContext which will be + * used to create the new device. + * @param flags Currently unused; should be set to zero. + * @return Zero on success, a negative AVERROR code on failure. + */ +int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ctx, + enum AVHWDeviceType type, + AVBufferRef *src_ctx, int flags); + + +/** + * Allocate an AVHWFramesContext tied to a given device context. + * + * @param device_ctx a reference to a AVHWDeviceContext. This function will make + * a new reference for internal use, the one passed to the + * function remains owned by the caller. + * @return a reference to the newly created AVHWFramesContext on success or NULL + * on failure. + */ +AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ctx); + +/** + * Finalize the context before use. This function must be called after the + * context is filled with all the required information and before it is attached + * to any frames. + * + * @param ref a reference to the AVHWFramesContext + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hwframe_ctx_init(AVBufferRef *ref); + +/** + * Allocate a new frame attached to the given AVHWFramesContext. + * + * @param hwframe_ctx a reference to an AVHWFramesContext + * @param frame an empty (freshly allocated or unreffed) frame to be filled with + * newly allocated buffers. + * @param flags currently unused, should be set to zero + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hwframe_get_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame, int flags); + +/** + * Copy data to or from a hw surface. At least one of dst/src must have an + * AVHWFramesContext attached. + * + * If src has an AVHWFramesContext attached, then the format of dst (if set) + * must use one of the formats returned by av_hwframe_transfer_get_formats(src, + * AV_HWFRAME_TRANSFER_DIRECTION_FROM). + * If dst has an AVHWFramesContext attached, then the format of src must use one + * of the formats returned by av_hwframe_transfer_get_formats(dst, + * AV_HWFRAME_TRANSFER_DIRECTION_TO) + * + * dst may be "clean" (i.e. with data/buf pointers unset), in which case the + * data buffers will be allocated by this function using av_frame_get_buffer(). + * If dst->format is set, then this format will be used, otherwise (when + * dst->format is AV_PIX_FMT_NONE) the first acceptable format will be chosen. + * + * The two frames must have matching allocated dimensions (i.e. equal to + * AVHWFramesContext.width/height), since not all device types support + * transferring a sub-rectangle of the whole surface. The display dimensions + * (i.e. AVFrame.width/height) may be smaller than the allocated dimensions, but + * also have to be equal for both frames. When the display dimensions are + * smaller than the allocated dimensions, the content of the padding in the + * destination frame is unspecified. + * + * @param dst the destination frame. dst is not touched on failure. + * @param src the source frame. + * @param flags currently unused, should be set to zero + * @return 0 on success, a negative AVERROR error code on failure. + */ +int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags); + +enum AVHWFrameTransferDirection { + /** + * Transfer the data from the queried hw frame. + */ + AV_HWFRAME_TRANSFER_DIRECTION_FROM, + + /** + * Transfer the data to the queried hw frame. + */ + AV_HWFRAME_TRANSFER_DIRECTION_TO, +}; + +/** + * Get a list of possible source or target formats usable in + * av_hwframe_transfer_data(). + * + * @param hwframe_ctx the frame context to obtain the information for + * @param dir the direction of the transfer + * @param formats the pointer to the output format list will be written here. + * The list is terminated with AV_PIX_FMT_NONE and must be freed + * by the caller when no longer needed using av_free(). + * If this function returns successfully, the format list will + * have at least one item (not counting the terminator). + * On failure, the contents of this pointer are unspecified. + * @param flags currently unused, should be set to zero + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats, int flags); + + +/** + * This struct describes the constraints on hardware frames attached to + * a given device with a hardware-specific configuration. This is returned + * by av_hwdevice_get_hwframe_constraints() and must be freed by + * av_hwframe_constraints_free() after use. + */ +typedef struct AVHWFramesConstraints { + /** + * A list of possible values for format in the hw_frames_ctx, + * terminated by AV_PIX_FMT_NONE. This member will always be filled. + */ + enum AVPixelFormat *valid_hw_formats; + + /** + * A list of possible values for sw_format in the hw_frames_ctx, + * terminated by AV_PIX_FMT_NONE. Can be NULL if this information is + * not known. + */ + enum AVPixelFormat *valid_sw_formats; + + /** + * The minimum size of frames in this hw_frames_ctx. + * (Zero if not known.) + */ + int min_width; + int min_height; + + /** + * The maximum size of frames in this hw_frames_ctx. + * (INT_MAX if not known / no limit.) + */ + int max_width; + int max_height; +} AVHWFramesConstraints; + +/** + * Allocate a HW-specific configuration structure for a given HW device. + * After use, the user must free all members as required by the specific + * hardware structure being used, then free the structure itself with + * av_free(). + * + * @param device_ctx a reference to the associated AVHWDeviceContext. + * @return The newly created HW-specific configuration structure on + * success or NULL on failure. + */ +void *av_hwdevice_hwconfig_alloc(AVBufferRef *device_ctx); + +/** + * Get the constraints on HW frames given a device and the HW-specific + * configuration to be used with that device. If no HW-specific + * configuration is provided, returns the maximum possible capabilities + * of the device. + * + * @param ref a reference to the associated AVHWDeviceContext. + * @param hwconfig a filled HW-specific configuration structure, or NULL + * to return the maximum possible capabilities of the device. + * @return AVHWFramesConstraints structure describing the constraints + * on the device, or NULL if not available. + */ +AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, + const void *hwconfig); + +/** + * Free an AVHWFrameConstraints structure. + * + * @param constraints The (filled or unfilled) AVHWFrameConstraints structure. + */ +void av_hwframe_constraints_free(AVHWFramesConstraints **constraints); + + +/** + * Flags to apply to frame mappings. + */ +enum { + /** + * The mapping must be readable. + */ + AV_HWFRAME_MAP_READ = 1 << 0, + /** + * The mapping must be writeable. + */ + AV_HWFRAME_MAP_WRITE = 1 << 1, + /** + * The mapped frame will be overwritten completely in subsequent + * operations, so the current frame data need not be loaded. Any values + * which are not overwritten are unspecified. + */ + AV_HWFRAME_MAP_OVERWRITE = 1 << 2, + /** + * The mapping must be direct. That is, there must not be any copying in + * the map or unmap steps. Note that performance of direct mappings may + * be much lower than normal memory. + */ + AV_HWFRAME_MAP_DIRECT = 1 << 3, +}; + +/** + * Map a hardware frame. + * + * This has a number of different possible effects, depending on the format + * and origin of the src and dst frames. On input, src should be a usable + * frame with valid buffers and dst should be blank (typically as just created + * by av_frame_alloc()). src should have an associated hwframe context, and + * dst may optionally have a format and associated hwframe context. + * + * If src was created by mapping a frame from the hwframe context of dst, + * then this function undoes the mapping - dst is replaced by a reference to + * the frame that src was originally mapped from. + * + * If both src and dst have an associated hwframe context, then this function + * attempts to map the src frame from its hardware context to that of dst and + * then fill dst with appropriate data to be usable there. This will only be + * possible if the hwframe contexts and associated devices are compatible - + * given compatible devices, av_hwframe_ctx_create_derived() can be used to + * create a hwframe context for dst in which mapping should be possible. + * + * If src has a hwframe context but dst does not, then the src frame is + * mapped to normal memory and should thereafter be usable as a normal frame. + * If the format is set on dst, then the mapping will attempt to create dst + * with that format and fail if it is not possible. If format is unset (is + * AV_PIX_FMT_NONE) then dst will be mapped with whatever the most appropriate + * format to use is (probably the sw_format of the src hwframe context). + * + * A return value of AVERROR(ENOSYS) indicates that the mapping is not + * possible with the given arguments and hwframe setup, while other return + * values indicate that it failed somehow. + * + * @param dst Destination frame, to contain the mapping. + * @param src Source frame, to be mapped. + * @param flags Some combination of AV_HWFRAME_MAP_* flags. + * @return Zero on success, negative AVERROR code on failure. + */ +int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags); + + +/** + * Create and initialise an AVHWFramesContext as a mapping of another existing + * AVHWFramesContext on a different device. + * + * av_hwframe_ctx_init() should not be called after this. + * + * @param derived_frame_ctx On success, a reference to the newly created + * AVHWFramesContext. + * @param derived_device_ctx A reference to the device to create the new + * AVHWFramesContext on. + * @param source_frame_ctx A reference to an existing AVHWFramesContext + * which will be mapped to the derived context. + * @param flags Some combination of AV_HWFRAME_MAP_* flags, defining the + * mapping parameters to apply to frames which are allocated + * in the derived device. + * @return Zero on success, negative AVERROR code on failure. + */ +int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx, + enum AVPixelFormat format, + AVBufferRef *derived_device_ctx, + AVBufferRef *source_frame_ctx, + int flags); + +#endif /* AVUTIL_HWCONTEXT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda.c new file mode 100644 index 0000000000..cca39e9fc7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda.c @@ -0,0 +1,381 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "buffer.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_internal.h" +#include "hwcontext_cuda_internal.h" +#include "cuda_check.h" +#include "mem.h" +#include "pixdesc.h" +#include "pixfmt.h" +#include "imgutils.h" + +#define CUDA_FRAME_ALIGNMENT 256 + +typedef struct CUDAFramesContext { + int shift_width, shift_height; +} CUDAFramesContext; + +static const enum AVPixelFormat supported_formats[] = { + AV_PIX_FMT_NV12, + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_P010, + AV_PIX_FMT_P016, + AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_0RGB32, + AV_PIX_FMT_0BGR32, +}; + +#define CHECK_CU(x) FF_CUDA_CHECK_DL(device_ctx, cu, x) + +static int cuda_frames_get_constraints(AVHWDeviceContext *ctx, + const void *hwconfig, + AVHWFramesConstraints *constraints) +{ + int i; + + constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1, + sizeof(*constraints->valid_sw_formats)); + if (!constraints->valid_sw_formats) + return AVERROR(ENOMEM); + + for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) + constraints->valid_sw_formats[i] = supported_formats[i]; + constraints->valid_sw_formats[FF_ARRAY_ELEMS(supported_formats)] = AV_PIX_FMT_NONE; + + constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); + if (!constraints->valid_hw_formats) + return AVERROR(ENOMEM); + + constraints->valid_hw_formats[0] = AV_PIX_FMT_CUDA; + constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; + + return 0; +} + +static void cuda_buffer_free(void *opaque, uint8_t *data) +{ + AVHWFramesContext *ctx = opaque; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; + + CUcontext dummy; + + CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); + + CHECK_CU(cu->cuMemFree((CUdeviceptr)data)); + + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); +} + +static AVBufferRef *cuda_pool_alloc(void *opaque, int size) +{ + AVHWFramesContext *ctx = opaque; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; + + AVBufferRef *ret = NULL; + CUcontext dummy = NULL; + CUdeviceptr data; + int err; + + err = CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); + if (err < 0) + return NULL; + + err = CHECK_CU(cu->cuMemAlloc(&data, size)); + if (err < 0) + goto fail; + + ret = av_buffer_create((uint8_t*)data, size, cuda_buffer_free, ctx, 0); + if (!ret) { + CHECK_CU(cu->cuMemFree(data)); + goto fail; + } + +fail: + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); + return ret; +} + +static int cuda_frames_init(AVHWFramesContext *ctx) +{ + CUDAFramesContext *priv = ctx->internal->priv; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { + if (ctx->sw_format == supported_formats[i]) + break; + } + if (i == FF_ARRAY_ELEMS(supported_formats)) { + av_log(ctx, AV_LOG_ERROR, "Pixel format '%s' is not supported\n", + av_get_pix_fmt_name(ctx->sw_format)); + return AVERROR(ENOSYS); + } + + av_pix_fmt_get_chroma_sub_sample(ctx->sw_format, &priv->shift_width, &priv->shift_height); + + if (!ctx->pool) { + int size = av_image_get_buffer_size(ctx->sw_format, ctx->width, ctx->height, CUDA_FRAME_ALIGNMENT); + if (size < 0) + return size; + + ctx->internal->pool_internal = av_buffer_pool_init2(size, ctx, cuda_pool_alloc, NULL); + if (!ctx->internal->pool_internal) + return AVERROR(ENOMEM); + } + + return 0; +} + +static int cuda_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) +{ + int res; + + frame->buf[0] = av_buffer_pool_get(ctx->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + + res = av_image_fill_arrays(frame->data, frame->linesize, frame->buf[0]->data, + ctx->sw_format, ctx->width, ctx->height, CUDA_FRAME_ALIGNMENT); + if (res < 0) + return res; + + // YUV420P is a special case. + // Nvenc expects the U/V planes in swapped order from how ffmpeg expects them, also chroma is half-aligned + if (ctx->sw_format == AV_PIX_FMT_YUV420P) { + frame->linesize[1] = frame->linesize[2] = frame->linesize[0] / 2; + frame->data[2] = frame->data[1]; + frame->data[1] = frame->data[2] + frame->linesize[2] * ctx->height / 2; + } + + frame->format = AV_PIX_FMT_CUDA; + frame->width = ctx->width; + frame->height = ctx->height; + + return 0; +} + +static int cuda_transfer_get_formats(AVHWFramesContext *ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ + enum AVPixelFormat *fmts; + + fmts = av_malloc_array(2, sizeof(*fmts)); + if (!fmts) + return AVERROR(ENOMEM); + + fmts[0] = ctx->sw_format; + fmts[1] = AV_PIX_FMT_NONE; + + *formats = fmts; + + return 0; +} + +static int cuda_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src) +{ + CUDAFramesContext *priv = ctx->internal->priv; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; + + CUcontext dummy; + int i, ret; + + ret = CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); + if (ret < 0) + return ret; + + for (i = 0; i < FF_ARRAY_ELEMS(src->data) && src->data[i]; i++) { + CUDA_MEMCPY2D cpy = { + .srcMemoryType = CU_MEMORYTYPE_DEVICE, + .dstMemoryType = CU_MEMORYTYPE_HOST, + .srcDevice = (CUdeviceptr)src->data[i], + .dstHost = dst->data[i], + .srcPitch = src->linesize[i], + .dstPitch = dst->linesize[i], + .WidthInBytes = FFMIN(src->linesize[i], dst->linesize[i]), + .Height = src->height >> (i ? priv->shift_height : 0), + }; + + ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, hwctx->stream)); + if (ret < 0) + goto exit; + } + + ret = CHECK_CU(cu->cuStreamSynchronize(hwctx->stream)); + if (ret < 0) + goto exit; + +exit: + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); + + return 0; +} + +static int cuda_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src) +{ + CUDAFramesContext *priv = ctx->internal->priv; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; + + CUcontext dummy; + int i, ret; + + ret = CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); + if (ret < 0) + return ret; + + for (i = 0; i < FF_ARRAY_ELEMS(src->data) && src->data[i]; i++) { + CUDA_MEMCPY2D cpy = { + .srcMemoryType = CU_MEMORYTYPE_HOST, + .dstMemoryType = CU_MEMORYTYPE_DEVICE, + .srcHost = src->data[i], + .dstDevice = (CUdeviceptr)dst->data[i], + .srcPitch = src->linesize[i], + .dstPitch = dst->linesize[i], + .WidthInBytes = FFMIN(src->linesize[i], dst->linesize[i]), + .Height = src->height >> (i ? priv->shift_height : 0), + }; + + ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, hwctx->stream)); + if (ret < 0) + goto exit; + } + +exit: + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); + + return 0; +} + +static void cuda_device_uninit(AVHWDeviceContext *device_ctx) +{ + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + + if (hwctx->internal) { + CudaFunctions *cu = hwctx->internal->cuda_dl; + if (hwctx->internal->is_allocated && hwctx->cuda_ctx) { + CHECK_CU(cu->cuCtxDestroy(hwctx->cuda_ctx)); + hwctx->cuda_ctx = NULL; + } + cuda_free_functions(&hwctx->internal->cuda_dl); + } + + av_freep(&hwctx->internal); +} + +static int cuda_device_init(AVHWDeviceContext *ctx) +{ + AVCUDADeviceContext *hwctx = ctx->hwctx; + int ret; + + if (!hwctx->internal) { + hwctx->internal = av_mallocz(sizeof(*hwctx->internal)); + if (!hwctx->internal) + return AVERROR(ENOMEM); + } + + if (!hwctx->internal->cuda_dl) { + ret = cuda_load_functions(&hwctx->internal->cuda_dl, ctx); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Could not dynamically load CUDA\n"); + goto error; + } + } + + return 0; + +error: + cuda_device_uninit(ctx); + return ret; +} + +static int cuda_device_create(AVHWDeviceContext *device_ctx, + const char *device, + AVDictionary *opts, int flags) +{ + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu; + CUdevice cu_device; + CUcontext dummy; + int ret, device_idx = 0; + + if (device) + device_idx = strtol(device, NULL, 0); + + if (cuda_device_init(device_ctx) < 0) + goto error; + + cu = hwctx->internal->cuda_dl; + + ret = CHECK_CU(cu->cuInit(0)); + if (ret < 0) + goto error; + + ret = CHECK_CU(cu->cuDeviceGet(&cu_device, device_idx)); + if (ret < 0) + goto error; + + ret = CHECK_CU(cu->cuCtxCreate(&hwctx->cuda_ctx, CU_CTX_SCHED_BLOCKING_SYNC, cu_device)); + if (ret < 0) + goto error; + + // Setting stream to NULL will make functions automatically use the default CUstream + hwctx->stream = NULL; + + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); + + hwctx->internal->is_allocated = 1; + + return 0; + +error: + cuda_device_uninit(device_ctx); + return AVERROR_UNKNOWN; +} + +const HWContextType ff_hwcontext_type_cuda = { + .type = AV_HWDEVICE_TYPE_CUDA, + .name = "CUDA", + + .device_hwctx_size = sizeof(AVCUDADeviceContext), + .frames_priv_size = sizeof(CUDAFramesContext), + + .device_create = cuda_device_create, + .device_init = cuda_device_init, + .device_uninit = cuda_device_uninit, + .frames_get_constraints = cuda_frames_get_constraints, + .frames_init = cuda_frames_init, + .frames_get_buffer = cuda_get_buffer, + .transfer_get_formats = cuda_transfer_get_formats, + .transfer_data_to = cuda_transfer_data_to, + .transfer_data_from = cuda_transfer_data_from, + + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, AV_PIX_FMT_NONE }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda.h new file mode 100644 index 0000000000..81a0552cab --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda.h @@ -0,0 +1,52 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef AVUTIL_HWCONTEXT_CUDA_H +#define AVUTIL_HWCONTEXT_CUDA_H + +#ifndef CUDA_VERSION +#include +#endif + +#include "pixfmt.h" + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_CUDA. + * + * This API supports dynamic frame pools. AVHWFramesContext.pool must return + * AVBufferRefs whose data pointer is a CUdeviceptr. + */ + +typedef struct AVCUDADeviceContextInternal AVCUDADeviceContextInternal; + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVCUDADeviceContext { + CUcontext cuda_ctx; + CUstream stream; + AVCUDADeviceContextInternal *internal; +} AVCUDADeviceContext; + +/** + * AVHWFramesContext.hwctx is currently not used + */ + +#endif /* AVUTIL_HWCONTEXT_CUDA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda_internal.h new file mode 100644 index 0000000000..e1bc6ff350 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_cuda_internal.h @@ -0,0 +1,37 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef AVUTIL_HWCONTEXT_CUDA_INTERNAL_H +#define AVUTIL_HWCONTEXT_CUDA_INTERNAL_H + +#include "compat/cuda/dynlink_loader.h" +#include "hwcontext_cuda.h" + +/** + * @file + * FFmpeg internal API for CUDA. + */ + +struct AVCUDADeviceContextInternal { + CudaFunctions *cuda_dl; + int is_allocated; +}; + +#endif /* AVUTIL_HWCONTEXT_CUDA_INTERNAL_H */ + diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_d3d11va.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_d3d11va.c new file mode 100644 index 0000000000..6670c47579 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_d3d11va.c @@ -0,0 +1,615 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include + +#define COBJMACROS + +#include +#include +#include + +#if HAVE_DXGIDEBUG_H +#include +#endif + +#include "avassert.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_d3d11va.h" +#include "hwcontext_internal.h" +#include "imgutils.h" +#include "pixdesc.h" +#include "pixfmt.h" +#include "thread.h" + +typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); + +static AVOnce functions_loaded = AV_ONCE_INIT; + +static PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory; +static PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice; + +static av_cold void load_functions(void) +{ +#if !HAVE_UWP + // We let these "leak" - this is fine, as unloading has no great benefit, and + // Windows will mark a DLL as loaded forever if its internal refcount overflows + // from too many LoadLibrary calls. + HANDLE d3dlib, dxgilib; + + d3dlib = LoadLibrary("d3d11.dll"); + dxgilib = LoadLibrary("dxgi.dll"); + if (!d3dlib || !dxgilib) + return; + + mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) GetProcAddress(d3dlib, "D3D11CreateDevice"); + mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) GetProcAddress(dxgilib, "CreateDXGIFactory"); +#else + // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't available, + // only CreateDXGIFactory1 + mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE) D3D11CreateDevice; + mCreateDXGIFactory = (PFN_CREATE_DXGI_FACTORY) CreateDXGIFactory1; +#endif +} + +typedef struct D3D11VAFramesContext { + int nb_surfaces_used; + + DXGI_FORMAT format; + + ID3D11Texture2D *staging_texture; +} D3D11VAFramesContext; + +static const struct { + DXGI_FORMAT d3d_format; + enum AVPixelFormat pix_fmt; +} supported_formats[] = { + { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 }, + { DXGI_FORMAT_P010, AV_PIX_FMT_P010 }, + // Special opaque formats. The pix_fmt is merely a place holder, as the + // opaque format cannot be accessed directly. + { DXGI_FORMAT_420_OPAQUE, AV_PIX_FMT_YUV420P }, +}; + +static void d3d11va_default_lock(void *ctx) +{ + WaitForSingleObjectEx(ctx, INFINITE, FALSE); +} + +static void d3d11va_default_unlock(void *ctx) +{ + ReleaseMutex(ctx); +} + +static void d3d11va_frames_uninit(AVHWFramesContext *ctx) +{ + AVD3D11VAFramesContext *frames_hwctx = ctx->hwctx; + D3D11VAFramesContext *s = ctx->internal->priv; + + if (frames_hwctx->texture) + ID3D11Texture2D_Release(frames_hwctx->texture); + frames_hwctx->texture = NULL; + + if (s->staging_texture) + ID3D11Texture2D_Release(s->staging_texture); + s->staging_texture = NULL; +} + +static int d3d11va_frames_get_constraints(AVHWDeviceContext *ctx, + const void *hwconfig, + AVHWFramesConstraints *constraints) +{ + AVD3D11VADeviceContext *device_hwctx = ctx->hwctx; + int nb_sw_formats = 0; + HRESULT hr; + int i; + + constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1, + sizeof(*constraints->valid_sw_formats)); + if (!constraints->valid_sw_formats) + return AVERROR(ENOMEM); + + for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { + UINT format_support = 0; + hr = ID3D11Device_CheckFormatSupport(device_hwctx->device, supported_formats[i].d3d_format, &format_support); + if (SUCCEEDED(hr) && (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D)) + constraints->valid_sw_formats[nb_sw_formats++] = supported_formats[i].pix_fmt; + } + constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE; + + constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); + if (!constraints->valid_hw_formats) + return AVERROR(ENOMEM); + + constraints->valid_hw_formats[0] = AV_PIX_FMT_D3D11; + constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; + + return 0; +} + +static void free_texture(void *opaque, uint8_t *data) +{ + ID3D11Texture2D_Release((ID3D11Texture2D *)opaque); + av_free(data); +} + +static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index) +{ + AVBufferRef *buf; + AVD3D11FrameDescriptor *desc = av_mallocz(sizeof(*desc)); + if (!desc) { + ID3D11Texture2D_Release(tex); + return NULL; + } + + desc->texture = tex; + desc->index = index; + + buf = av_buffer_create((uint8_t *)desc, sizeof(desc), free_texture, tex, 0); + if (!buf) { + ID3D11Texture2D_Release(tex); + av_free(desc); + return NULL; + } + + return buf; +} + +static AVBufferRef *d3d11va_alloc_single(AVHWFramesContext *ctx) +{ + D3D11VAFramesContext *s = ctx->internal->priv; + AVD3D11VAFramesContext *hwctx = ctx->hwctx; + AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; + HRESULT hr; + ID3D11Texture2D *tex; + D3D11_TEXTURE2D_DESC texDesc = { + .Width = ctx->width, + .Height = ctx->height, + .MipLevels = 1, + .Format = s->format, + .SampleDesc = { .Count = 1 }, + .ArraySize = 1, + .Usage = D3D11_USAGE_DEFAULT, + .BindFlags = hwctx->BindFlags, + .MiscFlags = hwctx->MiscFlags, + }; + + hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &tex); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr); + return NULL; + } + + return wrap_texture_buf(tex, 0); +} + +static AVBufferRef *d3d11va_pool_alloc(void *opaque, int size) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; + D3D11VAFramesContext *s = ctx->internal->priv; + AVD3D11VAFramesContext *hwctx = ctx->hwctx; + D3D11_TEXTURE2D_DESC texDesc; + + if (!hwctx->texture) + return d3d11va_alloc_single(ctx); + + ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc); + + if (s->nb_surfaces_used >= texDesc.ArraySize) { + av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n"); + return NULL; + } + + ID3D11Texture2D_AddRef(hwctx->texture); + return wrap_texture_buf(hwctx->texture, s->nb_surfaces_used++); +} + +static int d3d11va_frames_init(AVHWFramesContext *ctx) +{ + AVD3D11VAFramesContext *hwctx = ctx->hwctx; + AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; + D3D11VAFramesContext *s = ctx->internal->priv; + + int i; + HRESULT hr; + D3D11_TEXTURE2D_DESC texDesc; + + for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { + if (ctx->sw_format == supported_formats[i].pix_fmt) { + s->format = supported_formats[i].d3d_format; + break; + } + } + if (i == FF_ARRAY_ELEMS(supported_formats)) { + av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n", + av_get_pix_fmt_name(ctx->sw_format)); + return AVERROR(EINVAL); + } + + texDesc = (D3D11_TEXTURE2D_DESC){ + .Width = ctx->width, + .Height = ctx->height, + .MipLevels = 1, + .Format = s->format, + .SampleDesc = { .Count = 1 }, + .ArraySize = ctx->initial_pool_size, + .Usage = D3D11_USAGE_DEFAULT, + .BindFlags = hwctx->BindFlags, + .MiscFlags = hwctx->MiscFlags, + }; + + if (hwctx->texture) { + D3D11_TEXTURE2D_DESC texDesc2; + ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc2); + + if (texDesc.Width != texDesc2.Width || + texDesc.Height != texDesc2.Height || + texDesc.Format != texDesc2.Format) { + av_log(ctx, AV_LOG_ERROR, "User-provided texture has mismatching parameters\n"); + return AVERROR(EINVAL); + } + } else if (texDesc.ArraySize > 0) { + hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &hwctx->texture); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Could not create the texture (%lx)\n", (long)hr); + return AVERROR_UNKNOWN; + } + } + + ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor), + ctx, d3d11va_pool_alloc, NULL); + if (!ctx->internal->pool_internal) + return AVERROR(ENOMEM); + + return 0; +} + +static int d3d11va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) +{ + AVD3D11FrameDescriptor *desc; + + frame->buf[0] = av_buffer_pool_get(ctx->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + + desc = (AVD3D11FrameDescriptor *)frame->buf[0]->data; + + frame->data[0] = (uint8_t *)desc->texture; + frame->data[1] = (uint8_t *)desc->index; + frame->format = AV_PIX_FMT_D3D11; + frame->width = ctx->width; + frame->height = ctx->height; + + return 0; +} + +static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ + D3D11VAFramesContext *s = ctx->internal->priv; + enum AVPixelFormat *fmts; + + fmts = av_malloc_array(2, sizeof(*fmts)); + if (!fmts) + return AVERROR(ENOMEM); + + fmts[0] = ctx->sw_format; + fmts[1] = AV_PIX_FMT_NONE; + + // Don't signal support for opaque formats. Actual access would fail. + if (s->format == DXGI_FORMAT_420_OPAQUE) + fmts[0] = AV_PIX_FMT_NONE; + + *formats = fmts; + + return 0; +} + +static int d3d11va_create_staging_texture(AVHWFramesContext *ctx) +{ + AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; + D3D11VAFramesContext *s = ctx->internal->priv; + HRESULT hr; + D3D11_TEXTURE2D_DESC texDesc = { + .Width = ctx->width, + .Height = ctx->height, + .MipLevels = 1, + .Format = s->format, + .SampleDesc = { .Count = 1 }, + .ArraySize = 1, + .Usage = D3D11_USAGE_STAGING, + .CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE, + }; + + hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &s->staging_texture); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture (%lx)\n", (long)hr); + return AVERROR_UNKNOWN; + } + + return 0; +} + +static void fill_texture_ptrs(uint8_t *data[4], int linesize[4], + AVHWFramesContext *ctx, + D3D11_TEXTURE2D_DESC *desc, + D3D11_MAPPED_SUBRESOURCE *map) +{ + int i; + + for (i = 0; i < 4; i++) + linesize[i] = map->RowPitch; + + av_image_fill_pointers(data, ctx->sw_format, desc->Height, + (uint8_t*)map->pData, linesize); +} + +static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src) +{ + AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx; + D3D11VAFramesContext *s = ctx->internal->priv; + int download = src->format == AV_PIX_FMT_D3D11; + const AVFrame *frame = download ? src : dst; + const AVFrame *other = download ? dst : src; + // (The interface types are compatible.) + ID3D11Resource *texture = (ID3D11Resource *)(ID3D11Texture2D *)frame->data[0]; + int index = (intptr_t)frame->data[1]; + ID3D11Resource *staging; + int w = FFMIN(dst->width, src->width); + int h = FFMIN(dst->height, src->height); + uint8_t *map_data[4]; + int map_linesize[4]; + D3D11_TEXTURE2D_DESC desc; + D3D11_MAPPED_SUBRESOURCE map; + HRESULT hr; + + if (frame->hw_frames_ctx->data != (uint8_t *)ctx || other->format != ctx->sw_format) + return AVERROR(EINVAL); + + device_hwctx->lock(device_hwctx->lock_ctx); + + if (!s->staging_texture) { + int res = d3d11va_create_staging_texture(ctx); + if (res < 0) + return res; + } + + staging = (ID3D11Resource *)s->staging_texture; + + ID3D11Texture2D_GetDesc(s->staging_texture, &desc); + + if (download) { + ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context, + staging, 0, 0, 0, 0, + texture, index, NULL); + + hr = ID3D11DeviceContext_Map(device_hwctx->device_context, + staging, 0, D3D11_MAP_READ, 0, &map); + if (FAILED(hr)) + goto map_failed; + + fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map); + + av_image_copy(dst->data, dst->linesize, (const uint8_t **)map_data, map_linesize, + ctx->sw_format, w, h); + + ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0); + } else { + hr = ID3D11DeviceContext_Map(device_hwctx->device_context, + staging, 0, D3D11_MAP_WRITE, 0, &map); + if (FAILED(hr)) + goto map_failed; + + fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map); + + av_image_copy(map_data, map_linesize, (const uint8_t **)src->data, src->linesize, + ctx->sw_format, w, h); + + ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0); + + ID3D11DeviceContext_CopySubresourceRegion(device_hwctx->device_context, + texture, index, 0, 0, 0, + staging, 0, NULL); + } + + device_hwctx->unlock(device_hwctx->lock_ctx); + return 0; + +map_failed: + av_log(ctx, AV_LOG_ERROR, "Unable to lock D3D11VA surface (%lx)\n", (long)hr); + device_hwctx->unlock(device_hwctx->lock_ctx); + return AVERROR_UNKNOWN; +} + +static int d3d11va_device_init(AVHWDeviceContext *hwdev) +{ + AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx; + HRESULT hr; + + if (!device_hwctx->lock) { + device_hwctx->lock_ctx = CreateMutex(NULL, 0, NULL); + if (device_hwctx->lock_ctx == INVALID_HANDLE_VALUE) { + av_log(NULL, AV_LOG_ERROR, "Failed to create a mutex\n"); + return AVERROR(EINVAL); + } + device_hwctx->lock = d3d11va_default_lock; + device_hwctx->unlock = d3d11va_default_unlock; + } + + if (!device_hwctx->device_context) { + ID3D11Device_GetImmediateContext(device_hwctx->device, &device_hwctx->device_context); + if (!device_hwctx->device_context) + return AVERROR_UNKNOWN; + } + + if (!device_hwctx->video_device) { + hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device, &IID_ID3D11VideoDevice, + (void **)&device_hwctx->video_device); + if (FAILED(hr)) + return AVERROR_UNKNOWN; + } + + if (!device_hwctx->video_context) { + hr = ID3D11DeviceContext_QueryInterface(device_hwctx->device_context, &IID_ID3D11VideoContext, + (void **)&device_hwctx->video_context); + if (FAILED(hr)) + return AVERROR_UNKNOWN; + } + + return 0; +} + +static void d3d11va_device_uninit(AVHWDeviceContext *hwdev) +{ + AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx; + + if (device_hwctx->device) { + ID3D11Device_Release(device_hwctx->device); + device_hwctx->device = NULL; + } + + if (device_hwctx->device_context) { + ID3D11DeviceContext_Release(device_hwctx->device_context); + device_hwctx->device_context = NULL; + } + + if (device_hwctx->video_device) { + ID3D11VideoDevice_Release(device_hwctx->video_device); + device_hwctx->video_device = NULL; + } + + if (device_hwctx->video_context) { + ID3D11VideoContext_Release(device_hwctx->video_context); + device_hwctx->video_context = NULL; + } + + if (device_hwctx->lock == d3d11va_default_lock) { + CloseHandle(device_hwctx->lock_ctx); + device_hwctx->lock_ctx = INVALID_HANDLE_VALUE; + device_hwctx->lock = NULL; + } +} + +static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + AVD3D11VADeviceContext *device_hwctx = ctx->hwctx; + + HRESULT hr; + IDXGIAdapter *pAdapter = NULL; + ID3D10Multithread *pMultithread; + UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT; + int is_debug = !!av_dict_get(opts, "debug", NULL, 0); + int ret; + + // (On UWP we can't check this.) +#if !HAVE_UWP + if (!LoadLibrary("d3d11_1sdklayers.dll")) + is_debug = 0; +#endif + + if (is_debug) + creationFlags |= D3D11_CREATE_DEVICE_DEBUG; + + if ((ret = ff_thread_once(&functions_loaded, load_functions)) != 0) + return AVERROR_UNKNOWN; + if (!mD3D11CreateDevice || !mCreateDXGIFactory) { + av_log(ctx, AV_LOG_ERROR, "Failed to load D3D11 library or its functions\n"); + return AVERROR_UNKNOWN; + } + + if (device) { + IDXGIFactory2 *pDXGIFactory; + hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory); + if (SUCCEEDED(hr)) { + int adapter = atoi(device); + if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter, &pAdapter))) + pAdapter = NULL; + IDXGIFactory2_Release(pDXGIFactory); + } + } + + if (pAdapter) { + DXGI_ADAPTER_DESC desc; + hr = IDXGIAdapter2_GetDesc(pAdapter, &desc); + if (!FAILED(hr)) { + av_log(ctx, AV_LOG_INFO, "Using device %04x:%04x (%ls).\n", + desc.VendorId, desc.DeviceId, desc.Description); + } + } + + hr = mD3D11CreateDevice(pAdapter, pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, NULL, creationFlags, NULL, 0, + D3D11_SDK_VERSION, &device_hwctx->device, NULL, NULL); + if (pAdapter) + IDXGIAdapter_Release(pAdapter); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device (%lx)\n", (long)hr); + return AVERROR_UNKNOWN; + } + + hr = ID3D11Device_QueryInterface(device_hwctx->device, &IID_ID3D10Multithread, (void **)&pMultithread); + if (SUCCEEDED(hr)) { + ID3D10Multithread_SetMultithreadProtected(pMultithread, TRUE); + ID3D10Multithread_Release(pMultithread); + } + +#if !HAVE_UWP && HAVE_DXGIDEBUG_H + if (is_debug) { + HANDLE dxgidebug_dll = LoadLibrary("dxgidebug.dll"); + if (dxgidebug_dll) { + HRESULT (WINAPI * pf_DXGIGetDebugInterface)(const GUID *riid, void **ppDebug) + = (void *)GetProcAddress(dxgidebug_dll, "DXGIGetDebugInterface"); + if (pf_DXGIGetDebugInterface) { + IDXGIDebug *dxgi_debug = NULL; + hr = pf_DXGIGetDebugInterface(&IID_IDXGIDebug, (void**)&dxgi_debug); + if (SUCCEEDED(hr) && dxgi_debug) + IDXGIDebug_ReportLiveObjects(dxgi_debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL); + } + } + } +#endif + + return 0; +} + +const HWContextType ff_hwcontext_type_d3d11va = { + .type = AV_HWDEVICE_TYPE_D3D11VA, + .name = "D3D11VA", + + .device_hwctx_size = sizeof(AVD3D11VADeviceContext), + .frames_hwctx_size = sizeof(AVD3D11VAFramesContext), + .frames_priv_size = sizeof(D3D11VAFramesContext), + + .device_create = d3d11va_device_create, + .device_init = d3d11va_device_init, + .device_uninit = d3d11va_device_uninit, + .frames_get_constraints = d3d11va_frames_get_constraints, + .frames_init = d3d11va_frames_init, + .frames_uninit = d3d11va_frames_uninit, + .frames_get_buffer = d3d11va_get_buffer, + .transfer_get_formats = d3d11va_transfer_get_formats, + .transfer_data_to = d3d11va_transfer_data, + .transfer_data_from = d3d11va_transfer_data, + + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_D3D11, AV_PIX_FMT_NONE }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_d3d11va.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_d3d11va.h new file mode 100644 index 0000000000..9f91e9b1b6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_d3d11va.h @@ -0,0 +1,169 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_D3D11VA_H +#define AVUTIL_HWCONTEXT_D3D11VA_H + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_D3D11VA. + * + * The default pool implementation will be fixed-size if initial_pool_size is + * set (and allocate elements from an array texture). Otherwise it will allocate + * individual textures. Be aware that decoding requires a single array texture. + * + * Using sw_format==AV_PIX_FMT_YUV420P has special semantics, and maps to + * DXGI_FORMAT_420_OPAQUE. av_hwframe_transfer_data() is not supported for + * this format. Refer to MSDN for details. + * + * av_hwdevice_ctx_create() for this device type supports a key named "debug" + * for the AVDictionary entry. If this is set to any value, the device creation + * code will try to load various supported D3D debugging layers. + */ + +#include +#include + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVD3D11VADeviceContext { + /** + * Device used for texture creation and access. This can also be used to + * set the libavcodec decoding device. + * + * Must be set by the user. This is the only mandatory field - the other + * device context fields are set from this and are available for convenience. + * + * Deallocating the AVHWDeviceContext will always release this interface, + * and it does not matter whether it was user-allocated. + */ + ID3D11Device *device; + + /** + * If unset, this will be set from the device field on init. + * + * Deallocating the AVHWDeviceContext will always release this interface, + * and it does not matter whether it was user-allocated. + */ + ID3D11DeviceContext *device_context; + + /** + * If unset, this will be set from the device field on init. + * + * Deallocating the AVHWDeviceContext will always release this interface, + * and it does not matter whether it was user-allocated. + */ + ID3D11VideoDevice *video_device; + + /** + * If unset, this will be set from the device_context field on init. + * + * Deallocating the AVHWDeviceContext will always release this interface, + * and it does not matter whether it was user-allocated. + */ + ID3D11VideoContext *video_context; + + /** + * Callbacks for locking. They protect accesses to device_context and + * video_context calls. They also protect access to the internal staging + * texture (for av_hwframe_transfer_data() calls). They do NOT protect + * access to hwcontext or decoder state in general. + * + * If unset on init, the hwcontext implementation will set them to use an + * internal mutex. + * + * The underlying lock must be recursive. lock_ctx is for free use by the + * locking implementation. + */ + void (*lock)(void *lock_ctx); + void (*unlock)(void *lock_ctx); + void *lock_ctx; +} AVD3D11VADeviceContext; + +/** + * D3D11 frame descriptor for pool allocation. + * + * In user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer pointing at an object of this type describing the + * planes of the frame. + * + * This has no use outside of custom allocation, and AVFrame AVBufferRef do not + * necessarily point to an instance of this struct. + */ +typedef struct AVD3D11FrameDescriptor { + /** + * The texture in which the frame is located. The reference count is + * managed by the AVBufferRef, and destroying the reference will release + * the interface. + * + * Normally stored in AVFrame.data[0]. + */ + ID3D11Texture2D *texture; + + /** + * The index into the array texture element representing the frame, or 0 + * if the texture is not an array texture. + * + * Normally stored in AVFrame.data[1] (cast from intptr_t). + */ + intptr_t index; +} AVD3D11FrameDescriptor; + +/** + * This struct is allocated as AVHWFramesContext.hwctx + */ +typedef struct AVD3D11VAFramesContext { + /** + * The canonical texture used for pool allocation. If this is set to NULL + * on init, the hwframes implementation will allocate and set an array + * texture if initial_pool_size > 0. + * + * The only situation when the API user should set this is: + * - the user wants to do manual pool allocation (setting + * AVHWFramesContext.pool), instead of letting AVHWFramesContext + * allocate the pool + * - of an array texture + * - and wants it to use it for decoding + * - this has to be done before calling av_hwframe_ctx_init() + * + * Deallocating the AVHWFramesContext will always release this interface, + * and it does not matter whether it was user-allocated. + * + * This is in particular used by the libavcodec D3D11VA hwaccel, which + * requires a single array texture. It will create ID3D11VideoDecoderOutputView + * objects for each array texture element on decoder initialization. + */ + ID3D11Texture2D *texture; + + /** + * D3D11_TEXTURE2D_DESC.BindFlags used for texture creation. The user must + * at least set D3D11_BIND_DECODER if the frames context is to be used for + * video decoding. + * This field is ignored/invalid if a user-allocated texture is provided. + */ + UINT BindFlags; + + /** + * D3D11_TEXTURE2D_DESC.MiscFlags used for texture creation. + * This field is ignored/invalid if a user-allocated texture is provided. + */ + UINT MiscFlags; +} AVD3D11VAFramesContext; + +#endif /* AVUTIL_HWCONTEXT_D3D11VA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_drm.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_drm.c new file mode 100644 index 0000000000..32cbde82eb --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_drm.c @@ -0,0 +1,289 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include +#include + +#include "avassert.h" +#include "hwcontext.h" +#include "hwcontext_drm.h" +#include "hwcontext_internal.h" +#include "imgutils.h" + + +static void drm_device_free(AVHWDeviceContext *hwdev) +{ + AVDRMDeviceContext *hwctx = hwdev->hwctx; + + close(hwctx->fd); +} + +static int drm_device_create(AVHWDeviceContext *hwdev, const char *device, + AVDictionary *opts, int flags) +{ + AVDRMDeviceContext *hwctx = hwdev->hwctx; + drmVersionPtr version; + + hwctx->fd = open(device, O_RDWR); + if (hwctx->fd < 0) + return AVERROR(errno); + + version = drmGetVersion(hwctx->fd); + if (!version) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get version information " + "from %s: probably not a DRM device?\n", device); + close(hwctx->fd); + return AVERROR(EINVAL); + } + + av_log(hwdev, AV_LOG_VERBOSE, "Opened DRM device %s: driver %s " + "version %d.%d.%d.\n", device, version->name, + version->version_major, version->version_minor, + version->version_patchlevel); + + drmFreeVersion(version); + + hwdev->free = &drm_device_free; + + return 0; +} + +static int drm_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) +{ + frame->buf[0] = av_buffer_pool_get(hwfc->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + + frame->data[0] = (uint8_t*)frame->buf[0]->data; + + frame->format = AV_PIX_FMT_DRM_PRIME; + frame->width = hwfc->width; + frame->height = hwfc->height; + + return 0; +} + +typedef struct DRMMapping { + // Address and length of each mmap()ed region. + int nb_regions; + void *address[AV_DRM_MAX_PLANES]; + size_t length[AV_DRM_MAX_PLANES]; +} DRMMapping; + +static void drm_unmap_frame(AVHWFramesContext *hwfc, + HWMapDescriptor *hwmap) +{ + DRMMapping *map = hwmap->priv; + int i; + + for (i = 0; i < map->nb_regions; i++) + munmap(map->address[i], map->length[i]); + + av_free(map); +} + +static int drm_map_frame(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src, int flags) +{ + const AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor*)src->data[0]; + DRMMapping *map; + int err, i, p, plane; + int mmap_prot; + void *addr; + + map = av_mallocz(sizeof(*map)); + if (!map) + return AVERROR(ENOMEM); + + mmap_prot = 0; + if (flags & AV_HWFRAME_MAP_READ) + mmap_prot |= PROT_READ; + if (flags & AV_HWFRAME_MAP_WRITE) + mmap_prot |= PROT_WRITE; + + av_assert0(desc->nb_objects <= AV_DRM_MAX_PLANES); + for (i = 0; i < desc->nb_objects; i++) { + addr = mmap(NULL, desc->objects[i].size, mmap_prot, MAP_SHARED, + desc->objects[i].fd, 0); + if (addr == MAP_FAILED) { + err = AVERROR(errno); + av_log(hwfc, AV_LOG_ERROR, "Failed to map DRM object %d to " + "memory: %d.\n", desc->objects[i].fd, errno); + goto fail; + } + + map->address[i] = addr; + map->length[i] = desc->objects[i].size; + } + map->nb_regions = i; + + plane = 0; + for (i = 0; i < desc->nb_layers; i++) { + const AVDRMLayerDescriptor *layer = &desc->layers[i]; + for (p = 0; p < layer->nb_planes; p++) { + dst->data[plane] = + (uint8_t*)map->address[layer->planes[p].object_index] + + layer->planes[p].offset; + dst->linesize[plane] = layer->planes[p].pitch; + ++plane; + } + } + av_assert0(plane <= AV_DRM_MAX_PLANES); + + dst->width = src->width; + dst->height = src->height; + + err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, + &drm_unmap_frame, map); + if (err < 0) + goto fail; + + return 0; + +fail: + for (i = 0; i < desc->nb_objects; i++) { + if (map->address[i]) + munmap(map->address[i], map->length[i]); + } + av_free(map); + return err; +} + +static int drm_transfer_get_formats(AVHWFramesContext *ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ + enum AVPixelFormat *pix_fmts; + + pix_fmts = av_malloc_array(2, sizeof(*pix_fmts)); + if (!pix_fmts) + return AVERROR(ENOMEM); + + pix_fmts[0] = ctx->sw_format; + pix_fmts[1] = AV_PIX_FMT_NONE; + + *formats = pix_fmts; + return 0; +} + +static int drm_transfer_data_from(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src) +{ + AVFrame *map; + int err; + + if (dst->width > hwfc->width || dst->height > hwfc->height) + return AVERROR(EINVAL); + + map = av_frame_alloc(); + if (!map) + return AVERROR(ENOMEM); + map->format = dst->format; + + err = drm_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ); + if (err) + goto fail; + + map->width = dst->width; + map->height = dst->height; + + err = av_frame_copy(dst, map); + if (err) + goto fail; + + err = 0; +fail: + av_frame_free(&map); + return err; +} + +static int drm_transfer_data_to(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src) +{ + AVFrame *map; + int err; + + if (src->width > hwfc->width || src->height > hwfc->height) + return AVERROR(EINVAL); + + map = av_frame_alloc(); + if (!map) + return AVERROR(ENOMEM); + map->format = src->format; + + err = drm_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | + AV_HWFRAME_MAP_OVERWRITE); + if (err) + goto fail; + + map->width = src->width; + map->height = src->height; + + err = av_frame_copy(map, src); + if (err) + goto fail; + + err = 0; +fail: + av_frame_free(&map); + return err; +} + +static int drm_map_from(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + int err; + + if (hwfc->sw_format != dst->format) + return AVERROR(ENOSYS); + + err = drm_map_frame(hwfc, dst, src, flags); + if (err) + return err; + + err = av_frame_copy_props(dst, src); + if (err) + return err; + + return 0; +} + +const HWContextType ff_hwcontext_type_drm = { + .type = AV_HWDEVICE_TYPE_DRM, + .name = "DRM", + + .device_hwctx_size = sizeof(AVDRMDeviceContext), + + .device_create = &drm_device_create, + + .frames_get_buffer = &drm_get_buffer, + + .transfer_get_formats = &drm_transfer_get_formats, + .transfer_data_to = &drm_transfer_data_to, + .transfer_data_from = &drm_transfer_data_from, + .map_from = &drm_map_from, + + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_DRM_PRIME, + AV_PIX_FMT_NONE + }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_drm.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_drm.h new file mode 100644 index 0000000000..42709f215e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_drm.h @@ -0,0 +1,169 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_DRM_H +#define AVUTIL_HWCONTEXT_DRM_H + +#include +#include + +/** + * @file + * API-specific header for AV_HWDEVICE_TYPE_DRM. + * + * Internal frame allocation is not currently supported - all frames + * must be allocated by the user. Thus AVHWFramesContext is always + * NULL, though this may change if support for frame allocation is + * added in future. + */ + +enum { + /** + * The maximum number of layers/planes in a DRM frame. + */ + AV_DRM_MAX_PLANES = 4 +}; + +/** + * DRM object descriptor. + * + * Describes a single DRM object, addressing it as a PRIME file + * descriptor. + */ +typedef struct AVDRMObjectDescriptor { + /** + * DRM PRIME fd for the object. + */ + int fd; + /** + * Total size of the object. + * + * (This includes any parts not which do not contain image data.) + */ + size_t size; + /** + * Format modifier applied to the object (DRM_FORMAT_MOD_*). + * + * If the format modifier is unknown then this should be set to + * DRM_FORMAT_MOD_INVALID. + */ + uint64_t format_modifier; +} AVDRMObjectDescriptor; + +/** + * DRM plane descriptor. + * + * Describes a single plane of a layer, which is contained within + * a single object. + */ +typedef struct AVDRMPlaneDescriptor { + /** + * Index of the object containing this plane in the objects + * array of the enclosing frame descriptor. + */ + int object_index; + /** + * Offset within that object of this plane. + */ + ptrdiff_t offset; + /** + * Pitch (linesize) of this plane. + */ + ptrdiff_t pitch; +} AVDRMPlaneDescriptor; + +/** + * DRM layer descriptor. + * + * Describes a single layer within a frame. This has the structure + * defined by its format, and will contain one or more planes. + */ +typedef struct AVDRMLayerDescriptor { + /** + * Format of the layer (DRM_FORMAT_*). + */ + uint32_t format; + /** + * Number of planes in the layer. + * + * This must match the number of planes required by format. + */ + int nb_planes; + /** + * Array of planes in this layer. + */ + AVDRMPlaneDescriptor planes[AV_DRM_MAX_PLANES]; +} AVDRMLayerDescriptor; + +/** + * DRM frame descriptor. + * + * This is used as the data pointer for AV_PIX_FMT_DRM_PRIME frames. + * It is also used by user-allocated frame pools - allocating in + * AVHWFramesContext.pool must return AVBufferRefs which contain + * an object of this type. + * + * The fields of this structure should be set such it can be + * imported directly by EGL using the EGL_EXT_image_dma_buf_import + * and EGL_EXT_image_dma_buf_import_modifiers extensions. + * (Note that the exact layout of a particular format may vary between + * platforms - we only specify that the same platform should be able + * to import it.) + * + * The total number of planes must not exceed AV_DRM_MAX_PLANES, and + * the order of the planes by increasing layer index followed by + * increasing plane index must be the same as the order which would + * be used for the data pointers in the equivalent software format. + */ +typedef struct AVDRMFrameDescriptor { + /** + * Number of DRM objects making up this frame. + */ + int nb_objects; + /** + * Array of objects making up the frame. + */ + AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES]; + /** + * Number of layers in the frame. + */ + int nb_layers; + /** + * Array of layers in the frame. + */ + AVDRMLayerDescriptor layers[AV_DRM_MAX_PLANES]; +} AVDRMFrameDescriptor; + +/** + * DRM device. + * + * Allocated as AVHWDeviceContext.hwctx. + */ +typedef struct AVDRMDeviceContext { + /** + * File descriptor of DRM device. + * + * This is used as the device to create frames on, and may also be + * used in some derivation and mapping operations. + * + * If no device is required, set to -1. + */ + int fd; +} AVDRMDeviceContext; + +#endif /* AVUTIL_HWCONTEXT_DRM_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_dxva2.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_dxva2.c new file mode 100644 index 0000000000..64366cea89 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_dxva2.c @@ -0,0 +1,594 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#define DXVA2API_USE_BITFIELDS +#define COBJMACROS + +#include +#include +#include + +#include "avassert.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_dxva2.h" +#include "hwcontext_internal.h" +#include "imgutils.h" +#include "pixdesc.h" +#include "pixfmt.h" +#include "compat/w32dlfcn.h" + +typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT); +typedef HRESULT WINAPI pDirect3DCreate9Ex(UINT, IDirect3D9Ex **); +typedef HRESULT WINAPI pCreateDeviceManager9(UINT *, IDirect3DDeviceManager9 **); + +#define FF_D3DCREATE_FLAGS (D3DCREATE_SOFTWARE_VERTEXPROCESSING | \ + D3DCREATE_MULTITHREADED | \ + D3DCREATE_FPU_PRESERVE) + +static const D3DPRESENT_PARAMETERS dxva2_present_params = { + .Windowed = TRUE, + .BackBufferWidth = 640, + .BackBufferHeight = 480, + .BackBufferCount = 0, + .SwapEffect = D3DSWAPEFFECT_DISCARD, + .Flags = D3DPRESENTFLAG_VIDEO, +}; + +typedef struct DXVA2Mapping { + uint32_t palette_dummy[256]; +} DXVA2Mapping; + +typedef struct DXVA2FramesContext { + IDirect3DSurface9 **surfaces_internal; + int nb_surfaces_used; + + HANDLE device_handle; + IDirectXVideoAccelerationService *service; + + D3DFORMAT format; +} DXVA2FramesContext; + +typedef struct DXVA2DevicePriv { + HMODULE d3dlib; + HMODULE dxva2lib; + + HANDLE device_handle; + + IDirect3D9 *d3d9; + IDirect3DDevice9 *d3d9device; +} DXVA2DevicePriv; + +static const struct { + D3DFORMAT d3d_format; + enum AVPixelFormat pix_fmt; +} supported_formats[] = { + { MKTAG('N', 'V', '1', '2'), AV_PIX_FMT_NV12 }, + { MKTAG('P', '0', '1', '0'), AV_PIX_FMT_P010 }, + { D3DFMT_P8, AV_PIX_FMT_PAL8 }, +}; + +DEFINE_GUID(video_decoder_service, 0xfc51a551, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02); +DEFINE_GUID(video_processor_service, 0xfc51a552, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02); + +static void dxva2_frames_uninit(AVHWFramesContext *ctx) +{ + AVDXVA2DeviceContext *device_hwctx = ctx->device_ctx->hwctx; + AVDXVA2FramesContext *frames_hwctx = ctx->hwctx; + DXVA2FramesContext *s = ctx->internal->priv; + int i; + + if (frames_hwctx->decoder_to_release) + IDirectXVideoDecoder_Release(frames_hwctx->decoder_to_release); + + if (s->surfaces_internal) { + for (i = 0; i < frames_hwctx->nb_surfaces; i++) { + if (s->surfaces_internal[i]) + IDirect3DSurface9_Release(s->surfaces_internal[i]); + } + } + av_freep(&s->surfaces_internal); + + if (s->service) { + IDirectXVideoAccelerationService_Release(s->service); + s->service = NULL; + } + + if (s->device_handle != INVALID_HANDLE_VALUE) { + IDirect3DDeviceManager9_CloseDeviceHandle(device_hwctx->devmgr, s->device_handle); + s->device_handle = INVALID_HANDLE_VALUE; + } +} + +static void dxva2_pool_release_dummy(void *opaque, uint8_t *data) +{ + // important not to free anything here--data is a surface object + // associated with the call to CreateSurface(), and these surfaces are + // released in dxva2_frames_uninit() +} + +static AVBufferRef *dxva2_pool_alloc(void *opaque, int size) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; + DXVA2FramesContext *s = ctx->internal->priv; + AVDXVA2FramesContext *hwctx = ctx->hwctx; + + if (s->nb_surfaces_used < hwctx->nb_surfaces) { + s->nb_surfaces_used++; + return av_buffer_create((uint8_t*)s->surfaces_internal[s->nb_surfaces_used - 1], + sizeof(*hwctx->surfaces), dxva2_pool_release_dummy, 0, 0); + } + + return NULL; +} + +static int dxva2_init_pool(AVHWFramesContext *ctx) +{ + AVDXVA2FramesContext *frames_hwctx = ctx->hwctx; + AVDXVA2DeviceContext *device_hwctx = ctx->device_ctx->hwctx; + DXVA2FramesContext *s = ctx->internal->priv; + int decode = (frames_hwctx->surface_type == DXVA2_VideoDecoderRenderTarget); + + int i; + HRESULT hr; + + if (ctx->initial_pool_size <= 0) + return 0; + + hr = IDirect3DDeviceManager9_OpenDeviceHandle(device_hwctx->devmgr, &s->device_handle); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to open device handle\n"); + return AVERROR_UNKNOWN; + } + + hr = IDirect3DDeviceManager9_GetVideoService(device_hwctx->devmgr, + s->device_handle, + decode ? &video_decoder_service : &video_processor_service, + (void **)&s->service); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to create the video service\n"); + return AVERROR_UNKNOWN; + } + + for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { + if (ctx->sw_format == supported_formats[i].pix_fmt) { + s->format = supported_formats[i].d3d_format; + break; + } + } + if (i == FF_ARRAY_ELEMS(supported_formats)) { + av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n", + av_get_pix_fmt_name(ctx->sw_format)); + return AVERROR(EINVAL); + } + + s->surfaces_internal = av_mallocz_array(ctx->initial_pool_size, + sizeof(*s->surfaces_internal)); + if (!s->surfaces_internal) + return AVERROR(ENOMEM); + + hr = IDirectXVideoAccelerationService_CreateSurface(s->service, + ctx->width, ctx->height, + ctx->initial_pool_size - 1, + s->format, D3DPOOL_DEFAULT, 0, + frames_hwctx->surface_type, + s->surfaces_internal, NULL); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Could not create the surfaces\n"); + return AVERROR_UNKNOWN; + } + + ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(*s->surfaces_internal), + ctx, dxva2_pool_alloc, NULL); + if (!ctx->internal->pool_internal) + return AVERROR(ENOMEM); + + frames_hwctx->surfaces = s->surfaces_internal; + frames_hwctx->nb_surfaces = ctx->initial_pool_size; + + return 0; +} + +static int dxva2_frames_init(AVHWFramesContext *ctx) +{ + AVDXVA2FramesContext *hwctx = ctx->hwctx; + DXVA2FramesContext *s = ctx->internal->priv; + int ret; + + if (hwctx->surface_type != DXVA2_VideoDecoderRenderTarget && + hwctx->surface_type != DXVA2_VideoProcessorRenderTarget) { + av_log(ctx, AV_LOG_ERROR, "Unknown surface type: %lu\n", + hwctx->surface_type); + return AVERROR(EINVAL); + } + + s->device_handle = INVALID_HANDLE_VALUE; + + /* init the frame pool if the caller didn't provide one */ + if (!ctx->pool) { + ret = dxva2_init_pool(ctx); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error creating an internal frame pool\n"); + return ret; + } + } + + return 0; +} + +static int dxva2_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) +{ + frame->buf[0] = av_buffer_pool_get(ctx->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + + frame->data[3] = frame->buf[0]->data; + frame->format = AV_PIX_FMT_DXVA2_VLD; + frame->width = ctx->width; + frame->height = ctx->height; + + return 0; +} + +static int dxva2_transfer_get_formats(AVHWFramesContext *ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ + enum AVPixelFormat *fmts; + + fmts = av_malloc_array(2, sizeof(*fmts)); + if (!fmts) + return AVERROR(ENOMEM); + + fmts[0] = ctx->sw_format; + fmts[1] = AV_PIX_FMT_NONE; + + *formats = fmts; + + return 0; +} + +static void dxva2_unmap_frame(AVHWFramesContext *ctx, HWMapDescriptor *hwmap) +{ + IDirect3DSurface9 *surface = (IDirect3DSurface9*)hwmap->source->data[3]; + IDirect3DSurface9_UnlockRect(surface); + av_freep(&hwmap->priv); +} + +static int dxva2_map_frame(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src, + int flags) +{ + IDirect3DSurface9 *surface = (IDirect3DSurface9*)src->data[3]; + DXVA2Mapping *map; + D3DSURFACE_DESC surfaceDesc; + D3DLOCKED_RECT LockedRect; + HRESULT hr; + int i, err, nb_planes; + int lock_flags = 0; + + nb_planes = av_pix_fmt_count_planes(dst->format); + + hr = IDirect3DSurface9_GetDesc(surface, &surfaceDesc); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Error getting a surface description\n"); + return AVERROR_UNKNOWN; + } + + if (!(flags & AV_HWFRAME_MAP_WRITE)) + lock_flags |= D3DLOCK_READONLY; + if (flags & AV_HWFRAME_MAP_OVERWRITE) + lock_flags |= D3DLOCK_DISCARD; + + hr = IDirect3DSurface9_LockRect(surface, &LockedRect, NULL, lock_flags); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Unable to lock DXVA2 surface\n"); + return AVERROR_UNKNOWN; + } + + map = av_mallocz(sizeof(*map)); + if (!map) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, + dxva2_unmap_frame, map); + if (err < 0) { + av_freep(&map); + goto fail; + } + + for (i = 0; i < nb_planes; i++) + dst->linesize[i] = LockedRect.Pitch; + + av_image_fill_pointers(dst->data, dst->format, surfaceDesc.Height, + (uint8_t*)LockedRect.pBits, dst->linesize); + + if (dst->format == AV_PIX_FMT_PAL8) + dst->data[1] = (uint8_t*)map->palette_dummy; + + return 0; +fail: + IDirect3DSurface9_UnlockRect(surface); + return err; +} + +static int dxva2_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src) +{ + AVFrame *map; + int ret; + + if (src->format != ctx->sw_format) + return AVERROR(ENOSYS); + + map = av_frame_alloc(); + if (!map) + return AVERROR(ENOMEM); + map->format = dst->format; + + ret = dxva2_map_frame(ctx, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE); + if (ret < 0) + goto fail; + + av_image_copy(map->data, map->linesize, (const uint8_t **)src->data, src->linesize, + ctx->sw_format, src->width, src->height); + +fail: + av_frame_free(&map); + return ret; +} + +static int dxva2_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src) +{ + AVFrame *map; + ptrdiff_t src_linesize[4], dst_linesize[4]; + int ret, i; + + if (dst->format != ctx->sw_format) + return AVERROR(ENOSYS); + + map = av_frame_alloc(); + if (!map) + return AVERROR(ENOMEM); + map->format = dst->format; + + ret = dxva2_map_frame(ctx, map, src, AV_HWFRAME_MAP_READ); + if (ret < 0) + goto fail; + + for (i = 0; i < 4; i++) { + dst_linesize[i] = dst->linesize[i]; + src_linesize[i] = map->linesize[i]; + } + av_image_copy_uc_from(dst->data, dst_linesize, (const uint8_t **)map->data, src_linesize, + ctx->sw_format, src->width, src->height); +fail: + av_frame_free(&map); + return ret; +} + +static int dxva2_map_from(AVHWFramesContext *ctx, + AVFrame *dst, const AVFrame *src, int flags) +{ + int err; + + if (dst->format != AV_PIX_FMT_NONE && dst->format != ctx->sw_format) + return AVERROR(ENOSYS); + dst->format = ctx->sw_format; + + err = dxva2_map_frame(ctx, dst, src, flags); + if (err < 0) + return err; + + err = av_frame_copy_props(dst, src); + if (err < 0) + return err; + + return 0; +} + +static void dxva2_device_free(AVHWDeviceContext *ctx) +{ + AVDXVA2DeviceContext *hwctx = ctx->hwctx; + DXVA2DevicePriv *priv = ctx->user_opaque; + + if (hwctx->devmgr && priv->device_handle != INVALID_HANDLE_VALUE) + IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, priv->device_handle); + + if (hwctx->devmgr) + IDirect3DDeviceManager9_Release(hwctx->devmgr); + + if (priv->d3d9device) + IDirect3DDevice9_Release(priv->d3d9device); + + if (priv->d3d9) + IDirect3D9_Release(priv->d3d9); + + if (priv->d3dlib) + dlclose(priv->d3dlib); + + if (priv->dxva2lib) + dlclose(priv->dxva2lib); + + av_freep(&ctx->user_opaque); +} + +static int dxva2_device_create9(AVHWDeviceContext *ctx, UINT adapter) +{ + DXVA2DevicePriv *priv = ctx->user_opaque; + D3DPRESENT_PARAMETERS d3dpp = dxva2_present_params; + D3DDISPLAYMODE d3ddm; + HRESULT hr; + pDirect3DCreate9 *createD3D = (pDirect3DCreate9 *)dlsym(priv->d3dlib, "Direct3DCreate9"); + if (!createD3D) { + av_log(ctx, AV_LOG_ERROR, "Failed to locate Direct3DCreate9\n"); + return AVERROR_UNKNOWN; + } + + priv->d3d9 = createD3D(D3D_SDK_VERSION); + if (!priv->d3d9) { + av_log(ctx, AV_LOG_ERROR, "Failed to create IDirect3D object\n"); + return AVERROR_UNKNOWN; + } + + IDirect3D9_GetAdapterDisplayMode(priv->d3d9, adapter, &d3ddm); + + d3dpp.BackBufferFormat = d3ddm.Format; + + hr = IDirect3D9_CreateDevice(priv->d3d9, adapter, D3DDEVTYPE_HAL, GetDesktopWindow(), + FF_D3DCREATE_FLAGS, + &d3dpp, &priv->d3d9device); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device\n"); + return AVERROR_UNKNOWN; + } + + return 0; +} + +static int dxva2_device_create9ex(AVHWDeviceContext *ctx, UINT adapter) +{ + DXVA2DevicePriv *priv = ctx->user_opaque; + D3DPRESENT_PARAMETERS d3dpp = dxva2_present_params; + D3DDISPLAYMODEEX modeex = {0}; + IDirect3D9Ex *d3d9ex = NULL; + IDirect3DDevice9Ex *exdev = NULL; + HRESULT hr; + pDirect3DCreate9Ex *createD3DEx = (pDirect3DCreate9Ex *)dlsym(priv->d3dlib, "Direct3DCreate9Ex"); + if (!createD3DEx) + return AVERROR(ENOSYS); + + hr = createD3DEx(D3D_SDK_VERSION, &d3d9ex); + if (FAILED(hr)) + return AVERROR_UNKNOWN; + + modeex.Size = sizeof(D3DDISPLAYMODEEX); + hr = IDirect3D9Ex_GetAdapterDisplayModeEx(d3d9ex, adapter, &modeex, NULL); + if (FAILED(hr)) { + IDirect3D9Ex_Release(d3d9ex); + return AVERROR_UNKNOWN; + } + + d3dpp.BackBufferFormat = modeex.Format; + + hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, adapter, D3DDEVTYPE_HAL, GetDesktopWindow(), + FF_D3DCREATE_FLAGS, + &d3dpp, NULL, &exdev); + if (FAILED(hr)) { + IDirect3D9Ex_Release(d3d9ex); + return AVERROR_UNKNOWN; + } + + av_log(ctx, AV_LOG_VERBOSE, "Using D3D9Ex device.\n"); + priv->d3d9 = (IDirect3D9 *)d3d9ex; + priv->d3d9device = (IDirect3DDevice9 *)exdev; + return 0; +} + +static int dxva2_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + AVDXVA2DeviceContext *hwctx = ctx->hwctx; + DXVA2DevicePriv *priv; + pCreateDeviceManager9 *createDeviceManager = NULL; + unsigned resetToken = 0; + UINT adapter = D3DADAPTER_DEFAULT; + HRESULT hr; + int err; + + if (device) + adapter = atoi(device); + + priv = av_mallocz(sizeof(*priv)); + if (!priv) + return AVERROR(ENOMEM); + + ctx->user_opaque = priv; + ctx->free = dxva2_device_free; + + priv->device_handle = INVALID_HANDLE_VALUE; + + priv->d3dlib = dlopen("d3d9.dll", 0); + if (!priv->d3dlib) { + av_log(ctx, AV_LOG_ERROR, "Failed to load D3D9 library\n"); + return AVERROR_UNKNOWN; + } + priv->dxva2lib = dlopen("dxva2.dll", 0); + if (!priv->dxva2lib) { + av_log(ctx, AV_LOG_ERROR, "Failed to load DXVA2 library\n"); + return AVERROR_UNKNOWN; + } + + createDeviceManager = (pCreateDeviceManager9 *)dlsym(priv->dxva2lib, + "DXVA2CreateDirect3DDeviceManager9"); + if (!createDeviceManager) { + av_log(ctx, AV_LOG_ERROR, "Failed to locate DXVA2CreateDirect3DDeviceManager9\n"); + return AVERROR_UNKNOWN; + } + + if (dxva2_device_create9ex(ctx, adapter) < 0) { + // Retry with "classic" d3d9 + err = dxva2_device_create9(ctx, adapter); + if (err < 0) + return err; + } + + hr = createDeviceManager(&resetToken, &hwctx->devmgr); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to create Direct3D device manager\n"); + return AVERROR_UNKNOWN; + } + + hr = IDirect3DDeviceManager9_ResetDevice(hwctx->devmgr, priv->d3d9device, resetToken); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to bind Direct3D device to device manager\n"); + return AVERROR_UNKNOWN; + } + + hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &priv->device_handle); + if (FAILED(hr)) { + av_log(ctx, AV_LOG_ERROR, "Failed to open device handle\n"); + return AVERROR_UNKNOWN; + } + + return 0; +} + +const HWContextType ff_hwcontext_type_dxva2 = { + .type = AV_HWDEVICE_TYPE_DXVA2, + .name = "DXVA2", + + .device_hwctx_size = sizeof(AVDXVA2DeviceContext), + .frames_hwctx_size = sizeof(AVDXVA2FramesContext), + .frames_priv_size = sizeof(DXVA2FramesContext), + + .device_create = dxva2_device_create, + .frames_init = dxva2_frames_init, + .frames_uninit = dxva2_frames_uninit, + .frames_get_buffer = dxva2_get_buffer, + .transfer_get_formats = dxva2_transfer_get_formats, + .transfer_data_to = dxva2_transfer_data_to, + .transfer_data_from = dxva2_transfer_data_from, + .map_from = dxva2_map_from, + + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_DXVA2_VLD, AV_PIX_FMT_NONE }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_dxva2.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_dxva2.h new file mode 100644 index 0000000000..e1b79bc0de --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_dxva2.h @@ -0,0 +1,75 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef AVUTIL_HWCONTEXT_DXVA2_H +#define AVUTIL_HWCONTEXT_DXVA2_H + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_DXVA2. + * + * Only fixed-size pools are supported. + * + * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer set to a pointer to IDirect3DSurface9. + */ + +#include +#include + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVDXVA2DeviceContext { + IDirect3DDeviceManager9 *devmgr; +} AVDXVA2DeviceContext; + +/** + * This struct is allocated as AVHWFramesContext.hwctx + */ +typedef struct AVDXVA2FramesContext { + /** + * The surface type (e.g. DXVA2_VideoProcessorRenderTarget or + * DXVA2_VideoDecoderRenderTarget). Must be set by the caller. + */ + DWORD surface_type; + + /** + * The surface pool. When an external pool is not provided by the caller, + * this will be managed (allocated and filled on init, freed on uninit) by + * libavutil. + */ + IDirect3DSurface9 **surfaces; + int nb_surfaces; + + /** + * Certain drivers require the decoder to be destroyed before the surfaces. + * To allow internally managed pools to work properly in such cases, this + * field is provided. + * + * If it is non-NULL, libavutil will call IDirectXVideoDecoder_Release() on + * it just before the internal surface pool is freed. + * + * This is for convenience only. Some code uses other methods to manage the + * decoder reference. + */ + IDirectXVideoDecoder *decoder_to_release; +} AVDXVA2FramesContext; + +#endif /* AVUTIL_HWCONTEXT_DXVA2_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_internal.h new file mode 100644 index 0000000000..77dc47ddd6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_internal.h @@ -0,0 +1,176 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_INTERNAL_H +#define AVUTIL_HWCONTEXT_INTERNAL_H + +#include + +#include "buffer.h" +#include "hwcontext.h" +#include "frame.h" +#include "pixfmt.h" + +typedef struct HWContextType { + enum AVHWDeviceType type; + const char *name; + + /** + * An array of pixel formats supported by the AVHWFramesContext instances + * Terminated by AV_PIX_FMT_NONE. + */ + const enum AVPixelFormat *pix_fmts; + + /** + * size of the public hardware-specific context, + * i.e. AVHWDeviceContext.hwctx + */ + size_t device_hwctx_size; + /** + * size of the private data, i.e. + * AVHWDeviceInternal.priv + */ + size_t device_priv_size; + + /** + * Size of the hardware-specific device configuration. + * (Used to query hwframe constraints.) + */ + size_t device_hwconfig_size; + + /** + * size of the public frame pool hardware-specific context, + * i.e. AVHWFramesContext.hwctx + */ + size_t frames_hwctx_size; + /** + * size of the private data, i.e. + * AVHWFramesInternal.priv + */ + size_t frames_priv_size; + + int (*device_create)(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags); + int (*device_derive)(AVHWDeviceContext *dst_ctx, + AVHWDeviceContext *src_ctx, int flags); + + int (*device_init)(AVHWDeviceContext *ctx); + void (*device_uninit)(AVHWDeviceContext *ctx); + + int (*frames_get_constraints)(AVHWDeviceContext *ctx, + const void *hwconfig, + AVHWFramesConstraints *constraints); + + int (*frames_init)(AVHWFramesContext *ctx); + void (*frames_uninit)(AVHWFramesContext *ctx); + + int (*frames_get_buffer)(AVHWFramesContext *ctx, AVFrame *frame); + int (*transfer_get_formats)(AVHWFramesContext *ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats); + int (*transfer_data_to)(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src); + int (*transfer_data_from)(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src); + + int (*map_to)(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src, int flags); + int (*map_from)(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src, int flags); + + int (*frames_derive_to)(AVHWFramesContext *dst_ctx, + AVHWFramesContext *src_ctx, int flags); + int (*frames_derive_from)(AVHWFramesContext *dst_ctx, + AVHWFramesContext *src_ctx, int flags); +} HWContextType; + +struct AVHWDeviceInternal { + const HWContextType *hw_type; + void *priv; + + /** + * For a derived device, a reference to the original device + * context it was derived from. + */ + AVBufferRef *source_device; +}; + +struct AVHWFramesInternal { + const HWContextType *hw_type; + void *priv; + + AVBufferPool *pool_internal; + + /** + * For a derived context, a reference to the original frames + * context it was derived from. + */ + AVBufferRef *source_frames; + /** + * Flags to apply to the mapping from the source to the derived + * frame context when trying to allocate in the derived context. + */ + int source_allocation_map_flags; +}; + +typedef struct HWMapDescriptor { + /** + * A reference to the original source of the mapping. + */ + AVFrame *source; + /** + * A reference to the hardware frames context in which this + * mapping was made. May be the same as source->hw_frames_ctx, + * but need not be. + */ + AVBufferRef *hw_frames_ctx; + /** + * Unmap function. + */ + void (*unmap)(AVHWFramesContext *ctx, + struct HWMapDescriptor *hwmap); + /** + * Hardware-specific private data associated with the mapping. + */ + void *priv; +} HWMapDescriptor; + +int ff_hwframe_map_create(AVBufferRef *hwframe_ref, + AVFrame *dst, const AVFrame *src, + void (*unmap)(AVHWFramesContext *ctx, + HWMapDescriptor *hwmap), + void *priv); + +/** + * Replace the current hwmap of dst with the one from src, used for indirect + * mappings like VAAPI->(DRM)->OpenCL/Vulkan where a direct interop is missing + */ +int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src); + +extern const HWContextType ff_hwcontext_type_cuda; +extern const HWContextType ff_hwcontext_type_d3d11va; +extern const HWContextType ff_hwcontext_type_drm; +extern const HWContextType ff_hwcontext_type_dxva2; +extern const HWContextType ff_hwcontext_type_opencl; +extern const HWContextType ff_hwcontext_type_qsv; +extern const HWContextType ff_hwcontext_type_vaapi; +extern const HWContextType ff_hwcontext_type_vdpau; +extern const HWContextType ff_hwcontext_type_videotoolbox; +extern const HWContextType ff_hwcontext_type_mediacodec; + +#endif /* AVUTIL_HWCONTEXT_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_mediacodec.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_mediacodec.c new file mode 100644 index 0000000000..b0d8993e15 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_mediacodec.c @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "buffer.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_internal.h" +#include "hwcontext_mediacodec.h" + +static int mc_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + if (device && device[0]) { + av_log(ctx, AV_LOG_ERROR, "Device selection unsupported.\n"); + return AVERROR_UNKNOWN; + } + + return 0; +} + +const HWContextType ff_hwcontext_type_mediacodec = { + .type = AV_HWDEVICE_TYPE_MEDIACODEC, + .name = "mediacodec", + + .device_hwctx_size = sizeof(AVMediaCodecDeviceContext), + + .device_create = mc_device_create, + + .pix_fmts = (const enum AVPixelFormat[]){ + AV_PIX_FMT_MEDIACODEC, + AV_PIX_FMT_NONE + }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_mediacodec.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_mediacodec.h new file mode 100644 index 0000000000..101a9806d5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_mediacodec.h @@ -0,0 +1,36 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_MEDIACODEC_H +#define AVUTIL_HWCONTEXT_MEDIACODEC_H + +/** + * MediaCodec details. + * + * Allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVMediaCodecDeviceContext { + /** + * android/view/Surface handle, to be filled by the user. + * + * This is the default surface used by decoders on this device. + */ + void *surface; +} AVMediaCodecDeviceContext; + +#endif /* AVUTIL_HWCONTEXT_MEDIACODEC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_opencl.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_opencl.c new file mode 100644 index 0000000000..41fdfe96f1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_opencl.c @@ -0,0 +1,2942 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define CL_USE_DEPRECATED_OPENCL_1_2_APIS + +#include + +#include "config.h" + +#include "avassert.h" +#include "avstring.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_internal.h" +#include "hwcontext_opencl.h" +#include "mem.h" +#include "pixdesc.h" + +#if HAVE_OPENCL_VAAPI_BEIGNET +#include +#include +#include +#include +#include "hwcontext_vaapi.h" +#endif + +#if HAVE_OPENCL_DRM_BEIGNET +#include +#include +#include "hwcontext_drm.h" +#endif + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA +#if CONFIG_LIBMFX +#include +#endif +#include +#include +#include "hwcontext_vaapi.h" +#endif + +#if HAVE_OPENCL_DXVA2 +#define COBJMACROS +#include +#include +#include "hwcontext_dxva2.h" +#endif + +#if HAVE_OPENCL_D3D11 +#include +#include "hwcontext_d3d11va.h" +#endif + +#if HAVE_OPENCL_DRM_ARM +#include +#include +#include "hwcontext_drm.h" +#endif + + +typedef struct OpenCLDeviceContext { + // Default command queue to use for transfer/mapping operations on + // the device. If the user supplies one, this is a reference to it. + // Otherwise, it is newly-created. + cl_command_queue command_queue; + + // The platform the context exists on. This is needed to query and + // retrieve extension functions. + cl_platform_id platform_id; + + // Platform/device-specific functions. +#if HAVE_OPENCL_DRM_BEIGNET + int beignet_drm_mapping_usable; + clCreateImageFromFdINTEL_fn clCreateImageFromFdINTEL; +#endif + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + int qsv_mapping_usable; + clCreateFromVA_APIMediaSurfaceINTEL_fn + clCreateFromVA_APIMediaSurfaceINTEL; + clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn + clEnqueueAcquireVA_APIMediaSurfacesINTEL; + clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn + clEnqueueReleaseVA_APIMediaSurfacesINTEL; +#endif + +#if HAVE_OPENCL_DXVA2 + int dxva2_mapping_usable; + cl_dx9_media_adapter_type_khr dx9_media_adapter_type; + + clCreateFromDX9MediaSurfaceKHR_fn + clCreateFromDX9MediaSurfaceKHR; + clEnqueueAcquireDX9MediaSurfacesKHR_fn + clEnqueueAcquireDX9MediaSurfacesKHR; + clEnqueueReleaseDX9MediaSurfacesKHR_fn + clEnqueueReleaseDX9MediaSurfacesKHR; +#endif + +#if HAVE_OPENCL_D3D11 + int d3d11_mapping_usable; + clCreateFromD3D11Texture2DKHR_fn + clCreateFromD3D11Texture2DKHR; + clEnqueueAcquireD3D11ObjectsKHR_fn + clEnqueueAcquireD3D11ObjectsKHR; + clEnqueueReleaseD3D11ObjectsKHR_fn + clEnqueueReleaseD3D11ObjectsKHR; +#endif + +#if HAVE_OPENCL_DRM_ARM + int drm_arm_mapping_usable; +#endif +} OpenCLDeviceContext; + +typedef struct OpenCLFramesContext { + // Command queue used for transfer/mapping operations on this frames + // context. If the user supplies one, this is a reference to it. + // Otherwise, it is a reference to the default command queue for the + // device. + cl_command_queue command_queue; + +#if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11 + // For mapping APIs which have separate creation and acquire/release + // steps, this stores the OpenCL memory objects corresponding to each + // frame. + int nb_mapped_frames; + AVOpenCLFrameDescriptor *mapped_frames; +#endif +} OpenCLFramesContext; + + +static void CL_CALLBACK opencl_error_callback(const char *errinfo, + const void *private_info, + size_t cb, + void *user_data) +{ + AVHWDeviceContext *ctx = user_data; + av_log(ctx, AV_LOG_ERROR, "OpenCL error: %s\n", errinfo); +} + +static void opencl_device_free(AVHWDeviceContext *hwdev) +{ + AVOpenCLDeviceContext *hwctx = hwdev->hwctx; + cl_int cle; + + cle = clReleaseContext(hwctx->context); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to release OpenCL " + "context: %d.\n", cle); + } +} + +static struct { + const char *key; + cl_platform_info name; +} opencl_platform_params[] = { + { "platform_profile", CL_PLATFORM_PROFILE }, + { "platform_version", CL_PLATFORM_VERSION }, + { "platform_name", CL_PLATFORM_NAME }, + { "platform_vendor", CL_PLATFORM_VENDOR }, + { "platform_extensions", CL_PLATFORM_EXTENSIONS }, +}; + +static struct { + const char *key; + cl_device_info name; +} opencl_device_params[] = { + { "device_name", CL_DEVICE_NAME }, + { "device_vendor", CL_DEVICE_VENDOR }, + { "driver_version", CL_DRIVER_VERSION }, + { "device_version", CL_DEVICE_VERSION }, + { "device_profile", CL_DEVICE_PROFILE }, + { "device_extensions", CL_DEVICE_EXTENSIONS }, +}; + +static struct { + const char *key; + cl_device_type type; +} opencl_device_types[] = { + { "cpu", CL_DEVICE_TYPE_CPU }, + { "gpu", CL_DEVICE_TYPE_GPU }, + { "accelerator", CL_DEVICE_TYPE_ACCELERATOR }, + { "custom", CL_DEVICE_TYPE_CUSTOM }, + { "default", CL_DEVICE_TYPE_DEFAULT }, + { "all", CL_DEVICE_TYPE_ALL }, +}; + +static char *opencl_get_platform_string(cl_platform_id platform_id, + cl_platform_info key) +{ + char *str; + size_t size; + cl_int cle; + cle = clGetPlatformInfo(platform_id, key, 0, NULL, &size); + if (cle != CL_SUCCESS) + return NULL; + str = av_malloc(size); + if (!str) + return NULL; + cle = clGetPlatformInfo(platform_id, key, size, str, &size); + if (cle != CL_SUCCESS) { + av_free(str); + return NULL; + } + av_assert0(strlen(str) + 1 == size); + return str; +} + +static char *opencl_get_device_string(cl_device_id device_id, + cl_device_info key) +{ + char *str; + size_t size; + cl_int cle; + cle = clGetDeviceInfo(device_id, key, 0, NULL, &size); + if (cle != CL_SUCCESS) + return NULL; + str = av_malloc(size); + if (!str) + return NULL; + cle = clGetDeviceInfo(device_id, key, size, str, &size); + if (cle != CL_SUCCESS) { + av_free(str); + return NULL; + } + av_assert0(strlen(str) + 1== size); + return str; +} + +static int opencl_check_platform_extension(cl_platform_id platform_id, + const char *name) +{ + char *str; + int found = 0; + str = opencl_get_platform_string(platform_id, + CL_PLATFORM_EXTENSIONS); + if (str && strstr(str, name)) + found = 1; + av_free(str); + return found; +} + +static int opencl_check_device_extension(cl_device_id device_id, + const char *name) +{ + char *str; + int found = 0; + str = opencl_get_device_string(device_id, + CL_DEVICE_EXTENSIONS); + if (str && strstr(str, name)) + found = 1; + av_free(str); + return found; +} + +static av_unused int opencl_check_extension(AVHWDeviceContext *hwdev, + const char *name) +{ + AVOpenCLDeviceContext *hwctx = hwdev->hwctx; + OpenCLDeviceContext *priv = hwdev->internal->priv; + + if (opencl_check_platform_extension(priv->platform_id, name)) { + av_log(hwdev, AV_LOG_DEBUG, + "%s found as platform extension.\n", name); + return 1; + } + + if (opencl_check_device_extension(hwctx->device_id, name)) { + av_log(hwdev, AV_LOG_DEBUG, + "%s found as device extension.\n", name); + return 1; + } + + return 0; +} + +static int opencl_enumerate_platforms(AVHWDeviceContext *hwdev, + cl_uint *nb_platforms, + cl_platform_id **platforms, + void *context) +{ + cl_int cle; + + cle = clGetPlatformIDs(0, NULL, nb_platforms); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get number of " + "OpenCL platforms: %d.\n", cle); + return AVERROR(ENODEV); + } + av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL platforms found.\n", + *nb_platforms); + + *platforms = av_malloc_array(*nb_platforms, sizeof(**platforms)); + if (!*platforms) + return AVERROR(ENOMEM); + + cle = clGetPlatformIDs(*nb_platforms, *platforms, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get list of OpenCL " + "platforms: %d.\n", cle); + av_freep(platforms); + return AVERROR(ENODEV); + } + + return 0; +} + +static int opencl_filter_platform(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context) +{ + AVDictionary *opts = context; + const AVDictionaryEntry *param; + char *str; + int i, ret = 0; + + for (i = 0; i < FF_ARRAY_ELEMS(opencl_platform_params); i++) { + param = av_dict_get(opts, opencl_platform_params[i].key, + NULL, 0); + if (!param) + continue; + + str = opencl_get_platform_string(platform_id, + opencl_platform_params[i].name); + if (!str) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query %s " + "of platform \"%s\".\n", + opencl_platform_params[i].key, platform_name); + return AVERROR_UNKNOWN; + } + if (!av_stristr(str, param->value)) { + av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n", + param->key, str); + ret = 1; + } + av_free(str); + } + + return ret; +} + +static int opencl_enumerate_devices(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + cl_uint *nb_devices, + cl_device_id **devices, + void *context) +{ + cl_int cle; + + cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL, + 0, NULL, nb_devices); + if (cle == CL_DEVICE_NOT_FOUND) { + av_log(hwdev, AV_LOG_DEBUG, "No devices found " + "on platform \"%s\".\n", platform_name); + *nb_devices = 0; + return 0; + } else if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices " + "on platform \"%s\": %d.\n", platform_name, cle); + return AVERROR(ENODEV); + } + av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL devices found on " + "platform \"%s\".\n", *nb_devices, platform_name); + + *devices = av_malloc_array(*nb_devices, sizeof(**devices)); + if (!*devices) + return AVERROR(ENOMEM); + + cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL, + *nb_devices, *devices, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get list of devices " + "on platform \"%s\": %d.\n", platform_name, cle); + av_freep(devices); + return AVERROR(ENODEV); + } + + return 0; +} + +static int opencl_filter_device(AVHWDeviceContext *hwdev, + cl_device_id device_id, + const char *device_name, + void *context) +{ + AVDictionary *opts = context; + const AVDictionaryEntry *param; + char *str; + int i, ret = 0; + + param = av_dict_get(opts, "device_type", NULL, 0); + if (param) { + cl_device_type match_type = 0, device_type; + cl_int cle; + + for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_types); i++) { + if (!strcmp(opencl_device_types[i].key, param->value)) { + match_type = opencl_device_types[i].type; + break; + } + } + if (!match_type) { + av_log(hwdev, AV_LOG_ERROR, "Unknown device type %s.\n", + param->value); + return AVERROR(EINVAL); + } + + cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE, + sizeof(device_type), &device_type, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query device type " + "of device \"%s\".\n", device_name); + return AVERROR_UNKNOWN; + } + + if (!(device_type & match_type)) { + av_log(hwdev, AV_LOG_DEBUG, "device_type does not match.\n"); + return 1; + } + } + + for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_params); i++) { + param = av_dict_get(opts, opencl_device_params[i].key, + NULL, 0); + if (!param) + continue; + + str = opencl_get_device_string(device_id, + opencl_device_params[i].name); + if (!str) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query %s " + "of device \"%s\".\n", + opencl_device_params[i].key, device_name); + return AVERROR_UNKNOWN; + } + if (!av_stristr(str, param->value)) { + av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n", + param->key, str); + ret = 1; + } + av_free(str); + } + + return ret; +} + +typedef struct OpenCLDeviceSelector { + int platform_index; + int device_index; + void *context; + int (*enumerate_platforms)(AVHWDeviceContext *hwdev, + cl_uint *nb_platforms, + cl_platform_id **platforms, + void *context); + int (*filter_platform) (AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context); + int (*enumerate_devices) (AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + cl_uint *nb_devices, + cl_device_id **devices, + void *context); + int (*filter_device) (AVHWDeviceContext *hwdev, + cl_device_id device_id, + const char *device_name, + void *context); +} OpenCLDeviceSelector; + +static int opencl_device_create_internal(AVHWDeviceContext *hwdev, + const OpenCLDeviceSelector *selector, + cl_context_properties *props) +{ + cl_uint nb_platforms; + cl_platform_id *platforms = NULL; + cl_platform_id platform_id; + cl_uint nb_devices; + cl_device_id *devices = NULL; + AVOpenCLDeviceContext *hwctx = hwdev->hwctx; + cl_int cle; + cl_context_properties default_props[3]; + char *platform_name_src = NULL, + *device_name_src = NULL; + int err, found, p, d; + + av_assert0(selector->enumerate_platforms && + selector->enumerate_devices); + + err = selector->enumerate_platforms(hwdev, &nb_platforms, &platforms, + selector->context); + if (err) + return err; + + found = 0; + for (p = 0; p < nb_platforms; p++) { + const char *platform_name; + + if (selector->platform_index >= 0 && + selector->platform_index != p) + continue; + + av_freep(&platform_name_src); + platform_name_src = opencl_get_platform_string(platforms[p], + CL_PLATFORM_NAME); + if (platform_name_src) + platform_name = platform_name_src; + else + platform_name = "Unknown Platform"; + + if (selector->filter_platform) { + err = selector->filter_platform(hwdev, platforms[p], + platform_name, + selector->context); + if (err < 0) + goto fail; + if (err > 0) + continue; + } + + err = selector->enumerate_devices(hwdev, platforms[p], platform_name, + &nb_devices, &devices, + selector->context); + if (err < 0) + continue; + + for (d = 0; d < nb_devices; d++) { + const char *device_name; + + if (selector->device_index >= 0 && + selector->device_index != d) + continue; + + av_freep(&device_name_src); + device_name_src = opencl_get_device_string(devices[d], + CL_DEVICE_NAME); + if (device_name_src) + device_name = device_name_src; + else + device_name = "Unknown Device"; + + if (selector->filter_device) { + err = selector->filter_device(hwdev, devices[d], + device_name, + selector->context); + if (err < 0) + goto fail; + if (err > 0) + continue; + } + + av_log(hwdev, AV_LOG_VERBOSE, "%d.%d: %s / %s\n", p, d, + platform_name, device_name); + + ++found; + platform_id = platforms[p]; + hwctx->device_id = devices[d]; + } + + av_freep(&devices); + } + + if (found == 0) { + av_log(hwdev, AV_LOG_ERROR, "No matching devices found.\n"); + err = AVERROR(ENODEV); + goto fail; + } + if (found > 1) { + av_log(hwdev, AV_LOG_ERROR, "More than one matching device found.\n"); + err = AVERROR(ENODEV); + goto fail; + } + + if (!props) { + props = default_props; + default_props[0] = CL_CONTEXT_PLATFORM; + default_props[1] = (intptr_t)platform_id; + default_props[2] = 0; + } else { + if (props[0] == CL_CONTEXT_PLATFORM && props[1] == 0) + props[1] = (intptr_t)platform_id; + } + + hwctx->context = clCreateContext(props, 1, &hwctx->device_id, + &opencl_error_callback, hwdev, &cle); + if (!hwctx->context) { + av_log(hwdev, AV_LOG_ERROR, "Failed to create OpenCL context: " + "%d.\n", cle); + err = AVERROR(ENODEV); + goto fail; + } + + hwdev->free = &opencl_device_free; + + err = 0; +fail: + av_freep(&platform_name_src); + av_freep(&device_name_src); + av_freep(&platforms); + av_freep(&devices); + return err; +} + +static int opencl_device_create(AVHWDeviceContext *hwdev, const char *device, + AVDictionary *opts, int flags) +{ + OpenCLDeviceSelector selector = { + .context = opts, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_platform, + .enumerate_devices = &opencl_enumerate_devices, + .filter_device = &opencl_filter_device, + }; + + if (device && device[0]) { + // Match one or both indices for platform and device. + int d = -1, p = -1, ret; + if (device[0] == '.') + ret = sscanf(device, ".%d", &d); + else + ret = sscanf(device, "%d.%d", &p, &d); + if (ret < 1) { + av_log(hwdev, AV_LOG_ERROR, "Invalid OpenCL platform/device " + "index specification \"%s\".\n", device); + return AVERROR(EINVAL); + } + selector.platform_index = p; + selector.device_index = d; + } else { + selector.platform_index = -1; + selector.device_index = -1; + } + + return opencl_device_create_internal(hwdev, &selector, NULL); +} + +static int opencl_device_init(AVHWDeviceContext *hwdev) +{ + AVOpenCLDeviceContext *hwctx = hwdev->hwctx; + OpenCLDeviceContext *priv = hwdev->internal->priv; + cl_int cle; + + if (hwctx->command_queue) { + cle = clRetainCommandQueue(hwctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to retain external " + "command queue: %d.\n", cle); + return AVERROR(EIO); + } + priv->command_queue = hwctx->command_queue; + } else { + priv->command_queue = clCreateCommandQueue(hwctx->context, + hwctx->device_id, + 0, &cle); + if (!priv->command_queue) { + av_log(hwdev, AV_LOG_ERROR, "Failed to create internal " + "command queue: %d.\n", cle); + return AVERROR(EIO); + } + } + + cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_PLATFORM, + sizeof(priv->platform_id), &priv->platform_id, + NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to determine the OpenCL " + "platform containing the device.\n"); + return AVERROR(EIO); + } + +#define CL_FUNC(name, desc) do { \ + if (fail) \ + break; \ + priv->name = clGetExtensionFunctionAddressForPlatform( \ + priv->platform_id, #name); \ + if (!priv->name) { \ + av_log(hwdev, AV_LOG_VERBOSE, \ + desc " function not found (%s).\n", #name); \ + fail = 1; \ + } else { \ + av_log(hwdev, AV_LOG_VERBOSE, \ + desc " function found (%s).\n", #name); \ + } \ + } while (0) + +#if HAVE_OPENCL_DRM_BEIGNET + { + int fail = 0; + + CL_FUNC(clCreateImageFromFdINTEL, + "Beignet DRM to OpenCL image mapping"); + + if (fail) { + av_log(hwdev, AV_LOG_WARNING, "Beignet DRM to OpenCL " + "mapping not usable.\n"); + priv->beignet_drm_mapping_usable = 0; + } else { + priv->beignet_drm_mapping_usable = 1; + } + } +#endif + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + { + size_t props_size; + cl_context_properties *props = NULL; + VADisplay va_display; + const char *va_ext = "cl_intel_va_api_media_sharing"; + int i, fail = 0; + + if (!opencl_check_extension(hwdev, va_ext)) { + av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is " + "required for QSV to OpenCL mapping.\n", va_ext); + goto no_qsv; + } + + cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES, + 0, NULL, &props_size); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context " + "properties: %d.\n", cle); + goto no_qsv; + } + if (props_size == 0) { + av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be " + "enabled on context creation to use QSV to " + "OpenCL mapping.\n"); + goto no_qsv; + } + + props = av_malloc(props_size); + if (!props) + return AVERROR(ENOMEM); + + cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES, + props_size, props, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context " + "properties: %d.\n", cle); + goto no_qsv; + } + + va_display = NULL; + for (i = 0; i < (props_size / sizeof(*props) - 1); i++) { + if (props[i] == CL_CONTEXT_VA_API_DISPLAY_INTEL) { + va_display = (VADisplay)(intptr_t)props[i+1]; + break; + } + } + if (!va_display) { + av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be " + "enabled on context creation to use QSV to " + "OpenCL mapping.\n"); + goto no_qsv; + } + if (!vaDisplayIsValid(va_display)) { + av_log(hwdev, AV_LOG_VERBOSE, "A valid VADisplay is " + "required on context creation to use QSV to " + "OpenCL mapping.\n"); + goto no_qsv; + } + + CL_FUNC(clCreateFromVA_APIMediaSurfaceINTEL, + "Intel QSV to OpenCL mapping"); + CL_FUNC(clEnqueueAcquireVA_APIMediaSurfacesINTEL, + "Intel QSV in OpenCL acquire"); + CL_FUNC(clEnqueueReleaseVA_APIMediaSurfacesINTEL, + "Intel QSV in OpenCL release"); + + if (fail) { + no_qsv: + av_log(hwdev, AV_LOG_WARNING, "QSV to OpenCL mapping " + "not usable.\n"); + priv->qsv_mapping_usable = 0; + } else { + priv->qsv_mapping_usable = 1; + } + av_free(props); + } +#endif + +#if HAVE_OPENCL_DXVA2 + { + int fail = 0; + + CL_FUNC(clCreateFromDX9MediaSurfaceKHR, + "DXVA2 to OpenCL mapping"); + CL_FUNC(clEnqueueAcquireDX9MediaSurfacesKHR, + "DXVA2 in OpenCL acquire"); + CL_FUNC(clEnqueueReleaseDX9MediaSurfacesKHR, + "DXVA2 in OpenCL release"); + + if (fail) { + av_log(hwdev, AV_LOG_WARNING, "DXVA2 to OpenCL mapping " + "not usable.\n"); + priv->dxva2_mapping_usable = 0; + } else { + priv->dx9_media_adapter_type = CL_ADAPTER_D3D9EX_KHR; + priv->dxva2_mapping_usable = 1; + } + } +#endif + +#if HAVE_OPENCL_D3D11 + { + const char *d3d11_ext = "cl_khr_d3d11_sharing"; + const char *nv12_ext = "cl_intel_d3d11_nv12_media_sharing"; + int fail = 0; + + if (!opencl_check_extension(hwdev, d3d11_ext)) { + av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is " + "required for D3D11 to OpenCL mapping.\n", d3d11_ext); + fail = 1; + } else if (!opencl_check_extension(hwdev, nv12_ext)) { + av_log(hwdev, AV_LOG_VERBOSE, "The %s extension may be " + "required for D3D11 to OpenCL mapping.\n", nv12_ext); + // Not fatal. + } + + CL_FUNC(clCreateFromD3D11Texture2DKHR, + "D3D11 to OpenCL mapping"); + CL_FUNC(clEnqueueAcquireD3D11ObjectsKHR, + "D3D11 in OpenCL acquire"); + CL_FUNC(clEnqueueReleaseD3D11ObjectsKHR, + "D3D11 in OpenCL release"); + + if (fail) { + av_log(hwdev, AV_LOG_WARNING, "D3D11 to OpenCL mapping " + "not usable.\n"); + priv->d3d11_mapping_usable = 0; + } else { + priv->d3d11_mapping_usable = 1; + } + } +#endif + +#if HAVE_OPENCL_DRM_ARM + { + const char *drm_arm_ext = "cl_arm_import_memory"; + const char *image_ext = "cl_khr_image2d_from_buffer"; + int fail = 0; + + if (!opencl_check_extension(hwdev, drm_arm_ext)) { + av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is " + "required for DRM to OpenCL mapping on ARM.\n", + drm_arm_ext); + fail = 1; + } + if (!opencl_check_extension(hwdev, image_ext)) { + av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is " + "required for DRM to OpenCL mapping on ARM.\n", + image_ext); + fail = 1; + } + + // clImportMemoryARM() is linked statically. + + if (fail) { + av_log(hwdev, AV_LOG_WARNING, "DRM to OpenCL mapping on ARM " + "not usable.\n"); + priv->drm_arm_mapping_usable = 0; + } else { + priv->drm_arm_mapping_usable = 1; + } + } +#endif + +#undef CL_FUNC + + return 0; +} + +static void opencl_device_uninit(AVHWDeviceContext *hwdev) +{ + OpenCLDeviceContext *priv = hwdev->internal->priv; + cl_int cle; + + if (priv->command_queue) { + cle = clReleaseCommandQueue(priv->command_queue); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to release internal " + "command queue reference: %d.\n", cle); + } + priv->command_queue = NULL; + } +} + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA +static int opencl_filter_intel_media_vaapi_platform(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context) +{ + // This doesn't exist as a platform extension, so just test whether + // the function we will use for device enumeration exists. + + if (!clGetExtensionFunctionAddressForPlatform(platform_id, + "clGetDeviceIDsFromVA_APIMediaAdapterINTEL")) { + av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not export the " + "VAAPI device enumeration function.\n", platform_name); + return 1; + } else { + return 0; + } +} + +static int opencl_enumerate_intel_media_vaapi_devices(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + cl_uint *nb_devices, + cl_device_id **devices, + void *context) +{ + VADisplay va_display = context; + clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn + clGetDeviceIDsFromVA_APIMediaAdapterINTEL; + cl_int cle; + + clGetDeviceIDsFromVA_APIMediaAdapterINTEL = + clGetExtensionFunctionAddressForPlatform(platform_id, + "clGetDeviceIDsFromVA_APIMediaAdapterINTEL"); + if (!clGetDeviceIDsFromVA_APIMediaAdapterINTEL) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get address of " + "clGetDeviceIDsFromVA_APIMediaAdapterINTEL().\n"); + return AVERROR_UNKNOWN; + } + + cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL( + platform_id, CL_VA_API_DISPLAY_INTEL, va_display, + CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, 0, NULL, nb_devices); + if (cle == CL_DEVICE_NOT_FOUND) { + av_log(hwdev, AV_LOG_DEBUG, "No VAAPI-supporting devices found " + "on platform \"%s\".\n", platform_name); + *nb_devices = 0; + return 0; + } else if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices " + "on platform \"%s\": %d.\n", platform_name, cle); + return AVERROR_UNKNOWN; + } + + *devices = av_malloc_array(*nb_devices, sizeof(**devices)); + if (!*devices) + return AVERROR(ENOMEM); + + cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL( + platform_id, CL_VA_API_DISPLAY_INTEL, va_display, + CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, *nb_devices, *devices, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get list of VAAPI-supporting " + "devices on platform \"%s\": %d.\n", platform_name, cle); + av_freep(devices); + return AVERROR_UNKNOWN; + } + + return 0; +} + +static int opencl_filter_intel_media_vaapi_device(AVHWDeviceContext *hwdev, + cl_device_id device_id, + const char *device_name, + void *context) +{ + const char *va_ext = "cl_intel_va_api_media_sharing"; + + if (opencl_check_device_extension(device_id, va_ext)) { + return 0; + } else { + av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the " + "%s extension.\n", device_name, va_ext); + return 1; + } +} +#endif + +#if HAVE_OPENCL_DXVA2 +static int opencl_filter_dxva2_platform(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context) +{ + const char *dx9_ext = "cl_khr_dx9_media_sharing"; + + if (opencl_check_platform_extension(platform_id, dx9_ext)) { + return 0; + } else { + av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the " + "%s extension.\n", platform_name, dx9_ext); + return 1; + } +} + +static int opencl_enumerate_dxva2_devices(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + cl_uint *nb_devices, + cl_device_id **devices, + void *context) +{ + IDirect3DDevice9 *device = context; + clGetDeviceIDsFromDX9MediaAdapterKHR_fn + clGetDeviceIDsFromDX9MediaAdapterKHR; + cl_dx9_media_adapter_type_khr media_adapter_type = CL_ADAPTER_D3D9EX_KHR; + cl_int cle; + + clGetDeviceIDsFromDX9MediaAdapterKHR = + clGetExtensionFunctionAddressForPlatform(platform_id, + "clGetDeviceIDsFromDX9MediaAdapterKHR"); + if (!clGetDeviceIDsFromDX9MediaAdapterKHR) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get address of " + "clGetDeviceIDsFromDX9MediaAdapterKHR().\n"); + return AVERROR_UNKNOWN; + } + + cle = clGetDeviceIDsFromDX9MediaAdapterKHR( + platform_id, 1, &media_adapter_type, (void**)&device, + CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR, + 0, NULL, nb_devices); + if (cle == CL_DEVICE_NOT_FOUND) { + av_log(hwdev, AV_LOG_DEBUG, "No DXVA2-supporting devices found " + "on platform \"%s\".\n", platform_name); + *nb_devices = 0; + return 0; + } else if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices " + "on platform \"%s\": %d.\n", platform_name, cle); + return AVERROR_UNKNOWN; + } + + *devices = av_malloc_array(*nb_devices, sizeof(**devices)); + if (!*devices) + return AVERROR(ENOMEM); + + cle = clGetDeviceIDsFromDX9MediaAdapterKHR( + platform_id, 1, &media_adapter_type, (void**)&device, + CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR, + *nb_devices, *devices, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get list of DXVA2-supporting " + "devices on platform \"%s\": %d.\n", platform_name, cle); + av_freep(devices); + return AVERROR_UNKNOWN; + } + + return 0; +} +#endif + +#if HAVE_OPENCL_D3D11 +static int opencl_filter_d3d11_platform(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context) +{ + const char *d3d11_ext = "cl_khr_d3d11_sharing"; + + if (opencl_check_platform_extension(platform_id, d3d11_ext)) { + return 0; + } else { + av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the " + "%s extension.\n", platform_name, d3d11_ext); + return 1; + } +} + +static int opencl_enumerate_d3d11_devices(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + cl_uint *nb_devices, + cl_device_id **devices, + void *context) +{ + ID3D11Device *device = context; + clGetDeviceIDsFromD3D11KHR_fn clGetDeviceIDsFromD3D11KHR; + cl_int cle; + + clGetDeviceIDsFromD3D11KHR = + clGetExtensionFunctionAddressForPlatform(platform_id, + "clGetDeviceIDsFromD3D11KHR"); + if (!clGetDeviceIDsFromD3D11KHR) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get address of " + "clGetDeviceIDsFromD3D11KHR().\n"); + return AVERROR_UNKNOWN; + } + + cle = clGetDeviceIDsFromD3D11KHR(platform_id, + CL_D3D11_DEVICE_KHR, device, + CL_PREFERRED_DEVICES_FOR_D3D11_KHR, + 0, NULL, nb_devices); + if (cle == CL_DEVICE_NOT_FOUND) { + av_log(hwdev, AV_LOG_DEBUG, "No D3D11-supporting devices found " + "on platform \"%s\".\n", platform_name); + *nb_devices = 0; + return 0; + } else if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices " + "on platform \"%s\": %d.\n", platform_name, cle); + return AVERROR_UNKNOWN; + } + + *devices = av_malloc_array(*nb_devices, sizeof(**devices)); + if (!*devices) + return AVERROR(ENOMEM); + + cle = clGetDeviceIDsFromD3D11KHR(platform_id, + CL_D3D11_DEVICE_KHR, device, + CL_PREFERRED_DEVICES_FOR_D3D11_KHR, + *nb_devices, *devices, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get list of D3D11-supporting " + "devices on platform \"%s\": %d.\n", platform_name, cle); + av_freep(devices); + return AVERROR_UNKNOWN; + } + + return 0; +} +#endif + +#if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11 +static int opencl_filter_gpu_device(AVHWDeviceContext *hwdev, + cl_device_id device_id, + const char *device_name, + void *context) +{ + cl_device_type device_type; + cl_int cle; + + cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE, + sizeof(device_type), &device_type, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query device type " + "of device \"%s\".\n", device_name); + return AVERROR_UNKNOWN; + } + if (!(device_type & CL_DEVICE_TYPE_GPU)) { + av_log(hwdev, AV_LOG_DEBUG, "Device %s skipped (not GPU).\n", + device_name); + return 1; + } + + return 0; +} +#endif + +#if HAVE_OPENCL_DRM_ARM +static int opencl_filter_drm_arm_platform(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context) +{ + const char *drm_arm_ext = "cl_arm_import_memory"; + + if (opencl_check_platform_extension(platform_id, drm_arm_ext)) { + return 0; + } else { + av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the " + "%s extension.\n", platform_name, drm_arm_ext); + return 1; + } +} + +static int opencl_filter_drm_arm_device(AVHWDeviceContext *hwdev, + cl_device_id device_id, + const char *device_name, + void *context) +{ + const char *drm_arm_ext = "cl_arm_import_memory"; + + if (opencl_check_device_extension(device_id, drm_arm_ext)) { + return 0; + } else { + av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the " + "%s extension.\n", device_name, drm_arm_ext); + return 1; + } +} +#endif + +static int opencl_device_derive(AVHWDeviceContext *hwdev, + AVHWDeviceContext *src_ctx, + int flags) +{ + int err; + switch (src_ctx->type) { + +#if HAVE_OPENCL_DRM_BEIGNET + case AV_HWDEVICE_TYPE_DRM: + case AV_HWDEVICE_TYPE_VAAPI: + { + // Surface mapping works via DRM PRIME fds with no special + // initialisation required in advance. This just finds the + // Beignet ICD by name. + AVDictionary *opts = NULL; + + err = av_dict_set(&opts, "platform_vendor", "Intel", 0); + if (err >= 0) + err = av_dict_set(&opts, "platform_version", "beignet", 0); + if (err >= 0) { + OpenCLDeviceSelector selector = { + .platform_index = -1, + .device_index = 0, + .context = opts, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_platform, + .enumerate_devices = &opencl_enumerate_devices, + .filter_device = NULL, + }; + err = opencl_device_create_internal(hwdev, &selector, NULL); + } + av_dict_free(&opts); + } + break; +#endif + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + // The generic code automatically attempts to derive from all + // ancestors of the given device, so we can ignore QSV devices here + // and just consider the inner VAAPI device it was derived from. + case AV_HWDEVICE_TYPE_VAAPI: + { + AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx; + cl_context_properties props[7] = { + CL_CONTEXT_PLATFORM, + 0, + CL_CONTEXT_VA_API_DISPLAY_INTEL, + (intptr_t)src_hwctx->display, + CL_CONTEXT_INTEROP_USER_SYNC, + CL_FALSE, + 0, + }; + OpenCLDeviceSelector selector = { + .platform_index = -1, + .device_index = -1, + .context = src_hwctx->display, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_intel_media_vaapi_platform, + .enumerate_devices = &opencl_enumerate_intel_media_vaapi_devices, + .filter_device = &opencl_filter_intel_media_vaapi_device, + }; + + err = opencl_device_create_internal(hwdev, &selector, props); + } + break; +#endif + +#if HAVE_OPENCL_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + { + AVDXVA2DeviceContext *src_hwctx = src_ctx->hwctx; + IDirect3DDevice9 *device; + HANDLE device_handle; + HRESULT hr; + + hr = IDirect3DDeviceManager9_OpenDeviceHandle(src_hwctx->devmgr, + &device_handle); + if (FAILED(hr)) { + av_log(hwdev, AV_LOG_ERROR, "Failed to open device handle " + "for Direct3D9 device: %lx.\n", (unsigned long)hr); + err = AVERROR_UNKNOWN; + break; + } + + hr = IDirect3DDeviceManager9_LockDevice(src_hwctx->devmgr, + device_handle, + &device, FALSE); + if (SUCCEEDED(hr)) { + cl_context_properties props[5] = { + CL_CONTEXT_PLATFORM, + 0, + CL_CONTEXT_ADAPTER_D3D9EX_KHR, + (intptr_t)device, + 0, + }; + OpenCLDeviceSelector selector = { + .platform_index = -1, + .device_index = -1, + .context = device, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_dxva2_platform, + .enumerate_devices = &opencl_enumerate_dxva2_devices, + .filter_device = &opencl_filter_gpu_device, + }; + + err = opencl_device_create_internal(hwdev, &selector, props); + + IDirect3DDeviceManager9_UnlockDevice(src_hwctx->devmgr, + device_handle, FALSE); + } else { + av_log(hwdev, AV_LOG_ERROR, "Failed to lock device handle " + "for Direct3D9 device: %lx.\n", (unsigned long)hr); + err = AVERROR_UNKNOWN; + } + + IDirect3DDeviceManager9_CloseDeviceHandle(src_hwctx->devmgr, + device_handle); + } + break; +#endif + +#if HAVE_OPENCL_D3D11 + case AV_HWDEVICE_TYPE_D3D11VA: + { + AVD3D11VADeviceContext *src_hwctx = src_ctx->hwctx; + cl_context_properties props[5] = { + CL_CONTEXT_PLATFORM, + 0, + CL_CONTEXT_D3D11_DEVICE_KHR, + (intptr_t)src_hwctx->device, + 0, + }; + OpenCLDeviceSelector selector = { + .platform_index = -1, + .device_index = -1, + .context = src_hwctx->device, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_d3d11_platform, + .enumerate_devices = &opencl_enumerate_d3d11_devices, + .filter_device = &opencl_filter_gpu_device, + }; + + err = opencl_device_create_internal(hwdev, &selector, props); + } + break; +#endif + +#if HAVE_OPENCL_DRM_ARM + case AV_HWDEVICE_TYPE_DRM: + { + OpenCLDeviceSelector selector = { + .platform_index = -1, + .device_index = -1, + .context = NULL, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_drm_arm_platform, + .enumerate_devices = &opencl_enumerate_devices, + .filter_device = &opencl_filter_drm_arm_device, + }; + + err = opencl_device_create_internal(hwdev, &selector, NULL); + } + break; +#endif + + default: + err = AVERROR(ENOSYS); + break; + } + + return err; +} + +static int opencl_get_plane_format(enum AVPixelFormat pixfmt, + int plane, int width, int height, + cl_image_format *image_format, + cl_image_desc *image_desc) +{ + const AVPixFmtDescriptor *desc; + const AVComponentDescriptor *comp; + int channels = 0, order = 0, depth = 0, step = 0; + int wsub, hsub, alpha; + int c; + + if (plane >= AV_NUM_DATA_POINTERS) + return AVERROR(ENOENT); + + desc = av_pix_fmt_desc_get(pixfmt); + + // Only normal images are allowed. + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | + AV_PIX_FMT_FLAG_HWACCEL | + AV_PIX_FMT_FLAG_PAL)) + return AVERROR(EINVAL); + + wsub = 1 << desc->log2_chroma_w; + hsub = 1 << desc->log2_chroma_h; + // Subsampled components must be exact. + if (width & wsub - 1 || height & hsub - 1) + return AVERROR(EINVAL); + + for (c = 0; c < desc->nb_components; c++) { + comp = &desc->comp[c]; + if (comp->plane != plane) + continue; + // The step size must be a power of two. + if (comp->step != 1 && comp->step != 2 && + comp->step != 4 && comp->step != 8) + return AVERROR(EINVAL); + // The bits in each component must be packed in the + // most-significant-bits of the relevant bytes. + if (comp->shift + comp->depth != 8 && + comp->shift + comp->depth != 16) + return AVERROR(EINVAL); + // The depth must not vary between components. + if (depth && comp->depth != depth) + return AVERROR(EINVAL); + // If a single data element crosses multiple bytes then + // it must match the native endianness. + if (comp->depth > 8 && + HAVE_BIGENDIAN == !(desc->flags & AV_PIX_FMT_FLAG_BE)) + return AVERROR(EINVAL); + // A single data element must not contain multiple samples + // from the same component. + if (step && comp->step != step) + return AVERROR(EINVAL); + + depth = comp->depth; + order = order * 10 + comp->offset / ((depth + 7) / 8) + 1; + step = comp->step; + alpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA && + c == desc->nb_components - 1); + ++channels; + } + if (channels == 0) + return AVERROR(ENOENT); + + memset(image_format, 0, sizeof(*image_format)); + memset(image_desc, 0, sizeof(*image_desc)); + image_desc->image_type = CL_MEM_OBJECT_IMAGE2D; + + if (plane == 0 || alpha) { + image_desc->image_width = width; + image_desc->image_height = height; + image_desc->image_row_pitch = step * width; + } else { + image_desc->image_width = width / wsub; + image_desc->image_height = height / hsub; + image_desc->image_row_pitch = step * width / wsub; + } + + if (depth <= 8) { + image_format->image_channel_data_type = CL_UNORM_INT8; + } else { + if (depth <= 16) + image_format->image_channel_data_type = CL_UNORM_INT16; + else + return AVERROR(EINVAL); + } + +#define CHANNEL_ORDER(order, type) \ + case order: image_format->image_channel_order = type; break; + switch (order) { + CHANNEL_ORDER(1, CL_R); + CHANNEL_ORDER(12, CL_RG); + CHANNEL_ORDER(1234, CL_RGBA); + CHANNEL_ORDER(2341, CL_ARGB); + CHANNEL_ORDER(3214, CL_BGRA); +#ifdef CL_ABGR + CHANNEL_ORDER(4321, CL_ABGR); +#endif + default: + return AVERROR(EINVAL); + } +#undef CHANNEL_ORDER + + return 0; +} + +static int opencl_frames_get_constraints(AVHWDeviceContext *hwdev, + const void *hwconfig, + AVHWFramesConstraints *constraints) +{ + AVOpenCLDeviceContext *hwctx = hwdev->hwctx; + cl_uint nb_image_formats; + cl_image_format *image_formats = NULL; + cl_int cle; + enum AVPixelFormat pix_fmt; + int err, pix_fmts_found; + size_t max_width, max_height; + + cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_WIDTH, + sizeof(max_width), &max_width, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum " + "supported image width: %d.\n", cle); + } else { + constraints->max_width = max_width; + } + cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_HEIGHT, + sizeof(max_height), &max_height, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum " + "supported image height: %d.\n", cle); + } else { + constraints->max_height = max_height; + } + av_log(hwdev, AV_LOG_DEBUG, "Maximum supported image size %dx%d.\n", + constraints->max_width, constraints->max_height); + + cle = clGetSupportedImageFormats(hwctx->context, + CL_MEM_READ_WRITE, + CL_MEM_OBJECT_IMAGE2D, + 0, NULL, &nb_image_formats); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query supported " + "image formats: %d.\n", cle); + err = AVERROR(ENOSYS); + goto fail; + } + if (nb_image_formats == 0) { + av_log(hwdev, AV_LOG_ERROR, "No image support in OpenCL " + "driver (zero supported image formats).\n"); + err = AVERROR(ENOSYS); + goto fail; + } + + image_formats = + av_malloc_array(nb_image_formats, sizeof(*image_formats)); + if (!image_formats) { + err = AVERROR(ENOMEM); + goto fail; + } + + cle = clGetSupportedImageFormats(hwctx->context, + CL_MEM_READ_WRITE, + CL_MEM_OBJECT_IMAGE2D, + nb_image_formats, + image_formats, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query supported " + "image formats: %d.\n", cle); + err = AVERROR(ENOSYS); + goto fail; + } + + pix_fmts_found = 0; + for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) { + cl_image_format image_format; + cl_image_desc image_desc; + int plane, i; + + for (plane = 0;; plane++) { + err = opencl_get_plane_format(pix_fmt, plane, 0, 0, + &image_format, + &image_desc); + if (err < 0) + break; + + for (i = 0; i < nb_image_formats; i++) { + if (image_formats[i].image_channel_order == + image_format.image_channel_order && + image_formats[i].image_channel_data_type == + image_format.image_channel_data_type) + break; + } + if (i == nb_image_formats) { + err = AVERROR(EINVAL); + break; + } + } + if (err != AVERROR(ENOENT)) + continue; + + av_log(hwdev, AV_LOG_DEBUG, "Format %s supported.\n", + av_get_pix_fmt_name(pix_fmt)); + + err = av_reallocp_array(&constraints->valid_sw_formats, + pix_fmts_found + 2, + sizeof(*constraints->valid_sw_formats)); + if (err < 0) + goto fail; + constraints->valid_sw_formats[pix_fmts_found] = pix_fmt; + constraints->valid_sw_formats[pix_fmts_found + 1] = + AV_PIX_FMT_NONE; + ++pix_fmts_found; + } + + av_freep(&image_formats); + + constraints->valid_hw_formats = + av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); + if (!constraints->valid_hw_formats) { + err = AVERROR(ENOMEM); + goto fail; + } + constraints->valid_hw_formats[0] = AV_PIX_FMT_OPENCL; + constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; + + return 0; + +fail: + av_freep(&image_formats); + return err; +} + +static void opencl_pool_free(void *opaque, uint8_t *data) +{ + AVHWFramesContext *hwfc = opaque; + AVOpenCLFrameDescriptor *desc = (AVOpenCLFrameDescriptor*)data; + cl_int cle; + int p; + + for (p = 0; p < desc->nb_planes; p++) { + cle = clReleaseMemObject(desc->planes[p]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release plane %d: " + "%d.\n", p, cle); + } + } + + av_free(desc); +} + +static AVBufferRef *opencl_pool_alloc(void *opaque, int size) +{ + AVHWFramesContext *hwfc = opaque; + AVOpenCLDeviceContext *hwctx = hwfc->device_ctx->hwctx; + AVOpenCLFrameDescriptor *desc; + cl_int cle; + cl_mem image; + cl_image_format image_format; + cl_image_desc image_desc; + int err, p; + AVBufferRef *ref; + + desc = av_mallocz(sizeof(*desc)); + if (!desc) + return NULL; + + for (p = 0;; p++) { + err = opencl_get_plane_format(hwfc->sw_format, p, + hwfc->width, hwfc->height, + &image_format, &image_desc); + if (err == AVERROR(ENOENT)) + break; + if (err < 0) + goto fail; + + // For generic image objects, the pitch is determined by the + // implementation. + image_desc.image_row_pitch = 0; + + image = clCreateImage(hwctx->context, CL_MEM_READ_WRITE, + &image_format, &image_desc, NULL, &cle); + if (!image) { + av_log(hwfc, AV_LOG_ERROR, "Failed to create image for " + "plane %d: %d.\n", p, cle); + goto fail; + } + + desc->planes[p] = image; + } + + desc->nb_planes = p; + + ref = av_buffer_create((uint8_t*)desc, sizeof(*desc), + &opencl_pool_free, hwfc, 0); + if (!ref) + goto fail; + + return ref; + +fail: + for (p = 0; desc->planes[p]; p++) + clReleaseMemObject(desc->planes[p]); + av_free(desc); + return NULL; +} + +static int opencl_frames_init_command_queue(AVHWFramesContext *hwfc) +{ + AVOpenCLFramesContext *hwctx = hwfc->hwctx; + OpenCLDeviceContext *devpriv = hwfc->device_ctx->internal->priv; + OpenCLFramesContext *priv = hwfc->internal->priv; + cl_int cle; + + priv->command_queue = hwctx->command_queue ? hwctx->command_queue + : devpriv->command_queue; + cle = clRetainCommandQueue(priv->command_queue); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to retain frame " + "command queue: %d.\n", cle); + return AVERROR(EIO); + } + + return 0; +} + +static int opencl_frames_init(AVHWFramesContext *hwfc) +{ + if (!hwfc->pool) { + hwfc->internal->pool_internal = + av_buffer_pool_init2(sizeof(cl_mem), hwfc, + &opencl_pool_alloc, NULL); + if (!hwfc->internal->pool_internal) + return AVERROR(ENOMEM); + } + + return opencl_frames_init_command_queue(hwfc); +} + +static void opencl_frames_uninit(AVHWFramesContext *hwfc) +{ + OpenCLFramesContext *priv = hwfc->internal->priv; + cl_int cle; + +#if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11 + int i, p; + for (i = 0; i < priv->nb_mapped_frames; i++) { + AVOpenCLFrameDescriptor *desc = &priv->mapped_frames[i]; + for (p = 0; p < desc->nb_planes; p++) { + cle = clReleaseMemObject(desc->planes[p]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release mapped " + "frame object (frame %d plane %d): %d.\n", + i, p, cle); + } + } + } + av_freep(&priv->mapped_frames); +#endif + + if (priv->command_queue) { + cle = clReleaseCommandQueue(priv->command_queue); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release frame " + "command queue: %d.\n", cle); + } + priv->command_queue = NULL; + } +} + +static int opencl_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) +{ + AVOpenCLFrameDescriptor *desc; + int p; + + frame->buf[0] = av_buffer_pool_get(hwfc->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + + desc = (AVOpenCLFrameDescriptor*)frame->buf[0]->data; + + for (p = 0; p < desc->nb_planes; p++) + frame->data[p] = (uint8_t*)desc->planes[p]; + + frame->format = AV_PIX_FMT_OPENCL; + frame->width = hwfc->width; + frame->height = hwfc->height; + + return 0; +} + +static int opencl_transfer_get_formats(AVHWFramesContext *hwfc, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ + enum AVPixelFormat *fmts; + + fmts = av_malloc_array(2, sizeof(*fmts)); + if (!fmts) + return AVERROR(ENOMEM); + + fmts[0] = hwfc->sw_format; + fmts[1] = AV_PIX_FMT_NONE; + + *formats = fmts; + return 0; +} + +static int opencl_wait_events(AVHWFramesContext *hwfc, + cl_event *events, int nb_events) +{ + cl_int cle; + int i; + + cle = clWaitForEvents(nb_events, events); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to wait for event " + "completion: %d.\n", cle); + return AVERROR(EIO); + } + + for (i = 0; i < nb_events; i++) { + cle = clReleaseEvent(events[i]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release " + "event: %d.\n", cle); + } + } + + return 0; +} + +static int opencl_transfer_data_from(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src) +{ + OpenCLFramesContext *priv = hwfc->internal->priv; + cl_image_format image_format; + cl_image_desc image_desc; + cl_int cle; + size_t origin[3] = { 0, 0, 0 }; + size_t region[3]; + cl_event events[AV_NUM_DATA_POINTERS]; + int err, p; + + if (dst->format != hwfc->sw_format) + return AVERROR(EINVAL); + + for (p = 0;; p++) { + err = opencl_get_plane_format(hwfc->sw_format, p, + src->width, src->height, + &image_format, &image_desc); + if (err < 0) { + if (err == AVERROR(ENOENT)) + err = 0; + break; + } + + if (!dst->data[p]) { + av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on " + "destination frame for transfer.\n", p); + err = AVERROR(EINVAL); + break; + } + + region[0] = image_desc.image_width; + region[1] = image_desc.image_height; + region[2] = 1; + + cle = clEnqueueReadImage(priv->command_queue, + (cl_mem)src->data[p], + CL_FALSE, origin, region, + dst->linesize[p], 0, + dst->data[p], + 0, NULL, &events[p]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue read of " + "OpenCL image plane %d: %d.\n", p, cle); + err = AVERROR(EIO); + break; + } + } + + opencl_wait_events(hwfc, events, p); + + return err; +} + +static int opencl_transfer_data_to(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src) +{ + OpenCLFramesContext *priv = hwfc->internal->priv; + cl_image_format image_format; + cl_image_desc image_desc; + cl_int cle; + size_t origin[3] = { 0, 0, 0 }; + size_t region[3]; + cl_event events[AV_NUM_DATA_POINTERS]; + int err, p; + + if (src->format != hwfc->sw_format) + return AVERROR(EINVAL); + + for (p = 0;; p++) { + err = opencl_get_plane_format(hwfc->sw_format, p, + src->width, src->height, + &image_format, &image_desc); + if (err < 0) { + if (err == AVERROR(ENOENT)) + err = 0; + break; + } + + if (!src->data[p]) { + av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on " + "source frame for transfer.\n", p); + err = AVERROR(EINVAL); + break; + } + + region[0] = image_desc.image_width; + region[1] = image_desc.image_height; + region[2] = 1; + + cle = clEnqueueWriteImage(priv->command_queue, + (cl_mem)dst->data[p], + CL_FALSE, origin, region, + src->linesize[p], 0, + src->data[p], + 0, NULL, &events[p]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue write of " + "OpenCL image plane %d: %d.\n", p, cle); + err = AVERROR(EIO); + break; + } + } + + opencl_wait_events(hwfc, events, p); + + return err; +} + +typedef struct OpenCLMapping { + // The mapped addresses for each plane. + // The destination frame is not available when we unmap, so these + // need to be stored separately. + void *address[AV_NUM_DATA_POINTERS]; +} OpenCLMapping; + +static void opencl_unmap_frame(AVHWFramesContext *hwfc, + HWMapDescriptor *hwmap) +{ + OpenCLFramesContext *priv = hwfc->internal->priv; + OpenCLMapping *map = hwmap->priv; + cl_event events[AV_NUM_DATA_POINTERS]; + int p, e; + cl_int cle; + + for (p = e = 0; p < FF_ARRAY_ELEMS(map->address); p++) { + if (!map->address[p]) + break; + + cle = clEnqueueUnmapMemObject(priv->command_queue, + (cl_mem)hwmap->source->data[p], + map->address[p], + 0, NULL, &events[e]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to unmap OpenCL " + "image plane %d: %d.\n", p, cle); + } + ++e; + } + + opencl_wait_events(hwfc, events, e); + + av_free(map); +} + +static int opencl_map_frame(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + OpenCLFramesContext *priv = hwfc->internal->priv; + cl_map_flags map_flags; + cl_image_format image_format; + cl_image_desc image_desc; + cl_int cle; + OpenCLMapping *map; + size_t origin[3] = { 0, 0, 0 }; + size_t region[3]; + size_t row_pitch; + cl_event events[AV_NUM_DATA_POINTERS]; + int err, p; + + av_assert0(hwfc->sw_format == dst->format); + + if (flags & AV_HWFRAME_MAP_OVERWRITE && + !(flags & AV_HWFRAME_MAP_READ)) { + // This is mutually exclusive with the read/write flags, so + // there is no way to map with read here. + map_flags = CL_MAP_WRITE_INVALIDATE_REGION; + } else { + map_flags = 0; + if (flags & AV_HWFRAME_MAP_READ) + map_flags |= CL_MAP_READ; + if (flags & AV_HWFRAME_MAP_WRITE) + map_flags |= CL_MAP_WRITE; + } + + map = av_mallocz(sizeof(*map)); + if (!map) + return AVERROR(ENOMEM); + + for (p = 0;; p++) { + err = opencl_get_plane_format(hwfc->sw_format, p, + src->width, src->height, + &image_format, &image_desc); + if (err == AVERROR(ENOENT)) + break; + if (err < 0) + goto fail; + + region[0] = image_desc.image_width; + region[1] = image_desc.image_height; + region[2] = 1; + + map->address[p] = + clEnqueueMapImage(priv->command_queue, + (cl_mem)src->data[p], + CL_FALSE, map_flags, origin, region, + &row_pitch, NULL, 0, NULL, + &events[p], &cle); + if (!map->address[p]) { + av_log(hwfc, AV_LOG_ERROR, "Failed to map OpenCL " + "image plane %d: %d.\n", p, cle); + err = AVERROR(EIO); + goto fail; + } + + dst->data[p] = map->address[p]; + + av_log(hwfc, AV_LOG_DEBUG, "Map plane %d (%p -> %p).\n", + p, src->data[p], dst->data[p]); + } + + err = opencl_wait_events(hwfc, events, p); + if (err < 0) + goto fail; + + err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, + &opencl_unmap_frame, map); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + for (p = 0; p < AV_NUM_DATA_POINTERS; p++) { + if (!map->address[p]) + break; + clEnqueueUnmapMemObject(priv->command_queue, + (cl_mem)src->data[p], + map->address[p], + 0, NULL, &events[p]); + } + if (p > 0) + opencl_wait_events(hwfc, events, p); + av_freep(&map); + return err; +} + +#if HAVE_OPENCL_DRM_BEIGNET + +typedef struct DRMBeignetToOpenCLMapping { + AVFrame *drm_frame; + AVDRMFrameDescriptor *drm_desc; + + AVOpenCLFrameDescriptor frame; +} DRMBeignetToOpenCLMapping; + +static void opencl_unmap_from_drm_beignet(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + DRMBeignetToOpenCLMapping *mapping = hwmap->priv; + cl_int cle; + int i; + + for (i = 0; i < mapping->frame.nb_planes; i++) { + cle = clReleaseMemObject(mapping->frame.planes[i]); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL image " + "of plane %d of DRM frame: %d.\n", i, cle); + } + } + + av_free(mapping); +} + +static int opencl_map_from_drm_beignet(AVHWFramesContext *dst_fc, + AVFrame *dst, const AVFrame *src, + int flags) +{ + AVOpenCLDeviceContext *hwctx = dst_fc->device_ctx->hwctx; + OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv; + DRMBeignetToOpenCLMapping *mapping; + const AVDRMFrameDescriptor *desc; + cl_int cle; + int err, i, j, p; + + desc = (const AVDRMFrameDescriptor*)src->data[0]; + + mapping = av_mallocz(sizeof(*mapping)); + if (!mapping) + return AVERROR(ENOMEM); + + p = 0; + for (i = 0; i < desc->nb_layers; i++) { + const AVDRMLayerDescriptor *layer = &desc->layers[i]; + for (j = 0; j < layer->nb_planes; j++) { + const AVDRMPlaneDescriptor *plane = &layer->planes[j]; + const AVDRMObjectDescriptor *object = + &desc->objects[plane->object_index]; + + cl_import_image_info_intel image_info = { + .fd = object->fd, + .size = object->size, + .type = CL_MEM_OBJECT_IMAGE2D, + .offset = plane->offset, + .row_pitch = plane->pitch, + }; + cl_image_desc image_desc; + + err = opencl_get_plane_format(dst_fc->sw_format, p, + src->width, src->height, + &image_info.fmt, + &image_desc); + if (err < 0) { + av_log(dst_fc, AV_LOG_ERROR, "DRM frame layer %d " + "plane %d is not representable in OpenCL: %d.\n", + i, j, err); + goto fail; + } + image_info.width = image_desc.image_width; + image_info.height = image_desc.image_height; + + mapping->frame.planes[p] = + priv->clCreateImageFromFdINTEL(hwctx->context, + &image_info, &cle); + if (!mapping->frame.planes[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image " + "from layer %d plane %d of DRM frame: %d.\n", + i, j, cle); + err = AVERROR(EIO); + goto fail; + } + + dst->data[p] = (uint8_t*)mapping->frame.planes[p]; + mapping->frame.nb_planes = ++p; + } + } + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &opencl_unmap_from_drm_beignet, + mapping); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + for (p = 0; p < mapping->frame.nb_planes; p++) { + if (mapping->frame.planes[p]) + clReleaseMemObject(mapping->frame.planes[p]); + } + av_free(mapping); + return err; +} + +#if HAVE_OPENCL_VAAPI_BEIGNET + +static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, + AVFrame *dst, const AVFrame *src, + int flags) +{ + AVFrame *tmp; + int err; + + tmp = av_frame_alloc(); + if (!tmp) + return AVERROR(ENOMEM); + + tmp->format = AV_PIX_FMT_DRM_PRIME; + + err = av_hwframe_map(tmp, src, flags); + if (err < 0) + goto fail; + + err = opencl_map_from_drm_beignet(dst_fc, dst, tmp, flags); + if (err < 0) + goto fail; + + err = ff_hwframe_map_replace(dst, src); + +fail: + av_frame_free(&tmp); + return err; +} + +#endif /* HAVE_OPENCL_VAAPI_BEIGNET */ +#endif /* HAVE_OPENCL_DRM_BEIGNET */ + +static inline cl_mem_flags opencl_mem_flags_for_mapping(int map_flags) +{ + if ((map_flags & AV_HWFRAME_MAP_READ) && + (map_flags & AV_HWFRAME_MAP_WRITE)) + return CL_MEM_READ_WRITE; + else if (map_flags & AV_HWFRAME_MAP_READ) + return CL_MEM_READ_ONLY; + else if (map_flags & AV_HWFRAME_MAP_WRITE) + return CL_MEM_WRITE_ONLY; + else + return 0; +} + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + +static void opencl_unmap_from_qsv(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + AVOpenCLFrameDescriptor *desc = hwmap->priv; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + cl_event event; + cl_int cle; + int p; + + av_log(dst_fc, AV_LOG_DEBUG, "Unmap QSV/VAAPI surface from OpenCL.\n"); + + cle = device_priv->clEnqueueReleaseVA_APIMediaSurfacesINTEL( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface " + "handles: %d.\n", cle); + } + + opencl_wait_events(dst_fc, &event, 1); + + for (p = 0; p < desc->nb_planes; p++) { + cle = clReleaseMemObject(desc->planes[p]); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL " + "image of plane %d of QSV/VAAPI surface: %d\n", + p, cle); + } + } + + av_free(desc); +} + +static int opencl_map_from_qsv(AVHWFramesContext *dst_fc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVHWFramesContext *src_fc = + (AVHWFramesContext*)src->hw_frames_ctx->data; + AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + AVOpenCLFrameDescriptor *desc; + VASurfaceID va_surface; + cl_mem_flags cl_flags; + cl_event event; + cl_int cle; + int err, p; + +#if CONFIG_LIBMFX + if (src->format == AV_PIX_FMT_QSV) { + mfxFrameSurface1 *mfx_surface = (mfxFrameSurface1*)src->data[3]; + va_surface = *(VASurfaceID*)mfx_surface->Data.MemId; + } else +#endif + if (src->format == AV_PIX_FMT_VAAPI) { + va_surface = (VASurfaceID)(uintptr_t)src->data[3]; + } else { + return AVERROR(ENOSYS); + } + + cl_flags = opencl_mem_flags_for_mapping(flags); + if (!cl_flags) + return AVERROR(EINVAL); + + av_log(src_fc, AV_LOG_DEBUG, "Map QSV/VAAPI surface %#x to " + "OpenCL.\n", va_surface); + + desc = av_mallocz(sizeof(*desc)); + if (!desc) + return AVERROR(ENOMEM); + + // The cl_intel_va_api_media_sharing extension only supports NV12 + // surfaces, so for now there are always exactly two planes. + desc->nb_planes = 2; + + for (p = 0; p < desc->nb_planes; p++) { + desc->planes[p] = + device_priv->clCreateFromVA_APIMediaSurfaceINTEL( + dst_dev->context, cl_flags, &va_surface, p, &cle); + if (!desc->planes[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL " + "image from plane %d of QSV/VAAPI surface " + "%#x: %d.\n", p, va_surface, cle); + err = AVERROR(EIO); + goto fail; + } + + dst->data[p] = (uint8_t*)desc->planes[p]; + } + + cle = device_priv->clEnqueueAcquireVA_APIMediaSurfacesINTEL( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface " + "handles: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + err = opencl_wait_events(dst_fc, &event, 1); + if (err < 0) + goto fail; + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &opencl_unmap_from_qsv, desc); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + for (p = 0; p < desc->nb_planes; p++) + if (desc->planes[p]) + clReleaseMemObject(desc->planes[p]); + av_freep(&desc); + return err; +} + +#endif + +#if HAVE_OPENCL_DXVA2 + +static void opencl_unmap_from_dxva2(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + AVOpenCLFrameDescriptor *desc = hwmap->priv; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv; + cl_event event; + cl_int cle; + + av_log(dst_fc, AV_LOG_DEBUG, "Unmap DXVA2 surface from OpenCL.\n"); + + cle = device_priv->clEnqueueReleaseDX9MediaSurfacesKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface " + "handle: %d.\n", cle); + return; + } + + opencl_wait_events(dst_fc, &event, 1); +} + +static int opencl_map_from_dxva2(AVHWFramesContext *dst_fc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVHWFramesContext *src_fc = + (AVHWFramesContext*)src->hw_frames_ctx->data; + AVDXVA2FramesContext *src_hwctx = src_fc->hwctx; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + AVOpenCLFrameDescriptor *desc; + cl_event event; + cl_int cle; + int err, i; + + av_log(dst_fc, AV_LOG_DEBUG, "Map DXVA2 surface %p to " + "OpenCL.\n", src->data[3]); + + for (i = 0; i < src_hwctx->nb_surfaces; i++) { + if (src_hwctx->surfaces[i] == (IDirect3DSurface9*)src->data[3]) + break; + } + if (i >= src_hwctx->nb_surfaces) { + av_log(dst_fc, AV_LOG_ERROR, "Trying to map from a surface which " + "is not in the mapped frames context.\n"); + return AVERROR(EINVAL); + } + + desc = &frames_priv->mapped_frames[i]; + + cle = device_priv->clEnqueueAcquireDX9MediaSurfacesKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface " + "handle: %d.\n", cle); + return AVERROR(EIO); + } + + err = opencl_wait_events(dst_fc, &event, 1); + if (err < 0) + goto fail; + + for (i = 0; i < desc->nb_planes; i++) + dst->data[i] = (uint8_t*)desc->planes[i]; + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &opencl_unmap_from_dxva2, desc); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + cle = device_priv->clEnqueueReleaseDX9MediaSurfacesKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle == CL_SUCCESS) + opencl_wait_events(dst_fc, &event, 1); + return err; +} + +static int opencl_frames_derive_from_dxva2(AVHWFramesContext *dst_fc, + AVHWFramesContext *src_fc, int flags) +{ + AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + AVDXVA2FramesContext *src_hwctx = src_fc->hwctx; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + cl_mem_flags cl_flags; + cl_int cle; + int err, i, p, nb_planes; + + if (src_fc->sw_format != AV_PIX_FMT_NV12) { + av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported " + "for DXVA2 to OpenCL mapping.\n"); + return AVERROR(EINVAL); + } + nb_planes = 2; + + if (src_fc->initial_pool_size == 0) { + av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported " + "for DXVA2 to OpenCL mapping.\n"); + return AVERROR(EINVAL); + } + + cl_flags = opencl_mem_flags_for_mapping(flags); + if (!cl_flags) + return AVERROR(EINVAL); + + frames_priv->nb_mapped_frames = src_hwctx->nb_surfaces; + + frames_priv->mapped_frames = + av_mallocz_array(frames_priv->nb_mapped_frames, + sizeof(*frames_priv->mapped_frames)); + if (!frames_priv->mapped_frames) + return AVERROR(ENOMEM); + + for (i = 0; i < frames_priv->nb_mapped_frames; i++) { + AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i]; + cl_dx9_surface_info_khr surface_info = { + .resource = src_hwctx->surfaces[i], + .shared_handle = NULL, + }; + desc->nb_planes = nb_planes; + for (p = 0; p < nb_planes; p++) { + desc->planes[p] = + device_priv->clCreateFromDX9MediaSurfaceKHR( + dst_dev->context, cl_flags, + device_priv->dx9_media_adapter_type, + &surface_info, p, &cle); + if (!desc->planes[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL " + "image from plane %d of DXVA2 surface %d: %d.\n", + p, i, cle); + err = AVERROR(EIO); + goto fail; + } + } + } + + return 0; + +fail: + for (i = 0; i < frames_priv->nb_mapped_frames; i++) { + AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i]; + for (p = 0; p < desc->nb_planes; p++) { + if (desc->planes[p]) + clReleaseMemObject(desc->planes[p]); + } + } + av_freep(&frames_priv->mapped_frames); + frames_priv->nb_mapped_frames = 0; + return err; +} + +#endif + +#if HAVE_OPENCL_D3D11 + +static void opencl_unmap_from_d3d11(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + AVOpenCLFrameDescriptor *desc = hwmap->priv; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv; + cl_event event; + cl_int cle; + + cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface " + "handle: %d.\n", cle); + } + + opencl_wait_events(dst_fc, &event, 1); +} + +static int opencl_map_from_d3d11(AVHWFramesContext *dst_fc, AVFrame *dst, + const AVFrame *src, int flags) +{ + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + AVOpenCLFrameDescriptor *desc; + cl_event event; + cl_int cle; + int err, index, i; + + index = (intptr_t)src->data[1]; + if (index >= frames_priv->nb_mapped_frames) { + av_log(dst_fc, AV_LOG_ERROR, "Texture array index out of range for " + "mapping: %d >= %d.\n", index, frames_priv->nb_mapped_frames); + return AVERROR(EINVAL); + } + + av_log(dst_fc, AV_LOG_DEBUG, "Map D3D11 texture %d to OpenCL.\n", + index); + + desc = &frames_priv->mapped_frames[index]; + + cle = device_priv->clEnqueueAcquireD3D11ObjectsKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface " + "handle: %d.\n", cle); + return AVERROR(EIO); + } + + err = opencl_wait_events(dst_fc, &event, 1); + if (err < 0) + goto fail; + + for (i = 0; i < desc->nb_planes; i++) + dst->data[i] = (uint8_t*)desc->planes[i]; + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &opencl_unmap_from_d3d11, desc); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle == CL_SUCCESS) + opencl_wait_events(dst_fc, &event, 1); + return err; +} + +static int opencl_frames_derive_from_d3d11(AVHWFramesContext *dst_fc, + AVHWFramesContext *src_fc, int flags) +{ + AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + AVD3D11VAFramesContext *src_hwctx = src_fc->hwctx; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + cl_mem_flags cl_flags; + cl_int cle; + int err, i, p, nb_planes; + + if (src_fc->sw_format != AV_PIX_FMT_NV12) { + av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported " + "for D3D11 to OpenCL mapping.\n"); + return AVERROR(EINVAL); + } + nb_planes = 2; + + if (src_fc->initial_pool_size == 0) { + av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported " + "for D3D11 to OpenCL mapping.\n"); + return AVERROR(EINVAL); + } + + cl_flags = opencl_mem_flags_for_mapping(flags); + if (!cl_flags) + return AVERROR(EINVAL); + + frames_priv->nb_mapped_frames = src_fc->initial_pool_size; + + frames_priv->mapped_frames = + av_mallocz_array(frames_priv->nb_mapped_frames, + sizeof(*frames_priv->mapped_frames)); + if (!frames_priv->mapped_frames) + return AVERROR(ENOMEM); + + for (i = 0; i < frames_priv->nb_mapped_frames; i++) { + AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i]; + desc->nb_planes = nb_planes; + for (p = 0; p < nb_planes; p++) { + UINT subresource = 2 * i + p; + + desc->planes[p] = + device_priv->clCreateFromD3D11Texture2DKHR( + dst_dev->context, cl_flags, src_hwctx->texture, + subresource, &cle); + if (!desc->planes[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL " + "image from plane %d of D3D texture " + "index %d (subresource %u): %d.\n", + p, i, (unsigned int)subresource, cle); + err = AVERROR(EIO); + goto fail; + } + } + } + + return 0; + +fail: + for (i = 0; i < frames_priv->nb_mapped_frames; i++) { + AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i]; + for (p = 0; p < desc->nb_planes; p++) { + if (desc->planes[p]) + clReleaseMemObject(desc->planes[p]); + } + } + av_freep(&frames_priv->mapped_frames); + frames_priv->nb_mapped_frames = 0; + return err; +} + +#endif + +#if HAVE_OPENCL_DRM_ARM + +typedef struct DRMARMtoOpenCLMapping { + int nb_objects; + cl_mem object_buffers[AV_DRM_MAX_PLANES]; + int nb_planes; + cl_mem plane_images[AV_DRM_MAX_PLANES]; +} DRMARMtoOpenCLMapping; + +static void opencl_unmap_from_drm_arm(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + DRMARMtoOpenCLMapping *mapping = hwmap->priv; + int i; + + for (i = 0; i < mapping->nb_planes; i++) + clReleaseMemObject(mapping->plane_images[i]); + + for (i = 0; i < mapping->nb_objects; i++) + clReleaseMemObject(mapping->object_buffers[i]); + + av_free(mapping); +} + +static int opencl_map_from_drm_arm(AVHWFramesContext *dst_fc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVHWFramesContext *src_fc = + (AVHWFramesContext*)src->hw_frames_ctx->data; + AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + const AVDRMFrameDescriptor *desc; + DRMARMtoOpenCLMapping *mapping = NULL; + cl_mem_flags cl_flags; + const cl_import_properties_arm props[3] = { + CL_IMPORT_TYPE_ARM, CL_IMPORT_TYPE_DMA_BUF_ARM, 0, + }; + cl_int cle; + int err, i, j; + + desc = (const AVDRMFrameDescriptor*)src->data[0]; + + cl_flags = opencl_mem_flags_for_mapping(flags); + if (!cl_flags) + return AVERROR(EINVAL); + + mapping = av_mallocz(sizeof(*mapping)); + if (!mapping) + return AVERROR(ENOMEM); + + mapping->nb_objects = desc->nb_objects; + for (i = 0; i < desc->nb_objects; i++) { + int fd = desc->objects[i].fd; + + av_log(dst_fc, AV_LOG_DEBUG, "Map DRM PRIME fd %d to OpenCL.\n", fd); + + if (desc->objects[i].format_modifier) { + av_log(dst_fc, AV_LOG_DEBUG, "Warning: object %d fd %d has " + "nonzero format modifier %"PRId64", result may not " + "be as expected.\n", i, fd, + desc->objects[i].format_modifier); + } + + mapping->object_buffers[i] = + clImportMemoryARM(dst_dev->context, cl_flags, props, + &fd, desc->objects[i].size, &cle); + if (!mapping->object_buffers[i]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL buffer " + "from object %d (fd %d, size %"SIZE_SPECIFIER") of DRM frame: %d.\n", + i, fd, desc->objects[i].size, cle); + err = AVERROR(EIO); + goto fail; + } + } + + mapping->nb_planes = 0; + for (i = 0; i < desc->nb_layers; i++) { + const AVDRMLayerDescriptor *layer = &desc->layers[i]; + + for (j = 0; j < layer->nb_planes; j++) { + const AVDRMPlaneDescriptor *plane = &layer->planes[j]; + cl_mem plane_buffer; + cl_image_format image_format; + cl_image_desc image_desc; + cl_buffer_region region; + int p = mapping->nb_planes; + + err = opencl_get_plane_format(src_fc->sw_format, p, + src_fc->width, src_fc->height, + &image_format, &image_desc); + if (err < 0) { + av_log(dst_fc, AV_LOG_ERROR, "Invalid plane %d (DRM " + "layer %d plane %d): %d.\n", p, i, j, err); + goto fail; + } + + region.origin = plane->offset; + region.size = image_desc.image_row_pitch * + image_desc.image_height; + + plane_buffer = + clCreateSubBuffer(mapping->object_buffers[plane->object_index], + cl_flags, + CL_BUFFER_CREATE_TYPE_REGION, + ®ion, &cle); + if (!plane_buffer) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create sub-buffer " + "for plane %d: %d.\n", p, cle); + err = AVERROR(EIO); + goto fail; + } + + image_desc.buffer = plane_buffer; + + mapping->plane_images[p] = + clCreateImage(dst_dev->context, cl_flags, + &image_format, &image_desc, NULL, &cle); + + // Unreference the sub-buffer immediately - we don't need it + // directly and a reference is held by the image. + clReleaseMemObject(plane_buffer); + + if (!mapping->plane_images[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create image " + "for plane %d: %d.\n", p, cle); + err = AVERROR(EIO); + goto fail; + } + + ++mapping->nb_planes; + } + } + + for (i = 0; i < mapping->nb_planes; i++) + dst->data[i] = (uint8_t*)mapping->plane_images[i]; + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &opencl_unmap_from_drm_arm, mapping); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + for (i = 0; i < mapping->nb_planes; i++) { + clReleaseMemObject(mapping->plane_images[i]); + } + for (i = 0; i < mapping->nb_objects; i++) { + if (mapping->object_buffers[i]) + clReleaseMemObject(mapping->object_buffers[i]); + } + av_free(mapping); + return err; +} + +#endif + +static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + av_assert0(src->format == AV_PIX_FMT_OPENCL); + if (hwfc->sw_format != dst->format) + return AVERROR(ENOSYS); + return opencl_map_frame(hwfc, dst, src, flags); +} + +static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + av_unused OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv; + av_assert0(dst->format == AV_PIX_FMT_OPENCL); + switch (src->format) { +#if HAVE_OPENCL_DRM_BEIGNET + case AV_PIX_FMT_DRM_PRIME: + if (priv->beignet_drm_mapping_usable) + return opencl_map_from_drm_beignet(hwfc, dst, src, flags); +#endif +#if HAVE_OPENCL_VAAPI_BEIGNET + case AV_PIX_FMT_VAAPI: + if (priv->beignet_drm_mapping_usable) + return opencl_map_from_vaapi(hwfc, dst, src, flags); +#endif +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + case AV_PIX_FMT_QSV: + case AV_PIX_FMT_VAAPI: + if (priv->qsv_mapping_usable) + return opencl_map_from_qsv(hwfc, dst, src, flags); +#endif +#if HAVE_OPENCL_DXVA2 + case AV_PIX_FMT_DXVA2_VLD: + if (priv->dxva2_mapping_usable) + return opencl_map_from_dxva2(hwfc, dst, src, flags); +#endif +#if HAVE_OPENCL_D3D11 + case AV_PIX_FMT_D3D11: + if (priv->d3d11_mapping_usable) + return opencl_map_from_d3d11(hwfc, dst, src, flags); +#endif +#if HAVE_OPENCL_DRM_ARM + case AV_PIX_FMT_DRM_PRIME: + if (priv->drm_arm_mapping_usable) + return opencl_map_from_drm_arm(hwfc, dst, src, flags); +#endif + } + return AVERROR(ENOSYS); +} + +static int opencl_frames_derive_to(AVHWFramesContext *dst_fc, + AVHWFramesContext *src_fc, int flags) +{ + av_unused OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv; + switch (src_fc->device_ctx->type) { +#if HAVE_OPENCL_DRM_BEIGNET + case AV_HWDEVICE_TYPE_DRM: + if (!priv->beignet_drm_mapping_usable) + return AVERROR(ENOSYS); + break; +#endif +#if HAVE_OPENCL_VAAPI_BEIGNET + case AV_HWDEVICE_TYPE_VAAPI: + if (!priv->beignet_drm_mapping_usable) + return AVERROR(ENOSYS); + break; +#endif +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + case AV_HWDEVICE_TYPE_QSV: + case AV_HWDEVICE_TYPE_VAAPI: + if (!priv->qsv_mapping_usable) + return AVERROR(ENOSYS); + break; +#endif +#if HAVE_OPENCL_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + if (!priv->dxva2_mapping_usable) + return AVERROR(ENOSYS); + { + int err; + err = opencl_frames_derive_from_dxva2(dst_fc, src_fc, flags); + if (err < 0) + return err; + } + break; +#endif +#if HAVE_OPENCL_D3D11 + case AV_HWDEVICE_TYPE_D3D11VA: + if (!priv->d3d11_mapping_usable) + return AVERROR(ENOSYS); + { + int err; + err = opencl_frames_derive_from_d3d11(dst_fc, src_fc, flags); + if (err < 0) + return err; + } + break; +#endif +#if HAVE_OPENCL_DRM_ARM + case AV_HWDEVICE_TYPE_DRM: + if (!priv->drm_arm_mapping_usable) + return AVERROR(ENOSYS); + break; +#endif + default: + return AVERROR(ENOSYS); + } + return opencl_frames_init_command_queue(dst_fc); +} + +const HWContextType ff_hwcontext_type_opencl = { + .type = AV_HWDEVICE_TYPE_OPENCL, + .name = "OpenCL", + + .device_hwctx_size = sizeof(AVOpenCLDeviceContext), + .device_priv_size = sizeof(OpenCLDeviceContext), + .frames_hwctx_size = sizeof(AVOpenCLFramesContext), + .frames_priv_size = sizeof(OpenCLFramesContext), + + .device_create = &opencl_device_create, + .device_derive = &opencl_device_derive, + .device_init = &opencl_device_init, + .device_uninit = &opencl_device_uninit, + + .frames_get_constraints = &opencl_frames_get_constraints, + .frames_init = &opencl_frames_init, + .frames_uninit = &opencl_frames_uninit, + .frames_get_buffer = &opencl_get_buffer, + + .transfer_get_formats = &opencl_transfer_get_formats, + .transfer_data_to = &opencl_transfer_data_to, + .transfer_data_from = &opencl_transfer_data_from, + + .map_from = &opencl_map_from, + .map_to = &opencl_map_to, + .frames_derive_to = &opencl_frames_derive_to, + + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_OPENCL, + AV_PIX_FMT_NONE + }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_opencl.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_opencl.h new file mode 100644 index 0000000000..ef54486c95 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_opencl.h @@ -0,0 +1,100 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_OPENCL_H +#define AVUTIL_HWCONTEXT_OPENCL_H + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include "frame.h" + +/** + * @file + * API-specific header for AV_HWDEVICE_TYPE_OPENCL. + * + * Pools allocated internally are always dynamic, and are primarily intended + * to be used in OpenCL-only cases. If interoperation is required, it is + * typically required to allocate frames in the other API and then map the + * frames context to OpenCL with av_hwframe_ctx_create_derived(). + */ + +/** + * OpenCL frame descriptor for pool allocation. + * + * In user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer pointing at an object of this type describing the + * planes of the frame. + */ +typedef struct AVOpenCLFrameDescriptor { + /** + * Number of planes in the frame. + */ + int nb_planes; + /** + * OpenCL image2d objects for each plane of the frame. + */ + cl_mem planes[AV_NUM_DATA_POINTERS]; +} AVOpenCLFrameDescriptor; + +/** + * OpenCL device details. + * + * Allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVOpenCLDeviceContext { + /** + * The primary device ID of the device. If multiple OpenCL devices + * are associated with the context then this is the one which will + * be used for all operations internal to FFmpeg. + */ + cl_device_id device_id; + /** + * The OpenCL context which will contain all operations and frames on + * this device. + */ + cl_context context; + /** + * The default command queue for this device, which will be used by all + * frames contexts which do not have their own command queue. If not + * intialised by the user, a default queue will be created on the + * primary device. + */ + cl_command_queue command_queue; +} AVOpenCLDeviceContext; + +/** + * OpenCL-specific data associated with a frame pool. + * + * Allocated as AVHWFramesContext.hwctx. + */ +typedef struct AVOpenCLFramesContext { + /** + * The command queue used for internal asynchronous operations on this + * device (av_hwframe_transfer_data(), av_hwframe_map()). + * + * If this is not set, the command queue from the associated device is + * used instead. + */ + cl_command_queue command_queue; +} AVOpenCLFramesContext; + +#endif /* AVUTIL_HWCONTEXT_OPENCL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_qsv.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_qsv.c new file mode 100644 index 0000000000..59e4ed9157 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_qsv.c @@ -0,0 +1,1278 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include + +#include "config.h" + +#if HAVE_PTHREADS +#include +#endif + +#if CONFIG_VAAPI +#include "hwcontext_vaapi.h" +#endif +#if CONFIG_DXVA2 +#include "hwcontext_dxva2.h" +#endif + +#include "buffer.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_internal.h" +#include "hwcontext_qsv.h" +#include "mem.h" +#include "pixfmt.h" +#include "pixdesc.h" +#include "time.h" + +typedef struct QSVDevicePriv { + AVBufferRef *child_device_ctx; +} QSVDevicePriv; + +typedef struct QSVDeviceContext { + mfxHDL handle; + mfxHandleType handle_type; + mfxVersion ver; + mfxIMPL impl; + + enum AVHWDeviceType child_device_type; + enum AVPixelFormat child_pix_fmt; +} QSVDeviceContext; + +typedef struct QSVFramesContext { + mfxSession session_download; + int session_download_init; + mfxSession session_upload; + int session_upload_init; +#if HAVE_PTHREADS + pthread_mutex_t session_lock; + pthread_cond_t session_cond; +#endif + + AVBufferRef *child_frames_ref; + mfxFrameSurface1 *surfaces_internal; + int nb_surfaces_used; + + // used in the frame allocator for non-opaque surfaces + mfxMemId *mem_ids; + // used in the opaque alloc request for opaque surfaces + mfxFrameSurface1 **surface_ptrs; + + mfxExtOpaqueSurfaceAlloc opaque_alloc; + mfxExtBuffer *ext_buffers[1]; +} QSVFramesContext; + +static const struct { + mfxHandleType handle_type; + enum AVHWDeviceType device_type; + enum AVPixelFormat pix_fmt; +} supported_handle_types[] = { +#if CONFIG_VAAPI + { MFX_HANDLE_VA_DISPLAY, AV_HWDEVICE_TYPE_VAAPI, AV_PIX_FMT_VAAPI }, +#endif +#if CONFIG_DXVA2 + { MFX_HANDLE_D3D9_DEVICE_MANAGER, AV_HWDEVICE_TYPE_DXVA2, AV_PIX_FMT_DXVA2_VLD }, +#endif + { 0 }, +}; + +static const struct { + enum AVPixelFormat pix_fmt; + uint32_t fourcc; +} supported_pixel_formats[] = { + { AV_PIX_FMT_NV12, MFX_FOURCC_NV12 }, + { AV_PIX_FMT_BGRA, MFX_FOURCC_RGB4 }, + { AV_PIX_FMT_P010, MFX_FOURCC_P010 }, + { AV_PIX_FMT_PAL8, MFX_FOURCC_P8 }, +}; + +static uint32_t qsv_fourcc_from_pix_fmt(enum AVPixelFormat pix_fmt) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(supported_pixel_formats); i++) { + if (supported_pixel_formats[i].pix_fmt == pix_fmt) + return supported_pixel_formats[i].fourcc; + } + return 0; +} + +static int qsv_device_init(AVHWDeviceContext *ctx) +{ + AVQSVDeviceContext *hwctx = ctx->hwctx; + QSVDeviceContext *s = ctx->internal->priv; + + mfxStatus err; + int i; + + for (i = 0; supported_handle_types[i].handle_type; i++) { + err = MFXVideoCORE_GetHandle(hwctx->session, supported_handle_types[i].handle_type, + &s->handle); + if (err == MFX_ERR_NONE) { + s->handle_type = supported_handle_types[i].handle_type; + s->child_device_type = supported_handle_types[i].device_type; + s->child_pix_fmt = supported_handle_types[i].pix_fmt; + break; + } + } + if (!s->handle) { + av_log(ctx, AV_LOG_VERBOSE, "No supported hw handle could be retrieved " + "from the session\n"); + } + + err = MFXQueryIMPL(hwctx->session, &s->impl); + if (err == MFX_ERR_NONE) + err = MFXQueryVersion(hwctx->session, &s->ver); + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, "Error querying the session attributes\n"); + return AVERROR_UNKNOWN; + } + + return 0; +} + +static void qsv_frames_uninit(AVHWFramesContext *ctx) +{ + QSVFramesContext *s = ctx->internal->priv; + + if (s->session_download) { + MFXVideoVPP_Close(s->session_download); + MFXClose(s->session_download); + } + s->session_download = NULL; + s->session_download_init = 0; + + if (s->session_upload) { + MFXVideoVPP_Close(s->session_upload); + MFXClose(s->session_upload); + } + s->session_upload = NULL; + s->session_upload_init = 0; + +#if HAVE_PTHREADS + pthread_mutex_destroy(&s->session_lock); + pthread_cond_destroy(&s->session_cond); +#endif + + av_freep(&s->mem_ids); + av_freep(&s->surface_ptrs); + av_freep(&s->surfaces_internal); + av_buffer_unref(&s->child_frames_ref); +} + +static void qsv_pool_release_dummy(void *opaque, uint8_t *data) +{ +} + +static AVBufferRef *qsv_pool_alloc(void *opaque, int size) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)opaque; + QSVFramesContext *s = ctx->internal->priv; + AVQSVFramesContext *hwctx = ctx->hwctx; + + if (s->nb_surfaces_used < hwctx->nb_surfaces) { + s->nb_surfaces_used++; + return av_buffer_create((uint8_t*)(s->surfaces_internal + s->nb_surfaces_used - 1), + sizeof(*hwctx->surfaces), qsv_pool_release_dummy, NULL, 0); + } + + return NULL; +} + +static int qsv_init_child_ctx(AVHWFramesContext *ctx) +{ + AVQSVFramesContext *hwctx = ctx->hwctx; + QSVFramesContext *s = ctx->internal->priv; + QSVDeviceContext *device_priv = ctx->device_ctx->internal->priv; + + AVBufferRef *child_device_ref = NULL; + AVBufferRef *child_frames_ref = NULL; + + AVHWDeviceContext *child_device_ctx; + AVHWFramesContext *child_frames_ctx; + + int i, ret = 0; + + if (!device_priv->handle) { + av_log(ctx, AV_LOG_ERROR, + "Cannot create a non-opaque internal surface pool without " + "a hardware handle\n"); + return AVERROR(EINVAL); + } + + child_device_ref = av_hwdevice_ctx_alloc(device_priv->child_device_type); + if (!child_device_ref) + return AVERROR(ENOMEM); + child_device_ctx = (AVHWDeviceContext*)child_device_ref->data; + +#if CONFIG_VAAPI + if (child_device_ctx->type == AV_HWDEVICE_TYPE_VAAPI) { + AVVAAPIDeviceContext *child_device_hwctx = child_device_ctx->hwctx; + child_device_hwctx->display = (VADisplay)device_priv->handle; + } +#endif +#if CONFIG_DXVA2 + if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { + AVDXVA2DeviceContext *child_device_hwctx = child_device_ctx->hwctx; + child_device_hwctx->devmgr = (IDirect3DDeviceManager9*)device_priv->handle; + } +#endif + + ret = av_hwdevice_ctx_init(child_device_ref); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error initializing a child device context\n"); + goto fail; + } + + child_frames_ref = av_hwframe_ctx_alloc(child_device_ref); + if (!child_frames_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + child_frames_ctx = (AVHWFramesContext*)child_frames_ref->data; + + child_frames_ctx->format = device_priv->child_pix_fmt; + child_frames_ctx->sw_format = ctx->sw_format; + child_frames_ctx->initial_pool_size = ctx->initial_pool_size; + child_frames_ctx->width = FFALIGN(ctx->width, 16); + child_frames_ctx->height = FFALIGN(ctx->height, 16); + +#if CONFIG_DXVA2 + if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { + AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx->hwctx; + if (hwctx->frame_type & MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET) + child_frames_hwctx->surface_type = DXVA2_VideoProcessorRenderTarget; + else + child_frames_hwctx->surface_type = DXVA2_VideoDecoderRenderTarget; + } +#endif + + ret = av_hwframe_ctx_init(child_frames_ref); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error initializing a child frames context\n"); + goto fail; + } + +#if CONFIG_VAAPI + if (child_device_ctx->type == AV_HWDEVICE_TYPE_VAAPI) { + AVVAAPIFramesContext *child_frames_hwctx = child_frames_ctx->hwctx; + for (i = 0; i < ctx->initial_pool_size; i++) + s->surfaces_internal[i].Data.MemId = child_frames_hwctx->surface_ids + i; + hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + } +#endif +#if CONFIG_DXVA2 + if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { + AVDXVA2FramesContext *child_frames_hwctx = child_frames_ctx->hwctx; + for (i = 0; i < ctx->initial_pool_size; i++) + s->surfaces_internal[i].Data.MemId = (mfxMemId)child_frames_hwctx->surfaces[i]; + if (child_frames_hwctx->surface_type == DXVA2_VideoProcessorRenderTarget) + hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET; + else + hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + } +#endif + + s->child_frames_ref = child_frames_ref; + child_frames_ref = NULL; + +fail: + av_buffer_unref(&child_device_ref); + av_buffer_unref(&child_frames_ref); + return ret; +} + +static int qsv_init_surface(AVHWFramesContext *ctx, mfxFrameSurface1 *surf) +{ + const AVPixFmtDescriptor *desc; + uint32_t fourcc; + + desc = av_pix_fmt_desc_get(ctx->sw_format); + if (!desc) + return AVERROR(EINVAL); + + fourcc = qsv_fourcc_from_pix_fmt(ctx->sw_format); + if (!fourcc) + return AVERROR(EINVAL); + + surf->Info.BitDepthLuma = desc->comp[0].depth; + surf->Info.BitDepthChroma = desc->comp[0].depth; + surf->Info.Shift = desc->comp[0].depth > 8; + + if (desc->log2_chroma_w && desc->log2_chroma_h) + surf->Info.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + else if (desc->log2_chroma_w) + surf->Info.ChromaFormat = MFX_CHROMAFORMAT_YUV422; + else + surf->Info.ChromaFormat = MFX_CHROMAFORMAT_YUV444; + + surf->Info.FourCC = fourcc; + surf->Info.Width = FFALIGN(ctx->width, 16); + surf->Info.CropW = ctx->width; + surf->Info.Height = FFALIGN(ctx->height, 16); + surf->Info.CropH = ctx->height; + surf->Info.FrameRateExtN = 25; + surf->Info.FrameRateExtD = 1; + surf->Info.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + + return 0; +} + +static int qsv_init_pool(AVHWFramesContext *ctx, uint32_t fourcc) +{ + QSVFramesContext *s = ctx->internal->priv; + AVQSVFramesContext *frames_hwctx = ctx->hwctx; + + int i, ret = 0; + + if (ctx->initial_pool_size <= 0) { + av_log(ctx, AV_LOG_ERROR, "QSV requires a fixed frame pool size\n"); + return AVERROR(EINVAL); + } + + s->surfaces_internal = av_mallocz_array(ctx->initial_pool_size, + sizeof(*s->surfaces_internal)); + if (!s->surfaces_internal) + return AVERROR(ENOMEM); + + for (i = 0; i < ctx->initial_pool_size; i++) { + ret = qsv_init_surface(ctx, &s->surfaces_internal[i]); + if (ret < 0) + return ret; + } + + if (!(frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME)) { + ret = qsv_init_child_ctx(ctx); + if (ret < 0) + return ret; + } + + ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(mfxFrameSurface1), + ctx, qsv_pool_alloc, NULL); + if (!ctx->internal->pool_internal) + return AVERROR(ENOMEM); + + frames_hwctx->surfaces = s->surfaces_internal; + frames_hwctx->nb_surfaces = ctx->initial_pool_size; + + return 0; +} + +static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, + mfxFrameAllocResponse *resp) +{ + AVHWFramesContext *ctx = pthis; + QSVFramesContext *s = ctx->internal->priv; + AVQSVFramesContext *hwctx = ctx->hwctx; + mfxFrameInfo *i = &req->Info; + mfxFrameInfo *i1 = &hwctx->surfaces[0].Info; + + if (!(req->Type & MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET) || + !(req->Type & (MFX_MEMTYPE_FROM_VPPIN | MFX_MEMTYPE_FROM_VPPOUT)) || + !(req->Type & MFX_MEMTYPE_EXTERNAL_FRAME)) + return MFX_ERR_UNSUPPORTED; + if (i->Width > i1->Width || i->Height > i1->Height || + i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) { + av_log(ctx, AV_LOG_ERROR, "Mismatching surface properties in an " + "allocation request: %dx%d %d %d vs %dx%d %d %d\n", + i->Width, i->Height, i->FourCC, i->ChromaFormat, + i1->Width, i1->Height, i1->FourCC, i1->ChromaFormat); + return MFX_ERR_UNSUPPORTED; + } + + resp->mids = s->mem_ids; + resp->NumFrameActual = hwctx->nb_surfaces; + + return MFX_ERR_NONE; +} + +static mfxStatus frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp) +{ + return MFX_ERR_NONE; +} + +static mfxStatus frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) +{ + return MFX_ERR_UNSUPPORTED; +} + +static mfxStatus frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) +{ + return MFX_ERR_UNSUPPORTED; +} + +static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl) +{ + *hdl = mid; + return MFX_ERR_NONE; +} + +static int qsv_init_internal_session(AVHWFramesContext *ctx, + mfxSession *session, int upload) +{ + QSVFramesContext *s = ctx->internal->priv; + AVQSVFramesContext *frames_hwctx = ctx->hwctx; + QSVDeviceContext *device_priv = ctx->device_ctx->internal->priv; + int opaque = !!(frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME); + + mfxFrameAllocator frame_allocator = { + .pthis = ctx, + .Alloc = frame_alloc, + .Lock = frame_lock, + .Unlock = frame_unlock, + .GetHDL = frame_get_hdl, + .Free = frame_free, + }; + + mfxVideoParam par; + mfxStatus err; + + err = MFXInit(device_priv->impl, &device_priv->ver, session); + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, "Error initializing an internal session\n"); + return AVERROR_UNKNOWN; + } + + if (device_priv->handle) { + err = MFXVideoCORE_SetHandle(*session, device_priv->handle_type, + device_priv->handle); + if (err != MFX_ERR_NONE) + return AVERROR_UNKNOWN; + } + + if (!opaque) { + err = MFXVideoCORE_SetFrameAllocator(*session, &frame_allocator); + if (err != MFX_ERR_NONE) + return AVERROR_UNKNOWN; + } + + memset(&par, 0, sizeof(par)); + + if (opaque) { + par.ExtParam = s->ext_buffers; + par.NumExtParam = FF_ARRAY_ELEMS(s->ext_buffers); + par.IOPattern = upload ? MFX_IOPATTERN_OUT_OPAQUE_MEMORY : + MFX_IOPATTERN_IN_OPAQUE_MEMORY; + } else { + par.IOPattern = upload ? MFX_IOPATTERN_OUT_VIDEO_MEMORY : + MFX_IOPATTERN_IN_VIDEO_MEMORY; + } + + par.IOPattern |= upload ? MFX_IOPATTERN_IN_SYSTEM_MEMORY : + MFX_IOPATTERN_OUT_SYSTEM_MEMORY; + par.AsyncDepth = 1; + + par.vpp.In = frames_hwctx->surfaces[0].Info; + + /* Apparently VPP requires the frame rate to be set to some value, otherwise + * init will fail (probably for the framerate conversion filter). Since we + * are only doing data upload/download here, we just invent an arbitrary + * value */ + par.vpp.In.FrameRateExtN = 25; + par.vpp.In.FrameRateExtD = 1; + par.vpp.Out = par.vpp.In; + + err = MFXVideoVPP_Init(*session, &par); + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_VERBOSE, "Error opening the internal VPP session." + "Surface upload/download will not be possible\n"); + MFXClose(*session); + *session = NULL; + } + + return 0; +} + +static int qsv_frames_init(AVHWFramesContext *ctx) +{ + QSVFramesContext *s = ctx->internal->priv; + AVQSVFramesContext *frames_hwctx = ctx->hwctx; + + int opaque = !!(frames_hwctx->frame_type & MFX_MEMTYPE_OPAQUE_FRAME); + + uint32_t fourcc; + int i, ret; + + fourcc = qsv_fourcc_from_pix_fmt(ctx->sw_format); + if (!fourcc) { + av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format\n"); + return AVERROR(ENOSYS); + } + + if (!ctx->pool) { + ret = qsv_init_pool(ctx, fourcc); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error creating an internal frame pool\n"); + return ret; + } + } + + if (opaque) { + s->surface_ptrs = av_mallocz_array(frames_hwctx->nb_surfaces, + sizeof(*s->surface_ptrs)); + if (!s->surface_ptrs) + return AVERROR(ENOMEM); + + for (i = 0; i < frames_hwctx->nb_surfaces; i++) + s->surface_ptrs[i] = frames_hwctx->surfaces + i; + + s->opaque_alloc.In.Surfaces = s->surface_ptrs; + s->opaque_alloc.In.NumSurface = frames_hwctx->nb_surfaces; + s->opaque_alloc.In.Type = frames_hwctx->frame_type; + + s->opaque_alloc.Out = s->opaque_alloc.In; + + s->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; + s->opaque_alloc.Header.BufferSz = sizeof(s->opaque_alloc); + + s->ext_buffers[0] = (mfxExtBuffer*)&s->opaque_alloc; + } else { + s->mem_ids = av_mallocz_array(frames_hwctx->nb_surfaces, sizeof(*s->mem_ids)); + if (!s->mem_ids) + return AVERROR(ENOMEM); + + for (i = 0; i < frames_hwctx->nb_surfaces; i++) + s->mem_ids[i] = frames_hwctx->surfaces[i].Data.MemId; + } + + s->session_download = NULL; + s->session_upload = NULL; + + s->session_download_init = 0; + s->session_upload_init = 0; + +#if HAVE_PTHREADS + pthread_mutex_init(&s->session_lock, NULL); + pthread_cond_init(&s->session_cond, NULL); +#endif + + return 0; +} + +static int qsv_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) +{ + frame->buf[0] = av_buffer_pool_get(ctx->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + + frame->data[3] = frame->buf[0]->data; + frame->format = AV_PIX_FMT_QSV; + frame->width = ctx->width; + frame->height = ctx->height; + + return 0; +} + +static int qsv_transfer_get_formats(AVHWFramesContext *ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ + enum AVPixelFormat *fmts; + + fmts = av_malloc_array(2, sizeof(*fmts)); + if (!fmts) + return AVERROR(ENOMEM); + + fmts[0] = ctx->sw_format; + fmts[1] = AV_PIX_FMT_NONE; + + *formats = fmts; + + return 0; +} + +static int qsv_frames_derive_from(AVHWFramesContext *dst_ctx, + AVHWFramesContext *src_ctx, int flags) +{ + AVQSVFramesContext *src_hwctx = src_ctx->hwctx; + int i; + + switch (dst_ctx->device_ctx->type) { +#if CONFIG_VAAPI + case AV_HWDEVICE_TYPE_VAAPI: + { + AVVAAPIFramesContext *dst_hwctx = dst_ctx->hwctx; + dst_hwctx->surface_ids = av_mallocz_array(src_hwctx->nb_surfaces, + sizeof(*dst_hwctx->surface_ids)); + if (!dst_hwctx->surface_ids) + return AVERROR(ENOMEM); + for (i = 0; i < src_hwctx->nb_surfaces; i++) + dst_hwctx->surface_ids[i] = + *(VASurfaceID*)src_hwctx->surfaces[i].Data.MemId; + dst_hwctx->nb_surfaces = src_hwctx->nb_surfaces; + } + break; +#endif +#if CONFIG_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + { + AVDXVA2FramesContext *dst_hwctx = dst_ctx->hwctx; + dst_hwctx->surfaces = av_mallocz_array(src_hwctx->nb_surfaces, + sizeof(*dst_hwctx->surfaces)); + if (!dst_hwctx->surfaces) + return AVERROR(ENOMEM); + for (i = 0; i < src_hwctx->nb_surfaces; i++) + dst_hwctx->surfaces[i] = + (IDirect3DSurface9*)src_hwctx->surfaces[i].Data.MemId; + dst_hwctx->nb_surfaces = src_hwctx->nb_surfaces; + if (src_hwctx->frame_type == MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET) + dst_hwctx->surface_type = DXVA2_VideoDecoderRenderTarget; + else + dst_hwctx->surface_type = DXVA2_VideoProcessorRenderTarget; + } + break; +#endif + default: + return AVERROR(ENOSYS); + } + + return 0; +} + +static int qsv_map_from(AVHWFramesContext *ctx, + AVFrame *dst, const AVFrame *src, int flags) +{ + QSVFramesContext *s = ctx->internal->priv; + mfxFrameSurface1 *surf = (mfxFrameSurface1*)src->data[3]; + AVHWFramesContext *child_frames_ctx; + const AVPixFmtDescriptor *desc; + uint8_t *child_data; + AVFrame *dummy; + int ret = 0; + + if (!s->child_frames_ref) + return AVERROR(ENOSYS); + child_frames_ctx = (AVHWFramesContext*)s->child_frames_ref->data; + + switch (child_frames_ctx->device_ctx->type) { +#if CONFIG_VAAPI + case AV_HWDEVICE_TYPE_VAAPI: + child_data = (uint8_t*)(intptr_t)*(VASurfaceID*)surf->Data.MemId; + break; +#endif +#if CONFIG_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + child_data = surf->Data.MemId; + break; +#endif + default: + return AVERROR(ENOSYS); + } + + if (dst->format == child_frames_ctx->format) { + ret = ff_hwframe_map_create(s->child_frames_ref, + dst, src, NULL, NULL); + if (ret < 0) + return ret; + + dst->width = src->width; + dst->height = src->height; + dst->data[3] = child_data; + + return 0; + } + + desc = av_pix_fmt_desc_get(dst->format); + if (desc && desc->flags & AV_PIX_FMT_FLAG_HWACCEL) { + // This only supports mapping to software. + return AVERROR(ENOSYS); + } + + dummy = av_frame_alloc(); + if (!dummy) + return AVERROR(ENOMEM); + + dummy->buf[0] = av_buffer_ref(src->buf[0]); + dummy->hw_frames_ctx = av_buffer_ref(s->child_frames_ref); + if (!dummy->buf[0] || !dummy->hw_frames_ctx) + goto fail; + + dummy->format = child_frames_ctx->format; + dummy->width = src->width; + dummy->height = src->height; + dummy->data[3] = child_data; + + ret = av_hwframe_map(dst, dummy, flags); + +fail: + av_frame_free(&dummy); + + return ret; +} + +static int qsv_transfer_data_child(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src) +{ + QSVFramesContext *s = ctx->internal->priv; + AVHWFramesContext *child_frames_ctx = (AVHWFramesContext*)s->child_frames_ref->data; + int download = !!src->hw_frames_ctx; + mfxFrameSurface1 *surf = (mfxFrameSurface1*)(download ? src->data[3] : dst->data[3]); + + AVFrame *dummy; + int ret; + + dummy = av_frame_alloc(); + if (!dummy) + return AVERROR(ENOMEM); + + dummy->format = child_frames_ctx->format; + dummy->width = src->width; + dummy->height = src->height; + dummy->buf[0] = download ? src->buf[0] : dst->buf[0]; + dummy->data[3] = surf->Data.MemId; + dummy->hw_frames_ctx = s->child_frames_ref; + + ret = download ? av_hwframe_transfer_data(dst, dummy, 0) : + av_hwframe_transfer_data(dummy, src, 0); + + dummy->buf[0] = NULL; + dummy->data[3] = NULL; + dummy->hw_frames_ctx = NULL; + + av_frame_free(&dummy); + + return ret; +} + +static int map_frame_to_surface(const AVFrame *frame, mfxFrameSurface1 *surface) +{ + switch (frame->format) { + case AV_PIX_FMT_NV12: + case AV_PIX_FMT_P010: + surface->Data.Y = frame->data[0]; + surface->Data.UV = frame->data[1]; + break; + + case AV_PIX_FMT_YUV420P: + surface->Data.Y = frame->data[0]; + surface->Data.U = frame->data[1]; + surface->Data.V = frame->data[2]; + break; + + case AV_PIX_FMT_BGRA: + surface->Data.B = frame->data[0]; + surface->Data.G = frame->data[0] + 1; + surface->Data.R = frame->data[0] + 2; + surface->Data.A = frame->data[0] + 3; + break; + + default: + return MFX_ERR_UNSUPPORTED; + } + surface->Data.Pitch = frame->linesize[0]; + surface->Data.TimeStamp = frame->pts; + + return 0; +} + +static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src) +{ + QSVFramesContext *s = ctx->internal->priv; + mfxFrameSurface1 out = {{ 0 }}; + mfxFrameSurface1 *in = (mfxFrameSurface1*)src->data[3]; + + mfxSyncPoint sync = NULL; + mfxStatus err; + int ret = 0; + + while (!s->session_download_init && !s->session_download && !ret) { +#if HAVE_PTHREADS + if (pthread_mutex_trylock(&s->session_lock) == 0) { +#endif + if (!s->session_download_init) { + ret = qsv_init_internal_session(ctx, &s->session_download, 0); + if (s->session_download) + s->session_download_init = 1; + } +#if HAVE_PTHREADS + pthread_mutex_unlock(&s->session_lock); + pthread_cond_signal(&s->session_cond); + } else { + pthread_mutex_lock(&s->session_lock); + while (!s->session_download_init && !s->session_download) { + pthread_cond_wait(&s->session_cond, &s->session_lock); + } + pthread_mutex_unlock(&s->session_lock); + } +#endif + } + + if (ret < 0) + return ret; + + if (!s->session_download) { + if (s->child_frames_ref) + return qsv_transfer_data_child(ctx, dst, src); + + av_log(ctx, AV_LOG_ERROR, "Surface download not possible\n"); + return AVERROR(ENOSYS); + } + + out.Info = in->Info; + map_frame_to_surface(dst, &out); + + do { + err = MFXVideoVPP_RunFrameVPPAsync(s->session_download, in, &out, NULL, &sync); + if (err == MFX_WRN_DEVICE_BUSY) + av_usleep(1); + } while (err == MFX_WRN_DEVICE_BUSY); + + if (err < 0 || !sync) { + av_log(ctx, AV_LOG_ERROR, "Error downloading the surface\n"); + return AVERROR_UNKNOWN; + } + + do { + err = MFXVideoCORE_SyncOperation(s->session_download, sync, 1000); + } while (err == MFX_WRN_IN_EXECUTION); + if (err < 0) { + av_log(ctx, AV_LOG_ERROR, "Error synchronizing the operation: %d\n", err); + return AVERROR_UNKNOWN; + } + + return 0; +} + +static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src) +{ + QSVFramesContext *s = ctx->internal->priv; + mfxFrameSurface1 in = {{ 0 }}; + mfxFrameSurface1 *out = (mfxFrameSurface1*)dst->data[3]; + + mfxSyncPoint sync = NULL; + mfxStatus err; + int ret = 0; + /* make a copy if the input is not padded as libmfx requires */ + AVFrame tmp_frame; + const AVFrame *src_frame; + int realigned = 0; + + + while (!s->session_upload_init && !s->session_upload && !ret) { +#if HAVE_PTHREADS + if (pthread_mutex_trylock(&s->session_lock) == 0) { +#endif + if (!s->session_upload_init) { + ret = qsv_init_internal_session(ctx, &s->session_upload, 1); + if (s->session_upload) + s->session_upload_init = 1; + } +#if HAVE_PTHREADS + pthread_mutex_unlock(&s->session_lock); + pthread_cond_signal(&s->session_cond); + } else { + pthread_mutex_lock(&s->session_lock); + while (!s->session_upload_init && !s->session_upload) { + pthread_cond_wait(&s->session_cond, &s->session_lock); + } + pthread_mutex_unlock(&s->session_lock); + } +#endif + } + if (ret < 0) + return ret; + + if (src->height & 15 || src->linesize[0] & 15) { + realigned = 1; + memset(&tmp_frame, 0, sizeof(tmp_frame)); + tmp_frame.format = src->format; + tmp_frame.width = FFALIGN(src->width, 16); + tmp_frame.height = FFALIGN(src->height, 16); + ret = av_frame_get_buffer(&tmp_frame, 32); + if (ret < 0) + return ret; + + ret = av_frame_copy(&tmp_frame, src); + if (ret < 0) { + av_frame_unref(&tmp_frame); + return ret; + } + } + + src_frame = realigned ? &tmp_frame : src; + + if (!s->session_upload) { + if (s->child_frames_ref) + return qsv_transfer_data_child(ctx, dst, src_frame); + + av_log(ctx, AV_LOG_ERROR, "Surface upload not possible\n"); + return AVERROR(ENOSYS); + } + + in.Info = out->Info; + map_frame_to_surface(src_frame, &in); + + do { + err = MFXVideoVPP_RunFrameVPPAsync(s->session_upload, &in, out, NULL, &sync); + if (err == MFX_WRN_DEVICE_BUSY) + av_usleep(1); + } while (err == MFX_WRN_DEVICE_BUSY); + + if (err < 0 || !sync) { + av_log(ctx, AV_LOG_ERROR, "Error uploading the surface\n"); + return AVERROR_UNKNOWN; + } + + do { + err = MFXVideoCORE_SyncOperation(s->session_upload, sync, 1000); + } while (err == MFX_WRN_IN_EXECUTION); + if (err < 0) { + av_log(ctx, AV_LOG_ERROR, "Error synchronizing the operation\n"); + return AVERROR_UNKNOWN; + } + + if (realigned) + av_frame_unref(&tmp_frame); + + return 0; +} + +static int qsv_frames_derive_to(AVHWFramesContext *dst_ctx, + AVHWFramesContext *src_ctx, int flags) +{ + QSVFramesContext *s = dst_ctx->internal->priv; + AVQSVFramesContext *dst_hwctx = dst_ctx->hwctx; + int i; + + switch (src_ctx->device_ctx->type) { +#if CONFIG_VAAPI + case AV_HWDEVICE_TYPE_VAAPI: + { + AVVAAPIFramesContext *src_hwctx = src_ctx->hwctx; + s->surfaces_internal = av_mallocz_array(src_hwctx->nb_surfaces, + sizeof(*s->surfaces_internal)); + if (!s->surfaces_internal) + return AVERROR(ENOMEM); + for (i = 0; i < src_hwctx->nb_surfaces; i++) { + qsv_init_surface(dst_ctx, &s->surfaces_internal[i]); + s->surfaces_internal[i].Data.MemId = src_hwctx->surface_ids + i; + } + dst_hwctx->nb_surfaces = src_hwctx->nb_surfaces; + dst_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + } + break; +#endif +#if CONFIG_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + { + AVDXVA2FramesContext *src_hwctx = src_ctx->hwctx; + s->surfaces_internal = av_mallocz_array(src_hwctx->nb_surfaces, + sizeof(*s->surfaces_internal)); + if (!s->surfaces_internal) + return AVERROR(ENOMEM); + for (i = 0; i < src_hwctx->nb_surfaces; i++) { + qsv_init_surface(dst_ctx, &s->surfaces_internal[i]); + s->surfaces_internal[i].Data.MemId = (mfxMemId)src_hwctx->surfaces[i]; + } + dst_hwctx->nb_surfaces = src_hwctx->nb_surfaces; + if (src_hwctx->surface_type == DXVA2_VideoProcessorRenderTarget) + dst_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET; + else + dst_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + } + break; +#endif + default: + return AVERROR(ENOSYS); + } + + dst_hwctx->surfaces = s->surfaces_internal; + + return 0; +} + +static int qsv_map_to(AVHWFramesContext *dst_ctx, + AVFrame *dst, const AVFrame *src, int flags) +{ + AVQSVFramesContext *hwctx = dst_ctx->hwctx; + int i, err; + + for (i = 0; i < hwctx->nb_surfaces; i++) { +#if CONFIG_VAAPI + if (*(VASurfaceID*)hwctx->surfaces[i].Data.MemId == + (VASurfaceID)(uintptr_t)src->data[3]) + break; +#endif +#if CONFIG_DXVA2 + if ((IDirect3DSurface9*)hwctx->surfaces[i].Data.MemId == + (IDirect3DSurface9*)(uintptr_t)src->data[3]) + break; +#endif + } + if (i >= hwctx->nb_surfaces) { + av_log(dst_ctx, AV_LOG_ERROR, "Trying to map from a surface which " + "is not in the mapped frames context.\n"); + return AVERROR(EINVAL); + } + + err = ff_hwframe_map_create(dst->hw_frames_ctx, + dst, src, NULL, NULL); + if (err) + return err; + + dst->width = src->width; + dst->height = src->height; + dst->data[3] = (uint8_t*)&hwctx->surfaces[i]; + + return 0; +} + +static int qsv_frames_get_constraints(AVHWDeviceContext *ctx, + const void *hwconfig, + AVHWFramesConstraints *constraints) +{ + int i; + + constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_pixel_formats) + 1, + sizeof(*constraints->valid_sw_formats)); + if (!constraints->valid_sw_formats) + return AVERROR(ENOMEM); + + for (i = 0; i < FF_ARRAY_ELEMS(supported_pixel_formats); i++) + constraints->valid_sw_formats[i] = supported_pixel_formats[i].pix_fmt; + constraints->valid_sw_formats[FF_ARRAY_ELEMS(supported_pixel_formats)] = AV_PIX_FMT_NONE; + + constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); + if (!constraints->valid_hw_formats) + return AVERROR(ENOMEM); + + constraints->valid_hw_formats[0] = AV_PIX_FMT_QSV; + constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; + + return 0; +} + +static void qsv_device_free(AVHWDeviceContext *ctx) +{ + AVQSVDeviceContext *hwctx = ctx->hwctx; + QSVDevicePriv *priv = ctx->user_opaque; + + if (hwctx->session) + MFXClose(hwctx->session); + + av_buffer_unref(&priv->child_device_ctx); + av_freep(&priv); +} + +static mfxIMPL choose_implementation(const char *device) +{ + static const struct { + const char *name; + mfxIMPL impl; + } impl_map[] = { + { "auto", MFX_IMPL_AUTO }, + { "sw", MFX_IMPL_SOFTWARE }, + { "hw", MFX_IMPL_HARDWARE }, + { "auto_any", MFX_IMPL_AUTO_ANY }, + { "hw_any", MFX_IMPL_HARDWARE_ANY }, + { "hw2", MFX_IMPL_HARDWARE2 }, + { "hw3", MFX_IMPL_HARDWARE3 }, + { "hw4", MFX_IMPL_HARDWARE4 }, + }; + + mfxIMPL impl = MFX_IMPL_AUTO_ANY; + int i; + + if (device) { + for (i = 0; i < FF_ARRAY_ELEMS(impl_map); i++) + if (!strcmp(device, impl_map[i].name)) { + impl = impl_map[i].impl; + break; + } + if (i == FF_ARRAY_ELEMS(impl_map)) + impl = strtol(device, NULL, 0); + } + + return impl; +} + +static int qsv_device_derive_from_child(AVHWDeviceContext *ctx, + mfxIMPL implementation, + AVHWDeviceContext *child_device_ctx, + int flags) +{ + AVQSVDeviceContext *hwctx = ctx->hwctx; + + mfxVersion ver = { { 3, 1 } }; + mfxHDL handle; + mfxHandleType handle_type; + mfxStatus err; + int ret; + + switch (child_device_ctx->type) { +#if CONFIG_VAAPI + case AV_HWDEVICE_TYPE_VAAPI: + { + AVVAAPIDeviceContext *child_device_hwctx = child_device_ctx->hwctx; + handle_type = MFX_HANDLE_VA_DISPLAY; + handle = (mfxHDL)child_device_hwctx->display; + } + break; +#endif +#if CONFIG_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + { + AVDXVA2DeviceContext *child_device_hwctx = child_device_ctx->hwctx; + handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER; + handle = (mfxHDL)child_device_hwctx->devmgr; + } + break; +#endif + default: + ret = AVERROR(ENOSYS); + goto fail; + } + + err = MFXInit(implementation, &ver, &hwctx->session); + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, "Error initializing an MFX session: " + "%d.\n", err); + ret = AVERROR_UNKNOWN; + goto fail; + } + + err = MFXQueryVersion(hwctx->session, &ver); + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, "Error querying an MFX session: %d.\n", err); + ret = AVERROR_UNKNOWN; + goto fail; + } + + av_log(ctx, AV_LOG_VERBOSE, + "Initialize MFX session: API version is %d.%d, implementation version is %d.%d\n", + MFX_VERSION_MAJOR, MFX_VERSION_MINOR, ver.Major, ver.Minor); + + MFXClose(hwctx->session); + + err = MFXInit(implementation, &ver, &hwctx->session); + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, + "Error initializing an MFX session: %d.\n", err); + ret = AVERROR_UNKNOWN; + goto fail; + } + + err = MFXVideoCORE_SetHandle(hwctx->session, handle_type, handle); + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, "Error setting child device handle: " + "%d\n", err); + ret = AVERROR_UNKNOWN; + goto fail; + } + + ret = MFXQueryVersion(hwctx->session,&ver); + if (ret == MFX_ERR_NONE) { + av_log(ctx, AV_LOG_VERBOSE, "MFX compile/runtime API: %d.%d/%d.%d\n", + MFX_VERSION_MAJOR, MFX_VERSION_MINOR, ver.Major, ver.Minor); + } + return 0; + +fail: + if (hwctx->session) + MFXClose(hwctx->session); + return ret; +} + +static int qsv_device_derive(AVHWDeviceContext *ctx, + AVHWDeviceContext *child_device_ctx, int flags) +{ + return qsv_device_derive_from_child(ctx, MFX_IMPL_HARDWARE_ANY, + child_device_ctx, flags); +} + +static int qsv_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + QSVDevicePriv *priv; + enum AVHWDeviceType child_device_type; + AVHWDeviceContext *child_device; + AVDictionary *child_device_opts; + AVDictionaryEntry *e; + + mfxIMPL impl; + int ret; + + priv = av_mallocz(sizeof(*priv)); + if (!priv) + return AVERROR(ENOMEM); + + ctx->user_opaque = priv; + ctx->free = qsv_device_free; + + e = av_dict_get(opts, "child_device", NULL, 0); + + child_device_opts = NULL; + if (CONFIG_VAAPI) { + child_device_type = AV_HWDEVICE_TYPE_VAAPI; + // libmfx does not actually implement VAAPI properly, rather it + // depends on the specific behaviour of a matching iHD driver when + // used on recent Intel hardware. Set options to the VAAPI device + // creation so that we should pick a usable setup by default if + // possible, even when multiple devices and drivers are available. + av_dict_set(&child_device_opts, "kernel_driver", "i915", 0); + av_dict_set(&child_device_opts, "driver", "iHD", 0); + } else if (CONFIG_DXVA2) + child_device_type = AV_HWDEVICE_TYPE_DXVA2; + else { + av_log(ctx, AV_LOG_ERROR, "No supported child device type is enabled\n"); + return AVERROR(ENOSYS); + } + + ret = av_hwdevice_ctx_create(&priv->child_device_ctx, child_device_type, + e ? e->value : NULL, child_device_opts, 0); + if (ret < 0) + return ret; + + child_device = (AVHWDeviceContext*)priv->child_device_ctx->data; + + impl = choose_implementation(device); + + return qsv_device_derive_from_child(ctx, impl, child_device, 0); +} + +const HWContextType ff_hwcontext_type_qsv = { + .type = AV_HWDEVICE_TYPE_QSV, + .name = "QSV", + + .device_hwctx_size = sizeof(AVQSVDeviceContext), + .device_priv_size = sizeof(QSVDeviceContext), + .frames_hwctx_size = sizeof(AVQSVFramesContext), + .frames_priv_size = sizeof(QSVFramesContext), + + .device_create = qsv_device_create, + .device_derive = qsv_device_derive, + .device_init = qsv_device_init, + .frames_get_constraints = qsv_frames_get_constraints, + .frames_init = qsv_frames_init, + .frames_uninit = qsv_frames_uninit, + .frames_get_buffer = qsv_get_buffer, + .transfer_get_formats = qsv_transfer_get_formats, + .transfer_data_to = qsv_transfer_data_to, + .transfer_data_from = qsv_transfer_data_from, + .map_to = qsv_map_to, + .map_from = qsv_map_from, + .frames_derive_to = qsv_frames_derive_to, + .frames_derive_from = qsv_frames_derive_from, + + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_qsv.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_qsv.h new file mode 100644 index 0000000000..b98d611cfc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_qsv.h @@ -0,0 +1,53 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_QSV_H +#define AVUTIL_HWCONTEXT_QSV_H + +#include + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_QSV. + * + * This API does not support dynamic frame pools. AVHWFramesContext.pool must + * contain AVBufferRefs whose data pointer points to an mfxFrameSurface1 struct. + */ + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVQSVDeviceContext { + mfxSession session; +} AVQSVDeviceContext; + +/** + * This struct is allocated as AVHWFramesContext.hwctx + */ +typedef struct AVQSVFramesContext { + mfxFrameSurface1 *surfaces; + int nb_surfaces; + + /** + * A combination of MFX_MEMTYPE_* describing the frame pool. + */ + int frame_type; +} AVQSVFramesContext; + +#endif /* AVUTIL_HWCONTEXT_QSV_H */ + diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vaapi.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vaapi.c new file mode 100644 index 0000000000..cf117640f2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vaapi.c @@ -0,0 +1,1689 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#if HAVE_VAAPI_X11 +# include +#endif +#if HAVE_VAAPI_DRM +# include +#endif + +#if CONFIG_LIBDRM +# include +# include +# include +# ifndef DRM_FORMAT_MOD_INVALID +# define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) +# endif +#endif + +#include +#if HAVE_UNISTD_H +# include +#endif + + +#include "avassert.h" +#include "buffer.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_drm.h" +#include "hwcontext_internal.h" +#include "hwcontext_vaapi.h" +#include "mem.h" +#include "pixdesc.h" +#include "pixfmt.h" + + +typedef struct VAAPIDevicePriv { +#if HAVE_VAAPI_X11 + Display *x11_display; +#endif + + int drm_fd; +} VAAPIDevicePriv; + +typedef struct VAAPISurfaceFormat { + enum AVPixelFormat pix_fmt; + VAImageFormat image_format; +} VAAPISurfaceFormat; + +typedef struct VAAPIDeviceContext { + // Surface formats which can be used with this device. + VAAPISurfaceFormat *formats; + int nb_formats; +} VAAPIDeviceContext; + +typedef struct VAAPIFramesContext { + // Surface attributes set at create time. + VASurfaceAttrib *attributes; + int nb_attributes; + // RT format of the underlying surface (Intel driver ignores this anyway). + unsigned int rt_format; + // Whether vaDeriveImage works. + int derive_works; +} VAAPIFramesContext; + +typedef struct VAAPIMapping { + // Handle to the derived or copied image which is mapped. + VAImage image; + // The mapping flags actually used. + int flags; +} VAAPIMapping; + +typedef struct VAAPIFormat { + unsigned int fourcc; + unsigned int rt_format; + enum AVPixelFormat pix_fmt; + int chroma_planes_swapped; +} VAAPIFormatDescriptor; + +#define MAP(va, rt, av, swap_uv) { \ + VA_FOURCC_ ## va, \ + VA_RT_FORMAT_ ## rt, \ + AV_PIX_FMT_ ## av, \ + swap_uv, \ + } +// The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V +// plane swap cases. The frame handling below tries to hide these. +static const VAAPIFormatDescriptor vaapi_format_map[] = { + MAP(NV12, YUV420, NV12, 0), +#ifdef VA_FOURCC_I420 + MAP(I420, YUV420, YUV420P, 0), +#endif + MAP(YV12, YUV420, YUV420P, 1), + MAP(IYUV, YUV420, YUV420P, 0), + MAP(422H, YUV422, YUV422P, 0), +#ifdef VA_FOURCC_YV16 + MAP(YV16, YUV422, YUV422P, 1), +#endif + MAP(UYVY, YUV422, UYVY422, 0), + MAP(YUY2, YUV422, YUYV422, 0), + MAP(411P, YUV411, YUV411P, 0), + MAP(422V, YUV422, YUV440P, 0), + MAP(444P, YUV444, YUV444P, 0), + MAP(Y800, YUV400, GRAY8, 0), +#ifdef VA_FOURCC_P010 + MAP(P010, YUV420_10BPP, P010, 0), +#endif + MAP(BGRA, RGB32, BGRA, 0), + MAP(BGRX, RGB32, BGR0, 0), + MAP(RGBA, RGB32, RGBA, 0), + MAP(RGBX, RGB32, RGB0, 0), +#ifdef VA_FOURCC_ABGR + MAP(ABGR, RGB32, ABGR, 0), + MAP(XBGR, RGB32, 0BGR, 0), +#endif + MAP(ARGB, RGB32, ARGB, 0), + MAP(XRGB, RGB32, 0RGB, 0), +}; +#undef MAP + +static const VAAPIFormatDescriptor * + vaapi_format_from_fourcc(unsigned int fourcc) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) + if (vaapi_format_map[i].fourcc == fourcc) + return &vaapi_format_map[i]; + return NULL; +} + +static const VAAPIFormatDescriptor * + vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) + if (vaapi_format_map[i].pix_fmt == pix_fmt) + return &vaapi_format_map[i]; + return NULL; +} + +static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc) +{ + const VAAPIFormatDescriptor *desc; + desc = vaapi_format_from_fourcc(fourcc); + if (desc) + return desc->pix_fmt; + else + return AV_PIX_FMT_NONE; +} + +static int vaapi_get_image_format(AVHWDeviceContext *hwdev, + enum AVPixelFormat pix_fmt, + VAImageFormat **image_format) +{ + VAAPIDeviceContext *ctx = hwdev->internal->priv; + int i; + + for (i = 0; i < ctx->nb_formats; i++) { + if (ctx->formats[i].pix_fmt == pix_fmt) { + if (image_format) + *image_format = &ctx->formats[i].image_format; + return 0; + } + } + return AVERROR(EINVAL); +} + +static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev, + const void *hwconfig, + AVHWFramesConstraints *constraints) +{ + AVVAAPIDeviceContext *hwctx = hwdev->hwctx; + const AVVAAPIHWConfig *config = hwconfig; + VAAPIDeviceContext *ctx = hwdev->internal->priv; + VASurfaceAttrib *attr_list = NULL; + VAStatus vas; + enum AVPixelFormat pix_fmt; + unsigned int fourcc; + int err, i, j, attr_count, pix_fmt_count; + + if (config && + !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) { + attr_count = 0; + vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id, + 0, &attr_count); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR(ENOSYS); + goto fail; + } + + attr_list = av_malloc(attr_count * sizeof(*attr_list)); + if (!attr_list) { + err = AVERROR(ENOMEM); + goto fail; + } + + vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id, + attr_list, &attr_count); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR(ENOSYS); + goto fail; + } + + pix_fmt_count = 0; + for (i = 0; i < attr_count; i++) { + switch (attr_list[i].type) { + case VASurfaceAttribPixelFormat: + fourcc = attr_list[i].value.value.i; + pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc); + if (pix_fmt != AV_PIX_FMT_NONE) { + ++pix_fmt_count; + } else { + // Something unsupported - ignore. + } + break; + case VASurfaceAttribMinWidth: + constraints->min_width = attr_list[i].value.value.i; + break; + case VASurfaceAttribMinHeight: + constraints->min_height = attr_list[i].value.value.i; + break; + case VASurfaceAttribMaxWidth: + constraints->max_width = attr_list[i].value.value.i; + break; + case VASurfaceAttribMaxHeight: + constraints->max_height = attr_list[i].value.value.i; + break; + } + } + if (pix_fmt_count == 0) { + // Nothing usable found. Presumably there exists something which + // works, so leave the set null to indicate unknown. + constraints->valid_sw_formats = NULL; + } else { + constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1, + sizeof(pix_fmt)); + if (!constraints->valid_sw_formats) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (i = j = 0; i < attr_count; i++) { + if (attr_list[i].type != VASurfaceAttribPixelFormat) + continue; + fourcc = attr_list[i].value.value.i; + pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc); + if (pix_fmt != AV_PIX_FMT_NONE) + constraints->valid_sw_formats[j++] = pix_fmt; + } + av_assert0(j == pix_fmt_count); + constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE; + } + } else { + // No configuration supplied. + // Return the full set of image formats known by the implementation. + constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1, + sizeof(pix_fmt)); + if (!constraints->valid_sw_formats) { + err = AVERROR(ENOMEM); + goto fail; + } + for (i = 0; i < ctx->nb_formats; i++) + constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt; + constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE; + } + + constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt)); + if (!constraints->valid_hw_formats) { + err = AVERROR(ENOMEM); + goto fail; + } + constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI; + constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; + + err = 0; +fail: + av_freep(&attr_list); + return err; +} + +static const struct { + const char *friendly_name; + const char *match_string; + unsigned int quirks; +} vaapi_driver_quirks_table[] = { +#if !VA_CHECK_VERSION(1, 0, 0) + // The i965 driver did not conform before version 2.0. + { + "Intel i965 (Quick Sync)", + "i965", + AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS, + }, +#endif + { + "Intel iHD", + "ubit", + AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE, + }, + { + "VDPAU wrapper", + "Splitted-Desktop Systems VDPAU backend for VA-API", + AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES, + }, +}; + +static int vaapi_device_init(AVHWDeviceContext *hwdev) +{ + VAAPIDeviceContext *ctx = hwdev->internal->priv; + AVVAAPIDeviceContext *hwctx = hwdev->hwctx; + VAImageFormat *image_list = NULL; + VAStatus vas; + const char *vendor_string; + int err, i, image_count; + enum AVPixelFormat pix_fmt; + unsigned int fourcc; + + image_count = vaMaxNumImageFormats(hwctx->display); + if (image_count <= 0) { + err = AVERROR(EIO); + goto fail; + } + image_list = av_malloc(image_count * sizeof(*image_list)); + if (!image_list) { + err = AVERROR(ENOMEM); + goto fail; + } + vas = vaQueryImageFormats(hwctx->display, image_list, &image_count); + if (vas != VA_STATUS_SUCCESS) { + err = AVERROR(EIO); + goto fail; + } + + ctx->formats = av_malloc(image_count * sizeof(*ctx->formats)); + if (!ctx->formats) { + err = AVERROR(ENOMEM); + goto fail; + } + ctx->nb_formats = 0; + for (i = 0; i < image_count; i++) { + fourcc = image_list[i].fourcc; + pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc); + if (pix_fmt == AV_PIX_FMT_NONE) { + av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n", + fourcc); + } else { + av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n", + fourcc, av_get_pix_fmt_name(pix_fmt)); + ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt; + ctx->formats[ctx->nb_formats].image_format = image_list[i]; + ++ctx->nb_formats; + } + } + + vendor_string = vaQueryVendorString(hwctx->display); + if (vendor_string) + av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string); + + if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) { + av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n", + hwctx->driver_quirks); + } else { + // Detect the driver in use and set quirk flags if necessary. + hwctx->driver_quirks = 0; + if (vendor_string) { + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) { + if (strstr(vendor_string, + vaapi_driver_quirks_table[i].match_string)) { + av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string " + "as known nonstandard driver \"%s\", setting " + "quirks (%#x).\n", + vaapi_driver_quirks_table[i].friendly_name, + vaapi_driver_quirks_table[i].quirks); + hwctx->driver_quirks |= + vaapi_driver_quirks_table[i].quirks; + break; + } + } + if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) { + av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known " + "nonstandard list, using standard behaviour.\n"); + } + } else { + av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, " + "assuming standard behaviour.\n"); + } + } + + av_free(image_list); + return 0; +fail: + av_freep(&ctx->formats); + av_free(image_list); + return err; +} + +static void vaapi_device_uninit(AVHWDeviceContext *hwdev) +{ + VAAPIDeviceContext *ctx = hwdev->internal->priv; + + av_freep(&ctx->formats); +} + +static void vaapi_buffer_free(void *opaque, uint8_t *data) +{ + AVHWFramesContext *hwfc = opaque; + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + VASurfaceID surface_id; + VAStatus vas; + + surface_id = (VASurfaceID)(uintptr_t)data; + + vas = vaDestroySurfaces(hwctx->display, &surface_id, 1); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: " + "%d (%s).\n", surface_id, vas, vaErrorStr(vas)); + } +} + +static AVBufferRef *vaapi_pool_alloc(void *opaque, int size) +{ + AVHWFramesContext *hwfc = opaque; + VAAPIFramesContext *ctx = hwfc->internal->priv; + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + AVVAAPIFramesContext *avfc = hwfc->hwctx; + VASurfaceID surface_id; + VAStatus vas; + AVBufferRef *ref; + + if (hwfc->initial_pool_size > 0 && + avfc->nb_surfaces >= hwfc->initial_pool_size) + return NULL; + + vas = vaCreateSurfaces(hwctx->display, ctx->rt_format, + hwfc->width, hwfc->height, + &surface_id, 1, + ctx->attributes, ctx->nb_attributes); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: " + "%d (%s).\n", vas, vaErrorStr(vas)); + return NULL; + } + av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id); + + ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id, + sizeof(surface_id), &vaapi_buffer_free, + hwfc, AV_BUFFER_FLAG_READONLY); + if (!ref) { + vaDestroySurfaces(hwctx->display, &surface_id, 1); + return NULL; + } + + if (hwfc->initial_pool_size > 0) { + // This is a fixed-size pool, so we must still be in the initial + // allocation sequence. + av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size); + avfc->surface_ids[avfc->nb_surfaces] = surface_id; + ++avfc->nb_surfaces; + } + + return ref; +} + +static int vaapi_frames_init(AVHWFramesContext *hwfc) +{ + AVVAAPIFramesContext *avfc = hwfc->hwctx; + VAAPIFramesContext *ctx = hwfc->internal->priv; + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + const VAAPIFormatDescriptor *desc; + VAImageFormat *expected_format; + AVBufferRef *test_surface = NULL; + VASurfaceID test_surface_id; + VAImage test_image; + VAStatus vas; + int err, i; + + desc = vaapi_format_from_pix_fmt(hwfc->sw_format); + if (!desc) { + av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n", + av_get_pix_fmt_name(hwfc->sw_format)); + return AVERROR(EINVAL); + } + + if (!hwfc->pool) { + if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) { + int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE); + int need_pixel_format = 1; + for (i = 0; i < avfc->nb_attributes; i++) { + if (avfc->attributes[i].type == VASurfaceAttribMemoryType) + need_memory_type = 0; + if (avfc->attributes[i].type == VASurfaceAttribPixelFormat) + need_pixel_format = 0; + } + ctx->nb_attributes = + avfc->nb_attributes + need_memory_type + need_pixel_format; + + ctx->attributes = av_malloc(ctx->nb_attributes * + sizeof(*ctx->attributes)); + if (!ctx->attributes) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (i = 0; i < avfc->nb_attributes; i++) + ctx->attributes[i] = avfc->attributes[i]; + if (need_memory_type) { + ctx->attributes[i++] = (VASurfaceAttrib) { + .type = VASurfaceAttribMemoryType, + .flags = VA_SURFACE_ATTRIB_SETTABLE, + .value.type = VAGenericValueTypeInteger, + .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA, + }; + } + if (need_pixel_format) { + ctx->attributes[i++] = (VASurfaceAttrib) { + .type = VASurfaceAttribPixelFormat, + .flags = VA_SURFACE_ATTRIB_SETTABLE, + .value.type = VAGenericValueTypeInteger, + .value.value.i = desc->fourcc, + }; + } + av_assert0(i == ctx->nb_attributes); + } else { + ctx->attributes = NULL; + ctx->nb_attributes = 0; + } + + ctx->rt_format = desc->rt_format; + + if (hwfc->initial_pool_size > 0) { + // This pool will be usable as a render target, so we need to store + // all of the surface IDs somewhere that vaCreateContext() calls + // will be able to access them. + avfc->nb_surfaces = 0; + avfc->surface_ids = av_malloc(hwfc->initial_pool_size * + sizeof(*avfc->surface_ids)); + if (!avfc->surface_ids) { + err = AVERROR(ENOMEM); + goto fail; + } + } else { + // This pool allows dynamic sizing, and will not be usable as a + // render target. + avfc->nb_surfaces = 0; + avfc->surface_ids = NULL; + } + + hwfc->internal->pool_internal = + av_buffer_pool_init2(sizeof(VASurfaceID), hwfc, + &vaapi_pool_alloc, NULL); + if (!hwfc->internal->pool_internal) { + av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n"); + err = AVERROR(ENOMEM); + goto fail; + } + } + + // Allocate a single surface to test whether vaDeriveImage() is going + // to work for the specific configuration. + if (hwfc->pool) { + test_surface = av_buffer_pool_get(hwfc->pool); + if (!test_surface) { + av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from " + "user-configured buffer pool.\n"); + err = AVERROR(ENOMEM); + goto fail; + } + } else { + test_surface = av_buffer_pool_get(hwfc->internal->pool_internal); + if (!test_surface) { + av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from " + "internal buffer pool.\n"); + err = AVERROR(ENOMEM); + goto fail; + } + } + test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data; + + ctx->derive_works = 0; + + err = vaapi_get_image_format(hwfc->device_ctx, + hwfc->sw_format, &expected_format); + if (err == 0) { + vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image); + if (vas == VA_STATUS_SUCCESS) { + if (expected_format->fourcc == test_image.format.fourcc) { + av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n"); + ctx->derive_works = 1; + } else { + av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " + "derived image format %08x does not match " + "expected format %08x.\n", + expected_format->fourcc, test_image.format.fourcc); + } + vaDestroyImage(hwctx->display, test_image.image_id); + } else { + av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " + "deriving image does not work: " + "%d (%s).\n", vas, vaErrorStr(vas)); + } + } else { + av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " + "image format is not supported.\n"); + } + + av_buffer_unref(&test_surface); + return 0; + +fail: + av_buffer_unref(&test_surface); + av_freep(&avfc->surface_ids); + av_freep(&ctx->attributes); + return err; +} + +static void vaapi_frames_uninit(AVHWFramesContext *hwfc) +{ + AVVAAPIFramesContext *avfc = hwfc->hwctx; + VAAPIFramesContext *ctx = hwfc->internal->priv; + + av_freep(&avfc->surface_ids); + av_freep(&ctx->attributes); +} + +static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) +{ + frame->buf[0] = av_buffer_pool_get(hwfc->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + + frame->data[3] = frame->buf[0]->data; + frame->format = AV_PIX_FMT_VAAPI; + frame->width = hwfc->width; + frame->height = hwfc->height; + + return 0; +} + +static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ + VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv; + enum AVPixelFormat *pix_fmts; + int i, k, sw_format_available; + + sw_format_available = 0; + for (i = 0; i < ctx->nb_formats; i++) { + if (ctx->formats[i].pix_fmt == hwfc->sw_format) + sw_format_available = 1; + } + + pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts)); + if (!pix_fmts) + return AVERROR(ENOMEM); + + if (sw_format_available) { + pix_fmts[0] = hwfc->sw_format; + k = 1; + } else { + k = 0; + } + for (i = 0; i < ctx->nb_formats; i++) { + if (ctx->formats[i].pix_fmt == hwfc->sw_format) + continue; + av_assert0(k < ctx->nb_formats); + pix_fmts[k++] = ctx->formats[i].pix_fmt; + } + pix_fmts[k] = AV_PIX_FMT_NONE; + + *formats = pix_fmts; + return 0; +} + +static void vaapi_unmap_frame(AVHWFramesContext *hwfc, + HWMapDescriptor *hwmap) +{ + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + VAAPIMapping *map = hwmap->priv; + VASurfaceID surface_id; + VAStatus vas; + + surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3]; + av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id); + + vas = vaUnmapBuffer(hwctx->display, map->image.buf); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface " + "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); + } + + if ((map->flags & AV_HWFRAME_MAP_WRITE) && + !(map->flags & AV_HWFRAME_MAP_DIRECT)) { + vas = vaPutImage(hwctx->display, surface_id, map->image.image_id, + 0, 0, hwfc->width, hwfc->height, + 0, 0, hwfc->width, hwfc->height); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface " + "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); + } + } + + vas = vaDestroyImage(hwctx->display, map->image.image_id); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface " + "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); + } + + av_free(map); +} + +static int vaapi_map_frame(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src, int flags) +{ + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + VAAPIFramesContext *ctx = hwfc->internal->priv; + VASurfaceID surface_id; + const VAAPIFormatDescriptor *desc; + VAImageFormat *image_format; + VAAPIMapping *map; + VAStatus vas; + void *address = NULL; + int err, i; + + surface_id = (VASurfaceID)(uintptr_t)src->data[3]; + av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id); + + if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) { + // Requested direct mapping but it is not possible. + return AVERROR(EINVAL); + } + if (dst->format == AV_PIX_FMT_NONE) + dst->format = hwfc->sw_format; + if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) { + // Requested direct mapping but the formats do not match. + return AVERROR(EINVAL); + } + + err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format); + if (err < 0) { + // Requested format is not a valid output format. + return AVERROR(EINVAL); + } + + map = av_malloc(sizeof(*map)); + if (!map) + return AVERROR(ENOMEM); + map->flags = flags; + map->image.image_id = VA_INVALID_ID; + + vas = vaSyncSurface(hwctx->display, surface_id); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface " + "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + + // The memory which we map using derive need not be connected to the CPU + // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the + // memory is mappable but not cached, so normal memcpy()-like access is + // very slow to read it (but writing is ok). It is possible to read much + // faster with a copy routine which is aware of the limitation, but we + // assume for now that the user is not aware of that and would therefore + // prefer not to be given direct-mapped memory if they request read access. + if (ctx->derive_works && dst->format == hwfc->sw_format && + ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) { + vas = vaDeriveImage(hwctx->display, surface_id, &map->image); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from " + "surface %#x: %d (%s).\n", + surface_id, vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + if (map->image.format.fourcc != image_format->fourcc) { + av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x " + "is in wrong format: expected %#08x, got %#08x.\n", + surface_id, image_format->fourcc, map->image.format.fourcc); + err = AVERROR(EIO); + goto fail; + } + map->flags |= AV_HWFRAME_MAP_DIRECT; + } else { + vas = vaCreateImage(hwctx->display, image_format, + hwfc->width, hwfc->height, &map->image); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to create image for " + "surface %#x: %d (%s).\n", + surface_id, vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) { + vas = vaGetImage(hwctx->display, surface_id, 0, 0, + hwfc->width, hwfc->height, map->image.image_id); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to read image from " + "surface %#x: %d (%s).\n", + surface_id, vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + } + } + + vas = vaMapBuffer(hwctx->display, map->image.buf, &address); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface " + "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + + err = ff_hwframe_map_create(src->hw_frames_ctx, + dst, src, &vaapi_unmap_frame, map); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + for (i = 0; i < map->image.num_planes; i++) { + dst->data[i] = (uint8_t*)address + map->image.offsets[i]; + dst->linesize[i] = map->image.pitches[i]; + } + + desc = vaapi_format_from_fourcc(map->image.format.fourcc); + if (desc && desc->chroma_planes_swapped) { + // Chroma planes are YVU rather than YUV, so swap them. + FFSWAP(uint8_t*, dst->data[1], dst->data[2]); + } + + return 0; + +fail: + if (map) { + if (address) + vaUnmapBuffer(hwctx->display, map->image.buf); + if (map->image.image_id != VA_INVALID_ID) + vaDestroyImage(hwctx->display, map->image.image_id); + av_free(map); + } + return err; +} + +static int vaapi_transfer_data_from(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src) +{ + AVFrame *map; + int err; + + if (dst->width > hwfc->width || dst->height > hwfc->height) + return AVERROR(EINVAL); + + map = av_frame_alloc(); + if (!map) + return AVERROR(ENOMEM); + map->format = dst->format; + + err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ); + if (err) + goto fail; + + map->width = dst->width; + map->height = dst->height; + + err = av_frame_copy(dst, map); + if (err) + goto fail; + + err = 0; +fail: + av_frame_free(&map); + return err; +} + +static int vaapi_transfer_data_to(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src) +{ + AVFrame *map; + int err; + + if (src->width > hwfc->width || src->height > hwfc->height) + return AVERROR(EINVAL); + + map = av_frame_alloc(); + if (!map) + return AVERROR(ENOMEM); + map->format = src->format; + + err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE); + if (err) + goto fail; + + map->width = src->width; + map->height = src->height; + + err = av_frame_copy(map, src); + if (err) + goto fail; + + err = 0; +fail: + av_frame_free(&map); + return err; +} + +static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + int err; + + if (dst->format != AV_PIX_FMT_NONE) { + err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL); + if (err < 0) + return AVERROR(ENOSYS); + } + + err = vaapi_map_frame(hwfc, dst, src, flags); + if (err) + return err; + + err = av_frame_copy_props(dst, src); + if (err) + return err; + + return 0; +} + +#if CONFIG_LIBDRM + +#define DRM_MAP(va, layers, ...) { \ + VA_FOURCC_ ## va, \ + layers, \ + { __VA_ARGS__ } \ + } +static const struct { + uint32_t va_fourcc; + int nb_layer_formats; + uint32_t layer_formats[AV_DRM_MAX_PLANES]; +} vaapi_drm_format_map[] = { +#ifdef DRM_FORMAT_R8 + DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88), +#endif + DRM_MAP(NV12, 1, DRM_FORMAT_NV12), +#if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16) + DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616), +#endif + DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888), + DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888), + DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888), + DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888), +#ifdef VA_FOURCC_ABGR + DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888), + DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888), +#endif + DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888), + DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888), +}; +#undef DRM_MAP + +static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + + VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv; + + av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id); + + vaDestroySurfaces(dst_dev->display, &surface_id, 1); +} + +static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVHWFramesContext *dst_fc = + (AVHWFramesContext*)dst->hw_frames_ctx->data; + AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + const AVDRMFrameDescriptor *desc; + const VAAPIFormatDescriptor *format_desc; + VASurfaceID surface_id; + VAStatus vas; + uint32_t va_fourcc; + int err, i, j, k; + + unsigned long buffer_handle; + VASurfaceAttribExternalBuffers buffer_desc; + VASurfaceAttrib attrs[2] = { + { + .type = VASurfaceAttribMemoryType, + .flags = VA_SURFACE_ATTRIB_SETTABLE, + .value.type = VAGenericValueTypeInteger, + .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME, + }, + { + .type = VASurfaceAttribExternalBufferDescriptor, + .flags = VA_SURFACE_ATTRIB_SETTABLE, + .value.type = VAGenericValueTypePointer, + .value.value.p = &buffer_desc, + } + }; + + desc = (AVDRMFrameDescriptor*)src->data[0]; + + if (desc->nb_objects != 1) { + av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames " + "made from a single DRM object.\n"); + return AVERROR(EINVAL); + } + + va_fourcc = 0; + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) { + if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats) + continue; + for (j = 0; j < desc->nb_layers; j++) { + if (desc->layers[j].format != + vaapi_drm_format_map[i].layer_formats[j]) + break; + } + if (j != desc->nb_layers) + continue; + va_fourcc = vaapi_drm_format_map[i].va_fourcc; + break; + } + if (!va_fourcc) { + av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported " + "by VAAPI.\n"); + return AVERROR(EINVAL); + } + + av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as " + "%08x.\n", desc->objects[0].fd, va_fourcc); + + format_desc = vaapi_format_from_fourcc(va_fourcc); + av_assert0(format_desc); + + buffer_handle = desc->objects[0].fd; + buffer_desc.pixel_format = va_fourcc; + buffer_desc.width = src_fc->width; + buffer_desc.height = src_fc->height; + buffer_desc.data_size = desc->objects[0].size; + buffer_desc.buffers = &buffer_handle; + buffer_desc.num_buffers = 1; + buffer_desc.flags = 0; + + k = 0; + for (i = 0; i < desc->nb_layers; i++) { + for (j = 0; j < desc->layers[i].nb_planes; j++) { + buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch; + buffer_desc.offsets[k] = desc->layers[i].planes[j].offset; + ++k; + } + } + buffer_desc.num_planes = k; + + if (format_desc->chroma_planes_swapped && + buffer_desc.num_planes == 3) { + FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]); + FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]); + } + + vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format, + src->width, src->height, + &surface_id, 1, + attrs, FF_ARRAY_ELEMS(attrs)); + if (vas != VA_STATUS_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM " + "object: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id); + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &vaapi_unmap_from_drm, + (void*)(uintptr_t)surface_id); + if (err < 0) + return err; + + dst->width = src->width; + dst->height = src->height; + dst->data[3] = (uint8_t*)(uintptr_t)surface_id; + + av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to " + "surface %#x.\n", desc->objects[0].fd, surface_id); + + return 0; +} + +#if VA_CHECK_VERSION(1, 1, 0) +static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc, + HWMapDescriptor *hwmap) +{ + AVDRMFrameDescriptor *drm_desc = hwmap->priv; + int i; + + for (i = 0; i < drm_desc->nb_objects; i++) + close(drm_desc->objects[i].fd); + + av_freep(&drm_desc); +} + +static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + VASurfaceID surface_id; + VAStatus vas; + VADRMPRIMESurfaceDescriptor va_desc; + AVDRMFrameDescriptor *drm_desc = NULL; + uint32_t export_flags; + int err, i, j; + + surface_id = (VASurfaceID)(uintptr_t)src->data[3]; + + export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS; + if (flags & AV_HWFRAME_MAP_READ) + export_flags |= VA_EXPORT_SURFACE_READ_ONLY; + if (flags & AV_HWFRAME_MAP_WRITE) + export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY; + + vas = vaExportSurfaceHandle(hwctx->display, surface_id, + VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, + export_flags, &va_desc); + if (vas != VA_STATUS_SUCCESS) { + if (vas == VA_STATUS_ERROR_UNIMPLEMENTED) + return AVERROR(ENOSYS); + av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: " + "%d (%s).\n", surface_id, vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + + drm_desc = av_mallocz(sizeof(*drm_desc)); + if (!drm_desc) { + err = AVERROR(ENOMEM); + goto fail; + } + + // By some bizarre coincidence, these structures are very similar... + drm_desc->nb_objects = va_desc.num_objects; + for (i = 0; i < va_desc.num_objects; i++) { + drm_desc->objects[i].fd = va_desc.objects[i].fd; + drm_desc->objects[i].size = va_desc.objects[i].size; + drm_desc->objects[i].format_modifier = + va_desc.objects[i].drm_format_modifier; + } + drm_desc->nb_layers = va_desc.num_layers; + for (i = 0; i < va_desc.num_layers; i++) { + drm_desc->layers[i].format = va_desc.layers[i].drm_format; + drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes; + for (j = 0; j < va_desc.layers[i].num_planes; j++) { + drm_desc->layers[i].planes[j].object_index = + va_desc.layers[i].object_index[j]; + drm_desc->layers[i].planes[j].offset = + va_desc.layers[i].offset[j]; + drm_desc->layers[i].planes[j].pitch = + va_desc.layers[i].pitch[j]; + } + } + + err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, + &vaapi_unmap_to_drm_esh, drm_desc); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + dst->data[0] = (uint8_t*)drm_desc; + + return 0; + +fail: + for (i = 0; i < va_desc.num_objects; i++) + close(va_desc.objects[i].fd); + av_freep(&drm_desc); + return err; +} +#endif + +#if VA_CHECK_VERSION(0, 36, 0) +typedef struct VAAPIDRMImageBufferMapping { + VAImage image; + VABufferInfo buffer_info; + + AVDRMFrameDescriptor drm_desc; +} VAAPIDRMImageBufferMapping; + +static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc, + HWMapDescriptor *hwmap) +{ + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + VAAPIDRMImageBufferMapping *mapping = hwmap->priv; + VASurfaceID surface_id; + VAStatus vas; + + surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3]; + av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n", + surface_id); + + // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(), + // so we shouldn't close them separately. + + vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer " + "handle of image %#x (derived from surface %#x): " + "%d (%s).\n", mapping->image.buf, surface_id, + vas, vaErrorStr(vas)); + } + + vas = vaDestroyImage(hwctx->display, mapping->image.image_id); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image " + "derived from surface %#x: %d (%s).\n", + surface_id, vas, vaErrorStr(vas)); + } + + av_free(mapping); +} + +static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + VAAPIDRMImageBufferMapping *mapping = NULL; + VASurfaceID surface_id; + VAStatus vas; + int err, i, p; + + surface_id = (VASurfaceID)(uintptr_t)src->data[3]; + av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n", + surface_id); + + mapping = av_mallocz(sizeof(*mapping)); + if (!mapping) + return AVERROR(ENOMEM); + + vas = vaDeriveImage(hwctx->display, surface_id, + &mapping->image); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from " + "surface %#x: %d (%s).\n", + surface_id, vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) { + if (vaapi_drm_format_map[i].va_fourcc == + mapping->image.format.fourcc) + break; + } + if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) { + av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for " + "VAAPI format %#x.\n", mapping->image.format.fourcc); + err = AVERROR(EINVAL); + goto fail_derived; + } + + mapping->buffer_info.mem_type = + VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; + + mapping->drm_desc.nb_layers = + vaapi_drm_format_map[i].nb_layer_formats; + if (mapping->drm_desc.nb_layers > 1) { + if (mapping->drm_desc.nb_layers != mapping->image.num_planes) { + av_log(hwfc, AV_LOG_ERROR, "Image properties do not match " + "expected format: got %d planes, but expected %d.\n", + mapping->image.num_planes, mapping->drm_desc.nb_layers); + err = AVERROR(EINVAL); + goto fail_derived; + } + + for(p = 0; p < mapping->drm_desc.nb_layers; p++) { + mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) { + .format = vaapi_drm_format_map[i].layer_formats[p], + .nb_planes = 1, + .planes[0] = { + .object_index = 0, + .offset = mapping->image.offsets[p], + .pitch = mapping->image.pitches[p], + }, + }; + } + } else { + mapping->drm_desc.layers[0].format = + vaapi_drm_format_map[i].layer_formats[0]; + mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes; + for (p = 0; p < mapping->image.num_planes; p++) { + mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) { + .object_index = 0, + .offset = mapping->image.offsets[p], + .pitch = mapping->image.pitches[p], + }; + } + } + + vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf, + &mapping->buffer_info); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer " + "handle from image %#x (derived from surface %#x): " + "%d (%s).\n", mapping->image.buf, surface_id, + vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail_derived; + } + + av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n", + mapping->buffer_info.handle); + + mapping->drm_desc.nb_objects = 1; + mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) { + .fd = mapping->buffer_info.handle, + .size = mapping->image.data_size, + // There is no way to get the format modifier with this API. + .format_modifier = DRM_FORMAT_MOD_INVALID, + }; + + err = ff_hwframe_map_create(src->hw_frames_ctx, + dst, src, &vaapi_unmap_to_drm_abh, + mapping); + if (err < 0) + goto fail_mapped; + + dst->data[0] = (uint8_t*)&mapping->drm_desc; + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail_mapped: + vaReleaseBufferHandle(hwctx->display, mapping->image.buf); +fail_derived: + vaDestroyImage(hwctx->display, mapping->image.image_id); +fail: + av_freep(&mapping); + return err; +} +#endif + +static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ +#if VA_CHECK_VERSION(1, 1, 0) + int err; + err = vaapi_map_to_drm_esh(hwfc, dst, src, flags); + if (err != AVERROR(ENOSYS)) + return err; +#endif +#if VA_CHECK_VERSION(0, 36, 0) + return vaapi_map_to_drm_abh(hwfc, dst, src, flags); +#endif + return AVERROR(ENOSYS); +} + +#endif /* CONFIG_LIBDRM */ + +static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + switch (src->format) { +#if CONFIG_LIBDRM + case AV_PIX_FMT_DRM_PRIME: + return vaapi_map_from_drm(hwfc, dst, src, flags); +#endif + default: + return AVERROR(ENOSYS); + } +} + +static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + switch (dst->format) { +#if CONFIG_LIBDRM + case AV_PIX_FMT_DRM_PRIME: + return vaapi_map_to_drm(hwfc, dst, src, flags); +#endif + default: + return vaapi_map_to_memory(hwfc, dst, src, flags); + } +} + +static void vaapi_device_free(AVHWDeviceContext *ctx) +{ + AVVAAPIDeviceContext *hwctx = ctx->hwctx; + VAAPIDevicePriv *priv = ctx->user_opaque; + + if (hwctx->display) + vaTerminate(hwctx->display); + +#if HAVE_VAAPI_X11 + if (priv->x11_display) + XCloseDisplay(priv->x11_display); +#endif + + if (priv->drm_fd >= 0) + close(priv->drm_fd); + + av_freep(&priv); +} + +#if CONFIG_VAAPI_1 +static void vaapi_device_log_error(void *context, const char *message) +{ + AVHWDeviceContext *ctx = context; + + av_log(ctx, AV_LOG_ERROR, "libva: %s", message); +} + +static void vaapi_device_log_info(void *context, const char *message) +{ + AVHWDeviceContext *ctx = context; + + av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message); +} +#endif + +static int vaapi_device_connect(AVHWDeviceContext *ctx, + VADisplay display) +{ + AVVAAPIDeviceContext *hwctx = ctx->hwctx; + int major, minor; + VAStatus vas; + +#if CONFIG_VAAPI_1 + vaSetErrorCallback(display, &vaapi_device_log_error, ctx); + vaSetInfoCallback (display, &vaapi_device_log_info, ctx); +#endif + + hwctx->display = display; + + vas = vaInitialize(display, &major, &minor); + if (vas != VA_STATUS_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI " + "connection: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: " + "version %d.%d\n", major, minor); + + return 0; +} + +static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + VAAPIDevicePriv *priv; + VADisplay display = NULL; + const AVDictionaryEntry *ent; + int try_drm, try_x11, try_all; + + priv = av_mallocz(sizeof(*priv)); + if (!priv) + return AVERROR(ENOMEM); + + priv->drm_fd = -1; + + ctx->user_opaque = priv; + ctx->free = vaapi_device_free; + + ent = av_dict_get(opts, "connection_type", NULL, 0); + if (ent) { + try_all = try_drm = try_x11 = 0; + if (!strcmp(ent->value, "drm")) { + try_drm = 1; + } else if (!strcmp(ent->value, "x11")) { + try_x11 = 1; + } else { + av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n", + ent->value); + return AVERROR(EINVAL); + } + } else { + try_all = 1; + try_drm = HAVE_VAAPI_DRM; + try_x11 = HAVE_VAAPI_X11; + } + +#if HAVE_VAAPI_DRM + while (!display && try_drm) { + // If the device is specified, try to open it as a DRM device node. + // If not, look for a usable render node, possibly restricted to those + // using a specified kernel driver. + int loglevel = try_all ? AV_LOG_VERBOSE : AV_LOG_ERROR; + if (device) { + priv->drm_fd = open(device, O_RDWR); + if (priv->drm_fd < 0) { + av_log(ctx, loglevel, "Failed to open %s as " + "DRM device node.\n", device); + break; + } + } else { + char path[64]; + int n, max_devices = 8; +#if CONFIG_LIBDRM + const AVDictionaryEntry *kernel_driver; + kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0); +#endif + for (n = 0; n < max_devices; n++) { + snprintf(path, sizeof(path), + "/dev/dri/renderD%d", 128 + n); + priv->drm_fd = open(path, O_RDWR); + if (priv->drm_fd < 0) { + av_log(ctx, AV_LOG_VERBOSE, "Cannot open " + "DRM render node for device %d.\n", n); + break; + } +#if CONFIG_LIBDRM + if (kernel_driver) { + drmVersion *info; + info = drmGetVersion(priv->drm_fd); + if (strcmp(kernel_driver->value, info->name)) { + av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d " + "with non-matching kernel driver (%s).\n", + n, info->name); + drmFreeVersion(info); + close(priv->drm_fd); + priv->drm_fd = -1; + continue; + } + av_log(ctx, AV_LOG_VERBOSE, "Trying to use " + "DRM render node for device %d, " + "with matching kernel driver (%s).\n", + n, info->name); + drmFreeVersion(info); + } else +#endif + { + av_log(ctx, AV_LOG_VERBOSE, "Trying to use " + "DRM render node for device %d.\n", n); + } + break; + } + if (n >= max_devices) + break; + } + + display = vaGetDisplayDRM(priv->drm_fd); + if (!display) { + av_log(ctx, AV_LOG_VERBOSE, "Cannot open a VA display " + "from DRM device %s.\n", device); + return AVERROR_EXTERNAL; + } + break; + } +#endif + +#if HAVE_VAAPI_X11 + if (!display && try_x11) { + // Try to open the device as an X11 display. + priv->x11_display = XOpenDisplay(device); + if (!priv->x11_display) { + av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display " + "%s.\n", XDisplayName(device)); + } else { + display = vaGetDisplay(priv->x11_display); + if (!display) { + av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display " + "from X11 display %s.\n", XDisplayName(device)); + return AVERROR_UNKNOWN; + } + + av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via " + "X11 display %s.\n", XDisplayName(device)); + } + } +#endif + + if (!display) { + if (device) + av_log(ctx, AV_LOG_ERROR, "No VA display found for " + "device %s.\n", device); + else + av_log(ctx, AV_LOG_ERROR, "No VA display found for " + "any default device.\n"); + return AVERROR(EINVAL); + } + + ent = av_dict_get(opts, "driver", NULL, 0); + if (ent) { +#if VA_CHECK_VERSION(0, 38, 0) + VAStatus vas; + vas = vaSetDriverName(display, ent->value); + if (vas != VA_STATUS_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "Failed to set driver name to " + "%s: %d (%s).\n", ent->value, vas, vaErrorStr(vas)); + vaTerminate(display); + return AVERROR_EXTERNAL; + } +#else + av_log(ctx, AV_LOG_WARNING, "Driver name setting is not " + "supported with this VAAPI version.\n"); +#endif + } + + return vaapi_device_connect(ctx, display); +} + +static int vaapi_device_derive(AVHWDeviceContext *ctx, + AVHWDeviceContext *src_ctx, int flags) +{ +#if HAVE_VAAPI_DRM + if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) { + AVDRMDeviceContext *src_hwctx = src_ctx->hwctx; + VADisplay *display; + VAAPIDevicePriv *priv; + + if (src_hwctx->fd < 0) { + av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated " + "device to derive a VA display from.\n"); + return AVERROR(EINVAL); + } + + priv = av_mallocz(sizeof(*priv)); + if (!priv) + return AVERROR(ENOMEM); + + // Inherits the fd from the source context, which will close it. + priv->drm_fd = -1; + + ctx->user_opaque = priv; + ctx->free = &vaapi_device_free; + + display = vaGetDisplayDRM(src_hwctx->fd); + if (!display) { + av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from " + "DRM device.\n"); + return AVERROR(EIO); + } + + return vaapi_device_connect(ctx, display); + } +#endif + return AVERROR(ENOSYS); +} + +const HWContextType ff_hwcontext_type_vaapi = { + .type = AV_HWDEVICE_TYPE_VAAPI, + .name = "VAAPI", + + .device_hwctx_size = sizeof(AVVAAPIDeviceContext), + .device_priv_size = sizeof(VAAPIDeviceContext), + .device_hwconfig_size = sizeof(AVVAAPIHWConfig), + .frames_hwctx_size = sizeof(AVVAAPIFramesContext), + .frames_priv_size = sizeof(VAAPIFramesContext), + + .device_create = &vaapi_device_create, + .device_derive = &vaapi_device_derive, + .device_init = &vaapi_device_init, + .device_uninit = &vaapi_device_uninit, + .frames_get_constraints = &vaapi_frames_get_constraints, + .frames_init = &vaapi_frames_init, + .frames_uninit = &vaapi_frames_uninit, + .frames_get_buffer = &vaapi_get_buffer, + .transfer_get_formats = &vaapi_transfer_get_formats, + .transfer_data_to = &vaapi_transfer_data_to, + .transfer_data_from = &vaapi_transfer_data_from, + .map_to = &vaapi_map_to, + .map_from = &vaapi_map_from, + + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_VAAPI, + AV_PIX_FMT_NONE + }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vaapi.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vaapi.h new file mode 100644 index 0000000000..0b2e071cb3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vaapi.h @@ -0,0 +1,117 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_VAAPI_H +#define AVUTIL_HWCONTEXT_VAAPI_H + +#include + +/** + * @file + * API-specific header for AV_HWDEVICE_TYPE_VAAPI. + * + * Dynamic frame pools are supported, but note that any pool used as a render + * target is required to be of fixed size in order to be be usable as an + * argument to vaCreateContext(). + * + * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer set to a VASurfaceID. + */ + +enum { + /** + * The quirks field has been set by the user and should not be detected + * automatically by av_hwdevice_ctx_init(). + */ + AV_VAAPI_DRIVER_QUIRK_USER_SET = (1 << 0), + /** + * The driver does not destroy parameter buffers when they are used by + * vaRenderPicture(). Additional code will be required to destroy them + * separately afterwards. + */ + AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS = (1 << 1), + + /** + * The driver does not support the VASurfaceAttribMemoryType attribute, + * so the surface allocation code will not try to use it. + */ + AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE = (1 << 2), + + /** + * The driver does not support surface attributes at all. + * The surface allocation code will never pass them to surface allocation, + * and the results of the vaQuerySurfaceAttributes() call will be faked. + */ + AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES = (1 << 3), +}; + +/** + * VAAPI connection details. + * + * Allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVVAAPIDeviceContext { + /** + * The VADisplay handle, to be filled by the user. + */ + VADisplay display; + /** + * Driver quirks to apply - this is filled by av_hwdevice_ctx_init(), + * with reference to a table of known drivers, unless the + * AV_VAAPI_DRIVER_QUIRK_USER_SET bit is already present. The user + * may need to refer to this field when performing any later + * operations using VAAPI with the same VADisplay. + */ + unsigned int driver_quirks; +} AVVAAPIDeviceContext; + +/** + * VAAPI-specific data associated with a frame pool. + * + * Allocated as AVHWFramesContext.hwctx. + */ +typedef struct AVVAAPIFramesContext { + /** + * Set by the user to apply surface attributes to all surfaces in + * the frame pool. If null, default settings are used. + */ + VASurfaceAttrib *attributes; + int nb_attributes; + /** + * The surfaces IDs of all surfaces in the pool after creation. + * Only valid if AVHWFramesContext.initial_pool_size was positive. + * These are intended to be used as the render_targets arguments to + * vaCreateContext(). + */ + VASurfaceID *surface_ids; + int nb_surfaces; +} AVVAAPIFramesContext; + +/** + * VAAPI hardware pipeline configuration details. + * + * Allocated with av_hwdevice_hwconfig_alloc(). + */ +typedef struct AVVAAPIHWConfig { + /** + * ID of a VAAPI pipeline configuration. + */ + VAConfigID config_id; +} AVVAAPIHWConfig; + +#endif /* AVUTIL_HWCONTEXT_VAAPI_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vdpau.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vdpau.c new file mode 100644 index 0000000000..6b8c1d5f76 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vdpau.c @@ -0,0 +1,511 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include + +#include + +#include "buffer.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_internal.h" +#include "hwcontext_vdpau.h" +#include "mem.h" +#include "pixfmt.h" +#include "pixdesc.h" + +typedef struct VDPAUDeviceContext { + VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities *get_transfer_caps; + VdpVideoSurfaceGetBitsYCbCr *get_data; + VdpVideoSurfacePutBitsYCbCr *put_data; + VdpVideoSurfaceCreate *surf_create; + VdpVideoSurfaceDestroy *surf_destroy; + + enum AVPixelFormat *pix_fmts[3]; + int nb_pix_fmts[3]; +} VDPAUDeviceContext; + +typedef struct VDPAUFramesContext { + VdpVideoSurfaceGetBitsYCbCr *get_data; + VdpVideoSurfacePutBitsYCbCr *put_data; + VdpChromaType chroma_type; + int chroma_idx; + + const enum AVPixelFormat *pix_fmts; + int nb_pix_fmts; +} VDPAUFramesContext; + +typedef struct VDPAUPixFmtMap { + VdpYCbCrFormat vdpau_fmt; + enum AVPixelFormat pix_fmt; +} VDPAUPixFmtMap; + +static const VDPAUPixFmtMap pix_fmts_420[] = { + { VDP_YCBCR_FORMAT_NV12, AV_PIX_FMT_NV12 }, + { VDP_YCBCR_FORMAT_YV12, AV_PIX_FMT_YUV420P }, + { 0, AV_PIX_FMT_NONE, }, +}; + +static const VDPAUPixFmtMap pix_fmts_422[] = { + { VDP_YCBCR_FORMAT_NV12, AV_PIX_FMT_NV16 }, + { VDP_YCBCR_FORMAT_YV12, AV_PIX_FMT_YUV422P }, + { VDP_YCBCR_FORMAT_UYVY, AV_PIX_FMT_UYVY422 }, + { VDP_YCBCR_FORMAT_YUYV, AV_PIX_FMT_YUYV422 }, + { 0, AV_PIX_FMT_NONE, }, +}; + +static const VDPAUPixFmtMap pix_fmts_444[] = { +#ifdef VDP_YCBCR_FORMAT_Y_U_V_444 + { VDP_YCBCR_FORMAT_Y_U_V_444, AV_PIX_FMT_YUV444P }, +#endif + { 0, AV_PIX_FMT_NONE, }, +}; + +static const struct { + VdpChromaType chroma_type; + enum AVPixelFormat frames_sw_format; + const VDPAUPixFmtMap *map; +} vdpau_pix_fmts[] = { + { VDP_CHROMA_TYPE_420, AV_PIX_FMT_YUV420P, pix_fmts_420 }, + { VDP_CHROMA_TYPE_422, AV_PIX_FMT_YUV422P, pix_fmts_422 }, + { VDP_CHROMA_TYPE_444, AV_PIX_FMT_YUV444P, pix_fmts_444 }, +}; + +static int count_pixfmts(const VDPAUPixFmtMap *map) +{ + int count = 0; + while (map->pix_fmt != AV_PIX_FMT_NONE) { + map++; + count++; + } + return count; +} + +static int vdpau_init_pixmfts(AVHWDeviceContext *ctx) +{ + AVVDPAUDeviceContext *hwctx = ctx->hwctx; + VDPAUDeviceContext *priv = ctx->internal->priv; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(priv->pix_fmts); i++) { + const VDPAUPixFmtMap *map = vdpau_pix_fmts[i].map; + int nb_pix_fmts; + + nb_pix_fmts = count_pixfmts(map); + priv->pix_fmts[i] = av_malloc_array(nb_pix_fmts + 1, sizeof(*priv->pix_fmts[i])); + if (!priv->pix_fmts[i]) + return AVERROR(ENOMEM); + + nb_pix_fmts = 0; + while (map->pix_fmt != AV_PIX_FMT_NONE) { + VdpBool supported; + VdpStatus err = priv->get_transfer_caps(hwctx->device, vdpau_pix_fmts[i].chroma_type, + map->vdpau_fmt, &supported); + if (err == VDP_STATUS_OK && supported) + priv->pix_fmts[i][nb_pix_fmts++] = map->pix_fmt; + map++; + } + priv->pix_fmts[i][nb_pix_fmts++] = AV_PIX_FMT_NONE; + priv->nb_pix_fmts[i] = nb_pix_fmts; + } + + return 0; +} + +#define GET_CALLBACK(id, result) \ +do { \ + void *tmp; \ + err = hwctx->get_proc_address(hwctx->device, id, &tmp); \ + if (err != VDP_STATUS_OK) { \ + av_log(ctx, AV_LOG_ERROR, "Error getting the " #id " callback.\n"); \ + return AVERROR_UNKNOWN; \ + } \ + result = tmp; \ +} while (0) + +static int vdpau_device_init(AVHWDeviceContext *ctx) +{ + AVVDPAUDeviceContext *hwctx = ctx->hwctx; + VDPAUDeviceContext *priv = ctx->internal->priv; + VdpStatus err; + int ret; + + GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES, + priv->get_transfer_caps); + GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, priv->get_data); + GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR, priv->put_data); + GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_CREATE, priv->surf_create); + GET_CALLBACK(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, priv->surf_destroy); + + ret = vdpau_init_pixmfts(ctx); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error querying the supported pixel formats\n"); + return ret; + } + + return 0; +} + +static void vdpau_device_uninit(AVHWDeviceContext *ctx) +{ + VDPAUDeviceContext *priv = ctx->internal->priv; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(priv->pix_fmts); i++) + av_freep(&priv->pix_fmts[i]); +} + +static int vdpau_frames_get_constraints(AVHWDeviceContext *ctx, + const void *hwconfig, + AVHWFramesConstraints *constraints) +{ + VDPAUDeviceContext *priv = ctx->internal->priv; + int nb_sw_formats = 0; + int i; + + constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(vdpau_pix_fmts) + 1, + sizeof(*constraints->valid_sw_formats)); + if (!constraints->valid_sw_formats) + return AVERROR(ENOMEM); + + for (i = 0; i < FF_ARRAY_ELEMS(vdpau_pix_fmts); i++) { + if (priv->nb_pix_fmts[i] > 1) + constraints->valid_sw_formats[nb_sw_formats++] = vdpau_pix_fmts[i].frames_sw_format; + } + constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE; + + constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); + if (!constraints->valid_hw_formats) + return AVERROR(ENOMEM); + + constraints->valid_hw_formats[0] = AV_PIX_FMT_VDPAU; + constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; + + return 0; +} + +static void vdpau_buffer_free(void *opaque, uint8_t *data) +{ + AVHWFramesContext *ctx = opaque; + VDPAUDeviceContext *device_priv = ctx->device_ctx->internal->priv; + VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)data; + + device_priv->surf_destroy(surf); +} + +static AVBufferRef *vdpau_pool_alloc(void *opaque, int size) +{ + AVHWFramesContext *ctx = opaque; + VDPAUFramesContext *priv = ctx->internal->priv; + AVVDPAUDeviceContext *device_hwctx = ctx->device_ctx->hwctx; + VDPAUDeviceContext *device_priv = ctx->device_ctx->internal->priv; + + AVBufferRef *ret; + VdpVideoSurface surf; + VdpStatus err; + + err = device_priv->surf_create(device_hwctx->device, priv->chroma_type, + ctx->width, ctx->height, &surf); + if (err != VDP_STATUS_OK) { + av_log(ctx, AV_LOG_ERROR, "Error allocating a VDPAU video surface\n"); + return NULL; + } + + ret = av_buffer_create((uint8_t*)(uintptr_t)surf, sizeof(surf), + vdpau_buffer_free, ctx, AV_BUFFER_FLAG_READONLY); + if (!ret) { + device_priv->surf_destroy(surf); + return NULL; + } + + return ret; +} + +static int vdpau_frames_init(AVHWFramesContext *ctx) +{ + VDPAUDeviceContext *device_priv = ctx->device_ctx->internal->priv; + VDPAUFramesContext *priv = ctx->internal->priv; + + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(vdpau_pix_fmts); i++) { + if (vdpau_pix_fmts[i].frames_sw_format == ctx->sw_format) { + priv->chroma_type = vdpau_pix_fmts[i].chroma_type; + priv->chroma_idx = i; + priv->pix_fmts = device_priv->pix_fmts[i]; + priv->nb_pix_fmts = device_priv->nb_pix_fmts[i]; + break; + } + } + if (priv->nb_pix_fmts < 2) { + av_log(ctx, AV_LOG_ERROR, "Unsupported sw format: %s\n", + av_get_pix_fmt_name(ctx->sw_format)); + return AVERROR(ENOSYS); + } + + if (!ctx->pool) { + ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(VdpVideoSurface), ctx, + vdpau_pool_alloc, NULL); + if (!ctx->internal->pool_internal) + return AVERROR(ENOMEM); + } + + priv->get_data = device_priv->get_data; + priv->put_data = device_priv->put_data; + + return 0; +} + +static int vdpau_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) +{ + frame->buf[0] = av_buffer_pool_get(ctx->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + + frame->data[3] = frame->buf[0]->data; + frame->format = AV_PIX_FMT_VDPAU; + frame->width = ctx->width; + frame->height = ctx->height; + + return 0; +} + +static int vdpau_transfer_get_formats(AVHWFramesContext *ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ + VDPAUFramesContext *priv = ctx->internal->priv; + + enum AVPixelFormat *fmts; + + if (priv->nb_pix_fmts == 1) { + av_log(ctx, AV_LOG_ERROR, + "No target formats are supported for this chroma type\n"); + return AVERROR(ENOSYS); + } + + fmts = av_malloc_array(priv->nb_pix_fmts, sizeof(*fmts)); + if (!fmts) + return AVERROR(ENOMEM); + + memcpy(fmts, priv->pix_fmts, sizeof(*fmts) * (priv->nb_pix_fmts)); + *formats = fmts; + + return 0; +} + +static int vdpau_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src) +{ + VDPAUFramesContext *priv = ctx->internal->priv; + VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)src->data[3]; + + void *data[3]; + uint32_t linesize[3]; + + const VDPAUPixFmtMap *map; + VdpYCbCrFormat vdpau_format; + VdpStatus err; + int i; + + for (i = 0; i< FF_ARRAY_ELEMS(data) && dst->data[i]; i++) { + data[i] = dst->data[i]; + if (dst->linesize[i] < 0 || dst->linesize[i] > UINT32_MAX) { + av_log(ctx, AV_LOG_ERROR, + "The linesize %d cannot be represented as uint32\n", + dst->linesize[i]); + return AVERROR(ERANGE); + } + linesize[i] = dst->linesize[i]; + } + + map = vdpau_pix_fmts[priv->chroma_idx].map; + for (i = 0; map[i].pix_fmt != AV_PIX_FMT_NONE; i++) { + if (map[i].pix_fmt == dst->format) { + vdpau_format = map[i].vdpau_fmt; + break; + } + } + if (map[i].pix_fmt == AV_PIX_FMT_NONE) { + av_log(ctx, AV_LOG_ERROR, + "Unsupported target pixel format: %s\n", + av_get_pix_fmt_name(dst->format)); + return AVERROR(EINVAL); + } + + if ((vdpau_format == VDP_YCBCR_FORMAT_YV12) +#ifdef VDP_YCBCR_FORMAT_Y_U_V_444 + || (vdpau_format == VDP_YCBCR_FORMAT_Y_U_V_444) +#endif + ) + FFSWAP(void*, data[1], data[2]); + + err = priv->get_data(surf, vdpau_format, data, linesize); + if (err != VDP_STATUS_OK) { + av_log(ctx, AV_LOG_ERROR, "Error retrieving the data from a VDPAU surface\n"); + return AVERROR_UNKNOWN; + } + + return 0; +} + +static int vdpau_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src) +{ + VDPAUFramesContext *priv = ctx->internal->priv; + VdpVideoSurface surf = (VdpVideoSurface)(uintptr_t)dst->data[3]; + + const void *data[3]; + uint32_t linesize[3]; + + const VDPAUPixFmtMap *map; + VdpYCbCrFormat vdpau_format; + VdpStatus err; + int i; + + for (i = 0; i< FF_ARRAY_ELEMS(data) && src->data[i]; i++) { + data[i] = src->data[i]; + if (src->linesize[i] < 0 || src->linesize[i] > UINT32_MAX) { + av_log(ctx, AV_LOG_ERROR, + "The linesize %d cannot be represented as uint32\n", + src->linesize[i]); + return AVERROR(ERANGE); + } + linesize[i] = src->linesize[i]; + } + + map = vdpau_pix_fmts[priv->chroma_idx].map; + for (i = 0; map[i].pix_fmt != AV_PIX_FMT_NONE; i++) { + if (map[i].pix_fmt == src->format) { + vdpau_format = map[i].vdpau_fmt; + break; + } + } + if (map[i].pix_fmt == AV_PIX_FMT_NONE) { + av_log(ctx, AV_LOG_ERROR, + "Unsupported source pixel format: %s\n", + av_get_pix_fmt_name(src->format)); + return AVERROR(EINVAL); + } + + if ((vdpau_format == VDP_YCBCR_FORMAT_YV12) +#ifdef VDP_YCBCR_FORMAT_Y_U_V_444 + || (vdpau_format == VDP_YCBCR_FORMAT_Y_U_V_444) +#endif + ) + FFSWAP(const void*, data[1], data[2]); + + err = priv->put_data(surf, vdpau_format, data, linesize); + if (err != VDP_STATUS_OK) { + av_log(ctx, AV_LOG_ERROR, "Error uploading the data to a VDPAU surface\n"); + return AVERROR_UNKNOWN; + } + + return 0; +} + +#if HAVE_VDPAU_X11 +#include +#include + +typedef struct VDPAUDevicePriv { + VdpDeviceDestroy *device_destroy; + Display *dpy; +} VDPAUDevicePriv; + +static void vdpau_device_free(AVHWDeviceContext *ctx) +{ + AVVDPAUDeviceContext *hwctx = ctx->hwctx; + VDPAUDevicePriv *priv = ctx->user_opaque; + + if (priv->device_destroy) + priv->device_destroy(hwctx->device); + if (priv->dpy) + XCloseDisplay(priv->dpy); + av_freep(&priv); +} + +static int vdpau_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + AVVDPAUDeviceContext *hwctx = ctx->hwctx; + + VDPAUDevicePriv *priv; + VdpStatus err; + VdpGetInformationString *get_information_string; + const char *display, *vendor; + + priv = av_mallocz(sizeof(*priv)); + if (!priv) + return AVERROR(ENOMEM); + + ctx->user_opaque = priv; + ctx->free = vdpau_device_free; + + priv->dpy = XOpenDisplay(device); + if (!priv->dpy) { + av_log(ctx, AV_LOG_ERROR, "Cannot open the X11 display %s.\n", + XDisplayName(device)); + return AVERROR_UNKNOWN; + } + display = XDisplayString(priv->dpy); + + err = vdp_device_create_x11(priv->dpy, XDefaultScreen(priv->dpy), + &hwctx->device, &hwctx->get_proc_address); + if (err != VDP_STATUS_OK) { + av_log(ctx, AV_LOG_ERROR, "VDPAU device creation on X11 display %s failed.\n", + display); + return AVERROR_UNKNOWN; + } + + GET_CALLBACK(VDP_FUNC_ID_GET_INFORMATION_STRING, get_information_string); + GET_CALLBACK(VDP_FUNC_ID_DEVICE_DESTROY, priv->device_destroy); + + get_information_string(&vendor); + av_log(ctx, AV_LOG_VERBOSE, "Successfully created a VDPAU device (%s) on " + "X11 display %s\n", vendor, display); + + return 0; +} +#endif + +const HWContextType ff_hwcontext_type_vdpau = { + .type = AV_HWDEVICE_TYPE_VDPAU, + .name = "VDPAU", + + .device_hwctx_size = sizeof(AVVDPAUDeviceContext), + .device_priv_size = sizeof(VDPAUDeviceContext), + .frames_priv_size = sizeof(VDPAUFramesContext), + +#if HAVE_VDPAU_X11 + .device_create = vdpau_device_create, +#endif + .device_init = vdpau_device_init, + .device_uninit = vdpau_device_uninit, + .frames_get_constraints = vdpau_frames_get_constraints, + .frames_init = vdpau_frames_init, + .frames_get_buffer = vdpau_get_buffer, + .transfer_get_formats = vdpau_transfer_get_formats, + .transfer_data_to = vdpau_transfer_data_to, + .transfer_data_from = vdpau_transfer_data_from, + + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VDPAU, AV_PIX_FMT_NONE }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vdpau.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vdpau.h new file mode 100644 index 0000000000..1b7ea1e443 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_vdpau.h @@ -0,0 +1,44 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_VDPAU_H +#define AVUTIL_HWCONTEXT_VDPAU_H + +#include + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_VDPAU. + * + * This API supports dynamic frame pools. AVHWFramesContext.pool must return + * AVBufferRefs whose data pointer is a VdpVideoSurface. + */ + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVVDPAUDeviceContext { + VdpDevice device; + VdpGetProcAddress *get_proc_address; +} AVVDPAUDeviceContext; + +/** + * AVHWFramesContext.hwctx is currently not used + */ + +#endif /* AVUTIL_HWCONTEXT_VDPAU_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_videotoolbox.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_videotoolbox.c new file mode 100644 index 0000000000..6eac2c0774 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_videotoolbox.c @@ -0,0 +1,246 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include + +#include + +#include "buffer.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_internal.h" +#include "hwcontext_videotoolbox.h" +#include "mem.h" +#include "pixfmt.h" +#include "pixdesc.h" + +static const struct { + uint32_t cv_fmt; + enum AVPixelFormat pix_fmt; +} cv_pix_fmts[] = { + { kCVPixelFormatType_420YpCbCr8Planar, AV_PIX_FMT_YUV420P }, + { kCVPixelFormatType_422YpCbCr8, AV_PIX_FMT_UYVY422 }, + { kCVPixelFormatType_32BGRA, AV_PIX_FMT_BGRA }, +#ifdef kCFCoreFoundationVersionNumber10_7 + { kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, AV_PIX_FMT_NV12 }, +#endif +#if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE + { kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange, AV_PIX_FMT_P010 }, +#endif +}; + +enum AVPixelFormat av_map_videotoolbox_format_to_pixfmt(uint32_t cv_fmt) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(cv_pix_fmts); i++) { + if (cv_pix_fmts[i].cv_fmt == cv_fmt) + return cv_pix_fmts[i].pix_fmt; + } + return AV_PIX_FMT_NONE; +} + +uint32_t av_map_videotoolbox_format_from_pixfmt(enum AVPixelFormat pix_fmt) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(cv_pix_fmts); i++) { + if (cv_pix_fmts[i].pix_fmt == pix_fmt) + return cv_pix_fmts[i].cv_fmt; + } + return 0; +} + +static int vt_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) +{ + frame->buf[0] = av_buffer_pool_get(ctx->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + + frame->data[3] = frame->buf[0]->data; + frame->format = AV_PIX_FMT_VIDEOTOOLBOX; + frame->width = ctx->width; + frame->height = ctx->height; + + return 0; +} + +static int vt_transfer_get_formats(AVHWFramesContext *ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ + enum AVPixelFormat *fmts = av_malloc_array(2, sizeof(*fmts)); + if (!fmts) + return AVERROR(ENOMEM); + + fmts[0] = ctx->sw_format; + fmts[1] = AV_PIX_FMT_NONE; + + *formats = fmts; + return 0; +} + +static void vt_unmap(AVHWFramesContext *ctx, HWMapDescriptor *hwmap) +{ + CVPixelBufferRef pixbuf = (CVPixelBufferRef)hwmap->source->data[3]; + + CVPixelBufferUnlockBaseAddress(pixbuf, (uintptr_t)hwmap->priv); +} + +static int vt_map_frame(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src, + int flags) +{ + CVPixelBufferRef pixbuf = (CVPixelBufferRef)src->data[3]; + OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf); + CVReturn err; + uint32_t map_flags = 0; + int ret; + int i; + enum AVPixelFormat format; + + format = av_map_videotoolbox_format_to_pixfmt(pixel_format); + if (dst->format != format) { + av_log(ctx, AV_LOG_ERROR, "Unsupported or mismatching pixel format: %s\n", + av_fourcc2str(pixel_format)); + return AVERROR_UNKNOWN; + } + + if (CVPixelBufferGetWidth(pixbuf) != ctx->width || + CVPixelBufferGetHeight(pixbuf) != ctx->height) { + av_log(ctx, AV_LOG_ERROR, "Inconsistent frame dimensions.\n"); + return AVERROR_UNKNOWN; + } + + if (flags == AV_HWFRAME_MAP_READ) + map_flags = kCVPixelBufferLock_ReadOnly; + + err = CVPixelBufferLockBaseAddress(pixbuf, map_flags); + if (err != kCVReturnSuccess) { + av_log(ctx, AV_LOG_ERROR, "Error locking the pixel buffer.\n"); + return AVERROR_UNKNOWN; + } + + if (CVPixelBufferIsPlanar(pixbuf)) { + int planes = CVPixelBufferGetPlaneCount(pixbuf); + for (i = 0; i < planes; i++) { + dst->data[i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i); + dst->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i); + } + } else { + dst->data[0] = CVPixelBufferGetBaseAddress(pixbuf); + dst->linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf); + } + + ret = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, vt_unmap, + (void *)(uintptr_t)map_flags); + if (ret < 0) + goto unlock; + + return 0; + +unlock: + CVPixelBufferUnlockBaseAddress(pixbuf, map_flags); + return ret; +} + +static int vt_transfer_data_from(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src) +{ + AVFrame *map; + int err; + + if (dst->width > hwfc->width || dst->height > hwfc->height) + return AVERROR(EINVAL); + + map = av_frame_alloc(); + if (!map) + return AVERROR(ENOMEM); + map->format = dst->format; + + err = vt_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ); + if (err) + goto fail; + + map->width = dst->width; + map->height = dst->height; + + err = av_frame_copy(dst, map); + if (err) + goto fail; + + err = 0; +fail: + av_frame_free(&map); + return err; +} + +static int vt_transfer_data_to(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src) +{ + AVFrame *map; + int err; + + if (src->width > hwfc->width || src->height > hwfc->height) + return AVERROR(EINVAL); + + map = av_frame_alloc(); + if (!map) + return AVERROR(ENOMEM); + map->format = src->format; + + err = vt_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE); + if (err) + goto fail; + + map->width = src->width; + map->height = src->height; + + err = av_frame_copy(map, src); + if (err) + goto fail; + + err = 0; +fail: + av_frame_free(&map); + return err; +} + +static int vt_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + if (device && device[0]) { + av_log(ctx, AV_LOG_ERROR, "Device selection unsupported.\n"); + return AVERROR_UNKNOWN; + } + + return 0; +} + +const HWContextType ff_hwcontext_type_videotoolbox = { + .type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX, + .name = "videotoolbox", + + .device_create = vt_device_create, + .frames_get_buffer = vt_get_buffer, + .transfer_get_formats = vt_transfer_get_formats, + .transfer_data_to = vt_transfer_data_to, + .transfer_data_from = vt_transfer_data_from, + + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VIDEOTOOLBOX, AV_PIX_FMT_NONE }, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_videotoolbox.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_videotoolbox.h new file mode 100644 index 0000000000..380918d92e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/hwcontext_videotoolbox.h @@ -0,0 +1,54 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_VIDEOTOOLBOX_H +#define AVUTIL_HWCONTEXT_VIDEOTOOLBOX_H + +#include + +#include + +#include "pixfmt.h" + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_VIDEOTOOLBOX. + * + * This API currently does not support frame allocation, as the raw VideoToolbox + * API does allocation, and FFmpeg itself never has the need to allocate frames. + * + * If the API user sets a custom pool, AVHWFramesContext.pool must return + * AVBufferRefs whose data pointer is a CVImageBufferRef or CVPixelBufferRef. + * + * Currently AVHWDeviceContext.hwctx and AVHWFramesContext.hwctx are always + * NULL. + */ + +/** + * Convert a VideoToolbox (actually CoreVideo) format to AVPixelFormat. + * Returns AV_PIX_FMT_NONE if no known equivalent was found. + */ +enum AVPixelFormat av_map_videotoolbox_format_to_pixfmt(uint32_t cv_fmt); + +/** + * Convert an AVPixelFormat to a VideoToolbox (actually CoreVideo) format. + * Returns 0 if no known equivalent was found. + */ +uint32_t av_map_videotoolbox_format_from_pixfmt(enum AVPixelFormat pix_fmt); + +#endif /* AVUTIL_HWCONTEXT_VIDEOTOOLBOX_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils.c new file mode 100644 index 0000000000..c733cb5cf5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils.c @@ -0,0 +1,645 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * misc image utilities + */ + +#include "avassert.h" +#include "common.h" +#include "imgutils.h" +#include "imgutils_internal.h" +#include "internal.h" +#include "intreadwrite.h" +#include "log.h" +#include "mathematics.h" +#include "pixdesc.h" +#include "rational.h" + +void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], + const AVPixFmtDescriptor *pixdesc) +{ + int i; + memset(max_pixsteps, 0, 4*sizeof(max_pixsteps[0])); + if (max_pixstep_comps) + memset(max_pixstep_comps, 0, 4*sizeof(max_pixstep_comps[0])); + + for (i = 0; i < 4; i++) { + const AVComponentDescriptor *comp = &(pixdesc->comp[i]); + if (comp->step > max_pixsteps[comp->plane]) { + max_pixsteps[comp->plane] = comp->step; + if (max_pixstep_comps) + max_pixstep_comps[comp->plane] = i; + } + } +} + +static inline +int image_get_linesize(int width, int plane, + int max_step, int max_step_comp, + const AVPixFmtDescriptor *desc) +{ + int s, shifted_w, linesize; + + if (!desc) + return AVERROR(EINVAL); + + if (width < 0) + return AVERROR(EINVAL); + s = (max_step_comp == 1 || max_step_comp == 2) ? desc->log2_chroma_w : 0; + shifted_w = ((width + (1 << s) - 1)) >> s; + if (shifted_w && max_step > INT_MAX / shifted_w) + return AVERROR(EINVAL); + linesize = max_step * shifted_w; + + if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) + linesize = (linesize + 7) >> 3; + return linesize; +} + +int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int max_step [4]; /* max pixel step for each plane */ + int max_step_comp[4]; /* the component for each plane which has the max pixel step */ + + if (!desc || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + av_image_fill_max_pixsteps(max_step, max_step_comp, desc); + return image_get_linesize(width, plane, max_step[plane], max_step_comp[plane], desc); +} + +int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width) +{ + int i, ret; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int max_step [4]; /* max pixel step for each plane */ + int max_step_comp[4]; /* the component for each plane which has the max pixel step */ + + memset(linesizes, 0, 4*sizeof(linesizes[0])); + + if (!desc || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + av_image_fill_max_pixsteps(max_step, max_step_comp, desc); + for (i = 0; i < 4; i++) { + if ((ret = image_get_linesize(width, i, max_step[i], max_step_comp[i], desc)) < 0) + return ret; + linesizes[i] = ret; + } + + return 0; +} + +int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, + uint8_t *ptr, const int linesizes[4]) +{ + int i, total_size, size[4] = { 0 }, has_plane[4] = { 0 }; + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + memset(data , 0, sizeof(data[0])*4); + + if (!desc || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + data[0] = ptr; + if (linesizes[0] > (INT_MAX - 1024) / height) + return AVERROR(EINVAL); + size[0] = linesizes[0] * height; + + if (desc->flags & AV_PIX_FMT_FLAG_PAL || + desc->flags & FF_PSEUDOPAL) { + data[1] = ptr + size[0]; /* palette is stored here as 256 32 bits words */ + return size[0] + 256 * 4; + } + + for (i = 0; i < 4; i++) + has_plane[desc->comp[i].plane] = 1; + + total_size = size[0]; + for (i = 1; i < 4 && has_plane[i]; i++) { + int h, s = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; + data[i] = data[i-1] + size[i-1]; + h = (height + (1 << s) - 1) >> s; + if (linesizes[i] > INT_MAX / h) + return AVERROR(EINVAL); + size[i] = h * linesizes[i]; + if (total_size > INT_MAX - size[i]) + return AVERROR(EINVAL); + total_size += size[i]; + } + + return total_size; +} + +int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt) +{ + int i; + + for (i = 0; i < 256; i++) { + int r, g, b; + + switch (pix_fmt) { + case AV_PIX_FMT_RGB8: + r = (i>>5 )*36; + g = ((i>>2)&7)*36; + b = (i&3 )*85; + break; + case AV_PIX_FMT_BGR8: + b = (i>>6 )*85; + g = ((i>>3)&7)*36; + r = (i&7 )*36; + break; + case AV_PIX_FMT_RGB4_BYTE: + r = (i>>3 )*255; + g = ((i>>1)&3)*85; + b = (i&1 )*255; + break; + case AV_PIX_FMT_BGR4_BYTE: + b = (i>>3 )*255; + g = ((i>>1)&3)*85; + r = (i&1 )*255; + break; + case AV_PIX_FMT_GRAY8: + r = b = g = i; + break; + default: + return AVERROR(EINVAL); + } + pal[i] = b + (g << 8) + (r << 16) + (0xFFU << 24); + } + + return 0; +} + +int av_image_alloc(uint8_t *pointers[4], int linesizes[4], + int w, int h, enum AVPixelFormat pix_fmt, int align) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int i, ret; + uint8_t *buf; + + if (!desc) + return AVERROR(EINVAL); + + if ((ret = av_image_check_size(w, h, 0, NULL)) < 0) + return ret; + if ((ret = av_image_fill_linesizes(linesizes, pix_fmt, align>7 ? FFALIGN(w, 8) : w)) < 0) + return ret; + + for (i = 0; i < 4; i++) + linesizes[i] = FFALIGN(linesizes[i], align); + + if ((ret = av_image_fill_pointers(pointers, pix_fmt, h, NULL, linesizes)) < 0) + return ret; + buf = av_malloc(ret + align); + if (!buf) + return AVERROR(ENOMEM); + if ((ret = av_image_fill_pointers(pointers, pix_fmt, h, buf, linesizes)) < 0) { + av_free(buf); + return ret; + } + if (desc->flags & AV_PIX_FMT_FLAG_PAL || (desc->flags & FF_PSEUDOPAL && pointers[1])) { + avpriv_set_systematic_pal2((uint32_t*)pointers[1], pix_fmt); + if (align < 4) { + av_log(NULL, AV_LOG_ERROR, "Formats with a palette require a minimum alignment of 4\n"); + return AVERROR(EINVAL); + } + } + + if ((desc->flags & AV_PIX_FMT_FLAG_PAL || + desc->flags & FF_PSEUDOPAL) && pointers[1] && + pointers[1] - pointers[0] > linesizes[0] * h) { + /* zero-initialize the padding before the palette */ + memset(pointers[0] + linesizes[0] * h, 0, + pointers[1] - pointers[0] - linesizes[0] * h); + } + + return ret; +} + +typedef struct ImgUtils { + const AVClass *class; + int log_offset; + void *log_ctx; +} ImgUtils; + +static const AVClass imgutils_class = { + .class_name = "IMGUTILS", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(ImgUtils, log_offset), + .parent_log_context_offset = offsetof(ImgUtils, log_ctx), +}; + +int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx) +{ + ImgUtils imgutils = { + .class = &imgutils_class, + .log_offset = log_offset, + .log_ctx = log_ctx, + }; + int64_t stride = av_image_get_linesize(pix_fmt, w, 0); + if (stride <= 0) + stride = 8LL*w; + stride += 128*8; + + if ((int)w<=0 || (int)h<=0 || stride >= INT_MAX || stride*(uint64_t)(h+128) >= INT_MAX) { + av_log(&imgutils, AV_LOG_ERROR, "Picture size %ux%u is invalid\n", w, h); + return AVERROR(EINVAL); + } + + if (max_pixels < INT64_MAX) { + if (w*(int64_t)h > max_pixels) { + av_log(&imgutils, AV_LOG_ERROR, + "Picture size %ux%u exceeds specified max pixel count %"PRId64", see the documentation if you wish to increase it\n", + w, h, max_pixels); + return AVERROR(EINVAL); + } + } + + return 0; +} + +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx) +{ + return av_image_check_size2(w, h, INT64_MAX, AV_PIX_FMT_NONE, log_offset, log_ctx); +} + +int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar) +{ + int64_t scaled_dim; + + if (sar.den <= 0 || sar.num < 0) + return AVERROR(EINVAL); + + if (!sar.num || sar.num == sar.den) + return 0; + + if (sar.num < sar.den) + scaled_dim = av_rescale_rnd(w, sar.num, sar.den, AV_ROUND_ZERO); + else + scaled_dim = av_rescale_rnd(h, sar.den, sar.num, AV_ROUND_ZERO); + + if (scaled_dim > 0) + return 0; + + return AVERROR(EINVAL); +} + +static void image_copy_plane(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height) +{ + if (!dst || !src) + return; + av_assert0(FFABS(src_linesize) >= bytewidth); + av_assert0(FFABS(dst_linesize) >= bytewidth); + for (;height > 0; height--) { + memcpy(dst, src, bytewidth); + dst += dst_linesize; + src += src_linesize; + } +} + +static void image_copy_plane_uc_from(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height) +{ + int ret = -1; + +#if ARCH_X86 + ret = ff_image_copy_plane_uc_from_x86(dst, dst_linesize, src, src_linesize, + bytewidth, height); +#endif + + if (ret < 0) + image_copy_plane(dst, dst_linesize, src, src_linesize, bytewidth, height); +} + +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height) +{ + image_copy_plane(dst, dst_linesize, src, src_linesize, bytewidth, height); +} + +static void image_copy(uint8_t *dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t *src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height, + void (*copy_plane)(uint8_t *, ptrdiff_t, const uint8_t *, + ptrdiff_t, ptrdiff_t, int)) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + + if (!desc || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return; + + if (desc->flags & AV_PIX_FMT_FLAG_PAL || + desc->flags & FF_PSEUDOPAL) { + copy_plane(dst_data[0], dst_linesizes[0], + src_data[0], src_linesizes[0], + width, height); + /* copy the palette */ + if ((desc->flags & AV_PIX_FMT_FLAG_PAL) || (dst_data[1] && src_data[1])) + memcpy(dst_data[1], src_data[1], 4*256); + } else { + int i, planes_nb = 0; + + for (i = 0; i < desc->nb_components; i++) + planes_nb = FFMAX(planes_nb, desc->comp[i].plane + 1); + + for (i = 0; i < planes_nb; i++) { + int h = height; + ptrdiff_t bwidth = av_image_get_linesize(pix_fmt, width, i); + if (bwidth < 0) { + av_log(NULL, AV_LOG_ERROR, "av_image_get_linesize failed\n"); + return; + } + if (i == 1 || i == 2) { + h = AV_CEIL_RSHIFT(height, desc->log2_chroma_h); + } + copy_plane(dst_data[i], dst_linesizes[i], + src_data[i], src_linesizes[i], + bwidth, h); + } + } +} + +void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], + const uint8_t *src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height) +{ + ptrdiff_t dst_linesizes1[4], src_linesizes1[4]; + int i; + + for (i = 0; i < 4; i++) { + dst_linesizes1[i] = dst_linesizes[i]; + src_linesizes1[i] = src_linesizes[i]; + } + + image_copy(dst_data, dst_linesizes1, src_data, src_linesizes1, pix_fmt, + width, height, image_copy_plane); +} + +void av_image_copy_uc_from(uint8_t *dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t *src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height) +{ + image_copy(dst_data, dst_linesizes, src_data, src_linesizes, pix_fmt, + width, height, image_copy_plane_uc_from); +} + +int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], + const uint8_t *src, enum AVPixelFormat pix_fmt, + int width, int height, int align) +{ + int ret, i; + + ret = av_image_check_size(width, height, 0, NULL); + if (ret < 0) + return ret; + + ret = av_image_fill_linesizes(dst_linesize, pix_fmt, width); + if (ret < 0) + return ret; + + for (i = 0; i < 4; i++) + dst_linesize[i] = FFALIGN(dst_linesize[i], align); + + return av_image_fill_pointers(dst_data, pix_fmt, height, (uint8_t *)src, dst_linesize); +} + +int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, + int width, int height, int align) +{ + uint8_t *data[4]; + int linesize[4]; + int ret; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) + return AVERROR(EINVAL); + + ret = av_image_check_size(width, height, 0, NULL); + if (ret < 0) + return ret; + + // do not include palette for these pseudo-paletted formats + if (desc->flags & FF_PSEUDOPAL) + return FFALIGN(width, align) * height; + + return av_image_fill_arrays(data, linesize, NULL, pix_fmt, + width, height, align); +} + +int av_image_copy_to_buffer(uint8_t *dst, int dst_size, + const uint8_t * const src_data[4], + const int src_linesize[4], + enum AVPixelFormat pix_fmt, + int width, int height, int align) +{ + int i, j, nb_planes = 0, linesize[4]; + int size = av_image_get_buffer_size(pix_fmt, width, height, align); + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int ret; + + if (size > dst_size || size < 0 || !desc) + return AVERROR(EINVAL); + + for (i = 0; i < desc->nb_components; i++) + nb_planes = FFMAX(desc->comp[i].plane, nb_planes); + + nb_planes++; + + ret = av_image_fill_linesizes(linesize, pix_fmt, width); + av_assert0(ret >= 0); // was checked previously + + for (i = 0; i < nb_planes; i++) { + int h, shift = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; + const uint8_t *src = src_data[i]; + h = (height + (1 << shift) - 1) >> shift; + + for (j = 0; j < h; j++) { + memcpy(dst, src, linesize[i]); + dst += FFALIGN(linesize[i], align); + src += src_linesize[i]; + } + } + + if (desc->flags & AV_PIX_FMT_FLAG_PAL) { + uint32_t *d32 = (uint32_t *)dst; + + for (i = 0; i<256; i++) + AV_WL32(d32 + i, AV_RN32(src_data[1] + 4*i)); + } + + return size; +} + +// Fill dst[0..dst_size] with the bytes in clear[0..clear_size]. The clear +// bytes are repeated until dst_size is reached. If dst_size is unaligned (i.e. +// dst_size%clear_size!=0), the remaining data will be filled with the beginning +// of the clear data only. +static void memset_bytes(uint8_t *dst, size_t dst_size, uint8_t *clear, + size_t clear_size) +{ + int same = 1; + int i; + + if (!clear_size) + return; + + // Reduce to memset() if possible. + for (i = 0; i < clear_size; i++) { + if (clear[i] != clear[0]) { + same = 0; + break; + } + } + if (same) + clear_size = 1; + + if (clear_size == 1) { + memset(dst, clear[0], dst_size); + dst_size = 0; + } else { + if (clear_size > dst_size) + clear_size = dst_size; + memcpy(dst, clear, clear_size); + av_memcpy_backptr(dst + clear_size, clear_size, dst_size - clear_size); + } +} + +// Maximum size in bytes of a plane element (usually a pixel, or multiple pixels +// if it's a subsampled packed format). +#define MAX_BLOCK_SIZE 32 + +int av_image_fill_black(uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4], + enum AVPixelFormat pix_fmt, enum AVColorRange range, + int width, int height) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int nb_planes = av_pix_fmt_count_planes(pix_fmt); + // A pixel or a group of pixels on each plane, with a value that represents black. + // Consider e.g. AV_PIX_FMT_UYVY422 for non-trivial cases. + uint8_t clear_block[4][MAX_BLOCK_SIZE] = {{0}}; // clear padding with 0 + int clear_block_size[4] = {0}; + ptrdiff_t plane_line_bytes[4] = {0}; + int rgb, limited; + int plane, c; + + if (!desc || nb_planes < 1 || nb_planes > 4 || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + rgb = !!(desc->flags & AV_PIX_FMT_FLAG_RGB); + limited = !rgb && range != AVCOL_RANGE_JPEG; + + if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) { + ptrdiff_t bytewidth = av_image_get_linesize(pix_fmt, width, 0); + uint8_t *data; + int mono = pix_fmt == AV_PIX_FMT_MONOWHITE || pix_fmt == AV_PIX_FMT_MONOBLACK; + int fill = pix_fmt == AV_PIX_FMT_MONOWHITE ? 0xFF : 0; + if (nb_planes != 1 || !(rgb || mono) || bytewidth < 1) + return AVERROR(EINVAL); + + if (!dst_data) + return 0; + + data = dst_data[0]; + + // (Bitstream + alpha will be handled incorrectly - it'll remain transparent.) + for (;height > 0; height--) { + memset(data, fill, bytewidth); + data += dst_linesize[0]; + } + return 0; + } + + for (c = 0; c < desc->nb_components; c++) { + const AVComponentDescriptor comp = desc->comp[c]; + + // We try to operate on entire non-subsampled pixel groups (for + // AV_PIX_FMT_UYVY422 this would mean two consecutive pixels). + clear_block_size[comp.plane] = FFMAX(clear_block_size[comp.plane], comp.step); + + if (clear_block_size[comp.plane] > MAX_BLOCK_SIZE) + return AVERROR(EINVAL); + } + + // Create a byte array for clearing 1 pixel (sometimes several pixels). + for (c = 0; c < desc->nb_components; c++) { + const AVComponentDescriptor comp = desc->comp[c]; + // (Multiple pixels happen e.g. with AV_PIX_FMT_UYVY422.) + int w = clear_block_size[comp.plane] / comp.step; + uint8_t *c_data[4]; + const int c_linesize[4] = {0}; + uint16_t src_array[MAX_BLOCK_SIZE]; + uint16_t src = 0; + int x; + + if (comp.depth > 16) + return AVERROR(EINVAL); + if (!rgb && comp.depth < 8) + return AVERROR(EINVAL); + if (w < 1) + return AVERROR(EINVAL); + + if (c == 0 && limited) { + src = 16 << (comp.depth - 8); + } else if ((c == 1 || c == 2) && !rgb) { + src = 128 << (comp.depth - 8); + } else if (c == 3) { + // (Assume even limited YUV uses full range alpha.) + src = (1 << comp.depth) - 1; + } + + for (x = 0; x < w; x++) + src_array[x] = src; + + for (x = 0; x < 4; x++) + c_data[x] = &clear_block[x][0]; + + av_write_image_line(src_array, c_data, c_linesize, desc, 0, 0, c, w); + } + + for (plane = 0; plane < nb_planes; plane++) { + plane_line_bytes[plane] = av_image_get_linesize(pix_fmt, width, plane); + if (plane_line_bytes[plane] < 0) + return AVERROR(EINVAL); + } + + if (!dst_data) + return 0; + + for (plane = 0; plane < nb_planes; plane++) { + size_t bytewidth = plane_line_bytes[plane]; + uint8_t *data = dst_data[plane]; + int chroma_div = plane == 1 || plane == 2 ? desc->log2_chroma_h : 0; + int plane_h = ((height + ( 1 << chroma_div) - 1)) >> chroma_div; + + for (; plane_h > 0; plane_h--) { + memset_bytes(data, bytewidth, &clear_block[plane][0], clear_block_size[plane]); + data += dst_linesize[plane]; + } + } + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils.h new file mode 100644 index 0000000000..5b790ecf0a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils.h @@ -0,0 +1,277 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IMGUTILS_H +#define AVUTIL_IMGUTILS_H + +/** + * @file + * misc image utilities + * + * @addtogroup lavu_picture + * @{ + */ + +#include "avutil.h" +#include "pixdesc.h" +#include "rational.h" + +/** + * Compute the max pixel step for each plane of an image with a + * format described by pixdesc. + * + * The pixel step is the distance in bytes between the first byte of + * the group of bytes which describe a pixel component and the first + * byte of the successive group in the same plane for the same + * component. + * + * @param max_pixsteps an array which is filled with the max pixel step + * for each plane. Since a plane may contain different pixel + * components, the computed max_pixsteps[plane] is relative to the + * component in the plane with the max pixel step. + * @param max_pixstep_comps an array which is filled with the component + * for each plane which has the max pixel step. May be NULL. + */ +void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], + const AVPixFmtDescriptor *pixdesc); + +/** + * Compute the size of an image line with format pix_fmt and width + * width for the plane plane. + * + * @return the computed size in bytes + */ +int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane); + +/** + * Fill plane linesizes for an image with pixel format pix_fmt and + * width width. + * + * @param linesizes array to be filled with the linesize for each plane + * @return >= 0 in case of success, a negative error code otherwise + */ +int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width); + +/** + * Fill plane data pointers for an image with pixel format pix_fmt and + * height height. + * + * @param data pointers array to be filled with the pointer for each image plane + * @param ptr the pointer to a buffer which will contain the image + * @param linesizes the array containing the linesize for each + * plane, should be filled by av_image_fill_linesizes() + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, + uint8_t *ptr, const int linesizes[4]); + +/** + * Allocate an image with size w and h and pixel format pix_fmt, and + * fill pointers and linesizes accordingly. + * The allocated image buffer has to be freed by using + * av_freep(&pointers[0]). + * + * @param align the value to use for buffer size alignment + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_alloc(uint8_t *pointers[4], int linesizes[4], + int w, int h, enum AVPixelFormat pix_fmt, int align); + +/** + * Copy image plane from src to dst. + * That is, copy "height" number of lines of "bytewidth" bytes each. + * The first byte of each successive line is separated by *_linesize + * bytes. + * + * bytewidth must be contained by both absolute values of dst_linesize + * and src_linesize, otherwise the function behavior is undefined. + * + * @param dst_linesize linesize for the image plane in dst + * @param src_linesize linesize for the image plane in src + */ +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height); + +/** + * Copy image in src_data to dst_data. + * + * @param dst_linesizes linesizes for the image in dst_data + * @param src_linesizes linesizes for the image in src_data + */ +void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], + const uint8_t *src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Copy image data located in uncacheable (e.g. GPU mapped) memory. Where + * available, this function will use special functionality for reading from such + * memory, which may result in greatly improved performance compared to plain + * av_image_copy(). + * + * The data pointers and the linesizes must be aligned to the maximum required + * by the CPU architecture. + * + * @note The linesize parameters have the type ptrdiff_t here, while they are + * int for av_image_copy(). + * @note On x86, the linesizes currently need to be aligned to the cacheline + * size (i.e. 64) to get improved performance. + */ +void av_image_copy_uc_from(uint8_t *dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t *src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Setup the data pointers and linesizes based on the specified image + * parameters and the provided array. + * + * The fields of the given image are filled in by using the src + * address which points to the image data buffer. Depending on the + * specified pixel format, one or multiple image data pointers and + * line sizes will be set. If a planar format is specified, several + * pointers will be set pointing to the different picture planes and + * the line sizes of the different planes will be stored in the + * lines_sizes array. Call with src == NULL to get the required + * size for the src buffer. + * + * To allocate the buffer and fill in the dst_data and dst_linesize in + * one call, use av_image_alloc(). + * + * @param dst_data data pointers to be filled in + * @param dst_linesize linesizes for the image in dst_data to be filled in + * @param src buffer which will contain or contains the actual image data, can be NULL + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param align the value used in src for linesize alignment + * @return the size in bytes required for src, a negative error code + * in case of failure + */ +int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], + const uint8_t *src, + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Return the size in bytes of the amount of data required to store an + * image with the given parameters. + * + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param align the assumed linesize alignment + * @return the buffer size in bytes, a negative error code in case of failure + */ +int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Copy image data from an image into a buffer. + * + * av_image_get_buffer_size() can be used to compute the required size + * for the buffer to fill. + * + * @param dst a buffer into which picture data will be copied + * @param dst_size the size in bytes of dst + * @param src_data pointers containing the source image data + * @param src_linesize linesizes for the image in src_data + * @param pix_fmt the pixel format of the source image + * @param width the width of the source image in pixels + * @param height the height of the source image in pixels + * @param align the assumed linesize alignment for dst + * @return the number of bytes written to dst, or a negative value + * (error code) on error + */ +int av_image_copy_to_buffer(uint8_t *dst, int dst_size, + const uint8_t * const src_data[4], const int src_linesize[4], + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Check if the given dimension of an image is valid, meaning that all + * bytes of the image can be addressed with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx); + +/** + * Check if the given dimension of an image is valid, meaning that all + * bytes of a plane of an image with the specified pix_fmt can be addressed + * with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param max_pixels the maximum number of pixels the user wants to accept + * @param pix_fmt the pixel format, can be AV_PIX_FMT_NONE if unknown. + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx); + +/** + * Check if the given sample aspect ratio of an image is valid. + * + * It is considered invalid if the denominator is 0 or if applying the ratio + * to the image size would make the smaller dimension less than 1. If the + * sar numerator is 0, it is considered unknown and will return as valid. + * + * @param w width of the image + * @param h height of the image + * @param sar sample aspect ratio of the image + * @return 0 if valid, a negative AVERROR code otherwise + */ +int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar); + +/** + * Overwrite the image data with black. This is suitable for filling a + * sub-rectangle of an image, meaning the padding between the right most pixel + * and the left most pixel on the next line will not be overwritten. For some + * formats, the image size might be rounded up due to inherent alignment. + * + * If the pixel format has alpha, the alpha is cleared to opaque. + * + * This can return an error if the pixel format is not supported. Normally, all + * non-hwaccel pixel formats should be supported. + * + * Passing NULL for dst_data is allowed. Then the function returns whether the + * operation would have succeeded. (It can return an error if the pix_fmt is + * not supported.) + * + * @param dst_data data pointers to destination image + * @param dst_linesize linesizes for the destination image + * @param pix_fmt the pixel format of the image + * @param range the color range of the image (important for colorspaces such as YUV) + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @return 0 if the image data was cleared, a negative AVERROR code otherwise + */ +int av_image_fill_black(uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4], + enum AVPixelFormat pix_fmt, enum AVColorRange range, + int width, int height); + +/** + * @} + */ + + +#endif /* AVUTIL_IMGUTILS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils_internal.h new file mode 100644 index 0000000000..d515858413 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/imgutils_internal.h @@ -0,0 +1,30 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IMGUTILS_INTERNAL_H +#define AVUTIL_IMGUTILS_INTERNAL_H + +#include +#include + +int ff_image_copy_plane_uc_from_x86(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height); + + +#endif /* AVUTIL_IMGUTILS_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/integer.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/integer.c new file mode 100644 index 0000000000..78e252fbde --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/integer.c @@ -0,0 +1,166 @@ +/* + * arbitrary precision integers + * Copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * arbitrary precision integers + * @author Michael Niedermayer + */ + +#include "common.h" +#include "integer.h" +#include "avassert.h" + +static const AVInteger zero_i; + +AVInteger av_add_i(AVInteger a, AVInteger b){ + int i, carry=0; + + for(i=0; i>16) + a.v[i] + b.v[i]; + a.v[i]= carry; + } + return a; +} + +AVInteger av_sub_i(AVInteger a, AVInteger b){ + int i, carry=0; + + for(i=0; i>16) + a.v[i] - b.v[i]; + a.v[i]= carry; + } + return a; +} + +int av_log2_i(AVInteger a){ + int i; + + for(i=AV_INTEGER_SIZE-1; i>=0; i--){ + if(a.v[i]) + return av_log2_16bit(a.v[i]) + 16*i; + } + return -1; +} + +AVInteger av_mul_i(AVInteger a, AVInteger b){ + AVInteger out; + int i, j; + int na= (av_log2_i(a)+16) >> 4; + int nb= (av_log2_i(b)+16) >> 4; + + memset(&out, 0, sizeof(out)); + + for(i=0; i>16) + out.v[j] + a.v[i]*(unsigned)b.v[j-i]; + out.v[j]= carry; + } + } + + return out; +} + +int av_cmp_i(AVInteger a, AVInteger b){ + int i; + int v= (int16_t)a.v[AV_INTEGER_SIZE-1] - (int16_t)b.v[AV_INTEGER_SIZE-1]; + if(v) return (v>>16)|1; + + for(i=AV_INTEGER_SIZE-2; i>=0; i--){ + int v= a.v[i] - b.v[i]; + if(v) return (v>>16)|1; + } + return 0; +} + +AVInteger av_shr_i(AVInteger a, int s){ + AVInteger out; + int i; + + for(i=0; i>4); + unsigned int v=0; + if(index+1> (s&15); + } + return out; +} + +AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b){ + int i= av_log2_i(a) - av_log2_i(b); + AVInteger quot_temp; + if(!quot) quot = "_temp; + + if ((int16_t)a.v[AV_INTEGER_SIZE-1] < 0) { + a = av_mod_i(quot, av_sub_i(zero_i, a), b); + *quot = av_sub_i(zero_i, *quot); + return av_sub_i(zero_i, a); + } + + av_assert2((int16_t)a.v[AV_INTEGER_SIZE-1] >= 0 && (int16_t)b.v[AV_INTEGER_SIZE-1] >= 0); + av_assert2(av_log2_i(b)>=0); + + if(i > 0) + b= av_shr_i(b, -i); + + memset(quot, 0, sizeof(AVInteger)); + + while(i-- >= 0){ + *quot= av_shr_i(*quot, -1); + if(av_cmp_i(a, b) >= 0){ + a= av_sub_i(a, b); + quot->v[0] += 1; + } + b= av_shr_i(b, 1); + } + return a; +} + +AVInteger av_div_i(AVInteger a, AVInteger b){ + AVInteger quot; + av_mod_i(", a, b); + return quot; +} + +AVInteger av_int2i(int64_t a){ + AVInteger out; + int i; + + for(i=0; i>=16; + } + return out; +} + +int64_t av_i2int(AVInteger a){ + int i; + int64_t out=(int8_t)a.v[AV_INTEGER_SIZE-1]; + + for(i= AV_INTEGER_SIZE-2; i>=0; i--){ + out = (out<<16) + a.v[i]; + } + return out; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/integer.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/integer.h new file mode 100644 index 0000000000..45f733c04c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/integer.h @@ -0,0 +1,86 @@ +/* + * arbitrary precision integers + * Copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * arbitrary precision integers + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_INTEGER_H +#define AVUTIL_INTEGER_H + +#include +#include "common.h" + +#define AV_INTEGER_SIZE 8 + +typedef struct AVInteger{ + uint16_t v[AV_INTEGER_SIZE]; +} AVInteger; + +AVInteger av_add_i(AVInteger a, AVInteger b) av_const; +AVInteger av_sub_i(AVInteger a, AVInteger b) av_const; + +/** + * Return the rounded-down value of the base 2 logarithm of the given + * AVInteger. This is simply the index of the most significant bit + * which is 1, or 0 if all bits are 0. + */ +int av_log2_i(AVInteger a) av_const; +AVInteger av_mul_i(AVInteger a, AVInteger b) av_const; + +/** + * Return 0 if a==b, 1 if a>b and -1 if a + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal API header + */ + +#ifndef AVUTIL_INTERNAL_H +#define AVUTIL_INTERNAL_H + +#if !defined(DEBUG) && !defined(NDEBUG) +# define NDEBUG +#endif + +// This can be enabled to allow detection of additional integer overflows with ubsan +//#define CHECKED + +#include +#include +#include +#include +#include "config.h" +#include "attributes.h" +#include "timer.h" +#include "cpu.h" +#include "dict.h" +#include "macros.h" +#include "mem.h" +#include "pixfmt.h" +#include "version.h" + +#if ARCH_X86 +# include "x86/emms.h" +#endif + +#ifndef emms_c +# define emms_c() do {} while(0) +#endif + +#ifndef attribute_align_arg +#if ARCH_X86_32 && AV_GCC_VERSION_AT_LEAST(4,2) +# define attribute_align_arg __attribute__((force_align_arg_pointer)) +#else +# define attribute_align_arg +#endif +#endif + +#if defined(_WIN32) && CONFIG_SHARED && !defined(BUILDING_avutil) +# define av_export_avutil __declspec(dllimport) +#else +# define av_export_avutil +#endif + +#if HAVE_PRAGMA_DEPRECATED +# if defined(__ICL) || defined (__INTEL_COMPILER) +# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:1478)) +# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop)) +# elif defined(_MSC_VER) +# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:4996)) +# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop)) +# else +# define FF_DISABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define FF_ENABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic pop") +# endif +#else +# define FF_DISABLE_DEPRECATION_WARNINGS +# define FF_ENABLE_DEPRECATION_WARNINGS +#endif + + +#define FF_MEMORY_POISON 0x2a + +#define MAKE_ACCESSORS(str, name, type, field) \ + type av_##name##_get_##field(const str *s) { return s->field; } \ + void av_##name##_set_##field(str *s, type v) { s->field = v; } + +// Some broken preprocessors need a second expansion +// to be forced to tokenize __VA_ARGS__ +#define E1(x) x + +/* Check if the hard coded offset of a struct member still matches reality. + * Induce a compilation failure if not. + */ +#define AV_CHECK_OFFSET(s, m, o) struct check_##o { \ + int x_##o[offsetof(s, m) == o? 1: -1]; \ + } + +#define LOCAL_ALIGNED_A(a, t, v, s, o, ...) \ + uint8_t la_##v[sizeof(t s o) + (a)]; \ + t (*v) o = (void *)FFALIGN((uintptr_t)la_##v, a) + +#define LOCAL_ALIGNED_D(a, t, v, s, o, ...) \ + DECLARE_ALIGNED(a, t, la_##v) s o; \ + t (*v) o = la_##v + +#define LOCAL_ALIGNED(a, t, v, ...) LOCAL_ALIGNED_##a(t, v, __VA_ARGS__) + +#if HAVE_LOCAL_ALIGNED +# define LOCAL_ALIGNED_4(t, v, ...) E1(LOCAL_ALIGNED_D(4, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_4(t, v, ...) E1(LOCAL_ALIGNED_A(4, t, v, __VA_ARGS__,,)) +#endif + +#if HAVE_LOCAL_ALIGNED +# define LOCAL_ALIGNED_8(t, v, ...) E1(LOCAL_ALIGNED_D(8, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_8(t, v, ...) E1(LOCAL_ALIGNED_A(8, t, v, __VA_ARGS__,,)) +#endif + +#if HAVE_LOCAL_ALIGNED +# define LOCAL_ALIGNED_16(t, v, ...) E1(LOCAL_ALIGNED_D(16, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_16(t, v, ...) E1(LOCAL_ALIGNED_A(16, t, v, __VA_ARGS__,,)) +#endif + +#if HAVE_LOCAL_ALIGNED +# define LOCAL_ALIGNED_32(t, v, ...) E1(LOCAL_ALIGNED_D(32, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_32(t, v, ...) E1(LOCAL_ALIGNED_A(32, t, v, __VA_ARGS__,,)) +#endif + +#define FF_ALLOC_OR_GOTO(ctx, p, size, label)\ +{\ + p = av_malloc(size);\ + if (!(p) && (size) != 0) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#define FF_ALLOCZ_OR_GOTO(ctx, p, size, label)\ +{\ + p = av_mallocz(size);\ + if (!(p) && (size) != 0) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#define FF_ALLOC_ARRAY_OR_GOTO(ctx, p, nelem, elsize, label)\ +{\ + p = av_malloc_array(nelem, elsize);\ + if (!p) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#define FF_ALLOCZ_ARRAY_OR_GOTO(ctx, p, nelem, elsize, label)\ +{\ + p = av_mallocz_array(nelem, elsize);\ + if (!p) {\ + av_log(ctx, AV_LOG_ERROR, "Cannot allocate memory.\n");\ + goto label;\ + }\ +} + +#include "libm.h" + +/** + * Return NULL if CONFIG_SMALL is true, otherwise the argument + * without modification. Used to disable the definition of strings + * (for example AVCodec long_names). + */ +#if CONFIG_SMALL +# define NULL_IF_CONFIG_SMALL(x) NULL +#else +# define NULL_IF_CONFIG_SMALL(x) x +#endif + +/** + * Define a function with only the non-default version specified. + * + * On systems with ELF shared libraries, all symbols exported from + * FFmpeg libraries are tagged with the name and major version of the + * library to which they belong. If a function is moved from one + * library to another, a wrapper must be retained in the original + * location to preserve binary compatibility. + * + * Functions defined with this macro will never be used to resolve + * symbols by the build-time linker. + * + * @param type return type of function + * @param name name of function + * @param args argument list of function + * @param ver version tag to assign function + */ +#if HAVE_SYMVER_ASM_LABEL +# define FF_SYMVER(type, name, args, ver) \ + type ff_##name args __asm__ (EXTERN_PREFIX #name "@" ver); \ + type ff_##name args +#elif HAVE_SYMVER_GNU_ASM +# define FF_SYMVER(type, name, args, ver) \ + __asm__ (".symver ff_" #name "," EXTERN_PREFIX #name "@" ver); \ + type ff_##name args; \ + type ff_##name args +#endif + +/** + * Return NULL if a threading library has not been enabled. + * Used to disable threading functions in AVCodec definitions + * when not needed. + */ +#if HAVE_THREADS +# define ONLY_IF_THREADS_ENABLED(x) x +#else +# define ONLY_IF_THREADS_ENABLED(x) NULL +#endif + +/** + * Log a generic warning message about a missing feature. + * + * @param[in] avc a pointer to an arbitrary struct of which the first + * field is a pointer to an AVClass struct + * @param[in] msg string containing the name of the missing feature + */ +void avpriv_report_missing_feature(void *avc, + const char *msg, ...) av_printf_format(2, 3); + +/** + * Log a generic warning message about a missing feature. + * Additionally request that a sample showcasing the feature be uploaded. + * + * @param[in] avc a pointer to an arbitrary struct of which the first field is + * a pointer to an AVClass struct + * @param[in] msg string containing the name of the missing feature + */ +void avpriv_request_sample(void *avc, + const char *msg, ...) av_printf_format(2, 3); + +#if HAVE_LIBC_MSVCRT +#include +#if defined(_VC_CRT_MAJOR_VERSION) && _VC_CRT_MAJOR_VERSION < 14 +#pragma comment(linker, "/include:" EXTERN_PREFIX "avpriv_strtod") +#pragma comment(linker, "/include:" EXTERN_PREFIX "avpriv_snprintf") +#endif + +#define avpriv_open ff_open +#define avpriv_tempfile ff_tempfile +#define PTRDIFF_SPECIFIER "Id" +#define SIZE_SPECIFIER "Iu" +#else +#define PTRDIFF_SPECIFIER "td" +#define SIZE_SPECIFIER "zu" +#endif + +#ifdef DEBUG +# define ff_dlog(ctx, ...) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__) +#else +# define ff_dlog(ctx, ...) do { if (0) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) +#endif + +// For debuging we use signed operations so overflows can be detected (by ubsan) +// For production we use unsigned so there are no undefined operations +#ifdef CHECKED +#define SUINT int +#define SUINT32 int32_t +#else +#define SUINT unsigned +#define SUINT32 uint32_t +#endif + +/** + * Clip and convert a double value into the long long amin-amax range. + * This function is needed because conversion of floating point to integers when + * it does not fit in the integer's representation does not necessarily saturate + * correctly (usually converted to a cvttsd2si on x86) which saturates numbers + * > INT64_MAX to INT64_MIN. The standard marks such conversions as undefined + * behavior, allowing this sort of mathematically bogus conversions. This provides + * a safe alternative that is slower obviously but assures safety and better + * mathematical behavior. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int64_t ff_rint64_clip(double a, int64_t amin, int64_t amax) +{ + int64_t res; +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + // INT64_MAX+1,INT64_MIN are exactly representable as IEEE doubles + // do range checks first + if (a >= 9223372036854775808.0) + return amax; + if (a <= -9223372036854775808.0) + return amin; + + // safe to call llrint and clip accordingly + res = llrint(a); + if (res > amax) + return amax; + if (res < amin) + return amin; + return res; +} + +/** + * A wrapper for open() setting O_CLOEXEC. + */ +av_warn_unused_result +int avpriv_open(const char *filename, int flags, ...); + +/** + * Wrapper to work around the lack of mkstemp() on mingw. + * Also, tries to create file in /tmp first, if possible. + * *prefix can be a character constant; *filename will be allocated internally. + * @return file descriptor of opened file (or negative value corresponding to an + * AVERROR code on error) + * and opened file name in **filename. + * @note On very old libcs it is necessary to set a secure umask before + * calling this, av_tempfile() can't call umask itself as it is used in + * libraries and could interfere with the calling application. + */ +int avpriv_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx); + +int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt); + +static av_always_inline av_const int avpriv_mirror(int x, int w) +{ + if (!w) + return 0; + + while ((unsigned)x > (unsigned)w) { + x = -x; + if (x < 0) + x += 2 * w; + } + return x; +} + +void ff_check_pixfmt_descriptors(void); + +/** + * Set a dictionary value to an ISO-8601 compliant timestamp string. + * + * @param s AVFormatContext + * @param key metadata key + * @param timestamp unix timestamp in microseconds + * @return <0 on error + */ +int avpriv_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp); + +// Helper macro for AV_PIX_FMT_FLAG_PSEUDOPAL deprecation. Code inside FFmpeg +// should always use FF_PSEUDOPAL. Once the public API flag gets removed, all +// code using it is dead code. +#if FF_API_PSEUDOPAL +#define FF_PSEUDOPAL AV_PIX_FMT_FLAG_PSEUDOPAL +#else +#define FF_PSEUDOPAL 0 +#endif + +#endif /* AVUTIL_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intfloat.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intfloat.h new file mode 100644 index 0000000000..fe3d7ec4a5 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intfloat.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTFLOAT_H +#define AVUTIL_INTFLOAT_H + +#include +#include "attributes.h" + +union av_intfloat32 { + uint32_t i; + float f; +}; + +union av_intfloat64 { + uint64_t i; + double f; +}; + +/** + * Reinterpret a 32-bit integer as a float. + */ +static av_always_inline float av_int2float(uint32_t i) +{ + union av_intfloat32 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a float as a 32-bit integer. + */ +static av_always_inline uint32_t av_float2int(float f) +{ + union av_intfloat32 v; + v.f = f; + return v.i; +} + +/** + * Reinterpret a 64-bit integer as a double. + */ +static av_always_inline double av_int2double(uint64_t i) +{ + union av_intfloat64 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a double as a 64-bit integer. + */ +static av_always_inline uint64_t av_double2int(double f) +{ + union av_intfloat64 v; + v.f = f; + return v.i; +} + +#endif /* AVUTIL_INTFLOAT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intmath.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intmath.c new file mode 100644 index 0000000000..b0c00e1cad --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intmath.c @@ -0,0 +1,34 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "intmath.h" + +/* undef these to get the function prototypes from common.h */ +#undef av_log2 +#undef av_log2_16bit +#include "common.h" + +int av_log2(unsigned v) +{ + return ff_log2(v); +} + +int av_log2_16bit(unsigned v) +{ + return ff_log2_16bit(v); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intmath.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intmath.h new file mode 100644 index 0000000000..9573109e9d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intmath.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2010 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTMATH_H +#define AVUTIL_INTMATH_H + +#include + +#include "config.h" +#include "attributes.h" + +#if ARCH_ARM +# include "arm/intmath.h" +#endif +#if ARCH_X86 +# include "x86/intmath.h" +#endif + +#if HAVE_FAST_CLZ +#if AV_GCC_VERSION_AT_LEAST(3,4) +#ifndef ff_log2 +# define ff_log2(x) (31 - __builtin_clz((x)|1)) +# ifndef ff_log2_16bit +# define ff_log2_16bit av_log2 +# endif +#endif /* ff_log2 */ +#endif /* AV_GCC_VERSION_AT_LEAST(3,4) */ +#endif + +extern const uint8_t ff_log2_tab[256]; + +#ifndef ff_log2 +#define ff_log2 ff_log2_c +static av_always_inline av_const int ff_log2_c(unsigned int v) +{ + int n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} +#endif + +#ifndef ff_log2_16bit +#define ff_log2_16bit ff_log2_16bit_c +static av_always_inline av_const int ff_log2_16bit_c(unsigned int v) +{ + int n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} +#endif + +#define av_log2 ff_log2 +#define av_log2_16bit ff_log2_16bit + +/** + * @addtogroup lavu_math + * @{ + */ + +#if HAVE_FAST_CLZ +#if AV_GCC_VERSION_AT_LEAST(3,4) +#ifndef ff_ctz +#define ff_ctz(v) __builtin_ctz(v) +#endif +#ifndef ff_ctzll +#define ff_ctzll(v) __builtin_ctzll(v) +#endif +#ifndef ff_clz +#define ff_clz(v) __builtin_clz(v) +#endif +#endif +#endif + +#ifndef ff_ctz +#define ff_ctz ff_ctz_c +/** + * Trailing zero bit count. + * + * @param v input value. If v is 0, the result is undefined. + * @return the number of trailing 0-bits + */ +/* We use the De-Bruijn method outlined in: + * http://supertech.csail.mit.edu/papers/debruijn.pdf. */ +static av_always_inline av_const int ff_ctz_c(int v) +{ + static const uint8_t debruijn_ctz32[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + return debruijn_ctz32[(uint32_t)((v & -v) * 0x077CB531U) >> 27]; +} +#endif + +#ifndef ff_ctzll +#define ff_ctzll ff_ctzll_c +/* We use the De-Bruijn method outlined in: + * http://supertech.csail.mit.edu/papers/debruijn.pdf. */ +static av_always_inline av_const int ff_ctzll_c(long long v) +{ + static const uint8_t debruijn_ctz64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + return debruijn_ctz64[(uint64_t)((v & -v) * 0x022FDD63CC95386DU) >> 58]; +} +#endif + +#ifndef ff_clz +#define ff_clz ff_clz_c +static av_always_inline av_const unsigned ff_clz_c(unsigned x) +{ + unsigned i = sizeof(x) * 8; + + while (x) { + x >>= 1; + i--; + } + + return i; +} +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,4) +#ifndef av_parity +#define av_parity __builtin_parity +#endif +#endif + +/** + * @} + */ +#endif /* AVUTIL_INTMATH_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intreadwrite.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intreadwrite.h new file mode 100644 index 0000000000..4c8413a536 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/intreadwrite.h @@ -0,0 +1,644 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTREADWRITE_H +#define AVUTIL_INTREADWRITE_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" +#include "bswap.h" + +typedef union { + uint64_t u64; + uint32_t u32[2]; + uint16_t u16[4]; + uint8_t u8 [8]; + double f64; + float f32[2]; +} av_alias av_alias64; + +typedef union { + uint32_t u32; + uint16_t u16[2]; + uint8_t u8 [4]; + float f32; +} av_alias av_alias32; + +typedef union { + uint16_t u16; + uint8_t u8 [2]; +} av_alias av_alias16; + +/* + * Arch-specific headers can provide any combination of + * AV_[RW][BLN](16|24|32|48|64) and AV_(COPY|SWAP|ZERO)(64|128) macros. + * Preprocessor symbols must be defined, even if these are implemented + * as inline functions. + * + * R/W means read/write, B/L/N means big/little/native endianness. + * The following macros require aligned access, compared to their + * unaligned variants: AV_(COPY|SWAP|ZERO)(64|128), AV_[RW]N[8-64]A. + * Incorrect usage may range from abysmal performance to crash + * depending on the platform. + * + * The unaligned variants are AV_[RW][BLN][8-64] and AV_COPY*U. + */ + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_ARM +# include "arm/intreadwrite.h" +#elif ARCH_AVR32 +# include "avr32/intreadwrite.h" +#elif ARCH_MIPS +# include "mips/intreadwrite.h" +#elif ARCH_PPC +# include "ppc/intreadwrite.h" +#elif ARCH_TOMI +# include "tomi/intreadwrite.h" +#elif ARCH_X86 +# include "x86/intreadwrite.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +/* + * Map AV_RNXX <-> AV_R[BL]XX for all variants provided by per-arch headers. + */ + +#if AV_HAVE_BIGENDIAN + +# if defined(AV_RN16) && !defined(AV_RB16) +# define AV_RB16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RB16) +# define AV_RN16(p) AV_RB16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WB16) +# define AV_WB16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WB16) +# define AV_WN16(p, v) AV_WB16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RB24) +# define AV_RB24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RB24) +# define AV_RN24(p) AV_RB24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WB24) +# define AV_WB24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WB24) +# define AV_WN24(p, v) AV_WB24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RB32) +# define AV_RB32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RB32) +# define AV_RN32(p) AV_RB32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WB32) +# define AV_WB32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WB32) +# define AV_WN32(p, v) AV_WB32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RB48) +# define AV_RB48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RB48) +# define AV_RN48(p) AV_RB48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WB48) +# define AV_WB48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WB48) +# define AV_WN48(p, v) AV_WB48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RB64) +# define AV_RB64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RB64) +# define AV_RN64(p) AV_RB64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WB64) +# define AV_WB64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WB64) +# define AV_WN64(p, v) AV_WB64(p, v) +# endif + +#else /* AV_HAVE_BIGENDIAN */ + +# if defined(AV_RN16) && !defined(AV_RL16) +# define AV_RL16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RL16) +# define AV_RN16(p) AV_RL16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WL16) +# define AV_WL16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WL16) +# define AV_WN16(p, v) AV_WL16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RL24) +# define AV_RL24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RL24) +# define AV_RN24(p) AV_RL24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WL24) +# define AV_WL24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WL24) +# define AV_WN24(p, v) AV_WL24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RL32) +# define AV_RL32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RL32) +# define AV_RN32(p) AV_RL32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WL32) +# define AV_WL32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WL32) +# define AV_WN32(p, v) AV_WL32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RL48) +# define AV_RL48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RL48) +# define AV_RN48(p) AV_RL48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WL48) +# define AV_WL48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WL48) +# define AV_WN48(p, v) AV_WL48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RL64) +# define AV_RL64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RL64) +# define AV_RN64(p) AV_RL64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WL64) +# define AV_WL64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WL64) +# define AV_WN64(p, v) AV_WL64(p, v) +# endif + +#endif /* !AV_HAVE_BIGENDIAN */ + +/* + * Define AV_[RW]N helper macros to simplify definitions not provided + * by per-arch headers. + */ + +#if defined(__GNUC__) + +union unaligned_64 { uint64_t l; } __attribute__((packed)) av_alias; +union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias; +union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; + +# define AV_RN(s, p) (((const union unaligned_##s *) (p))->l) +# define AV_WN(s, p, v) ((((union unaligned_##s *) (p))->l) = (v)) + +#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_X64) || defined(_M_ARM64)) && AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) +# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) + +#elif AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) +# define AV_WN(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#else + +#ifndef AV_RB16 +# define AV_RB16(x) \ + ((((const uint8_t*)(x))[0] << 8) | \ + ((const uint8_t*)(x))[1]) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, val) do { \ + uint16_t d = (val); \ + ((uint8_t*)(p))[1] = (d); \ + ((uint8_t*)(p))[0] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RL16 +# define AV_RL16(x) \ + ((((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, val) do { \ + uint16_t d = (val); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RB32 +# define AV_RB32(x) \ + (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ + (((const uint8_t*)(x))[1] << 16) | \ + (((const uint8_t*)(x))[2] << 8) | \ + ((const uint8_t*)(x))[3]) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, val) do { \ + uint32_t d = (val); \ + ((uint8_t*)(p))[3] = (d); \ + ((uint8_t*)(p))[2] = (d)>>8; \ + ((uint8_t*)(p))[1] = (d)>>16; \ + ((uint8_t*)(p))[0] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RL32 +# define AV_RL32(x) \ + (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ + (((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, val) do { \ + uint32_t d = (val); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RB64 +# define AV_RB64(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 8) | \ + (uint64_t)((const uint8_t*)(x))[7]) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, val) do { \ + uint64_t d = (val); \ + ((uint8_t*)(p))[7] = (d); \ + ((uint8_t*)(p))[6] = (d)>>8; \ + ((uint8_t*)(p))[5] = (d)>>16; \ + ((uint8_t*)(p))[4] = (d)>>24; \ + ((uint8_t*)(p))[3] = (d)>>32; \ + ((uint8_t*)(p))[2] = (d)>>40; \ + ((uint8_t*)(p))[1] = (d)>>48; \ + ((uint8_t*)(p))[0] = (d)>>56; \ + } while(0) +#endif + +#ifndef AV_RL64 +# define AV_RL64(x) \ + (((uint64_t)((const uint8_t*)(x))[7] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, val) do { \ + uint64_t d = (val); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + ((uint8_t*)(p))[6] = (d)>>48; \ + ((uint8_t*)(p))[7] = (d)>>56; \ + } while(0) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RN(s, p) AV_RB##s(p) +# define AV_WN(s, p, v) AV_WB##s(p, v) +#else +# define AV_RN(s, p) AV_RL##s(p) +# define AV_WN(s, p, v) AV_WL##s(p, v) +#endif + +#endif /* HAVE_FAST_UNALIGNED */ + +#ifndef AV_RN16 +# define AV_RN16(p) AV_RN(16, p) +#endif + +#ifndef AV_RN32 +# define AV_RN32(p) AV_RN(32, p) +#endif + +#ifndef AV_RN64 +# define AV_RN64(p) AV_RN(64, p) +#endif + +#ifndef AV_WN16 +# define AV_WN16(p, v) AV_WN(16, p, v) +#endif + +#ifndef AV_WN32 +# define AV_WN32(p, v) AV_WN(32, p, v) +#endif + +#ifndef AV_WN64 +# define AV_WN64(p, v) AV_WN(64, p, v) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RB(s, p) AV_RN##s(p) +# define AV_WB(s, p, v) AV_WN##s(p, v) +# define AV_RL(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WL(s, p, v) AV_WN##s(p, av_bswap##s(v)) +#else +# define AV_RB(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WB(s, p, v) AV_WN##s(p, av_bswap##s(v)) +# define AV_RL(s, p) AV_RN##s(p) +# define AV_WL(s, p, v) AV_WN##s(p, v) +#endif + +#define AV_RB8(x) (((const uint8_t*)(x))[0]) +#define AV_WB8(p, d) do { ((uint8_t*)(p))[0] = (d); } while(0) + +#define AV_RL8(x) AV_RB8(x) +#define AV_WL8(p, d) AV_WB8(p, d) + +#ifndef AV_RB16 +# define AV_RB16(p) AV_RB(16, p) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, v) AV_WB(16, p, v) +#endif + +#ifndef AV_RL16 +# define AV_RL16(p) AV_RL(16, p) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, v) AV_WL(16, p, v) +#endif + +#ifndef AV_RB32 +# define AV_RB32(p) AV_RB(32, p) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, v) AV_WB(32, p, v) +#endif + +#ifndef AV_RL32 +# define AV_RL32(p) AV_RL(32, p) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, v) AV_WL(32, p, v) +#endif + +#ifndef AV_RB64 +# define AV_RB64(p) AV_RB(64, p) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, v) AV_WB(64, p, v) +#endif + +#ifndef AV_RL64 +# define AV_RL64(p) AV_RL(64, p) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, v) AV_WL(64, p, v) +#endif + +#ifndef AV_RB24 +# define AV_RB24(x) \ + ((((const uint8_t*)(x))[0] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[2]) +#endif +#ifndef AV_WB24 +# define AV_WB24(p, d) do { \ + ((uint8_t*)(p))[2] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[0] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RL24 +# define AV_RL24(x) \ + ((((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL24 +# define AV_WL24(p, d) do { \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RB48 +# define AV_RB48(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 8) | \ + (uint64_t)((const uint8_t*)(x))[5]) +#endif +#ifndef AV_WB48 +# define AV_WB48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[5] = (d); \ + ((uint8_t*)(p))[4] = (d)>>8; \ + ((uint8_t*)(p))[3] = (d)>>16; \ + ((uint8_t*)(p))[2] = (d)>>24; \ + ((uint8_t*)(p))[1] = (d)>>32; \ + ((uint8_t*)(p))[0] = (d)>>40; \ + } while(0) +#endif + +#ifndef AV_RL48 +# define AV_RL48(x) \ + (((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL48 +# define AV_WL48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + } while(0) +#endif + +/* + * The AV_[RW]NA macros access naturally aligned data + * in a type-safe way. + */ + +#define AV_RNA(s, p) (((const av_alias##s*)(p))->u##s) +#define AV_WNA(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#ifndef AV_RN16A +# define AV_RN16A(p) AV_RNA(16, p) +#endif + +#ifndef AV_RN32A +# define AV_RN32A(p) AV_RNA(32, p) +#endif + +#ifndef AV_RN64A +# define AV_RN64A(p) AV_RNA(64, p) +#endif + +#ifndef AV_WN16A +# define AV_WN16A(p, v) AV_WNA(16, p, v) +#endif + +#ifndef AV_WN32A +# define AV_WN32A(p, v) AV_WNA(32, p, v) +#endif + +#ifndef AV_WN64A +# define AV_WN64A(p, v) AV_WNA(64, p, v) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RLA(s, p) av_bswap##s(AV_RN##s##A(p)) +# define AV_WLA(s, p, v) AV_WN##s##A(p, av_bswap##s(v)) +#else +# define AV_RLA(s, p) AV_RN##s##A(p) +# define AV_WLA(s, p, v) AV_WN##s##A(p, v) +#endif + +#ifndef AV_RL64A +# define AV_RL64A(p) AV_RLA(64, p) +#endif +#ifndef AV_WL64A +# define AV_WL64A(p, v) AV_WLA(64, p, v) +#endif + +/* + * The AV_COPYxxU macros are suitable for copying data to/from unaligned + * memory locations. + */ + +#define AV_COPYU(n, d, s) AV_WN##n(d, AV_RN##n(s)); + +#ifndef AV_COPY16U +# define AV_COPY16U(d, s) AV_COPYU(16, d, s) +#endif + +#ifndef AV_COPY32U +# define AV_COPY32U(d, s) AV_COPYU(32, d, s) +#endif + +#ifndef AV_COPY64U +# define AV_COPY64U(d, s) AV_COPYU(64, d, s) +#endif + +#ifndef AV_COPY128U +# define AV_COPY128U(d, s) \ + do { \ + AV_COPY64U(d, s); \ + AV_COPY64U((char *)(d) + 8, (const char *)(s) + 8); \ + } while(0) +#endif + +/* Parameters for AV_COPY*, AV_SWAP*, AV_ZERO* must be + * naturally aligned. They may be implemented using MMX, + * so emms_c() must be called before using any float code + * afterwards. + */ + +#define AV_COPY(n, d, s) \ + (((av_alias##n*)(d))->u##n = ((const av_alias##n*)(s))->u##n) + +#ifndef AV_COPY16 +# define AV_COPY16(d, s) AV_COPY(16, d, s) +#endif + +#ifndef AV_COPY32 +# define AV_COPY32(d, s) AV_COPY(32, d, s) +#endif + +#ifndef AV_COPY64 +# define AV_COPY64(d, s) AV_COPY(64, d, s) +#endif + +#ifndef AV_COPY128 +# define AV_COPY128(d, s) \ + do { \ + AV_COPY64(d, s); \ + AV_COPY64((char*)(d)+8, (char*)(s)+8); \ + } while(0) +#endif + +#define AV_SWAP(n, a, b) FFSWAP(av_alias##n, *(av_alias##n*)(a), *(av_alias##n*)(b)) + +#ifndef AV_SWAP64 +# define AV_SWAP64(a, b) AV_SWAP(64, a, b) +#endif + +#define AV_ZERO(n, d) (((av_alias##n*)(d))->u##n = 0) + +#ifndef AV_ZERO16 +# define AV_ZERO16(d) AV_ZERO(16, d) +#endif + +#ifndef AV_ZERO32 +# define AV_ZERO32(d) AV_ZERO(32, d) +#endif + +#ifndef AV_ZERO64 +# define AV_ZERO64(d) AV_ZERO(64, d) +#endif + +#ifndef AV_ZERO128 +# define AV_ZERO128(d) \ + do { \ + AV_ZERO64(d); \ + AV_ZERO64((char*)(d)+8); \ + } while(0) +#endif + +#endif /* AVUTIL_INTREADWRITE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lfg.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lfg.c new file mode 100644 index 0000000000..46b04d2403 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lfg.c @@ -0,0 +1,87 @@ +/* + * Lagged Fibonacci PRNG + * Copyright (c) 2008 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "lfg.h" +#include "crc.h" +#include "md5.h" +#include "error.h" +#include "intreadwrite.h" +#include "attributes.h" + +av_cold void av_lfg_init(AVLFG *c, unsigned int seed) +{ + uint8_t tmp[16] = { 0 }; + int i; + + for (i = 8; i < 64; i += 4) { + AV_WL32(tmp, seed); + tmp[4] = i; + av_md5_sum(tmp, tmp, 16); + c->state[i ] = AV_RL32(tmp); + c->state[i + 1] = AV_RL32(tmp + 4); + c->state[i + 2] = AV_RL32(tmp + 8); + c->state[i + 3] = AV_RL32(tmp + 12); + } + c->index = 0; +} + +void av_bmg_get(AVLFG *lfg, double out[2]) +{ + double x1, x2, w; + + do { + x1 = 2.0 / UINT_MAX * av_lfg_get(lfg) - 1.0; + x2 = 2.0 / UINT_MAX * av_lfg_get(lfg) - 1.0; + w = x1 * x1 + x2 * x2; + } while (w >= 1.0); + + w = sqrt((-2.0 * log(w)) / w); + out[0] = x1 * w; + out[1] = x2 * w; +} + +int av_lfg_init_from_data(AVLFG *c, const uint8_t *data, unsigned int length) { + unsigned int beg, end, segm; + const AVCRC *avcrc; + uint32_t crc = 1; + + /* avoid integer overflow in the loop below. */ + if (length > (UINT_MAX / 128U)) return AVERROR(EINVAL); + + c->index = 0; + avcrc = av_crc_get_table(AV_CRC_32_IEEE); /* This can't fail. It's a well-defined table in crc.c */ + + /* across 64 segments of the incoming data, + * do a running crc of each segment and store the crc as the state for that slot. + * this works even if the length of the segment is 0 bytes. */ + beg = 0; + for (segm = 0;segm < 64;segm++) { + end = (((segm + 1) * length) / 64); + crc = av_crc(avcrc, crc, data + beg, end - beg); + c->state[segm] = (unsigned int)crc; + beg = end; + } + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lfg.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lfg.h new file mode 100644 index 0000000000..03f779ad8a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lfg.h @@ -0,0 +1,71 @@ +/* + * Lagged Fibonacci PRNG + * Copyright (c) 2008 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LFG_H +#define AVUTIL_LFG_H + +#include + +typedef struct AVLFG { + unsigned int state[64]; + int index; +} AVLFG; + +void av_lfg_init(AVLFG *c, unsigned int seed); + +/** + * Seed the state of the ALFG using binary data. + * + * Return value: 0 on success, negative value (AVERROR) on failure. + */ +int av_lfg_init_from_data(AVLFG *c, const uint8_t *data, unsigned int length); + +/** + * Get the next random unsigned 32-bit number using an ALFG. + * + * Please also consider a simple LCG like state= state*1664525+1013904223, + * it may be good enough and faster for your specific use case. + */ +static inline unsigned int av_lfg_get(AVLFG *c){ + c->state[c->index & 63] = c->state[(c->index-24) & 63] + c->state[(c->index-55) & 63]; + return c->state[c->index++ & 63]; +} + +/** + * Get the next random unsigned 32-bit number using a MLFG. + * + * Please also consider av_lfg_get() above, it is faster. + */ +static inline unsigned int av_mlfg_get(AVLFG *c){ + unsigned int a= c->state[(c->index-55) & 63]; + unsigned int b= c->state[(c->index-24) & 63]; + return c->state[c->index++ & 63] = 2*a*b+a+b; +} + +/** + * Get the next two numbers generated by a Box-Muller Gaussian + * generator using the random numbers issued by lfg. + * + * @param out array where the two generated numbers are placed + */ +void av_bmg_get(AVLFG *lfg, double out[2]); + +#endif /* AVUTIL_LFG_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/libm.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/libm.h new file mode 100644 index 0000000000..a819962391 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/libm.h @@ -0,0 +1,471 @@ +/* + * erf function: Copyright (c) 2006 John Maddock + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Replacements for frequently missing libm functions + */ + +#ifndef AVUTIL_LIBM_H +#define AVUTIL_LIBM_H + +#include +#include "config.h" +#include "attributes.h" +#include "intfloat.h" +#include "mathematics.h" + +#if HAVE_MIPSFPU && HAVE_INLINE_ASM +#include "libavutil/mips/libm_mips.h" +#endif /* HAVE_MIPSFPU && HAVE_INLINE_ASM*/ + +#if !HAVE_ATANF +#undef atanf +#define atanf(x) ((float)atan(x)) +#endif /* HAVE_ATANF */ + +#if !HAVE_ATAN2F +#undef atan2f +#define atan2f(y, x) ((float)atan2(y, x)) +#endif /* HAVE_ATAN2F */ + +#if !HAVE_POWF +#undef powf +#define powf(x, y) ((float)pow(x, y)) +#endif /* HAVE_POWF */ + +#if !HAVE_CBRT +static av_always_inline double cbrt(double x) +{ + return x < 0 ? -pow(-x, 1.0 / 3.0) : pow(x, 1.0 / 3.0); +} +#endif /* HAVE_CBRT */ + +#if !HAVE_CBRTF +static av_always_inline float cbrtf(float x) +{ + return x < 0 ? -powf(-x, 1.0 / 3.0) : powf(x, 1.0 / 3.0); +} +#endif /* HAVE_CBRTF */ + +#if !HAVE_COPYSIGN +static av_always_inline double copysign(double x, double y) +{ + uint64_t vx = av_double2int(x); + uint64_t vy = av_double2int(y); + return av_int2double((vx & UINT64_C(0x7fffffffffffffff)) | (vy & UINT64_C(0x8000000000000000))); +} +#endif /* HAVE_COPYSIGN */ + +#if !HAVE_COSF +#undef cosf +#define cosf(x) ((float)cos(x)) +#endif /* HAVE_COSF */ + +#if !HAVE_ERF +static inline double ff_eval_poly(const double *coeff, int size, double x) { + double sum = coeff[size-1]; + int i; + for (i = size-2; i >= 0; --i) { + sum *= x; + sum += coeff[i]; + } + return sum; +} + +/** + * erf function + * Algorithm taken from the Boost project, source: + * http://www.boost.org/doc/libs/1_46_1/boost/math/special_functions/erf.hpp + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0 (see notice below). + * Boost Software License - Version 1.0 - August 17th, 2003 +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + */ +static inline double erf(double z) +{ +#ifndef FF_ARRAY_ELEMS +#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) +#endif + double result; + + /* handle the symmetry: erf(-x) = -erf(x) */ + if (z < 0) + return -erf(-z); + + /* branch based on range of z, and pick appropriate approximation */ + if (z == 0) + return 0; + else if (z < 1e-10) + return z * 1.125 + z * 0.003379167095512573896158903121545171688; + else if (z < 0.5) { + // Maximum Deviation Found: 1.561e-17 + // Expected Error Term: 1.561e-17 + // Maximum Relative Change in Control Points: 1.155e-04 + // Max Error found at double precision = 2.961182e-17 + + static const double y = 1.044948577880859375; + static const double p[] = { + 0.0834305892146531832907, + -0.338165134459360935041, + -0.0509990735146777432841, + -0.00772758345802133288487, + -0.000322780120964605683831, + }; + static const double q[] = { + 1, + 0.455004033050794024546, + 0.0875222600142252549554, + 0.00858571925074406212772, + 0.000370900071787748000569, + }; + double zz = z * z; + return z * (y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), zz) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), zz)); + } + /* here onwards compute erfc */ + else if (z < 1.5) { + // Maximum Deviation Found: 3.702e-17 + // Expected Error Term: 3.702e-17 + // Maximum Relative Change in Control Points: 2.845e-04 + // Max Error found at double precision = 4.841816e-17 + static const double y = 0.405935764312744140625; + static const double p[] = { + -0.098090592216281240205, + 0.178114665841120341155, + 0.191003695796775433986, + 0.0888900368967884466578, + 0.0195049001251218801359, + 0.00180424538297014223957, + }; + static const double q[] = { + 1, + 1.84759070983002217845, + 1.42628004845511324508, + 0.578052804889902404909, + 0.12385097467900864233, + 0.0113385233577001411017, + 0.337511472483094676155e-5, + }; + result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), z - 0.5) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), z - 0.5); + result *= exp(-z * z) / z; + return 1 - result; + } + else if (z < 2.5) { + // Max Error found at double precision = 6.599585e-18 + // Maximum Deviation Found: 3.909e-18 + // Expected Error Term: 3.909e-18 + // Maximum Relative Change in Control Points: 9.886e-05 + static const double y = 0.50672817230224609375; + static const double p[] = { + -0.0243500476207698441272, + 0.0386540375035707201728, + 0.04394818964209516296, + 0.0175679436311802092299, + 0.00323962406290842133584, + 0.000235839115596880717416, + }; + static const double q[] = { + 1, + 1.53991494948552447182, + 0.982403709157920235114, + 0.325732924782444448493, + 0.0563921837420478160373, + 0.00410369723978904575884, + }; + result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), z - 1.5) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), z - 1.5); + result *= exp(-z * z) / z; + return 1 - result; + } + else if (z < 4.5) { + // Maximum Deviation Found: 1.512e-17 + // Expected Error Term: 1.512e-17 + // Maximum Relative Change in Control Points: 2.222e-04 + // Max Error found at double precision = 2.062515e-17 + static const double y = 0.5405750274658203125; + static const double p[] = { + 0.00295276716530971662634, + 0.0137384425896355332126, + 0.00840807615555585383007, + 0.00212825620914618649141, + 0.000250269961544794627958, + 0.113212406648847561139e-4, + }; + static const double q[] = { + 1, + 1.04217814166938418171, + 0.442597659481563127003, + 0.0958492726301061423444, + 0.0105982906484876531489, + 0.000479411269521714493907, + }; + result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), z - 3.5) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), z - 3.5); + result *= exp(-z * z) / z; + return 1 - result; + } + /* differ from Boost here, the claim of underflow of erfc(x) past 5.8 is + * slightly incorrect, change to 5.92 + * (really somewhere between 5.9125 and 5.925 is when it saturates) */ + else if (z < 5.92) { + // Max Error found at double precision = 2.997958e-17 + // Maximum Deviation Found: 2.860e-17 + // Expected Error Term: 2.859e-17 + // Maximum Relative Change in Control Points: 1.357e-05 + static const double y = 0.5579090118408203125; + static const double p[] = { + 0.00628057170626964891937, + 0.0175389834052493308818, + -0.212652252872804219852, + -0.687717681153649930619, + -2.5518551727311523996, + -3.22729451764143718517, + -2.8175401114513378771, + }; + static const double q[] = { + 1, + 2.79257750980575282228, + 11.0567237927800161565, + 15.930646027911794143, + 22.9367376522880577224, + 13.5064170191802889145, + 5.48409182238641741584, + }; + result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), 1 / z) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), 1 / z); + result *= exp(-z * z) / z; + return 1 - result; + } + /* handle the nan case, but don't use isnan for max portability */ + else if (z != z) + return z; + /* finally return saturated result */ + else + return 1; +} +#endif /* HAVE_ERF */ + +#if !HAVE_EXPF +#undef expf +#define expf(x) ((float)exp(x)) +#endif /* HAVE_EXPF */ + +#if !HAVE_EXP2 +#undef exp2 +#define exp2(x) exp((x) * M_LN2) +#endif /* HAVE_EXP2 */ + +#if !HAVE_EXP2F +#undef exp2f +#define exp2f(x) ((float)exp2(x)) +#endif /* HAVE_EXP2F */ + +#if !HAVE_ISINF +#undef isinf +/* Note: these do not follow the BSD/Apple/GNU convention of returning -1 for +-Inf, +1 for Inf, 0 otherwise, but merely follow the POSIX/ISO mandated spec of +returning a non-zero value for +/-Inf, 0 otherwise. */ +static av_always_inline av_const int avpriv_isinff(float x) +{ + uint32_t v = av_float2int(x); + if ((v & 0x7f800000) != 0x7f800000) + return 0; + return !(v & 0x007fffff); +} + +static av_always_inline av_const int avpriv_isinf(double x) +{ + uint64_t v = av_double2int(x); + if ((v & 0x7ff0000000000000) != 0x7ff0000000000000) + return 0; + return !(v & 0x000fffffffffffff); +} + +#define isinf(x) \ + (sizeof(x) == sizeof(float) \ + ? avpriv_isinff(x) \ + : avpriv_isinf(x)) +#endif /* HAVE_ISINF */ + +#if !HAVE_ISNAN +static av_always_inline av_const int avpriv_isnanf(float x) +{ + uint32_t v = av_float2int(x); + if ((v & 0x7f800000) != 0x7f800000) + return 0; + return v & 0x007fffff; +} + +static av_always_inline av_const int avpriv_isnan(double x) +{ + uint64_t v = av_double2int(x); + if ((v & 0x7ff0000000000000) != 0x7ff0000000000000) + return 0; + return (v & 0x000fffffffffffff) && 1; +} + +#define isnan(x) \ + (sizeof(x) == sizeof(float) \ + ? avpriv_isnanf(x) \ + : avpriv_isnan(x)) +#endif /* HAVE_ISNAN */ + +#if !HAVE_ISFINITE +static av_always_inline av_const int avpriv_isfinitef(float x) +{ + uint32_t v = av_float2int(x); + return (v & 0x7f800000) != 0x7f800000; +} + +static av_always_inline av_const int avpriv_isfinite(double x) +{ + uint64_t v = av_double2int(x); + return (v & 0x7ff0000000000000) != 0x7ff0000000000000; +} + +#define isfinite(x) \ + (sizeof(x) == sizeof(float) \ + ? avpriv_isfinitef(x) \ + : avpriv_isfinite(x)) +#endif /* HAVE_ISFINITE */ + +#if !HAVE_HYPOT +static inline av_const double hypot(double x, double y) +{ + double ret, temp; + x = fabs(x); + y = fabs(y); + + if (isinf(x) || isinf(y)) + return av_int2double(0x7ff0000000000000); + if (x == 0 || y == 0) + return x + y; + if (x < y) { + temp = x; + x = y; + y = temp; + } + + y = y/x; + return x*sqrt(1 + y*y); +} +#endif /* HAVE_HYPOT */ + +#if !HAVE_LDEXPF +#undef ldexpf +#define ldexpf(x, exp) ((float)ldexp(x, exp)) +#endif /* HAVE_LDEXPF */ + +#if !HAVE_LLRINT +#undef llrint +#define llrint(x) ((long long)rint(x)) +#endif /* HAVE_LLRINT */ + +#if !HAVE_LLRINTF +#undef llrintf +#define llrintf(x) ((long long)rint(x)) +#endif /* HAVE_LLRINT */ + +#if !HAVE_LOG2 +#undef log2 +#define log2(x) (log(x) * 1.44269504088896340736) +#endif /* HAVE_LOG2 */ + +#if !HAVE_LOG2F +#undef log2f +#define log2f(x) ((float)log2(x)) +#endif /* HAVE_LOG2F */ + +#if !HAVE_LOG10F +#undef log10f +#define log10f(x) ((float)log10(x)) +#endif /* HAVE_LOG10F */ + +#if !HAVE_SINF +#undef sinf +#define sinf(x) ((float)sin(x)) +#endif /* HAVE_SINF */ + +#if !HAVE_RINT +static inline double rint(double x) +{ + return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); +} +#endif /* HAVE_RINT */ + +#if !HAVE_LRINT +static av_always_inline av_const long int lrint(double x) +{ + return rint(x); +} +#endif /* HAVE_LRINT */ + +#if !HAVE_LRINTF +static av_always_inline av_const long int lrintf(float x) +{ + return (int)(rint(x)); +} +#endif /* HAVE_LRINTF */ + +#if !HAVE_ROUND +static av_always_inline av_const double round(double x) +{ + return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5); +} +#endif /* HAVE_ROUND */ + +#if !HAVE_ROUNDF +static av_always_inline av_const float roundf(float x) +{ + return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5); +} +#endif /* HAVE_ROUNDF */ + +#if !HAVE_TRUNC +static av_always_inline av_const double trunc(double x) +{ + return (x > 0) ? floor(x) : ceil(x); +} +#endif /* HAVE_TRUNC */ + +#if !HAVE_TRUNCF +static av_always_inline av_const float truncf(float x) +{ + return (x > 0) ? floor(x) : ceil(x); +} +#endif /* HAVE_TRUNCF */ + +#endif /* AVUTIL_LIBM_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lls.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lls.c new file mode 100644 index 0000000000..0560b6a79c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lls.c @@ -0,0 +1,123 @@ +/* + * linear least squares model + * + * Copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * linear least squares model + */ + +#include +#include + +#include "attributes.h" +#include "internal.h" +#include "version.h" +#include "lls.h" + +static void update_lls(LLSModel *m, const double *var) +{ + int i, j; + + for (i = 0; i <= m->indep_count; i++) { + for (j = i; j <= m->indep_count; j++) { + m->covariance[i][j] += var[i] * var[j]; + } + } +} + +void avpriv_solve_lls(LLSModel *m, double threshold, unsigned short min_order) +{ + int i, j, k; + double (*factor)[MAX_VARS_ALIGN] = (void *) &m->covariance[1][0]; + double (*covar) [MAX_VARS_ALIGN] = (void *) &m->covariance[1][1]; + double *covar_y = m->covariance[0]; + int count = m->indep_count; + + for (i = 0; i < count; i++) { + for (j = i; j < count; j++) { + double sum = covar[i][j]; + + for (k = 0; k <= i-1; k++) + sum -= factor[i][k] * factor[j][k]; + + if (i == j) { + if (sum < threshold) + sum = 1.0; + factor[i][i] = sqrt(sum); + } else { + factor[j][i] = sum / factor[i][i]; + } + } + } + + for (i = 0; i < count; i++) { + double sum = covar_y[i + 1]; + + for (k = 0; k <= i-1; k++) + sum -= factor[i][k] * m->coeff[0][k]; + + m->coeff[0][i] = sum / factor[i][i]; + } + + for (j = count - 1; j >= min_order; j--) { + for (i = j; i >= 0; i--) { + double sum = m->coeff[0][i]; + + for (k = i + 1; k <= j; k++) + sum -= factor[k][i] * m->coeff[j][k]; + + m->coeff[j][i] = sum / factor[i][i]; + } + + m->variance[j] = covar_y[0]; + + for (i = 0; i <= j; i++) { + double sum = m->coeff[j][i] * covar[i][i] - 2 * covar_y[i + 1]; + + for (k = 0; k < i; k++) + sum += 2 * m->coeff[j][k] * covar[k][i]; + + m->variance[j] += m->coeff[j][i] * sum; + } + } +} + +static double evaluate_lls(LLSModel *m, const double *param, int order) +{ + int i; + double out = 0; + + for (i = 0; i <= order; i++) + out += param[i] * m->coeff[order][i]; + + return out; +} + +av_cold void avpriv_init_lls(LLSModel *m, int indep_count) +{ + memset(m, 0, sizeof(LLSModel)); + m->indep_count = indep_count; + m->update_lls = update_lls; + m->evaluate_lls = evaluate_lls; + if (ARCH_X86) + ff_init_lls_x86(m); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lls.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lls.h new file mode 100644 index 0000000000..1a276d537d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/lls.h @@ -0,0 +1,64 @@ +/* + * linear least squares model + * + * Copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LLS_H +#define AVUTIL_LLS_H + +#include "macros.h" +#include "mem.h" +#include "version.h" + +#define MAX_VARS 32 +#define MAX_VARS_ALIGN FFALIGN(MAX_VARS+1,4) + +//FIXME avoid direct access to LLSModel from outside + +/** + * Linear least squares model. + */ +typedef struct LLSModel { + DECLARE_ALIGNED(32, double, covariance[MAX_VARS_ALIGN][MAX_VARS_ALIGN]); + DECLARE_ALIGNED(32, double, coeff[MAX_VARS][MAX_VARS]); + double variance[MAX_VARS]; + int indep_count; + /** + * Take the outer-product of var[] with itself, and add to the covariance matrix. + * @param m this context + * @param var training samples, starting with the value to be predicted + * 32-byte aligned, and any padding elements must be initialized + * (i.e not denormal/nan). + */ + void (*update_lls)(struct LLSModel *m, const double *var); + /** + * Inner product of var[] and the LPC coefs. + * @param m this context + * @param var training samples, excluding the value to be predicted. unaligned. + * @param order lpc order + */ + double (*evaluate_lls)(struct LLSModel *m, const double *var, int order); +} LLSModel; + +void avpriv_init_lls(LLSModel *m, int indep_count); +void ff_init_lls_x86(LLSModel *m); +void avpriv_solve_lls(LLSModel *m, double threshold, unsigned short min_order); + +#endif /* AVUTIL_LLS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log.c new file mode 100644 index 0000000000..93a156b8e4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log.c @@ -0,0 +1,435 @@ +/* + * log functions + * Copyright (c) 2003 Michel Bardiaux + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * logging functions + */ + +#include "config.h" + +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_IO_H +#include +#endif +#include +#include +#include "avutil.h" +#include "bprint.h" +#include "common.h" +#include "internal.h" +#include "log.h" +#include "thread.h" + +static AVMutex mutex = AV_MUTEX_INITIALIZER; + +#define LINE_SZ 1024 + +#if HAVE_VALGRIND_VALGRIND_H +#include +/* this is the log level at which valgrind will output a full backtrace */ +#define BACKTRACE_LOGLEVEL AV_LOG_ERROR +#endif + +static int av_log_level = AV_LOG_INFO; +static int flags; + +#define NB_LEVELS 8 +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE +#include +static const uint8_t color[16 + AV_CLASS_CATEGORY_NB] = { + [AV_LOG_PANIC /8] = 12, + [AV_LOG_FATAL /8] = 12, + [AV_LOG_ERROR /8] = 12, + [AV_LOG_WARNING/8] = 14, + [AV_LOG_INFO /8] = 7, + [AV_LOG_VERBOSE/8] = 10, + [AV_LOG_DEBUG /8] = 10, + [AV_LOG_TRACE /8] = 8, + [16+AV_CLASS_CATEGORY_NA ] = 7, + [16+AV_CLASS_CATEGORY_INPUT ] = 13, + [16+AV_CLASS_CATEGORY_OUTPUT ] = 5, + [16+AV_CLASS_CATEGORY_MUXER ] = 13, + [16+AV_CLASS_CATEGORY_DEMUXER ] = 5, + [16+AV_CLASS_CATEGORY_ENCODER ] = 11, + [16+AV_CLASS_CATEGORY_DECODER ] = 3, + [16+AV_CLASS_CATEGORY_FILTER ] = 10, + [16+AV_CLASS_CATEGORY_BITSTREAM_FILTER] = 9, + [16+AV_CLASS_CATEGORY_SWSCALER ] = 7, + [16+AV_CLASS_CATEGORY_SWRESAMPLER ] = 7, + [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ] = 13, + [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ] = 5, + [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ] = 13, + [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ] = 5, + [16+AV_CLASS_CATEGORY_DEVICE_OUTPUT ] = 13, + [16+AV_CLASS_CATEGORY_DEVICE_INPUT ] = 5, +}; + +static int16_t background, attr_orig; +static HANDLE con; +#else + +static const uint32_t color[16 + AV_CLASS_CATEGORY_NB] = { + [AV_LOG_PANIC /8] = 52 << 16 | 196 << 8 | 0x41, + [AV_LOG_FATAL /8] = 208 << 8 | 0x41, + [AV_LOG_ERROR /8] = 196 << 8 | 0x11, + [AV_LOG_WARNING/8] = 226 << 8 | 0x03, + [AV_LOG_INFO /8] = 253 << 8 | 0x09, + [AV_LOG_VERBOSE/8] = 40 << 8 | 0x02, + [AV_LOG_DEBUG /8] = 34 << 8 | 0x02, + [AV_LOG_TRACE /8] = 34 << 8 | 0x07, + [16+AV_CLASS_CATEGORY_NA ] = 250 << 8 | 0x09, + [16+AV_CLASS_CATEGORY_INPUT ] = 219 << 8 | 0x15, + [16+AV_CLASS_CATEGORY_OUTPUT ] = 201 << 8 | 0x05, + [16+AV_CLASS_CATEGORY_MUXER ] = 213 << 8 | 0x15, + [16+AV_CLASS_CATEGORY_DEMUXER ] = 207 << 8 | 0x05, + [16+AV_CLASS_CATEGORY_ENCODER ] = 51 << 8 | 0x16, + [16+AV_CLASS_CATEGORY_DECODER ] = 39 << 8 | 0x06, + [16+AV_CLASS_CATEGORY_FILTER ] = 155 << 8 | 0x12, + [16+AV_CLASS_CATEGORY_BITSTREAM_FILTER] = 192 << 8 | 0x14, + [16+AV_CLASS_CATEGORY_SWSCALER ] = 153 << 8 | 0x14, + [16+AV_CLASS_CATEGORY_SWRESAMPLER ] = 147 << 8 | 0x14, + [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ] = 213 << 8 | 0x15, + [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ] = 207 << 8 | 0x05, + [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ] = 213 << 8 | 0x15, + [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ] = 207 << 8 | 0x05, + [16+AV_CLASS_CATEGORY_DEVICE_OUTPUT ] = 213 << 8 | 0x15, + [16+AV_CLASS_CATEGORY_DEVICE_INPUT ] = 207 << 8 | 0x05, +}; + +#endif +static int use_color = -1; + +static void check_color_terminal(void) +{ +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE + CONSOLE_SCREEN_BUFFER_INFO con_info; + con = GetStdHandle(STD_ERROR_HANDLE); + use_color = (con != INVALID_HANDLE_VALUE) && !getenv("NO_COLOR") && + !getenv("AV_LOG_FORCE_NOCOLOR"); + if (use_color) { + GetConsoleScreenBufferInfo(con, &con_info); + attr_orig = con_info.wAttributes; + background = attr_orig & 0xF0; + } +#elif HAVE_ISATTY + char *term = getenv("TERM"); + use_color = !getenv("NO_COLOR") && !getenv("AV_LOG_FORCE_NOCOLOR") && + (getenv("TERM") && isatty(2) || getenv("AV_LOG_FORCE_COLOR")); + if ( getenv("AV_LOG_FORCE_256COLOR") + || (term && strstr(term, "256color"))) + use_color *= 256; +#else + use_color = getenv("AV_LOG_FORCE_COLOR") && !getenv("NO_COLOR") && + !getenv("AV_LOG_FORCE_NOCOLOR"); +#endif +} + +static void colored_fputs(int level, int tint, const char *str) +{ + int local_use_color; + if (!*str) + return; + + if (use_color < 0) + check_color_terminal(); + + if (level == AV_LOG_INFO/8) local_use_color = 0; + else local_use_color = use_color; + +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE + if (local_use_color) + SetConsoleTextAttribute(con, background | color[level]); + fputs(str, stderr); + if (local_use_color) + SetConsoleTextAttribute(con, attr_orig); +#else + if (local_use_color == 1) { + fprintf(stderr, + "\033[%"PRIu32";3%"PRIu32"m%s\033[0m", + (color[level] >> 4) & 15, + color[level] & 15, + str); + } else if (tint && use_color == 256) { + fprintf(stderr, + "\033[48;5;%"PRIu32"m\033[38;5;%dm%s\033[0m", + (color[level] >> 16) & 0xff, + tint, + str); + } else if (local_use_color == 256) { + fprintf(stderr, + "\033[48;5;%"PRIu32"m\033[38;5;%"PRIu32"m%s\033[0m", + (color[level] >> 16) & 0xff, + (color[level] >> 8) & 0xff, + str); + } else + fputs(str, stderr); +#endif + +} + +const char *av_default_item_name(void *ptr) +{ + return (*(AVClass **) ptr)->class_name; +} + +AVClassCategory av_default_get_category(void *ptr) +{ + return (*(AVClass **) ptr)->category; +} + +static void sanitize(uint8_t *line){ + while(*line){ + if(*line < 0x08 || (*line > 0x0D && *line < 0x20)) + *line='?'; + line++; + } +} + +static int get_category(void *ptr){ + AVClass *avc = *(AVClass **) ptr; + if( !avc + || (avc->version&0xFF)<100 + || avc->version < (51 << 16 | 59 << 8) + || avc->category >= AV_CLASS_CATEGORY_NB) return AV_CLASS_CATEGORY_NA + 16; + + if(avc->get_category) + return avc->get_category(ptr) + 16; + + return avc->category + 16; +} + +static const char *get_level_str(int level) +{ + switch (level) { + case AV_LOG_QUIET: + return "quiet"; + case AV_LOG_DEBUG: + return "debug"; + case AV_LOG_VERBOSE: + return "verbose"; + case AV_LOG_INFO: + return "info"; + case AV_LOG_WARNING: + return "warning"; + case AV_LOG_ERROR: + return "error"; + case AV_LOG_FATAL: + return "fatal"; + case AV_LOG_PANIC: + return "panic"; + default: + return ""; + } +} + +static void format_line(void *avcl, int level, const char *fmt, va_list vl, + AVBPrint part[4], int *print_prefix, int type[2]) +{ + AVClass* avc = avcl ? *(AVClass **) avcl : NULL; + av_bprint_init(part+0, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprint_init(part+1, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprint_init(part+2, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprint_init(part+3, 0, 65536); + + if(type) type[0] = type[1] = AV_CLASS_CATEGORY_NA + 16; + if (*print_prefix && avc) { + if (avc->parent_log_context_offset) { + AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) + + avc->parent_log_context_offset); + if (parent && *parent) { + av_bprintf(part+0, "[%s @ %p] ", + (*parent)->item_name(parent), parent); + if(type) type[0] = get_category(parent); + } + } + av_bprintf(part+1, "[%s @ %p] ", + avc->item_name(avcl), avcl); + if(type) type[1] = get_category(avcl); + } + + if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL)) + av_bprintf(part+2, "[%s] ", get_level_str(level)); + + av_vbprintf(part+3, fmt, vl); + + if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) { + char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0; + *print_prefix = lastc == '\n' || lastc == '\r'; + } +} + +void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix) +{ + av_log_format_line2(ptr, level, fmt, vl, line, line_size, print_prefix); +} + +int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix) +{ + AVBPrint part[4]; + int ret; + + format_line(ptr, level, fmt, vl, part, print_prefix, NULL); + ret = snprintf(line, line_size, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str); + av_bprint_finalize(part+3, NULL); + return ret; +} + +void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) +{ + static int print_prefix = 1; + static int count; + static char prev[LINE_SZ]; + AVBPrint part[4]; + char line[LINE_SZ]; + static int is_atty; + int type[2]; + unsigned tint = 0; + + if (level >= 0) { + tint = level & 0xff00; + level &= 0xff; + } + + if (level > av_log_level) + return; + ff_mutex_lock(&mutex); + + format_line(ptr, level, fmt, vl, part, &print_prefix, type); + snprintf(line, sizeof(line), "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str); + +#if HAVE_ISATTY + if (!is_atty) + is_atty = isatty(2) ? 1 : -1; +#endif + + if (print_prefix && (flags & AV_LOG_SKIP_REPEATED) && !strcmp(line, prev) && + *line && line[strlen(line) - 1] != '\r'){ + count++; + if (is_atty == 1) + fprintf(stderr, " Last message repeated %d times\r", count); + goto end; + } + if (count > 0) { + fprintf(stderr, " Last message repeated %d times\n", count); + count = 0; + } + strcpy(prev, line); + sanitize(part[0].str); + colored_fputs(type[0], 0, part[0].str); + sanitize(part[1].str); + colored_fputs(type[1], 0, part[1].str); + sanitize(part[2].str); + colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[2].str); + sanitize(part[3].str); + colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[3].str); + +#if CONFIG_VALGRIND_BACKTRACE + if (level <= BACKTRACE_LOGLEVEL) + VALGRIND_PRINTF_BACKTRACE("%s", ""); +#endif +end: + av_bprint_finalize(part+3, NULL); + ff_mutex_unlock(&mutex); +} + +static void (*av_log_callback)(void*, int, const char*, va_list) = + av_log_default_callback; + +void av_log(void* avcl, int level, const char *fmt, ...) +{ + AVClass* avc = avcl ? *(AVClass **) avcl : NULL; + va_list vl; + va_start(vl, fmt); + if (avc && avc->version >= (50 << 16 | 15 << 8 | 2) && + avc->log_level_offset_offset && level >= AV_LOG_FATAL) + level += *(int *) (((uint8_t *) avcl) + avc->log_level_offset_offset); + av_vlog(avcl, level, fmt, vl); + va_end(vl); +} + +void av_vlog(void* avcl, int level, const char *fmt, va_list vl) +{ + void (*log_callback)(void*, int, const char*, va_list) = av_log_callback; + if (log_callback) + log_callback(avcl, level, fmt, vl); +} + +int av_log_get_level(void) +{ + return av_log_level; +} + +void av_log_set_level(int level) +{ + av_log_level = level; +} + +void av_log_set_flags(int arg) +{ + flags = arg; +} + +int av_log_get_flags(void) +{ + return flags; +} + +void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)) +{ + av_log_callback = callback; +} + +static void missing_feature_sample(int sample, void *avc, const char *msg, + va_list argument_list) +{ + av_vlog(avc, AV_LOG_WARNING, msg, argument_list); + av_log(avc, AV_LOG_WARNING, " is not implemented. Update your FFmpeg " + "version to the newest one from Git. If the problem still " + "occurs, it means that your file has a feature which has not " + "been implemented.\n"); + if (sample) + av_log(avc, AV_LOG_WARNING, "If you want to help, upload a sample " + "of this file to ftp://upload.ffmpeg.org/incoming/ " + "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n"); +} + +void avpriv_request_sample(void *avc, const char *msg, ...) +{ + va_list argument_list; + + va_start(argument_list, msg); + missing_feature_sample(1, avc, msg, argument_list); + va_end(argument_list); +} + +void avpriv_report_missing_feature(void *avc, const char *msg, ...) +{ + va_list argument_list; + + va_start(argument_list, msg); + missing_feature_sample(0, avc, msg, argument_list); + va_end(argument_list); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log.h new file mode 100644 index 0000000000..d9554e609d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log.h @@ -0,0 +1,362 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LOG_H +#define AVUTIL_LOG_H + +#include +#include "avutil.h" +#include "attributes.h" +#include "version.h" + +typedef enum { + AV_CLASS_CATEGORY_NA = 0, + AV_CLASS_CATEGORY_INPUT, + AV_CLASS_CATEGORY_OUTPUT, + AV_CLASS_CATEGORY_MUXER, + AV_CLASS_CATEGORY_DEMUXER, + AV_CLASS_CATEGORY_ENCODER, + AV_CLASS_CATEGORY_DECODER, + AV_CLASS_CATEGORY_FILTER, + AV_CLASS_CATEGORY_BITSTREAM_FILTER, + AV_CLASS_CATEGORY_SWSCALER, + AV_CLASS_CATEGORY_SWRESAMPLER, + AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT = 40, + AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, + AV_CLASS_CATEGORY_DEVICE_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_INPUT, + AV_CLASS_CATEGORY_NB ///< not part of ABI/API +}AVClassCategory; + +#define AV_IS_INPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_INPUT)) + +#define AV_IS_OUTPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_OUTPUT)) + +struct AVOptionRanges; + +/** + * Describe the class of an AVClass context structure. That is an + * arbitrary struct of which the first field is a pointer to an + * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.). + */ +typedef struct AVClass { + /** + * The name of the class; usually it is the same name as the + * context structure type to which the AVClass is associated. + */ + const char* class_name; + + /** + * A pointer to a function which returns the name of a context + * instance ctx associated with the class. + */ + const char* (*item_name)(void* ctx); + + /** + * a pointer to the first option specified in the class if any or NULL + * + * @see av_set_default_options() + */ + const struct AVOption *option; + + /** + * LIBAVUTIL_VERSION with which this structure was created. + * This is used to allow fields to be added without requiring major + * version bumps everywhere. + */ + + int version; + + /** + * Offset in the structure where log_level_offset is stored. + * 0 means there is no such variable + */ + int log_level_offset_offset; + + /** + * Offset in the structure where a pointer to the parent context for + * logging is stored. For example a decoder could pass its AVCodecContext + * to eval as such a parent context, which an av_log() implementation + * could then leverage to display the parent context. + * The offset can be NULL. + */ + int parent_log_context_offset; + + /** + * Return next AVOptions-enabled child or NULL + */ + void* (*child_next)(void *obj, void *prev); + + /** + * Return an AVClass corresponding to the next potential + * AVOptions-enabled child. + * + * The difference between child_next and this is that + * child_next iterates over _already existing_ objects, while + * child_class_next iterates over _all possible_ children. + */ + const struct AVClass* (*child_class_next)(const struct AVClass *prev); + + /** + * Category used for visualization (like color) + * This is only set if the category is equal for all objects using this class. + * available since version (51 << 16 | 56 << 8 | 100) + */ + AVClassCategory category; + + /** + * Callback to return the category. + * available since version (51 << 16 | 59 << 8 | 100) + */ + AVClassCategory (*get_category)(void* ctx); + + /** + * Callback to return the supported/allowed ranges. + * available since version (52.12) + */ + int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags); +} AVClass; + +/** + * @addtogroup lavu_log + * + * @{ + * + * @defgroup lavu_log_constants Logging Constants + * + * @{ + */ + +/** + * Print no output. + */ +#define AV_LOG_QUIET -8 + +/** + * Something went really wrong and we will crash now. + */ +#define AV_LOG_PANIC 0 + +/** + * Something went wrong and recovery is not possible. + * For example, no header was found for a format which depends + * on headers or an illegal combination of parameters is used. + */ +#define AV_LOG_FATAL 8 + +/** + * Something went wrong and cannot losslessly be recovered. + * However, not all future data is affected. + */ +#define AV_LOG_ERROR 16 + +/** + * Something somehow does not look correct. This may or may not + * lead to problems. An example would be the use of '-vstrict -2'. + */ +#define AV_LOG_WARNING 24 + +/** + * Standard information. + */ +#define AV_LOG_INFO 32 + +/** + * Detailed information. + */ +#define AV_LOG_VERBOSE 40 + +/** + * Stuff which is only useful for libav* developers. + */ +#define AV_LOG_DEBUG 48 + +/** + * Extremely verbose debugging, useful for libav* development. + */ +#define AV_LOG_TRACE 56 + +#define AV_LOG_MAX_OFFSET (AV_LOG_TRACE - AV_LOG_QUIET) + +/** + * @} + */ + +/** + * Sets additional colors for extended debugging sessions. + * @code + av_log(ctx, AV_LOG_DEBUG|AV_LOG_C(134), "Message in purple\n"); + @endcode + * Requires 256color terminal support. Uses outside debugging is not + * recommended. + */ +#define AV_LOG_C(x) ((x) << 8) + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct or NULL if general log. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + */ +void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4); + + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_vlog(void *avcl, int level, const char *fmt, va_list vl); + +/** + * Get the current log level + * + * @see lavu_log_constants + * + * @return Current log level + */ +int av_log_get_level(void); + +/** + * Set the log level + * + * @see lavu_log_constants + * + * @param level Logging level + */ +void av_log_set_level(int level); + +/** + * Set the logging callback + * + * @note The callback must be thread safe, even if the application does not use + * threads itself as some codecs are multithreaded. + * + * @see av_log_default_callback + * + * @param callback A logging function with a compatible signature. + */ +void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)); + +/** + * Default logging callback + * + * It prints the message to stderr, optionally colorizing it. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_log_default_callback(void *avcl, int level, const char *fmt, + va_list vl); + +/** + * Return the context name + * + * @param ctx The AVClass context + * + * @return The AVClass class_name + */ +const char* av_default_item_name(void* ctx); +AVClassCategory av_default_get_category(void *ptr); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formatted line + * @param line_size size of the buffer + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + */ +void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formatted line; + * may be NULL if line_size is 0 + * @param line_size size of the buffer; at most line_size-1 characters will + * be written to the buffer, plus one null terminator + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + * @return Returns a negative value if an error occurred, otherwise returns + * the number of characters that would have been written for a + * sufficiently large buffer, not including the terminating null + * character. If the return value is not less than line_size, it means + * that the log message was truncated to fit the buffer. + */ +int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +/** + * Skip repeated messages, this requires the user app to use av_log() instead of + * (f)printf as the 2 would otherwise interfere and lead to + * "Last message repeated x times" messages below (f)printf messages with some + * bad luck. + * Also to receive the last, "last repeated" line if any, the user app must + * call av_log(NULL, AV_LOG_QUIET, "%s", ""); at the end + */ +#define AV_LOG_SKIP_REPEATED 1 + +/** + * Include the log severity in messages originating from codecs. + * + * Results in messages such as: + * [rawvideo @ 0xDEADBEEF] [error] encode did not produce valid pts + */ +#define AV_LOG_PRINT_LEVEL 2 + +void av_log_set_flags(int arg); +int av_log_get_flags(void); + +/** + * @} + */ + +#endif /* AVUTIL_LOG_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log2_tab.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log2_tab.c new file mode 100644 index 0000000000..0dbf07d74c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/log2_tab.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2003-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +const uint8_t ff_log2_tab[256]={ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/macros.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/macros.h new file mode 100644 index 0000000000..2007ee5619 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/macros.h @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu + * Utility Preprocessor macros + */ + +#ifndef AVUTIL_MACROS_H +#define AVUTIL_MACROS_H + +/** + * @addtogroup preproc_misc Preprocessor String Macros + * + * String manipulation macros + * + * @{ + */ + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s + +#define AV_GLUE(a, b) a ## b +#define AV_JOIN(a, b) AV_GLUE(a, b) + +/** + * @} + */ + +#define AV_PRAGMA(s) _Pragma(#s) + +#define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) + +#endif /* AVUTIL_MACROS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mastering_display_metadata.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mastering_display_metadata.c new file mode 100644 index 0000000000..6069347617 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mastering_display_metadata.c @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2016 Neil Birkbeck + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "mastering_display_metadata.h" +#include "mem.h" + +AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc(void) +{ + return av_mallocz(sizeof(AVMasteringDisplayMetadata)); +} + +AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA, + sizeof(AVMasteringDisplayMetadata)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, sizeof(AVMasteringDisplayMetadata)); + + return (AVMasteringDisplayMetadata *)side_data->data; +} + +AVContentLightMetadata *av_content_light_metadata_alloc(size_t *size) +{ + AVContentLightMetadata *metadata = av_mallocz(sizeof(AVContentLightMetadata)); + + if (size) + *size = sizeof(*metadata); + + return metadata; +} + +AVContentLightMetadata *av_content_light_metadata_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + sizeof(AVContentLightMetadata)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, sizeof(AVContentLightMetadata)); + + return (AVContentLightMetadata *)side_data->data; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mastering_display_metadata.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mastering_display_metadata.h new file mode 100644 index 0000000000..c23b07c3cd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mastering_display_metadata.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2016 Neil Birkbeck + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MASTERING_DISPLAY_METADATA_H +#define AVUTIL_MASTERING_DISPLAY_METADATA_H + +#include "frame.h" +#include "rational.h" + + +/** + * Mastering display metadata capable of representing the color volume of + * the display used to master the content (SMPTE 2086:2014). + * + * To be used as payload of a AVFrameSideData or AVPacketSideData with the + * appropriate type. + * + * @note The struct should be allocated with av_mastering_display_metadata_alloc() + * and its size is not a part of the public ABI. + */ +typedef struct AVMasteringDisplayMetadata { + /** + * CIE 1931 xy chromaticity coords of color primaries (r, g, b order). + */ + AVRational display_primaries[3][2]; + + /** + * CIE 1931 xy chromaticity coords of white point. + */ + AVRational white_point[2]; + + /** + * Min luminance of mastering display (cd/m^2). + */ + AVRational min_luminance; + + /** + * Max luminance of mastering display (cd/m^2). + */ + AVRational max_luminance; + + /** + * Flag indicating whether the display primaries (and white point) are set. + */ + int has_primaries; + + /** + * Flag indicating whether the luminance (min_ and max_) have been set. + */ + int has_luminance; + +} AVMasteringDisplayMetadata; + +/** + * Allocate an AVMasteringDisplayMetadata structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVMasteringDisplayMetadata filled with default values or NULL + * on failure. + */ +AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc(void); + +/** + * Allocate a complete AVMasteringDisplayMetadata and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVMasteringDisplayMetadata structure to be filled by caller. + */ +AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFrame *frame); + +/** + * Content light level needed by to transmit HDR over HDMI (CTA-861.3). + * + * To be used as payload of a AVFrameSideData or AVPacketSideData with the + * appropriate type. + * + * @note The struct should be allocated with av_content_light_metadata_alloc() + * and its size is not a part of the public ABI. + */ +typedef struct AVContentLightMetadata { + /** + * Max content light level (cd/m^2). + */ + unsigned MaxCLL; + + /** + * Max average light level per frame (cd/m^2). + */ + unsigned MaxFALL; +} AVContentLightMetadata; + +/** + * Allocate an AVContentLightMetadata structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVContentLightMetadata filled with default values or NULL + * on failure. + */ +AVContentLightMetadata *av_content_light_metadata_alloc(size_t *size); + +/** + * Allocate a complete AVContentLightMetadata and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVContentLightMetadata structure to be filled by caller. + */ +AVContentLightMetadata *av_content_light_metadata_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_MASTERING_DISPLAY_METADATA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mathematics.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mathematics.c new file mode 100644 index 0000000000..1bf044cdf1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mathematics.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2005-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * miscellaneous math routines and tables + */ + +#include +#include + +#include "mathematics.h" +#include "libavutil/intmath.h" +#include "libavutil/common.h" +#include "avassert.h" +#include "version.h" + +/* Stein's binary GCD algorithm: + * https://en.wikipedia.org/wiki/Binary_GCD_algorithm */ +int64_t av_gcd(int64_t a, int64_t b) { + int za, zb, k; + int64_t u, v; + if (a == 0) + return b; + if (b == 0) + return a; + za = ff_ctzll(a); + zb = ff_ctzll(b); + k = FFMIN(za, zb); + u = llabs(a >> za); + v = llabs(b >> zb); + while (u != v) { + if (u > v) + FFSWAP(int64_t, v, u); + v -= u; + v >>= ff_ctzll(v); + } + return (uint64_t)u << k; +} + +int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) +{ + int64_t r = 0; + av_assert2(c > 0); + av_assert2(b >=0); + av_assert2((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4); + + if (c <= 0 || b < 0 || !((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4)) + return INT64_MIN; + + if (rnd & AV_ROUND_PASS_MINMAX) { + if (a == INT64_MIN || a == INT64_MAX) + return a; + rnd -= AV_ROUND_PASS_MINMAX; + } + + if (a < 0) + return -(uint64_t)av_rescale_rnd(-FFMAX(a, -INT64_MAX), b, c, rnd ^ ((rnd >> 1) & 1)); + + if (rnd == AV_ROUND_NEAR_INF) + r = c / 2; + else if (rnd & 1) + r = c - 1; + + if (b <= INT_MAX && c <= INT_MAX) { + if (a <= INT_MAX) + return (a * b + r) / c; + else { + int64_t ad = a / c; + int64_t a2 = (a % c * b + r) / c; + if (ad >= INT32_MAX && b && ad > (INT64_MAX - a2) / b) + return INT64_MIN; + return ad * b + a2; + } + } else { +#if 1 + uint64_t a0 = a & 0xFFFFFFFF; + uint64_t a1 = a >> 32; + uint64_t b0 = b & 0xFFFFFFFF; + uint64_t b1 = b >> 32; + uint64_t t1 = a0 * b1 + a1 * b0; + uint64_t t1a = t1 << 32; + int i; + + a0 = a0 * b0 + t1a; + a1 = a1 * b1 + (t1 >> 32) + (a0 < t1a); + a0 += r; + a1 += a0 < r; + + for (i = 63; i >= 0; i--) { + a1 += a1 + ((a0 >> i) & 1); + t1 += t1; + if (c <= a1) { + a1 -= c; + t1++; + } + } + if (t1 > INT64_MAX) + return INT64_MIN; + return t1; +#else + /* reference code doing (a*b + r) / c, requires libavutil/integer.h */ + AVInteger ai; + ai = av_mul_i(av_int2i(a), av_int2i(b)); + ai = av_add_i(ai, av_int2i(r)); + + return av_i2int(av_div_i(ai, av_int2i(c))); +#endif + } +} + +int64_t av_rescale(int64_t a, int64_t b, int64_t c) +{ + return av_rescale_rnd(a, b, c, AV_ROUND_NEAR_INF); +} + +int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, + enum AVRounding rnd) +{ + int64_t b = bq.num * (int64_t)cq.den; + int64_t c = cq.num * (int64_t)bq.den; + return av_rescale_rnd(a, b, c, rnd); +} + +int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) +{ + return av_rescale_q_rnd(a, bq, cq, AV_ROUND_NEAR_INF); +} + +int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b) +{ + int64_t a = tb_a.num * (int64_t)tb_b.den; + int64_t b = tb_b.num * (int64_t)tb_a.den; + if ((FFABS(ts_a)|a|FFABS(ts_b)|b) <= INT_MAX) + return (ts_a*a > ts_b*b) - (ts_a*a < ts_b*b); + if (av_rescale_rnd(ts_a, a, b, AV_ROUND_DOWN) < ts_b) + return -1; + if (av_rescale_rnd(ts_b, b, a, AV_ROUND_DOWN) < ts_a) + return 1; + return 0; +} + +int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod) +{ + int64_t c = (a - b) & (mod - 1); + if (c > (mod >> 1)) + c -= mod; + return c; +} + +int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){ + int64_t a, b, this; + + av_assert0(in_ts != AV_NOPTS_VALUE); + av_assert0(duration >= 0); + + if (*last == AV_NOPTS_VALUE || !duration || in_tb.num*(int64_t)out_tb.den <= out_tb.num*(int64_t)in_tb.den) { +simple_round: + *last = av_rescale_q(in_ts, in_tb, fs_tb) + duration; + return av_rescale_q(in_ts, in_tb, out_tb); + } + + a = av_rescale_q_rnd(2*in_ts-1, in_tb, fs_tb, AV_ROUND_DOWN) >>1; + b = (av_rescale_q_rnd(2*in_ts+1, in_tb, fs_tb, AV_ROUND_UP )+1)>>1; + if (*last < 2*a - b || *last > 2*b - a) + goto simple_round; + + this = av_clip64(*last, a, b); + *last = this + duration; + + return av_rescale_q(this, fs_tb, out_tb); +} + +int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc) +{ + int64_t m, d; + + if (inc != 1) + inc_tb = av_mul_q(inc_tb, (AVRational) {inc, 1}); + + m = inc_tb.num * (int64_t)ts_tb.den; + d = inc_tb.den * (int64_t)ts_tb.num; + + if (m % d == 0) + return ts + m / d; + if (m < d) + return ts; + + { + int64_t old = av_rescale_q(ts, ts_tb, inc_tb); + int64_t old_ts = av_rescale_q(old, inc_tb, ts_tb); + return av_rescale_q(old + 1, inc_tb, ts_tb) + (ts - old_ts); + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mathematics.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mathematics.h new file mode 100644 index 0000000000..54901800ba --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mathematics.h @@ -0,0 +1,242 @@ +/* + * copyright (c) 2005-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @addtogroup lavu_math + * Mathematical utilities for working with timestamp and time base. + */ + +#ifndef AVUTIL_MATHEMATICS_H +#define AVUTIL_MATHEMATICS_H + +#include +#include +#include "attributes.h" +#include "rational.h" +#include "intfloat.h" + +#ifndef M_E +#define M_E 2.7182818284590452354 /* e */ +#endif +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 /* log_e 2 */ +#endif +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 /* log_e 10 */ +#endif +#ifndef M_LOG2_10 +#define M_LOG2_10 3.32192809488736234787 /* log_2 10 */ +#endif +#ifndef M_PHI +#define M_PHI 1.61803398874989484820 /* phi / golden ratio */ +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ +#endif +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#endif +#ifndef NAN +#define NAN av_int2float(0x7fc00000) +#endif +#ifndef INFINITY +#define INFINITY av_int2float(0x7f800000) +#endif + +/** + * @addtogroup lavu_math + * + * @{ + */ + +/** + * Rounding methods. + */ +enum AVRounding { + AV_ROUND_ZERO = 0, ///< Round toward zero. + AV_ROUND_INF = 1, ///< Round away from zero. + AV_ROUND_DOWN = 2, ///< Round toward -infinity. + AV_ROUND_UP = 3, ///< Round toward +infinity. + AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero. + /** + * Flag telling rescaling functions to pass `INT64_MIN`/`MAX` through + * unchanged, avoiding special cases for #AV_NOPTS_VALUE. + * + * Unlike other values of the enumeration AVRounding, this value is a + * bitmask that must be used in conjunction with another value of the + * enumeration through a bitwise OR, in order to set behavior for normal + * cases. + * + * @code{.c} + * av_rescale_rnd(3, 1, 2, AV_ROUND_UP | AV_ROUND_PASS_MINMAX); + * // Rescaling 3: + * // Calculating 3 * 1 / 2 + * // 3 / 2 is rounded up to 2 + * // => 2 + * + * av_rescale_rnd(AV_NOPTS_VALUE, 1, 2, AV_ROUND_UP | AV_ROUND_PASS_MINMAX); + * // Rescaling AV_NOPTS_VALUE: + * // AV_NOPTS_VALUE == INT64_MIN + * // AV_NOPTS_VALUE is passed through + * // => AV_NOPTS_VALUE + * @endcode + */ + AV_ROUND_PASS_MINMAX = 8192, +}; + +/** + * Compute the greatest common divisor of two integer operands. + * + * @param a,b Operands + * @return GCD of a and b up to sign; if a >= 0 and b >= 0, return value is >= 0; + * if a == 0 and b == 0, returns 0. + */ +int64_t av_const av_gcd(int64_t a, int64_t b); + +/** + * Rescale a 64-bit integer with rounding to nearest. + * + * The operation is mathematically equivalent to `a * b / c`, but writing that + * directly can overflow. + * + * This function is equivalent to av_rescale_rnd() with #AV_ROUND_NEAR_INF. + * + * @see av_rescale_rnd(), av_rescale_q(), av_rescale_q_rnd() + */ +int64_t av_rescale(int64_t a, int64_t b, int64_t c) av_const; + +/** + * Rescale a 64-bit integer with specified rounding. + * + * The operation is mathematically equivalent to `a * b / c`, but writing that + * directly can overflow, and does not support different rounding methods. + * + * @see av_rescale(), av_rescale_q(), av_rescale_q_rnd() + */ +int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) av_const; + +/** + * Rescale a 64-bit integer by 2 rational numbers. + * + * The operation is mathematically equivalent to `a * bq / cq`. + * + * This function is equivalent to av_rescale_q_rnd() with #AV_ROUND_NEAR_INF. + * + * @see av_rescale(), av_rescale_rnd(), av_rescale_q_rnd() + */ +int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const; + +/** + * Rescale a 64-bit integer by 2 rational numbers with specified rounding. + * + * The operation is mathematically equivalent to `a * bq / cq`. + * + * @see av_rescale(), av_rescale_rnd(), av_rescale_q() + */ +int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, + enum AVRounding rnd) av_const; + +/** + * Compare two timestamps each in its own time base. + * + * @return One of the following values: + * - -1 if `ts_a` is before `ts_b` + * - 1 if `ts_a` is after `ts_b` + * - 0 if they represent the same position + * + * @warning + * The result of the function is undefined if one of the timestamps is outside + * the `int64_t` range when represented in the other's timebase. + */ +int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b); + +/** + * Compare the remainders of two integer operands divided by a common divisor. + * + * In other words, compare the least significant `log2(mod)` bits of integers + * `a` and `b`. + * + * @code{.c} + * av_compare_mod(0x11, 0x02, 0x10) < 0 // since 0x11 % 0x10 (0x1) < 0x02 % 0x10 (0x2) + * av_compare_mod(0x11, 0x02, 0x20) > 0 // since 0x11 % 0x20 (0x11) > 0x02 % 0x20 (0x02) + * @endcode + * + * @param a,b Operands + * @param mod Divisor; must be a power of 2 + * @return + * - a negative value if `a % mod < b % mod` + * - a positive value if `a % mod > b % mod` + * - zero if `a % mod == b % mod` + */ +int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod); + +/** + * Rescale a timestamp while preserving known durations. + * + * This function is designed to be called per audio packet to scale the input + * timestamp to a different time base. Compared to a simple av_rescale_q() + * call, this function is robust against possible inconsistent frame durations. + * + * The `last` parameter is a state variable that must be preserved for all + * subsequent calls for the same stream. For the first call, `*last` should be + * initialized to #AV_NOPTS_VALUE. + * + * @param[in] in_tb Input time base + * @param[in] in_ts Input timestamp + * @param[in] fs_tb Duration time base; typically this is finer-grained + * (greater) than `in_tb` and `out_tb` + * @param[in] duration Duration till the next call to this function (i.e. + * duration of the current packet/frame) + * @param[in,out] last Pointer to a timestamp expressed in terms of + * `fs_tb`, acting as a state variable + * @param[in] out_tb Output timebase + * @return Timestamp expressed in terms of `out_tb` + * + * @note In the context of this function, "duration" is in term of samples, not + * seconds. + */ +int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb); + +/** + * Add a value to a timestamp. + * + * This function guarantees that when the same value is repeatly added that + * no accumulation of rounding errors occurs. + * + * @param[in] ts Input timestamp + * @param[in] ts_tb Input timestamp time base + * @param[in] inc Value to be added + * @param[in] inc_tb Time base of `inc` + */ +int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc); + + +/** + * @} + */ + +#endif /* AVUTIL_MATHEMATICS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/md5.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/md5.c new file mode 100644 index 0000000000..31e69925ae --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/md5.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2006 Michael Niedermayer (michaelni@gmx.at) + * Copyright (C) 2003-2005 by Christopher R. Hertel (crh@ubiqx.mn.org) + * + * References: + * IETF RFC 1321: The MD5 Message-Digest Algorithm + * Ron Rivest. IETF, April, 1992 + * + * based on http://ubiqx.org/libcifs/source/Auth/MD5.c + * from Christopher R. Hertel (crh@ubiqx.mn.org) + * Simplified, cleaned and IMO redundant comments removed by Michael. + * + * If you use gcc, then version 4.1 or later and -fomit-frame-pointer is + * strongly recommended. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "bswap.h" +#include "intreadwrite.h" +#include "mem.h" +#include "md5.h" + +typedef struct AVMD5 { + uint64_t len; + uint8_t block[64]; + uint32_t ABCD[4]; +} AVMD5; + +const int av_md5_size = sizeof(AVMD5); + +struct AVMD5 *av_md5_alloc(void) +{ + return av_mallocz(sizeof(struct AVMD5)); +} + +static const uint8_t S[4][4] = { + { 7, 12, 17, 22 }, /* round 1 */ + { 5, 9, 14, 20 }, /* round 2 */ + { 4, 11, 16, 23 }, /* round 3 */ + { 6, 10, 15, 21 } /* round 4 */ +}; + +static const uint32_t T[64] = { // T[i]= fabs(sin(i+1)<<32) + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* round 1 */ + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* round 2 */ + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* round 3 */ + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* round 4 */ + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, +}; + +#define CORE(i, a, b, c, d) \ + do { \ + t = S[i >> 4][i & 3]; \ + a += T[i]; \ + \ + if (i < 32) { \ + if (i < 16) \ + a += (d ^ (b & (c ^ d))) + AV_RL32(X+( i & 15));\ + else \ + a += ((d & b) | (~d & c)) + AV_RL32(X+((1 + 5*i) & 15));\ + } else { \ + if (i < 48) \ + a += (b ^ c ^ d) + AV_RL32(X+((5 + 3*i) & 15));\ + else \ + a += (c ^ (b | ~d)) + AV_RL32(X+(( 7*i) & 15));\ + } \ + a = b + (a << t | a >> (32 - t)); \ + } while (0) + +static void body(uint32_t ABCD[4], const uint8_t *src, int nblocks) +{ + int i av_unused; + int n; + const uint32_t *X; + uint32_t a, b, c, d, t; + + for (n = 0; n < nblocks; n++) { + a = ABCD[3]; + b = ABCD[2]; + c = ABCD[1]; + d = ABCD[0]; + + X = (const uint32_t *)src + n * 16; + +#if CONFIG_SMALL + for (i = 0; i < 64; i++) { + CORE(i, a, b, c, d); + t = d; + d = c; + c = b; + b = a; + a = t; + } +#else +#define CORE2(i) \ + CORE(i, a, b, c, d); CORE((i + 1), d, a, b, c); \ + CORE((i + 2), c, d, a, b); CORE((i + 3), b, c, d, a) +#define CORE4(i) CORE2(i); CORE2((i + 4)); CORE2((i + 8)); CORE2((i + 12)) + CORE4(0); + CORE4(16); + CORE4(32); + CORE4(48); +#endif + + ABCD[0] += d; + ABCD[1] += c; + ABCD[2] += b; + ABCD[3] += a; + } +} + +void av_md5_init(AVMD5 *ctx) +{ + ctx->len = 0; + + ctx->ABCD[0] = 0x10325476; + ctx->ABCD[1] = 0x98badcfe; + ctx->ABCD[2] = 0xefcdab89; + ctx->ABCD[3] = 0x67452301; +} + +#if FF_API_CRYPTO_SIZE_T +void av_md5_update(AVMD5 *ctx, const uint8_t *src, int len) +#else +void av_md5_update(AVMD5 *ctx, const uint8_t *src, size_t len) +#endif +{ + const uint8_t *end; + int j; + + j = ctx->len & 63; + ctx->len += len; + + if (j) { + int cnt = FFMIN(len, 64 - j); + memcpy(ctx->block + j, src, cnt); + src += cnt; + len -= cnt; + if (j + cnt < 64) + return; + body(ctx->ABCD, ctx->block, 1); + } + + end = src + (len & ~63); + if (!HAVE_FAST_UNALIGNED && ((intptr_t)src & 3)) { + while (src < end) { + memcpy(ctx->block, src, 64); + body(ctx->ABCD, ctx->block, 1); + src += 64; + } + } else { + int nblocks = len / 64; + body(ctx->ABCD, src, nblocks); + src = end; + } + len &= 63; + if (len > 0) + memcpy(ctx->block, src, len); +} + +void av_md5_final(AVMD5 *ctx, uint8_t *dst) +{ + int i; + uint64_t finalcount = av_le2ne64(ctx->len << 3); + + av_md5_update(ctx, "\200", 1); + while ((ctx->len & 63) != 56) + av_md5_update(ctx, "", 1); + + av_md5_update(ctx, (uint8_t *) &finalcount, 8); + + for (i = 0; i < 4; i++) + AV_WL32(dst + 4 * i, ctx->ABCD[3 - i]); +} + +#if FF_API_CRYPTO_SIZE_T +void av_md5_sum(uint8_t *dst, const uint8_t *src, const int len) +#else +void av_md5_sum(uint8_t *dst, const uint8_t *src, size_t len) +#endif +{ + AVMD5 ctx; + + av_md5_init(&ctx); + av_md5_update(&ctx, src, len); + av_md5_final(&ctx, dst); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/md5.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/md5.h new file mode 100644 index 0000000000..ca72ccbf83 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/md5.h @@ -0,0 +1,98 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_md5 + * Public header for MD5 hash function implementation. + */ + +#ifndef AVUTIL_MD5_H +#define AVUTIL_MD5_H + +#include +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_md5 MD5 + * @ingroup lavu_hash + * MD5 hash function implementation. + * + * @{ + */ + +extern const int av_md5_size; + +struct AVMD5; + +/** + * Allocate an AVMD5 context. + */ +struct AVMD5 *av_md5_alloc(void); + +/** + * Initialize MD5 hashing. + * + * @param ctx pointer to the function context (of size av_md5_size) + */ +void av_md5_init(struct AVMD5 *ctx); + +/** + * Update hash value. + * + * @param ctx hash function context + * @param src input data to update hash with + * @param len input data length + */ +#if FF_API_CRYPTO_SIZE_T +void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, int len); +#else +void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, size_t len); +#endif + +/** + * Finish hashing and output digest value. + * + * @param ctx hash function context + * @param dst buffer where output digest value is stored + */ +void av_md5_final(struct AVMD5 *ctx, uint8_t *dst); + +/** + * Hash an array of data. + * + * @param dst The output buffer to write the digest into + * @param src The data to hash + * @param len The length of the data, in bytes + */ +#if FF_API_CRYPTO_SIZE_T +void av_md5_sum(uint8_t *dst, const uint8_t *src, const int len); +#else +void av_md5_sum(uint8_t *dst, const uint8_t *src, size_t len); +#endif + +/** + * @} + */ + +#endif /* AVUTIL_MD5_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem.c new file mode 100644 index 0000000000..88fe09b179 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem.c @@ -0,0 +1,508 @@ +/* + * default memory allocator for libavutil + * Copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * default memory allocator for libavutil + */ + +#define _XOPEN_SOURCE 600 + +#include "config.h" + +#include +#include +#include +#include +#if HAVE_MALLOC_H +#include +#endif + +#include "avassert.h" +#include "avutil.h" +#include "common.h" +#include "dynarray.h" +#include "intreadwrite.h" +#include "mem.h" + +#ifdef MALLOC_PREFIX + +#define malloc AV_JOIN(MALLOC_PREFIX, malloc) +#define memalign AV_JOIN(MALLOC_PREFIX, memalign) +#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign) +#define realloc AV_JOIN(MALLOC_PREFIX, realloc) +#define free AV_JOIN(MALLOC_PREFIX, free) + +void *malloc(size_t size); +void *memalign(size_t align, size_t size); +int posix_memalign(void **ptr, size_t align, size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); + +#endif /* MALLOC_PREFIX */ + +#include "mem_internal.h" + +#define ALIGN (HAVE_AVX512 ? 64 : (HAVE_AVX ? 32 : 16)) + +/* NOTE: if you want to override these functions with your own + * implementations (not recommended) you have to link libav* as + * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags. + * Note that this will cost performance. */ + +static size_t max_alloc_size= INT_MAX; + +void av_max_alloc(size_t max){ + max_alloc_size = max; +} + +void *av_malloc(size_t size) +{ + void *ptr = NULL; + + /* let's disallow possibly ambiguous cases */ + if (size > (max_alloc_size - 32)) + return NULL; + +#if HAVE_POSIX_MEMALIGN + if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation + if (posix_memalign(&ptr, ALIGN, size)) + ptr = NULL; +#elif HAVE_ALIGNED_MALLOC + ptr = _aligned_malloc(size, ALIGN); +#elif HAVE_MEMALIGN +#ifndef __DJGPP__ + ptr = memalign(ALIGN, size); +#else + ptr = memalign(size, ALIGN); +#endif + /* Why 64? + * Indeed, we should align it: + * on 4 for 386 + * on 16 for 486 + * on 32 for 586, PPro - K6-III + * on 64 for K7 (maybe for P3 too). + * Because L1 and L2 caches are aligned on those values. + * But I don't want to code such logic here! + */ + /* Why 32? + * For AVX ASM. SSE / NEON needs only 16. + * Why not larger? Because I did not see a difference in benchmarks ... + */ + /* benchmarks with P3 + * memalign(64) + 1 3071, 3051, 3032 + * memalign(64) + 2 3051, 3032, 3041 + * memalign(64) + 4 2911, 2896, 2915 + * memalign(64) + 8 2545, 2554, 2550 + * memalign(64) + 16 2543, 2572, 2563 + * memalign(64) + 32 2546, 2545, 2571 + * memalign(64) + 64 2570, 2533, 2558 + * + * BTW, malloc seems to do 8-byte alignment by default here. + */ +#else + ptr = malloc(size); +#endif + if(!ptr && !size) { + size = 1; + ptr= av_malloc(1); + } +#if CONFIG_MEMORY_POISONING + if (ptr) + memset(ptr, FF_MEMORY_POISON, size); +#endif + return ptr; +} + +void *av_realloc(void *ptr, size_t size) +{ + /* let's disallow possibly ambiguous cases */ + if (size > (max_alloc_size - 32)) + return NULL; + +#if HAVE_ALIGNED_MALLOC + return _aligned_realloc(ptr, size + !size, ALIGN); +#else + return realloc(ptr, size + !size); +#endif +} + +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) +{ + size_t size; + void *r; + + if (av_size_mult(elsize, nelem, &size)) { + av_free(ptr); + return NULL; + } + r = av_realloc(ptr, size); + if (!r) + av_free(ptr); + return r; +} + +int av_reallocp(void *ptr, size_t size) +{ + void *val; + + if (!size) { + av_freep(ptr); + return 0; + } + + memcpy(&val, ptr, sizeof(val)); + val = av_realloc(val, size); + + if (!val) { + av_freep(ptr); + return AVERROR(ENOMEM); + } + + memcpy(ptr, &val, sizeof(val)); + return 0; +} + +void *av_malloc_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_malloc(nmemb * size); +} + +void *av_mallocz_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_mallocz(nmemb * size); +} + +void *av_realloc_array(void *ptr, size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_realloc(ptr, nmemb * size); +} + +int av_reallocp_array(void *ptr, size_t nmemb, size_t size) +{ + void *val; + + memcpy(&val, ptr, sizeof(val)); + val = av_realloc_f(val, nmemb, size); + memcpy(ptr, &val, sizeof(val)); + if (!val && nmemb && size) + return AVERROR(ENOMEM); + + return 0; +} + +void av_free(void *ptr) +{ +#if HAVE_ALIGNED_MALLOC + _aligned_free(ptr); +#else + free(ptr); +#endif +} + +void av_freep(void *arg) +{ + void *val; + + memcpy(&val, arg, sizeof(val)); + memcpy(arg, &(void *){ NULL }, sizeof(val)); + av_free(val); +} + +void *av_mallocz(size_t size) +{ + void *ptr = av_malloc(size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +void *av_calloc(size_t nmemb, size_t size) +{ + if (size <= 0 || nmemb >= INT_MAX / size) + return NULL; + return av_mallocz(nmemb * size); +} + +char *av_strdup(const char *s) +{ + char *ptr = NULL; + if (s) { + size_t len = strlen(s) + 1; + ptr = av_realloc(NULL, len); + if (ptr) + memcpy(ptr, s, len); + } + return ptr; +} + +char *av_strndup(const char *s, size_t len) +{ + char *ret = NULL, *end; + + if (!s) + return NULL; + + end = memchr(s, 0, len); + if (end) + len = end - s; + + ret = av_realloc(NULL, len + 1); + if (!ret) + return NULL; + + memcpy(ret, s, len); + ret[len] = 0; + return ret; +} + +void *av_memdup(const void *p, size_t size) +{ + void *ptr = NULL; + if (p) { + ptr = av_malloc(size); + if (ptr) + memcpy(ptr, p, size); + } + return ptr; +} + +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem) +{ + void **tab; + memcpy(&tab, tab_ptr, sizeof(tab)); + + FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { + tab[*nb_ptr] = elem; + memcpy(tab_ptr, &tab, sizeof(tab)); + }, { + return AVERROR(ENOMEM); + }); + return 0; +} + +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem) +{ + void **tab; + memcpy(&tab, tab_ptr, sizeof(tab)); + + FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { + tab[*nb_ptr] = elem; + memcpy(tab_ptr, &tab, sizeof(tab)); + }, { + *nb_ptr = 0; + av_freep(tab_ptr); + }); +} + +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data) +{ + uint8_t *tab_elem_data = NULL; + + FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, { + tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size; + if (elem_data) + memcpy(tab_elem_data, elem_data, elem_size); + else if (CONFIG_MEMORY_POISONING) + memset(tab_elem_data, FF_MEMORY_POISON, elem_size); + }, { + av_freep(tab_ptr); + *nb_ptr = 0; + }); + return tab_elem_data; +} + +static void fill16(uint8_t *dst, int len) +{ + uint32_t v = AV_RN16(dst - 2); + + v |= v << 16; + + while (len >= 4) { + AV_WN32(dst, v); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-2]; + dst++; + } +} + +static void fill24(uint8_t *dst, int len) +{ +#if HAVE_BIGENDIAN + uint32_t v = AV_RB24(dst - 3); + uint32_t a = v << 8 | v >> 16; + uint32_t b = v << 16 | v >> 8; + uint32_t c = v << 24 | v; +#else + uint32_t v = AV_RL24(dst - 3); + uint32_t a = v | v << 24; + uint32_t b = v >> 8 | v << 16; + uint32_t c = v >> 16 | v << 8; +#endif + + while (len >= 12) { + AV_WN32(dst, a); + AV_WN32(dst + 4, b); + AV_WN32(dst + 8, c); + dst += 12; + len -= 12; + } + + if (len >= 4) { + AV_WN32(dst, a); + dst += 4; + len -= 4; + } + + if (len >= 4) { + AV_WN32(dst, b); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-3]; + dst++; + } +} + +static void fill32(uint8_t *dst, int len) +{ + uint32_t v = AV_RN32(dst - 4); + +#if HAVE_FAST_64BIT + uint64_t v2= v + ((uint64_t)v<<32); + while (len >= 32) { + AV_WN64(dst , v2); + AV_WN64(dst+ 8, v2); + AV_WN64(dst+16, v2); + AV_WN64(dst+24, v2); + dst += 32; + len -= 32; + } +#endif + + while (len >= 4) { + AV_WN32(dst, v); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-4]; + dst++; + } +} + +void av_memcpy_backptr(uint8_t *dst, int back, int cnt) +{ + const uint8_t *src = &dst[-back]; + if (!back) + return; + + if (back == 1) { + memset(dst, *src, cnt); + } else if (back == 2) { + fill16(dst, cnt); + } else if (back == 3) { + fill24(dst, cnt); + } else if (back == 4) { + fill32(dst, cnt); + } else { + if (cnt >= 16) { + int blocklen = back; + while (cnt > blocklen) { + memcpy(dst, src, blocklen); + dst += blocklen; + cnt -= blocklen; + blocklen <<= 1; + } + memcpy(dst, src, cnt); + return; + } + if (cnt >= 8) { + AV_COPY32U(dst, src); + AV_COPY32U(dst + 4, src + 4); + src += 8; + dst += 8; + cnt -= 8; + } + if (cnt >= 4) { + AV_COPY32U(dst, src); + src += 4; + dst += 4; + cnt -= 4; + } + if (cnt >= 2) { + AV_COPY16U(dst, src); + src += 2; + dst += 2; + cnt -= 2; + } + if (cnt) + *dst = *src; + } +} + +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) +{ + if (min_size <= *size) + return ptr; + + if (min_size > max_alloc_size - 32) { + *size = 0; + return NULL; + } + + min_size = FFMIN(max_alloc_size - 32, FFMAX(min_size + min_size / 16 + 32, min_size)); + + ptr = av_realloc(ptr, min_size); + /* we could set this to the unmodified min_size but this is safer + * if the user lost the ptr and uses NULL now + */ + if (!ptr) + min_size = 0; + + *size = min_size; + + return ptr; +} + +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size) +{ + ff_fast_malloc(ptr, size, min_size, 0); +} + +void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size) +{ + ff_fast_malloc(ptr, size, min_size, 1); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem.h new file mode 100644 index 0000000000..5fb1a02dd9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem.h @@ -0,0 +1,700 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_mem + * Memory handling functions + */ + +#ifndef AVUTIL_MEM_H +#define AVUTIL_MEM_H + +#include +#include + +#include "attributes.h" +#include "error.h" +#include "avutil.h" + +/** + * @addtogroup lavu_mem + * Utilities for manipulating memory. + * + * FFmpeg has several applications of memory that are not required of a typical + * program. For example, the computing-heavy components like video decoding and + * encoding can be sped up significantly through the use of aligned memory. + * + * However, for each of FFmpeg's applications of memory, there might not be a + * recognized or standardized API for that specific use. Memory alignment, for + * instance, varies wildly depending on operating systems, architectures, and + * compilers. Hence, this component of @ref libavutil is created to make + * dealing with memory consistently possible on all platforms. + * + * @{ + * + * @defgroup lavu_mem_macros Alignment Macros + * Helper macros for declaring aligned variables. + * @{ + */ + +/** + * @def DECLARE_ALIGNED(n,t,v) + * Declare a variable that is aligned in memory. + * + * @code{.c} + * DECLARE_ALIGNED(16, uint16_t, aligned_int) = 42; + * DECLARE_ALIGNED(32, uint8_t, aligned_array)[128]; + * + * // The default-alignment equivalent would be + * uint16_t aligned_int = 42; + * uint8_t aligned_array[128]; + * @endcode + * + * @param n Minimum alignment in bytes + * @param t Type of the variable (or array element) + * @param v Name of the variable + */ + +/** + * @def DECLARE_ASM_ALIGNED(n,t,v) + * Declare an aligned variable appropriate for use in inline assembly code. + * + * @code{.c} + * DECLARE_ASM_ALIGNED(16, uint64_t, pw_08) = UINT64_C(0x0008000800080008); + * @endcode + * + * @param n Minimum alignment in bytes + * @param t Type of the variable (or array element) + * @param v Name of the variable + */ + +/** + * @def DECLARE_ASM_CONST(n,t,v) + * Declare a static constant aligned variable appropriate for use in inline + * assembly code. + * + * @code{.c} + * DECLARE_ASM_CONST(16, uint64_t, pw_08) = UINT64_C(0x0008000800080008); + * @endcode + * + * @param n Minimum alignment in bytes + * @param t Type of the variable (or array element) + * @param v Name of the variable + */ + +#if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1110 || defined(__SUNPRO_C) + #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_CONST(n,t,v) const t __attribute__ ((aligned (n))) v +#elif defined(__DJGPP__) + #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (FFMIN(n, 16)))) v + #define DECLARE_ASM_ALIGNED(n,t,v) t av_used __attribute__ ((aligned (FFMIN(n, 16)))) v + #define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (FFMIN(n, 16)))) v +#elif defined(__GNUC__) || defined(__clang__) + #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_ALIGNED(n,t,v) t av_used __attribute__ ((aligned (n))) v + #define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (n))) v +#elif defined(_MSC_VER) + #define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v + #define DECLARE_ASM_ALIGNED(n,t,v) __declspec(align(n)) t v + #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t v +#else + #define DECLARE_ALIGNED(n,t,v) t v + #define DECLARE_ASM_ALIGNED(n,t,v) t v + #define DECLARE_ASM_CONST(n,t,v) static const t v +#endif + +/** + * @} + */ + +/** + * @defgroup lavu_mem_attrs Function Attributes + * Function attributes applicable to memory handling functions. + * + * These function attributes can help compilers emit more useful warnings, or + * generate better code. + * @{ + */ + +/** + * @def av_malloc_attrib + * Function attribute denoting a malloc-like function. + * + * @see
      Function attribute `malloc` in GCC's documentation + */ + +#if AV_GCC_VERSION_AT_LEAST(3,1) + #define av_malloc_attrib __attribute__((__malloc__)) +#else + #define av_malloc_attrib +#endif + +/** + * @def av_alloc_size(...) + * Function attribute used on a function that allocates memory, whose size is + * given by the specified parameter(s). + * + * @code{.c} + * void *av_malloc(size_t size) av_alloc_size(1); + * void *av_calloc(size_t nmemb, size_t size) av_alloc_size(1, 2); + * @endcode + * + * @param ... One or two parameter indexes, separated by a comma + * + * @see Function attribute `alloc_size` in GCC's documentation + */ + +#if AV_GCC_VERSION_AT_LEAST(4,3) + #define av_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) +#else + #define av_alloc_size(...) +#endif + +/** + * @} + */ + +/** + * @defgroup lavu_mem_funcs Heap Management + * Functions responsible for allocating, freeing, and copying memory. + * + * All memory allocation functions have a built-in upper limit of `INT_MAX` + * bytes. This may be changed with av_max_alloc(), although exercise extreme + * caution when doing so. + * + * @{ + */ + +/** + * Allocate a memory block with alignment suitable for all memory accesses + * (including vectors if available on the CPU). + * + * @param size Size in bytes for the memory block to be allocated + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * @see av_mallocz() + */ +void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a memory block with alignment suitable for all memory accesses + * (including vectors if available on the CPU) and zero all the bytes of the + * block. + * + * @param size Size in bytes for the memory block to be allocated + * @return Pointer to the allocated block, or `NULL` if it cannot be allocated + * @see av_malloc() + */ +void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a memory block for an array with av_malloc(). + * + * The allocated memory will have size `size * nmemb` bytes. + * + * @param nmemb Number of element + * @param size Size of a single element + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * @see av_malloc() + */ +av_alloc_size(1, 2) void *av_malloc_array(size_t nmemb, size_t size); + +/** + * Allocate a memory block for an array with av_mallocz(). + * + * The allocated memory will have size `size * nmemb` bytes. + * + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * + * @see av_mallocz() + * @see av_malloc_array() + */ +av_alloc_size(1, 2) void *av_mallocz_array(size_t nmemb, size_t size); + +/** + * Non-inlined equivalent of av_mallocz_array(). + * + * Created for symmetry with the calloc() C function. + */ +void *av_calloc(size_t nmemb, size_t size) av_malloc_attrib; + +/** + * Allocate, reallocate, or free a block of memory. + * + * If `ptr` is `NULL` and `size` > 0, allocate a new block. If `size` is + * zero, free the memory block pointed to by `ptr`. Otherwise, expand or + * shrink that block of memory according to `size`. + * + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or `NULL` + * @param size Size in bytes of the memory block to be allocated or + * reallocated + * + * @return Pointer to a newly-reallocated block or `NULL` if the block + * cannot be reallocated or the function is used to free the memory block + * + * @warning Unlike av_malloc(), the returned pointer is not guaranteed to be + * correctly aligned. + * @see av_fast_realloc() + * @see av_reallocp() + */ +void *av_realloc(void *ptr, size_t size) av_alloc_size(2); + +/** + * Allocate, reallocate, or free a block of memory through a pointer to a + * pointer. + * + * If `*ptr` is `NULL` and `size` > 0, allocate a new block. If `size` is + * zero, free the memory block pointed to by `*ptr`. Otherwise, expand or + * shrink that block of memory according to `size`. + * + * @param[in,out] ptr Pointer to a pointer to a memory block already allocated + * with av_realloc(), or a pointer to `NULL`. The pointer + * is updated on success, or freed on failure. + * @param[in] size Size in bytes for the memory block to be allocated or + * reallocated + * + * @return Zero on success, an AVERROR error code on failure + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. + */ +av_warn_unused_result +int av_reallocp(void *ptr, size_t size); + +/** + * Allocate, reallocate, or free a block of memory. + * + * This function does the same thing as av_realloc(), except: + * - It takes two size arguments and allocates `nelem * elsize` bytes, + * after checking the result of the multiplication for integer overflow. + * - It frees the input block in case of failure, thus avoiding the memory + * leak with the classic + * @code{.c} + * buf = realloc(buf); + * if (!buf) + * return -1; + * @endcode + * pattern. + */ +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize); + +/** + * Allocate, reallocate, or free an array. + * + * If `ptr` is `NULL` and `nmemb` > 0, allocate a new block. If + * `nmemb` is zero, free the memory block pointed to by `ptr`. + * + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or `NULL` + * @param nmemb Number of elements in the array + * @param size Size of the single element of the array + * + * @return Pointer to a newly-reallocated block or NULL if the block + * cannot be reallocated or the function is used to free the memory block + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. + * @see av_reallocp_array() + */ +av_alloc_size(2, 3) void *av_realloc_array(void *ptr, size_t nmemb, size_t size); + +/** + * Allocate, reallocate, or free an array through a pointer to a pointer. + * + * If `*ptr` is `NULL` and `nmemb` > 0, allocate a new block. If `nmemb` is + * zero, free the memory block pointed to by `*ptr`. + * + * @param[in,out] ptr Pointer to a pointer to a memory block already + * allocated with av_realloc(), or a pointer to `NULL`. + * The pointer is updated on success, or freed on failure. + * @param[in] nmemb Number of elements + * @param[in] size Size of the single element + * + * @return Zero on success, an AVERROR error code on failure + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. + */ +int av_reallocp_array(void *ptr, size_t nmemb, size_t size); + +/** + * Reallocate the given buffer if it is not large enough, otherwise do nothing. + * + * If the given buffer is `NULL`, then a new uninitialized buffer is allocated. + * + * If the given buffer is not large enough, and reallocation fails, `NULL` is + * returned and `*size` is set to 0, but the original buffer is not changed or + * freed. + * + * A typical use pattern follows: + * + * @code{.c} + * uint8_t *buf = ...; + * uint8_t *new_buf = av_fast_realloc(buf, ¤t_size, size_needed); + * if (!new_buf) { + * // Allocation failed; clean up original buffer + * av_freep(&buf); + * return AVERROR(ENOMEM); + * } + * @endcode + * + * @param[in,out] ptr Already allocated buffer, or `NULL` + * @param[in,out] size Pointer to the size of buffer `ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `ptr` + * @return `ptr` if the buffer is large enough, a pointer to newly reallocated + * buffer if the buffer was not large enough, or `NULL` in case of + * error + * @see av_realloc() + * @see av_fast_malloc() + */ +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate a buffer, reusing the given one if large enough. + * + * Contrary to av_fast_realloc(), the current buffer contents might not be + * preserved and on error the old buffer is freed, thus no special handling to + * avoid memleaks is necessary. + * + * `*ptr` is allowed to be `NULL`, in which case allocation always happens if + * `size_needed` is greater than 0. + * + * @code{.c} + * uint8_t *buf = ...; + * av_fast_malloc(&buf, ¤t_size, size_needed); + * if (!buf) { + * // Allocation failed; buf already freed + * return AVERROR(ENOMEM); + * } + * @endcode + * + * @param[in,out] ptr Pointer to pointer to an already allocated buffer. + * `*ptr` will be overwritten with pointer to new + * buffer on success or `NULL` on failure + * @param[in,out] size Pointer to the size of buffer `*ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `*ptr` + * @see av_realloc() + * @see av_fast_mallocz() + */ +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate and clear a buffer, reusing the given one if large enough. + * + * Like av_fast_malloc(), but all newly allocated space is initially cleared. + * Reused buffer is not cleared. + * + * `*ptr` is allowed to be `NULL`, in which case allocation always happens if + * `size_needed` is greater than 0. + * + * @param[in,out] ptr Pointer to pointer to an already allocated buffer. + * `*ptr` will be overwritten with pointer to new + * buffer on success or `NULL` on failure + * @param[in,out] size Pointer to the size of buffer `*ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `*ptr` + * @see av_fast_malloc() + */ +void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size); + +/** + * Free a memory block which has been allocated with a function of av_malloc() + * or av_realloc() family. + * + * @param ptr Pointer to the memory block which should be freed. + * + * @note `ptr = NULL` is explicitly allowed. + * @note It is recommended that you use av_freep() instead, to prevent leaving + * behind dangling pointers. + * @see av_freep() + */ +void av_free(void *ptr); + +/** + * Free a memory block which has been allocated with a function of av_malloc() + * or av_realloc() family, and set the pointer pointing to it to `NULL`. + * + * @code{.c} + * uint8_t *buf = av_malloc(16); + * av_free(buf); + * // buf now contains a dangling pointer to freed memory, and accidental + * // dereference of buf will result in a use-after-free, which may be a + * // security risk. + * + * uint8_t *buf = av_malloc(16); + * av_freep(&buf); + * // buf is now NULL, and accidental dereference will only result in a + * // NULL-pointer dereference. + * @endcode + * + * @param ptr Pointer to the pointer to the memory block which should be freed + * @note `*ptr = NULL` is safe and leads to no action. + * @see av_free() + */ +void av_freep(void *ptr); + +/** + * Duplicate a string. + * + * @param s String to be duplicated + * @return Pointer to a newly-allocated string containing a + * copy of `s` or `NULL` if the string cannot be allocated + * @see av_strndup() + */ +char *av_strdup(const char *s) av_malloc_attrib; + +/** + * Duplicate a substring of a string. + * + * @param s String to be duplicated + * @param len Maximum length of the resulting string (not counting the + * terminating byte) + * @return Pointer to a newly-allocated string containing a + * substring of `s` or `NULL` if the string cannot be allocated + */ +char *av_strndup(const char *s, size_t len) av_malloc_attrib; + +/** + * Duplicate a buffer with av_malloc(). + * + * @param p Buffer to be duplicated + * @param size Size in bytes of the buffer copied + * @return Pointer to a newly allocated buffer containing a + * copy of `p` or `NULL` if the buffer cannot be allocated + */ +void *av_memdup(const void *p, size_t size); + +/** + * Overlapping memcpy() implementation. + * + * @param dst Destination buffer + * @param back Number of bytes back to start copying (i.e. the initial size of + * the overlapping window); must be > 0 + * @param cnt Number of bytes to copy; must be >= 0 + * + * @note `cnt > back` is valid, this will copy the bytes we just copied, + * thus creating a repeating pattern with a period length of `back`. + */ +void av_memcpy_backptr(uint8_t *dst, int back, int cnt); + +/** + * @} + */ + +/** + * @defgroup lavu_mem_dynarray Dynamic Array + * + * Utilities to make an array grow when needed. + * + * Sometimes, the programmer would want to have an array that can grow when + * needed. The libavutil dynamic array utilities fill that need. + * + * libavutil supports two systems of appending elements onto a dynamically + * allocated array, the first one storing the pointer to the value in the + * array, and the second storing the value directly. In both systems, the + * caller is responsible for maintaining a variable containing the length of + * the array, as well as freeing of the array after use. + * + * The first system stores pointers to values in a block of dynamically + * allocated memory. Since only pointers are stored, the function does not need + * to know the size of the type. Both av_dynarray_add() and + * av_dynarray_add_nofree() implement this system. + * + * @code + * type **array = NULL; //< an array of pointers to values + * int nb = 0; //< a variable to keep track of the length of the array + * + * type to_be_added = ...; + * type to_be_added2 = ...; + * + * av_dynarray_add(&array, &nb, &to_be_added); + * if (nb == 0) + * return AVERROR(ENOMEM); + * + * av_dynarray_add(&array, &nb, &to_be_added2); + * if (nb == 0) + * return AVERROR(ENOMEM); + * + * // Now: + * // nb == 2 + * // &to_be_added == array[0] + * // &to_be_added2 == array[1] + * + * av_freep(&array); + * @endcode + * + * The second system stores the value directly in a block of memory. As a + * result, the function has to know the size of the type. av_dynarray2_add() + * implements this mechanism. + * + * @code + * type *array = NULL; //< an array of values + * int nb = 0; //< a variable to keep track of the length of the array + * + * type to_be_added = ...; + * type to_be_added2 = ...; + * + * type *addr = av_dynarray2_add((void **)&array, &nb, sizeof(*array), NULL); + * if (!addr) + * return AVERROR(ENOMEM); + * memcpy(addr, &to_be_added, sizeof(to_be_added)); + * + * // Shortcut of the above. + * type *addr = av_dynarray2_add((void **)&array, &nb, sizeof(*array), + * (const void *)&to_be_added2); + * if (!addr) + * return AVERROR(ENOMEM); + * + * // Now: + * // nb == 2 + * // to_be_added == array[0] + * // to_be_added2 == array[1] + * + * av_freep(&array); + * @endcode + * + * @{ + */ + +/** + * Add the pointer to an element to a dynamic array. + * + * The array to grow is supposed to be an array of pointers to + * structures, and the element to add must be a pointer to an already + * allocated structure. + * + * The array is reallocated when its size reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by `nb_ptr` + * is incremented. + * In case of failure, the array is freed, `*tab_ptr` is set to `NULL` and + * `*nb_ptr` is set to 0. + * + * @param[in,out] tab_ptr Pointer to the array to grow + * @param[in,out] nb_ptr Pointer to the number of elements in the array + * @param[in] elem Element to add + * @see av_dynarray_add_nofree(), av_dynarray2_add() + */ +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element to a dynamic array. + * + * Function has the same functionality as av_dynarray_add(), + * but it doesn't free memory on fails. It returns error code + * instead and leave current buffer untouched. + * + * @return >=0 on success, negative otherwise + * @see av_dynarray_add(), av_dynarray2_add() + */ +av_warn_unused_result +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element of size `elem_size` to a dynamic array. + * + * The array is reallocated when its number of elements reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by `nb_ptr` + * is incremented. + * In case of failure, the array is freed, `*tab_ptr` is set to `NULL` and + * `*nb_ptr` is set to 0. + * + * @param[in,out] tab_ptr Pointer to the array to grow + * @param[in,out] nb_ptr Pointer to the number of elements in the array + * @param[in] elem_size Size in bytes of an element in the array + * @param[in] elem_data Pointer to the data of the element to add. If + * `NULL`, the space of the newly added element is + * allocated but left uninitialized. + * + * @return Pointer to the data of the element to copy in the newly allocated + * space + * @see av_dynarray_add(), av_dynarray_add_nofree() + */ +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data); + +/** + * @} + */ + +/** + * @defgroup lavu_mem_misc Miscellaneous Functions + * + * Other functions related to memory allocation. + * + * @{ + */ + +/** + * Multiply two `size_t` values checking for overflow. + * + * @param[in] a,b Operands of multiplication + * @param[out] r Pointer to the result of the operation + * @return 0 on success, AVERROR(EINVAL) on overflow + */ +static inline int av_size_mult(size_t a, size_t b, size_t *r) +{ + size_t t = a * b; + /* Hack inspired from glibc: don't try the division if nelem and elsize + * are both less than sqrt(SIZE_MAX). */ + if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b) + return AVERROR(EINVAL); + *r = t; + return 0; +} + +/** + * Set the maximum size that may be allocated in one block. + * + * The value specified with this function is effective for all libavutil's @ref + * lavu_mem_funcs "heap management functions." + * + * By default, the max value is defined as `INT_MAX`. + * + * @param max Value to be set as the new maximum size + * + * @warning Exercise extreme caution when using this function. Don't touch + * this if you do not understand the full consequence of doing so. + */ +void av_max_alloc(size_t max); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_MEM_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem_internal.h new file mode 100644 index 0000000000..6fdbcb016e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/mem_internal.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MEM_INTERNAL_H +#define AVUTIL_MEM_INTERNAL_H + +#include "avassert.h" +#include "mem.h" + +static inline int ff_fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc) +{ + void *val; + + memcpy(&val, ptr, sizeof(val)); + if (min_size <= *size) { + av_assert0(val || !min_size); + return 0; + } + min_size = FFMAX(min_size + min_size / 16 + 32, min_size); + av_freep(ptr); + val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size); + memcpy(ptr, &val, sizeof(val)); + if (!val) + min_size = 0; + *size = min_size; + return 1; +} +#endif /* AVUTIL_MEM_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/motion_vector.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/motion_vector.h new file mode 100644 index 0000000000..ec29556388 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/motion_vector.h @@ -0,0 +1,57 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MOTION_VECTOR_H +#define AVUTIL_MOTION_VECTOR_H + +#include + +typedef struct AVMotionVector { + /** + * Where the current macroblock comes from; negative value when it comes + * from the past, positive value when it comes from the future. + * XXX: set exact relative ref frame reference instead of a +/- 1 "direction". + */ + int32_t source; + /** + * Width and height of the block. + */ + uint8_t w, h; + /** + * Absolute source position. Can be outside the frame area. + */ + int16_t src_x, src_y; + /** + * Absolute destination position. Can be outside the frame area. + */ + int16_t dst_x, dst_y; + /** + * Extra flag information. + * Currently unused. + */ + uint64_t flags; + /** + * Motion vector + * src_x = dst_x + motion_x / motion_scale + * src_y = dst_y + motion_y / motion_scale + */ + int32_t motion_x, motion_y; + uint16_t motion_scale; +} AVMotionVector; + +#endif /* AVUTIL_MOTION_VECTOR_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/murmur3.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/murmur3.c new file mode 100644 index 0000000000..7961752515 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/murmur3.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2013 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include "mem.h" +#include "intreadwrite.h" +#include "murmur3.h" + +typedef struct AVMurMur3 { + uint64_t h1, h2; + uint8_t state[16]; + int state_pos; + uint64_t len; +} AVMurMur3; + +AVMurMur3 *av_murmur3_alloc(void) +{ + return av_mallocz(sizeof(AVMurMur3)); +} + +void av_murmur3_init_seeded(AVMurMur3 *c, uint64_t seed) +{ + memset(c, 0, sizeof(*c)); + c->h1 = c->h2 = seed; +} + +void av_murmur3_init(AVMurMur3 *c) +{ + // arbitrary random number as seed + av_murmur3_init_seeded(c, 0x725acc55daddca55); +} + +static const uint64_t c1 = UINT64_C(0x87c37b91114253d5); +static const uint64_t c2 = UINT64_C(0x4cf5ad432745937f); + +#define ROT(a, b) (((a) << (b)) | ((a) >> (64 - (b)))) + +static uint64_t inline get_k1(const uint8_t *src) +{ + uint64_t k = AV_RL64(src); + k *= c1; + k = ROT(k, 31); + k *= c2; + return k; +} + +static inline uint64_t get_k2(const uint8_t *src) +{ + uint64_t k = AV_RL64(src + 8); + k *= c2; + k = ROT(k, 33); + k *= c1; + return k; +} + +static inline uint64_t update_h1(uint64_t k, uint64_t h1, uint64_t h2) +{ + k ^= h1; + k = ROT(k, 27); + k += h2; + k *= 5; + k += 0x52dce729; + return k; +} + +static inline uint64_t update_h2(uint64_t k, uint64_t h1, uint64_t h2) +{ + k ^= h2; + k = ROT(k, 31); + k += h1; + k *= 5; + k += 0x38495ab5; + return k; +} + +#if FF_API_CRYPTO_SIZE_T +void av_murmur3_update(AVMurMur3 *c, const uint8_t *src, int len) +#else +void av_murmur3_update(AVMurMur3 *c, const uint8_t *src, size_t len) +#endif +{ + const uint8_t *end; + uint64_t h1 = c->h1, h2 = c->h2; + uint64_t k1, k2; + if (len <= 0) return; + c->len += len; + if (c->state_pos > 0) { + while (c->state_pos < 16) { + c->state[c->state_pos++] = *src++; + if (--len <= 0) return; + } + c->state_pos = 0; + k1 = get_k1(c->state); + k2 = get_k2(c->state); + h1 = update_h1(k1, h1, h2); + h2 = update_h2(k2, h1, h2); + } + + end = src + (len & ~15); + while (src < end) { + // These could be done sequentially instead + // of interleaved, but like this is over 10% faster + k1 = get_k1(src); + k2 = get_k2(src); + h1 = update_h1(k1, h1, h2); + h2 = update_h2(k2, h1, h2); + src += 16; + } + c->h1 = h1; + c->h2 = h2; + + len &= 15; + if (len > 0) { + memcpy(c->state, src, len); + c->state_pos = len; + } +} + +static inline uint64_t fmix(uint64_t k) +{ + k ^= k >> 33; + k *= UINT64_C(0xff51afd7ed558ccd); + k ^= k >> 33; + k *= UINT64_C(0xc4ceb9fe1a85ec53); + k ^= k >> 33; + return k; +} + +void av_murmur3_final(AVMurMur3 *c, uint8_t dst[16]) +{ + uint64_t h1 = c->h1, h2 = c->h2; + memset(c->state + c->state_pos, 0, sizeof(c->state) - c->state_pos); + h1 ^= get_k1(c->state) ^ c->len; + h2 ^= get_k2(c->state) ^ c->len; + h1 += h2; + h2 += h1; + h1 = fmix(h1); + h2 = fmix(h2); + h1 += h2; + h2 += h1; + AV_WL64(dst, h1); + AV_WL64(dst + 8, h2); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/murmur3.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/murmur3.h new file mode 100644 index 0000000000..1b09175c1e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/murmur3.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2013 Reimar D枚ffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_murmur3 + * Public header for MurmurHash3 hash function implementation. + */ + +#ifndef AVUTIL_MURMUR3_H +#define AVUTIL_MURMUR3_H + +#include + +#include "version.h" + +/** + * @defgroup lavu_murmur3 Murmur3 + * @ingroup lavu_hash + * MurmurHash3 hash function implementation. + * + * MurmurHash3 is a non-cryptographic hash function, of which three + * incompatible versions were created by its inventor Austin Appleby: + * + * - 32-bit output + * - 128-bit output for 32-bit platforms + * - 128-bit output for 64-bit platforms + * + * FFmpeg only implements the last variant: 128-bit output designed for 64-bit + * platforms. Even though the hash function was designed for 64-bit platforms, + * the function in reality works on 32-bit systems too, only with reduced + * performance. + * + * @anchor lavu_murmur3_seedinfo + * By design, MurmurHash3 requires a seed to operate. In response to this, + * libavutil provides two functions for hash initiation, one that requires a + * seed (av_murmur3_init_seeded()) and one that uses a fixed arbitrary integer + * as the seed, and therefore does not (av_murmur3_init()). + * + * To make hashes comparable, you should provide the same seed for all calls to + * this hash function -- if you are supplying one yourself, that is. + * + * @{ + */ + +/** + * Allocate an AVMurMur3 hash context. + * + * @return Uninitialized hash context or `NULL` in case of error + */ +struct AVMurMur3 *av_murmur3_alloc(void); + +/** + * Initialize or reinitialize an AVMurMur3 hash context with a seed. + * + * @param[out] c Hash context + * @param[in] seed Random seed + * + * @see av_murmur3_init() + * @see @ref lavu_murmur3_seedinfo "Detailed description" on a discussion of + * seeds for MurmurHash3. + */ +void av_murmur3_init_seeded(struct AVMurMur3 *c, uint64_t seed); + +/** + * Initialize or reinitialize an AVMurMur3 hash context. + * + * Equivalent to av_murmur3_init_seeded() with a built-in seed. + * + * @param[out] c Hash context + * + * @see av_murmur3_init_seeded() + * @see @ref lavu_murmur3_seedinfo "Detailed description" on a discussion of + * seeds for MurmurHash3. + */ +void av_murmur3_init(struct AVMurMur3 *c); + +/** + * Update hash context with new data. + * + * @param[out] c Hash context + * @param[in] src Input data to update hash with + * @param[in] len Number of bytes to read from `src` + */ +#if FF_API_CRYPTO_SIZE_T +void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, int len); +#else +void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, size_t len); +#endif + +/** + * Finish hashing and output digest value. + * + * @param[in,out] c Hash context + * @param[out] dst Buffer where output digest value is stored + */ +void av_murmur3_final(struct AVMurMur3 *c, uint8_t dst[16]); + +/** + * @} + */ + +#endif /* AVUTIL_MURMUR3_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/opt.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/opt.c new file mode 100644 index 0000000000..93d6c26c11 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/opt.c @@ -0,0 +1,2039 @@ +/* + * AVOptions + * Copyright (c) 2005 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AVOptions + * @author Michael Niedermayer + */ + +#include "avutil.h" +#include "avassert.h" +#include "avstring.h" +#include "channel_layout.h" +#include "common.h" +#include "dict.h" +#include "eval.h" +#include "log.h" +#include "parseutils.h" +#include "pixdesc.h" +#include "mathematics.h" +#include "opt.h" +#include "samplefmt.h" +#include "bprint.h" + +#include + +const AVOption *av_opt_next(const void *obj, const AVOption *last) +{ + const AVClass *class; + if (!obj) + return NULL; + class = *(const AVClass**)obj; + if (!last && class && class->option && class->option[0].name) + return class->option; + if (last && last[1].name) + return ++last; + return NULL; +} + +static int read_number(const AVOption *o, const void *dst, double *num, int *den, int64_t *intnum) +{ + switch (o->type) { + case AV_OPT_TYPE_FLAGS: + *intnum = *(unsigned int*)dst; + return 0; + case AV_OPT_TYPE_PIXEL_FMT: + *intnum = *(enum AVPixelFormat *)dst; + return 0; + case AV_OPT_TYPE_SAMPLE_FMT: + *intnum = *(enum AVSampleFormat *)dst; + return 0; + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_INT: + *intnum = *(int *)dst; + return 0; + case AV_OPT_TYPE_CHANNEL_LAYOUT: + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + *intnum = *(int64_t *)dst; + return 0; + case AV_OPT_TYPE_FLOAT: + *num = *(float *)dst; + return 0; + case AV_OPT_TYPE_DOUBLE: + *num = *(double *)dst; + return 0; + case AV_OPT_TYPE_RATIONAL: + *intnum = ((AVRational *)dst)->num; + *den = ((AVRational *)dst)->den; + return 0; + case AV_OPT_TYPE_CONST: + *num = o->default_val.dbl; + return 0; + } + return AVERROR(EINVAL); +} + +static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum) +{ + if (o->type != AV_OPT_TYPE_FLAGS && + (!den || o->max * den < num * intnum || o->min * den > num * intnum)) { + num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN); + av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", + num, o->name, o->min, o->max); + return AVERROR(ERANGE); + } + if (o->type == AV_OPT_TYPE_FLAGS) { + double d = num*intnum/den; + if (d < -1.5 || d > 0xFFFFFFFF+0.5 || (llrint(d*256) & 255)) { + av_log(obj, AV_LOG_ERROR, + "Value %f for parameter '%s' is not a valid set of 32bit integer flags\n", + num*intnum/den, o->name); + return AVERROR(ERANGE); + } + } + + switch (o->type) { + case AV_OPT_TYPE_PIXEL_FMT: + *(enum AVPixelFormat *)dst = llrint(num / den) * intnum; + break; + case AV_OPT_TYPE_SAMPLE_FMT: + *(enum AVSampleFormat *)dst = llrint(num / den) * intnum; + break; + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_INT: + *(int *)dst = llrint(num / den) * intnum; + break; + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_CHANNEL_LAYOUT: + case AV_OPT_TYPE_INT64:{ + double d = num / den; + if (intnum == 1 && d == (double)INT64_MAX) { + *(int64_t *)dst = INT64_MAX; + } else + *(int64_t *)dst = llrint(d) * intnum; + break;} + case AV_OPT_TYPE_UINT64:{ + double d = num / den; + // We must special case uint64_t here as llrint() does not support values + // outside the int64_t range and there is no portable function which does + // "INT64_MAX + 1ULL" is used as it is representable exactly as IEEE double + // while INT64_MAX is not + if (intnum == 1 && d == (double)UINT64_MAX) { + *(uint64_t *)dst = UINT64_MAX; + } else if (d > INT64_MAX + 1ULL) { + *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum; + } else { + *(uint64_t *)dst = llrint(d) * intnum; + } + break;} + case AV_OPT_TYPE_FLOAT: + *(float *)dst = num * intnum / den; + break; + case AV_OPT_TYPE_DOUBLE: + *(double *)dst = num * intnum / den; + break; + case AV_OPT_TYPE_RATIONAL: + case AV_OPT_TYPE_VIDEO_RATE: + if ((int) num == num) + *(AVRational *)dst = (AVRational) { num *intnum, den }; + else + *(AVRational *)dst = av_d2q(num * intnum / den, 1 << 24); + break; + default: + return AVERROR(EINVAL); + } + return 0; +} + +static int hexchar2int(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +static int set_string_binary(void *obj, const AVOption *o, const char *val, uint8_t **dst) +{ + int *lendst = (int *)(dst + 1); + uint8_t *bin, *ptr; + int len; + + av_freep(dst); + *lendst = 0; + + if (!val || !(len = strlen(val))) + return 0; + + if (len & 1) + return AVERROR(EINVAL); + len /= 2; + + ptr = bin = av_malloc(len); + if (!ptr) + return AVERROR(ENOMEM); + while (*val) { + int a = hexchar2int(*val++); + int b = hexchar2int(*val++); + if (a < 0 || b < 0) { + av_free(bin); + return AVERROR(EINVAL); + } + *ptr++ = (a << 4) | b; + } + *dst = bin; + *lendst = len; + + return 0; +} + +static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **dst) +{ + av_freep(dst); + *dst = av_strdup(val); + return *dst ? 0 : AVERROR(ENOMEM); +} + +#define DEFAULT_NUMVAL(opt) ((opt->type == AV_OPT_TYPE_INT64 || \ + opt->type == AV_OPT_TYPE_UINT64 || \ + opt->type == AV_OPT_TYPE_CONST || \ + opt->type == AV_OPT_TYPE_FLAGS || \ + opt->type == AV_OPT_TYPE_INT) \ + ? opt->default_val.i64 \ + : opt->default_val.dbl) + +static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst) +{ + int ret = 0; + int num, den; + char c; + + if (sscanf(val, "%d%*1[:/]%d%c", &num, &den, &c) == 2) { + if ((ret = write_number(obj, o, dst, 1, den, num)) >= 0) + return ret; + ret = 0; + } + + for (;;) { + int i = 0; + char buf[256]; + int cmd = 0; + double d; + int64_t intnum = 1; + + if (o->type == AV_OPT_TYPE_FLAGS) { + if (*val == '+' || *val == '-') + cmd = *(val++); + for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++) + buf[i] = val[i]; + buf[i] = 0; + } + + { + const AVOption *o_named = av_opt_find(target_obj, i ? buf : val, o->unit, 0, 0); + int res; + int ci = 0; + double const_values[64]; + const char * const_names[64]; + if (o_named && o_named->type == AV_OPT_TYPE_CONST) + d = DEFAULT_NUMVAL(o_named); + else { + if (o->unit) { + for (o_named = NULL; o_named = av_opt_next(target_obj, o_named); ) { + if (o_named->type == AV_OPT_TYPE_CONST && + o_named->unit && + !strcmp(o_named->unit, o->unit)) { + if (ci + 6 >= FF_ARRAY_ELEMS(const_values)) { + av_log(obj, AV_LOG_ERROR, "const_values array too small for %s\n", o->unit); + return AVERROR_PATCHWELCOME; + } + const_names [ci ] = o_named->name; + const_values[ci++] = DEFAULT_NUMVAL(o_named); + } + } + } + const_names [ci ] = "default"; + const_values[ci++] = DEFAULT_NUMVAL(o); + const_names [ci ] = "max"; + const_values[ci++] = o->max; + const_names [ci ] = "min"; + const_values[ci++] = o->min; + const_names [ci ] = "none"; + const_values[ci++] = 0; + const_names [ci ] = "all"; + const_values[ci++] = ~0; + const_names [ci] = NULL; + const_values[ci] = 0; + + res = av_expr_parse_and_eval(&d, i ? buf : val, const_names, + const_values, NULL, NULL, NULL, NULL, NULL, 0, obj); + if (res < 0) { + av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\"\n", val); + return res; + } + } + } + if (o->type == AV_OPT_TYPE_FLAGS) { + read_number(o, dst, NULL, NULL, &intnum); + if (cmd == '+') + d = intnum | (int64_t)d; + else if (cmd == '-') + d = intnum &~(int64_t)d; + } + + if ((ret = write_number(obj, o, dst, d, 1, 1)) < 0) + return ret; + val += i; + if (!i || !*val) + return 0; + } +} + +static int set_string_image_size(void *obj, const AVOption *o, const char *val, int *dst) +{ + int ret; + + if (!val || !strcmp(val, "none")) { + dst[0] = + dst[1] = 0; + return 0; + } + ret = av_parse_video_size(dst, dst + 1, val); + if (ret < 0) + av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as image size\n", val); + return ret; +} + +static int set_string_video_rate(void *obj, const AVOption *o, const char *val, AVRational *dst) +{ + int ret; + if (!val) { + ret = AVERROR(EINVAL); + } else { + ret = av_parse_video_rate(dst, val); + } + if (ret < 0) + av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as video rate\n", val); + return ret; +} + +static int set_string_color(void *obj, const AVOption *o, const char *val, uint8_t *dst) +{ + int ret; + + if (!val) { + return 0; + } else { + ret = av_parse_color(dst, val, -1, obj); + if (ret < 0) + av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as color\n", val); + return ret; + } + return 0; +} + +static const char *get_bool_name(int val) +{ + if (val < 0) + return "auto"; + return val ? "true" : "false"; +} + +static int set_string_bool(void *obj, const AVOption *o, const char *val, int *dst) +{ + int n; + + if (!val) + return 0; + + if (!strcmp(val, "auto")) { + n = -1; + } else if (av_match_name(val, "true,y,yes,enable,enabled,on")) { + n = 1; + } else if (av_match_name(val, "false,n,no,disable,disabled,off")) { + n = 0; + } else { + char *end = NULL; + n = strtol(val, &end, 10); + if (val + strlen(val) != end) + goto fail; + } + + if (n < o->min || n > o->max) + goto fail; + + *dst = n; + return 0; + +fail: + av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as boolean\n", val); + return AVERROR(EINVAL); +} + +static int set_string_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst, + int fmt_nb, int ((*get_fmt)(const char *)), const char *desc) +{ + int fmt, min, max; + + if (!val || !strcmp(val, "none")) { + fmt = -1; + } else { + fmt = get_fmt(val); + if (fmt == -1) { + char *tail; + fmt = strtol(val, &tail, 0); + if (*tail || (unsigned)fmt >= fmt_nb) { + av_log(obj, AV_LOG_ERROR, + "Unable to parse option value \"%s\" as %s\n", val, desc); + return AVERROR(EINVAL); + } + } + } + + min = FFMAX(o->min, -1); + max = FFMIN(o->max, fmt_nb-1); + + // hack for compatibility with old ffmpeg + if(min == 0 && max == 0) { + min = -1; + max = fmt_nb-1; + } + + if (fmt < min || fmt > max) { + av_log(obj, AV_LOG_ERROR, + "Value %d for parameter '%s' out of %s format range [%d - %d]\n", + fmt, o->name, desc, min, max); + return AVERROR(ERANGE); + } + + *(int *)dst = fmt; + return 0; +} + +static int set_string_pixel_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst) +{ + return set_string_fmt(obj, o, val, dst, + AV_PIX_FMT_NB, av_get_pix_fmt, "pixel format"); +} + +static int set_string_sample_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst) +{ + return set_string_fmt(obj, o, val, dst, + AV_SAMPLE_FMT_NB, av_get_sample_fmt, "sample format"); +} + +int av_opt_set(void *obj, const char *name, const char *val, int search_flags) +{ + int ret = 0; + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (!val && (o->type != AV_OPT_TYPE_STRING && + o->type != AV_OPT_TYPE_PIXEL_FMT && o->type != AV_OPT_TYPE_SAMPLE_FMT && + o->type != AV_OPT_TYPE_IMAGE_SIZE && o->type != AV_OPT_TYPE_VIDEO_RATE && + o->type != AV_OPT_TYPE_DURATION && o->type != AV_OPT_TYPE_COLOR && + o->type != AV_OPT_TYPE_CHANNEL_LAYOUT && o->type != AV_OPT_TYPE_BOOL)) + return AVERROR(EINVAL); + + if (o->flags & AV_OPT_FLAG_READONLY) + return AVERROR(EINVAL); + + if (o->flags & AV_OPT_FLAG_DEPRECATED) + av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); + + dst = ((uint8_t *)target_obj) + o->offset; + switch (o->type) { + case AV_OPT_TYPE_BOOL: + return set_string_bool(obj, o, val, dst); + case AV_OPT_TYPE_STRING: + return set_string(obj, o, val, dst); + case AV_OPT_TYPE_BINARY: + return set_string_binary(obj, o, val, dst); + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_FLOAT: + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_RATIONAL: + return set_string_number(obj, target_obj, o, val, dst); + case AV_OPT_TYPE_IMAGE_SIZE: + return set_string_image_size(obj, o, val, dst); + case AV_OPT_TYPE_VIDEO_RATE: { + AVRational tmp; + ret = set_string_video_rate(obj, o, val, &tmp); + if (ret < 0) + return ret; + return write_number(obj, o, dst, 1, tmp.den, tmp.num); + } + case AV_OPT_TYPE_PIXEL_FMT: + return set_string_pixel_fmt(obj, o, val, dst); + case AV_OPT_TYPE_SAMPLE_FMT: + return set_string_sample_fmt(obj, o, val, dst); + case AV_OPT_TYPE_DURATION: + { + int64_t usecs = 0; + if (val) { + if ((ret = av_parse_time(&usecs, val, 1)) < 0) { + av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as duration\n", val); + return ret; + } + } + if (usecs < o->min || usecs > o->max) { + av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", + usecs / 1000000.0, o->name, o->min / 1000000.0, o->max / 1000000.0); + return AVERROR(ERANGE); + } + *(int64_t *)dst = usecs; + return 0; + } + case AV_OPT_TYPE_COLOR: + return set_string_color(obj, o, val, dst); + case AV_OPT_TYPE_CHANNEL_LAYOUT: + if (!val || !strcmp(val, "none")) { + *(int64_t *)dst = 0; + } else { + int64_t cl = av_get_channel_layout(val); + if (!cl) { + av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as channel layout\n", val); + ret = AVERROR(EINVAL); + } + *(int64_t *)dst = cl; + return ret; + } + break; + } + + av_log(obj, AV_LOG_ERROR, "Invalid option type.\n"); + return AVERROR(EINVAL); +} + +#define OPT_EVAL_NUMBER(name, opttype, vartype) \ +int av_opt_eval_ ## name(void *obj, const AVOption *o, \ + const char *val, vartype *name ## _out) \ +{ \ + if (!o || o->type != opttype || o->flags & AV_OPT_FLAG_READONLY) \ + return AVERROR(EINVAL); \ + return set_string_number(obj, obj, o, val, name ## _out); \ +} + +OPT_EVAL_NUMBER(flags, AV_OPT_TYPE_FLAGS, int) +OPT_EVAL_NUMBER(int, AV_OPT_TYPE_INT, int) +OPT_EVAL_NUMBER(int64, AV_OPT_TYPE_INT64, int64_t) +OPT_EVAL_NUMBER(float, AV_OPT_TYPE_FLOAT, float) +OPT_EVAL_NUMBER(double, AV_OPT_TYPE_DOUBLE, double) +OPT_EVAL_NUMBER(q, AV_OPT_TYPE_RATIONAL, AVRational) + +static int set_number(void *obj, const char *name, double num, int den, int64_t intnum, + int search_flags) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + + if (o->flags & AV_OPT_FLAG_READONLY) + return AVERROR(EINVAL); + + dst = ((uint8_t *)target_obj) + o->offset; + return write_number(obj, o, dst, num, den, intnum); +} + +int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags) +{ + return set_number(obj, name, 1, 1, val, search_flags); +} + +int av_opt_set_double(void *obj, const char *name, double val, int search_flags) +{ + return set_number(obj, name, val, 1, 1, search_flags); +} + +int av_opt_set_q(void *obj, const char *name, AVRational val, int search_flags) +{ + return set_number(obj, name, val.num, val.den, 1, search_flags); +} + +int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int search_flags) +{ + void *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + uint8_t *ptr; + uint8_t **dst; + int *lendst; + + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + + if (o->type != AV_OPT_TYPE_BINARY || o->flags & AV_OPT_FLAG_READONLY) + return AVERROR(EINVAL); + + ptr = len ? av_malloc(len) : NULL; + if (len && !ptr) + return AVERROR(ENOMEM); + + dst = (uint8_t **)(((uint8_t *)target_obj) + o->offset); + lendst = (int *)(dst + 1); + + av_free(*dst); + *dst = ptr; + *lendst = len; + if (len) + memcpy(ptr, val, len); + + return 0; +} + +int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags) +{ + void *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != AV_OPT_TYPE_IMAGE_SIZE) { + av_log(obj, AV_LOG_ERROR, + "The value set by option '%s' is not an image size.\n", o->name); + return AVERROR(EINVAL); + } + if (w<0 || h<0) { + av_log(obj, AV_LOG_ERROR, + "Invalid negative size value %dx%d for size '%s'\n", w, h, o->name); + return AVERROR(EINVAL); + } + *(int *)(((uint8_t *)target_obj) + o->offset) = w; + *(int *)(((uint8_t *)target_obj+sizeof(int)) + o->offset) = h; + return 0; +} + +int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags) +{ + void *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != AV_OPT_TYPE_VIDEO_RATE) { + av_log(obj, AV_LOG_ERROR, + "The value set by option '%s' is not a video rate.\n", o->name); + return AVERROR(EINVAL); + } + if (val.num <= 0 || val.den <= 0) + return AVERROR(EINVAL); + return set_number(obj, name, val.num, val.den, 1, search_flags); +} + +static int set_format(void *obj, const char *name, int fmt, int search_flags, + enum AVOptionType type, const char *desc, int nb_fmts) +{ + void *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, + search_flags, &target_obj); + int min, max; + + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != type) { + av_log(obj, AV_LOG_ERROR, + "The value set by option '%s' is not a %s format", name, desc); + return AVERROR(EINVAL); + } + + min = FFMAX(o->min, -1); + max = FFMIN(o->max, nb_fmts-1); + + if (fmt < min || fmt > max) { + av_log(obj, AV_LOG_ERROR, + "Value %d for parameter '%s' out of %s format range [%d - %d]\n", + fmt, name, desc, min, max); + return AVERROR(ERANGE); + } + *(int *)(((uint8_t *)target_obj) + o->offset) = fmt; + return 0; +} + +int av_opt_set_pixel_fmt(void *obj, const char *name, enum AVPixelFormat fmt, int search_flags) +{ + return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_PIXEL_FMT, "pixel", AV_PIX_FMT_NB); +} + +int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags) +{ + return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_SAMPLE_FMT, "sample", AV_SAMPLE_FMT_NB); +} + +int av_opt_set_channel_layout(void *obj, const char *name, int64_t cl, int search_flags) +{ + void *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != AV_OPT_TYPE_CHANNEL_LAYOUT) { + av_log(obj, AV_LOG_ERROR, + "The value set by option '%s' is not a channel layout.\n", o->name); + return AVERROR(EINVAL); + } + *(int64_t *)(((uint8_t *)target_obj) + o->offset) = cl; + return 0; +} + +int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, + int search_flags) +{ + void *target_obj; + AVDictionary **dst; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->flags & AV_OPT_FLAG_READONLY) + return AVERROR(EINVAL); + + dst = (AVDictionary **)(((uint8_t *)target_obj) + o->offset); + av_dict_free(dst); + av_dict_copy(dst, val, 0); + + return 0; +} + +static void format_duration(char *buf, size_t size, int64_t d) +{ + char *e; + + av_assert0(size >= 25); + if (d < 0 && d != INT64_MIN) { + *(buf++) = '-'; + size--; + d = -d; + } + if (d == INT64_MAX) + snprintf(buf, size, "INT64_MAX"); + else if (d == INT64_MIN) + snprintf(buf, size, "INT64_MIN"); + else if (d > (int64_t)3600*1000000) + snprintf(buf, size, "%"PRId64":%02d:%02d.%06d", d / 3600000000, + (int)((d / 60000000) % 60), + (int)((d / 1000000) % 60), + (int)(d % 1000000)); + else if (d > 60*1000000) + snprintf(buf, size, "%d:%02d.%06d", + (int)(d / 60000000), + (int)((d / 1000000) % 60), + (int)(d % 1000000)); + else + snprintf(buf, size, "%d.%06d", + (int)(d / 1000000), + (int)(d % 1000000)); + e = buf + strlen(buf); + while (e > buf && e[-1] == '0') + *(--e) = 0; + if (e > buf && e[-1] == '.') + *(--e) = 0; +} + +int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + uint8_t *bin, buf[128]; + int len, i, ret; + int64_t i64; + + if (!o || !target_obj || (o->offset<=0 && o->type != AV_OPT_TYPE_CONST)) + return AVERROR_OPTION_NOT_FOUND; + + if (o->flags & AV_OPT_FLAG_DEPRECATED) + av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); + + dst = (uint8_t *)target_obj + o->offset; + + buf[0] = 0; + switch (o->type) { + case AV_OPT_TYPE_BOOL: + ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(get_bool_name(*(int *)dst), "invalid")); + break; + case AV_OPT_TYPE_FLAGS: + ret = snprintf(buf, sizeof(buf), "0x%08X", *(int *)dst); + break; + case AV_OPT_TYPE_INT: + ret = snprintf(buf, sizeof(buf), "%d", *(int *)dst); + break; + case AV_OPT_TYPE_INT64: + ret = snprintf(buf, sizeof(buf), "%"PRId64, *(int64_t *)dst); + break; + case AV_OPT_TYPE_UINT64: + ret = snprintf(buf, sizeof(buf), "%"PRIu64, *(uint64_t *)dst); + break; + case AV_OPT_TYPE_FLOAT: + ret = snprintf(buf, sizeof(buf), "%f", *(float *)dst); + break; + case AV_OPT_TYPE_DOUBLE: + ret = snprintf(buf, sizeof(buf), "%f", *(double *)dst); + break; + case AV_OPT_TYPE_VIDEO_RATE: + case AV_OPT_TYPE_RATIONAL: + ret = snprintf(buf, sizeof(buf), "%d/%d", ((AVRational *)dst)->num, ((AVRational *)dst)->den); + break; + case AV_OPT_TYPE_CONST: + ret = snprintf(buf, sizeof(buf), "%f", o->default_val.dbl); + break; + case AV_OPT_TYPE_STRING: + if (*(uint8_t **)dst) { + *out_val = av_strdup(*(uint8_t **)dst); + } else if (search_flags & AV_OPT_ALLOW_NULL) { + *out_val = NULL; + return 0; + } else { + *out_val = av_strdup(""); + } + return *out_val ? 0 : AVERROR(ENOMEM); + case AV_OPT_TYPE_BINARY: + if (!*(uint8_t **)dst && (search_flags & AV_OPT_ALLOW_NULL)) { + *out_val = NULL; + return 0; + } + len = *(int *)(((uint8_t *)dst) + sizeof(uint8_t *)); + if ((uint64_t)len * 2 + 1 > INT_MAX) + return AVERROR(EINVAL); + if (!(*out_val = av_malloc(len * 2 + 1))) + return AVERROR(ENOMEM); + if (!len) { + *out_val[0] = '\0'; + return 0; + } + bin = *(uint8_t **)dst; + for (i = 0; i < len; i++) + snprintf(*out_val + i * 2, 3, "%02X", bin[i]); + return 0; + case AV_OPT_TYPE_IMAGE_SIZE: + ret = snprintf(buf, sizeof(buf), "%dx%d", ((int *)dst)[0], ((int *)dst)[1]); + break; + case AV_OPT_TYPE_PIXEL_FMT: + ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(av_get_pix_fmt_name(*(enum AVPixelFormat *)dst), "none")); + break; + case AV_OPT_TYPE_SAMPLE_FMT: + ret = snprintf(buf, sizeof(buf), "%s", (char *)av_x_if_null(av_get_sample_fmt_name(*(enum AVSampleFormat *)dst), "none")); + break; + case AV_OPT_TYPE_DURATION: + i64 = *(int64_t *)dst; + format_duration(buf, sizeof(buf), i64); + ret = strlen(buf); // no overflow possible, checked by an assert + break; + case AV_OPT_TYPE_COLOR: + ret = snprintf(buf, sizeof(buf), "0x%02x%02x%02x%02x", + (int)((uint8_t *)dst)[0], (int)((uint8_t *)dst)[1], + (int)((uint8_t *)dst)[2], (int)((uint8_t *)dst)[3]); + break; + case AV_OPT_TYPE_CHANNEL_LAYOUT: + i64 = *(int64_t *)dst; + ret = snprintf(buf, sizeof(buf), "0x%"PRIx64, i64); + break; + default: + return AVERROR(EINVAL); + } + + if (ret >= sizeof(buf)) + return AVERROR(EINVAL); + *out_val = av_strdup(buf); + return *out_val ? 0 : AVERROR(ENOMEM); +} + +static int get_number(void *obj, const char *name, const AVOption **o_out, double *num, int *den, int64_t *intnum, + int search_flags) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + goto error; + + dst = ((uint8_t *)target_obj) + o->offset; + + if (o_out) *o_out= o; + + return read_number(o, dst, num, den, intnum); + +error: + *den = + *intnum = 0; + return -1; +} + +int av_opt_get_int(void *obj, const char *name, int search_flags, int64_t *out_val) +{ + int64_t intnum = 1; + double num = 1; + int ret, den = 1; + + if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0) + return ret; + *out_val = num * intnum / den; + return 0; +} + +int av_opt_get_double(void *obj, const char *name, int search_flags, double *out_val) +{ + int64_t intnum = 1; + double num = 1; + int ret, den = 1; + + if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0) + return ret; + *out_val = num * intnum / den; + return 0; +} + +int av_opt_get_q(void *obj, const char *name, int search_flags, AVRational *out_val) +{ + int64_t intnum = 1; + double num = 1; + int ret, den = 1; + + if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0) + return ret; + + if (num == 1.0 && (int)intnum == intnum) + *out_val = (AVRational){intnum, den}; + else + *out_val = av_d2q(num*intnum/den, 1<<24); + return 0; +} + +int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != AV_OPT_TYPE_IMAGE_SIZE) { + av_log(obj, AV_LOG_ERROR, + "The value for option '%s' is not an image size.\n", name); + return AVERROR(EINVAL); + } + + dst = ((uint8_t*)target_obj) + o->offset; + if (w_out) *w_out = *(int *)dst; + if (h_out) *h_out = *((int *)dst+1); + return 0; +} + +int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val) +{ + int64_t intnum = 1; + double num = 1; + int ret, den = 1; + + if ((ret = get_number(obj, name, NULL, &num, &den, &intnum, search_flags)) < 0) + return ret; + + if (num == 1.0 && (int)intnum == intnum) + *out_val = (AVRational) { intnum, den }; + else + *out_val = av_d2q(num * intnum / den, 1 << 24); + return 0; +} + +static int get_format(void *obj, const char *name, int search_flags, int *out_fmt, + enum AVOptionType type, const char *desc) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != type) { + av_log(obj, AV_LOG_ERROR, + "The value for option '%s' is not a %s format.\n", desc, name); + return AVERROR(EINVAL); + } + + dst = ((uint8_t*)target_obj) + o->offset; + *out_fmt = *(int *)dst; + return 0; +} + +int av_opt_get_pixel_fmt(void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt) +{ + return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_PIXEL_FMT, "pixel"); +} + +int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt) +{ + return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_SAMPLE_FMT, "sample"); +} + +int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *cl) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != AV_OPT_TYPE_CHANNEL_LAYOUT) { + av_log(obj, AV_LOG_ERROR, + "The value for option '%s' is not a channel layout.\n", name); + return AVERROR(EINVAL); + } + + dst = ((uint8_t*)target_obj) + o->offset; + *cl = *(int64_t *)dst; + return 0; +} + +int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val) +{ + void *target_obj; + AVDictionary *src; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != AV_OPT_TYPE_DICT) + return AVERROR(EINVAL); + + src = *(AVDictionary **)(((uint8_t *)target_obj) + o->offset); + av_dict_copy(out_val, src, 0); + + return 0; +} + +int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name) +{ + const AVOption *field = av_opt_find(obj, field_name, NULL, 0, 0); + const AVOption *flag = av_opt_find(obj, flag_name, + field ? field->unit : NULL, 0, 0); + int64_t res; + + if (!field || !flag || flag->type != AV_OPT_TYPE_CONST || + av_opt_get_int(obj, field_name, 0, &res) < 0) + return 0; + return res & flag->default_val.i64; +} + +static void log_value(void *av_log_obj, int level, double d) +{ + if (d == INT_MAX) { + av_log(av_log_obj, level, "INT_MAX"); + } else if (d == INT_MIN) { + av_log(av_log_obj, level, "INT_MIN"); + } else if (d == UINT32_MAX) { + av_log(av_log_obj, level, "UINT32_MAX"); + } else if (d == (double)INT64_MAX) { + av_log(av_log_obj, level, "I64_MAX"); + } else if (d == INT64_MIN) { + av_log(av_log_obj, level, "I64_MIN"); + } else if (d == FLT_MAX) { + av_log(av_log_obj, level, "FLT_MAX"); + } else if (d == FLT_MIN) { + av_log(av_log_obj, level, "FLT_MIN"); + } else if (d == -FLT_MAX) { + av_log(av_log_obj, level, "-FLT_MAX"); + } else if (d == -FLT_MIN) { + av_log(av_log_obj, level, "-FLT_MIN"); + } else if (d == DBL_MAX) { + av_log(av_log_obj, level, "DBL_MAX"); + } else if (d == DBL_MIN) { + av_log(av_log_obj, level, "DBL_MIN"); + } else if (d == -DBL_MAX) { + av_log(av_log_obj, level, "-DBL_MAX"); + } else if (d == -DBL_MIN) { + av_log(av_log_obj, level, "-DBL_MIN"); + } else { + av_log(av_log_obj, level, "%g", d); + } +} + +static const char *get_opt_const_name(void *obj, const char *unit, int64_t value) +{ + const AVOption *opt = NULL; + + if (!unit) + return NULL; + while ((opt = av_opt_next(obj, opt))) + if (opt->type == AV_OPT_TYPE_CONST && !strcmp(opt->unit, unit) && + opt->default_val.i64 == value) + return opt->name; + return NULL; +} + +static char *get_opt_flags_string(void *obj, const char *unit, int64_t value) +{ + const AVOption *opt = NULL; + char flags[512]; + + flags[0] = 0; + if (!unit) + return NULL; + while ((opt = av_opt_next(obj, opt))) { + if (opt->type == AV_OPT_TYPE_CONST && !strcmp(opt->unit, unit) && + opt->default_val.i64 & value) { + if (flags[0]) + av_strlcatf(flags, sizeof(flags), "+"); + av_strlcatf(flags, sizeof(flags), "%s", opt->name); + } + } + if (flags[0]) + return av_strdup(flags); + return NULL; +} + +static void opt_list(void *obj, void *av_log_obj, const char *unit, + int req_flags, int rej_flags) +{ + const AVOption *opt = NULL; + AVOptionRanges *r; + int i; + + while ((opt = av_opt_next(obj, opt))) { + if (!(opt->flags & req_flags) || (opt->flags & rej_flags)) + continue; + + /* Don't print CONST's on level one. + * Don't print anything but CONST's on level two. + * Only print items from the requested unit. + */ + if (!unit && opt->type == AV_OPT_TYPE_CONST) + continue; + else if (unit && opt->type != AV_OPT_TYPE_CONST) + continue; + else if (unit && opt->type == AV_OPT_TYPE_CONST && strcmp(unit, opt->unit)) + continue; + else if (unit && opt->type == AV_OPT_TYPE_CONST) + av_log(av_log_obj, AV_LOG_INFO, " %-15s ", opt->name); + else + av_log(av_log_obj, AV_LOG_INFO, " %s%-17s ", + (opt->flags & AV_OPT_FLAG_FILTERING_PARAM) ? "" : "-", + opt->name); + + switch (opt->type) { + case AV_OPT_TYPE_FLAGS: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_INT: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_INT64: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_UINT64: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_DOUBLE: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_FLOAT: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_STRING: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_RATIONAL: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_BINARY: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_IMAGE_SIZE: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_VIDEO_RATE: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_PIXEL_FMT: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_SAMPLE_FMT: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_DURATION: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_COLOR: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_CHANNEL_LAYOUT: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_BOOL: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + case AV_OPT_TYPE_CONST: + default: + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); + break; + } + av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_ENCODING_PARAM) ? 'E' : '.'); + av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_DECODING_PARAM) ? 'D' : '.'); + av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_FILTERING_PARAM)? 'F' : '.'); + av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_VIDEO_PARAM ) ? 'V' : '.'); + av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_AUDIO_PARAM ) ? 'A' : '.'); + av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_SUBTITLE_PARAM) ? 'S' : '.'); + av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_EXPORT) ? 'X' : '.'); + av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_READONLY) ? 'R' : '.'); + av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_BSF_PARAM) ? 'B' : '.'); + + if (opt->help) + av_log(av_log_obj, AV_LOG_INFO, " %s", opt->help); + + if (av_opt_query_ranges(&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) >= 0) { + switch (opt->type) { + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: + case AV_OPT_TYPE_RATIONAL: + for (i = 0; i < r->nb_ranges; i++) { + av_log(av_log_obj, AV_LOG_INFO, " (from "); + log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_min); + av_log(av_log_obj, AV_LOG_INFO, " to "); + log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_max); + av_log(av_log_obj, AV_LOG_INFO, ")"); + } + break; + } + av_opt_freep_ranges(&r); + } + + if (opt->type != AV_OPT_TYPE_CONST && + opt->type != AV_OPT_TYPE_BINARY && + !((opt->type == AV_OPT_TYPE_COLOR || + opt->type == AV_OPT_TYPE_IMAGE_SIZE || + opt->type == AV_OPT_TYPE_STRING || + opt->type == AV_OPT_TYPE_VIDEO_RATE) && + !opt->default_val.str)) { + av_log(av_log_obj, AV_LOG_INFO, " (default "); + switch (opt->type) { + case AV_OPT_TYPE_BOOL: + av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(get_bool_name(opt->default_val.i64), "invalid")); + break; + case AV_OPT_TYPE_FLAGS: { + char *def_flags = get_opt_flags_string(obj, opt->unit, opt->default_val.i64); + if (def_flags) { + av_log(av_log_obj, AV_LOG_INFO, "%s", def_flags); + av_freep(&def_flags); + } else { + av_log(av_log_obj, AV_LOG_INFO, "%"PRIX64, opt->default_val.i64); + } + break; + } + case AV_OPT_TYPE_DURATION: { + char buf[25]; + format_duration(buf, sizeof(buf), opt->default_val.i64); + av_log(av_log_obj, AV_LOG_INFO, "%s", buf); + break; + } + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_INT64: { + const char *def_const = get_opt_const_name(obj, opt->unit, opt->default_val.i64); + if (def_const) + av_log(av_log_obj, AV_LOG_INFO, "%s", def_const); + else + log_value(av_log_obj, AV_LOG_INFO, opt->default_val.i64); + break; + } + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: + log_value(av_log_obj, AV_LOG_INFO, opt->default_val.dbl); + break; + case AV_OPT_TYPE_RATIONAL: { + AVRational q = av_d2q(opt->default_val.dbl, INT_MAX); + av_log(av_log_obj, AV_LOG_INFO, "%d/%d", q.num, q.den); } + break; + case AV_OPT_TYPE_PIXEL_FMT: + av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_pix_fmt_name(opt->default_val.i64), "none")); + break; + case AV_OPT_TYPE_SAMPLE_FMT: + av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_sample_fmt_name(opt->default_val.i64), "none")); + break; + case AV_OPT_TYPE_COLOR: + case AV_OPT_TYPE_IMAGE_SIZE: + case AV_OPT_TYPE_STRING: + case AV_OPT_TYPE_VIDEO_RATE: + av_log(av_log_obj, AV_LOG_INFO, "\"%s\"", opt->default_val.str); + break; + case AV_OPT_TYPE_CHANNEL_LAYOUT: + av_log(av_log_obj, AV_LOG_INFO, "0x%"PRIx64, opt->default_val.i64); + break; + } + av_log(av_log_obj, AV_LOG_INFO, ")"); + } + + av_log(av_log_obj, AV_LOG_INFO, "\n"); + if (opt->unit && opt->type != AV_OPT_TYPE_CONST) + opt_list(obj, av_log_obj, opt->unit, req_flags, rej_flags); + } +} + +int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags) +{ + if (!obj) + return -1; + + av_log(av_log_obj, AV_LOG_INFO, "%s AVOptions:\n", (*(AVClass **)obj)->class_name); + + opt_list(obj, av_log_obj, NULL, req_flags, rej_flags); + + return 0; +} + +void av_opt_set_defaults(void *s) +{ + av_opt_set_defaults2(s, 0, 0); +} + +void av_opt_set_defaults2(void *s, int mask, int flags) +{ + const AVOption *opt = NULL; + while ((opt = av_opt_next(s, opt))) { + void *dst = ((uint8_t*)s) + opt->offset; + + if ((opt->flags & mask) != flags) + continue; + + if (opt->flags & AV_OPT_FLAG_READONLY) + continue; + + switch (opt->type) { + case AV_OPT_TYPE_CONST: + /* Nothing to be done here */ + break; + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_CHANNEL_LAYOUT: + case AV_OPT_TYPE_PIXEL_FMT: + case AV_OPT_TYPE_SAMPLE_FMT: + write_number(s, opt, dst, 1, 1, opt->default_val.i64); + break; + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: { + double val; + val = opt->default_val.dbl; + write_number(s, opt, dst, val, 1, 1); + } + break; + case AV_OPT_TYPE_RATIONAL: { + AVRational val; + val = av_d2q(opt->default_val.dbl, INT_MAX); + write_number(s, opt, dst, 1, val.den, val.num); + } + break; + case AV_OPT_TYPE_COLOR: + set_string_color(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_STRING: + set_string(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_IMAGE_SIZE: + set_string_image_size(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_VIDEO_RATE: + set_string_video_rate(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_BINARY: + set_string_binary(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_DICT: + /* Cannot set defaults for these types */ + break; + default: + av_log(s, AV_LOG_DEBUG, "AVOption type %d of option %s not implemented yet\n", + opt->type, opt->name); + } + } +} + +/** + * Store the value in the field in ctx that is named like key. + * ctx must be an AVClass context, storing is done using AVOptions. + * + * @param buf the string to parse, buf will be updated to point at the + * separator just after the parsed key/value pair + * @param key_val_sep a 0-terminated list of characters used to + * separate key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @return 0 if the key/value pair has been successfully parsed and + * set, or a negative value corresponding to an AVERROR code in case + * of error: + * AVERROR(EINVAL) if the key/value pair cannot be parsed, + * the error code issued by av_opt_set() if the key/value pair + * cannot be set + */ +static int parse_key_value_pair(void *ctx, const char **buf, + const char *key_val_sep, const char *pairs_sep) +{ + char *key = av_get_token(buf, key_val_sep); + char *val; + int ret; + + if (!key) + return AVERROR(ENOMEM); + + if (*key && strspn(*buf, key_val_sep)) { + (*buf)++; + val = av_get_token(buf, pairs_sep); + if (!val) { + av_freep(&key); + return AVERROR(ENOMEM); + } + } else { + av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key); + av_free(key); + return AVERROR(EINVAL); + } + + av_log(ctx, AV_LOG_DEBUG, "Setting entry with key '%s' to value '%s'\n", key, val); + + ret = av_opt_set(ctx, key, val, AV_OPT_SEARCH_CHILDREN); + if (ret == AVERROR_OPTION_NOT_FOUND) + av_log(ctx, AV_LOG_ERROR, "Key '%s' not found.\n", key); + + av_free(key); + av_free(val); + return ret; +} + +int av_set_options_string(void *ctx, const char *opts, + const char *key_val_sep, const char *pairs_sep) +{ + int ret, count = 0; + + if (!opts) + return 0; + + while (*opts) { + if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0) + return ret; + count++; + + if (*opts) + opts++; + } + + return count; +} + +#define WHITESPACES " \n\t\r" + +static int is_key_char(char c) +{ + return (unsigned)((c | 32) - 'a') < 26 || + (unsigned)(c - '0') < 10 || + c == '-' || c == '_' || c == '/' || c == '.'; +} + +/** + * Read a key from a string. + * + * The key consists of is_key_char characters and must be terminated by a + * character from the delim string; spaces are ignored. + * + * @return 0 for success (even with ellipsis), <0 for failure + */ +static int get_key(const char **ropts, const char *delim, char **rkey) +{ + const char *opts = *ropts; + const char *key_start, *key_end; + + key_start = opts += strspn(opts, WHITESPACES); + while (is_key_char(*opts)) + opts++; + key_end = opts; + opts += strspn(opts, WHITESPACES); + if (!*opts || !strchr(delim, *opts)) + return AVERROR(EINVAL); + opts++; + if (!(*rkey = av_malloc(key_end - key_start + 1))) + return AVERROR(ENOMEM); + memcpy(*rkey, key_start, key_end - key_start); + (*rkey)[key_end - key_start] = 0; + *ropts = opts; + return 0; +} + +int av_opt_get_key_value(const char **ropts, + const char *key_val_sep, const char *pairs_sep, + unsigned flags, + char **rkey, char **rval) +{ + int ret; + char *key = NULL, *val; + const char *opts = *ropts; + + if ((ret = get_key(&opts, key_val_sep, &key)) < 0 && + !(flags & AV_OPT_FLAG_IMPLICIT_KEY)) + return AVERROR(EINVAL); + if (!(val = av_get_token(&opts, pairs_sep))) { + av_free(key); + return AVERROR(ENOMEM); + } + *ropts = opts; + *rkey = key; + *rval = val; + return 0; +} + +int av_opt_set_from_string(void *ctx, const char *opts, + const char *const *shorthand, + const char *key_val_sep, const char *pairs_sep) +{ + int ret, count = 0; + const char *dummy_shorthand = NULL; + char *av_uninit(parsed_key), *av_uninit(value); + const char *key; + + if (!opts) + return 0; + if (!shorthand) + shorthand = &dummy_shorthand; + + while (*opts) { + ret = av_opt_get_key_value(&opts, key_val_sep, pairs_sep, + *shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0, + &parsed_key, &value); + if (ret < 0) { + if (ret == AVERROR(EINVAL)) + av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", opts); + else + av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", opts, + av_err2str(ret)); + return ret; + } + if (*opts) + opts++; + if (parsed_key) { + key = parsed_key; + while (*shorthand) /* discard all remaining shorthand */ + shorthand++; + } else { + key = *(shorthand++); + } + + av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value); + if ((ret = av_opt_set(ctx, key, value, 0)) < 0) { + if (ret == AVERROR_OPTION_NOT_FOUND) + av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key); + av_free(value); + av_free(parsed_key); + return ret; + } + + av_free(value); + av_free(parsed_key); + count++; + } + return count; +} + +void av_opt_free(void *obj) +{ + const AVOption *o = NULL; + while ((o = av_opt_next(obj, o))) { + switch (o->type) { + case AV_OPT_TYPE_STRING: + case AV_OPT_TYPE_BINARY: + av_freep((uint8_t *)obj + o->offset); + break; + + case AV_OPT_TYPE_DICT: + av_dict_free((AVDictionary **)(((uint8_t *)obj) + o->offset)); + break; + + default: + break; + } + } +} + +int av_opt_set_dict2(void *obj, AVDictionary **options, int search_flags) +{ + AVDictionaryEntry *t = NULL; + AVDictionary *tmp = NULL; + int ret = 0; + + if (!options) + return 0; + + while ((t = av_dict_get(*options, "", t, AV_DICT_IGNORE_SUFFIX))) { + ret = av_opt_set(obj, t->key, t->value, search_flags); + if (ret == AVERROR_OPTION_NOT_FOUND) + ret = av_dict_set(&tmp, t->key, t->value, 0); + if (ret < 0) { + av_log(obj, AV_LOG_ERROR, "Error setting option %s to value %s.\n", t->key, t->value); + av_dict_free(&tmp); + return ret; + } + ret = 0; + } + av_dict_free(options); + *options = tmp; + return ret; +} + +int av_opt_set_dict(void *obj, AVDictionary **options) +{ + return av_opt_set_dict2(obj, options, 0); +} + +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags) +{ + return av_opt_find2(obj, name, unit, opt_flags, search_flags, NULL); +} + +const AVOption *av_opt_find2(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags, void **target_obj) +{ + const AVClass *c; + const AVOption *o = NULL; + + if(!obj) + return NULL; + + c= *(AVClass**)obj; + + if (!c) + return NULL; + + if (search_flags & AV_OPT_SEARCH_CHILDREN) { + if (search_flags & AV_OPT_SEARCH_FAKE_OBJ) { + const AVClass *child = NULL; + while (child = av_opt_child_class_next(c, child)) + if (o = av_opt_find2(&child, name, unit, opt_flags, search_flags, NULL)) + return o; + } else { + void *child = NULL; + while (child = av_opt_child_next(obj, child)) + if (o = av_opt_find2(child, name, unit, opt_flags, search_flags, target_obj)) + return o; + } + } + + while (o = av_opt_next(obj, o)) { + if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags && + ((!unit && o->type != AV_OPT_TYPE_CONST) || + (unit && o->type == AV_OPT_TYPE_CONST && o->unit && !strcmp(o->unit, unit)))) { + if (target_obj) { + if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ)) + *target_obj = obj; + else + *target_obj = NULL; + } + return o; + } + } + return NULL; +} + +void *av_opt_child_next(void *obj, void *prev) +{ + const AVClass *c = *(AVClass **)obj; + if (c->child_next) + return c->child_next(obj, prev); + return NULL; +} + +const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev) +{ + if (parent->child_class_next) + return parent->child_class_next(prev); + return NULL; +} + +void *av_opt_ptr(const AVClass *class, void *obj, const char *name) +{ + const AVOption *opt= av_opt_find2(&class, name, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ, NULL); + if(!opt) + return NULL; + return (uint8_t*)obj + opt->offset; +} + +static int opt_size(enum AVOptionType type) +{ + switch(type) { + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_FLAGS: + return sizeof(int); + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_CHANNEL_LAYOUT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + return sizeof(int64_t); + case AV_OPT_TYPE_DOUBLE: + return sizeof(double); + case AV_OPT_TYPE_FLOAT: + return sizeof(float); + case AV_OPT_TYPE_STRING: + return sizeof(uint8_t*); + case AV_OPT_TYPE_VIDEO_RATE: + case AV_OPT_TYPE_RATIONAL: + return sizeof(AVRational); + case AV_OPT_TYPE_BINARY: + return sizeof(uint8_t*) + sizeof(int); + case AV_OPT_TYPE_IMAGE_SIZE: + return sizeof(int[2]); + case AV_OPT_TYPE_PIXEL_FMT: + return sizeof(enum AVPixelFormat); + case AV_OPT_TYPE_SAMPLE_FMT: + return sizeof(enum AVSampleFormat); + case AV_OPT_TYPE_COLOR: + return 4; + } + return AVERROR(EINVAL); +} + +int av_opt_copy(void *dst, const void *src) +{ + const AVOption *o = NULL; + const AVClass *c; + int ret = 0; + + if (!src) + return AVERROR(EINVAL); + + c = *(AVClass **)src; + if (!c || c != *(AVClass **)dst) + return AVERROR(EINVAL); + + while ((o = av_opt_next(src, o))) { + void *field_dst = (uint8_t *)dst + o->offset; + void *field_src = (uint8_t *)src + o->offset; + uint8_t **field_dst8 = (uint8_t **)field_dst; + uint8_t **field_src8 = (uint8_t **)field_src; + + if (o->type == AV_OPT_TYPE_STRING) { + if (*field_dst8 != *field_src8) + av_freep(field_dst8); + *field_dst8 = av_strdup(*field_src8); + if (*field_src8 && !*field_dst8) + ret = AVERROR(ENOMEM); + } else if (o->type == AV_OPT_TYPE_BINARY) { + int len = *(int *)(field_src8 + 1); + if (*field_dst8 != *field_src8) + av_freep(field_dst8); + *field_dst8 = av_memdup(*field_src8, len); + if (len && !*field_dst8) { + ret = AVERROR(ENOMEM); + len = 0; + } + *(int *)(field_dst8 + 1) = len; + } else if (o->type == AV_OPT_TYPE_CONST) { + // do nothing + } else if (o->type == AV_OPT_TYPE_DICT) { + AVDictionary **sdict = (AVDictionary **) field_src; + AVDictionary **ddict = (AVDictionary **) field_dst; + if (*sdict != *ddict) + av_dict_free(ddict); + *ddict = NULL; + av_dict_copy(ddict, *sdict, 0); + if (av_dict_count(*sdict) != av_dict_count(*ddict)) + ret = AVERROR(ENOMEM); + } else { + int size = opt_size(o->type); + if (size < 0) + ret = size; + else + memcpy(field_dst, field_src, size); + } + } + return ret; +} + +int av_opt_query_ranges(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags) +{ + int ret; + const AVClass *c = *(AVClass**)obj; + int (*callback)(AVOptionRanges **, void *obj, const char *key, int flags) = NULL; + + if (c->version > (52 << 16 | 11 << 8)) + callback = c->query_ranges; + + if (!callback) + callback = av_opt_query_ranges_default; + + ret = callback(ranges_arg, obj, key, flags); + if (ret >= 0) { + if (!(flags & AV_OPT_MULTI_COMPONENT_RANGE)) + ret = 1; + (*ranges_arg)->nb_components = ret; + } + return ret; +} + +int av_opt_query_ranges_default(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags) +{ + AVOptionRanges *ranges = av_mallocz(sizeof(*ranges)); + AVOptionRange **range_array = av_mallocz(sizeof(void*)); + AVOptionRange *range = av_mallocz(sizeof(*range)); + const AVOption *field = av_opt_find(obj, key, NULL, 0, flags); + int ret; + + *ranges_arg = NULL; + + if (!ranges || !range || !range_array || !field) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ranges->range = range_array; + ranges->range[0] = range; + ranges->nb_ranges = 1; + ranges->nb_components = 1; + range->is_range = 1; + range->value_min = field->min; + range->value_max = field->max; + + switch (field->type) { + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_PIXEL_FMT: + case AV_OPT_TYPE_SAMPLE_FMT: + case AV_OPT_TYPE_FLOAT: + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_COLOR: + case AV_OPT_TYPE_CHANNEL_LAYOUT: + break; + case AV_OPT_TYPE_STRING: + range->component_min = 0; + range->component_max = 0x10FFFF; // max unicode value + range->value_min = -1; + range->value_max = INT_MAX; + break; + case AV_OPT_TYPE_RATIONAL: + range->component_min = INT_MIN; + range->component_max = INT_MAX; + break; + case AV_OPT_TYPE_IMAGE_SIZE: + range->component_min = 0; + range->component_max = INT_MAX/128/8; + range->value_min = 0; + range->value_max = INT_MAX/8; + break; + case AV_OPT_TYPE_VIDEO_RATE: + range->component_min = 1; + range->component_max = INT_MAX; + range->value_min = 1; + range->value_max = INT_MAX; + break; + default: + ret = AVERROR(ENOSYS); + goto fail; + } + + *ranges_arg = ranges; + return 1; +fail: + av_free(ranges); + av_free(range); + av_free(range_array); + return ret; +} + +void av_opt_freep_ranges(AVOptionRanges **rangesp) +{ + int i; + AVOptionRanges *ranges = *rangesp; + + if (!ranges) + return; + + for (i = 0; i < ranges->nb_ranges * ranges->nb_components; i++) { + AVOptionRange *range = ranges->range[i]; + if (range) { + av_freep(&range->str); + av_freep(&ranges->range[i]); + } + } + av_freep(&ranges->range); + av_freep(rangesp); +} + +int av_opt_is_set_to_default(void *obj, const AVOption *o) +{ + int64_t i64; + double d, d2; + float f; + AVRational q; + int ret, w, h; + char *str; + void *dst; + + if (!o || !obj) + return AVERROR(EINVAL); + + dst = ((uint8_t*)obj) + o->offset; + + switch (o->type) { + case AV_OPT_TYPE_CONST: + return 1; + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_PIXEL_FMT: + case AV_OPT_TYPE_SAMPLE_FMT: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_CHANNEL_LAYOUT: + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + read_number(o, dst, NULL, NULL, &i64); + return o->default_val.i64 == i64; + case AV_OPT_TYPE_STRING: + str = *(char **)dst; + if (str == o->default_val.str) //2 NULLs + return 1; + if (!str || !o->default_val.str) //1 NULL + return 0; + return !strcmp(str, o->default_val.str); + case AV_OPT_TYPE_DOUBLE: + read_number(o, dst, &d, NULL, NULL); + return o->default_val.dbl == d; + case AV_OPT_TYPE_FLOAT: + read_number(o, dst, &d, NULL, NULL); + f = o->default_val.dbl; + d2 = f; + return d2 == d; + case AV_OPT_TYPE_RATIONAL: + q = av_d2q(o->default_val.dbl, INT_MAX); + return !av_cmp_q(*(AVRational*)dst, q); + case AV_OPT_TYPE_BINARY: { + struct { + uint8_t *data; + int size; + } tmp = {0}; + int opt_size = *(int *)((void **)dst + 1); + void *opt_ptr = *(void **)dst; + if (!opt_size && (!o->default_val.str || !strlen(o->default_val.str))) + return 1; + if (!opt_size || !o->default_val.str || !strlen(o->default_val.str )) + return 0; + if (opt_size != strlen(o->default_val.str) / 2) + return 0; + ret = set_string_binary(NULL, NULL, o->default_val.str, &tmp.data); + if (!ret) + ret = !memcmp(opt_ptr, tmp.data, tmp.size); + av_free(tmp.data); + return ret; + } + case AV_OPT_TYPE_DICT: + /* Binary and dict have not default support yet. Any pointer is not default. */ + return !!(*(void **)dst); + case AV_OPT_TYPE_IMAGE_SIZE: + if (!o->default_val.str || !strcmp(o->default_val.str, "none")) + w = h = 0; + else if ((ret = av_parse_video_size(&w, &h, o->default_val.str)) < 0) + return ret; + return (w == *(int *)dst) && (h == *((int *)dst+1)); + case AV_OPT_TYPE_VIDEO_RATE: + q = (AVRational){0, 0}; + if (o->default_val.str) { + if ((ret = av_parse_video_rate(&q, o->default_val.str)) < 0) + return ret; + } + return !av_cmp_q(*(AVRational*)dst, q); + case AV_OPT_TYPE_COLOR: { + uint8_t color[4] = {0, 0, 0, 0}; + if (o->default_val.str) { + if ((ret = av_parse_color(color, o->default_val.str, -1, NULL)) < 0) + return ret; + } + return !memcmp(color, dst, sizeof(color)); + } + default: + av_log(obj, AV_LOG_WARNING, "Not supported option type: %d, option name: %s\n", o->type, o->name); + break; + } + return AVERROR_PATCHWELCOME; +} + +int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags) +{ + const AVOption *o; + void *target; + if (!obj) + return AVERROR(EINVAL); + o = av_opt_find2(obj, name, NULL, 0, search_flags, &target); + if (!o) + return AVERROR_OPTION_NOT_FOUND; + return av_opt_is_set_to_default(target, o); +} + +int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, + const char key_val_sep, const char pairs_sep) +{ + const AVOption *o = NULL; + uint8_t *buf; + AVBPrint bprint; + int ret, cnt = 0; + const char special_chars[] = {pairs_sep, key_val_sep, '\0'}; + + if (pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep || + pairs_sep == '\\' || key_val_sep == '\\') { + av_log(obj, AV_LOG_ERROR, "Invalid separator(s) found."); + return AVERROR(EINVAL); + } + + if (!obj || !buffer) + return AVERROR(EINVAL); + + *buffer = NULL; + av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); + + while (o = av_opt_next(obj, o)) { + if (o->type == AV_OPT_TYPE_CONST) + continue; + if ((flags & AV_OPT_SERIALIZE_OPT_FLAGS_EXACT) && o->flags != opt_flags) + continue; + else if (((o->flags & opt_flags) != opt_flags)) + continue; + if (flags & AV_OPT_SERIALIZE_SKIP_DEFAULTS && av_opt_is_set_to_default(obj, o) > 0) + continue; + if ((ret = av_opt_get(obj, o->name, 0, &buf)) < 0) { + av_bprint_finalize(&bprint, NULL); + return ret; + } + if (buf) { + if (cnt++) + av_bprint_append_data(&bprint, &pairs_sep, 1); + av_bprint_escape(&bprint, o->name, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); + av_bprint_append_data(&bprint, &key_val_sep, 1); + av_bprint_escape(&bprint, buf, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); + av_freep(&buf); + } + } + av_bprint_finalize(&bprint, buffer); + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/opt.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/opt.h new file mode 100644 index 0000000000..39f4a8dda0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/opt.h @@ -0,0 +1,865 @@ +/* + * AVOptions + * copyright (c) 2005 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_OPT_H +#define AVUTIL_OPT_H + +/** + * @file + * AVOptions + */ + +#include "rational.h" +#include "avutil.h" +#include "dict.h" +#include "log.h" +#include "pixfmt.h" +#include "samplefmt.h" +#include "version.h" + +/** + * @defgroup avoptions AVOptions + * @ingroup lavu_data + * @{ + * AVOptions provide a generic system to declare options on arbitrary structs + * ("objects"). An option can have a help text, a type and a range of possible + * values. Options may then be enumerated, read and written to. + * + * @section avoptions_implement Implementing AVOptions + * This section describes how to add AVOptions capabilities to a struct. + * + * All AVOptions-related information is stored in an AVClass. Therefore + * the first member of the struct should be a pointer to an AVClass describing it. + * The option field of the AVClass must be set to a NULL-terminated static array + * of AVOptions. Each AVOption must have a non-empty name, a type, a default + * value and for number-type AVOptions also a range of allowed values. It must + * also declare an offset in bytes from the start of the struct, where the field + * associated with this AVOption is located. Other fields in the AVOption struct + * should also be set when applicable, but are not required. + * + * The following example illustrates an AVOptions-enabled struct: + * @code + * typedef struct test_struct { + * const AVClass *class; + * int int_opt; + * char *str_opt; + * uint8_t *bin_opt; + * int bin_len; + * } test_struct; + * + * static const AVOption test_options[] = { + * { "test_int", "This is a test option of int type.", offsetof(test_struct, int_opt), + * AV_OPT_TYPE_INT, { .i64 = -1 }, INT_MIN, INT_MAX }, + * { "test_str", "This is a test option of string type.", offsetof(test_struct, str_opt), + * AV_OPT_TYPE_STRING }, + * { "test_bin", "This is a test option of binary type.", offsetof(test_struct, bin_opt), + * AV_OPT_TYPE_BINARY }, + * { NULL }, + * }; + * + * static const AVClass test_class = { + * .class_name = "test class", + * .item_name = av_default_item_name, + * .option = test_options, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * @endcode + * + * Next, when allocating your struct, you must ensure that the AVClass pointer + * is set to the correct value. Then, av_opt_set_defaults() can be called to + * initialize defaults. After that the struct is ready to be used with the + * AVOptions API. + * + * When cleaning up, you may use the av_opt_free() function to automatically + * free all the allocated string and binary options. + * + * Continuing with the above example: + * + * @code + * test_struct *alloc_test_struct(void) + * { + * test_struct *ret = av_mallocz(sizeof(*ret)); + * ret->class = &test_class; + * av_opt_set_defaults(ret); + * return ret; + * } + * void free_test_struct(test_struct **foo) + * { + * av_opt_free(*foo); + * av_freep(foo); + * } + * @endcode + * + * @subsection avoptions_implement_nesting Nesting + * It may happen that an AVOptions-enabled struct contains another + * AVOptions-enabled struct as a member (e.g. AVCodecContext in + * libavcodec exports generic options, while its priv_data field exports + * codec-specific options). In such a case, it is possible to set up the + * parent struct to export a child's options. To do that, simply + * implement AVClass.child_next() and AVClass.child_class_next() in the + * parent struct's AVClass. + * Assuming that the test_struct from above now also contains a + * child_struct field: + * + * @code + * typedef struct child_struct { + * AVClass *class; + * int flags_opt; + * } child_struct; + * static const AVOption child_opts[] = { + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX }, + * { NULL }, + * }; + * static const AVClass child_class = { + * .class_name = "child class", + * .item_name = av_default_item_name, + * .option = child_opts, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * + * void *child_next(void *obj, void *prev) + * { + * test_struct *t = obj; + * if (!prev && t->child_struct) + * return t->child_struct; + * return NULL + * } + * const AVClass child_class_next(const AVClass *prev) + * { + * return prev ? NULL : &child_class; + * } + * @endcode + * Putting child_next() and child_class_next() as defined above into + * test_class will now make child_struct's options accessible through + * test_struct (again, proper setup as described above needs to be done on + * child_struct right after it is created). + * + * From the above example it might not be clear why both child_next() + * and child_class_next() are needed. The distinction is that child_next() + * iterates over actually existing objects, while child_class_next() + * iterates over all possible child classes. E.g. if an AVCodecContext + * was initialized to use a codec which has private options, then its + * child_next() will return AVCodecContext.priv_data and finish + * iterating. OTOH child_class_next() on AVCodecContext.av_class will + * iterate over all available codecs with private options. + * + * @subsection avoptions_implement_named_constants Named constants + * It is possible to create named constants for options. Simply set the unit + * field of the option the constants should apply to a string and + * create the constants themselves as options of type AV_OPT_TYPE_CONST + * with their unit field set to the same string. + * Their default_val field should contain the value of the named + * constant. + * For example, to add some named constants for the test_flags option + * above, put the following into the child_opts array: + * @code + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, "test_unit" }, + * { "flag1", "This is a flag with value 16", 0, AV_OPT_TYPE_CONST, { .i64 = 16 }, 0, 0, "test_unit" }, + * @endcode + * + * @section avoptions_use Using AVOptions + * This section deals with accessing options in an AVOptions-enabled struct. + * Such structs in FFmpeg are e.g. AVCodecContext in libavcodec or + * AVFormatContext in libavformat. + * + * @subsection avoptions_use_examine Examining AVOptions + * The basic functions for examining options are av_opt_next(), which iterates + * over all options defined for one object, and av_opt_find(), which searches + * for an option with the given name. + * + * The situation is more complicated with nesting. An AVOptions-enabled struct + * may have AVOptions-enabled children. Passing the AV_OPT_SEARCH_CHILDREN flag + * to av_opt_find() will make the function search children recursively. + * + * For enumerating there are basically two cases. The first is when you want to + * get all options that may potentially exist on the struct and its children + * (e.g. when constructing documentation). In that case you should call + * av_opt_child_class_next() recursively on the parent struct's AVClass. The + * second case is when you have an already initialized struct with all its + * children and you want to get all options that can be actually written or read + * from it. In that case you should call av_opt_child_next() recursively (and + * av_opt_next() on each result). + * + * @subsection avoptions_use_get_set Reading and writing AVOptions + * When setting options, you often have a string read directly from the + * user. In such a case, simply passing it to av_opt_set() is enough. For + * non-string type options, av_opt_set() will parse the string according to the + * option type. + * + * Similarly av_opt_get() will read any option type and convert it to a string + * which will be returned. Do not forget that the string is allocated, so you + * have to free it with av_free(). + * + * In some cases it may be more convenient to put all options into an + * AVDictionary and call av_opt_set_dict() on it. A specific case of this + * are the format/codec open functions in lavf/lavc which take a dictionary + * filled with option as a parameter. This makes it possible to set some options + * that cannot be set otherwise, since e.g. the input file format is not known + * before the file is actually opened. + */ + +enum AVOptionType{ + AV_OPT_TYPE_FLAGS, + AV_OPT_TYPE_INT, + AV_OPT_TYPE_INT64, + AV_OPT_TYPE_DOUBLE, + AV_OPT_TYPE_FLOAT, + AV_OPT_TYPE_STRING, + AV_OPT_TYPE_RATIONAL, + AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length + AV_OPT_TYPE_DICT, + AV_OPT_TYPE_UINT64, + AV_OPT_TYPE_CONST, + AV_OPT_TYPE_IMAGE_SIZE, ///< offset must point to two consecutive integers + AV_OPT_TYPE_PIXEL_FMT, + AV_OPT_TYPE_SAMPLE_FMT, + AV_OPT_TYPE_VIDEO_RATE, ///< offset must point to AVRational + AV_OPT_TYPE_DURATION, + AV_OPT_TYPE_COLOR, + AV_OPT_TYPE_CHANNEL_LAYOUT, + AV_OPT_TYPE_BOOL, +}; + +/** + * AVOption + */ +typedef struct AVOption { + const char *name; + + /** + * short English help text + * @todo What about other languages? + */ + const char *help; + + /** + * The offset relative to the context structure where the option + * value is stored. It should be 0 for named constants. + */ + int offset; + enum AVOptionType type; + + /** + * the default value for scalar options + */ + union { + int64_t i64; + double dbl; + const char *str; + /* TODO those are unused now */ + AVRational q; + } default_val; + double min; ///< minimum valid value for the option + double max; ///< maximum valid value for the option + + int flags; +#define AV_OPT_FLAG_ENCODING_PARAM 1 ///< a generic parameter which can be set by the user for muxing or encoding +#define AV_OPT_FLAG_DECODING_PARAM 2 ///< a generic parameter which can be set by the user for demuxing or decoding +#define AV_OPT_FLAG_AUDIO_PARAM 8 +#define AV_OPT_FLAG_VIDEO_PARAM 16 +#define AV_OPT_FLAG_SUBTITLE_PARAM 32 +/** + * The option is intended for exporting values to the caller. + */ +#define AV_OPT_FLAG_EXPORT 64 +/** + * The option may not be set through the AVOptions API, only read. + * This flag only makes sense when AV_OPT_FLAG_EXPORT is also set. + */ +#define AV_OPT_FLAG_READONLY 128 +#define AV_OPT_FLAG_BSF_PARAM (1<<8) ///< a generic parameter which can be set by the user for bit stream filtering +#define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering +#define AV_OPT_FLAG_DEPRECATED (1<<17) ///< set if option is deprecated, users should refer to AVOption.help text for more information +//FIXME think about enc-audio, ... style flags + + /** + * The logical unit to which the option belongs. Non-constant + * options and corresponding named constants share the same + * unit. May be NULL. + */ + const char *unit; +} AVOption; + +/** + * A single allowed range of values, or a single allowed value. + */ +typedef struct AVOptionRange { + const char *str; + /** + * Value range. + * For string ranges this represents the min/max length. + * For dimensions this represents the min/max pixel count or width/height in multi-component case. + */ + double value_min, value_max; + /** + * Value's component range. + * For string this represents the unicode range for chars, 0-127 limits to ASCII. + */ + double component_min, component_max; + /** + * Range flag. + * If set to 1 the struct encodes a range, if set to 0 a single value. + */ + int is_range; +} AVOptionRange; + +/** + * List of AVOptionRange structs. + */ +typedef struct AVOptionRanges { + /** + * Array of option ranges. + * + * Most of option types use just one component. + * Following describes multi-component option types: + * + * AV_OPT_TYPE_IMAGE_SIZE: + * component index 0: range of pixel count (width * height). + * component index 1: range of width. + * component index 2: range of height. + * + * @note To obtain multi-component version of this structure, user must + * provide AV_OPT_MULTI_COMPONENT_RANGE to av_opt_query_ranges or + * av_opt_query_ranges_default function. + * + * Multi-component range can be read as in following example: + * + * @code + * int range_index, component_index; + * AVOptionRanges *ranges; + * AVOptionRange *range[3]; //may require more than 3 in the future. + * av_opt_query_ranges(&ranges, obj, key, AV_OPT_MULTI_COMPONENT_RANGE); + * for (range_index = 0; range_index < ranges->nb_ranges; range_index++) { + * for (component_index = 0; component_index < ranges->nb_components; component_index++) + * range[component_index] = ranges->range[ranges->nb_ranges * component_index + range_index]; + * //do something with range here. + * } + * av_opt_freep_ranges(&ranges); + * @endcode + */ + AVOptionRange **range; + /** + * Number of ranges per component. + */ + int nb_ranges; + /** + * Number of componentes. + */ + int nb_components; +} AVOptionRanges; + +/** + * Show the obj options. + * + * @param req_flags requested flags for the options to show. Show only the + * options for which it is opt->flags & req_flags. + * @param rej_flags rejected flags for the options to show. Show only the + * options for which it is !(opt->flags & req_flags). + * @param av_log_obj log context to use for showing the options + */ +int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags); + +/** + * Set the values of all AVOption fields to their default values. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + */ +void av_opt_set_defaults(void *s); + +/** + * Set the values of all AVOption fields to their default values. Only these + * AVOption fields for which (opt->flags & mask) == flags will have their + * default applied to s. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + * @param mask combination of AV_OPT_FLAG_* + * @param flags combination of AV_OPT_FLAG_* + */ +void av_opt_set_defaults2(void *s, int mask, int flags); + +/** + * Parse the key/value pairs list in opts. For each key/value pair + * found, stores the value in the field in ctx that is named like the + * key. ctx must be an AVClass context, storing is done using + * AVOptions. + * + * @param opts options string to parse, may be NULL + * @param key_val_sep a 0-terminated list of characters used to + * separate key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @return the number of successfully set key/value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_opt_set() if a key/value pair + * cannot be set + */ +int av_set_options_string(void *ctx, const char *opts, + const char *key_val_sep, const char *pairs_sep); + +/** + * Parse the key-value pairs list in opts. For each key=value pair found, + * set the value of the corresponding option in ctx. + * + * @param ctx the AVClass object to set options on + * @param opts the options string, key-value pairs separated by a + * delimiter + * @param shorthand a NULL-terminated array of options names for shorthand + * notation: if the first field in opts has no key part, + * the key is taken from the first element of shorthand; + * then again for the second, etc., until either opts is + * finished, shorthand is finished or a named option is + * found; after that, all options must be named + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @return the number of successfully set key=value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_set_string3() if a key/value pair + * cannot be set + * + * Options names must use only the following characters: a-z A-Z 0-9 - . / _ + * Separators must use characters distinct from option names and from each + * other. + */ +int av_opt_set_from_string(void *ctx, const char *opts, + const char *const *shorthand, + const char *key_val_sep, const char *pairs_sep); +/** + * Free all allocated objects in obj. + */ +void av_opt_free(void *obj); + +/** + * Check whether a particular flag is set in a flags field. + * + * @param field_name the name of the flag field option + * @param flag_name the name of the flag to check + * @return non-zero if the flag is set, zero if the flag isn't set, + * isn't of the right type, or the flags field doesn't exist. + */ +int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name); + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict(void *obj, struct AVDictionary **options); + + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict2(void *obj, struct AVDictionary **options, int search_flags); + +/** + * Extract a key-value pair from the beginning of a string. + * + * @param ropts pointer to the options string, will be updated to + * point to the rest of the string (one of the pairs_sep + * or the final NUL) + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @param flags flags; see the AV_OPT_FLAG_* values below + * @param rkey parsed key; must be freed using av_free() + * @param rval parsed value; must be freed using av_free() + * + * @return >=0 for success, or a negative value corresponding to an + * AVERROR code in case of error; in particular: + * AVERROR(EINVAL) if no key is present + * + */ +int av_opt_get_key_value(const char **ropts, + const char *key_val_sep, const char *pairs_sep, + unsigned flags, + char **rkey, char **rval); + +enum { + + /** + * Accept to parse a value without a key; the key will then be returned + * as NULL. + */ + AV_OPT_FLAG_IMPLICIT_KEY = 1, +}; + +/** + * @defgroup opt_eval_funcs Evaluating option strings + * @{ + * This group of functions can be used to evaluate option strings + * and get numbers out of them. They do the same thing as av_opt_set(), + * except the result is written into the caller-supplied pointer. + * + * @param obj a struct whose first element is a pointer to AVClass. + * @param o an option for which the string is to be evaluated. + * @param val string to be evaluated. + * @param *_out value of the string will be written here. + * + * @return 0 on success, a negative number on failure. + */ +int av_opt_eval_flags (void *obj, const AVOption *o, const char *val, int *flags_out); +int av_opt_eval_int (void *obj, const AVOption *o, const char *val, int *int_out); +int av_opt_eval_int64 (void *obj, const AVOption *o, const char *val, int64_t *int64_out); +int av_opt_eval_float (void *obj, const AVOption *o, const char *val, float *float_out); +int av_opt_eval_double(void *obj, const AVOption *o, const char *val, double *double_out); +int av_opt_eval_q (void *obj, const AVOption *o, const char *val, AVRational *q_out); +/** + * @} + */ + +#define AV_OPT_SEARCH_CHILDREN (1 << 0) /**< Search in possible children of the + given object first. */ +/** + * The obj passed to av_opt_find() is fake -- only a double pointer to AVClass + * instead of a required pointer to a struct containing AVClass. This is + * useful for searching for options without needing to allocate the corresponding + * object. + */ +#define AV_OPT_SEARCH_FAKE_OBJ (1 << 1) + +/** + * In av_opt_get, return NULL if the option has a pointer type and is set to NULL, + * rather than returning an empty string. + */ +#define AV_OPT_ALLOW_NULL (1 << 2) + +/** + * Allows av_opt_query_ranges and av_opt_query_ranges_default to return more than + * one component for certain option types. + * @see AVOptionRanges for details. + */ +#define AV_OPT_MULTI_COMPONENT_RANGE (1 << 12) + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return A pointer to the option found, or NULL if no option + * was found. + * + * @note Options found with AV_OPT_SEARCH_CHILDREN flag may not be settable + * directly with av_opt_set(). Use special calls which take an options + * AVDictionary (e.g. avformat_open_input()) to set options found with this + * flag. + */ +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags); + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * @param[out] target_obj if non-NULL, an object to which the option belongs will be + * written here. It may be different from obj if AV_OPT_SEARCH_CHILDREN is present + * in search_flags. This parameter is ignored if search_flags contain + * AV_OPT_SEARCH_FAKE_OBJ. + * + * @return A pointer to the option found, or NULL if no option + * was found. + */ +const AVOption *av_opt_find2(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags, void **target_obj); + +/** + * Iterate over all AVOptions belonging to obj. + * + * @param obj an AVOptions-enabled struct or a double pointer to an + * AVClass describing it. + * @param prev result of the previous call to av_opt_next() on this object + * or NULL + * @return next AVOption or NULL + */ +const AVOption *av_opt_next(const void *obj, const AVOption *prev); + +/** + * Iterate over AVOptions-enabled children of obj. + * + * @param prev result of a previous call to this function or NULL + * @return next AVOptions-enabled child or NULL + */ +void *av_opt_child_next(void *obj, void *prev); + +/** + * Iterate over potential AVOptions-enabled children of parent. + * + * @param prev result of a previous call to this function or NULL + * @return AVClass corresponding to next potential child or NULL + */ +const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev); + +/** + * @defgroup opt_set_funcs Option setting functions + * @{ + * Those functions set the field of obj with the given name to value. + * + * @param[in] obj A struct whose first element is a pointer to an AVClass. + * @param[in] name the name of the field to set + * @param[in] val The value to set. In case of av_opt_set() if the field is not + * of a string type, then the given string is parsed. + * SI postfixes and some named scalars are supported. + * If the field is of a numeric type, it has to be a numeric or named + * scalar. Behavior with more than one scalar and +- infix operators + * is undefined. + * If the field is of a flags type, it has to be a sequence of numeric + * scalars or named flags separated by '+' or '-'. Prefixing a flag + * with '+' causes it to be set without affecting the other flags; + * similarly, '-' unsets a flag. + * @param search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be set on a child of obj. + * + * @return 0 if the value has been set, or an AVERROR code in case of + * error: + * AVERROR_OPTION_NOT_FOUND if no matching option exists + * AVERROR(ERANGE) if the value is out of range + * AVERROR(EINVAL) if the value is not valid + */ +int av_opt_set (void *obj, const char *name, const char *val, int search_flags); +int av_opt_set_int (void *obj, const char *name, int64_t val, int search_flags); +int av_opt_set_double (void *obj, const char *name, double val, int search_flags); +int av_opt_set_q (void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size, int search_flags); +int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags); +int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags); +int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags); +int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_channel_layout(void *obj, const char *name, int64_t ch_layout, int search_flags); +/** + * @note Any old dictionary present is discarded and replaced with a copy of the new one. The + * caller still owns val is and responsible for freeing it. + */ +int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags); + +/** + * Set a binary option to an integer list. + * + * @param obj AVClass object to set options on + * @param name name of the binary option + * @param val pointer to an integer list (must have the correct type with + * regard to the contents of the list) + * @param term list terminator (usually 0 or -1) + * @param flags search flags + */ +#define av_opt_set_int_list(obj, name, val, term, flags) \ + (av_int_list_length(val, term) > INT_MAX / sizeof(*(val)) ? \ + AVERROR(EINVAL) : \ + av_opt_set_bin(obj, name, (const uint8_t *)(val), \ + av_int_list_length(val, term) * sizeof(*(val)), flags)) + +/** + * @} + */ + +/** + * @defgroup opt_get_funcs Option getting functions + * @{ + * Those functions get a value of the option with the given name from an object. + * + * @param[in] obj a struct whose first element is a pointer to an AVClass. + * @param[in] name name of the option to get. + * @param[in] search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be found in a child of obj. + * @param[out] out_val value of the option will be written here + * @return >=0 on success, a negative error code otherwise + */ +/** + * @note the returned string will be av_malloc()ed and must be av_free()ed by the caller + * + * @note if AV_OPT_ALLOW_NULL is set in search_flags in av_opt_get, and the option has + * AV_OPT_TYPE_STRING or AV_OPT_TYPE_BINARY and is set to NULL, *out_val will be set + * to NULL instead of an allocated empty string. + */ +int av_opt_get (void *obj, const char *name, int search_flags, uint8_t **out_val); +int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t *out_val); +int av_opt_get_double (void *obj, const char *name, int search_flags, double *out_val); +int av_opt_get_q (void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out); +int av_opt_get_pixel_fmt (void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt); +int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt); +int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *ch_layout); +/** + * @param[out] out_val The returned dictionary is a copy of the actual value and must + * be freed with av_dict_free() by the caller + */ +int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val); +/** + * @} + */ +/** + * Gets a pointer to the requested field in a struct. + * This function allows accessing a struct even when its fields are moved or + * renamed since the application making the access has been compiled, + * + * @returns a pointer to the field, it can be cast to the correct type and read + * or written to. + */ +void *av_opt_ptr(const AVClass *avclass, void *obj, const char *name); + +/** + * Free an AVOptionRanges struct and set it to NULL. + */ +void av_opt_freep_ranges(AVOptionRanges **ranges); + +/** + * Get a list of allowed ranges for the given option. + * + * The returned list may depend on other fields in obj like for example profile. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_freep_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * Copy options from src object into dest object. + * + * Options that require memory allocation (e.g. string or binary) are malloc'ed in dest object. + * Original memory allocated for such options is freed unless both src and dest options points to the same memory. + * + * @param dest Object to copy from + * @param src Object to copy into + * @return 0 on success, negative on error + */ +int av_opt_copy(void *dest, const void *src); + +/** + * Get a default list of allowed ranges for the given option. + * + * This list is constructed without using the AVClass.query_ranges() callback + * and can be used as fallback from within the callback. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_free_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges_default(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * Check if given option is set to its default value. + * + * Options o must belong to the obj. This function must not be called to check child's options state. + * @see av_opt_is_set_to_default_by_name(). + * + * @param obj AVClass object to check option on + * @param o option to be checked + * @return >0 when option is set to its default, + * 0 when option is not set its default, + * <0 on error + */ +int av_opt_is_set_to_default(void *obj, const AVOption *o); + +/** + * Check if given option is set to its default value. + * + * @param obj AVClass object to check option on + * @param name option name + * @param search_flags combination of AV_OPT_SEARCH_* + * @return >0 when option is set to its default, + * 0 when option is not set its default, + * <0 on error + */ +int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags); + + +#define AV_OPT_SERIALIZE_SKIP_DEFAULTS 0x00000001 ///< Serialize options that are not set to default values only. +#define AV_OPT_SERIALIZE_OPT_FLAGS_EXACT 0x00000002 ///< Serialize options that exactly match opt_flags only. + +/** + * Serialize object's options. + * + * Create a string containing object's serialized options. + * Such string may be passed back to av_opt_set_from_string() in order to restore option values. + * A key/value or pairs separator occurring in the serialized value or + * name string are escaped through the av_escape() function. + * + * @param[in] obj AVClass object to serialize + * @param[in] opt_flags serialize options with all the specified flags set (AV_OPT_FLAG) + * @param[in] flags combination of AV_OPT_SERIALIZE_* flags + * @param[out] buffer Pointer to buffer that will be allocated with string containg serialized options. + * Buffer must be freed by the caller when is no longer needed. + * @param[in] key_val_sep character used to separate key from value + * @param[in] pairs_sep character used to separate two pairs from each other + * @return >= 0 on success, negative on error + * @warning Separators cannot be neither '\\' nor '\0'. They also cannot be the same. + */ +int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, + const char key_val_sep, const char pairs_sep); +/** + * @} + */ + +#endif /* AVUTIL_OPT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/parseutils.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/parseutils.c new file mode 100644 index 0000000000..167e822648 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/parseutils.c @@ -0,0 +1,786 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * misc parsing utilities + */ + +#include + +#include "avstring.h" +#include "avutil.h" +#include "common.h" +#include "eval.h" +#include "log.h" +#include "random_seed.h" +#include "time_internal.h" +#include "parseutils.h" +#include "time.h" + +#ifdef TEST + +#define av_get_random_seed av_get_random_seed_deterministic +static uint32_t av_get_random_seed_deterministic(void); + +#define av_gettime() 1331972053200000 + +#endif + +int av_parse_ratio(AVRational *q, const char *str, int max, + int log_offset, void *log_ctx) +{ + char c; + int ret; + + if (sscanf(str, "%d:%d%c", &q->num, &q->den, &c) != 2) { + double d; + ret = av_expr_parse_and_eval(&d, str, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, log_offset, log_ctx); + if (ret < 0) + return ret; + *q = av_d2q(d, max); + } else { + av_reduce(&q->num, &q->den, q->num, q->den, max); + } + + return 0; +} + +typedef struct VideoSizeAbbr { + const char *abbr; + int width, height; +} VideoSizeAbbr; + +typedef struct VideoRateAbbr { + const char *abbr; + AVRational rate; +} VideoRateAbbr; + +static const VideoSizeAbbr video_size_abbrs[] = { + { "ntsc", 720, 480 }, + { "pal", 720, 576 }, + { "qntsc", 352, 240 }, /* VCD compliant NTSC */ + { "qpal", 352, 288 }, /* VCD compliant PAL */ + { "sntsc", 640, 480 }, /* square pixel NTSC */ + { "spal", 768, 576 }, /* square pixel PAL */ + { "film", 352, 240 }, + { "ntsc-film", 352, 240 }, + { "sqcif", 128, 96 }, + { "qcif", 176, 144 }, + { "cif", 352, 288 }, + { "4cif", 704, 576 }, + { "16cif", 1408,1152 }, + { "qqvga", 160, 120 }, + { "qvga", 320, 240 }, + { "vga", 640, 480 }, + { "svga", 800, 600 }, + { "xga", 1024, 768 }, + { "uxga", 1600,1200 }, + { "qxga", 2048,1536 }, + { "sxga", 1280,1024 }, + { "qsxga", 2560,2048 }, + { "hsxga", 5120,4096 }, + { "wvga", 852, 480 }, + { "wxga", 1366, 768 }, + { "wsxga", 1600,1024 }, + { "wuxga", 1920,1200 }, + { "woxga", 2560,1600 }, + { "wqsxga", 3200,2048 }, + { "wquxga", 3840,2400 }, + { "whsxga", 6400,4096 }, + { "whuxga", 7680,4800 }, + { "cga", 320, 200 }, + { "ega", 640, 350 }, + { "hd480", 852, 480 }, + { "hd720", 1280, 720 }, + { "hd1080", 1920,1080 }, + { "2k", 2048,1080 }, /* Digital Cinema System Specification */ + { "2kdci", 2048,1080 }, + { "2kflat", 1998,1080 }, + { "2kscope", 2048, 858 }, + { "4k", 4096,2160 }, /* Digital Cinema System Specification */ + { "4kdci", 4096,2160 }, + { "4kflat", 3996,2160 }, + { "4kscope", 4096,1716 }, + { "nhd", 640,360 }, + { "hqvga", 240,160 }, + { "wqvga", 400,240 }, + { "fwqvga", 432,240 }, + { "hvga", 480,320 }, + { "qhd", 960,540 }, + { "uhd2160", 3840,2160 }, + { "uhd4320", 7680,4320 }, +}; + +static const VideoRateAbbr video_rate_abbrs[]= { + { "ntsc", { 30000, 1001 } }, + { "pal", { 25, 1 } }, + { "qntsc", { 30000, 1001 } }, /* VCD compliant NTSC */ + { "qpal", { 25, 1 } }, /* VCD compliant PAL */ + { "sntsc", { 30000, 1001 } }, /* square pixel NTSC */ + { "spal", { 25, 1 } }, /* square pixel PAL */ + { "film", { 24, 1 } }, + { "ntsc-film", { 24000, 1001 } }, +}; + +static const char *months[12] = { + "january", "february", "march", "april", "may", "june", "july", "august", + "september", "october", "november", "december" +}; + +int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str) +{ + int i; + int n = FF_ARRAY_ELEMS(video_size_abbrs); + const char *p; + int width = 0, height = 0; + + for (i = 0; i < n; i++) { + if (!strcmp(video_size_abbrs[i].abbr, str)) { + width = video_size_abbrs[i].width; + height = video_size_abbrs[i].height; + break; + } + } + if (i == n) { + width = strtol(str, (void*)&p, 10); + if (*p) + p++; + height = strtol(p, (void*)&p, 10); + + /* trailing extraneous data detected, like in 123x345foobar */ + if (*p) + return AVERROR(EINVAL); + } + if (width <= 0 || height <= 0) + return AVERROR(EINVAL); + *width_ptr = width; + *height_ptr = height; + return 0; +} + +int av_parse_video_rate(AVRational *rate, const char *arg) +{ + int i, ret; + int n = FF_ARRAY_ELEMS(video_rate_abbrs); + + /* First, we check our abbreviation table */ + for (i = 0; i < n; ++i) + if (!strcmp(video_rate_abbrs[i].abbr, arg)) { + *rate = video_rate_abbrs[i].rate; + return 0; + } + + /* Then, we try to parse it as fraction */ + if ((ret = av_parse_ratio_quiet(rate, arg, 1001000)) < 0) + return ret; + if (rate->num <= 0 || rate->den <= 0) + return AVERROR(EINVAL); + return 0; +} + +typedef struct ColorEntry { + const char *name; ///< a string representing the name of the color + uint8_t rgb_color[3]; ///< RGB values for the color +} ColorEntry; + +static const ColorEntry color_table[] = { + { "AliceBlue", { 0xF0, 0xF8, 0xFF } }, + { "AntiqueWhite", { 0xFA, 0xEB, 0xD7 } }, + { "Aqua", { 0x00, 0xFF, 0xFF } }, + { "Aquamarine", { 0x7F, 0xFF, 0xD4 } }, + { "Azure", { 0xF0, 0xFF, 0xFF } }, + { "Beige", { 0xF5, 0xF5, 0xDC } }, + { "Bisque", { 0xFF, 0xE4, 0xC4 } }, + { "Black", { 0x00, 0x00, 0x00 } }, + { "BlanchedAlmond", { 0xFF, 0xEB, 0xCD } }, + { "Blue", { 0x00, 0x00, 0xFF } }, + { "BlueViolet", { 0x8A, 0x2B, 0xE2 } }, + { "Brown", { 0xA5, 0x2A, 0x2A } }, + { "BurlyWood", { 0xDE, 0xB8, 0x87 } }, + { "CadetBlue", { 0x5F, 0x9E, 0xA0 } }, + { "Chartreuse", { 0x7F, 0xFF, 0x00 } }, + { "Chocolate", { 0xD2, 0x69, 0x1E } }, + { "Coral", { 0xFF, 0x7F, 0x50 } }, + { "CornflowerBlue", { 0x64, 0x95, 0xED } }, + { "Cornsilk", { 0xFF, 0xF8, 0xDC } }, + { "Crimson", { 0xDC, 0x14, 0x3C } }, + { "Cyan", { 0x00, 0xFF, 0xFF } }, + { "DarkBlue", { 0x00, 0x00, 0x8B } }, + { "DarkCyan", { 0x00, 0x8B, 0x8B } }, + { "DarkGoldenRod", { 0xB8, 0x86, 0x0B } }, + { "DarkGray", { 0xA9, 0xA9, 0xA9 } }, + { "DarkGreen", { 0x00, 0x64, 0x00 } }, + { "DarkKhaki", { 0xBD, 0xB7, 0x6B } }, + { "DarkMagenta", { 0x8B, 0x00, 0x8B } }, + { "DarkOliveGreen", { 0x55, 0x6B, 0x2F } }, + { "Darkorange", { 0xFF, 0x8C, 0x00 } }, + { "DarkOrchid", { 0x99, 0x32, 0xCC } }, + { "DarkRed", { 0x8B, 0x00, 0x00 } }, + { "DarkSalmon", { 0xE9, 0x96, 0x7A } }, + { "DarkSeaGreen", { 0x8F, 0xBC, 0x8F } }, + { "DarkSlateBlue", { 0x48, 0x3D, 0x8B } }, + { "DarkSlateGray", { 0x2F, 0x4F, 0x4F } }, + { "DarkTurquoise", { 0x00, 0xCE, 0xD1 } }, + { "DarkViolet", { 0x94, 0x00, 0xD3 } }, + { "DeepPink", { 0xFF, 0x14, 0x93 } }, + { "DeepSkyBlue", { 0x00, 0xBF, 0xFF } }, + { "DimGray", { 0x69, 0x69, 0x69 } }, + { "DodgerBlue", { 0x1E, 0x90, 0xFF } }, + { "FireBrick", { 0xB2, 0x22, 0x22 } }, + { "FloralWhite", { 0xFF, 0xFA, 0xF0 } }, + { "ForestGreen", { 0x22, 0x8B, 0x22 } }, + { "Fuchsia", { 0xFF, 0x00, 0xFF } }, + { "Gainsboro", { 0xDC, 0xDC, 0xDC } }, + { "GhostWhite", { 0xF8, 0xF8, 0xFF } }, + { "Gold", { 0xFF, 0xD7, 0x00 } }, + { "GoldenRod", { 0xDA, 0xA5, 0x20 } }, + { "Gray", { 0x80, 0x80, 0x80 } }, + { "Green", { 0x00, 0x80, 0x00 } }, + { "GreenYellow", { 0xAD, 0xFF, 0x2F } }, + { "HoneyDew", { 0xF0, 0xFF, 0xF0 } }, + { "HotPink", { 0xFF, 0x69, 0xB4 } }, + { "IndianRed", { 0xCD, 0x5C, 0x5C } }, + { "Indigo", { 0x4B, 0x00, 0x82 } }, + { "Ivory", { 0xFF, 0xFF, 0xF0 } }, + { "Khaki", { 0xF0, 0xE6, 0x8C } }, + { "Lavender", { 0xE6, 0xE6, 0xFA } }, + { "LavenderBlush", { 0xFF, 0xF0, 0xF5 } }, + { "LawnGreen", { 0x7C, 0xFC, 0x00 } }, + { "LemonChiffon", { 0xFF, 0xFA, 0xCD } }, + { "LightBlue", { 0xAD, 0xD8, 0xE6 } }, + { "LightCoral", { 0xF0, 0x80, 0x80 } }, + { "LightCyan", { 0xE0, 0xFF, 0xFF } }, + { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } }, + { "LightGreen", { 0x90, 0xEE, 0x90 } }, + { "LightGrey", { 0xD3, 0xD3, 0xD3 } }, + { "LightPink", { 0xFF, 0xB6, 0xC1 } }, + { "LightSalmon", { 0xFF, 0xA0, 0x7A } }, + { "LightSeaGreen", { 0x20, 0xB2, 0xAA } }, + { "LightSkyBlue", { 0x87, 0xCE, 0xFA } }, + { "LightSlateGray", { 0x77, 0x88, 0x99 } }, + { "LightSteelBlue", { 0xB0, 0xC4, 0xDE } }, + { "LightYellow", { 0xFF, 0xFF, 0xE0 } }, + { "Lime", { 0x00, 0xFF, 0x00 } }, + { "LimeGreen", { 0x32, 0xCD, 0x32 } }, + { "Linen", { 0xFA, 0xF0, 0xE6 } }, + { "Magenta", { 0xFF, 0x00, 0xFF } }, + { "Maroon", { 0x80, 0x00, 0x00 } }, + { "MediumAquaMarine", { 0x66, 0xCD, 0xAA } }, + { "MediumBlue", { 0x00, 0x00, 0xCD } }, + { "MediumOrchid", { 0xBA, 0x55, 0xD3 } }, + { "MediumPurple", { 0x93, 0x70, 0xD8 } }, + { "MediumSeaGreen", { 0x3C, 0xB3, 0x71 } }, + { "MediumSlateBlue", { 0x7B, 0x68, 0xEE } }, + { "MediumSpringGreen", { 0x00, 0xFA, 0x9A } }, + { "MediumTurquoise", { 0x48, 0xD1, 0xCC } }, + { "MediumVioletRed", { 0xC7, 0x15, 0x85 } }, + { "MidnightBlue", { 0x19, 0x19, 0x70 } }, + { "MintCream", { 0xF5, 0xFF, 0xFA } }, + { "MistyRose", { 0xFF, 0xE4, 0xE1 } }, + { "Moccasin", { 0xFF, 0xE4, 0xB5 } }, + { "NavajoWhite", { 0xFF, 0xDE, 0xAD } }, + { "Navy", { 0x00, 0x00, 0x80 } }, + { "OldLace", { 0xFD, 0xF5, 0xE6 } }, + { "Olive", { 0x80, 0x80, 0x00 } }, + { "OliveDrab", { 0x6B, 0x8E, 0x23 } }, + { "Orange", { 0xFF, 0xA5, 0x00 } }, + { "OrangeRed", { 0xFF, 0x45, 0x00 } }, + { "Orchid", { 0xDA, 0x70, 0xD6 } }, + { "PaleGoldenRod", { 0xEE, 0xE8, 0xAA } }, + { "PaleGreen", { 0x98, 0xFB, 0x98 } }, + { "PaleTurquoise", { 0xAF, 0xEE, 0xEE } }, + { "PaleVioletRed", { 0xD8, 0x70, 0x93 } }, + { "PapayaWhip", { 0xFF, 0xEF, 0xD5 } }, + { "PeachPuff", { 0xFF, 0xDA, 0xB9 } }, + { "Peru", { 0xCD, 0x85, 0x3F } }, + { "Pink", { 0xFF, 0xC0, 0xCB } }, + { "Plum", { 0xDD, 0xA0, 0xDD } }, + { "PowderBlue", { 0xB0, 0xE0, 0xE6 } }, + { "Purple", { 0x80, 0x00, 0x80 } }, + { "Red", { 0xFF, 0x00, 0x00 } }, + { "RosyBrown", { 0xBC, 0x8F, 0x8F } }, + { "RoyalBlue", { 0x41, 0x69, 0xE1 } }, + { "SaddleBrown", { 0x8B, 0x45, 0x13 } }, + { "Salmon", { 0xFA, 0x80, 0x72 } }, + { "SandyBrown", { 0xF4, 0xA4, 0x60 } }, + { "SeaGreen", { 0x2E, 0x8B, 0x57 } }, + { "SeaShell", { 0xFF, 0xF5, 0xEE } }, + { "Sienna", { 0xA0, 0x52, 0x2D } }, + { "Silver", { 0xC0, 0xC0, 0xC0 } }, + { "SkyBlue", { 0x87, 0xCE, 0xEB } }, + { "SlateBlue", { 0x6A, 0x5A, 0xCD } }, + { "SlateGray", { 0x70, 0x80, 0x90 } }, + { "Snow", { 0xFF, 0xFA, 0xFA } }, + { "SpringGreen", { 0x00, 0xFF, 0x7F } }, + { "SteelBlue", { 0x46, 0x82, 0xB4 } }, + { "Tan", { 0xD2, 0xB4, 0x8C } }, + { "Teal", { 0x00, 0x80, 0x80 } }, + { "Thistle", { 0xD8, 0xBF, 0xD8 } }, + { "Tomato", { 0xFF, 0x63, 0x47 } }, + { "Turquoise", { 0x40, 0xE0, 0xD0 } }, + { "Violet", { 0xEE, 0x82, 0xEE } }, + { "Wheat", { 0xF5, 0xDE, 0xB3 } }, + { "White", { 0xFF, 0xFF, 0xFF } }, + { "WhiteSmoke", { 0xF5, 0xF5, 0xF5 } }, + { "Yellow", { 0xFF, 0xFF, 0x00 } }, + { "YellowGreen", { 0x9A, 0xCD, 0x32 } }, +}; + +static int color_table_compare(const void *lhs, const void *rhs) +{ + return av_strcasecmp(lhs, ((const ColorEntry *)rhs)->name); +} + +#define ALPHA_SEP '@' + +int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, + void *log_ctx) +{ + char *tail, color_string2[128]; + const ColorEntry *entry; + int len, hex_offset = 0; + + if (color_string[0] == '#') { + hex_offset = 1; + } else if (!strncmp(color_string, "0x", 2)) + hex_offset = 2; + + if (slen < 0) + slen = strlen(color_string); + av_strlcpy(color_string2, color_string + hex_offset, + FFMIN(slen-hex_offset+1, sizeof(color_string2))); + if ((tail = strchr(color_string2, ALPHA_SEP))) + *tail++ = 0; + len = strlen(color_string2); + rgba_color[3] = 255; + + if (!av_strcasecmp(color_string2, "random") || !av_strcasecmp(color_string2, "bikeshed")) { + int rgba = av_get_random_seed(); + rgba_color[0] = rgba >> 24; + rgba_color[1] = rgba >> 16; + rgba_color[2] = rgba >> 8; + rgba_color[3] = rgba; + } else if (hex_offset || + strspn(color_string2, "0123456789ABCDEFabcdef") == len) { + char *tail; + unsigned int rgba = strtoul(color_string2, &tail, 16); + + if (*tail || (len != 6 && len != 8)) { + av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2); + return AVERROR(EINVAL); + } + if (len == 8) { + rgba_color[3] = rgba; + rgba >>= 8; + } + rgba_color[0] = rgba >> 16; + rgba_color[1] = rgba >> 8; + rgba_color[2] = rgba; + } else { + entry = bsearch(color_string2, + color_table, + FF_ARRAY_ELEMS(color_table), + sizeof(ColorEntry), + color_table_compare); + if (!entry) { + av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2); + return AVERROR(EINVAL); + } + memcpy(rgba_color, entry->rgb_color, 3); + } + + if (tail) { + double alpha; + const char *alpha_string = tail; + if (!strncmp(alpha_string, "0x", 2)) { + alpha = strtoul(alpha_string, &tail, 16); + } else { + double norm_alpha = strtod(alpha_string, &tail); + if (norm_alpha < 0.0 || norm_alpha > 1.0) + alpha = 256; + else + alpha = 255 * norm_alpha; + } + + if (tail == alpha_string || *tail || alpha > 255 || alpha < 0) { + av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n", + alpha_string, color_string); + return AVERROR(EINVAL); + } + rgba_color[3] = alpha; + } + + return 0; +} + +const char *av_get_known_color_name(int color_idx, const uint8_t **rgbp) +{ + const ColorEntry *color; + + if ((unsigned)color_idx >= FF_ARRAY_ELEMS(color_table)) + return NULL; + + color = &color_table[color_idx]; + if (rgbp) + *rgbp = color->rgb_color; + + return color->name; +} + +/* get a positive number between n_min and n_max, for a maximum length + of len_max. Return -1 if error. */ +static int date_get_num(const char **pp, + int n_min, int n_max, int len_max) +{ + int i, val, c; + const char *p; + + p = *pp; + val = 0; + for(i = 0; i < len_max; i++) { + c = *p; + if (!av_isdigit(c)) + break; + val = (val * 10) + c - '0'; + p++; + } + /* no number read ? */ + if (p == *pp) + return -1; + if (val < n_min || val > n_max) + return -1; + *pp = p; + return val; +} + +static int date_get_month(const char **pp) { + int i = 0; + for (; i < 12; i++) { + if (!av_strncasecmp(*pp, months[i], 3)) { + const char *mo_full = months[i] + 3; + int len = strlen(mo_full); + *pp += 3; + if (len > 0 && !av_strncasecmp(*pp, mo_full, len)) + *pp += len; + return i; + } + } + return -1; +} + +char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) +{ + int c, val; + + while((c = *fmt++)) { + if (c != '%') { + if (av_isspace(c)) + for (; *p && av_isspace(*p); p++); + else if (*p != c) + return NULL; + else p++; + continue; + } + + c = *fmt++; + switch(c) { + case 'H': + case 'J': + val = date_get_num(&p, 0, c == 'H' ? 23 : INT_MAX, c == 'H' ? 2 : 4); + + if (val == -1) + return NULL; + dt->tm_hour = val; + break; + case 'M': + val = date_get_num(&p, 0, 59, 2); + if (val == -1) + return NULL; + dt->tm_min = val; + break; + case 'S': + val = date_get_num(&p, 0, 59, 2); + if (val == -1) + return NULL; + dt->tm_sec = val; + break; + case 'Y': + val = date_get_num(&p, 0, 9999, 4); + if (val == -1) + return NULL; + dt->tm_year = val - 1900; + break; + case 'm': + val = date_get_num(&p, 1, 12, 2); + if (val == -1) + return NULL; + dt->tm_mon = val - 1; + break; + case 'd': + val = date_get_num(&p, 1, 31, 2); + if (val == -1) + return NULL; + dt->tm_mday = val; + break; + case 'T': + p = av_small_strptime(p, "%H:%M:%S", dt); + if (!p) + return NULL; + break; + case 'b': + case 'B': + case 'h': + val = date_get_month(&p); + if (val == -1) + return NULL; + dt->tm_mon = val; + break; + case '%': + if (*p++ != '%') + return NULL; + break; + default: + return NULL; + } + } + + return (char*)p; +} + +time_t av_timegm(struct tm *tm) +{ + time_t t; + + int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday; + + if (m < 3) { + m += 12; + y--; + } + + t = 86400LL * + (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469); + + t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec; + + return t; +} + +int av_parse_time(int64_t *timeval, const char *timestr, int duration) +{ + const char *p, *q; + int64_t t, now64; + time_t now; + struct tm dt = { 0 }, tmbuf; + int today = 0, negative = 0, microseconds = 0, suffix = 1000000; + int i; + static const char * const date_fmt[] = { + "%Y - %m - %d", + "%Y%m%d", + }; + static const char * const time_fmt[] = { + "%H:%M:%S", + "%H%M%S", + }; + static const char * const tz_fmt[] = { + "%H:%M", + "%H%M", + "%H", + }; + + p = timestr; + q = NULL; + *timeval = INT64_MIN; + if (!duration) { + now64 = av_gettime(); + now = now64 / 1000000; + + if (!av_strcasecmp(timestr, "now")) { + *timeval = now64; + return 0; + } + + /* parse the year-month-day part */ + for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) { + q = av_small_strptime(p, date_fmt[i], &dt); + if (q) + break; + } + + /* if the year-month-day part is missing, then take the + * current year-month-day time */ + if (!q) { + today = 1; + q = p; + } + p = q; + + if (*p == 'T' || *p == 't') + p++; + else + while (av_isspace(*p)) + p++; + + /* parse the hour-minute-second part */ + for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) { + q = av_small_strptime(p, time_fmt[i], &dt); + if (q) + break; + } + } else { + /* parse timestr as a duration */ + if (p[0] == '-') { + negative = 1; + ++p; + } + /* parse timestr as HH:MM:SS */ + q = av_small_strptime(p, "%J:%M:%S", &dt); + if (!q) { + /* parse timestr as MM:SS */ + q = av_small_strptime(p, "%M:%S", &dt); + dt.tm_hour = 0; + } + if (!q) { + char *o; + /* parse timestr as S+ */ + errno = 0; + t = strtoll(p, &o, 10); + if (o == p) /* the parsing didn't succeed */ + return AVERROR(EINVAL); + if (errno == ERANGE) + return AVERROR(ERANGE); + q = o; + } else { + t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec; + } + } + + /* Now we have all the fields that we can get */ + if (!q) + return AVERROR(EINVAL); + + /* parse the .m... part */ + if (*q == '.') { + int n; + q++; + for (n = 100000; n >= 1; n /= 10, q++) { + if (!av_isdigit(*q)) + break; + microseconds += n * (*q - '0'); + } + while (av_isdigit(*q)) + q++; + } + + if (duration) { + if (q[0] == 'm' && q[1] == 's') { + suffix = 1000; + microseconds /= 1000; + q += 2; + } else if (q[0] == 'u' && q[1] == 's') { + suffix = 1; + microseconds = 0; + q += 2; + } else if (*q == 's') + q++; + } else { + int is_utc = *q == 'Z' || *q == 'z'; + int tzoffset = 0; + q += is_utc; + if (!today && !is_utc && (*q == '+' || *q == '-')) { + struct tm tz = { 0 }; + int sign = (*q == '+' ? -1 : 1); + q++; + p = q; + for (i = 0; i < FF_ARRAY_ELEMS(tz_fmt); i++) { + q = av_small_strptime(p, tz_fmt[i], &tz); + if (q) + break; + } + if (!q) + return AVERROR(EINVAL); + tzoffset = sign * (tz.tm_hour * 60 + tz.tm_min) * 60; + is_utc = 1; + } + if (today) { /* fill in today's date */ + struct tm dt2 = is_utc ? *gmtime_r(&now, &tmbuf) : *localtime_r(&now, &tmbuf); + dt2.tm_hour = dt.tm_hour; + dt2.tm_min = dt.tm_min; + dt2.tm_sec = dt.tm_sec; + dt = dt2; + } + dt.tm_isdst = is_utc ? 0 : -1; + t = is_utc ? av_timegm(&dt) : mktime(&dt); + t += tzoffset; + } + + /* Check that we are at the end of the string */ + if (*q) + return AVERROR(EINVAL); + + if (INT64_MAX / suffix < t) + return AVERROR(ERANGE); + t *= suffix; + if (INT64_MAX - microseconds < t) + return AVERROR(ERANGE); + t += microseconds; + *timeval = negative ? -t : t; + return 0; +} + +int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info) +{ + const char *p; + char tag[128], *q; + + p = info; + if (*p == '?') + p++; + for(;;) { + q = tag; + while (*p != '\0' && *p != '=' && *p != '&') { + if ((q - tag) < sizeof(tag) - 1) + *q++ = *p; + p++; + } + *q = '\0'; + q = arg; + if (*p == '=') { + p++; + while (*p != '&' && *p != '\0') { + if ((q - arg) < arg_size - 1) { + if (*p == '+') + *q++ = ' '; + else + *q++ = *p; + } + p++; + } + } + *q = '\0'; + if (!strcmp(tag, tag1)) + return 1; + if (*p != '&') + break; + p++; + } + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/parseutils.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/parseutils.h new file mode 100644 index 0000000000..e66d24b76e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/parseutils.h @@ -0,0 +1,193 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PARSEUTILS_H +#define AVUTIL_PARSEUTILS_H + +#include + +#include "rational.h" + +/** + * @file + * misc parsing utilities + */ + +/** + * Parse str and store the parsed ratio in q. + * + * Note that a ratio with infinite (1/0) or negative value is + * considered valid, so you should check on the returned value if you + * want to exclude those values. + * + * The undefined value can be expressed using the "0:0" string. + * + * @param[in,out] q pointer to the AVRational which will contain the ratio + * @param[in] str the string to parse: it has to be a string in the format + * num:den, a float number or an expression + * @param[in] max the maximum allowed numerator and denominator + * @param[in] log_offset log level offset which is applied to the log + * level of log_ctx + * @param[in] log_ctx parent logging context + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_ratio(AVRational *q, const char *str, int max, + int log_offset, void *log_ctx); + +#define av_parse_ratio_quiet(rate, str, max) \ + av_parse_ratio(rate, str, max, AV_LOG_MAX_OFFSET, NULL) + +/** + * Parse str and put in width_ptr and height_ptr the detected values. + * + * @param[in,out] width_ptr pointer to the variable which will contain the detected + * width value + * @param[in,out] height_ptr pointer to the variable which will contain the detected + * height value + * @param[in] str the string to parse: it has to be a string in the format + * width x height or a valid video size abbreviation. + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str); + +/** + * Parse str and store the detected values in *rate. + * + * @param[in,out] rate pointer to the AVRational which will contain the detected + * frame rate + * @param[in] str the string to parse: it has to be a string in the format + * rate_num / rate_den, a float number or a valid video rate abbreviation + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_rate(AVRational *rate, const char *str); + +/** + * Put the RGBA values that correspond to color_string in rgba_color. + * + * @param color_string a string specifying a color. It can be the name of + * a color (case insensitive match) or a [0x|#]RRGGBB[AA] sequence, + * possibly followed by "@" and a string representing the alpha + * component. + * The alpha component may be a string composed by "0x" followed by an + * hexadecimal number or a decimal number between 0.0 and 1.0, which + * represents the opacity value (0x00/0.0 means completely transparent, + * 0xff/1.0 completely opaque). + * If the alpha component is not specified then 0xff is assumed. + * The string "random" will result in a random color. + * @param slen length of the initial part of color_string containing the + * color. It can be set to -1 if color_string is a null terminated string + * containing nothing else than the color. + * @return >= 0 in case of success, a negative value in case of + * failure (for example if color_string cannot be parsed). + */ +int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, + void *log_ctx); + +/** + * Get the name of a color from the internal table of hard-coded named + * colors. + * + * This function is meant to enumerate the color names recognized by + * av_parse_color(). + * + * @param color_idx index of the requested color, starting from 0 + * @param rgbp if not NULL, will point to a 3-elements array with the color value in RGB + * @return the color name string or NULL if color_idx is not in the array + */ +const char *av_get_known_color_name(int color_idx, const uint8_t **rgb); + +/** + * Parse timestr and return in *time a corresponding number of + * microseconds. + * + * @param timeval puts here the number of microseconds corresponding + * to the string in timestr. If the string represents a duration, it + * is the number of microseconds contained in the time interval. If + * the string is a date, is the number of microseconds since 1st of + * January, 1970 up to the time of the parsed date. If timestr cannot + * be successfully parsed, set *time to INT64_MIN. + + * @param timestr a string representing a date or a duration. + * - If a date the syntax is: + * @code + * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH:MM:SS[.m...]]]}|{HHMMSS[.m...]]]}}[Z] + * now + * @endcode + * If the value is "now" it takes the current time. + * Time is local time unless Z is appended, in which case it is + * interpreted as UTC. + * If the year-month-day part is not specified it takes the current + * year-month-day. + * - If a duration the syntax is: + * @code + * [-][HH:]MM:SS[.m...] + * [-]S+[.m...] + * @endcode + * @param duration flag which tells how to interpret timestr, if not + * zero timestr is interpreted as a duration, otherwise as a date + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_parse_time(int64_t *timeval, const char *timestr, int duration); + +/** + * Attempt to find a specific tag in a URL. + * + * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. + * Return 1 if found. + */ +int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); + +/** + * Simplified version of strptime + * + * Parse the input string p according to the format string fmt and + * store its results in the structure dt. + * This implementation supports only a subset of the formats supported + * by the standard strptime(). + * + * The supported input field descriptors are listed below. + * - %H: the hour as a decimal number, using a 24-hour clock, in the + * range '00' through '23' + * - %J: hours as a decimal number, in the range '0' through INT_MAX + * - %M: the minute as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %S: the second as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %Y: the year as a decimal number, using the Gregorian calendar + * - %m: the month as a decimal number, in the range '1' through '12' + * - %d: the day of the month as a decimal number, in the range '1' + * through '31' + * - %T: alias for '%H:%M:%S' + * - %%: a literal '%' + * + * @return a pointer to the first character not processed in this function + * call. In case the input string contains more characters than + * required by the format string the return value points right after + * the last consumed input character. In case the whole input string + * is consumed the return value points to the null byte at the end of + * the string. On failure NULL is returned. + */ +char *av_small_strptime(const char *p, const char *fmt, struct tm *dt); + +/** + * Convert the decomposed UTC time in tm to a time_t value. + */ +time_t av_timegm(struct tm *tm); + +#endif /* AVUTIL_PARSEUTILS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixdesc.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixdesc.c new file mode 100644 index 0000000000..b97b0665b0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixdesc.c @@ -0,0 +1,2961 @@ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "avassert.h" +#include "avstring.h" +#include "common.h" +#include "pixfmt.h" +#include "pixdesc.h" +#include "internal.h" +#include "intreadwrite.h" +#include "version.h" + +void av_read_image_line2(void *dst, + const uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, + int read_pal_component, + int dst_element_size) +{ + AVComponentDescriptor comp = desc->comp[c]; + int plane = comp.plane; + int depth = comp.depth; + unsigned mask = (1ULL << depth) - 1; + int shift = comp.shift; + int step = comp.step; + int flags = desc->flags; + uint16_t *dst16 = dst; + uint32_t *dst32 = dst; + + if (flags & AV_PIX_FMT_FLAG_BITSTREAM) { + int skip = x * step + comp.offset; + const uint8_t *p = data[plane] + y * linesize[plane] + (skip >> 3); + int shift = 8 - depth - (skip & 7); + + while (w--) { + int val = (*p >> shift) & mask; + if (read_pal_component) + val = data[1][4*val + c]; + shift -= step; + p -= shift >> 3; + shift &= 7; + if (dst_element_size == 4) *dst32++ = val; + else *dst16++ = val; + } + } else { + const uint8_t *p = data[plane] + y * linesize[plane] + + x * step + comp.offset; + int is_8bit = shift + depth <= 8; + int is_16bit= shift + depth <=16; + + if (is_8bit) + p += !!(flags & AV_PIX_FMT_FLAG_BE); + + while (w--) { + unsigned val; + if (is_8bit) val = *p; + else if(is_16bit) val = flags & AV_PIX_FMT_FLAG_BE ? AV_RB16(p) : AV_RL16(p); + else val = flags & AV_PIX_FMT_FLAG_BE ? AV_RB32(p) : AV_RL32(p); + val = (val >> shift) & mask; + if (read_pal_component) + val = data[1][4 * val + c]; + p += step; + if (dst_element_size == 4) *dst32++ = val; + else *dst16++ = val; + } + } +} + +void av_read_image_line(uint16_t *dst, + const uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, + int read_pal_component) +{ + av_read_image_line2(dst, data, linesize, desc,x, y, c, w, + read_pal_component, + 2); +} + +void av_write_image_line2(const void *src, + uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int src_element_size) +{ + AVComponentDescriptor comp = desc->comp[c]; + int plane = comp.plane; + int depth = comp.depth; + int step = comp.step; + int flags = desc->flags; + const uint32_t *src32 = src; + const uint16_t *src16 = src; + + if (flags & AV_PIX_FMT_FLAG_BITSTREAM) { + int skip = x * step + comp.offset; + uint8_t *p = data[plane] + y * linesize[plane] + (skip >> 3); + int shift = 8 - depth - (skip & 7); + + while (w--) { + *p |= (src_element_size == 4 ? *src32++ : *src16++) << shift; + shift -= step; + p -= shift >> 3; + shift &= 7; + } + } else { + int shift = comp.shift; + uint8_t *p = data[plane] + y * linesize[plane] + + x * step + comp.offset; + + if (shift + depth <= 8) { + p += !!(flags & AV_PIX_FMT_FLAG_BE); + while (w--) { + *p |= ((src_element_size == 4 ? *src32++ : *src16++) << shift); + p += step; + } + } else { + while (w--) { + unsigned s = (src_element_size == 4 ? *src32++ : *src16++); + if (shift + depth <= 16) { + if (flags & AV_PIX_FMT_FLAG_BE) { + uint16_t val = AV_RB16(p) | (s << shift); + AV_WB16(p, val); + } else { + uint16_t val = AV_RL16(p) | (s << shift); + AV_WL16(p, val); + } + } else { + if (flags & AV_PIX_FMT_FLAG_BE) { + uint32_t val = AV_RB32(p) | (s << shift); + AV_WB32(p, val); + } else { + uint32_t val = AV_RL32(p) | (s << shift); + AV_WL32(p, val); + } + } + p += step; + } + } + } +} + +void av_write_image_line(const uint16_t *src, + uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w) +{ + av_write_image_line2(src, data, linesize, desc, x, y, c, w, 2); +} + +#if FF_API_PLUS1_MINUS1 +FF_DISABLE_DEPRECATION_WARNINGS +#endif +static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { + [AV_PIX_FMT_YUV420P] = { + .name = "yuv420p", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUYV422] = { + .name = "yuyv422", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 8, 1, 7, 1 }, /* Y */ + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* U */ + { 0, 4, 3, 0, 8, 3, 7, 4 }, /* V */ + }, + }, + [AV_PIX_FMT_YVYU422] = { + .name = "yvyu422", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 8, 1, 7, 1 }, /* Y */ + { 0, 4, 3, 0, 8, 3, 7, 4 }, /* U */ + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* V */ + }, + }, + [AV_PIX_FMT_RGB24] = { + .name = "rgb24", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 3, 0, 0, 8, 2, 7, 1 }, /* R */ + { 0, 3, 1, 0, 8, 2, 7, 2 }, /* G */ + { 0, 3, 2, 0, 8, 2, 7, 3 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR24] = { + .name = "bgr24", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 3, 2, 0, 8, 2, 7, 3 }, /* R */ + { 0, 3, 1, 0, 8, 2, 7, 2 }, /* G */ + { 0, 3, 0, 0, 8, 2, 7, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_YUV422P] = { + .name = "yuv422p", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P] = { + .name = "yuv444p", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV410P] = { + .name = "yuv410p", + .nb_components = 3, + .log2_chroma_w = 2, + .log2_chroma_h = 2, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV411P] = { + .name = "yuv411p", + .nb_components = 3, + .log2_chroma_w = 2, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUVJ411P] = { + .name = "yuvj411p", + .nb_components = 3, + .log2_chroma_w = 2, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_GRAY8] = { + .name = "gray", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + }, + .flags = FF_PSEUDOPAL, + .alias = "gray8,y8", + }, + [AV_PIX_FMT_MONOWHITE] = { + .name = "monow", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 1, 0, 0, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BITSTREAM, + }, + [AV_PIX_FMT_MONOBLACK] = { + .name = "monob", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 7, 1, 0, 0, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BITSTREAM, + }, + [AV_PIX_FMT_PAL8] = { + .name = "pal8", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, + }, + .flags = AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVJ420P] = { + .name = "yuvj420p", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUVJ422P] = { + .name = "yuvj422p", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUVJ444P] = { + .name = "yuvj444p", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_XVMC] = { + .name = "xvmc", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_UYVY422] = { + .name = "uyvy422", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 1, 0, 8, 1, 7, 2 }, /* Y */ + { 0, 4, 0, 0, 8, 3, 7, 1 }, /* U */ + { 0, 4, 2, 0, 8, 3, 7, 3 }, /* V */ + }, + }, + [AV_PIX_FMT_UYYVYY411] = { + .name = "uyyvyy411", + .nb_components = 3, + .log2_chroma_w = 2, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* Y */ + { 0, 6, 0, 0, 8, 5, 7, 1 }, /* U */ + { 0, 6, 3, 0, 8, 5, 7, 4 }, /* V */ + }, + }, + [AV_PIX_FMT_BGR8] = { + .name = "bgr8", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 3, 0, 2, 1 }, /* R */ + { 0, 1, 0, 3, 3, 0, 2, 1 }, /* G */ + { 0, 1, 0, 6, 2, 0, 1, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL, + }, + [AV_PIX_FMT_BGR4] = { + .name = "bgr4", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 3, 0, 1, 3, 0, 4 }, /* R */ + { 0, 4, 1, 0, 2, 3, 1, 2 }, /* G */ + { 0, 4, 0, 0, 1, 3, 0, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR4_BYTE] = { + .name = "bgr4_byte", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 1, 0, 0, 1 }, /* R */ + { 0, 1, 0, 1, 2, 0, 1, 1 }, /* G */ + { 0, 1, 0, 3, 1, 0, 0, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL, + }, + [AV_PIX_FMT_RGB8] = { + .name = "rgb8", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 6, 2, 0, 1, 1 }, /* R */ + { 0, 1, 0, 3, 3, 0, 2, 1 }, /* G */ + { 0, 1, 0, 0, 3, 0, 2, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL, + }, + [AV_PIX_FMT_RGB4] = { + .name = "rgb4", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 1, 3, 0, 1 }, /* R */ + { 0, 4, 1, 0, 2, 3, 1, 2 }, /* G */ + { 0, 4, 3, 0, 1, 3, 0, 4 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB4_BYTE] = { + .name = "rgb4_byte", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 3, 1, 0, 0, 1 }, /* R */ + { 0, 1, 0, 1, 2, 0, 1, 1 }, /* G */ + { 0, 1, 0, 0, 1, 0, 0, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL, + }, + [AV_PIX_FMT_NV12] = { + .name = "nv12", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 2, 0, 0, 8, 1, 7, 1 }, /* U */ + { 1, 2, 1, 0, 8, 1, 7, 2 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_NV21] = { + .name = "nv21", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 2, 1, 0, 8, 1, 7, 2 }, /* U */ + { 1, 2, 0, 0, 8, 1, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_ARGB] = { + .name = "argb", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* R */ + { 0, 4, 2, 0, 8, 3, 7, 3 }, /* G */ + { 0, 4, 3, 0, 8, 3, 7, 4 }, /* B */ + { 0, 4, 0, 0, 8, 3, 7, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGBA] = { + .name = "rgba", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 8, 3, 7, 1 }, /* R */ + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* G */ + { 0, 4, 2, 0, 8, 3, 7, 3 }, /* B */ + { 0, 4, 3, 0, 8, 3, 7, 4 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_ABGR] = { + .name = "abgr", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 3, 0, 8, 3, 7, 4 }, /* R */ + { 0, 4, 2, 0, 8, 3, 7, 3 }, /* G */ + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* B */ + { 0, 4, 0, 0, 8, 3, 7, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_BGRA] = { + .name = "bgra", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 2, 0, 8, 3, 7, 3 }, /* R */ + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* G */ + { 0, 4, 0, 0, 8, 3, 7, 1 }, /* B */ + { 0, 4, 3, 0, 8, 3, 7, 4 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_0RGB] = { + .name = "0rgb", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* R */ + { 0, 4, 2, 0, 8, 3, 7, 3 }, /* G */ + { 0, 4, 3, 0, 8, 3, 7, 4 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB0] = { + .name = "rgb0", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 0, 0, 8, 3, 7, 1 }, /* R */ + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* G */ + { 0, 4, 2, 0, 8, 3, 7, 3 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_0BGR] = { + .name = "0bgr", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 3, 0, 8, 3, 7, 4 }, /* R */ + { 0, 4, 2, 0, 8, 3, 7, 3 }, /* G */ + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR0] = { + .name = "bgr0", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 2, 0, 8, 3, 7, 3 }, /* R */ + { 0, 4, 1, 0, 8, 3, 7, 2 }, /* G */ + { 0, 4, 0, 0, 8, 3, 7, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GRAY9BE] = { + .name = "gray9be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y9be", + }, + [AV_PIX_FMT_GRAY9LE] = { + .name = "gray9le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + }, + .alias = "y9le", + }, + [AV_PIX_FMT_GRAY10BE] = { + .name = "gray10be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y10be", + }, + [AV_PIX_FMT_GRAY10LE] = { + .name = "gray10le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + }, + .alias = "y10le", + }, + [AV_PIX_FMT_GRAY12BE] = { + .name = "gray12be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y12be", + }, + [AV_PIX_FMT_GRAY12LE] = { + .name = "gray12le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + }, + .alias = "y12le", + }, + [AV_PIX_FMT_GRAY14BE] = { + .name = "gray14be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y14be", + }, + [AV_PIX_FMT_GRAY14LE] = { + .name = "gray14le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* Y */ + }, + .alias = "y14le", + }, + [AV_PIX_FMT_GRAY16BE] = { + .name = "gray16be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y16be", + }, + [AV_PIX_FMT_GRAY16LE] = { + .name = "gray16le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + }, + .alias = "y16le", + }, + [AV_PIX_FMT_YUV440P] = { + .name = "yuv440p", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUVJ440P] = { + .name = "yuvj440p", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV440P10LE] = { + .name = "yuv440p10le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV440P10BE] = { + .name = "yuv440p10be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV440P12LE] = { + .name = "yuv440p12le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV440P12BE] = { + .name = "yuv440p12be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUVA420P] = { + .name = "yuva420p", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + { 3, 1, 0, 0, 8, 0, 7, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P] = { + .name = "yuva422p", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + { 3, 1, 0, 0, 8, 0, 7, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P] = { + .name = "yuva444p", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* U */ + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* V */ + { 3, 1, 0, 0, 8, 0, 7, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P9BE] = { + .name = "yuva420p9be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + { 3, 2, 0, 0, 9, 1, 8, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P9LE] = { + .name = "yuva420p9le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + { 3, 2, 0, 0, 9, 1, 8, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P9BE] = { + .name = "yuva422p9be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + { 3, 2, 0, 0, 9, 1, 8, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P9LE] = { + .name = "yuva422p9le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + { 3, 2, 0, 0, 9, 1, 8, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P9BE] = { + .name = "yuva444p9be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + { 3, 2, 0, 0, 9, 1, 8, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P9LE] = { + .name = "yuva444p9le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + { 3, 2, 0, 0, 9, 1, 8, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P10BE] = { + .name = "yuva420p10be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P10LE] = { + .name = "yuva420p10le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P10BE] = { + .name = "yuva422p10be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P10LE] = { + .name = "yuva422p10le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P10BE] = { + .name = "yuva444p10be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P10LE] = { + .name = "yuva444p10le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P16BE] = { + .name = "yuva420p16be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + { 3, 2, 0, 0, 16, 1, 15, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P16LE] = { + .name = "yuva420p16le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + { 3, 2, 0, 0, 16, 1, 15, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P16BE] = { + .name = "yuva422p16be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + { 3, 2, 0, 0, 16, 1, 15, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P16LE] = { + .name = "yuva422p16le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + { 3, 2, 0, 0, 16, 1, 15, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P16BE] = { + .name = "yuva444p16be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + { 3, 2, 0, 0, 16, 1, 15, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P16LE] = { + .name = "yuva444p16le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + { 3, 2, 0, 0, 16, 1, 15, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGB48BE] = { + .name = "rgb48be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 0, 0, 16, 5, 15, 1 }, /* R */ + { 0, 6, 2, 0, 16, 5, 15, 3 }, /* G */ + { 0, 6, 4, 0, 16, 5, 15, 5 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_RGB48LE] = { + .name = "rgb48le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 0, 0, 16, 5, 15, 1 }, /* R */ + { 0, 6, 2, 0, 16, 5, 15, 3 }, /* G */ + { 0, 6, 4, 0, 16, 5, 15, 5 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGBA64BE] = { + .name = "rgba64be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 0, 0, 16, 7, 15, 1 }, /* R */ + { 0, 8, 2, 0, 16, 7, 15, 3 }, /* G */ + { 0, 8, 4, 0, 16, 7, 15, 5 }, /* B */ + { 0, 8, 6, 0, 16, 7, 15, 7 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGBA64LE] = { + .name = "rgba64le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 0, 0, 16, 7, 15, 1 }, /* R */ + { 0, 8, 2, 0, 16, 7, 15, 3 }, /* G */ + { 0, 8, 4, 0, 16, 7, 15, 5 }, /* B */ + { 0, 8, 6, 0, 16, 7, 15, 7 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGB565BE] = { + .name = "rgb565be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, -1, 3, 5, 1, 4, 0 }, /* R */ + { 0, 2, 0, 5, 6, 1, 5, 1 }, /* G */ + { 0, 2, 0, 0, 5, 1, 4, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB565LE] = { + .name = "rgb565le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 1, 3, 5, 1, 4, 2 }, /* R */ + { 0, 2, 0, 5, 6, 1, 5, 1 }, /* G */ + { 0, 2, 0, 0, 5, 1, 4, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB555BE] = { + .name = "rgb555be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, -1, 2, 5, 1, 4, 0 }, /* R */ + { 0, 2, 0, 5, 5, 1, 4, 1 }, /* G */ + { 0, 2, 0, 0, 5, 1, 4, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB555LE] = { + .name = "rgb555le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 1, 2, 5, 1, 4, 2 }, /* R */ + { 0, 2, 0, 5, 5, 1, 4, 1 }, /* G */ + { 0, 2, 0, 0, 5, 1, 4, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB444BE] = { + .name = "rgb444be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, -1, 0, 4, 1, 3, 0 }, /* R */ + { 0, 2, 0, 4, 4, 1, 3, 1 }, /* G */ + { 0, 2, 0, 0, 4, 1, 3, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB444LE] = { + .name = "rgb444le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 1, 0, 4, 1, 3, 2 }, /* R */ + { 0, 2, 0, 4, 4, 1, 3, 1 }, /* G */ + { 0, 2, 0, 0, 4, 1, 3, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR48BE] = { + .name = "bgr48be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 4, 0, 16, 5, 15, 5 }, /* R */ + { 0, 6, 2, 0, 16, 5, 15, 3 }, /* G */ + { 0, 6, 0, 0, 16, 5, 15, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR48LE] = { + .name = "bgr48le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 4, 0, 16, 5, 15, 5 }, /* R */ + { 0, 6, 2, 0, 16, 5, 15, 3 }, /* G */ + { 0, 6, 0, 0, 16, 5, 15, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGRA64BE] = { + .name = "bgra64be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 4, 0, 16, 7, 15, 5 }, /* R */ + { 0, 8, 2, 0, 16, 7, 15, 3 }, /* G */ + { 0, 8, 0, 0, 16, 7, 15, 1 }, /* B */ + { 0, 8, 6, 0, 16, 7, 15, 7 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_BGRA64LE] = { + .name = "bgra64le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 4, 0, 16, 7, 15, 5 }, /* R */ + { 0, 8, 2, 0, 16, 7, 15, 3 }, /* G */ + { 0, 8, 0, 0, 16, 7, 15, 1 }, /* B */ + { 0, 8, 6, 0, 16, 7, 15, 7 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_BGR565BE] = { + .name = "bgr565be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 5, 1, 4, 1 }, /* R */ + { 0, 2, 0, 5, 6, 1, 5, 1 }, /* G */ + { 0, 2, -1, 3, 5, 1, 4, 0 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR565LE] = { + .name = "bgr565le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 5, 1, 4, 1 }, /* R */ + { 0, 2, 0, 5, 6, 1, 5, 1 }, /* G */ + { 0, 2, 1, 3, 5, 1, 4, 2 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR555BE] = { + .name = "bgr555be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 5, 1, 4, 1 }, /* R */ + { 0, 2, 0, 5, 5, 1, 4, 1 }, /* G */ + { 0, 2, -1, 2, 5, 1, 4, 0 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR555LE] = { + .name = "bgr555le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 5, 1, 4, 1 }, /* R */ + { 0, 2, 0, 5, 5, 1, 4, 1 }, /* G */ + { 0, 2, 1, 2, 5, 1, 4, 2 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR444BE] = { + .name = "bgr444be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 4, 1, 3, 1 }, /* R */ + { 0, 2, 0, 4, 4, 1, 3, 1 }, /* G */ + { 0, 2, -1, 0, 4, 1, 3, 0 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR444LE] = { + .name = "bgr444le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 4, 1, 3, 1 }, /* R */ + { 0, 2, 0, 4, 4, 1, 3, 1 }, /* G */ + { 0, 2, 1, 0, 4, 1, 3, 2 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, +#if FF_API_VAAPI + [AV_PIX_FMT_VAAPI_MOCO] = { + .name = "vaapi_moco", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_VAAPI_IDCT] = { + .name = "vaapi_idct", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_VAAPI_VLD] = { + .name = "vaapi_vld", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, +#else + [AV_PIX_FMT_VAAPI] = { + .name = "vaapi", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, +#endif + [AV_PIX_FMT_YUV420P9LE] = { + .name = "yuv420p9le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P9BE] = { + .name = "yuv420p9be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P10LE] = { + .name = "yuv420p10le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P10BE] = { + .name = "yuv420p10be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P12LE] = { + .name = "yuv420p12le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P12BE] = { + .name = "yuv420p12be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P14LE] = { + .name = "yuv420p14le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* Y */ + { 1, 2, 0, 0, 14, 1, 13, 1 }, /* U */ + { 2, 2, 0, 0, 14, 1, 13, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P14BE] = { + .name = "yuv420p14be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* Y */ + { 1, 2, 0, 0, 14, 1, 13, 1 }, /* U */ + { 2, 2, 0, 0, 14, 1, 13, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P16LE] = { + .name = "yuv420p16le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P16BE] = { + .name = "yuv420p16be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P9LE] = { + .name = "yuv422p9le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P9BE] = { + .name = "yuv422p9be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P10LE] = { + .name = "yuv422p10le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P10BE] = { + .name = "yuv422p10be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P12LE] = { + .name = "yuv422p12le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P12BE] = { + .name = "yuv422p12be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P14LE] = { + .name = "yuv422p14le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* Y */ + { 1, 2, 0, 0, 14, 1, 13, 1 }, /* U */ + { 2, 2, 0, 0, 14, 1, 13, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P14BE] = { + .name = "yuv422p14be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* Y */ + { 1, 2, 0, 0, 14, 1, 13, 1 }, /* U */ + { 2, 2, 0, 0, 14, 1, 13, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P16LE] = { + .name = "yuv422p16le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P16BE] = { + .name = "yuv422p16be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P16LE] = { + .name = "yuv444p16le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P16BE] = { + .name = "yuv444p16be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* U */ + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P10LE] = { + .name = "yuv444p10le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P10BE] = { + .name = "yuv444p10be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* U */ + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P9LE] = { + .name = "yuv444p9le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P9BE] = { + .name = "yuv444p9be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* Y */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* U */ + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P12LE] = { + .name = "yuv444p12le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P12BE] = { + .name = "yuv444p12be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P14LE] = { + .name = "yuv444p14le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* Y */ + { 1, 2, 0, 0, 14, 1, 13, 1 }, /* U */ + { 2, 2, 0, 0, 14, 1, 13, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P14BE] = { + .name = "yuv444p14be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* Y */ + { 1, 2, 0, 0, 14, 1, 13, 1 }, /* U */ + { 2, 2, 0, 0, 14, 1, 13, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_D3D11VA_VLD] = { + .name = "d3d11va_vld", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_DXVA2_VLD] = { + .name = "dxva2_vld", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_YA8] = { + .name = "ya8", + .nb_components = 2, + .comp = { + { 0, 2, 0, 0, 8, 1, 7, 1 }, /* Y */ + { 0, 2, 1, 0, 8, 1, 7, 2 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_ALPHA, + .alias = "gray8a", + }, + [AV_PIX_FMT_YA16LE] = { + .name = "ya16le", + .nb_components = 2, + .comp = { + { 0, 4, 0, 0, 16, 3, 15, 1 }, /* Y */ + { 0, 4, 2, 0, 16, 3, 15, 3 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YA16BE] = { + .name = "ya16be", + .nb_components = 2, + .comp = { + { 0, 4, 0, 0, 16, 3, 15, 1 }, /* Y */ + { 0, 4, 2, 0, 16, 3, 15, 3 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_VIDEOTOOLBOX] = { + .name = "videotoolbox_vld", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_GBRP] = { + .name = "gbrp", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* R */ + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* G */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP9LE] = { + .name = "gbrp9le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* R */ + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* G */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP9BE] = { + .name = "gbrp9be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 9, 1, 8, 1 }, /* R */ + { 0, 2, 0, 0, 9, 1, 8, 1 }, /* G */ + { 1, 2, 0, 0, 9, 1, 8, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP10LE] = { + .name = "gbrp10le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* R */ + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* G */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP10BE] = { + .name = "gbrp10be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* R */ + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* G */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP12LE] = { + .name = "gbrp12le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* R */ + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* G */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP12BE] = { + .name = "gbrp12be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* R */ + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* G */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP14LE] = { + .name = "gbrp14le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 14, 1, 13, 1 }, /* R */ + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* G */ + { 1, 2, 0, 0, 14, 1, 13, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP14BE] = { + .name = "gbrp14be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 14, 1, 13, 1 }, /* R */ + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* G */ + { 1, 2, 0, 0, 14, 1, 13, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP16LE] = { + .name = "gbrp16le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* R */ + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* G */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP16BE] = { + .name = "gbrp16be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* R */ + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* G */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRAP] = { + .name = "gbrap", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 1, 0, 0, 8, 0, 7, 1 }, /* R */ + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* G */ + { 1, 1, 0, 0, 8, 0, 7, 1 }, /* B */ + { 3, 1, 0, 0, 8, 0, 7, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP16LE] = { + .name = "gbrap16le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* R */ + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* G */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* B */ + { 3, 2, 0, 0, 16, 1, 15, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP16BE] = { + .name = "gbrap16be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16, 1, 15, 1 }, /* R */ + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* G */ + { 1, 2, 0, 0, 16, 1, 15, 1 }, /* B */ + { 3, 2, 0, 0, 16, 1, 15, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_VDPAU] = { + .name = "vdpau", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_XYZ12LE] = { + .name = "xyz12le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 0, 4, 12, 5, 11, 1 }, /* X */ + { 0, 6, 2, 4, 12, 5, 11, 3 }, /* Y */ + { 0, 6, 4, 4, 12, 5, 11, 5 }, /* Z */ + }, + /*.flags = -- not used*/ + }, + [AV_PIX_FMT_XYZ12BE] = { + .name = "xyz12be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 0, 4, 12, 5, 11, 1 }, /* X */ + { 0, 6, 2, 4, 12, 5, 11, 3 }, /* Y */ + { 0, 6, 4, 4, 12, 5, 11, 5 }, /* Z */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + }, + +#define BAYER8_DESC_COMMON \ + .nb_components= 3, \ + .log2_chroma_w= 0, \ + .log2_chroma_h= 0, \ + .comp = { \ + {0,1,0,0,2,0,1,1},\ + {0,1,0,0,4,0,3,1},\ + {0,1,0,0,2,0,1,1},\ + }, \ + +#define BAYER16_DESC_COMMON \ + .nb_components= 3, \ + .log2_chroma_w= 0, \ + .log2_chroma_h= 0, \ + .comp = { \ + {0,2,0,0,4,1,3,1},\ + {0,2,0,0,8,1,7,1},\ + {0,2,0,0,4,1,3,1},\ + }, \ + + [AV_PIX_FMT_BAYER_BGGR8] = { + .name = "bayer_bggr8", + BAYER8_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_BGGR16LE] = { + .name = "bayer_bggr16le", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_BGGR16BE] = { + .name = "bayer_bggr16be", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_RGGB8] = { + .name = "bayer_rggb8", + BAYER8_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_RGGB16LE] = { + .name = "bayer_rggb16le", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_RGGB16BE] = { + .name = "bayer_rggb16be", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GBRG8] = { + .name = "bayer_gbrg8", + BAYER8_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GBRG16LE] = { + .name = "bayer_gbrg16le", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GBRG16BE] = { + .name = "bayer_gbrg16be", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GRBG8] = { + .name = "bayer_grbg8", + BAYER8_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GRBG16LE] = { + .name = "bayer_grbg16le", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GRBG16BE] = { + .name = "bayer_grbg16be", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_NV16] = { + .name = "nv16", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 2, 0, 0, 8, 1, 7, 1 }, /* U */ + { 1, 2, 1, 0, 8, 1, 7, 2 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_NV20LE] = { + .name = "nv20le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 4, 0, 0, 10, 3, 9, 1 }, /* U */ + { 1, 4, 2, 0, 10, 3, 9, 3 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_NV20BE] = { + .name = "nv20be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* Y */ + { 1, 4, 0, 0, 10, 3, 9, 1 }, /* U */ + { 1, 4, 2, 0, 10, 3, 9, 3 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_QSV] = { + .name = "qsv", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_MEDIACODEC] = { + .name = "mediacodec", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_MMAL] = { + .name = "mmal", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_CUDA] = { + .name = "cuda", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_AYUV64LE] = { + .name = "ayuv64le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 2, 0, 16, 7, 15, 3 }, /* Y */ + { 0, 8, 4, 0, 16, 7, 15, 5 }, /* U */ + { 0, 8, 6, 0, 16, 7, 15, 7 }, /* V */ + { 0, 8, 0, 0, 16, 7, 15, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_AYUV64BE] = { + .name = "ayuv64be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 2, 0, 16, 7, 15, 3 }, /* Y */ + { 0, 8, 4, 0, 16, 7, 15, 5 }, /* U */ + { 0, 8, 6, 0, 16, 7, 15, 7 }, /* V */ + { 0, 8, 0, 0, 16, 7, 15, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_P010LE] = { + .name = "p010le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 6, 10, 1, 9, 1 }, /* Y */ + { 1, 4, 0, 6, 10, 3, 9, 1 }, /* U */ + { 1, 4, 2, 6, 10, 3, 9, 3 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_P010BE] = { + .name = "p010be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 6, 10, 1, 9, 1 }, /* Y */ + { 1, 4, 0, 6, 10, 3, 9, 1 }, /* U */ + { 1, 4, 2, 6, 10, 3, 9, 3 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_P016LE] = { + .name = "p016le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 4, 0, 0, 16, 3, 15, 1 }, /* U */ + { 1, 4, 2, 0, 16, 3, 15, 3 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_P016BE] = { + .name = "p016be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16, 1, 15, 1 }, /* Y */ + { 1, 4, 0, 0, 16, 3, 15, 1 }, /* U */ + { 1, 4, 2, 0, 16, 3, 15, 3 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_GBRAP12LE] = { + .name = "gbrap12le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* R */ + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* G */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* B */ + { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP12BE] = { + .name = "gbrap12be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* R */ + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* G */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* B */ + { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP10LE] = { + .name = "gbrap10le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* R */ + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* G */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* B */ + { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP10BE] = { + .name = "gbrap10be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 10, 1, 9, 1 }, /* R */ + { 0, 2, 0, 0, 10, 1, 9, 1 }, /* G */ + { 1, 2, 0, 0, 10, 1, 9, 1 }, /* B */ + { 3, 2, 0, 0, 10, 1, 9, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_D3D11] = { + .name = "d3d11", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_GBRPF32BE] = { + .name = "gbrpf32be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ + { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_GBRPF32LE] = { + .name = "gbrpf32le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ + { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_FLOAT | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRAPF32BE] = { + .name = "gbrapf32be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ + { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ + { 3, 4, 0, 0, 32, 3, 31, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_ALPHA | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_GBRAPF32LE] = { + .name = "gbrapf32le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32, 3, 31, 1 }, /* R */ + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* G */ + { 1, 4, 0, 0, 32, 3, 31, 1 }, /* B */ + { 3, 4, 0, 0, 32, 3, 31, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_DRM_PRIME] = { + .name = "drm_prime", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_OPENCL] = { + .name = "opencl", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_GRAYF32BE] = { + .name = "grayf32be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_FLOAT, + .alias = "yf32be", + }, + [AV_PIX_FMT_GRAYF32LE] = { + .name = "grayf32le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_FLOAT, + .alias = "yf32le", + }, + [AV_PIX_FMT_YUVA422P12BE] = { + .name = "yuva422p12be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P12LE] = { + .name = "yuva422p12le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P12BE] = { + .name = "yuva444p12be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P12LE] = { + .name = "yuva444p12le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_NV24] = { + .name = "nv24", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 2, 0, 0, 8, 1, 7, 1 }, /* U */ + { 1, 2, 1, 0, 8, 1, 7, 2 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_NV42] = { + .name = "nv42", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 2, 1, 0, 8, 1, 7, 2 }, /* U */ + { 1, 2, 0, 0, 8, 1, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, +}; +#if FF_API_PLUS1_MINUS1 +FF_ENABLE_DEPRECATION_WARNINGS +#endif + +static const char * const color_range_names[] = { + [AVCOL_RANGE_UNSPECIFIED] = "unknown", + [AVCOL_RANGE_MPEG] = "tv", + [AVCOL_RANGE_JPEG] = "pc", +}; + +static const char * const color_primaries_names[AVCOL_PRI_NB] = { + [AVCOL_PRI_RESERVED0] = "reserved", + [AVCOL_PRI_BT709] = "bt709", + [AVCOL_PRI_UNSPECIFIED] = "unknown", + [AVCOL_PRI_RESERVED] = "reserved", + [AVCOL_PRI_BT470M] = "bt470m", + [AVCOL_PRI_BT470BG] = "bt470bg", + [AVCOL_PRI_SMPTE170M] = "smpte170m", + [AVCOL_PRI_SMPTE240M] = "smpte240m", + [AVCOL_PRI_FILM] = "film", + [AVCOL_PRI_BT2020] = "bt2020", + [AVCOL_PRI_SMPTE428] = "smpte428", + [AVCOL_PRI_SMPTE431] = "smpte431", + [AVCOL_PRI_SMPTE432] = "smpte432", + [AVCOL_PRI_JEDEC_P22] = "jedec-p22", +}; + +static const char * const color_transfer_names[] = { + [AVCOL_TRC_RESERVED0] = "reserved", + [AVCOL_TRC_BT709] = "bt709", + [AVCOL_TRC_UNSPECIFIED] = "unknown", + [AVCOL_TRC_RESERVED] = "reserved", + [AVCOL_TRC_GAMMA22] = "bt470m", + [AVCOL_TRC_GAMMA28] = "bt470bg", + [AVCOL_TRC_SMPTE170M] = "smpte170m", + [AVCOL_TRC_SMPTE240M] = "smpte240m", + [AVCOL_TRC_LINEAR] = "linear", + [AVCOL_TRC_LOG] = "log100", + [AVCOL_TRC_LOG_SQRT] = "log316", + [AVCOL_TRC_IEC61966_2_4] = "iec61966-2-4", + [AVCOL_TRC_BT1361_ECG] = "bt1361e", + [AVCOL_TRC_IEC61966_2_1] = "iec61966-2-1", + [AVCOL_TRC_BT2020_10] = "bt2020-10", + [AVCOL_TRC_BT2020_12] = "bt2020-12", + [AVCOL_TRC_SMPTE2084] = "smpte2084", + [AVCOL_TRC_SMPTE428] = "smpte428", + [AVCOL_TRC_ARIB_STD_B67] = "arib-std-b67", +}; + +static const char * const color_space_names[] = { + [AVCOL_SPC_RGB] = "gbr", + [AVCOL_SPC_BT709] = "bt709", + [AVCOL_SPC_UNSPECIFIED] = "unknown", + [AVCOL_SPC_RESERVED] = "reserved", + [AVCOL_SPC_FCC] = "fcc", + [AVCOL_SPC_BT470BG] = "bt470bg", + [AVCOL_SPC_SMPTE170M] = "smpte170m", + [AVCOL_SPC_SMPTE240M] = "smpte240m", + [AVCOL_SPC_YCGCO] = "ycgco", + [AVCOL_SPC_BT2020_NCL] = "bt2020nc", + [AVCOL_SPC_BT2020_CL] = "bt2020c", + [AVCOL_SPC_SMPTE2085] = "smpte2085", + [AVCOL_SPC_CHROMA_DERIVED_NCL] = "chroma-derived-nc", + [AVCOL_SPC_CHROMA_DERIVED_CL] = "chroma-derived-c", + [AVCOL_SPC_ICTCP] = "ictcp", +}; + +static const char * const chroma_location_names[] = { + [AVCHROMA_LOC_UNSPECIFIED] = "unspecified", + [AVCHROMA_LOC_LEFT] = "left", + [AVCHROMA_LOC_CENTER] = "center", + [AVCHROMA_LOC_TOPLEFT] = "topleft", + [AVCHROMA_LOC_TOP] = "top", + [AVCHROMA_LOC_BOTTOMLEFT] = "bottomleft", + [AVCHROMA_LOC_BOTTOM] = "bottom", +}; + +static enum AVPixelFormat get_pix_fmt_internal(const char *name) +{ + enum AVPixelFormat pix_fmt; + + for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) + if (av_pix_fmt_descriptors[pix_fmt].name && + (!strcmp(av_pix_fmt_descriptors[pix_fmt].name, name) || + av_match_name(name, av_pix_fmt_descriptors[pix_fmt].alias))) + return pix_fmt; + + return AV_PIX_FMT_NONE; +} + +const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt) +{ + return (unsigned)pix_fmt < AV_PIX_FMT_NB ? + av_pix_fmt_descriptors[pix_fmt].name : NULL; +} + +#if HAVE_BIGENDIAN +# define X_NE(be, le) be +#else +# define X_NE(be, le) le +#endif + +enum AVPixelFormat av_get_pix_fmt(const char *name) +{ + enum AVPixelFormat pix_fmt; + + if (!strcmp(name, "rgb32")) + name = X_NE("argb", "bgra"); + else if (!strcmp(name, "bgr32")) + name = X_NE("abgr", "rgba"); + + pix_fmt = get_pix_fmt_internal(name); + if (pix_fmt == AV_PIX_FMT_NONE) { + char name2[32]; + + snprintf(name2, sizeof(name2), "%s%s", name, X_NE("be", "le")); + pix_fmt = get_pix_fmt_internal(name2); + } + +#if FF_API_VAAPI + if (pix_fmt == AV_PIX_FMT_NONE && !strcmp(name, "vaapi")) + pix_fmt = AV_PIX_FMT_VAAPI; +#endif + return pix_fmt; +} + +int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc) +{ + int c, bits = 0; + int log2_pixels = pixdesc->log2_chroma_w + pixdesc->log2_chroma_h; + + for (c = 0; c < pixdesc->nb_components; c++) { + int s = c == 1 || c == 2 ? 0 : log2_pixels; + bits += pixdesc->comp[c].depth << s; + } + + return bits >> log2_pixels; +} + +int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc) +{ + int c, bits = 0; + int log2_pixels = pixdesc->log2_chroma_w + pixdesc->log2_chroma_h; + int steps[4] = {0}; + + for (c = 0; c < pixdesc->nb_components; c++) { + const AVComponentDescriptor *comp = &pixdesc->comp[c]; + int s = c == 1 || c == 2 ? 0 : log2_pixels; + steps[comp->plane] = comp->step << s; + } + for (c = 0; c < 4; c++) + bits += steps[c]; + + if(!(pixdesc->flags & AV_PIX_FMT_FLAG_BITSTREAM)) + bits *= 8; + + return bits >> log2_pixels; +} + +char *av_get_pix_fmt_string(char *buf, int buf_size, + enum AVPixelFormat pix_fmt) +{ + /* print header */ + if (pix_fmt < 0) { + snprintf (buf, buf_size, "name" " nb_components" " nb_bits"); + } else { + const AVPixFmtDescriptor *pixdesc = &av_pix_fmt_descriptors[pix_fmt]; + snprintf(buf, buf_size, "%-11s %7d %10d", pixdesc->name, + pixdesc->nb_components, av_get_bits_per_pixel(pixdesc)); + } + + return buf; +} + +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt) +{ + if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB) + return NULL; + return &av_pix_fmt_descriptors[pix_fmt]; +} + +const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev) +{ + if (!prev) + return &av_pix_fmt_descriptors[0]; + while (prev - av_pix_fmt_descriptors < FF_ARRAY_ELEMS(av_pix_fmt_descriptors) - 1) { + prev++; + if (prev->name) + return prev; + } + return NULL; +} + +enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc) +{ + if (desc < av_pix_fmt_descriptors || + desc >= av_pix_fmt_descriptors + FF_ARRAY_ELEMS(av_pix_fmt_descriptors)) + return AV_PIX_FMT_NONE; + + return desc - av_pix_fmt_descriptors; +} + +int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, + int *h_shift, int *v_shift) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) + return AVERROR(ENOSYS); + *h_shift = desc->log2_chroma_w; + *v_shift = desc->log2_chroma_h; + + return 0; +} + +int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int i, planes[4] = { 0 }, ret = 0; + + if (!desc) + return AVERROR(EINVAL); + + for (i = 0; i < desc->nb_components; i++) + planes[desc->comp[i].plane] = 1; + for (i = 0; i < FF_ARRAY_ELEMS(planes); i++) + ret += planes[i]; + return ret; +} + +void ff_check_pixfmt_descriptors(void){ + int i, j; + + for (i=0; iname && !d->nb_components && !d->log2_chroma_w && !d->log2_chroma_h && !d->flags) + continue; +// av_log(NULL, AV_LOG_DEBUG, "Checking: %s\n", d->name); + av_assert0(d->log2_chroma_w <= 3); + av_assert0(d->log2_chroma_h <= 3); + av_assert0(d->nb_components <= 4); + av_assert0(d->name && d->name[0]); + av_assert2(av_get_pix_fmt(d->name) == i); + + for (j=0; jcomp); j++) { + const AVComponentDescriptor *c = &d->comp[j]; + if(j>=d->nb_components) { + av_assert0(!c->plane && !c->step && !c->offset && !c->shift && !c->depth); + continue; + } + if (d->flags & AV_PIX_FMT_FLAG_BITSTREAM) { + av_assert0(c->step >= c->depth); + } else { + av_assert0(8*c->step >= c->depth); + } + if (d->flags & AV_PIX_FMT_FLAG_BAYER) + continue; + av_read_image_line(tmp, (void*)data, linesize, d, 0, 0, j, 2, 0); + av_assert0(tmp[0] == 0 && tmp[1] == 0); + tmp[0] = tmp[1] = (1<depth) - 1; + av_write_image_line(tmp, data, linesize, d, 0, 0, j, 2); + } + } +} + + +enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + char name[16]; + int i; + + if (!desc || strlen(desc->name) < 2) + return AV_PIX_FMT_NONE; + av_strlcpy(name, desc->name, sizeof(name)); + i = strlen(name) - 2; + if (strcmp(name + i, "be") && strcmp(name + i, "le")) + return AV_PIX_FMT_NONE; + + name[i] ^= 'b' ^ 'l'; + + return get_pix_fmt_internal(name); +} + +#define FF_COLOR_NA -1 +#define FF_COLOR_RGB 0 /**< RGB color space */ +#define FF_COLOR_GRAY 1 /**< gray color space */ +#define FF_COLOR_YUV 2 /**< YUV color space. 16 <= Y <= 235, 16 <= U, V <= 240 */ +#define FF_COLOR_YUV_JPEG 3 /**< YUV color space. 0 <= Y <= 255, 0 <= U, V <= 255 */ +#define FF_COLOR_XYZ 4 + +#define pixdesc_has_alpha(pixdesc) \ + ((pixdesc)->flags & AV_PIX_FMT_FLAG_ALPHA) + + +static int get_color_type(const AVPixFmtDescriptor *desc) { + if (desc->flags & AV_PIX_FMT_FLAG_PAL) + return FF_COLOR_RGB; + + if(desc->nb_components == 1 || desc->nb_components == 2) + return FF_COLOR_GRAY; + + if(desc->name && !strncmp(desc->name, "yuvj", 4)) + return FF_COLOR_YUV_JPEG; + + if(desc->name && !strncmp(desc->name, "xyz", 3)) + return FF_COLOR_XYZ; + + if(desc->flags & AV_PIX_FMT_FLAG_RGB) + return FF_COLOR_RGB; + + if(desc->nb_components == 0) + return FF_COLOR_NA; + + return FF_COLOR_YUV; +} + +static int get_pix_fmt_depth(int *min, int *max, enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int i; + + if (!desc || !desc->nb_components) { + *min = *max = 0; + return AVERROR(EINVAL); + } + + *min = INT_MAX, *max = -INT_MAX; + for (i = 0; i < desc->nb_components; i++) { + *min = FFMIN(desc->comp[i].depth, *min); + *max = FFMAX(desc->comp[i].depth, *max); + } + return 0; +} + +static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + unsigned *lossp, unsigned consider) +{ + const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt); + const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt); + int src_color, dst_color; + int src_min_depth, src_max_depth, dst_min_depth, dst_max_depth; + int ret, loss, i, nb_components; + int score = INT_MAX - 1; + + if (!src_desc || !dst_desc) + return -4; + + if ((src_desc->flags & AV_PIX_FMT_FLAG_HWACCEL) || + (dst_desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) { + if (dst_pix_fmt == src_pix_fmt) + return -1; + else + return -2; + } + + /* compute loss */ + *lossp = loss = 0; + + if (dst_pix_fmt == src_pix_fmt) + return INT_MAX; + + if ((ret = get_pix_fmt_depth(&src_min_depth, &src_max_depth, src_pix_fmt)) < 0) + return -3; + if ((ret = get_pix_fmt_depth(&dst_min_depth, &dst_max_depth, dst_pix_fmt)) < 0) + return -3; + + src_color = get_color_type(src_desc); + dst_color = get_color_type(dst_desc); + if (dst_pix_fmt == AV_PIX_FMT_PAL8) + nb_components = FFMIN(src_desc->nb_components, 4); + else + nb_components = FFMIN(src_desc->nb_components, dst_desc->nb_components); + + for (i = 0; i < nb_components; i++) { + int depth_minus1 = (dst_pix_fmt == AV_PIX_FMT_PAL8) ? 7/nb_components : (dst_desc->comp[i].depth - 1); + if (src_desc->comp[i].depth - 1 > depth_minus1 && (consider & FF_LOSS_DEPTH)) { + loss |= FF_LOSS_DEPTH; + score -= 65536 >> depth_minus1; + } + } + + if (consider & FF_LOSS_RESOLUTION) { + if (dst_desc->log2_chroma_w > src_desc->log2_chroma_w) { + loss |= FF_LOSS_RESOLUTION; + score -= 256 << dst_desc->log2_chroma_w; + } + if (dst_desc->log2_chroma_h > src_desc->log2_chroma_h) { + loss |= FF_LOSS_RESOLUTION; + score -= 256 << dst_desc->log2_chroma_h; + } + // don't favor 422 over 420 if downsampling is needed, because 420 has much better support on the decoder side + if (dst_desc->log2_chroma_w == 1 && src_desc->log2_chroma_w == 0 && + dst_desc->log2_chroma_h == 1 && src_desc->log2_chroma_h == 0 ) { + score += 512; + } + } + + if(consider & FF_LOSS_COLORSPACE) + switch(dst_color) { + case FF_COLOR_RGB: + if (src_color != FF_COLOR_RGB && + src_color != FF_COLOR_GRAY) + loss |= FF_LOSS_COLORSPACE; + break; + case FF_COLOR_GRAY: + if (src_color != FF_COLOR_GRAY) + loss |= FF_LOSS_COLORSPACE; + break; + case FF_COLOR_YUV: + if (src_color != FF_COLOR_YUV) + loss |= FF_LOSS_COLORSPACE; + break; + case FF_COLOR_YUV_JPEG: + if (src_color != FF_COLOR_YUV_JPEG && + src_color != FF_COLOR_YUV && + src_color != FF_COLOR_GRAY) + loss |= FF_LOSS_COLORSPACE; + break; + default: + /* fail safe test */ + if (src_color != dst_color) + loss |= FF_LOSS_COLORSPACE; + break; + } + if(loss & FF_LOSS_COLORSPACE) + score -= (nb_components * 65536) >> FFMIN(dst_desc->comp[0].depth - 1, src_desc->comp[0].depth - 1); + + if (dst_color == FF_COLOR_GRAY && + src_color != FF_COLOR_GRAY && (consider & FF_LOSS_CHROMA)) { + loss |= FF_LOSS_CHROMA; + score -= 2 * 65536; + } + if (!pixdesc_has_alpha(dst_desc) && (pixdesc_has_alpha(src_desc) && (consider & FF_LOSS_ALPHA))) { + loss |= FF_LOSS_ALPHA; + score -= 65536; + } + if (dst_pix_fmt == AV_PIX_FMT_PAL8 && (consider & FF_LOSS_COLORQUANT) && + (src_pix_fmt != AV_PIX_FMT_PAL8 && (src_color != FF_COLOR_GRAY || (pixdesc_has_alpha(src_desc) && (consider & FF_LOSS_ALPHA))))) { + loss |= FF_LOSS_COLORQUANT; + score -= 65536; + } + + *lossp = loss; + return score; +} + +int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha) +{ + int loss; + int ret = get_pix_fmt_score(dst_pix_fmt, src_pix_fmt, &loss, has_alpha ? ~0 : ~FF_LOSS_ALPHA); + if (ret < 0) + return ret; + return loss; +} + +enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr) +{ + enum AVPixelFormat dst_pix_fmt; + int loss1, loss2, loss_mask; + const AVPixFmtDescriptor *desc1 = av_pix_fmt_desc_get(dst_pix_fmt1); + const AVPixFmtDescriptor *desc2 = av_pix_fmt_desc_get(dst_pix_fmt2); + int score1, score2; + + if (!desc1) { + dst_pix_fmt = dst_pix_fmt2; + } else if (!desc2) { + dst_pix_fmt = dst_pix_fmt1; + } else { + loss_mask= loss_ptr?~*loss_ptr:~0; /* use loss mask if provided */ + if(!has_alpha) + loss_mask &= ~FF_LOSS_ALPHA; + + score1 = get_pix_fmt_score(dst_pix_fmt1, src_pix_fmt, &loss1, loss_mask); + score2 = get_pix_fmt_score(dst_pix_fmt2, src_pix_fmt, &loss2, loss_mask); + + if (score1 == score2) { + if(av_get_padded_bits_per_pixel(desc2) != av_get_padded_bits_per_pixel(desc1)) { + dst_pix_fmt = av_get_padded_bits_per_pixel(desc2) < av_get_padded_bits_per_pixel(desc1) ? dst_pix_fmt2 : dst_pix_fmt1; + } else { + dst_pix_fmt = desc2->nb_components < desc1->nb_components ? dst_pix_fmt2 : dst_pix_fmt1; + } + } else { + dst_pix_fmt = score1 < score2 ? dst_pix_fmt2 : dst_pix_fmt1; + } + } + + if (loss_ptr) + *loss_ptr = av_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha); + return dst_pix_fmt; +} + +const char *av_color_range_name(enum AVColorRange range) +{ + return (unsigned) range < AVCOL_RANGE_NB ? + color_range_names[range] : NULL; +} + +int av_color_range_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_range_names); i++) { + size_t len = strlen(color_range_names[i]); + if (!strncmp(color_range_names[i], name, len)) + return i; + } + + return AVERROR(EINVAL); +} + +const char *av_color_primaries_name(enum AVColorPrimaries primaries) +{ + return (unsigned) primaries < AVCOL_PRI_NB ? + color_primaries_names[primaries] : NULL; +} + +int av_color_primaries_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_primaries_names); i++) { + size_t len; + + if (!color_primaries_names[i]) + continue; + + len = strlen(color_primaries_names[i]); + if (!strncmp(color_primaries_names[i], name, len)) + return i; + } + + return AVERROR(EINVAL); +} + +const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer) +{ + return (unsigned) transfer < AVCOL_TRC_NB ? + color_transfer_names[transfer] : NULL; +} + +int av_color_transfer_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_transfer_names); i++) { + size_t len; + + if (!color_transfer_names[i]) + continue; + + len = strlen(color_transfer_names[i]); + if (!strncmp(color_transfer_names[i], name, len)) + return i; + } + + return AVERROR(EINVAL); +} + +const char *av_color_space_name(enum AVColorSpace space) +{ + return (unsigned) space < AVCOL_SPC_NB ? + color_space_names[space] : NULL; +} + +int av_color_space_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_space_names); i++) { + size_t len; + + if (!color_space_names[i]) + continue; + + len = strlen(color_space_names[i]); + if (!strncmp(color_space_names[i], name, len)) + return i; + } + + return AVERROR(EINVAL); +} + +const char *av_chroma_location_name(enum AVChromaLocation location) +{ + return (unsigned) location < AVCHROMA_LOC_NB ? + chroma_location_names[location] : NULL; +} + +int av_chroma_location_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(chroma_location_names); i++) { + size_t len; + + if (!chroma_location_names[i]) + continue; + + len = strlen(chroma_location_names[i]); + if (!strncmp(chroma_location_names[i], name, len)) + return i; + } + + return AVERROR(EINVAL); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixdesc.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixdesc.h new file mode 100644 index 0000000000..c055810ae8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixdesc.h @@ -0,0 +1,440 @@ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXDESC_H +#define AVUTIL_PIXDESC_H + +#include + +#include "attributes.h" +#include "pixfmt.h" +#include "version.h" + +typedef struct AVComponentDescriptor { + /** + * Which of the 4 planes contains the component. + */ + int plane; + + /** + * Number of elements between 2 horizontally consecutive pixels. + * Elements are bits for bitstream formats, bytes otherwise. + */ + int step; + + /** + * Number of elements before the component of the first pixel. + * Elements are bits for bitstream formats, bytes otherwise. + */ + int offset; + + /** + * Number of least significant bits that must be shifted away + * to get the value. + */ + int shift; + + /** + * Number of bits in the component. + */ + int depth; + +#if FF_API_PLUS1_MINUS1 + /** deprecated, use step instead */ + attribute_deprecated int step_minus1; + + /** deprecated, use depth instead */ + attribute_deprecated int depth_minus1; + + /** deprecated, use offset instead */ + attribute_deprecated int offset_plus1; +#endif +} AVComponentDescriptor; + +/** + * Descriptor that unambiguously describes how the bits of a pixel are + * stored in the up to 4 data planes of an image. It also stores the + * subsampling factors and number of components. + * + * @note This is separate of the colorspace (RGB, YCbCr, YPbPr, JPEG-style YUV + * and all the YUV variants) AVPixFmtDescriptor just stores how values + * are stored not what these values represent. + */ +typedef struct AVPixFmtDescriptor { + const char *name; + uint8_t nb_components; ///< The number of components each pixel has, (1-4) + + /** + * Amount to shift the luma width right to find the chroma width. + * For YV12 this is 1 for example. + * chroma_width = AV_CEIL_RSHIFT(luma_width, log2_chroma_w) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_w; + + /** + * Amount to shift the luma height right to find the chroma height. + * For YV12 this is 1 for example. + * chroma_height= AV_CEIL_RSHIFT(luma_height, log2_chroma_h) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_h; + + /** + * Combination of AV_PIX_FMT_FLAG_... flags. + */ + uint64_t flags; + + /** + * Parameters that describe how pixels are packed. + * If the format has 1 or 2 components, then luma is 0. + * If the format has 3 or 4 components: + * if the RGB flag is set then 0 is red, 1 is green and 2 is blue; + * otherwise 0 is luma, 1 is chroma-U and 2 is chroma-V. + * + * If present, the Alpha channel is always the last component. + */ + AVComponentDescriptor comp[4]; + + /** + * Alternative comma-separated names. + */ + const char *alias; +} AVPixFmtDescriptor; + +/** + * Pixel format is big-endian. + */ +#define AV_PIX_FMT_FLAG_BE (1 << 0) +/** + * Pixel format has a palette in data[1], values are indexes in this palette. + */ +#define AV_PIX_FMT_FLAG_PAL (1 << 1) +/** + * All values of a component are bit-wise packed end to end. + */ +#define AV_PIX_FMT_FLAG_BITSTREAM (1 << 2) +/** + * Pixel format is an HW accelerated format. + */ +#define AV_PIX_FMT_FLAG_HWACCEL (1 << 3) +/** + * At least one pixel component is not in the first data plane. + */ +#define AV_PIX_FMT_FLAG_PLANAR (1 << 4) +/** + * The pixel format contains RGB-like data (as opposed to YUV/grayscale). + */ +#define AV_PIX_FMT_FLAG_RGB (1 << 5) + +/** + * The pixel format is "pseudo-paletted". This means that it contains a + * fixed palette in the 2nd plane but the palette is fixed/constant for each + * PIX_FMT. This allows interpreting the data as if it was PAL8, which can + * in some cases be simpler. Or the data can be interpreted purely based on + * the pixel format without using the palette. + * An example of a pseudo-paletted format is AV_PIX_FMT_GRAY8 + * + * @deprecated This flag is deprecated, and will be removed. When it is removed, + * the extra palette allocation in AVFrame.data[1] is removed as well. Only + * actual paletted formats (as indicated by AV_PIX_FMT_FLAG_PAL) will have a + * palette. Starting with FFmpeg versions which have this flag deprecated, the + * extra "pseudo" palette is already ignored, and API users are not required to + * allocate a palette for AV_PIX_FMT_FLAG_PSEUDOPAL formats (it was required + * before the deprecation, though). + */ +#define AV_PIX_FMT_FLAG_PSEUDOPAL (1 << 6) + +/** + * The pixel format has an alpha channel. This is set on all formats that + * support alpha in some way, including AV_PIX_FMT_PAL8. The alpha is always + * straight, never pre-multiplied. + * + * If a codec or a filter does not support alpha, it should set all alpha to + * opaque, or use the equivalent pixel formats without alpha component, e.g. + * AV_PIX_FMT_RGB0 (or AV_PIX_FMT_RGB24 etc.) instead of AV_PIX_FMT_RGBA. + */ +#define AV_PIX_FMT_FLAG_ALPHA (1 << 7) + +/** + * The pixel format is following a Bayer pattern + */ +#define AV_PIX_FMT_FLAG_BAYER (1 << 8) + +/** + * The pixel format contains IEEE-754 floating point values. Precision (double, + * single, or half) should be determined by the pixel size (64, 32, or 16 bits). + */ +#define AV_PIX_FMT_FLAG_FLOAT (1 << 9) + +/** + * Return the number of bits per pixel used by the pixel format + * described by pixdesc. Note that this is not the same as the number + * of bits per sample. + * + * The returned number of bits refers to the number of bits actually + * used for storing the pixel information, that is padding bits are + * not counted. + */ +int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * Return the number of bits per pixel for the pixel format + * described by pixdesc, including any padding or unused bits. + */ +int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * @return a pixel format descriptor for provided pixel format or NULL if + * this pixel format is unknown. + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt); + +/** + * Iterate over all pixel format descriptors known to libavutil. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev); + +/** + * @return an AVPixelFormat id described by desc, or AV_PIX_FMT_NONE if desc + * is not a valid pointer to a pixel format descriptor. + */ +enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc); + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w (horizontal/width shift) + * @param[out] v_shift store log2_chroma_h (vertical/height shift) + * + * @return 0 on success, AVERROR(ENOSYS) on invalid or unknown pixel format + */ +int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, + int *h_shift, int *v_shift); + +/** + * @return number of planes in pix_fmt, a negative AVERROR if pix_fmt is not a + * valid pixel format. + */ +int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt); + +/** + * @return the name for provided color range or NULL if unknown. + */ +const char *av_color_range_name(enum AVColorRange range); + +/** + * @return the AVColorRange value for name or an AVError if not found. + */ +int av_color_range_from_name(const char *name); + +/** + * @return the name for provided color primaries or NULL if unknown. + */ +const char *av_color_primaries_name(enum AVColorPrimaries primaries); + +/** + * @return the AVColorPrimaries value for name or an AVError if not found. + */ +int av_color_primaries_from_name(const char *name); + +/** + * @return the name for provided color transfer or NULL if unknown. + */ +const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer); + +/** + * @return the AVColorTransferCharacteristic value for name or an AVError if not found. + */ +int av_color_transfer_from_name(const char *name); + +/** + * @return the name for provided color space or NULL if unknown. + */ +const char *av_color_space_name(enum AVColorSpace space); + +/** + * @return the AVColorSpace value for name or an AVError if not found. + */ +int av_color_space_from_name(const char *name); + +/** + * @return the name for provided chroma location or NULL if unknown. + */ +const char *av_chroma_location_name(enum AVChromaLocation location); + +/** + * @return the AVChromaLocation value for name or an AVError if not found. + */ +int av_chroma_location_from_name(const char *name); + +/** + * Return the pixel format corresponding to name. + * + * If there is no pixel format with name name, then looks for a + * pixel format with the name corresponding to the native endian + * format of name. + * For example in a little-endian system, first looks for "gray16", + * then for "gray16le". + * + * Finally if no pixel format has been found, returns AV_PIX_FMT_NONE. + */ +enum AVPixelFormat av_get_pix_fmt(const char *name); + +/** + * Return the short name for a pixel format, NULL in case pix_fmt is + * unknown. + * + * @see av_get_pix_fmt(), av_get_pix_fmt_string() + */ +const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt); + +/** + * Print in buf the string corresponding to the pixel format with + * number pix_fmt, or a header if pix_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param pix_fmt the number of the pixel format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + */ +char *av_get_pix_fmt_string(char *buf, int buf_size, + enum AVPixelFormat pix_fmt); + +/** + * Read a line from an image, and write the values of the + * pixel format component c to dst. + * + * @param data the array containing the pointers to the planes of the image + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to read + * @param y the vertical coordinate of the first pixel to read + * @param w the width of the line to read, that is the number of + * values to write to dst + * @param read_pal_component if not zero and the format is a paletted + * format writes the values corresponding to the palette + * component c in data[1] to dst, rather than the palette indexes in + * data[0]. The behavior is undefined if the format is not paletted. + * @param dst_element_size size of elements in dst array (2 or 4 byte) + */ +void av_read_image_line2(void *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component, + int dst_element_size); + +void av_read_image_line(uint16_t *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component); + +/** + * Write the values from src to the pixel format component c of an + * image line. + * + * @param src array containing the values to write + * @param data the array containing the pointers to the planes of the + * image to write into. It is supposed to be zeroed. + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to write + * @param y the vertical coordinate of the first pixel to write + * @param w the width of the line to write, that is the number of + * values to write to the image line + * @param src_element_size size of elements in src array (2 or 4 byte) + */ +void av_write_image_line2(const void *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int src_element_size); + +void av_write_image_line(const uint16_t *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w); + +/** + * Utility function to swap the endianness of a pixel format. + * + * @param[in] pix_fmt the pixel format + * + * @return pixel format with swapped endianness if it exists, + * otherwise AV_PIX_FMT_NONE + */ +enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt); + +#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ +#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ +#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ +#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ +#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ +#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +#endif /* AVUTIL_PIXDESC_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixelutils.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixelutils.c new file mode 100644 index 0000000000..ebee3d6f90 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixelutils.c @@ -0,0 +1,89 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "common.h" +#include "pixelutils.h" +#include "internal.h" + +#if CONFIG_PIXELUTILS + +#include "x86/pixelutils.h" + +static av_always_inline int sad_wxh(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2, + int w, int h) +{ + int x, y, sum = 0; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) + sum += abs(src1[x] - src2[x]); + src1 += stride1; + src2 += stride2; + } + return sum; +} + +#define DECLARE_BLOCK_FUNCTIONS(size) \ +static int block_sad_##size##x##size##_c(const uint8_t *src1, ptrdiff_t stride1, \ + const uint8_t *src2, ptrdiff_t stride2) \ +{ \ + return sad_wxh(src1, stride1, src2, stride2, size, size); \ +} + +DECLARE_BLOCK_FUNCTIONS(2) +DECLARE_BLOCK_FUNCTIONS(4) +DECLARE_BLOCK_FUNCTIONS(8) +DECLARE_BLOCK_FUNCTIONS(16) +DECLARE_BLOCK_FUNCTIONS(32) + +static const av_pixelutils_sad_fn sad_c[] = { + block_sad_2x2_c, + block_sad_4x4_c, + block_sad_8x8_c, + block_sad_16x16_c, + block_sad_32x32_c, +}; + +#endif /* CONFIG_PIXELUTILS */ + +av_pixelutils_sad_fn av_pixelutils_get_sad_fn(int w_bits, int h_bits, int aligned, void *log_ctx) +{ +#if !CONFIG_PIXELUTILS + av_log(log_ctx, AV_LOG_ERROR, "pixelutils support is required " + "but libavutil is not compiled with it\n"); + return NULL; +#else + av_pixelutils_sad_fn sad[FF_ARRAY_ELEMS(sad_c)]; + + memcpy(sad, sad_c, sizeof(sad)); + + if (w_bits < 1 || w_bits > FF_ARRAY_ELEMS(sad) || + h_bits < 1 || h_bits > FF_ARRAY_ELEMS(sad)) + return NULL; + if (w_bits != h_bits) // only squared sad for now + return NULL; + +#if ARCH_X86 + ff_pixelutils_sad_init_x86(sad, aligned); +#endif + + return sad[w_bits - 1]; +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixelutils.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixelutils.h new file mode 100644 index 0000000000..a8dbc157e1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/pixelutils.h @@ -0,0 +1,52 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXELUTILS_H +#define AVUTIL_PIXELUTILS_H + +#include +#include +#include "common.h" + +/** + * Sum of abs(src1[x] - src2[x]) + */ +typedef int (*av_pixelutils_sad_fn)(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +/** + * Get a potentially optimized pointer to a Sum-of-absolute-differences + * function (see the av_pixelutils_sad_fn prototype). + * + * @param w_bits 1< + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXFMT_H +#define AVUTIL_PIXFMT_H + +/** + * @file + * pixel format definitions + */ + +#include "libavutil/avconfig.h" +#include "version.h" + +#define AVPALETTE_SIZE 1024 +#define AVPALETTE_COUNT 256 + +/** + * Pixel format. + * + * @note + * AV_PIX_FMT_RGB32 is handled in an endian-specific manner. An RGBA + * color is put together as: + * (A << 24) | (R << 16) | (G << 8) | B + * This is stored as BGRA on little-endian CPU architectures and ARGB on + * big-endian CPUs. + * + * @note + * If the resolution is not a multiple of the chroma subsampling factor + * then the chroma plane resolution must be rounded up. + * + * @par + * When the pixel format is palettized RGB32 (AV_PIX_FMT_PAL8), the palettized + * image data is stored in AVFrame.data[0]. The palette is transported in + * AVFrame.data[1], is 1024 bytes long (256 4-byte entries) and is + * formatted the same as in AV_PIX_FMT_RGB32 described above (i.e., it is + * also endian-specific). Note also that the individual RGB32 palette + * components stored in AVFrame.data[1] should be in the range 0..255. + * This is important as many custom PAL8 video codecs that were designed + * to run on the IBM VGA graphics adapter use 6-bit palette components. + * + * @par + * For all the 8 bits per pixel formats, an RGB32 palette is in data[1] like + * for pal8. This palette is filled in automatically by the function + * allocating the picture. + */ +enum AVPixelFormat { + AV_PIX_FMT_NONE = -1, + AV_PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + AV_PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + AV_PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... + AV_PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... + AV_PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + AV_PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + AV_PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + AV_PIX_FMT_GRAY8, ///< Y , 8bpp + AV_PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_PAL8, ///< 8 bits with AV_PIX_FMT_RGB32 palette + AV_PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting color_range + AV_PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting color_range + AV_PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting color_range + AV_PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + AV_PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + AV_PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + AV_PIX_FMT_BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + AV_PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) + AV_PIX_FMT_RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb) + AV_PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + AV_PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + AV_PIX_FMT_ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... + AV_PIX_FMT_RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... + AV_PIX_FMT_ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... + AV_PIX_FMT_BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... + + AV_PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + AV_PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + AV_PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) + AV_PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range + AV_PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) + AV_PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian + + AV_PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian + AV_PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian + AV_PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined + AV_PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined + + AV_PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian + AV_PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian + AV_PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), big-endian , X=unused/undefined + AV_PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), little-endian, X=unused/undefined + +#if FF_API_VAAPI + /** @name Deprecated pixel formats */ + /**@{*/ + AV_PIX_FMT_VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers + AV_PIX_FMT_VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers + AV_PIX_FMT_VAAPI_VLD, ///< HW decoding through VA API, Picture.data[3] contains a VASurfaceID + /**@}*/ + AV_PIX_FMT_VAAPI = AV_PIX_FMT_VAAPI_VLD, +#else + /** + * Hardware acceleration through VA-API, data[3] contains a + * VASurfaceID. + */ + AV_PIX_FMT_VAAPI, +#endif + + AV_PIX_FMT_YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer + + AV_PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_YA8, ///< 8 bits gray, 8 bits alpha + + AV_PIX_FMT_Y400A = AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + AV_PIX_FMT_GRAY8A= AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + + AV_PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian + + /** + * The following 12 formats have the disadvantage of needing 1 format for each bit depth. + * Notice that each 9/10 bits sample is stored in 16 bits with extra padding. + * If you want to support multiple bit depths, then using AV_PIX_FMT_YUV420P16* with the bpp stored separately is better. + */ + AV_PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp + AV_PIX_FMT_GBR24P = AV_PIX_FMT_GBRP, // alias for #AV_PIX_FMT_GBRP + AV_PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big-endian + AV_PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little-endian + AV_PIX_FMT_GBRP10BE, ///< planar GBR 4:4:4 30bpp, big-endian + AV_PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little-endian + AV_PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big-endian + AV_PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little-endian + AV_PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples) + AV_PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples) + AV_PIX_FMT_YUVA420P9BE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), big-endian + AV_PIX_FMT_YUVA420P9LE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), little-endian + AV_PIX_FMT_YUVA422P9BE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA422P9LE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA444P9BE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA444P9LE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA420P10BE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P10LE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P10BE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P10LE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P10BE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P10LE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA420P16BE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P16LE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P16BE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P16LE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P16BE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P16LE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + + AV_PIX_FMT_VDPAU, ///< HW acceleration through VDPAU, Picture.data[3] contains a VdpVideoSurface + + AV_PIX_FMT_XYZ12LE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as little-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_XYZ12BE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as big-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_NV16, ///< interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_NV20LE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_NV20BE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + + AV_PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + + AV_PIX_FMT_YVYU422, ///< packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb + + AV_PIX_FMT_YA16BE, ///< 16 bits gray, 16 bits alpha (big-endian) + AV_PIX_FMT_YA16LE, ///< 16 bits gray, 16 bits alpha (little-endian) + + AV_PIX_FMT_GBRAP, ///< planar GBRA 4:4:4:4 32bpp + AV_PIX_FMT_GBRAP16BE, ///< planar GBRA 4:4:4:4 64bpp, big-endian + AV_PIX_FMT_GBRAP16LE, ///< planar GBRA 4:4:4:4 64bpp, little-endian + /** + * HW acceleration through QSV, data[3] contains a pointer to the + * mfxFrameSurface1 structure. + */ + AV_PIX_FMT_QSV, + /** + * HW acceleration though MMAL, data[3] contains a pointer to the + * MMAL_BUFFER_HEADER_T structure. + */ + AV_PIX_FMT_MMAL, + + AV_PIX_FMT_D3D11VA_VLD, ///< HW decoding through Direct3D11 via old API, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer + + /** + * HW acceleration through CUDA. data[i] contain CUdeviceptr pointers + * exactly as for system memory frames. + */ + AV_PIX_FMT_CUDA, + + AV_PIX_FMT_0RGB, ///< packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined + AV_PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined + AV_PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined + AV_PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined + + AV_PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big-endian + AV_PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little-endian + AV_PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big-endian + AV_PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little-endian + AV_PIX_FMT_YUVJ411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV411P and setting color_range + + AV_PIX_FMT_BAYER_BGGR8, ///< bayer, BGBG..(odd line), GRGR..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_RGGB8, ///< bayer, RGRG..(odd line), GBGB..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_GBRG8, ///< bayer, GBGB..(odd line), RGRG..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_GRBG8, ///< bayer, GRGR..(odd line), BGBG..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_BGGR16LE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_BGGR16BE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_RGGB16LE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_RGGB16BE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_GBRG16LE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_GBRG16BE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_GRBG16LE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_GRBG16BE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, big-endian */ + + AV_PIX_FMT_XVMC,///< XVideo Motion Acceleration via common packet passing + + AV_PIX_FMT_YUV440P10LE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian + AV_PIX_FMT_YUV440P10BE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian + AV_PIX_FMT_YUV440P12LE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian + AV_PIX_FMT_YUV440P12BE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian + AV_PIX_FMT_AYUV64LE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_AYUV64BE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + + AV_PIX_FMT_VIDEOTOOLBOX, ///< hardware decoding through Videotoolbox + + AV_PIX_FMT_P010LE, ///< like NV12, with 10bpp per component, data in the high bits, zeros in the low bits, little-endian + AV_PIX_FMT_P010BE, ///< like NV12, with 10bpp per component, data in the high bits, zeros in the low bits, big-endian + + AV_PIX_FMT_GBRAP12BE, ///< planar GBR 4:4:4:4 48bpp, big-endian + AV_PIX_FMT_GBRAP12LE, ///< planar GBR 4:4:4:4 48bpp, little-endian + + AV_PIX_FMT_GBRAP10BE, ///< planar GBR 4:4:4:4 40bpp, big-endian + AV_PIX_FMT_GBRAP10LE, ///< planar GBR 4:4:4:4 40bpp, little-endian + + AV_PIX_FMT_MEDIACODEC, ///< hardware decoding through MediaCodec + + AV_PIX_FMT_GRAY12BE, ///< Y , 12bpp, big-endian + AV_PIX_FMT_GRAY12LE, ///< Y , 12bpp, little-endian + AV_PIX_FMT_GRAY10BE, ///< Y , 10bpp, big-endian + AV_PIX_FMT_GRAY10LE, ///< Y , 10bpp, little-endian + + AV_PIX_FMT_P016LE, ///< like NV12, with 16bpp per component, little-endian + AV_PIX_FMT_P016BE, ///< like NV12, with 16bpp per component, big-endian + + /** + * Hardware surfaces for Direct3D11. + * + * This is preferred over the legacy AV_PIX_FMT_D3D11VA_VLD. The new D3D11 + * hwaccel API and filtering support AV_PIX_FMT_D3D11 only. + * + * data[0] contains a ID3D11Texture2D pointer, and data[1] contains the + * texture array index of the frame as intptr_t if the ID3D11Texture2D is + * an array texture (or always 0 if it's a normal texture). + */ + AV_PIX_FMT_D3D11, + + AV_PIX_FMT_GRAY9BE, ///< Y , 9bpp, big-endian + AV_PIX_FMT_GRAY9LE, ///< Y , 9bpp, little-endian + + AV_PIX_FMT_GBRPF32BE, ///< IEEE-754 single precision planar GBR 4:4:4, 96bpp, big-endian + AV_PIX_FMT_GBRPF32LE, ///< IEEE-754 single precision planar GBR 4:4:4, 96bpp, little-endian + AV_PIX_FMT_GBRAPF32BE, ///< IEEE-754 single precision planar GBRA 4:4:4:4, 128bpp, big-endian + AV_PIX_FMT_GBRAPF32LE, ///< IEEE-754 single precision planar GBRA 4:4:4:4, 128bpp, little-endian + + /** + * DRM-managed buffers exposed through PRIME buffer sharing. + * + * data[0] points to an AVDRMFrameDescriptor. + */ + AV_PIX_FMT_DRM_PRIME, + /** + * Hardware surfaces for OpenCL. + * + * data[i] contain 2D image objects (typed in C as cl_mem, used + * in OpenCL as image2d_t) for each plane of the surface. + */ + AV_PIX_FMT_OPENCL, + + AV_PIX_FMT_GRAY14BE, ///< Y , 14bpp, big-endian + AV_PIX_FMT_GRAY14LE, ///< Y , 14bpp, little-endian + + AV_PIX_FMT_GRAYF32BE, ///< IEEE-754 single precision Y, 32bpp, big-endian + AV_PIX_FMT_GRAYF32LE, ///< IEEE-754 single precision Y, 32bpp, little-endian + + AV_PIX_FMT_YUVA422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), 12b alpha, big-endian + AV_PIX_FMT_YUVA422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), 12b alpha, little-endian + AV_PIX_FMT_YUVA444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), 12b alpha, big-endian + AV_PIX_FMT_YUVA444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), 12b alpha, little-endian + + AV_PIX_FMT_NV24, ///< planar YUV 4:4:4, 24bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + AV_PIX_FMT_NV42, ///< as above, but U and V bytes are swapped + + AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions +}; + +#if AV_HAVE_BIGENDIAN +# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##be +#else +# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##le +#endif + +#define AV_PIX_FMT_RGB32 AV_PIX_FMT_NE(ARGB, BGRA) +#define AV_PIX_FMT_RGB32_1 AV_PIX_FMT_NE(RGBA, ABGR) +#define AV_PIX_FMT_BGR32 AV_PIX_FMT_NE(ABGR, RGBA) +#define AV_PIX_FMT_BGR32_1 AV_PIX_FMT_NE(BGRA, ARGB) +#define AV_PIX_FMT_0RGB32 AV_PIX_FMT_NE(0RGB, BGR0) +#define AV_PIX_FMT_0BGR32 AV_PIX_FMT_NE(0BGR, RGB0) + +#define AV_PIX_FMT_GRAY9 AV_PIX_FMT_NE(GRAY9BE, GRAY9LE) +#define AV_PIX_FMT_GRAY10 AV_PIX_FMT_NE(GRAY10BE, GRAY10LE) +#define AV_PIX_FMT_GRAY12 AV_PIX_FMT_NE(GRAY12BE, GRAY12LE) +#define AV_PIX_FMT_GRAY14 AV_PIX_FMT_NE(GRAY14BE, GRAY14LE) +#define AV_PIX_FMT_GRAY16 AV_PIX_FMT_NE(GRAY16BE, GRAY16LE) +#define AV_PIX_FMT_YA16 AV_PIX_FMT_NE(YA16BE, YA16LE) +#define AV_PIX_FMT_RGB48 AV_PIX_FMT_NE(RGB48BE, RGB48LE) +#define AV_PIX_FMT_RGB565 AV_PIX_FMT_NE(RGB565BE, RGB565LE) +#define AV_PIX_FMT_RGB555 AV_PIX_FMT_NE(RGB555BE, RGB555LE) +#define AV_PIX_FMT_RGB444 AV_PIX_FMT_NE(RGB444BE, RGB444LE) +#define AV_PIX_FMT_RGBA64 AV_PIX_FMT_NE(RGBA64BE, RGBA64LE) +#define AV_PIX_FMT_BGR48 AV_PIX_FMT_NE(BGR48BE, BGR48LE) +#define AV_PIX_FMT_BGR565 AV_PIX_FMT_NE(BGR565BE, BGR565LE) +#define AV_PIX_FMT_BGR555 AV_PIX_FMT_NE(BGR555BE, BGR555LE) +#define AV_PIX_FMT_BGR444 AV_PIX_FMT_NE(BGR444BE, BGR444LE) +#define AV_PIX_FMT_BGRA64 AV_PIX_FMT_NE(BGRA64BE, BGRA64LE) + +#define AV_PIX_FMT_YUV420P9 AV_PIX_FMT_NE(YUV420P9BE , YUV420P9LE) +#define AV_PIX_FMT_YUV422P9 AV_PIX_FMT_NE(YUV422P9BE , YUV422P9LE) +#define AV_PIX_FMT_YUV444P9 AV_PIX_FMT_NE(YUV444P9BE , YUV444P9LE) +#define AV_PIX_FMT_YUV420P10 AV_PIX_FMT_NE(YUV420P10BE, YUV420P10LE) +#define AV_PIX_FMT_YUV422P10 AV_PIX_FMT_NE(YUV422P10BE, YUV422P10LE) +#define AV_PIX_FMT_YUV440P10 AV_PIX_FMT_NE(YUV440P10BE, YUV440P10LE) +#define AV_PIX_FMT_YUV444P10 AV_PIX_FMT_NE(YUV444P10BE, YUV444P10LE) +#define AV_PIX_FMT_YUV420P12 AV_PIX_FMT_NE(YUV420P12BE, YUV420P12LE) +#define AV_PIX_FMT_YUV422P12 AV_PIX_FMT_NE(YUV422P12BE, YUV422P12LE) +#define AV_PIX_FMT_YUV440P12 AV_PIX_FMT_NE(YUV440P12BE, YUV440P12LE) +#define AV_PIX_FMT_YUV444P12 AV_PIX_FMT_NE(YUV444P12BE, YUV444P12LE) +#define AV_PIX_FMT_YUV420P14 AV_PIX_FMT_NE(YUV420P14BE, YUV420P14LE) +#define AV_PIX_FMT_YUV422P14 AV_PIX_FMT_NE(YUV422P14BE, YUV422P14LE) +#define AV_PIX_FMT_YUV444P14 AV_PIX_FMT_NE(YUV444P14BE, YUV444P14LE) +#define AV_PIX_FMT_YUV420P16 AV_PIX_FMT_NE(YUV420P16BE, YUV420P16LE) +#define AV_PIX_FMT_YUV422P16 AV_PIX_FMT_NE(YUV422P16BE, YUV422P16LE) +#define AV_PIX_FMT_YUV444P16 AV_PIX_FMT_NE(YUV444P16BE, YUV444P16LE) + +#define AV_PIX_FMT_GBRP9 AV_PIX_FMT_NE(GBRP9BE , GBRP9LE) +#define AV_PIX_FMT_GBRP10 AV_PIX_FMT_NE(GBRP10BE, GBRP10LE) +#define AV_PIX_FMT_GBRP12 AV_PIX_FMT_NE(GBRP12BE, GBRP12LE) +#define AV_PIX_FMT_GBRP14 AV_PIX_FMT_NE(GBRP14BE, GBRP14LE) +#define AV_PIX_FMT_GBRP16 AV_PIX_FMT_NE(GBRP16BE, GBRP16LE) +#define AV_PIX_FMT_GBRAP10 AV_PIX_FMT_NE(GBRAP10BE, GBRAP10LE) +#define AV_PIX_FMT_GBRAP12 AV_PIX_FMT_NE(GBRAP12BE, GBRAP12LE) +#define AV_PIX_FMT_GBRAP16 AV_PIX_FMT_NE(GBRAP16BE, GBRAP16LE) + +#define AV_PIX_FMT_BAYER_BGGR16 AV_PIX_FMT_NE(BAYER_BGGR16BE, BAYER_BGGR16LE) +#define AV_PIX_FMT_BAYER_RGGB16 AV_PIX_FMT_NE(BAYER_RGGB16BE, BAYER_RGGB16LE) +#define AV_PIX_FMT_BAYER_GBRG16 AV_PIX_FMT_NE(BAYER_GBRG16BE, BAYER_GBRG16LE) +#define AV_PIX_FMT_BAYER_GRBG16 AV_PIX_FMT_NE(BAYER_GRBG16BE, BAYER_GRBG16LE) + +#define AV_PIX_FMT_GBRPF32 AV_PIX_FMT_NE(GBRPF32BE, GBRPF32LE) +#define AV_PIX_FMT_GBRAPF32 AV_PIX_FMT_NE(GBRAPF32BE, GBRAPF32LE) + +#define AV_PIX_FMT_GRAYF32 AV_PIX_FMT_NE(GRAYF32BE, GRAYF32LE) + +#define AV_PIX_FMT_YUVA420P9 AV_PIX_FMT_NE(YUVA420P9BE , YUVA420P9LE) +#define AV_PIX_FMT_YUVA422P9 AV_PIX_FMT_NE(YUVA422P9BE , YUVA422P9LE) +#define AV_PIX_FMT_YUVA444P9 AV_PIX_FMT_NE(YUVA444P9BE , YUVA444P9LE) +#define AV_PIX_FMT_YUVA420P10 AV_PIX_FMT_NE(YUVA420P10BE, YUVA420P10LE) +#define AV_PIX_FMT_YUVA422P10 AV_PIX_FMT_NE(YUVA422P10BE, YUVA422P10LE) +#define AV_PIX_FMT_YUVA444P10 AV_PIX_FMT_NE(YUVA444P10BE, YUVA444P10LE) +#define AV_PIX_FMT_YUVA422P12 AV_PIX_FMT_NE(YUVA422P12BE, YUVA422P12LE) +#define AV_PIX_FMT_YUVA444P12 AV_PIX_FMT_NE(YUVA444P12BE, YUVA444P12LE) +#define AV_PIX_FMT_YUVA420P16 AV_PIX_FMT_NE(YUVA420P16BE, YUVA420P16LE) +#define AV_PIX_FMT_YUVA422P16 AV_PIX_FMT_NE(YUVA422P16BE, YUVA422P16LE) +#define AV_PIX_FMT_YUVA444P16 AV_PIX_FMT_NE(YUVA444P16BE, YUVA444P16LE) + +#define AV_PIX_FMT_XYZ12 AV_PIX_FMT_NE(XYZ12BE, XYZ12LE) +#define AV_PIX_FMT_NV20 AV_PIX_FMT_NE(NV20BE, NV20LE) +#define AV_PIX_FMT_AYUV64 AV_PIX_FMT_NE(AYUV64BE, AYUV64LE) +#define AV_PIX_FMT_P010 AV_PIX_FMT_NE(P010BE, P010LE) +#define AV_PIX_FMT_P016 AV_PIX_FMT_NE(P016BE, P016LE) + +/** + * Chromaticity coordinates of the source primaries. + * These values match the ones defined by ISO/IEC 23001-8_2013 搂 7.1. + */ +enum AVColorPrimaries { + AVCOL_PRI_RESERVED0 = 0, + AVCOL_PRI_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B + AVCOL_PRI_UNSPECIFIED = 2, + AVCOL_PRI_RESERVED = 3, + AVCOL_PRI_BT470M = 4, ///< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + + AVCOL_PRI_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM + AVCOL_PRI_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_PRI_SMPTE240M = 7, ///< functionally identical to above + AVCOL_PRI_FILM = 8, ///< colour filters using Illuminant C + AVCOL_PRI_BT2020 = 9, ///< ITU-R BT2020 + AVCOL_PRI_SMPTE428 = 10, ///< SMPTE ST 428-1 (CIE 1931 XYZ) + AVCOL_PRI_SMPTEST428_1 = AVCOL_PRI_SMPTE428, + AVCOL_PRI_SMPTE431 = 11, ///< SMPTE ST 431-2 (2011) / DCI P3 + AVCOL_PRI_SMPTE432 = 12, ///< SMPTE ST 432-1 (2010) / P3 D65 / Display P3 + AVCOL_PRI_JEDEC_P22 = 22, ///< JEDEC P22 phosphors + AVCOL_PRI_NB ///< Not part of ABI +}; + +/** + * Color Transfer Characteristic. + * These values match the ones defined by ISO/IEC 23001-8_2013 搂 7.2. + */ +enum AVColorTransferCharacteristic { + AVCOL_TRC_RESERVED0 = 0, + AVCOL_TRC_BT709 = 1, ///< also ITU-R BT1361 + AVCOL_TRC_UNSPECIFIED = 2, + AVCOL_TRC_RESERVED = 3, + AVCOL_TRC_GAMMA22 = 4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM + AVCOL_TRC_GAMMA28 = 5, ///< also ITU-R BT470BG + AVCOL_TRC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC + AVCOL_TRC_SMPTE240M = 7, + AVCOL_TRC_LINEAR = 8, ///< "Linear transfer characteristics" + AVCOL_TRC_LOG = 9, ///< "Logarithmic transfer characteristic (100:1 range)" + AVCOL_TRC_LOG_SQRT = 10, ///< "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)" + AVCOL_TRC_IEC61966_2_4 = 11, ///< IEC 61966-2-4 + AVCOL_TRC_BT1361_ECG = 12, ///< ITU-R BT1361 Extended Colour Gamut + AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC) + AVCOL_TRC_BT2020_10 = 14, ///< ITU-R BT2020 for 10-bit system + AVCOL_TRC_BT2020_12 = 15, ///< ITU-R BT2020 for 12-bit system + AVCOL_TRC_SMPTE2084 = 16, ///< SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems + AVCOL_TRC_SMPTEST2084 = AVCOL_TRC_SMPTE2084, + AVCOL_TRC_SMPTE428 = 17, ///< SMPTE ST 428-1 + AVCOL_TRC_SMPTEST428_1 = AVCOL_TRC_SMPTE428, + AVCOL_TRC_ARIB_STD_B67 = 18, ///< ARIB STD-B67, known as "Hybrid log-gamma" + AVCOL_TRC_NB ///< Not part of ABI +}; + +/** + * YUV colorspace type. + * These values match the ones defined by ISO/IEC 23001-8_2013 搂 7.3. + */ +enum AVColorSpace { + AVCOL_SPC_RGB = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB) + AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B + AVCOL_SPC_UNSPECIFIED = 2, + AVCOL_SPC_RESERVED = 3, + AVCOL_SPC_FCC = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 + AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_SPC_SMPTE240M = 7, ///< functionally identical to above + AVCOL_SPC_YCGCO = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_YCOCG = AVCOL_SPC_YCGCO, + AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system + AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system + AVCOL_SPC_SMPTE2085 = 11, ///< SMPTE 2085, Y'D'zD'x + AVCOL_SPC_CHROMA_DERIVED_NCL = 12, ///< Chromaticity-derived non-constant luminance system + AVCOL_SPC_CHROMA_DERIVED_CL = 13, ///< Chromaticity-derived constant luminance system + AVCOL_SPC_ICTCP = 14, ///< ITU-R BT.2100-0, ICtCp + AVCOL_SPC_NB ///< Not part of ABI +}; + +/** + * MPEG vs JPEG YUV range. + */ +enum AVColorRange { + AVCOL_RANGE_UNSPECIFIED = 0, + AVCOL_RANGE_MPEG = 1, ///< the normal 219*2^(n-8) "MPEG" YUV ranges + AVCOL_RANGE_JPEG = 2, ///< the normal 2^n-1 "JPEG" YUV ranges + AVCOL_RANGE_NB ///< Not part of ABI +}; + +/** + * Location of chroma samples. + * + * Illustration showing the location of the first (top left) chroma sample of the + * image, the left shows only luma, the right + * shows the location of the chroma sample, the 2 could be imagined to overlay + * each other but are drawn separately due to limitations of ASCII + * + * 1st 2nd 1st 2nd horizontal luma sample positions + * v v v v + * ______ ______ + *1st luma line > |X X ... |3 4 X ... X are luma samples, + * | |1 2 1-6 are possible chroma positions + *2nd luma line > |X X ... |5 6 X ... 0 is undefined/unknown position + */ +enum AVChromaLocation { + AVCHROMA_LOC_UNSPECIFIED = 0, + AVCHROMA_LOC_LEFT = 1, ///< MPEG-2/4 4:2:0, H.264 default for 4:2:0 + AVCHROMA_LOC_CENTER = 2, ///< MPEG-1 4:2:0, JPEG 4:2:0, H.263 4:2:0 + AVCHROMA_LOC_TOPLEFT = 3, ///< ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2 + AVCHROMA_LOC_TOP = 4, + AVCHROMA_LOC_BOTTOMLEFT = 5, + AVCHROMA_LOC_BOTTOM = 6, + AVCHROMA_LOC_NB ///< Not part of ABI +}; + +#endif /* AVUTIL_PIXFMT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/qsort.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/qsort.h new file mode 100644 index 0000000000..39b7a08852 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/qsort.h @@ -0,0 +1,122 @@ +/* + * copyright (c) 2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_QSORT_H +#define AVUTIL_QSORT_H + +#include "common.h" + + +/** + * Quicksort + * This sort is fast, and fully inplace but not stable and it is possible + * to construct input that requires O(n^2) time but this is very unlikely to + * happen with non constructed input. + */ +#define AV_QSORT(p, num, type, cmp) do {\ + void *stack[64][2];\ + int sp= 1;\ + stack[0][0] = p;\ + stack[0][1] = (p)+(num)-1;\ + while(sp){\ + type *start= stack[--sp][0];\ + type *end = stack[ sp][1];\ + while(start < end){\ + if(start < end-1) {\ + int checksort=0;\ + type *right = end-2;\ + type *left = start+1;\ + type *mid = start + ((end-start)>>1);\ + if(cmp(start, end) > 0) {\ + if(cmp( end, mid) > 0) FFSWAP(type, *start, *mid);\ + else FFSWAP(type, *start, *end);\ + }else{\ + if(cmp(start, mid) > 0) FFSWAP(type, *start, *mid);\ + else checksort= 1;\ + }\ + if(cmp(mid, end) > 0){ \ + FFSWAP(type, *mid, *end);\ + checksort=0;\ + }\ + if(start == end-2) break;\ + FFSWAP(type, end[-1], *mid);\ + while(left <= right){\ + while(left<=right && cmp(left, end-1) < 0)\ + left++;\ + while(left<=right && cmp(right, end-1) > 0)\ + right--;\ + if(left <= right){\ + FFSWAP(type, *left, *right);\ + left++;\ + right--;\ + }\ + }\ + FFSWAP(type, end[-1], *left);\ + if(checksort && (mid == left-1 || mid == left)){\ + mid= start;\ + while(mid 0)\ + FFSWAP(type, *start, *end);\ + break;\ + }\ + }\ + }\ +} while (0) + +/** + * Merge sort, this sort requires a temporary buffer and is stable, its worst + * case time is O(n log n) + * @param p must be a lvalue pointer, this function may exchange it with tmp + * @param tmp must be a lvalue pointer, this function may exchange it with p + */ +#define AV_MSORT(p, tmp, num, type, cmp) do {\ + unsigned i, j, step;\ + for(step=1; step<(num); step+=step){\ + for(i=0; i<(num); i+=2*step){\ + unsigned a[2] = {i, i+step};\ + unsigned end = FFMIN(i+2*step, (num));\ + for(j=i; a[0] 0;\ + tmp[j] = p[ a[idx]++ ];\ + }\ + if(a[0]>=i+step) a[0] = a[1];\ + for(; j + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_IO_H +#include +#endif +#if HAVE_BCRYPT +#include +#include +#endif +#include +#include +#include +#include +#include "avassert.h" +#include "internal.h" +#include "intreadwrite.h" +#include "timer.h" +#include "random_seed.h" +#include "sha.h" + +#ifndef TEST +#define TEST 0 +#endif + +static int read_random(uint32_t *dst, const char *file) +{ +#if HAVE_UNISTD_H + int fd = avpriv_open(file, O_RDONLY); + int err = -1; + + if (fd == -1) + return -1; + err = read(fd, dst, sizeof(*dst)); + close(fd); + + return err; +#else + return -1; +#endif +} + +static uint32_t get_generic_seed(void) +{ + uint64_t tmp[120/8]; + struct AVSHA *sha = (void*)tmp; + clock_t last_t = 0; + clock_t last_td = 0; + clock_t init_t = 0; + static uint64_t i = 0; + static uint32_t buffer[512] = { 0 }; + unsigned char digest[20]; + uint64_t last_i = i; + + av_assert0(sizeof(tmp) >= av_sha_size); + + if(TEST){ + memset(buffer, 0, sizeof(buffer)); + last_i = i = 0; + }else{ +#ifdef AV_READ_TIME + buffer[13] ^= AV_READ_TIME(); + buffer[41] ^= AV_READ_TIME()>>32; +#endif + } + + for (;;) { + clock_t t = clock(); + if (last_t + 2*last_td + (CLOCKS_PER_SEC > 1000) >= t) { + last_td = t - last_t; + buffer[i & 511] = 1664525*buffer[i & 511] + 1013904223 + (last_td % 3294638521U); + } else { + last_td = t - last_t; + buffer[++i & 511] += last_td % 3294638521U; + if ((t - init_t) >= CLOCKS_PER_SEC>>5) + if (last_i && i - last_i > 4 || i - last_i > 64 || TEST && i - last_i > 8) + break; + } + last_t = t; + if (!init_t) + init_t = t; + } + + if(TEST) { + buffer[0] = buffer[1] = 0; + } else { +#ifdef AV_READ_TIME + buffer[111] += AV_READ_TIME(); +#endif + } + + av_sha_init(sha, 160); + av_sha_update(sha, (const uint8_t *)buffer, sizeof(buffer)); + av_sha_final(sha, digest); + return AV_RB32(digest) + AV_RB32(digest + 16); +} + +uint32_t av_get_random_seed(void) +{ + uint32_t seed; + +#if HAVE_BCRYPT + BCRYPT_ALG_HANDLE algo_handle; + NTSTATUS ret = BCryptOpenAlgorithmProvider(&algo_handle, BCRYPT_RNG_ALGORITHM, + MS_PRIMITIVE_PROVIDER, 0); + if (BCRYPT_SUCCESS(ret)) { + NTSTATUS ret = BCryptGenRandom(algo_handle, (UCHAR*)&seed, sizeof(seed), 0); + BCryptCloseAlgorithmProvider(algo_handle, 0); + if (BCRYPT_SUCCESS(ret)) + return seed; + } +#endif + +#if HAVE_ARC4RANDOM + return arc4random(); +#endif + + if (read_random(&seed, "/dev/urandom") == sizeof(seed)) + return seed; + if (read_random(&seed, "/dev/random") == sizeof(seed)) + return seed; + return get_generic_seed(); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/random_seed.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/random_seed.h new file mode 100644 index 0000000000..0462a048e0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/random_seed.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009 Baptiste Coudurier + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RANDOM_SEED_H +#define AVUTIL_RANDOM_SEED_H + +#include +/** + * @addtogroup lavu_crypto + * @{ + */ + +/** + * Get a seed to use in conjunction with random functions. + * This function tries to provide a good seed at a best effort bases. + * Its possible to call this function multiple times if more bits are needed. + * It can be quite slow, which is why it should only be used as seed for a faster + * PRNG. The quality of the seed depends on the platform. + */ +uint32_t av_get_random_seed(void); + +/** + * @} + */ + +#endif /* AVUTIL_RANDOM_SEED_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rational.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rational.c new file mode 100644 index 0000000000..35ee08877f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rational.c @@ -0,0 +1,184 @@ +/* + * rational numbers + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * rational numbers + * @author Michael Niedermayer + */ + +#include "avassert.h" +#include + +#include "common.h" +#include "mathematics.h" +#include "rational.h" + +int av_reduce(int *dst_num, int *dst_den, + int64_t num, int64_t den, int64_t max) +{ + AVRational a0 = { 0, 1 }, a1 = { 1, 0 }; + int sign = (num < 0) ^ (den < 0); + int64_t gcd = av_gcd(FFABS(num), FFABS(den)); + + if (gcd) { + num = FFABS(num) / gcd; + den = FFABS(den) / gcd; + } + if (num <= max && den <= max) { + a1 = (AVRational) { num, den }; + den = 0; + } + + while (den) { + uint64_t x = num / den; + int64_t next_den = num - den * x; + int64_t a2n = x * a1.num + a0.num; + int64_t a2d = x * a1.den + a0.den; + + if (a2n > max || a2d > max) { + if (a1.num) x = (max - a0.num) / a1.num; + if (a1.den) x = FFMIN(x, (max - a0.den) / a1.den); + + if (den * (2 * x * a1.den + a0.den) > num * a1.den) + a1 = (AVRational) { x * a1.num + a0.num, x * a1.den + a0.den }; + break; + } + + a0 = a1; + a1 = (AVRational) { a2n, a2d }; + num = den; + den = next_den; + } + av_assert2(av_gcd(a1.num, a1.den) <= 1U); + av_assert2(a1.num <= max && a1.den <= max); + + *dst_num = sign ? -a1.num : a1.num; + *dst_den = a1.den; + + return den == 0; +} + +AVRational av_mul_q(AVRational b, AVRational c) +{ + av_reduce(&b.num, &b.den, + b.num * (int64_t) c.num, + b.den * (int64_t) c.den, INT_MAX); + return b; +} + +AVRational av_div_q(AVRational b, AVRational c) +{ + return av_mul_q(b, (AVRational) { c.den, c.num }); +} + +AVRational av_add_q(AVRational b, AVRational c) { + av_reduce(&b.num, &b.den, + b.num * (int64_t) c.den + + c.num * (int64_t) b.den, + b.den * (int64_t) c.den, INT_MAX); + return b; +} + +AVRational av_sub_q(AVRational b, AVRational c) +{ + return av_add_q(b, (AVRational) { -c.num, c.den }); +} + +AVRational av_d2q(double d, int max) +{ + AVRational a; + int exponent; + int64_t den; + if (isnan(d)) + return (AVRational) { 0,0 }; + if (fabs(d) > INT_MAX + 3LL) + return (AVRational) { d < 0 ? -1 : 1, 0 }; + frexp(d, &exponent); + exponent = FFMAX(exponent-1, 0); + den = 1LL << (61 - exponent); + // (int64_t)rint() and llrint() do not work with gcc on ia64 and sparc64, + // see Ticket2713 for affected gcc/glibc versions + av_reduce(&a.num, &a.den, floor(d * den + 0.5), den, max); + if ((!a.num || !a.den) && d && max>0 && max n => a*d/b > n */ + int64_t x_up = av_rescale_rnd(a, q.den, b, AV_ROUND_UP); + + /* rnd_down(a*d/b) < n => a*d/b < n */ + int64_t x_down = av_rescale_rnd(a, q.den, b, AV_ROUND_DOWN); + + return ((x_up > q.num) - (x_down < q.num)) * av_cmp_q(q2, q1); +} + +int av_find_nearest_q_idx(AVRational q, const AVRational* q_list) +{ + int i, nearest_q_idx = 0; + for (i = 0; q_list[i].den; i++) + if (av_nearer_q(q, q_list[i], q_list[nearest_q_idx]) > 0) + nearest_q_idx = i; + + return nearest_q_idx; +} + +uint32_t av_q2intfloat(AVRational q) { + int64_t n; + int shift; + int sign = 0; + + if (q.den < 0) { + q.den *= -1; + q.num *= -1; + } + if (q.num < 0) { + q.num *= -1; + sign = 1; + } + + if (!q.num && !q.den) return 0xFFC00000; + if (!q.num) return 0; + if (!q.den) return 0x7F800000 | (q.num & 0x80000000); + + shift = 23 + av_log2(q.den) - av_log2(q.num); + if (shift >= 0) n = av_rescale(q.num, 1LL<= (1<<24); + shift += n < (1<<23); + + if (shift >= 0) n = av_rescale(q.num, 1LL<= (1<<23)); + + return sign<<31 | (150-shift)<<23 | (n - (1<<23)); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rational.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rational.h new file mode 100644 index 0000000000..5c6b67b4e9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rational.h @@ -0,0 +1,214 @@ +/* + * rational numbers + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_math_rational + * Utilties for rational number calculation. + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_RATIONAL_H +#define AVUTIL_RATIONAL_H + +#include +#include +#include "attributes.h" + +/** + * @defgroup lavu_math_rational AVRational + * @ingroup lavu_math + * Rational number calculation. + * + * While rational numbers can be expressed as floating-point numbers, the + * conversion process is a lossy one, so are floating-point operations. On the + * other hand, the nature of FFmpeg demands highly accurate calculation of + * timestamps. This set of rational number utilities serves as a generic + * interface for manipulating rational numbers as pairs of numerators and + * denominators. + * + * Many of the functions that operate on AVRational's have the suffix `_q`, in + * reference to the mathematical symbol "鈩" (Q) which denotes the set of all + * rational numbers. + * + * @{ + */ + +/** + * Rational number (pair of numerator and denominator). + */ +typedef struct AVRational{ + int num; ///< Numerator + int den; ///< Denominator +} AVRational; + +/** + * Create an AVRational. + * + * Useful for compilers that do not support compound literals. + * + * @note The return value is not reduced. + * @see av_reduce() + */ +static inline AVRational av_make_q(int num, int den) +{ + AVRational r = { num, den }; + return r; +} + +/** + * Compare two rationals. + * + * @param a First rational + * @param b Second rational + * + * @return One of the following values: + * - 0 if `a == b` + * - 1 if `a > b` + * - -1 if `a < b` + * - `INT_MIN` if one of the values is of the form `0 / 0` + */ +static inline int av_cmp_q(AVRational a, AVRational b){ + const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den; + + if(tmp) return (int)((tmp ^ a.den ^ b.den)>>63)|1; + else if(b.den && a.den) return 0; + else if(a.num && b.num) return (a.num>>31) - (b.num>>31); + else return INT_MIN; +} + +/** + * Convert an AVRational to a `double`. + * @param a AVRational to convert + * @return `a` in floating-point form + * @see av_d2q() + */ +static inline double av_q2d(AVRational a){ + return a.num / (double) a.den; +} + +/** + * Reduce a fraction. + * + * This is useful for framerate calculations. + * + * @param[out] dst_num Destination numerator + * @param[out] dst_den Destination denominator + * @param[in] num Source numerator + * @param[in] den Source denominator + * @param[in] max Maximum allowed values for `dst_num` & `dst_den` + * @return 1 if the operation is exact, 0 otherwise + */ +int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max); + +/** + * Multiply two rationals. + * @param b First rational + * @param c Second rational + * @return b*c + */ +AVRational av_mul_q(AVRational b, AVRational c) av_const; + +/** + * Divide one rational by another. + * @param b First rational + * @param c Second rational + * @return b/c + */ +AVRational av_div_q(AVRational b, AVRational c) av_const; + +/** + * Add two rationals. + * @param b First rational + * @param c Second rational + * @return b+c + */ +AVRational av_add_q(AVRational b, AVRational c) av_const; + +/** + * Subtract one rational from another. + * @param b First rational + * @param c Second rational + * @return b-c + */ +AVRational av_sub_q(AVRational b, AVRational c) av_const; + +/** + * Invert a rational. + * @param q value + * @return 1 / q + */ +static av_always_inline AVRational av_inv_q(AVRational q) +{ + AVRational r = { q.den, q.num }; + return r; +} + +/** + * Convert a double precision floating point number to a rational. + * + * In case of infinity, the returned value is expressed as `{1, 0}` or + * `{-1, 0}` depending on the sign. + * + * @param d `double` to convert + * @param max Maximum allowed numerator and denominator + * @return `d` in AVRational form + * @see av_q2d() + */ +AVRational av_d2q(double d, int max) av_const; + +/** + * Find which of the two rationals is closer to another rational. + * + * @param q Rational to be compared against + * @param q1,q2 Rationals to be tested + * @return One of the following values: + * - 1 if `q1` is nearer to `q` than `q2` + * - -1 if `q2` is nearer to `q` than `q1` + * - 0 if they have the same distance + */ +int av_nearer_q(AVRational q, AVRational q1, AVRational q2); + +/** + * Find the value in a list of rationals nearest a given reference rational. + * + * @param q Reference rational + * @param q_list Array of rationals terminated by `{0, 0}` + * @return Index of the nearest value found in the array + */ +int av_find_nearest_q_idx(AVRational q, const AVRational* q_list); + +/** + * Convert an AVRational to a IEEE 32-bit `float` expressed in fixed-point + * format. + * + * @param q Rational to be converted + * @return Equivalent floating-point value, expressed as an unsigned 32-bit + * integer. + * @note The returned value is platform-indepedant. + */ +uint32_t av_q2intfloat(AVRational q); + +/** + * @} + */ + +#endif /* AVUTIL_RATIONAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rc4.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rc4.c new file mode 100644 index 0000000000..ffcb112142 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rc4.c @@ -0,0 +1,65 @@ +/* + * RC4 encryption/decryption/pseudo-random number generator + * Copyright (c) 2007 Reimar Doeffinger + * + * loosely based on LibTomCrypt by Tom St Denis + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "avutil.h" +#include "common.h" +#include "mem.h" +#include "rc4.h" + +AVRC4 *av_rc4_alloc(void) +{ + return av_mallocz(sizeof(struct AVRC4)); +} + +int av_rc4_init(AVRC4 *r, const uint8_t *key, int key_bits, int decrypt) { + int i, j; + uint8_t y; + uint8_t *state = r->state; + int keylen = key_bits >> 3; + if (key_bits & 7) + return AVERROR(EINVAL); + for (i = 0; i < 256; i++) + state[i] = i; + y = 0; + // j is i % keylen + for (j = 0, i = 0; i < 256; i++, j++) { + if (j == keylen) j = 0; + y += state[i] + key[j]; + FFSWAP(uint8_t, state[i], state[y]); + } + r->x = 1; + r->y = state[1]; + return 0; +} + +void av_rc4_crypt(AVRC4 *r, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt) { + uint8_t x = r->x, y = r->y; + uint8_t *state = r->state; + while (count-- > 0) { + uint8_t sum = state[x] + state[y]; + FFSWAP(uint8_t, state[x], state[y]); + *dst++ = src ? *src++ ^ state[sum] : state[sum]; + x++; + y += state[x]; + } + r->x = x; r->y = y; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rc4.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rc4.h new file mode 100644 index 0000000000..029cd2ad58 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/rc4.h @@ -0,0 +1,66 @@ +/* + * RC4 encryption/decryption/pseudo-random number generator + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RC4_H +#define AVUTIL_RC4_H + +#include + +/** + * @defgroup lavu_rc4 RC4 + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVRC4 { + uint8_t state[256]; + int x, y; +} AVRC4; + +/** + * Allocate an AVRC4 context. + */ +AVRC4 *av_rc4_alloc(void); + +/** + * @brief Initializes an AVRC4 context. + * + * @param key_bits must be a multiple of 8 + * @param decrypt 0 for encryption, 1 for decryption, currently has no effect + * @return zero on success, negative value otherwise + */ +int av_rc4_init(struct AVRC4 *d, const uint8_t *key, int key_bits, int decrypt); + +/** + * @brief Encrypts / decrypts using the RC4 algorithm. + * + * @param count number of bytes + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst, may be NULL + * @param iv not (yet) used for RC4, should be NULL + * @param decrypt 0 for encryption, 1 for decryption, not (yet) used + */ +void av_rc4_crypt(struct AVRC4 *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_RC4_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/replaygain.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/replaygain.h new file mode 100644 index 0000000000..b49bf1a3d9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/replaygain.h @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REPLAYGAIN_H +#define AVUTIL_REPLAYGAIN_H + +#include + +/** + * ReplayGain information (see + * http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_1.0_specification). + * The size of this struct is a part of the public ABI. + */ +typedef struct AVReplayGain { + /** + * Track replay gain in microbels (divide by 100000 to get the value in dB). + * Should be set to INT32_MIN when unknown. + */ + int32_t track_gain; + /** + * Peak track amplitude, with 100000 representing full scale (but values + * may overflow). 0 when unknown. + */ + uint32_t track_peak; + /** + * Same as track_gain, but for the whole album. + */ + int32_t album_gain; + /** + * Same as track_peak, but for the whole album, + */ + uint32_t album_peak; +} AVReplayGain; + +#endif /* AVUTIL_REPLAYGAIN_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/reverse.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/reverse.c new file mode 100644 index 0000000000..105eb03dda --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/reverse.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +const uint8_t ff_reverse[256] = { +0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, +0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, +0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, +0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, +0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, +0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, +0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, +0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, +0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, +0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, +0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, +0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, +0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, +0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, +0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, +0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/reverse.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/reverse.h new file mode 100644 index 0000000000..4eb6123932 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/reverse.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2002-2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REVERSE_H +#define AVUTIL_REVERSE_H + +#include + +extern const uint8_t ff_reverse[256]; + +#endif /* AVUTIL_REVERSE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ripemd.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ripemd.c new file mode 100644 index 0000000000..4f1c4ea899 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ripemd.c @@ -0,0 +1,555 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "attributes.h" +#include "avutil.h" +#include "bswap.h" +#include "intreadwrite.h" +#include "ripemd.h" +#include "mem.h" + +/** hash context */ +typedef struct AVRIPEMD { + uint8_t digest_len; ///< digest length in 32-bit words + uint64_t count; ///< number of bytes in buffer + uint8_t buffer[64]; ///< 512-bit buffer of input values used in hash updating + uint32_t state[10]; ///< current hash value + /** function used to update hash for 512-bit input block */ + void (*transform)(uint32_t *state, const uint8_t buffer[64]); +} AVRIPEMD; + +const int av_ripemd_size = sizeof(AVRIPEMD); + +struct AVRIPEMD *av_ripemd_alloc(void) +{ + return av_mallocz(sizeof(struct AVRIPEMD)); +} + +static const uint32_t KA[4] = { + 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e +}; + +static const uint32_t KB[4] = { + 0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9 +}; + +static const int ROTA[80] = { + 11, 14, 15, 12, 5, 8, 7 , 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7 , 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 +}; + +static const int ROTB[80] = { + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 +}; + +static const int WA[80] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 +}; + +static const int WB[80] = { + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 +}; + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +#define ROUND128_0_TO_15(a,b,c,d,e,f,g,h) \ + a = rol(a + (( b ^ c ^ d) + block[WA[n]]), ROTA[n]); \ + e = rol(e + ((((f ^ g) & h) ^ g) + block[WB[n]] + KB[0]), ROTB[n]); \ + n++ + +#define ROUND128_16_TO_31(a,b,c,d,e,f,g,h) \ + a = rol(a + ((((c ^ d) & b) ^ d) + block[WA[n]] + KA[0]), ROTA[n]); \ + e = rol(e + (((~g | f) ^ h) + block[WB[n]] + KB[1]), ROTB[n]); \ + n++ + +#define ROUND128_32_TO_47(a,b,c,d,e,f,g,h) \ + a = rol(a + (((~c | b) ^ d) + block[WA[n]] + KA[1]), ROTA[n]); \ + e = rol(e + ((((g ^ h) & f) ^ h) + block[WB[n]] + KB[2]), ROTB[n]); \ + n++ + +#define ROUND128_48_TO_63(a,b,c,d,e,f,g,h) \ + a = rol(a + ((((b ^ c) & d) ^ c) + block[WA[n]] + KA[2]), ROTA[n]); \ + e = rol(e + (( f ^ g ^ h) + block[WB[n]]), ROTB[n]); \ + n++ + +#define R128_0 \ + ROUND128_0_TO_15(a,b,c,d,e,f,g,h); \ + ROUND128_0_TO_15(d,a,b,c,h,e,f,g); \ + ROUND128_0_TO_15(c,d,a,b,g,h,e,f); \ + ROUND128_0_TO_15(b,c,d,a,f,g,h,e) + +#define R128_16 \ + ROUND128_16_TO_31(a,b,c,d,e,f,g,h); \ + ROUND128_16_TO_31(d,a,b,c,h,e,f,g); \ + ROUND128_16_TO_31(c,d,a,b,g,h,e,f); \ + ROUND128_16_TO_31(b,c,d,a,f,g,h,e) + +#define R128_32 \ + ROUND128_32_TO_47(a,b,c,d,e,f,g,h); \ + ROUND128_32_TO_47(d,a,b,c,h,e,f,g); \ + ROUND128_32_TO_47(c,d,a,b,g,h,e,f); \ + ROUND128_32_TO_47(b,c,d,a,f,g,h,e) + +#define R128_48 \ + ROUND128_48_TO_63(a,b,c,d,e,f,g,h); \ + ROUND128_48_TO_63(d,a,b,c,h,e,f,g); \ + ROUND128_48_TO_63(c,d,a,b,g,h,e,f); \ + ROUND128_48_TO_63(b,c,d,a,f,g,h,e) + +static void ripemd128_transform(uint32_t *state, const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e, f, g, h, av_unused t; + uint32_t block[16]; + int n; + + a = e = state[0]; + b = f = state[1]; + c = g = state[2]; + d = h = state[3]; + + for (n = 0; n < 16; n++) + block[n] = AV_RL32(buffer + 4 * n); + n = 0; + +#if CONFIG_SMALL + for (; n < 16;) { + ROUND128_0_TO_15(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + + for (; n < 32;) { + ROUND128_16_TO_31(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + + for (; n < 48;) { + ROUND128_32_TO_47(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + + for (; n < 64;) { + ROUND128_48_TO_63(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } +#else + + R128_0; R128_0; R128_0; R128_0; + + R128_16; R128_16; R128_16; R128_16; + + R128_32; R128_32; R128_32; R128_32; + + R128_48; R128_48; R128_48; R128_48; +#endif + + h += c + state[1]; + state[1] = state[2] + d + e; + state[2] = state[3] + a + f; + state[3] = state[0] + b + g; + state[0] = h; +} + +static void ripemd256_transform(uint32_t *state, const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e, f, g, h, av_unused t; + uint32_t block[16]; + int n; + + a = state[0]; b = state[1]; c = state[2]; d = state[3]; + e = state[4]; f = state[5]; g = state[6]; h = state[7]; + + for (n = 0; n < 16; n++) + block[n] = AV_RL32(buffer + 4 * n); + n = 0; + +#if CONFIG_SMALL + for (; n < 16;) { + ROUND128_0_TO_15(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + FFSWAP(uint32_t, a, e); + + for (; n < 32;) { + ROUND128_16_TO_31(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + FFSWAP(uint32_t, b, f); + + for (; n < 48;) { + ROUND128_32_TO_47(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + FFSWAP(uint32_t, c, g); + + for (; n < 64;) { + ROUND128_48_TO_63(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + FFSWAP(uint32_t, d, h); +#else + + R128_0; R128_0; R128_0; R128_0; + FFSWAP(uint32_t, a, e); + + R128_16; R128_16; R128_16; R128_16; + FFSWAP(uint32_t, b, f); + + R128_32; R128_32; R128_32; R128_32; + FFSWAP(uint32_t, c, g); + + R128_48; R128_48; R128_48; R128_48; + FFSWAP(uint32_t, d, h); +#endif + + state[0] += a; state[1] += b; state[2] += c; state[3] += d; + state[4] += e; state[5] += f; state[6] += g; state[7] += h; +} + +#define ROTATE(x,y) \ + x = rol(x, 10); \ + y = rol(y, 10); \ + n++ + +#define ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j) \ + a = rol(a + (( b ^ c ^ d) + block[WA[n]]), ROTA[n]) + e; \ + f = rol(f + (((~i | h) ^ g) + block[WB[n]] + KB[0]), ROTB[n]) + j; \ + ROTATE(c,h) + +#define ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j) \ + a = rol(a + ((((c ^ d) & b) ^ d) + block[WA[n]] + KA[0]), ROTA[n]) + e; \ + f = rol(f + ((((g ^ h) & i) ^ h) + block[WB[n]] + KB[1]), ROTB[n]) + j; \ + ROTATE(c,h) + +#define ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j) \ + a = rol(a + (((~c | b) ^ d) + block[WA[n]] + KA[1]), ROTA[n]) + e; \ + f = rol(f + (((~h | g) ^ i) + block[WB[n]] + KB[2]), ROTB[n]) + j; \ + ROTATE(c,h) + +#define ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j) \ + a = rol(a + ((((b ^ c) & d) ^ c) + block[WA[n]] + KA[2]), ROTA[n]) + e; \ + f = rol(f + ((((h ^ i) & g) ^ i) + block[WB[n]] + KB[3]), ROTB[n]) + j; \ + ROTATE(c,h) + +#define ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j) \ + a = rol(a + (((~d | c) ^ b) + block[WA[n]] + KA[3]), ROTA[n]) + e; \ + f = rol(f + (( g ^ h ^ i) + block[WB[n]]), ROTB[n]) + j; \ + ROTATE(c,h) + +#define R160_0 \ + ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); \ + ROUND160_0_TO_15(e,a,b,c,d,j,f,g,h,i); \ + ROUND160_0_TO_15(d,e,a,b,c,i,j,f,g,h); \ + ROUND160_0_TO_15(c,d,e,a,b,h,i,j,f,g); \ + ROUND160_0_TO_15(b,c,d,e,a,g,h,i,j,f) + +#define R160_16 \ + ROUND160_16_TO_31(e,a,b,c,d,j,f,g,h,i); \ + ROUND160_16_TO_31(d,e,a,b,c,i,j,f,g,h); \ + ROUND160_16_TO_31(c,d,e,a,b,h,i,j,f,g); \ + ROUND160_16_TO_31(b,c,d,e,a,g,h,i,j,f); \ + ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j) + +#define R160_32 \ + ROUND160_32_TO_47(d,e,a,b,c,i,j,f,g,h); \ + ROUND160_32_TO_47(c,d,e,a,b,h,i,j,f,g); \ + ROUND160_32_TO_47(b,c,d,e,a,g,h,i,j,f); \ + ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j); \ + ROUND160_32_TO_47(e,a,b,c,d,j,f,g,h,i) + +#define R160_48 \ + ROUND160_48_TO_63(c,d,e,a,b,h,i,j,f,g); \ + ROUND160_48_TO_63(b,c,d,e,a,g,h,i,j,f); \ + ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j); \ + ROUND160_48_TO_63(e,a,b,c,d,j,f,g,h,i); \ + ROUND160_48_TO_63(d,e,a,b,c,i,j,f,g,h) + +#define R160_64 \ + ROUND160_64_TO_79(b,c,d,e,a,g,h,i,j,f); \ + ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j); \ + ROUND160_64_TO_79(e,a,b,c,d,j,f,g,h,i); \ + ROUND160_64_TO_79(d,e,a,b,c,i,j,f,g,h); \ + ROUND160_64_TO_79(c,d,e,a,b,h,i,j,f,g) + +static void ripemd160_transform(uint32_t *state, const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e, f, g, h, i, j, av_unused t; + uint32_t block[16]; + int n; + + a = f = state[0]; + b = g = state[1]; + c = h = state[2]; + d = i = state[3]; + e = j = state[4]; + + for (n = 0; n < 16; n++) + block[n] = AV_RL32(buffer + 4 * n); + n = 0; + +#if CONFIG_SMALL + for (; n < 16;) { + ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + + for (; n < 32;) { + ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + + for (; n < 48;) { + ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + + for (; n < 64;) { + ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + + for (; n < 80;) { + ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } +#else + + R160_0; R160_0; R160_0; + ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); + + R160_16; R160_16; R160_16; + ROUND160_16_TO_31(e,a,b,c,d,j,f,g,h,i); + + R160_32; R160_32; R160_32; + ROUND160_32_TO_47(d,e,a,b,c,i,j,f,g,h); + + R160_48; R160_48; R160_48; + ROUND160_48_TO_63(c,d,e,a,b,h,i,j,f,g); + + R160_64; R160_64; R160_64; + ROUND160_64_TO_79(b,c,d,e,a,g,h,i,j,f); +#endif + + i += c + state[1]; + state[1] = state[2] + d + j; + state[2] = state[3] + e + f; + state[3] = state[4] + a + g; + state[4] = state[0] + b + h; + state[0] = i; +} + +static void ripemd320_transform(uint32_t *state, const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e, f, g, h, i, j, av_unused t; + uint32_t block[16]; + int n; + + a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; + f = state[5]; g = state[6]; h = state[7]; i = state[8]; j = state[9]; + + for (n = 0; n < 16; n++) + block[n] = AV_RL32(buffer + 4 * n); + n = 0; + +#if CONFIG_SMALL + for (; n < 16;) { + ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + FFSWAP(uint32_t, b, g); + + for (; n < 32;) { + ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + FFSWAP(uint32_t, d, i); + + for (; n < 48;) { + ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + FFSWAP(uint32_t, a, f); + + for (; n < 64;) { + ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + FFSWAP(uint32_t, c, h); + + for (; n < 80;) { + ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + FFSWAP(uint32_t, e, j); +#else + + R160_0; R160_0; R160_0; + ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); + FFSWAP(uint32_t, a, f); + + R160_16; R160_16; R160_16; + ROUND160_16_TO_31(e,a,b,c,d,j,f,g,h,i); + FFSWAP(uint32_t, b, g); + + R160_32; R160_32; R160_32; + ROUND160_32_TO_47(d,e,a,b,c,i,j,f,g,h); + FFSWAP(uint32_t, c, h); + + R160_48; R160_48; R160_48; + ROUND160_48_TO_63(c,d,e,a,b,h,i,j,f,g); + FFSWAP(uint32_t, d, i); + + R160_64; R160_64; R160_64; + ROUND160_64_TO_79(b,c,d,e,a,g,h,i,j,f); + FFSWAP(uint32_t, e, j); +#endif + + state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; + state[5] += f; state[6] += g; state[7] += h; state[8] += i; state[9] += j; +} + +av_cold int av_ripemd_init(AVRIPEMD *ctx, int bits) +{ + ctx->digest_len = bits >> 5; + switch (bits) { + case 128: // RIPEMD-128 + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->transform = ripemd128_transform; + break; + case 160: // RIPEMD-160 + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->transform = ripemd160_transform; + break; + case 256: // RIPEMD-256 + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0x76543210; + ctx->state[5] = 0xFEDCBA98; + ctx->state[6] = 0x89ABCDEF; + ctx->state[7] = 0x01234567; + ctx->transform = ripemd256_transform; + break; + case 320: // RIPEMD-320 + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->state[5] = 0x76543210; + ctx->state[6] = 0xFEDCBA98; + ctx->state[7] = 0x89ABCDEF; + ctx->state[8] = 0x01234567; + ctx->state[9] = 0x3C2D1E0F; + ctx->transform = ripemd320_transform; + break; + default: + return AVERROR(EINVAL); + } + ctx->count = 0; + return 0; +} + +#if FF_API_CRYPTO_SIZE_T +void av_ripemd_update(AVRIPEMD* ctx, const uint8_t* data, unsigned int len) +#else +void av_ripemd_update(AVRIPEMD* ctx, const uint8_t* data, size_t len) +#endif +{ + unsigned int i, j; + + j = ctx->count & 63; + ctx->count += len; +#if CONFIG_SMALL + for (i = 0; i < len; i++) { + ctx->buffer[j++] = data[i]; + if (64 == j) { + ctx->transform(ctx->state, ctx->buffer); + j = 0; + } + } +#else + if ((j + len) > 63) { + memcpy(&ctx->buffer[j], data, (i = 64 - j)); + ctx->transform(ctx->state, ctx->buffer); + for (; i + 63 < len; i += 64) + ctx->transform(ctx->state, &data[i]); + j = 0; + } else + i = 0; + memcpy(&ctx->buffer[j], &data[i], len - i); +#endif +} + +void av_ripemd_final(AVRIPEMD* ctx, uint8_t *digest) +{ + int i; + uint64_t finalcount = av_le2ne64(ctx->count << 3); + + av_ripemd_update(ctx, "\200", 1); + while ((ctx->count & 63) != 56) + av_ripemd_update(ctx, "", 1); + av_ripemd_update(ctx, (uint8_t *)&finalcount, 8); /* Should cause a transform() */ + for (i = 0; i < ctx->digest_len; i++) + AV_WL32(digest + i*4, ctx->state[i]); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ripemd.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ripemd.h new file mode 100644 index 0000000000..0db6858ff3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ripemd.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_ripemd + * Public header for RIPEMD hash function implementation. + */ + +#ifndef AVUTIL_RIPEMD_H +#define AVUTIL_RIPEMD_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_ripemd RIPEMD + * @ingroup lavu_hash + * RIPEMD hash function implementation. + * + * @{ + */ + +extern const int av_ripemd_size; + +struct AVRIPEMD; + +/** + * Allocate an AVRIPEMD context. + */ +struct AVRIPEMD *av_ripemd_alloc(void); + +/** + * Initialize RIPEMD hashing. + * + * @param context pointer to the function context (of size av_ripemd_size) + * @param bits number of bits in digest (128, 160, 256 or 320 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_ripemd_init(struct AVRIPEMD* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +#if FF_API_CRYPTO_SIZE_T +void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, unsigned int len); +#else +void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, size_t len); +#endif + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_ripemd_final(struct AVRIPEMD* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_RIPEMD_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/samplefmt.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/samplefmt.c new file mode 100644 index 0000000000..fc077f6444 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/samplefmt.c @@ -0,0 +1,254 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "common.h" +#include "samplefmt.h" + +#include +#include +#include + +typedef struct SampleFmtInfo { + char name[8]; + int bits; + int planar; + enum AVSampleFormat altform; ///< planar<->packed alternative form +} SampleFmtInfo; + +/** this table gives more information about formats */ +static const SampleFmtInfo sample_fmt_info[AV_SAMPLE_FMT_NB] = { + [AV_SAMPLE_FMT_U8] = { .name = "u8", .bits = 8, .planar = 0, .altform = AV_SAMPLE_FMT_U8P }, + [AV_SAMPLE_FMT_S16] = { .name = "s16", .bits = 16, .planar = 0, .altform = AV_SAMPLE_FMT_S16P }, + [AV_SAMPLE_FMT_S32] = { .name = "s32", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_S32P }, + [AV_SAMPLE_FMT_S64] = { .name = "s64", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_S64P }, + [AV_SAMPLE_FMT_FLT] = { .name = "flt", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_FLTP }, + [AV_SAMPLE_FMT_DBL] = { .name = "dbl", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_DBLP }, + [AV_SAMPLE_FMT_U8P] = { .name = "u8p", .bits = 8, .planar = 1, .altform = AV_SAMPLE_FMT_U8 }, + [AV_SAMPLE_FMT_S16P] = { .name = "s16p", .bits = 16, .planar = 1, .altform = AV_SAMPLE_FMT_S16 }, + [AV_SAMPLE_FMT_S32P] = { .name = "s32p", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_S32 }, + [AV_SAMPLE_FMT_S64P] = { .name = "s64p", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_S64 }, + [AV_SAMPLE_FMT_FLTP] = { .name = "fltp", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_FLT }, + [AV_SAMPLE_FMT_DBLP] = { .name = "dblp", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_DBL }, +}; + +const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt) +{ + if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) + return NULL; + return sample_fmt_info[sample_fmt].name; +} + +enum AVSampleFormat av_get_sample_fmt(const char *name) +{ + int i; + + for (i = 0; i < AV_SAMPLE_FMT_NB; i++) + if (!strcmp(sample_fmt_info[i].name, name)) + return i; + return AV_SAMPLE_FMT_NONE; +} + +enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar) +{ + if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) + return AV_SAMPLE_FMT_NONE; + if (sample_fmt_info[sample_fmt].planar == planar) + return sample_fmt; + return sample_fmt_info[sample_fmt].altform; +} + +enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt) +{ + if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) + return AV_SAMPLE_FMT_NONE; + if (sample_fmt_info[sample_fmt].planar) + return sample_fmt_info[sample_fmt].altform; + return sample_fmt; +} + +enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt) +{ + if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) + return AV_SAMPLE_FMT_NONE; + if (sample_fmt_info[sample_fmt].planar) + return sample_fmt; + return sample_fmt_info[sample_fmt].altform; +} + +char *av_get_sample_fmt_string (char *buf, int buf_size, enum AVSampleFormat sample_fmt) +{ + /* print header */ + if (sample_fmt < 0) + snprintf(buf, buf_size, "name " " depth"); + else if (sample_fmt < AV_SAMPLE_FMT_NB) { + SampleFmtInfo info = sample_fmt_info[sample_fmt]; + snprintf (buf, buf_size, "%-6s" " %2d ", info.name, info.bits); + } + + return buf; +} + +int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt) +{ + return sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB ? + 0 : sample_fmt_info[sample_fmt].bits >> 3; +} + +int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt) +{ + if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) + return 0; + return sample_fmt_info[sample_fmt].planar; +} + +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align) +{ + int line_size; + int sample_size = av_get_bytes_per_sample(sample_fmt); + int planar = av_sample_fmt_is_planar(sample_fmt); + + /* validate parameter ranges */ + if (!sample_size || nb_samples <= 0 || nb_channels <= 0) + return AVERROR(EINVAL); + + /* auto-select alignment if not specified */ + if (!align) { + if (nb_samples > INT_MAX - 31) + return AVERROR(EINVAL); + align = 1; + nb_samples = FFALIGN(nb_samples, 32); + } + + /* check for integer overflow */ + if (nb_channels > INT_MAX / align || + (int64_t)nb_channels * nb_samples > (INT_MAX - (align * nb_channels)) / sample_size) + return AVERROR(EINVAL); + + line_size = planar ? FFALIGN(nb_samples * sample_size, align) : + FFALIGN(nb_samples * sample_size * nb_channels, align); + if (linesize) + *linesize = line_size; + + return planar ? line_size * nb_channels : line_size; +} + +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, + const uint8_t *buf, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align) +{ + int ch, planar, buf_size, line_size; + + planar = av_sample_fmt_is_planar(sample_fmt); + buf_size = av_samples_get_buffer_size(&line_size, nb_channels, nb_samples, + sample_fmt, align); + if (buf_size < 0) + return buf_size; + + audio_data[0] = (uint8_t *)buf; + for (ch = 1; planar && ch < nb_channels; ch++) + audio_data[ch] = audio_data[ch-1] + line_size; + + if (linesize) + *linesize = line_size; + + return buf_size; +} + +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align) +{ + uint8_t *buf; + int size = av_samples_get_buffer_size(NULL, nb_channels, nb_samples, + sample_fmt, align); + if (size < 0) + return size; + + buf = av_malloc(size); + if (!buf) + return AVERROR(ENOMEM); + + size = av_samples_fill_arrays(audio_data, linesize, buf, nb_channels, + nb_samples, sample_fmt, align); + if (size < 0) { + av_free(buf); + return size; + } + + av_samples_set_silence(audio_data, 0, nb_samples, nb_channels, sample_fmt); + + return size; +} + +int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align) +{ + int ret, nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1; + + *audio_data = av_calloc(nb_planes, sizeof(**audio_data)); + if (!*audio_data) + return AVERROR(ENOMEM); + ret = av_samples_alloc(*audio_data, linesize, nb_channels, + nb_samples, sample_fmt, align); + if (ret < 0) + av_freep(audio_data); + return ret; +} + +int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset, + int src_offset, int nb_samples, int nb_channels, + enum AVSampleFormat sample_fmt) +{ + int planar = av_sample_fmt_is_planar(sample_fmt); + int planes = planar ? nb_channels : 1; + int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels); + int data_size = nb_samples * block_align; + int i; + + dst_offset *= block_align; + src_offset *= block_align; + + if((dst[0] < src[0] ? src[0] - dst[0] : dst[0] - src[0]) >= data_size) { + for (i = 0; i < planes; i++) + memcpy(dst[i] + dst_offset, src[i] + src_offset, data_size); + } else { + for (i = 0; i < planes; i++) + memmove(dst[i] + dst_offset, src[i] + src_offset, data_size); + } + + return 0; +} + +int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples, + int nb_channels, enum AVSampleFormat sample_fmt) +{ + int planar = av_sample_fmt_is_planar(sample_fmt); + int planes = planar ? nb_channels : 1; + int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels); + int data_size = nb_samples * block_align; + int fill_char = (sample_fmt == AV_SAMPLE_FMT_U8 || + sample_fmt == AV_SAMPLE_FMT_U8P) ? 0x80 : 0x00; + int i; + + offset *= block_align; + + for (i = 0; i < planes; i++) + memset(audio_data[i] + offset, fill_char, data_size); + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/samplefmt.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/samplefmt.h new file mode 100644 index 0000000000..8cd43ae856 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/samplefmt.h @@ -0,0 +1,272 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SAMPLEFMT_H +#define AVUTIL_SAMPLEFMT_H + +#include + +#include "avutil.h" +#include "attributes.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_sampfmts Audio sample formats + * + * Audio sample format enumeration and related convenience functions. + * @{ + */ + +/** + * Audio sample formats + * + * - The data described by the sample format is always in native-endian order. + * Sample values can be expressed by native C types, hence the lack of a signed + * 24-bit sample format even though it is a common raw audio data format. + * + * - The floating-point formats are based on full volume being in the range + * [-1.0, 1.0]. Any values outside this range are beyond full volume level. + * + * - The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg + * (such as AVFrame in libavcodec) is as follows: + * + * @par + * For planar sample formats, each audio channel is in a separate data plane, + * and linesize is the buffer size, in bytes, for a single plane. All data + * planes must be the same size. For packed sample formats, only the first data + * plane is used, and samples for each channel are interleaved. In this case, + * linesize is the buffer size, in bytes, for the 1 plane. + * + */ +enum AVSampleFormat { + AV_SAMPLE_FMT_NONE = -1, + AV_SAMPLE_FMT_U8, ///< unsigned 8 bits + AV_SAMPLE_FMT_S16, ///< signed 16 bits + AV_SAMPLE_FMT_S32, ///< signed 32 bits + AV_SAMPLE_FMT_FLT, ///< float + AV_SAMPLE_FMT_DBL, ///< double + + AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar + AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar + AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar + AV_SAMPLE_FMT_FLTP, ///< float, planar + AV_SAMPLE_FMT_DBLP, ///< double, planar + AV_SAMPLE_FMT_S64, ///< signed 64 bits + AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar + + AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically +}; + +/** + * Return the name of sample_fmt, or NULL if sample_fmt is not + * recognized. + */ +const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt); + +/** + * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE + * on error. + */ +enum AVSampleFormat av_get_sample_fmt(const char *name); + +/** + * Return the planar<->packed alternative form of the given sample format, or + * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the + * requested planar/packed format, the format returned is the same as the + * input. + */ +enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar); + +/** + * Get the packed alternative form of the given sample format. + * + * If the passed sample_fmt is already in packed format, the format returned is + * the same as the input. + * + * @return the packed alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Get the planar alternative form of the given sample format. + * + * If the passed sample_fmt is already in planar format, the format returned is + * the same as the input. + * + * @return the planar alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Generate a string corresponding to the sample format with + * sample_fmt, or a header if sample_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param sample_fmt the number of the sample format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + * @return the pointer to the filled buffer or NULL if sample_fmt is + * unknown or in case of other errors + */ +char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); + +/** + * Return number of bytes per sample. + * + * @param sample_fmt the sample format + * @return number of bytes per sample or zero if unknown for the given + * sample format + */ +int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); + +/** + * Check if the sample format is planar. + * + * @param sample_fmt the sample format to inspect + * @return 1 if the sample format is planar, 0 if it is interleaved + */ +int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt); + +/** + * Get the required buffer size for the given audio parameters. + * + * @param[out] linesize calculated linesize, may be NULL + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return required buffer size, or negative error code on failure + */ +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * @} + * + * @defgroup lavu_sampmanip Samples manipulation + * + * Functions that manipulate audio samples + * @{ + */ + +/** + * Fill plane data pointers and linesize for samples with sample + * format sample_fmt. + * + * The audio_data array is filled with the pointers to the samples data planes: + * for planar, set the start point of each channel's data within the buffer, + * for packed, set the start point of the entire buffer only. + * + * The value pointed to by linesize is set to the aligned size of each + * channel's data buffer for planar layout, or to the aligned size of the + * buffer for all channels for packed layout. + * + * The buffer in buf must be big enough to contain all the samples + * (use av_samples_get_buffer_size() to compute its minimum size), + * otherwise the audio_data pointers will point to invalid data. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize calculated linesize, may be NULL + * @param buf the pointer to a buffer containing the samples + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return minimum size in bytes required for the buffer in case + * of success at the next bump + */ +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, + const uint8_t *buf, + int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a samples buffer for nb_samples samples, and fill data pointers and + * linesize accordingly. + * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) + * Allocated data will be initialized to silence. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize aligned size for audio buffer(s), may be NULL + * @param nb_channels number of audio channels + * @param nb_samples number of samples per channel + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return the size of the allocated buffer in case of success at the next bump + * @see av_samples_fill_arrays() + * @see av_samples_alloc_array_and_samples() + */ +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a data pointers array, samples buffer for nb_samples + * samples, and fill data pointers and linesize accordingly. + * + * This is the same as av_samples_alloc(), but also allocates the data + * pointers array. + * + * @see av_samples_alloc() + */ +int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Copy samples from src to dst. + * + * @param dst destination array of pointers to data planes + * @param src source array of pointers to data planes + * @param dst_offset offset in samples at which the data will be written to dst + * @param src_offset offset in samples at which the data will be read from src + * @param nb_samples number of samples to be copied + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset, + int src_offset, int nb_samples, int nb_channels, + enum AVSampleFormat sample_fmt); + +/** + * Fill an audio buffer with silence. + * + * @param audio_data array of pointers to data planes + * @param offset offset in samples at which to start filling + * @param nb_samples number of samples to fill + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples, + int nb_channels, enum AVSampleFormat sample_fmt); + +/** + * @} + * @} + */ +#endif /* AVUTIL_SAMPLEFMT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha.c new file mode 100644 index 0000000000..ef6fa44227 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2009 Konstantin Shishkov + * based on public domain SHA-1 code by Steve Reid + * and on BSD-licensed SHA-2 code by Aaron D. Gifford + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "attributes.h" +#include "avutil.h" +#include "bswap.h" +#include "sha.h" +#include "intreadwrite.h" +#include "mem.h" + +/** hash context */ +typedef struct AVSHA { + uint8_t digest_len; ///< digest length in 32-bit words + uint64_t count; ///< number of bytes in buffer + uint8_t buffer[64]; ///< 512-bit buffer of input values used in hash updating + uint32_t state[8]; ///< current hash value + /** function used to update hash for 512-bit input block */ + void (*transform)(uint32_t *state, const uint8_t buffer[64]); +} AVSHA; + +const int av_sha_size = sizeof(AVSHA); + +struct AVSHA *av_sha_alloc(void) +{ + return av_mallocz(sizeof(struct AVSHA)); +} + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define blk0(i) (block[i] = AV_RB32(buffer + 4 * (i))) +#define blk(i) (block[i] = rol(block[(i)-3] ^ block[(i)-8] ^ block[(i)-14] ^ block[(i)-16], 1)) + +#define R0(v,w,x,y,z,i) z += (((w)&((x)^(y)))^(y)) + blk0(i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); +#define R1(v,w,x,y,z,i) z += (((w)&((x)^(y)))^(y)) + blk (i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); +#define R2(v,w,x,y,z,i) z += ( (w)^(x) ^(y)) + blk (i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); +#define R3(v,w,x,y,z,i) z += ((((w)|(x))&(y))|((w)&(x))) + blk (i) + 0x8F1BBCDC + rol(v, 5); w = rol(w, 30); +#define R4(v,w,x,y,z,i) z += ( (w)^(x) ^(y)) + blk (i) + 0xCA62C1D6 + rol(v, 5); w = rol(w, 30); + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +static void sha1_transform(uint32_t state[5], const uint8_t buffer[64]) +{ + uint32_t block[80]; + unsigned int i, a, b, c, d, e; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; +#if CONFIG_SMALL + for (i = 0; i < 80; i++) { + int t; + if (i < 16) + t = AV_RB32(buffer + 4 * i); + else + t = rol(block[i-3] ^ block[i-8] ^ block[i-14] ^ block[i-16], 1); + block[i] = t; + t += e + rol(a, 5); + if (i < 40) { + if (i < 20) + t += ((b&(c^d))^d) + 0x5A827999; + else + t += ( b^c ^d) + 0x6ED9EBA1; + } else { + if (i < 60) + t += (((b|c)&d)|(b&c)) + 0x8F1BBCDC; + else + t += ( b^c ^d) + 0xCA62C1D6; + } + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } +#else + +#define R1_0 \ + R0(a, b, c, d, e, 0 + i); \ + R0(e, a, b, c, d, 1 + i); \ + R0(d, e, a, b, c, 2 + i); \ + R0(c, d, e, a, b, 3 + i); \ + R0(b, c, d, e, a, 4 + i); \ + i += 5 + + i = 0; + R1_0; R1_0; R1_0; + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + +#define R1_20 \ + R2(a, b, c, d, e, 0 + i); \ + R2(e, a, b, c, d, 1 + i); \ + R2(d, e, a, b, c, 2 + i); \ + R2(c, d, e, a, b, 3 + i); \ + R2(b, c, d, e, a, 4 + i); \ + i += 5 + + i = 20; + R1_20; R1_20; R1_20; R1_20; + +#define R1_40 \ + R3(a, b, c, d, e, 0 + i); \ + R3(e, a, b, c, d, 1 + i); \ + R3(d, e, a, b, c, 2 + i); \ + R3(c, d, e, a, b, 3 + i); \ + R3(b, c, d, e, a, 4 + i); \ + i += 5 + + R1_40; R1_40; R1_40; R1_40; + +#define R1_60 \ + R4(a, b, c, d, e, 0 + i); \ + R4(e, a, b, c, d, 1 + i); \ + R4(d, e, a, b, c, 2 + i); \ + R4(c, d, e, a, b, 3 + i); \ + R4(b, c, d, e, a, 4 + i); \ + i += 5 + + R1_60; R1_60; R1_60; R1_60; +#endif + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; +} + +static const uint32_t K256[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + + +#define Ch(x,y,z) (((x) & ((y) ^ (z))) ^ (z)) +#define Maj(z,y,x) ((((x) | (y)) & (z)) | ((x) & (y))) + +#define Sigma0_256(x) (rol((x), 30) ^ rol((x), 19) ^ rol((x), 10)) +#define Sigma1_256(x) (rol((x), 26) ^ rol((x), 21) ^ rol((x), 7)) +#define sigma0_256(x) (rol((x), 25) ^ rol((x), 14) ^ ((x) >> 3)) +#define sigma1_256(x) (rol((x), 15) ^ rol((x), 13) ^ ((x) >> 10)) + +#undef blk +#define blk(i) (block[i] = block[i - 16] + sigma0_256(block[i - 15]) + \ + sigma1_256(block[i - 2]) + block[i - 7]) + +#define ROUND256(a,b,c,d,e,f,g,h) \ + T1 += (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[i]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + i++ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = blk0(i); \ + ROUND256(a,b,c,d,e,f,g,h) + +#define ROUND256_16_TO_63(a,b,c,d,e,f,g,h) \ + T1 = blk(i); \ + ROUND256(a,b,c,d,e,f,g,h) + +static void sha256_transform(uint32_t *state, const uint8_t buffer[64]) +{ + unsigned int i, a, b, c, d, e, f, g, h; + uint32_t block[64]; + uint32_t T1; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; +#if CONFIG_SMALL + for (i = 0; i < 64; i++) { + uint32_t T2; + if (i < 16) + T1 = blk0(i); + else + T1 = blk(i); + T1 += h + Sigma1_256(e) + Ch(e, f, g) + K256[i]; + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } +#else + + i = 0; +#define R256_0 \ + ROUND256_0_TO_15(a, b, c, d, e, f, g, h); \ + ROUND256_0_TO_15(h, a, b, c, d, e, f, g); \ + ROUND256_0_TO_15(g, h, a, b, c, d, e, f); \ + ROUND256_0_TO_15(f, g, h, a, b, c, d, e); \ + ROUND256_0_TO_15(e, f, g, h, a, b, c, d); \ + ROUND256_0_TO_15(d, e, f, g, h, a, b, c); \ + ROUND256_0_TO_15(c, d, e, f, g, h, a, b); \ + ROUND256_0_TO_15(b, c, d, e, f, g, h, a) + + R256_0; R256_0; + +#define R256_16 \ + ROUND256_16_TO_63(a, b, c, d, e, f, g, h); \ + ROUND256_16_TO_63(h, a, b, c, d, e, f, g); \ + ROUND256_16_TO_63(g, h, a, b, c, d, e, f); \ + ROUND256_16_TO_63(f, g, h, a, b, c, d, e); \ + ROUND256_16_TO_63(e, f, g, h, a, b, c, d); \ + ROUND256_16_TO_63(d, e, f, g, h, a, b, c); \ + ROUND256_16_TO_63(c, d, e, f, g, h, a, b); \ + ROUND256_16_TO_63(b, c, d, e, f, g, h, a) + + R256_16; R256_16; R256_16; + R256_16; R256_16; R256_16; +#endif + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; +} + + +av_cold int av_sha_init(AVSHA *ctx, int bits) +{ + ctx->digest_len = bits >> 5; + switch (bits) { + case 160: // SHA-1 + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->transform = sha1_transform; + break; + case 224: // SHA-224 + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + ctx->transform = sha256_transform; + break; + case 256: // SHA-256 + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + ctx->transform = sha256_transform; + break; + default: + return AVERROR(EINVAL); + } + ctx->count = 0; + return 0; +} + +#if FF_API_CRYPTO_SIZE_T +void av_sha_update(struct AVSHA *ctx, const uint8_t *data, unsigned int len) +#else +void av_sha_update(struct AVSHA *ctx, const uint8_t *data, size_t len) +#endif +{ + unsigned int i, j; + + j = ctx->count & 63; + ctx->count += len; +#if CONFIG_SMALL + for (i = 0; i < len; i++) { + ctx->buffer[j++] = data[i]; + if (64 == j) { + ctx->transform(ctx->state, ctx->buffer); + j = 0; + } + } +#else + if ((j + len) > 63) { + memcpy(&ctx->buffer[j], data, (i = 64 - j)); + ctx->transform(ctx->state, ctx->buffer); + for (; i + 63 < len; i += 64) + ctx->transform(ctx->state, &data[i]); + j = 0; + } else + i = 0; + memcpy(&ctx->buffer[j], &data[i], len - i); +#endif +} + +void av_sha_final(AVSHA* ctx, uint8_t *digest) +{ + int i; + uint64_t finalcount = av_be2ne64(ctx->count << 3); + + av_sha_update(ctx, "\200", 1); + while ((ctx->count & 63) != 56) + av_sha_update(ctx, "", 1); + av_sha_update(ctx, (uint8_t *)&finalcount, 8); /* Should cause a transform() */ + for (i = 0; i < ctx->digest_len; i++) + AV_WB32(digest + i*4, ctx->state[i]); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha.h new file mode 100644 index 0000000000..c0180e5729 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_sha + * Public header for SHA-1 & SHA-256 hash function implementations. + */ + +#ifndef AVUTIL_SHA_H +#define AVUTIL_SHA_H + +#include +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha SHA + * @ingroup lavu_hash + * SHA-1 and SHA-256 (Secure Hash Algorithm) hash function implementations. + * + * This module supports the following SHA hash functions: + * + * - SHA-1: 160 bits + * - SHA-224: 224 bits, as a variant of SHA-2 + * - SHA-256: 256 bits, as a variant of SHA-2 + * + * @see For SHA-384, SHA-512, and variants thereof, see @ref lavu_sha512. + * + * @{ + */ + +extern const int av_sha_size; + +struct AVSHA; + +/** + * Allocate an AVSHA context. + */ +struct AVSHA *av_sha_alloc(void); + +/** + * Initialize SHA-1 or SHA-2 hashing. + * + * @param context pointer to the function context (of size av_sha_size) + * @param bits number of bits in digest (SHA-1 - 160 bits, SHA-2 224 or 256 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha_init(struct AVSHA* context, int bits); + +/** + * Update hash value. + * + * @param ctx hash function context + * @param data input data to update hash with + * @param len input data length + */ +#if FF_API_CRYPTO_SIZE_T +void av_sha_update(struct AVSHA *ctx, const uint8_t *data, unsigned int len); +#else +void av_sha_update(struct AVSHA *ctx, const uint8_t *data, size_t len); +#endif + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha_final(struct AVSHA* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha512.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha512.c new file mode 100644 index 0000000000..6d092a7c5c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha512.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2009 Konstantin Shishkov + * Copyright (C) 2013 James Almer + * based on BSD-licensed SHA-2 code by Aaron D. Gifford + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "attributes.h" +#include "avutil.h" +#include "bswap.h" +#include "sha512.h" +#include "intreadwrite.h" +#include "mem.h" + +/** hash context */ +typedef struct AVSHA512 { + uint8_t digest_len; ///< digest length in 64-bit words + uint64_t count; ///< number of bytes in buffer + uint8_t buffer[128]; ///< 1024-bit buffer of input values used in hash updating + uint64_t state[8]; ///< current hash value +} AVSHA512; + +const int av_sha512_size = sizeof(AVSHA512); + +struct AVSHA512 *av_sha512_alloc(void) +{ + return av_mallocz(sizeof(struct AVSHA512)); +} + +static const uint64_t K512[80] = { + UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), + UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc), + UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), + UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118), + UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), + UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2), + UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), + UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694), + UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), + UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65), + UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), + UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5), + UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), + UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4), + UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), + UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70), + UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), + UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df), + UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), + UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b), + UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), + UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30), + UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), + UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8), + UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), + UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8), + UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), + UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3), + UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), + UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec), + UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), + UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b), + UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), + UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178), + UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), + UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b), + UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), + UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c), + UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), + UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817), +}; + +#define ror(value, bits) (((value) >> (bits)) | ((value) << (64 - (bits)))) + +#define Ch(x,y,z) (((x) & ((y) ^ (z))) ^ (z)) +#define Maj(z,y,x) ((((x) | (y)) & (z)) | ((x) & (y))) + +#define Sigma0_512(x) (ror((x), 28) ^ ror((x), 34) ^ ror((x), 39)) +#define Sigma1_512(x) (ror((x), 14) ^ ror((x), 18) ^ ror((x), 41)) +#define sigma0_512(x) (ror((x), 1) ^ ror((x), 8) ^ ((x) >> 7)) +#define sigma1_512(x) (ror((x), 19) ^ ror((x), 61) ^ ((x) >> 6)) + +#define blk0(i) (block[i] = AV_RB64(buffer + 8 * (i))) +#define blk(i) (block[i] = block[i - 16] + sigma0_512(block[i - 15]) + \ + sigma1_512(block[i - 2]) + block[i - 7]) + +#define ROUND512(a,b,c,d,e,f,g,h) \ + T1 += (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[i]; \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + i++ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = blk0(i); \ + ROUND512(a,b,c,d,e,f,g,h) + +#define ROUND512_16_TO_80(a,b,c,d,e,f,g,h) \ + T1 = blk(i); \ + ROUND512(a,b,c,d,e,f,g,h) + +static void sha512_transform(uint64_t *state, const uint8_t buffer[128]) +{ + uint64_t a, b, c, d, e, f, g, h; + uint64_t block[80]; + uint64_t T1; + int i; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; +#if CONFIG_SMALL + for (i = 0; i < 80; i++) { + uint64_t T2; + if (i < 16) + T1 = blk0(i); + else + T1 = blk(i); + T1 += h + Sigma1_512(e) + Ch(e, f, g) + K512[i]; + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } +#else + +#define R512_0 \ + ROUND512_0_TO_15(a, b, c, d, e, f, g, h); \ + ROUND512_0_TO_15(h, a, b, c, d, e, f, g); \ + ROUND512_0_TO_15(g, h, a, b, c, d, e, f); \ + ROUND512_0_TO_15(f, g, h, a, b, c, d, e); \ + ROUND512_0_TO_15(e, f, g, h, a, b, c, d); \ + ROUND512_0_TO_15(d, e, f, g, h, a, b, c); \ + ROUND512_0_TO_15(c, d, e, f, g, h, a, b); \ + ROUND512_0_TO_15(b, c, d, e, f, g, h, a) + + i = 0; + R512_0; R512_0; + +#define R512_16 \ + ROUND512_16_TO_80(a, b, c, d, e, f, g, h); \ + ROUND512_16_TO_80(h, a, b, c, d, e, f, g); \ + ROUND512_16_TO_80(g, h, a, b, c, d, e, f); \ + ROUND512_16_TO_80(f, g, h, a, b, c, d, e); \ + ROUND512_16_TO_80(e, f, g, h, a, b, c, d); \ + ROUND512_16_TO_80(d, e, f, g, h, a, b, c); \ + ROUND512_16_TO_80(c, d, e, f, g, h, a, b); \ + ROUND512_16_TO_80(b, c, d, e, f, g, h, a) + + R512_16; R512_16; R512_16; R512_16; + R512_16; R512_16; R512_16; R512_16; +#endif + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; +} + + +av_cold int av_sha512_init(AVSHA512 *ctx, int bits) +{ + ctx->digest_len = bits >> 6; + switch (bits) { + case 224: // SHA-512/224 + ctx->state[0] = UINT64_C(0x8C3D37C819544DA2); + ctx->state[1] = UINT64_C(0x73E1996689DCD4D6); + ctx->state[2] = UINT64_C(0x1DFAB7AE32FF9C82); + ctx->state[3] = UINT64_C(0x679DD514582F9FCF); + ctx->state[4] = UINT64_C(0x0F6D2B697BD44DA8); + ctx->state[5] = UINT64_C(0x77E36F7304C48942); + ctx->state[6] = UINT64_C(0x3F9D85A86A1D36C8); + ctx->state[7] = UINT64_C(0x1112E6AD91D692A1); + break; + case 256: // SHA-512/256 + ctx->state[0] = UINT64_C(0x22312194FC2BF72C); + ctx->state[1] = UINT64_C(0x9F555FA3C84C64C2); + ctx->state[2] = UINT64_C(0x2393B86B6F53B151); + ctx->state[3] = UINT64_C(0x963877195940EABD); + ctx->state[4] = UINT64_C(0x96283EE2A88EFFE3); + ctx->state[5] = UINT64_C(0xBE5E1E2553863992); + ctx->state[6] = UINT64_C(0x2B0199FC2C85B8AA); + ctx->state[7] = UINT64_C(0x0EB72DDC81C52CA2); + break; + case 384: // SHA-384 + ctx->state[0] = UINT64_C(0xCBBB9D5DC1059ED8); + ctx->state[1] = UINT64_C(0x629A292A367CD507); + ctx->state[2] = UINT64_C(0x9159015A3070DD17); + ctx->state[3] = UINT64_C(0x152FECD8F70E5939); + ctx->state[4] = UINT64_C(0x67332667FFC00B31); + ctx->state[5] = UINT64_C(0x8EB44A8768581511); + ctx->state[6] = UINT64_C(0xDB0C2E0D64F98FA7); + ctx->state[7] = UINT64_C(0x47B5481DBEFA4FA4); + break; + case 512: // SHA-512 + ctx->state[0] = UINT64_C(0x6A09E667F3BCC908); + ctx->state[1] = UINT64_C(0xBB67AE8584CAA73B); + ctx->state[2] = UINT64_C(0x3C6EF372FE94F82B); + ctx->state[3] = UINT64_C(0xA54FF53A5F1D36F1); + ctx->state[4] = UINT64_C(0x510E527FADE682D1); + ctx->state[5] = UINT64_C(0x9B05688C2B3E6C1F); + ctx->state[6] = UINT64_C(0x1F83D9ABFB41BD6B); + ctx->state[7] = UINT64_C(0x5BE0CD19137E2179); + break; + default: + return AVERROR(EINVAL); + } + ctx->count = 0; + return 0; +} + +#if FF_API_CRYPTO_SIZE_T +void av_sha512_update(AVSHA512* ctx, const uint8_t* data, unsigned int len) +#else +void av_sha512_update(AVSHA512* ctx, const uint8_t* data, size_t len) +#endif +{ + unsigned int i, j; + + j = ctx->count & 127; + ctx->count += len; +#if CONFIG_SMALL + for (i = 0; i < len; i++) { + ctx->buffer[j++] = data[i]; + if (128 == j) { + sha512_transform(ctx->state, ctx->buffer); + j = 0; + } + } +#else + if ((j + len) > 127) { + memcpy(&ctx->buffer[j], data, (i = 128 - j)); + sha512_transform(ctx->state, ctx->buffer); + for (; i + 127 < len; i += 128) + sha512_transform(ctx->state, &data[i]); + j = 0; + } else + i = 0; + memcpy(&ctx->buffer[j], &data[i], len - i); +#endif +} + +void av_sha512_final(AVSHA512* ctx, uint8_t *digest) +{ + uint64_t i = 0; + uint64_t finalcount = av_be2ne64(ctx->count << 3); + + av_sha512_update(ctx, "\200", 1); + while ((ctx->count & 127) != 112) + av_sha512_update(ctx, "", 1); + av_sha512_update(ctx, (uint8_t *)&i, 8); + av_sha512_update(ctx, (uint8_t *)&finalcount, 8); /* Should cause a transform() */ + for (i = 0; i < ctx->digest_len; i++) + AV_WB64(digest + i*8, ctx->state[i]); + if (ctx->digest_len & 1) /* SHA512/224 is 28 bytes, and is not divisible by 8. */ + AV_WB32(digest + i*8, ctx->state[i] >> 32); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha512.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha512.h new file mode 100644 index 0000000000..bef714b41c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/sha512.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_sha512 + * Public header for SHA-512 implementation. + */ + +#ifndef AVUTIL_SHA512_H +#define AVUTIL_SHA512_H + +#include +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha512 SHA-512 + * @ingroup lavu_hash + * SHA-512 (Secure Hash Algorithm) hash function implementations. + * + * This module supports the following SHA-2 hash functions: + * + * - SHA-512/224: 224 bits + * - SHA-512/256: 256 bits + * - SHA-384: 384 bits + * - SHA-512: 512 bits + * + * @see For SHA-1, SHA-256, and variants thereof, see @ref lavu_sha. + * + * @{ + */ + +extern const int av_sha512_size; + +struct AVSHA512; + +/** + * Allocate an AVSHA512 context. + */ +struct AVSHA512 *av_sha512_alloc(void); + +/** + * Initialize SHA-2 512 hashing. + * + * @param context pointer to the function context (of size av_sha512_size) + * @param bits number of bits in digest (224, 256, 384 or 512 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha512_init(struct AVSHA512* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +#if FF_API_CRYPTO_SIZE_T +void av_sha512_update(struct AVSHA512* context, const uint8_t* data, unsigned int len); +#else +void av_sha512_update(struct AVSHA512* context, const uint8_t* data, size_t len); +#endif + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha512_final(struct AVSHA512* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA512_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/slicethread.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/slicethread.c new file mode 100644 index 0000000000..dfbe551ef2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/slicethread.c @@ -0,0 +1,255 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "slicethread.h" +#include "mem.h" +#include "thread.h" +#include "avassert.h" + +#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS + +typedef struct WorkerContext { + AVSliceThread *ctx; + pthread_mutex_t mutex; + pthread_cond_t cond; + pthread_t thread; + int done; +} WorkerContext; + +struct AVSliceThread { + WorkerContext *workers; + int nb_threads; + int nb_active_threads; + int nb_jobs; + + atomic_uint first_job; + atomic_uint current_job; + pthread_mutex_t done_mutex; + pthread_cond_t done_cond; + int done; + int finished; + + void *priv; + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads); + void (*main_func)(void *priv); +}; + +static int run_jobs(AVSliceThread *ctx) +{ + unsigned nb_jobs = ctx->nb_jobs; + unsigned nb_active_threads = ctx->nb_active_threads; + unsigned first_job = atomic_fetch_add_explicit(&ctx->first_job, 1, memory_order_acq_rel); + unsigned current_job = first_job; + + do { + ctx->worker_func(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads); + } while ((current_job = atomic_fetch_add_explicit(&ctx->current_job, 1, memory_order_acq_rel)) < nb_jobs); + + return current_job == nb_jobs + nb_active_threads - 1; +} + +static void *attribute_align_arg thread_worker(void *v) +{ + WorkerContext *w = v; + AVSliceThread *ctx = w->ctx; + + pthread_mutex_lock(&w->mutex); + pthread_cond_signal(&w->cond); + + while (1) { + w->done = 1; + while (w->done) + pthread_cond_wait(&w->cond, &w->mutex); + + if (ctx->finished) { + pthread_mutex_unlock(&w->mutex); + return NULL; + } + + if (run_jobs(ctx)) { + pthread_mutex_lock(&ctx->done_mutex); + ctx->done = 1; + pthread_cond_signal(&ctx->done_cond); + pthread_mutex_unlock(&ctx->done_mutex); + } + } +} + +int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), + void (*main_func)(void *priv), + int nb_threads) +{ + AVSliceThread *ctx; + int nb_workers, i; + + av_assert0(nb_threads >= 0); + if (!nb_threads) { + int nb_cpus = av_cpu_count(); + if (nb_cpus > 1) + nb_threads = nb_cpus + 1; + else + nb_threads = 1; + } + + nb_workers = nb_threads; + if (!main_func) + nb_workers--; + + *pctx = ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return AVERROR(ENOMEM); + + if (nb_workers && !(ctx->workers = av_calloc(nb_workers, sizeof(*ctx->workers)))) { + av_freep(pctx); + return AVERROR(ENOMEM); + } + + ctx->priv = priv; + ctx->worker_func = worker_func; + ctx->main_func = main_func; + ctx->nb_threads = nb_threads; + ctx->nb_active_threads = 0; + ctx->nb_jobs = 0; + ctx->finished = 0; + + atomic_init(&ctx->first_job, 0); + atomic_init(&ctx->current_job, 0); + pthread_mutex_init(&ctx->done_mutex, NULL); + pthread_cond_init(&ctx->done_cond, NULL); + ctx->done = 0; + + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + int ret; + w->ctx = ctx; + pthread_mutex_init(&w->mutex, NULL); + pthread_cond_init(&w->cond, NULL); + pthread_mutex_lock(&w->mutex); + w->done = 0; + + if (ret = pthread_create(&w->thread, NULL, thread_worker, w)) { + ctx->nb_threads = main_func ? i : i + 1; + pthread_mutex_unlock(&w->mutex); + pthread_cond_destroy(&w->cond); + pthread_mutex_destroy(&w->mutex); + avpriv_slicethread_free(pctx); + return AVERROR(ret); + } + + while (!w->done) + pthread_cond_wait(&w->cond, &w->mutex); + pthread_mutex_unlock(&w->mutex); + } + + return nb_threads; +} + +void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main) +{ + int nb_workers, i, is_last = 0; + + av_assert0(nb_jobs > 0); + ctx->nb_jobs = nb_jobs; + ctx->nb_active_threads = FFMIN(nb_jobs, ctx->nb_threads); + atomic_store_explicit(&ctx->first_job, 0, memory_order_relaxed); + atomic_store_explicit(&ctx->current_job, ctx->nb_active_threads, memory_order_relaxed); + nb_workers = ctx->nb_active_threads; + if (!ctx->main_func || !execute_main) + nb_workers--; + + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + pthread_mutex_lock(&w->mutex); + w->done = 0; + pthread_cond_signal(&w->cond); + pthread_mutex_unlock(&w->mutex); + } + + if (ctx->main_func && execute_main) + ctx->main_func(ctx->priv); + else + is_last = run_jobs(ctx); + + if (!is_last) { + pthread_mutex_lock(&ctx->done_mutex); + while (!ctx->done) + pthread_cond_wait(&ctx->done_cond, &ctx->done_mutex); + ctx->done = 0; + pthread_mutex_unlock(&ctx->done_mutex); + } +} + +void avpriv_slicethread_free(AVSliceThread **pctx) +{ + AVSliceThread *ctx; + int nb_workers, i; + + if (!pctx || !*pctx) + return; + + ctx = *pctx; + nb_workers = ctx->nb_threads; + if (!ctx->main_func) + nb_workers--; + + ctx->finished = 1; + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + pthread_mutex_lock(&w->mutex); + w->done = 0; + pthread_cond_signal(&w->cond); + pthread_mutex_unlock(&w->mutex); + } + + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + pthread_join(w->thread, NULL); + pthread_cond_destroy(&w->cond); + pthread_mutex_destroy(&w->mutex); + } + + pthread_cond_destroy(&ctx->done_cond); + pthread_mutex_destroy(&ctx->done_mutex); + av_freep(&ctx->workers); + av_freep(pctx); +} + +#else /* HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS32THREADS */ + +int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), + void (*main_func)(void *priv), + int nb_threads) +{ + *pctx = NULL; + return AVERROR(EINVAL); +} + +void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main) +{ + av_assert0(0); +} + +void avpriv_slicethread_free(AVSliceThread **pctx) +{ + av_assert0(!pctx || !*pctx); +} + +#endif /* HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS32THREADS */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/slicethread.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/slicethread.h new file mode 100644 index 0000000000..f6f6f302c4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/slicethread.h @@ -0,0 +1,52 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SLICETHREAD_H +#define AVUTIL_SLICETHREAD_H + +typedef struct AVSliceThread AVSliceThread; + +/** + * Create slice threading context. + * @param pctx slice threading context returned here + * @param priv private pointer to be passed to callback function + * @param worker_func callback function to be executed + * @param main_func special callback function, called from main thread, may be NULL + * @param nb_threads number of threads, 0 for automatic, must be >= 0 + * @return return number of threads or negative AVERROR on failure + */ +int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), + void (*main_func)(void *priv), + int nb_threads); + +/** + * Execute slice threading. + * @param ctx slice threading context + * @param nb_jobs number of jobs, must be > 0 + * @param execute_main also execute main_func + */ +void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main); + +/** + * Destroy slice threading context. + * @param pctx pointer to context + */ +void avpriv_slicethread_free(AVSliceThread **pctx); + +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat.h new file mode 100644 index 0000000000..a651406f74 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SOFTFLOAT_H +#define AVUTIL_SOFTFLOAT_H + +#include +#include "common.h" + +#include "avassert.h" +#include "softfloat_tables.h" + +#define MIN_EXP -149 +#define MAX_EXP 126 +#define ONE_BITS 29 + +typedef struct SoftFloat{ + int32_t mant; + int32_t exp; +}SoftFloat; + +static const SoftFloat FLOAT_0 = { 0, MIN_EXP}; ///< 0.0 +static const SoftFloat FLOAT_05 = { 0x20000000, 0}; ///< 0.5 +static const SoftFloat FLOAT_1 = { 0x20000000, 1}; ///< 1.0 +static const SoftFloat FLOAT_EPSILON = { 0x29F16B12, -16}; ///< A small value +static const SoftFloat FLOAT_1584893192 = { 0x32B771ED, 1}; ///< 1.584893192 (10^.2) +static const SoftFloat FLOAT_100000 = { 0x30D40000, 17}; ///< 100000 +static const SoftFloat FLOAT_0999999 = { 0x3FFFFBCE, 0}; ///< 0.999999 +static const SoftFloat FLOAT_MIN = { 0x20000000, MIN_EXP}; + + +/** + * Convert a SoftFloat to a double precision float. + */ +static inline av_const double av_sf2double(SoftFloat v) { + v.exp -= ONE_BITS +1; + return ldexp(v.mant, v.exp); +} + +static av_const SoftFloat av_normalize_sf(SoftFloat a){ + if(a.mant){ +#if 1 + while((a.mant + 0x1FFFFFFFU)<0x3FFFFFFFU){ + a.mant += a.mant; + a.exp -= 1; + } +#else + int s=ONE_BITS - av_log2(FFABS(a.mant)); + a.exp -= s; + a.mant <<= s; +#endif + if(a.exp < MIN_EXP){ + a.exp = MIN_EXP; + a.mant= 0; + } + }else{ + a.exp= MIN_EXP; + } + return a; +} + +static inline av_const SoftFloat av_normalize1_sf(SoftFloat a){ +#if 1 + if((int32_t)(a.mant + 0x40000000U) <= 0){ + a.exp++; + a.mant>>=1; + } + av_assert2(a.mant < 0x40000000 && a.mant > -0x40000000); + av_assert2(a.exp <= MAX_EXP); + return a; +#elif 1 + int t= a.mant + 0x40000000 < 0; + return (SoftFloat){ a.mant>>t, a.exp+t}; +#else + int t= (a.mant + 0x3FFFFFFFU)>>31; + return (SoftFloat){a.mant>>t, a.exp+t}; +#endif +} + +/** + * @return Will not be more denormalized than a*b. So if either input is + * normalized, then the output will not be worse then the other input. + * If both are normalized, then the output will be normalized. + */ +static inline av_const SoftFloat av_mul_sf(SoftFloat a, SoftFloat b){ + a.exp += b.exp; + av_assert2((int32_t)((a.mant * (int64_t)b.mant) >> ONE_BITS) == (a.mant * (int64_t)b.mant) >> ONE_BITS); + a.mant = (a.mant * (int64_t)b.mant) >> ONE_BITS; + a = av_normalize1_sf((SoftFloat){a.mant, a.exp - 1}); + if (!a.mant || a.exp < MIN_EXP) + return FLOAT_0; + return a; +} + +/** + * b has to be normalized and not zero. + * @return Will not be more denormalized than a. + */ +static inline av_const SoftFloat av_div_sf(SoftFloat a, SoftFloat b){ + int64_t temp = (int64_t)a.mant * (1<<(ONE_BITS+1)); + temp /= b.mant; + a.exp -= b.exp; + a.mant = temp; + while (a.mant != temp) { + temp /= 2; + a.exp--; + a.mant = temp; + } + a = av_normalize1_sf(a); + if (!a.mant || a.exp < MIN_EXP) + return FLOAT_0; + return a; +} + +/** + * Compares two SoftFloats. + * @returns < 0 if the first is less + * > 0 if the first is greater + * 0 if they are equal + */ +static inline av_const int av_cmp_sf(SoftFloat a, SoftFloat b){ + int t= a.exp - b.exp; + if (t <-31) return - b.mant ; + else if (t < 0) return (a.mant >> (-t)) - b.mant ; + else if (t < 32) return a.mant - (b.mant >> t); + else return a.mant ; +} + +/** + * Compares two SoftFloats. + * @returns 1 if a is greater than b, 0 otherwise + */ +static inline av_const int av_gt_sf(SoftFloat a, SoftFloat b) +{ + int t= a.exp - b.exp; + if (t <-31) return 0 > b.mant ; + else if (t < 0) return (a.mant >> (-t)) > b.mant ; + else if (t < 32) return a.mant > (b.mant >> t); + else return a.mant > 0 ; +} + +/** + * @returns the sum of 2 SoftFloats. + */ +static inline av_const SoftFloat av_add_sf(SoftFloat a, SoftFloat b){ + int t= a.exp - b.exp; + if (t <-31) return b; + else if (t < 0) return av_normalize_sf(av_normalize1_sf((SoftFloat){ b.mant + (a.mant >> (-t)), b.exp})); + else if (t < 32) return av_normalize_sf(av_normalize1_sf((SoftFloat){ a.mant + (b.mant >> t ), a.exp})); + else return a; +} + +/** + * @returns the difference of 2 SoftFloats. + */ +static inline av_const SoftFloat av_sub_sf(SoftFloat a, SoftFloat b){ + return av_add_sf(a, (SoftFloat){ -b.mant, b.exp}); +} + +//FIXME log, exp, pow + +/** + * Converts a mantisse and exponent to a SoftFloat. + * This converts a fixed point value v with frac_bits fractional bits to a + * SoftFloat. + * @returns a SoftFloat with value v * 2^-frac_bits + */ +static inline av_const SoftFloat av_int2sf(int v, int frac_bits){ + int exp_offset = 0; + if(v <= INT_MIN + 1){ + exp_offset = 1; + v>>=1; + } + return av_normalize_sf(av_normalize1_sf((SoftFloat){v, ONE_BITS + 1 - frac_bits + exp_offset})); +} + +/** + * Converts a SoftFloat to an integer. + * Rounding is to -inf. + */ +static inline av_const int av_sf2int(SoftFloat v, int frac_bits){ + v.exp += frac_bits - (ONE_BITS + 1); + if(v.exp >= 0) return v.mant << v.exp ; + else return v.mant >>(-v.exp); +} + +/** + * Rounding-to-nearest used. + */ +static av_always_inline SoftFloat av_sqrt_sf(SoftFloat val) +{ + int tabIndex, rem; + + if (val.mant == 0) + val.exp = MIN_EXP; + else if (val.mant < 0) + abort(); + else + { + tabIndex = (val.mant - 0x20000000) >> 20; + + rem = val.mant & 0xFFFFF; + val.mant = (int)(((int64_t)av_sqrttbl_sf[tabIndex] * (0x100000 - rem) + + (int64_t)av_sqrttbl_sf[tabIndex + 1] * rem + + 0x80000) >> 20); + val.mant = (int)(((int64_t)av_sqr_exp_multbl_sf[val.exp & 1] * val.mant + + 0x10000000) >> 29); + + if (val.mant < 0x40000000) + val.exp -= 2; + else + val.mant >>= 1; + + val.exp = (val.exp >> 1) + 1; + } + + return val; +} + +/** + * Rounding-to-nearest used. + */ +static av_unused void av_sincos_sf(int a, int *s, int *c) +{ + int idx, sign; + int sv, cv; + int st, ct; + + idx = a >> 26; + sign = (int32_t)((unsigned)idx << 27) >> 31; + cv = av_costbl_1_sf[idx & 0xf]; + cv = (cv ^ sign) - sign; + + idx -= 8; + sign = (int32_t)((unsigned)idx << 27) >> 31; + sv = av_costbl_1_sf[idx & 0xf]; + sv = (sv ^ sign) - sign; + + idx = a >> 21; + ct = av_costbl_2_sf[idx & 0x1f]; + st = av_sintbl_2_sf[idx & 0x1f]; + + idx = (int)(((int64_t)cv * ct - (int64_t)sv * st + 0x20000000) >> 30); + + sv = (int)(((int64_t)cv * st + (int64_t)sv * ct + 0x20000000) >> 30); + + cv = idx; + + idx = a >> 16; + ct = av_costbl_3_sf[idx & 0x1f]; + st = av_sintbl_3_sf[idx & 0x1f]; + + idx = (int)(((int64_t)cv * ct - (int64_t)sv * st + 0x20000000) >> 30); + + sv = (int)(((int64_t)cv * st + (int64_t)sv * ct + 0x20000000) >> 30); + cv = idx; + + idx = a >> 11; + + ct = (int)(((int64_t)av_costbl_4_sf[idx & 0x1f] * (0x800 - (a & 0x7ff)) + + (int64_t)av_costbl_4_sf[(idx & 0x1f)+1]*(a & 0x7ff) + + 0x400) >> 11); + st = (int)(((int64_t)av_sintbl_4_sf[idx & 0x1f] * (0x800 - (a & 0x7ff)) + + (int64_t)av_sintbl_4_sf[(idx & 0x1f) + 1] * (a & 0x7ff) + + 0x400) >> 11); + + *c = (int)(((int64_t)cv * ct + (int64_t)sv * st + 0x20000000) >> 30); + + *s = (int)(((int64_t)cv * st + (int64_t)sv * ct + 0x20000000) >> 30); +} + +#endif /* AVUTIL_SOFTFLOAT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat_ieee754.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat_ieee754.h new file mode 100644 index 0000000000..3398aa18be --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat_ieee754.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2016 Umair Khan + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SOFTFLOAT_IEEE754_H +#define AVUTIL_SOFTFLOAT_IEEE754_H + +#include + +#define EXP_BIAS 127 +#define MANT_BITS 23 + +typedef struct SoftFloat_IEEE754 { + int32_t sign; + uint64_t mant; + int32_t exp; +} SoftFloat_IEEE754; + +static const SoftFloat_IEEE754 FLOAT_0 = {0, 0, -126}; +static const SoftFloat_IEEE754 FLOAT_1 = {0, 0, 0}; + +/** Normalize the softfloat as defined by IEEE 754 single-recision floating + * point specification + */ +static inline SoftFloat_IEEE754 av_normalize_sf_ieee754(SoftFloat_IEEE754 sf) { + while( sf.mant >= 0x1000000UL ) { + sf.exp++; + sf.mant >>= 1; + } + sf.mant &= 0x007fffffUL; + return sf; +} + +/** Convert integer to softfloat. + * @return softfloat with value n * 2^e + */ +static inline SoftFloat_IEEE754 av_int2sf_ieee754(int64_t n, int e) { + int sign = 0; + + if (n < 0) { + sign = 1; + n *= -1; + } + return av_normalize_sf_ieee754((SoftFloat_IEEE754) {sign, n << MANT_BITS, 0 + e}); +} + +/** Make a softfloat out of the bitstream. Assumes the bits are in the form as defined + * by the IEEE 754 spec. + */ +static inline SoftFloat_IEEE754 av_bits2sf_ieee754(uint32_t n) { + return ((SoftFloat_IEEE754) { (n & 0x80000000UL) >> 31, (n & 0x7FFFFFUL), (int8_t)((n & 0x7F800000UL) >> 23)}); +} + +/** Convert the softfloat to integer + */ +static inline int av_sf2int_ieee754(SoftFloat_IEEE754 a) { + if(a.exp >= 0) return a.mant << a.exp ; + else return a.mant >>(-a.exp); +} + +/** Divide a by b. b should not be zero. + * @return normalized result + */ +static inline SoftFloat_IEEE754 av_div_sf_ieee754(SoftFloat_IEEE754 a, SoftFloat_IEEE754 b) { + int32_t mant, exp, sign; + a = av_normalize_sf_ieee754(a); + b = av_normalize_sf_ieee754(b); + sign = a.sign ^ b.sign; + mant = ((((uint64_t) (a.mant | 0x00800000UL)) << MANT_BITS) / (b.mant| 0x00800000UL)); + exp = a.exp - b.exp; + return av_normalize_sf_ieee754((SoftFloat_IEEE754) {sign, mant, exp}); +} + +/** Multiply a with b + * #return normalized result + */ +static inline SoftFloat_IEEE754 av_mul_sf_ieee754(SoftFloat_IEEE754 a, SoftFloat_IEEE754 b) { + int32_t sign, mant, exp; + a = av_normalize_sf_ieee754(a); + b = av_normalize_sf_ieee754(b); + sign = a.sign ^ b.sign; + mant = (((uint64_t)(a.mant|0x00800000UL) * (uint64_t)(b.mant|0x00800000UL))>>MANT_BITS); + exp = a.exp + b.exp; + return av_normalize_sf_ieee754((SoftFloat_IEEE754) {sign, mant, exp}); +} + +/** Compare a with b strictly + * @returns 1 if the a and b are equal, 0 otherwise. + */ +static inline int av_cmp_sf_ieee754(SoftFloat_IEEE754 a, SoftFloat_IEEE754 b) { + a = av_normalize_sf_ieee754(a); + b = av_normalize_sf_ieee754(b); + if (a.sign != b.sign) return 0; + if (a.mant != b.mant) return 0; + if (a.exp != b.exp ) return 0; + return 1; +} + +#endif /*AVUTIL_SOFTFLOAT_IEEE754_H*/ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat_tables.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat_tables.h new file mode 100644 index 0000000000..461f2b221d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/softfloat_tables.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2012 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of is + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Stanislav Ocovaj (stanislav.ocovaj imgtec com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVUTIL_SOFTFLOAT_TABLES_H +#define AVUTIL_SOFTFLOAT_TABLES_H + +#include + +static const int32_t av_sqrttbl_sf[512+1] = { /* sqrt(x), 0.5<=x<1 */ + 0x2d413ccd,0x2d4c8bb3,0x2d57d7c6,0x2d63210a, + 0x2d6e677f,0x2d79ab2a,0x2d84ec0b,0x2d902a23, + 0x2d9b6578,0x2da69e08,0x2db1d3d6,0x2dbd06e6, + 0x2dc83738,0x2dd364ce,0x2dde8fac,0x2de9b7d2, + 0x2df4dd43,0x2e000000,0x2e0b200c,0x2e163d68, + 0x2e215816,0x2e2c701a,0x2e378573,0x2e429824, + 0x2e4da830,0x2e58b598,0x2e63c05d,0x2e6ec883, + 0x2e79ce0a,0x2e84d0f5,0x2e8fd144,0x2e9acefb, + 0x2ea5ca1b,0x2eb0c2a7,0x2ebbb89e,0x2ec6ac04, + 0x2ed19cda,0x2edc8b23,0x2ee776df,0x2ef26012, + 0x2efd46bb,0x2f082add,0x2f130c7b,0x2f1deb95, + 0x2f28c82e,0x2f33a246,0x2f3e79e1,0x2f494eff, + 0x2f5421a3,0x2f5ef1ce,0x2f69bf81,0x2f748abe, + 0x2f7f5388,0x2f8a19e0,0x2f94ddc7,0x2f9f9f3e, + 0x2faa5e48,0x2fb51ae8,0x2fbfd51c,0x2fca8ce9, + 0x2fd5424e,0x2fdff54e,0x2feaa5eb,0x2ff55426, + 0x30000000,0x300aa97b,0x3015509a,0x301ff55c, + 0x302a97c5,0x303537d5,0x303fd58e,0x304a70f2, + 0x30550a01,0x305fa0be,0x306a352a,0x3074c747, + 0x307f5716,0x3089e499,0x30946fd2,0x309ef8c0, + 0x30a97f67,0x30b403c7,0x30be85e2,0x30c905bb, + 0x30d38351,0x30ddfea6,0x30e877bc,0x30f2ee96, + 0x30fd6332,0x3107d594,0x311245bc,0x311cb3ad, + 0x31271f67,0x313188ec,0x313bf03d,0x3146555c, + 0x3150b84a,0x315b1909,0x31657798,0x316fd3fc, + 0x317a2e34,0x31848642,0x318edc28,0x31992fe5, + 0x31a3817d,0x31add0f0,0x31b81e40,0x31c2696e, + 0x31ccb27b,0x31d6f969,0x31e13e38,0x31eb80eb, + 0x31f5c182,0x32000000,0x320a3c65,0x321476b1, + 0x321eaee8,0x3228e50a,0x32331917,0x323d4b13, + 0x32477afc,0x3251a8d6,0x325bd4a2,0x3265fe5f, + 0x32702611,0x327a4bb8,0x32846f55,0x328e90e9, + 0x3298b076,0x32a2cdfd,0x32ace97e,0x32b702fd, + 0x32c11a79,0x32cb2ff3,0x32d5436d,0x32df54e9, + 0x32e96466,0x32f371e8,0x32fd7d6d,0x330786f9, + 0x33118e8c,0x331b9426,0x332597cb,0x332f9979, + 0x33399933,0x334396fa,0x334d92cf,0x33578cb2, + 0x336184a6,0x336b7aab,0x33756ec3,0x337f60ed, + 0x3389512d,0x33933f83,0x339d2bef,0x33a71672, + 0x33b0ff10,0x33bae5c7,0x33c4ca99,0x33cead88, + 0x33d88e95,0x33e26dbf,0x33ec4b09,0x33f62673, + 0x34000000,0x3409d7af,0x3413ad82,0x341d817a, + 0x34275397,0x343123db,0x343af248,0x3444bedd, + 0x344e899d,0x34585288,0x3462199f,0x346bdee3, + 0x3475a254,0x347f63f5,0x348923c6,0x3492e1c9, + 0x349c9dfe,0x34a65865,0x34b01101,0x34b9c7d2, + 0x34c37cda,0x34cd3018,0x34d6e18f,0x34e0913f, + 0x34ea3f29,0x34f3eb4d,0x34fd95ae,0x35073e4c, + 0x3510e528,0x351a8a43,0x35242d9d,0x352dcf39, + 0x35376f16,0x35410d36,0x354aa99a,0x35544442, + 0x355ddd2f,0x35677463,0x357109df,0x357a9da2, + 0x35842fb0,0x358dc007,0x35974ea9,0x35a0db98, + 0x35aa66d3,0x35b3f05c,0x35bd7833,0x35c6fe5a, + 0x35d082d3,0x35da059c,0x35e386b7,0x35ed0626, + 0x35f683e8,0x36000000,0x36097a6e,0x3612f331, + 0x361c6a4d,0x3625dfc1,0x362f538f,0x3638c5b7, + 0x36423639,0x364ba518,0x36551252,0x365e7deb, + 0x3667e7e2,0x36715039,0x367ab6f0,0x36841c07, + 0x368d7f81,0x3696e15d,0x36a0419d,0x36a9a040, + 0x36b2fd49,0x36bc58b8,0x36c5b28e,0x36cf0acb, + 0x36d86170,0x36e1b680,0x36eb09f8,0x36f45bdc, + 0x36fdac2b,0x3706fae7,0x37104810,0x371993a7, + 0x3722ddad,0x372c2622,0x37356d08,0x373eb25f, + 0x3747f629,0x37513865,0x375a7914,0x3763b838, + 0x376cf5d0,0x377631e0,0x377f6c64,0x3788a561, + 0x3791dcd6,0x379b12c4,0x37a4472c,0x37ad7a0e, + 0x37b6ab6a,0x37bfdb44,0x37c90999,0x37d2366d, + 0x37db61be,0x37e48b8e,0x37edb3de,0x37f6daae, + 0x38000000,0x380923d3,0x3812462a,0x381b6703, + 0x38248660,0x382da442,0x3836c0aa,0x383fdb97, + 0x3848f50c,0x38520d09,0x385b238d,0x3864389b, + 0x386d4c33,0x38765e55,0x387f6f01,0x38887e3b, + 0x38918c00,0x389a9853,0x38a3a334,0x38acaca3, + 0x38b5b4a3,0x38bebb32,0x38c7c051,0x38d0c402, + 0x38d9c645,0x38e2c71b,0x38ebc685,0x38f4c482, + 0x38fdc114,0x3906bc3c,0x390fb5fa,0x3918ae4f, + 0x3921a53a,0x392a9abe,0x39338edb,0x393c8192, + 0x394572e2,0x394e62ce,0x39575155,0x39603e77, + 0x39692a36,0x39721494,0x397afd8f,0x3983e527, + 0x398ccb60,0x3995b039,0x399e93b2,0x39a775cc, + 0x39b05689,0x39b935e8,0x39c213e9,0x39caf08e, + 0x39d3cbd9,0x39dca5c7,0x39e57e5b,0x39ee5596, + 0x39f72b77,0x3a000000,0x3a08d331,0x3a11a50a, + 0x3a1a758d,0x3a2344ba,0x3a2c1291,0x3a34df13, + 0x3a3daa41,0x3a46741b,0x3a4f3ca3,0x3a5803d7, + 0x3a60c9ba,0x3a698e4b,0x3a72518b,0x3a7b137c, + 0x3a83d41d,0x3a8c936f,0x3a955173,0x3a9e0e29, + 0x3aa6c992,0x3aaf83ae,0x3ab83c7e,0x3ac0f403, + 0x3ac9aa3c,0x3ad25f2c,0x3adb12d1,0x3ae3c52d, + 0x3aec7642,0x3af5260e,0x3afdd492,0x3b0681d0, + 0x3b0f2dc6,0x3b17d878,0x3b2081e4,0x3b292a0c, + 0x3b31d0f0,0x3b3a7690,0x3b431aec,0x3b4bbe06, + 0x3b545fdf,0x3b5d0077,0x3b659fcd,0x3b6e3de4, + 0x3b76daba,0x3b7f7651,0x3b8810aa,0x3b90a9c4, + 0x3b9941a1,0x3ba1d842,0x3baa6da5,0x3bb301cd, + 0x3bbb94b9,0x3bc4266a,0x3bccb6e2,0x3bd5461f, + 0x3bddd423,0x3be660ee,0x3beeec81,0x3bf776dc, + 0x3c000000,0x3c0887ed,0x3c110ea4,0x3c199426, + 0x3c221872,0x3c2a9b8a,0x3c331d6e,0x3c3b9e1d, + 0x3c441d9a,0x3c4c9be5,0x3c5518fd,0x3c5d94e3, + 0x3c660f98,0x3c6e891d,0x3c770172,0x3c7f7898, + 0x3c87ee8e,0x3c906356,0x3c98d6ef,0x3ca1495b, + 0x3ca9ba9a,0x3cb22aac,0x3cba9992,0x3cc3074c, + 0x3ccb73dc,0x3cd3df41,0x3cdc497b,0x3ce4b28c, + 0x3ced1a73,0x3cf58132,0x3cfde6c8,0x3d064b37, + 0x3d0eae7f,0x3d17109f,0x3d1f719a,0x3d27d16e, + 0x3d30301d,0x3d388da8,0x3d40ea0d,0x3d49454f, + 0x3d519f6d,0x3d59f867,0x3d625040,0x3d6aa6f6, + 0x3d72fc8b,0x3d7b50fe,0x3d83a451,0x3d8bf683, + 0x3d944796,0x3d9c9788,0x3da4e65c,0x3dad3412, + 0x3db580a9,0x3dbdcc24,0x3dc61680,0x3dce5fc0, + 0x3dd6a7e4,0x3ddeeeed,0x3de734d9,0x3def79ab, + 0x3df7bd62,0x3e000000,0x3e084184,0x3e1081ee, + 0x3e18c140,0x3e20ff7a,0x3e293c9c,0x3e3178a7, + 0x3e39b39a,0x3e41ed77,0x3e4a263d,0x3e525def, + 0x3e5a948b,0x3e62ca12,0x3e6afe85,0x3e7331e4, + 0x3e7b642f,0x3e839567,0x3e8bc58c,0x3e93f49f, + 0x3e9c22a1,0x3ea44f91,0x3eac7b6f,0x3eb4a63e, + 0x3ebccffb,0x3ec4f8aa,0x3ecd2049,0x3ed546d9, + 0x3edd6c5a,0x3ee590cd,0x3eedb433,0x3ef5d68c, + 0x3efdf7d7,0x3f061816,0x3f0e3749,0x3f165570, + 0x3f1e728c,0x3f268e9d,0x3f2ea9a4,0x3f36c3a0, + 0x3f3edc93,0x3f46f47c,0x3f4f0b5d,0x3f572135, + 0x3f5f3606,0x3f6749cf,0x3f6f5c90,0x3f776e4a, + 0x3f7f7efe,0x3f878eab,0x3f8f9d53,0x3f97aaf6, + 0x3f9fb793,0x3fa7c32c,0x3fafcdc1,0x3fb7d752, + 0x3fbfdfe0,0x3fc7e76b,0x3fcfedf3,0x3fd7f378, + 0x3fdff7fc,0x3fe7fb7f,0x3feffe00,0x3ff7ff80, + 0x3fffffff, +}; + +static const int32_t av_sqr_exp_multbl_sf[2] = { + 0x20000000,0x2d413ccd, +}; + +static const int32_t av_costbl_1_sf[16] = { + 0x40000000,0x3ec52fa0,0x3b20d79e,0x3536cc52, + 0x2d413ccd,0x238e7673,0x187de2a7,0x0c7c5c1e, + 0x00000000,0xf383a3e3,0xe7821d5a,0xdc71898e, + 0xd2bec334,0xcac933af,0xc4df2863,0xc13ad061, +}; + +static const int32_t av_costbl_2_sf[32] = { + 0x40000000,0x3fffb10b,0x3ffec42d,0x3ffd3969, + 0x3ffb10c1,0x3ff84a3c,0x3ff4e5e0,0x3ff0e3b6, + 0x3fec43c7,0x3fe7061f,0x3fe12acb,0x3fdab1d9, + 0x3fd39b5a,0x3fcbe75e,0x3fc395f9,0x3fbaa740, + 0x3fb11b48,0x3fa6f228,0x3f9c2bfb,0x3f90c8da, + 0x3f84c8e2,0x3f782c30,0x3f6af2e3,0x3f5d1d1d, + 0x3f4eaafe,0x3f3f9cab,0x3f2ff24a,0x3f1fabff, + 0x3f0ec9f5,0x3efd4c54,0x3eeb3347,0x3ed87efc, +}; + +static const int32_t av_sintbl_2_sf[32] = { + 0x00000000,0x006487c4,0x00c90e90,0x012d936c, + 0x0192155f,0x01f69373,0x025b0caf,0x02bf801a, + 0x0323ecbe,0x038851a2,0x03ecadcf,0x0451004d, + 0x04b54825,0x0519845e,0x057db403,0x05e1d61b, + 0x0645e9af,0x06a9edc9,0x070de172,0x0771c3b3, + 0x07d59396,0x08395024,0x089cf867,0x09008b6a, + 0x09640837,0x09c76dd8,0x0a2abb59,0x0a8defc3, + 0x0af10a22,0x0b540982,0x0bb6ecef,0x0c19b374, +}; + +static const int32_t av_costbl_3_sf[32] = { + 0x40000000,0x3fffffec,0x3fffffb1,0x3fffff4e, + 0x3ffffec4,0x3ffffe13,0x3ffffd39,0x3ffffc39, + 0x3ffffb11,0x3ffff9c1,0x3ffff84a,0x3ffff6ac, + 0x3ffff4e6,0x3ffff2f8,0x3ffff0e3,0x3fffeea7, + 0x3fffec43,0x3fffe9b7,0x3fffe705,0x3fffe42a, + 0x3fffe128,0x3fffddff,0x3fffdaae,0x3fffd736, + 0x3fffd396,0x3fffcfcf,0x3fffcbe0,0x3fffc7ca, + 0x3fffc38c,0x3fffbf27,0x3fffba9b,0x3fffb5e7, +}; + +static const int32_t av_sintbl_3_sf[32] = { + 0x00000000,0x0003243f,0x0006487f,0x00096cbe, + 0x000c90fe,0x000fb53d,0x0012d97c,0x0015fdbb, + 0x001921fb,0x001c463a,0x001f6a79,0x00228eb8, + 0x0025b2f7,0x0028d736,0x002bfb74,0x002f1fb3, + 0x003243f1,0x00356830,0x00388c6e,0x003bb0ac, + 0x003ed4ea,0x0041f928,0x00451d66,0x004841a3, + 0x004b65e1,0x004e8a1e,0x0051ae5b,0x0054d297, + 0x0057f6d4,0x005b1b10,0x005e3f4c,0x00616388, +}; + +static const int32_t av_costbl_4_sf[33] = { + 0x40000000,0x40000000,0x40000000,0x40000000, + 0x40000000,0x40000000,0x3fffffff,0x3fffffff, + 0x3fffffff,0x3ffffffe,0x3ffffffe,0x3ffffffe, + 0x3ffffffd,0x3ffffffd,0x3ffffffc,0x3ffffffc, + 0x3ffffffb,0x3ffffffa,0x3ffffffa,0x3ffffff9, + 0x3ffffff8,0x3ffffff7,0x3ffffff7,0x3ffffff6, + 0x3ffffff5,0x3ffffff4,0x3ffffff3,0x3ffffff2, + 0x3ffffff1,0x3ffffff0,0x3fffffef,0x3fffffed, + 0x3fffffec, +}; + +static const int32_t av_sintbl_4_sf[33] = { + 0x00000000,0x00001922,0x00003244,0x00004b66, + 0x00006488,0x00007daa,0x000096cc,0x0000afee, + 0x0000c910,0x0000e232,0x0000fb54,0x00011476, + 0x00012d98,0x000146ba,0x00015fdc,0x000178fe, + 0x00019220,0x0001ab42,0x0001c464,0x0001dd86, + 0x0001f6a8,0x00020fca,0x000228ec,0x0002420e, + 0x00025b30,0x00027452,0x00028d74,0x0002a696, + 0x0002bfb7,0x0002d8d9,0x0002f1fb,0x00030b1d, + 0x0003243f, +}; +#endif /* AVUTIL_SOFTFLOAT_TABLES_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/spherical.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/spherical.c new file mode 100644 index 0000000000..4be55f36cf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/spherical.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mem.h" +#include "spherical.h" + +AVSphericalMapping *av_spherical_alloc(size_t *size) +{ + AVSphericalMapping *spherical = av_mallocz(sizeof(AVSphericalMapping)); + if (!spherical) + return NULL; + + if (size) + *size = sizeof(*spherical); + + return spherical; +} + +void av_spherical_tile_bounds(const AVSphericalMapping *map, + size_t width, size_t height, + size_t *left, size_t *top, + size_t *right, size_t *bottom) +{ + /* conversion from 0.32 coordinates to pixels */ + uint64_t orig_width = (uint64_t) width * UINT32_MAX / + (UINT32_MAX - map->bound_right - map->bound_left); + uint64_t orig_height = (uint64_t) height * UINT32_MAX / + (UINT32_MAX - map->bound_bottom - map->bound_top); + + /* add a (UINT32_MAX - 1) to round up integer division */ + *left = (orig_width * map->bound_left + UINT32_MAX - 1) / UINT32_MAX; + *top = (orig_height * map->bound_top + UINT32_MAX - 1) / UINT32_MAX; + *right = orig_width - width - *left; + *bottom = orig_height - height - *top; +} + +static const char *spherical_projection_names[] = { + [AV_SPHERICAL_EQUIRECTANGULAR] = "equirectangular", + [AV_SPHERICAL_CUBEMAP] = "cubemap", + [AV_SPHERICAL_EQUIRECTANGULAR_TILE] = "tiled equirectangular", +}; + +const char *av_spherical_projection_name(enum AVSphericalProjection projection) +{ + if ((unsigned)projection >= FF_ARRAY_ELEMS(spherical_projection_names)) + return "unknown"; + + return spherical_projection_names[projection]; +} + +int av_spherical_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(spherical_projection_names); i++) { + size_t len = strlen(spherical_projection_names[i]); + if (!strncmp(spherical_projection_names[i], name, len)) + return i; + } + + return -1; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/spherical.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/spherical.h new file mode 100644 index 0000000000..cef759cf27 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/spherical.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2016 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Spherical video + */ + +#ifndef AVUTIL_SPHERICAL_H +#define AVUTIL_SPHERICAL_H + +#include +#include + +/** + * @addtogroup lavu_video + * @{ + * + * @defgroup lavu_video_spherical Spherical video mapping + * @{ + */ + +/** + * @addtogroup lavu_video_spherical + * A spherical video file contains surfaces that need to be mapped onto a + * sphere. Depending on how the frame was converted, a different distortion + * transformation or surface recomposition function needs to be applied before + * the video should be mapped and displayed. + */ + +/** + * Projection of the video surface(s) on a sphere. + */ +enum AVSphericalProjection { + /** + * Video represents a sphere mapped on a flat surface using + * equirectangular projection. + */ + AV_SPHERICAL_EQUIRECTANGULAR, + + /** + * Video frame is split into 6 faces of a cube, and arranged on a + * 3x2 layout. Faces are oriented upwards for the front, left, right, + * and back faces. The up face is oriented so the top of the face is + * forwards and the down face is oriented so the top of the face is + * to the back. + */ + AV_SPHERICAL_CUBEMAP, + + /** + * Video represents a portion of a sphere mapped on a flat surface + * using equirectangular projection. The @ref bounding fields indicate + * the position of the current video in a larger surface. + */ + AV_SPHERICAL_EQUIRECTANGULAR_TILE, +}; + +/** + * This structure describes how to handle spherical videos, outlining + * information about projection, initial layout, and any other view modifier. + * + * @note The struct must be allocated with av_spherical_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVSphericalMapping { + /** + * Projection type. + */ + enum AVSphericalProjection projection; + + /** + * @name Initial orientation + * @{ + * There fields describe additional rotations applied to the sphere after + * the video frame is mapped onto it. The sphere is rotated around the + * viewer, who remains stationary. The order of transformation is always + * yaw, followed by pitch, and finally by roll. + * + * The coordinate system matches the one defined in OpenGL, where the + * forward vector (z) is coming out of screen, and it is equivalent to + * a rotation matrix of R = r_y(yaw) * r_x(pitch) * r_z(roll). + * + * A positive yaw rotates the portion of the sphere in front of the viewer + * toward their right. A positive pitch rotates the portion of the sphere + * in front of the viewer upwards. A positive roll tilts the portion of + * the sphere in front of the viewer to the viewer's right. + * + * These values are exported as 16.16 fixed point. + * + * See this equirectangular projection as example: + * + * @code{.unparsed} + * Yaw + * -180 0 180 + * 90 +-------------+-------------+ 180 + * | | | up + * P | | | y| forward + * i | ^ | | /z + * t 0 +-------------X-------------+ 0 Roll | / + * c | | | | / + * h | | | 0|/_____right + * | | | x + * -90 +-------------+-------------+ -180 + * + * X - the default camera center + * ^ - the default up vector + * @endcode + */ + int32_t yaw; ///< Rotation around the up vector [-180, 180]. + int32_t pitch; ///< Rotation around the right vector [-90, 90]. + int32_t roll; ///< Rotation around the forward vector [-180, 180]. + /** + * @} + */ + + /** + * @name Bounding rectangle + * @anchor bounding + * @{ + * These fields indicate the location of the current tile, and where + * it should be mapped relative to the original surface. They are + * exported as 0.32 fixed point, and can be converted to classic + * pixel values with av_spherical_bounds(). + * + * @code{.unparsed} + * +----------------+----------+ + * | |bound_top | + * | +--------+ | + * | bound_left |tile | | + * +<---------->| |<--->+bound_right + * | +--------+ | + * | | | + * | bound_bottom| | + * +----------------+----------+ + * @endcode + * + * If needed, the original video surface dimensions can be derived + * by adding the current stream or frame size to the related bounds, + * like in the following example: + * + * @code{c} + * original_width = tile->width + bound_left + bound_right; + * original_height = tile->height + bound_top + bound_bottom; + * @endcode + * + * @note These values are valid only for the tiled equirectangular + * projection type (@ref AV_SPHERICAL_EQUIRECTANGULAR_TILE), + * and should be ignored in all other cases. + */ + uint32_t bound_left; ///< Distance from the left edge + uint32_t bound_top; ///< Distance from the top edge + uint32_t bound_right; ///< Distance from the right edge + uint32_t bound_bottom; ///< Distance from the bottom edge + /** + * @} + */ + + /** + * Number of pixels to pad from the edge of each cube face. + * + * @note This value is valid for only for the cubemap projection type + * (@ref AV_SPHERICAL_CUBEMAP), and should be ignored in all other + * cases. + */ + uint32_t padding; +} AVSphericalMapping; + +/** + * Allocate a AVSphericalVideo structure and initialize its fields to default + * values. + * + * @return the newly allocated struct or NULL on failure + */ +AVSphericalMapping *av_spherical_alloc(size_t *size); + +/** + * Convert the @ref bounding fields from an AVSphericalVideo + * from 0.32 fixed point to pixels. + * + * @param map The AVSphericalVideo map to read bound values from. + * @param width Width of the current frame or stream. + * @param height Height of the current frame or stream. + * @param left Pixels from the left edge. + * @param top Pixels from the top edge. + * @param right Pixels from the right edge. + * @param bottom Pixels from the bottom edge. + */ +void av_spherical_tile_bounds(const AVSphericalMapping *map, + size_t width, size_t height, + size_t *left, size_t *top, + size_t *right, size_t *bottom); + +/** + * Provide a human-readable name of a given AVSphericalProjection. + * + * @param projection The input AVSphericalProjection. + * + * @return The name of the AVSphericalProjection, or "unknown". + */ +const char *av_spherical_projection_name(enum AVSphericalProjection projection); + +/** + * Get the AVSphericalProjection form a human-readable name. + * + * @param name The input string. + * + * @return The AVSphericalProjection value, or -1 if not found. + */ +int av_spherical_from_name(const char *name); +/** + * @} + * @} + */ + +#endif /* AVUTIL_SPHERICAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/stereo3d.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/stereo3d.c new file mode 100644 index 0000000000..6edcdb1796 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/stereo3d.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "common.h" +#include "mem.h" +#include "stereo3d.h" + +AVStereo3D *av_stereo3d_alloc(void) +{ + return av_mallocz(sizeof(AVStereo3D)); +} + +AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_STEREO3D, + sizeof(AVStereo3D)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, sizeof(AVStereo3D)); + + return (AVStereo3D *)side_data->data; +} + +static const char * const stereo3d_type_names[] = { + [AV_STEREO3D_2D] = "2D", + [AV_STEREO3D_SIDEBYSIDE] = "side by side", + [AV_STEREO3D_TOPBOTTOM] = "top and bottom", + [AV_STEREO3D_FRAMESEQUENCE] = "frame alternate", + [AV_STEREO3D_CHECKERBOARD] = "checkerboard", + [AV_STEREO3D_SIDEBYSIDE_QUINCUNX] = "side by side (quincunx subsampling)", + [AV_STEREO3D_LINES] = "interleaved lines", + [AV_STEREO3D_COLUMNS] = "interleaved columns", +}; + +const char *av_stereo3d_type_name(unsigned int type) +{ + if (type >= FF_ARRAY_ELEMS(stereo3d_type_names)) + return "unknown"; + + return stereo3d_type_names[type]; +} + +int av_stereo3d_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(stereo3d_type_names); i++) { + size_t len = strlen(stereo3d_type_names[i]); + if (!strncmp(stereo3d_type_names[i], name, len)) + return i; + } + + return -1; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/stereo3d.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/stereo3d.h new file mode 100644 index 0000000000..d421aac2a2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/stereo3d.h @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2013 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Stereoscopic video + */ + +#ifndef AVUTIL_STEREO3D_H +#define AVUTIL_STEREO3D_H + +#include + +#include "frame.h" + +/** + * @addtogroup lavu_video + * @{ + * + * @defgroup lavu_video_stereo3d Stereo3D types and functions + * @{ + */ + +/** + * @addtogroup lavu_video_stereo3d + * A stereoscopic video file consists in multiple views embedded in a single + * frame, usually describing two views of a scene. This file describes all + * possible codec-independent view arrangements. + * */ + +/** + * List of possible 3D Types + */ +enum AVStereo3DType { + /** + * Video is not stereoscopic (and metadata has to be there). + */ + AV_STEREO3D_2D, + + /** + * Views are next to each other. + * + * @code{.unparsed} + * LLLLRRRR + * LLLLRRRR + * LLLLRRRR + * ... + * @endcode + */ + AV_STEREO3D_SIDEBYSIDE, + + /** + * Views are on top of each other. + * + * @code{.unparsed} + * LLLLLLLL + * LLLLLLLL + * RRRRRRRR + * RRRRRRRR + * @endcode + */ + AV_STEREO3D_TOPBOTTOM, + + /** + * Views are alternated temporally. + * + * @code{.unparsed} + * frame0 frame1 frame2 ... + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * ... ... ... + * @endcode + */ + AV_STEREO3D_FRAMESEQUENCE, + + /** + * Views are packed in a checkerboard-like structure per pixel. + * + * @code{.unparsed} + * LRLRLRLR + * RLRLRLRL + * LRLRLRLR + * ... + * @endcode + */ + AV_STEREO3D_CHECKERBOARD, + + /** + * Views are next to each other, but when upscaling + * apply a checkerboard pattern. + * + * @code{.unparsed} + * LLLLRRRR L L L L R R R R + * LLLLRRRR => L L L L R R R R + * LLLLRRRR L L L L R R R R + * LLLLRRRR L L L L R R R R + * @endcode + */ + AV_STEREO3D_SIDEBYSIDE_QUINCUNX, + + /** + * Views are packed per line, as if interlaced. + * + * @code{.unparsed} + * LLLLLLLL + * RRRRRRRR + * LLLLLLLL + * ... + * @endcode + */ + AV_STEREO3D_LINES, + + /** + * Views are packed per column. + * + * @code{.unparsed} + * LRLRLRLR + * LRLRLRLR + * LRLRLRLR + * ... + * @endcode + */ + AV_STEREO3D_COLUMNS, +}; + +/** + * List of possible view types. + */ +enum AVStereo3DView { + /** + * Frame contains two packed views. + */ + AV_STEREO3D_VIEW_PACKED, + + /** + * Frame contains only the left view. + */ + AV_STEREO3D_VIEW_LEFT, + + /** + * Frame contains only the right view. + */ + AV_STEREO3D_VIEW_RIGHT, +}; + +/** + * Inverted views, Right/Bottom represents the left view. + */ +#define AV_STEREO3D_FLAG_INVERT (1 << 0) + +/** + * Stereo 3D type: this structure describes how two videos are packed + * within a single video surface, with additional information as needed. + * + * @note The struct must be allocated with av_stereo3d_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVStereo3D { + /** + * How views are packed within the video. + */ + enum AVStereo3DType type; + + /** + * Additional information about the frame packing. + */ + int flags; + + /** + * Determines which views are packed. + */ + enum AVStereo3DView view; +} AVStereo3D; + +/** + * Allocate an AVStereo3D structure and set its fields to default values. + * The resulting struct can be freed using av_freep(). + * + * @return An AVStereo3D filled with default values or NULL on failure. + */ +AVStereo3D *av_stereo3d_alloc(void); + +/** + * Allocate a complete AVFrameSideData and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVStereo3D structure to be filled by caller. + */ +AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame); + +/** + * Provide a human-readable name of a given stereo3d type. + * + * @param type The input stereo3d type value. + * + * @return The name of the stereo3d value, or "unknown". + */ +const char *av_stereo3d_type_name(unsigned int type); + +/** + * Get the AVStereo3DType form a human-readable name. + * + * @param name The input string. + * + * @return The AVStereo3DType value, or -1 if not found. + */ +int av_stereo3d_from_name(const char *name); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_STEREO3D_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tea.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tea.c new file mode 100644 index 0000000000..b138f8bea1 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tea.c @@ -0,0 +1,121 @@ +/* + * A 32-bit implementation of the TEA algorithm + * Copyright (c) 2015 Vesselin Bontchev + * + * Loosely based on the implementation of David Wheeler and Roger Needham, + * https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm#Reference_code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avutil.h" +#include "common.h" +#include "intreadwrite.h" +#include "tea.h" + +typedef struct AVTEA { + uint32_t key[16]; + int rounds; +} AVTEA; + +struct AVTEA *av_tea_alloc(void) +{ + return av_mallocz(sizeof(struct AVTEA)); +} + +const int av_tea_size = sizeof(AVTEA); + +void av_tea_init(AVTEA *ctx, const uint8_t key[16], int rounds) +{ + int i; + + for (i = 0; i < 4; i++) + ctx->key[i] = AV_RB32(key + (i << 2)); + + ctx->rounds = rounds; +} + +static void tea_crypt_ecb(AVTEA *ctx, uint8_t *dst, const uint8_t *src, + int decrypt, uint8_t *iv) +{ + uint32_t v0, v1; + int rounds = ctx->rounds; + uint32_t k0, k1, k2, k3; + k0 = ctx->key[0]; + k1 = ctx->key[1]; + k2 = ctx->key[2]; + k3 = ctx->key[3]; + + v0 = AV_RB32(src); + v1 = AV_RB32(src + 4); + + if (decrypt) { + int i; + uint32_t delta = 0x9E3779B9U, sum = delta * (rounds / 2); + + for (i = 0; i < rounds / 2; i++) { + v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3); + v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1); + sum -= delta; + } + if (iv) { + v0 ^= AV_RB32(iv); + v1 ^= AV_RB32(iv + 4); + memcpy(iv, src, 8); + } + } else { + int i; + uint32_t sum = 0, delta = 0x9E3779B9U; + + for (i = 0; i < rounds / 2; i++) { + sum += delta; + v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1); + v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3); + } + } + + AV_WB32(dst, v0); + AV_WB32(dst + 4, v1); +} + +void av_tea_crypt(AVTEA *ctx, uint8_t *dst, const uint8_t *src, int count, + uint8_t *iv, int decrypt) +{ + int i; + + if (decrypt) { + while (count--) { + tea_crypt_ecb(ctx, dst, src, decrypt, iv); + + src += 8; + dst += 8; + } + } else { + while (count--) { + if (iv) { + for (i = 0; i < 8; i++) + dst[i] = src[i] ^ iv[i]; + tea_crypt_ecb(ctx, dst, dst, decrypt, NULL); + memcpy(iv, dst, 8); + } else { + tea_crypt_ecb(ctx, dst, src, decrypt, NULL); + } + src += 8; + dst += 8; + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tea.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tea.h new file mode 100644 index 0000000000..dd929bdafd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tea.h @@ -0,0 +1,71 @@ +/* + * A 32-bit implementation of the TEA algorithm + * Copyright (c) 2015 Vesselin Bontchev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TEA_H +#define AVUTIL_TEA_H + +#include + +/** + * @file + * @brief Public header for libavutil TEA algorithm + * @defgroup lavu_tea TEA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_tea_size; + +struct AVTEA; + +/** + * Allocate an AVTEA context + * To free the struct: av_free(ptr) + */ +struct AVTEA *av_tea_alloc(void); + +/** + * Initialize an AVTEA context. + * + * @param ctx an AVTEA context + * @param key a key of 16 bytes used for encryption/decryption + * @param rounds the number of rounds in TEA (64 is the "standard") + */ +void av_tea_init(struct AVTEA *ctx, const uint8_t key[16], int rounds); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_tea_crypt(struct AVTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_TEA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/thread.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/thread.h new file mode 100644 index 0000000000..cc5272d379 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/thread.h @@ -0,0 +1,173 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// This header should only be used to simplify code where +// threading is optional, not as a generic threading abstraction. + +#ifndef AVUTIL_THREAD_H +#define AVUTIL_THREAD_H + +#include "config.h" + +#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS + +#if HAVE_PTHREADS +#include + +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 + +#include "log.h" + +#define ASSERT_PTHREAD_NORET(func, ...) do { \ + int ret = func(__VA_ARGS__); \ + if (ret) { \ + char errbuf[AV_ERROR_MAX_STRING_SIZE] = ""; \ + av_log(NULL, AV_LOG_FATAL, AV_STRINGIFY(func) \ + " failed with error: %s\n", \ + av_make_error_string(errbuf, AV_ERROR_MAX_STRING_SIZE, \ + AVERROR(ret))); \ + abort(); \ + } \ +} while (0) + +#define ASSERT_PTHREAD(func, ...) do { \ + ASSERT_PTHREAD_NORET(func, __VA_ARGS__); \ + return 0; \ +} while (0) + +static inline int strict_pthread_join(pthread_t thread, void **value_ptr) +{ + ASSERT_PTHREAD(pthread_join, thread, value_ptr); +} + +static inline int strict_pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) +{ + if (attr) { + ASSERT_PTHREAD_NORET(pthread_mutex_init, mutex, attr); + } else { + pthread_mutexattr_t local_attr; + ASSERT_PTHREAD_NORET(pthread_mutexattr_init, &local_attr); + ASSERT_PTHREAD_NORET(pthread_mutexattr_settype, &local_attr, PTHREAD_MUTEX_ERRORCHECK); + ASSERT_PTHREAD_NORET(pthread_mutex_init, mutex, &local_attr); + ASSERT_PTHREAD_NORET(pthread_mutexattr_destroy, &local_attr); + } + return 0; +} + +static inline int strict_pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + ASSERT_PTHREAD(pthread_mutex_destroy, mutex); +} + +static inline int strict_pthread_mutex_lock(pthread_mutex_t *mutex) +{ + ASSERT_PTHREAD(pthread_mutex_lock, mutex); +} + +static inline int strict_pthread_mutex_unlock(pthread_mutex_t *mutex) +{ + ASSERT_PTHREAD(pthread_mutex_unlock, mutex); +} + +static inline int strict_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) +{ + ASSERT_PTHREAD(pthread_cond_init, cond, attr); +} + +static inline int strict_pthread_cond_destroy(pthread_cond_t *cond) +{ + ASSERT_PTHREAD(pthread_cond_destroy, cond); +} + +static inline int strict_pthread_cond_signal(pthread_cond_t *cond) +{ + ASSERT_PTHREAD(pthread_cond_signal, cond); +} + +static inline int strict_pthread_cond_broadcast(pthread_cond_t *cond) +{ + ASSERT_PTHREAD(pthread_cond_broadcast, cond); +} + +static inline int strict_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + ASSERT_PTHREAD(pthread_cond_wait, cond, mutex); +} + +static inline int strict_pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + ASSERT_PTHREAD(pthread_once, once_control, init_routine); +} + +#define pthread_join strict_pthread_join +#define pthread_mutex_init strict_pthread_mutex_init +#define pthread_mutex_destroy strict_pthread_mutex_destroy +#define pthread_mutex_lock strict_pthread_mutex_lock +#define pthread_mutex_unlock strict_pthread_mutex_unlock +#define pthread_cond_init strict_pthread_cond_init +#define pthread_cond_destroy strict_pthread_cond_destroy +#define pthread_cond_signal strict_pthread_cond_signal +#define pthread_cond_broadcast strict_pthread_cond_broadcast +#define pthread_cond_wait strict_pthread_cond_wait +#define pthread_once strict_pthread_once +#endif + +#elif HAVE_OS2THREADS +#include "compat/os2threads.h" +#else +#include "compat/w32pthreads.h" +#endif + +#define AVMutex pthread_mutex_t +#define AV_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + +#define ff_mutex_init pthread_mutex_init +#define ff_mutex_lock pthread_mutex_lock +#define ff_mutex_unlock pthread_mutex_unlock +#define ff_mutex_destroy pthread_mutex_destroy + +#define AVOnce pthread_once_t +#define AV_ONCE_INIT PTHREAD_ONCE_INIT + +#define ff_thread_once(control, routine) pthread_once(control, routine) + +#else + +#define AVMutex char +#define AV_MUTEX_INITIALIZER 0 + +static inline int ff_mutex_init(AVMutex *mutex, const void *attr){ return 0; } +static inline int ff_mutex_lock(AVMutex *mutex){ return 0; } +static inline int ff_mutex_unlock(AVMutex *mutex){ return 0; } +static inline int ff_mutex_destroy(AVMutex *mutex){ return 0; } + +#define AVOnce char +#define AV_ONCE_INIT 0 + +static inline int ff_thread_once(char *control, void (*routine)(void)) +{ + if (!*control) { + routine(); + *control = 1; + } + return 0; +} + +#endif + +#endif /* AVUTIL_THREAD_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/threadmessage.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/threadmessage.c new file mode 100644 index 0000000000..764b7fb813 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/threadmessage.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2014 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "fifo.h" +#include "threadmessage.h" +#include "thread.h" + +struct AVThreadMessageQueue { +#if HAVE_THREADS + AVFifoBuffer *fifo; + pthread_mutex_t lock; + pthread_cond_t cond_recv; + pthread_cond_t cond_send; + int err_send; + int err_recv; + unsigned elsize; + void (*free_func)(void *msg); +#else + int dummy; +#endif +}; + +int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, + unsigned nelem, + unsigned elsize) +{ +#if HAVE_THREADS + AVThreadMessageQueue *rmq; + int ret = 0; + + if (nelem > INT_MAX / elsize) + return AVERROR(EINVAL); + if (!(rmq = av_mallocz(sizeof(*rmq)))) + return AVERROR(ENOMEM); + if ((ret = pthread_mutex_init(&rmq->lock, NULL))) { + av_free(rmq); + return AVERROR(ret); + } + if ((ret = pthread_cond_init(&rmq->cond_recv, NULL))) { + pthread_mutex_destroy(&rmq->lock); + av_free(rmq); + return AVERROR(ret); + } + if ((ret = pthread_cond_init(&rmq->cond_send, NULL))) { + pthread_cond_destroy(&rmq->cond_recv); + pthread_mutex_destroy(&rmq->lock); + av_free(rmq); + return AVERROR(ret); + } + if (!(rmq->fifo = av_fifo_alloc(elsize * nelem))) { + pthread_cond_destroy(&rmq->cond_send); + pthread_cond_destroy(&rmq->cond_recv); + pthread_mutex_destroy(&rmq->lock); + av_free(rmq); + return AVERROR(ENOMEM); + } + rmq->elsize = elsize; + *mq = rmq; + return 0; +#else + *mq = NULL; + return AVERROR(ENOSYS); +#endif /* HAVE_THREADS */ +} + +void av_thread_message_queue_set_free_func(AVThreadMessageQueue *mq, + void (*free_func)(void *msg)) +{ +#if HAVE_THREADS + mq->free_func = free_func; +#endif +} + +void av_thread_message_queue_free(AVThreadMessageQueue **mq) +{ +#if HAVE_THREADS + if (*mq) { + av_thread_message_flush(*mq); + av_fifo_freep(&(*mq)->fifo); + pthread_cond_destroy(&(*mq)->cond_send); + pthread_cond_destroy(&(*mq)->cond_recv); + pthread_mutex_destroy(&(*mq)->lock); + av_freep(mq); + } +#endif +} + +int av_thread_message_queue_nb_elems(AVThreadMessageQueue *mq) +{ +#if HAVE_THREADS + int ret; + pthread_mutex_lock(&mq->lock); + ret = av_fifo_size(mq->fifo); + pthread_mutex_unlock(&mq->lock); + return ret / mq->elsize; +#else + return AVERROR(ENOSYS); +#endif +} + +#if HAVE_THREADS + +static int av_thread_message_queue_send_locked(AVThreadMessageQueue *mq, + void *msg, + unsigned flags) +{ + while (!mq->err_send && av_fifo_space(mq->fifo) < mq->elsize) { + if ((flags & AV_THREAD_MESSAGE_NONBLOCK)) + return AVERROR(EAGAIN); + pthread_cond_wait(&mq->cond_send, &mq->lock); + } + if (mq->err_send) + return mq->err_send; + av_fifo_generic_write(mq->fifo, msg, mq->elsize, NULL); + /* one message is sent, signal one receiver */ + pthread_cond_signal(&mq->cond_recv); + return 0; +} + +static int av_thread_message_queue_recv_locked(AVThreadMessageQueue *mq, + void *msg, + unsigned flags) +{ + while (!mq->err_recv && av_fifo_size(mq->fifo) < mq->elsize) { + if ((flags & AV_THREAD_MESSAGE_NONBLOCK)) + return AVERROR(EAGAIN); + pthread_cond_wait(&mq->cond_recv, &mq->lock); + } + if (av_fifo_size(mq->fifo) < mq->elsize) + return mq->err_recv; + av_fifo_generic_read(mq->fifo, msg, mq->elsize, NULL); + /* one message space appeared, signal one sender */ + pthread_cond_signal(&mq->cond_send); + return 0; +} + +#endif /* HAVE_THREADS */ + +int av_thread_message_queue_send(AVThreadMessageQueue *mq, + void *msg, + unsigned flags) +{ +#if HAVE_THREADS + int ret; + + pthread_mutex_lock(&mq->lock); + ret = av_thread_message_queue_send_locked(mq, msg, flags); + pthread_mutex_unlock(&mq->lock); + return ret; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_THREADS */ +} + +int av_thread_message_queue_recv(AVThreadMessageQueue *mq, + void *msg, + unsigned flags) +{ +#if HAVE_THREADS + int ret; + + pthread_mutex_lock(&mq->lock); + ret = av_thread_message_queue_recv_locked(mq, msg, flags); + pthread_mutex_unlock(&mq->lock); + return ret; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_THREADS */ +} + +void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, + int err) +{ +#if HAVE_THREADS + pthread_mutex_lock(&mq->lock); + mq->err_send = err; + pthread_cond_broadcast(&mq->cond_send); + pthread_mutex_unlock(&mq->lock); +#endif /* HAVE_THREADS */ +} + +void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, + int err) +{ +#if HAVE_THREADS + pthread_mutex_lock(&mq->lock); + mq->err_recv = err; + pthread_cond_broadcast(&mq->cond_recv); + pthread_mutex_unlock(&mq->lock); +#endif /* HAVE_THREADS */ +} + +#if HAVE_THREADS +static void free_func_wrap(void *arg, void *msg, int size) +{ + AVThreadMessageQueue *mq = arg; + mq->free_func(msg); +} +#endif + +void av_thread_message_flush(AVThreadMessageQueue *mq) +{ +#if HAVE_THREADS + int used, off; + void *free_func = mq->free_func; + + pthread_mutex_lock(&mq->lock); + used = av_fifo_size(mq->fifo); + if (free_func) + for (off = 0; off < used; off += mq->elsize) + av_fifo_generic_peek_at(mq->fifo, mq, off, mq->elsize, free_func_wrap); + av_fifo_drain(mq->fifo, used); + /* only the senders need to be notified since the queue is empty and there + * is nothing to read */ + pthread_cond_broadcast(&mq->cond_send); + pthread_mutex_unlock(&mq->lock); +#endif /* HAVE_THREADS */ +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/threadmessage.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/threadmessage.h new file mode 100644 index 0000000000..42ce655f36 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/threadmessage.h @@ -0,0 +1,115 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_THREADMESSAGE_H +#define AVUTIL_THREADMESSAGE_H + +typedef struct AVThreadMessageQueue AVThreadMessageQueue; + +typedef enum AVThreadMessageFlags { + + /** + * Perform non-blocking operation. + * If this flag is set, send and recv operations are non-blocking and + * return AVERROR(EAGAIN) immediately if they can not proceed. + */ + AV_THREAD_MESSAGE_NONBLOCK = 1, + +} AVThreadMessageFlags; + +/** + * Allocate a new message queue. + * + * @param mq pointer to the message queue + * @param nelem maximum number of elements in the queue + * @param elsize size of each element in the queue + * @return >=0 for success; <0 for error, in particular AVERROR(ENOSYS) if + * lavu was built without thread support + */ +int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, + unsigned nelem, + unsigned elsize); + +/** + * Free a message queue. + * + * The message queue must no longer be in use by another thread. + */ +void av_thread_message_queue_free(AVThreadMessageQueue **mq); + +/** + * Send a message on the queue. + */ +int av_thread_message_queue_send(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Receive a message from the queue. + */ +int av_thread_message_queue_recv(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Set the sending error code. + * + * If the error code is set to non-zero, av_thread_message_queue_send() will + * return it immediately. Conventional values, such as AVERROR_EOF or + * AVERROR(EAGAIN), can be used to cause the sending thread to stop or + * suspend its operation. + */ +void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, + int err); + +/** + * Set the receiving error code. + * + * If the error code is set to non-zero, av_thread_message_queue_recv() will + * return it immediately when there are no longer available messages. + * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used + * to cause the receiving thread to stop or suspend its operation. + */ +void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, + int err); + +/** + * Set the optional free message callback function which will be called if an + * operation is removing messages from the queue. + */ +void av_thread_message_queue_set_free_func(AVThreadMessageQueue *mq, + void (*free_func)(void *msg)); + +/** + * Return the current number of messages in the queue. + * + * @return the current number of messages or AVERROR(ENOSYS) if lavu was built + * without thread support + */ +int av_thread_message_queue_nb_elems(AVThreadMessageQueue *mq); + +/** + * Flush the message queue + * + * This function is mostly equivalent to reading and free-ing every message + * except that it will be done in a single operation (no lock/unlock between + * reads). + */ +void av_thread_message_flush(AVThreadMessageQueue *mq); + +#endif /* AVUTIL_THREADMESSAGE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time.c new file mode 100644 index 0000000000..afa6658aa6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2000-2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include +#include +#if HAVE_GETTIMEOFDAY +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_WINDOWS_H +#include +#endif + +#include "time.h" +#include "error.h" + +int64_t av_gettime(void) +{ +#if HAVE_GETTIMEOFDAY + struct timeval tv; + gettimeofday(&tv, NULL); + return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; +#elif HAVE_GETSYSTEMTIMEASFILETIME + FILETIME ft; + int64_t t; + GetSystemTimeAsFileTime(&ft); + t = (int64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime; + return t / 10 - 11644473600000000; /* Jan 1, 1601 */ +#else + return -1; +#endif +} + +int64_t av_gettime_relative(void) +{ +#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) +#ifdef __APPLE__ + if (clock_gettime) +#endif + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + } +#endif + return av_gettime() + 42 * 60 * 60 * INT64_C(1000000); +} + +int av_gettime_relative_is_monotonic(void) +{ +#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) +#ifdef __APPLE__ + if (!clock_gettime) + return 0; +#endif + return 1; +#else + return 0; +#endif +} + +int av_usleep(unsigned usec) +{ +#if HAVE_NANOSLEEP + struct timespec ts = { usec / 1000000, usec % 1000000 * 1000 }; + while (nanosleep(&ts, &ts) < 0 && errno == EINTR); + return 0; +#elif HAVE_USLEEP + return usleep(usec); +#elif HAVE_SLEEP + Sleep(usec / 1000); + return 0; +#else + return AVERROR(ENOSYS); +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time.h new file mode 100644 index 0000000000..dc169b064a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000-2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TIME_H +#define AVUTIL_TIME_H + +#include + +/** + * Get the current time in microseconds. + */ +int64_t av_gettime(void); + +/** + * Get the current time in microseconds since some unspecified starting point. + * On platforms that support it, the time comes from a monotonic clock + * This property makes this time source ideal for measuring relative time. + * The returned values may not be monotonic on platforms where a monotonic + * clock is not available. + */ +int64_t av_gettime_relative(void); + +/** + * Indicates with a boolean result if the av_gettime_relative() time source + * is monotonic. + */ +int av_gettime_relative_is_monotonic(void); + +/** + * Sleep for a period of time. Although the duration is expressed in + * microseconds, the actual delay may be rounded to the precision of the + * system timer. + * + * @param usec Number of microseconds to sleep. + * @return zero on success or (negative) error code. + */ +int av_usleep(unsigned usec); + +#endif /* AVUTIL_TIME_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time_internal.h new file mode 100644 index 0000000000..d0f007ab1c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/time_internal.h @@ -0,0 +1,49 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TIME_INTERNAL_H +#define AVUTIL_TIME_INTERNAL_H + +#include +#include "config.h" + +#if !HAVE_GMTIME_R && !defined(gmtime_r) +static inline struct tm *ff_gmtime_r(const time_t* clock, struct tm *result) +{ + struct tm *ptr = gmtime(clock); + if (!ptr) + return NULL; + *result = *ptr; + return result; +} +#define gmtime_r ff_gmtime_r +#endif + +#if !HAVE_LOCALTIME_R && !defined(localtime_r) +static inline struct tm *ff_localtime_r(const time_t* clock, struct tm *result) +{ + struct tm *ptr = localtime(clock); + if (!ptr) + return NULL; + *result = *ptr; + return result; +} +#define localtime_r ff_localtime_r +#endif + +#endif /* AVUTIL_TIME_INTERNAL_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timecode.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timecode.c new file mode 100644 index 0000000000..60077ba0c0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timecode.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier + * Copyright (c) 2011-2012 Smartjog S.A.S, Cl茅ment B艙sch + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Timecode helpers + * @see https://en.wikipedia.org/wiki/SMPTE_time_code + * @see http://www.dropframetimecode.org + */ + +#include +#include "timecode.h" +#include "log.h" +#include "error.h" + +int av_timecode_adjust_ntsc_framenum2(int framenum, int fps) +{ + /* only works for NTSC 29.97 and 59.94 */ + int drop_frames = 0; + int d, m, frames_per_10mins; + + if (fps == 30) { + drop_frames = 2; + frames_per_10mins = 17982; + } else if (fps == 60) { + drop_frames = 4; + frames_per_10mins = 35964; + } else + return framenum; + + d = framenum / frames_per_10mins; + m = framenum % frames_per_10mins; + + return framenum + 9 * drop_frames * d + drop_frames * ((m - drop_frames) / (frames_per_10mins / 10)); +} + +uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum) +{ + unsigned fps = tc->fps; + int drop = !!(tc->flags & AV_TIMECODE_FLAG_DROPFRAME); + int hh, mm, ss, ff; + + framenum += tc->start; + if (drop) + framenum = av_timecode_adjust_ntsc_framenum2(framenum, tc->fps); + ff = framenum % fps; + ss = framenum / fps % 60; + mm = framenum / (fps*60) % 60; + hh = framenum / (fps*3600) % 24; + return 0 << 31 | // color frame flag (0: unsync mode, 1: sync mode) + drop << 30 | // drop frame flag (0: non drop, 1: drop) + (ff / 10) << 28 | // tens of frames + (ff % 10) << 24 | // units of frames + 0 << 23 | // PC (NTSC) or BGF0 (PAL) + (ss / 10) << 20 | // tens of seconds + (ss % 10) << 16 | // units of seconds + 0 << 15 | // BGF0 (NTSC) or BGF2 (PAL) + (mm / 10) << 12 | // tens of minutes + (mm % 10) << 8 | // units of minutes + 0 << 7 | // BGF2 (NTSC) or PC (PAL) + 0 << 6 | // BGF1 + (hh / 10) << 4 | // tens of hours + (hh % 10); // units of hours +} + +char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum) +{ + int fps = tc->fps; + int drop = tc->flags & AV_TIMECODE_FLAG_DROPFRAME; + int hh, mm, ss, ff, neg = 0; + + framenum += tc->start; + if (drop) + framenum = av_timecode_adjust_ntsc_framenum2(framenum, fps); + if (framenum < 0) { + framenum = -framenum; + neg = tc->flags & AV_TIMECODE_FLAG_ALLOWNEGATIVE; + } + ff = framenum % fps; + ss = framenum / fps % 60; + mm = framenum / (fps*60) % 60; + hh = framenum / (fps*3600); + if (tc->flags & AV_TIMECODE_FLAG_24HOURSMAX) + hh = hh % 24; + snprintf(buf, AV_TIMECODE_STR_SIZE, "%s%02d:%02d:%02d%c%02d", + neg ? "-" : "", + hh, mm, ss, drop ? ';' : ':', ff); + return buf; +} + +static unsigned bcd2uint(uint8_t bcd) +{ + unsigned low = bcd & 0xf; + unsigned high = bcd >> 4; + if (low > 9 || high > 9) + return 0; + return low + 10*high; +} + +char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df) +{ + unsigned hh = bcd2uint(tcsmpte & 0x3f); // 6-bit hours + unsigned mm = bcd2uint(tcsmpte>>8 & 0x7f); // 7-bit minutes + unsigned ss = bcd2uint(tcsmpte>>16 & 0x7f); // 7-bit seconds + unsigned ff = bcd2uint(tcsmpte>>24 & 0x3f); // 6-bit frames + unsigned drop = tcsmpte & 1<<30 && !prevent_df; // 1-bit drop if not arbitrary bit + snprintf(buf, AV_TIMECODE_STR_SIZE, "%02u:%02u:%02u%c%02u", + hh, mm, ss, drop ? ';' : ':', ff); + return buf; +} + +char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit) +{ + snprintf(buf, AV_TIMECODE_STR_SIZE, + "%02"PRIu32":%02"PRIu32":%02"PRIu32"%c%02"PRIu32, + tc25bit>>19 & 0x1f, // 5-bit hours + tc25bit>>13 & 0x3f, // 6-bit minutes + tc25bit>>6 & 0x3f, // 6-bit seconds + tc25bit & 1<<24 ? ';' : ':', // 1-bit drop flag + tc25bit & 0x3f); // 6-bit frames + return buf; +} + +static int check_fps(int fps) +{ + int i; + static const int supported_fps[] = { + 24, 25, 30, 48, 50, 60, 100, 120, 150, + }; + + for (i = 0; i < FF_ARRAY_ELEMS(supported_fps); i++) + if (fps == supported_fps[i]) + return 0; + return -1; +} + +static int check_timecode(void *log_ctx, AVTimecode *tc) +{ + if ((int)tc->fps <= 0) { + av_log(log_ctx, AV_LOG_ERROR, "Valid timecode frame rate must be specified. Minimum value is 1\n"); + return AVERROR(EINVAL); + } + if ((tc->flags & AV_TIMECODE_FLAG_DROPFRAME) && tc->fps != 30 && tc->fps != 60) { + av_log(log_ctx, AV_LOG_ERROR, "Drop frame is only allowed with 30000/1001 or 60000/1001 FPS\n"); + return AVERROR(EINVAL); + } + if (check_fps(tc->fps) < 0) { + av_log(log_ctx, AV_LOG_WARNING, "Using non-standard frame rate %d/%d\n", + tc->rate.num, tc->rate.den); + } + return 0; +} + +static int fps_from_frame_rate(AVRational rate) +{ + if (!rate.den || !rate.num) + return -1; + return (rate.num + rate.den/2) / rate.den; +} + +int av_timecode_check_frame_rate(AVRational rate) +{ + return check_fps(fps_from_frame_rate(rate)); +} + +int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx) +{ + memset(tc, 0, sizeof(*tc)); + tc->start = frame_start; + tc->flags = flags; + tc->rate = rate; + tc->fps = fps_from_frame_rate(rate); + return check_timecode(log_ctx, tc); +} + +int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx) +{ + char c; + int hh, mm, ss, ff, ret; + + if (sscanf(str, "%d:%d:%d%c%d", &hh, &mm, &ss, &c, &ff) != 5) { + av_log(log_ctx, AV_LOG_ERROR, "Unable to parse timecode, " + "syntax: hh:mm:ss[:;.]ff\n"); + return AVERROR_INVALIDDATA; + } + + memset(tc, 0, sizeof(*tc)); + tc->flags = c != ':' ? AV_TIMECODE_FLAG_DROPFRAME : 0; // drop if ';', '.', ... + tc->rate = rate; + tc->fps = fps_from_frame_rate(rate); + + ret = check_timecode(log_ctx, tc); + if (ret < 0) + return ret; + + tc->start = (hh*3600 + mm*60 + ss) * tc->fps + ff; + if (tc->flags & AV_TIMECODE_FLAG_DROPFRAME) { /* adjust frame number */ + int tmins = 60*hh + mm; + tc->start -= (tc->fps == 30 ? 2 : 4) * (tmins - tmins/10); + } + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timecode.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timecode.h new file mode 100644 index 0000000000..37c1361bc2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timecode.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier + * Copyright (c) 2011-2012 Smartjog S.A.S, Cl茅ment B艙sch + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Timecode helpers header + */ + +#ifndef AVUTIL_TIMECODE_H +#define AVUTIL_TIMECODE_H + +#include +#include "rational.h" + +#define AV_TIMECODE_STR_SIZE 23 + +enum AVTimecodeFlag { + AV_TIMECODE_FLAG_DROPFRAME = 1<<0, ///< timecode is drop frame + AV_TIMECODE_FLAG_24HOURSMAX = 1<<1, ///< timecode wraps after 24 hours + AV_TIMECODE_FLAG_ALLOWNEGATIVE = 1<<2, ///< negative time values are allowed +}; + +typedef struct { + int start; ///< timecode frame start (first base frame number) + uint32_t flags; ///< flags such as drop frame, +24 hours support, ... + AVRational rate; ///< frame rate in rational form + unsigned fps; ///< frame per second; must be consistent with the rate field +} AVTimecode; + +/** + * Adjust frame number for NTSC drop frame time code. + * + * @param framenum frame number to adjust + * @param fps frame per second, 30 or 60 + * @return adjusted frame number + * @warning adjustment is only valid in NTSC 29.97 and 59.94 + */ +int av_timecode_adjust_ntsc_framenum2(int framenum, int fps); + +/** + * Convert frame number to SMPTE 12M binary representation. + * + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the SMPTE binary representation + * + * @note Frame number adjustment is automatically done in case of drop timecode, + * you do NOT have to call av_timecode_adjust_ntsc_framenum2(). + * @note The frame number is relative to tc->start. + * @note Color frame (CF), binary group flags (BGF) and biphase mark polarity + * correction (PC) bits are set to zero. + */ +uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum); + +/** + * Load timecode string in buf. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the buf parameter + * + * @note Timecode representation can be a negative timecode and have more than + * 24 hours, but will only be honored if the flags are correctly set. + * @note The frame number is relative to tc->start. + */ +char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum); + +/** + * Get the timecode string from the SMPTE timecode format. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tcsmpte the 32-bit SMPTE timecode + * @param prevent_df prevent the use of a drop flag when it is known the DF bit + * is arbitrary + * @return the buf parameter + */ +char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df); + +/** + * Get the timecode string from the 25-bit timecode format (MPEG GOP format). + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc25bit the 25-bits timecode + * @return the buf parameter + */ +char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit); + +/** + * Init a timecode struct with the passed parameters. + * + * @param log_ctx a pointer to an arbitrary struct of which the first field + * is a pointer to an AVClass struct (used for av_log) + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param flags miscellaneous flags such as drop frame, +24 hours, ... + * (see AVTimecodeFlag) + * @param frame_start the first frame number + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx); + +/** + * Parse timecode representation (hh:mm:ss[:;.]ff). + * + * @param log_ctx a pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct (used for av_log). + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param str timecode string which will determine the frame start + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx); + +/** + * Check if the timecode feature is available for the given frame rate + * + * @return 0 if supported, <0 otherwise + */ +int av_timecode_check_frame_rate(AVRational rate); + +#endif /* AVUTIL_TIMECODE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timer.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timer.h new file mode 100644 index 0000000000..0bb353cfce --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timer.h @@ -0,0 +1,141 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * high precision timer, useful to profile code + */ + +#ifndef AVUTIL_TIMER_H +#define AVUTIL_TIMER_H + +#include "config.h" + +#if CONFIG_LINUX_PERF +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# include // read(3) +# include +# include +# include +#endif + +#include +#include +#include + +#if HAVE_MACH_ABSOLUTE_TIME +#include +#endif + +#include "log.h" + +#if ARCH_AARCH64 +# include "aarch64/timer.h" +#elif ARCH_ARM +# include "arm/timer.h" +#elif ARCH_PPC +# include "ppc/timer.h" +#elif ARCH_X86 +# include "x86/timer.h" +#endif + +#if !defined(AV_READ_TIME) +# if HAVE_GETHRTIME +# define AV_READ_TIME gethrtime +# elif HAVE_MACH_ABSOLUTE_TIME +# define AV_READ_TIME mach_absolute_time +# endif +#endif + +#ifndef FF_TIMER_UNITS +# define FF_TIMER_UNITS "UNITS" +#endif + +#define TIMER_REPORT(id, tdiff) \ + { \ + static uint64_t tsum = 0; \ + static int tcount = 0; \ + static int tskip_count = 0; \ + static int thistogram[32] = {0}; \ + thistogram[av_log2(tdiff)]++; \ + if (tcount < 2 || \ + (tdiff) < 8 * tsum / tcount || \ + (tdiff) < 2000) { \ + tsum += (tdiff); \ + tcount++; \ + } else \ + tskip_count++; \ + if (((tcount + tskip_count) & (tcount + tskip_count - 1)) == 0) { \ + int i; \ + av_log(NULL, AV_LOG_ERROR, \ + "%7"PRIu64" " FF_TIMER_UNITS " in %s,%8d runs,%7d skips", \ + tsum * 10 / tcount, id, tcount, tskip_count); \ + for (i = 0; i < 32; i++) \ + av_log(NULL, AV_LOG_VERBOSE, " %2d", av_log2(2*thistogram[i]));\ + av_log(NULL, AV_LOG_ERROR, "\n"); \ + } \ + } + +#if CONFIG_LINUX_PERF + +#define START_TIMER \ + static int linux_perf_fd; \ + uint64_t tperf; \ + if (!linux_perf_fd) { \ + struct perf_event_attr attr = { \ + .type = PERF_TYPE_HARDWARE, \ + .size = sizeof(struct perf_event_attr), \ + .config = PERF_COUNT_HW_CPU_CYCLES, \ + .disabled = 1, \ + .exclude_kernel = 1, \ + .exclude_hv = 1, \ + }; \ + linux_perf_fd = syscall(__NR_perf_event_open, &attr, \ + 0, -1, -1, 0); \ + } \ + if (linux_perf_fd == -1) { \ + av_log(NULL, AV_LOG_ERROR, "perf_event_open failed: %s\n", \ + av_err2str(AVERROR(errno))); \ + } else { \ + ioctl(linux_perf_fd, PERF_EVENT_IOC_RESET, 0); \ + ioctl(linux_perf_fd, PERF_EVENT_IOC_ENABLE, 0); \ + } + +#define STOP_TIMER(id) \ + ioctl(linux_perf_fd, PERF_EVENT_IOC_DISABLE, 0); \ + read(linux_perf_fd, &tperf, sizeof(tperf)); \ + TIMER_REPORT(id, tperf) + +#elif defined(AV_READ_TIME) +#define START_TIMER \ + uint64_t tend; \ + uint64_t tstart = AV_READ_TIME(); \ + +#define STOP_TIMER(id) \ + tend = AV_READ_TIME(); \ + TIMER_REPORT(id, tend - tstart) +#else +#define START_TIMER +#define STOP_TIMER(id) { } +#endif + +#endif /* AVUTIL_TIMER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timestamp.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timestamp.h new file mode 100644 index 0000000000..e082f01b40 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/timestamp.h @@ -0,0 +1,78 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * timestamp utils, mostly useful for debugging/logging purposes + */ + +#ifndef AVUTIL_TIMESTAMP_H +#define AVUTIL_TIMESTAMP_H + +#include "common.h" + +#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) && !defined(PRId64) +#error missing -D__STDC_FORMAT_MACROS / #define __STDC_FORMAT_MACROS +#endif + +#define AV_TS_MAX_STRING_SIZE 32 + +/** + * Fill the provided buffer with a string containing a timestamp + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @return the buffer in input + */ +static inline char *av_ts_make_string(char *buf, int64_t ts) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%" PRId64, ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts) + +/** + * Fill the provided buffer with a string containing a timestamp time + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @param tb the timebase of the timestamp + * @return the buffer in input + */ +static inline char *av_ts_make_time_string(char *buf, int64_t ts, AVRational *tb) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%.6g", av_q2d(*tb) * ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2timestr(ts, tb) av_ts_make_time_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts, tb) + +#endif /* AVUTIL_TIMESTAMP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tree.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tree.c new file mode 100644 index 0000000000..7b57b2d39a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tree.c @@ -0,0 +1,168 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "error.h" +#include "log.h" +#include "mem.h" +#include "tree.h" + +typedef struct AVTreeNode { + struct AVTreeNode *child[2]; + void *elem; + int state; +} AVTreeNode; + +const int av_tree_node_size = sizeof(AVTreeNode); + +struct AVTreeNode *av_tree_node_alloc(void) +{ + return av_mallocz(sizeof(struct AVTreeNode)); +} + +void *av_tree_find(const AVTreeNode *t, void *key, + int (*cmp)(const void *key, const void *b), void *next[2]) +{ + if (t) { + unsigned int v = cmp(key, t->elem); + if (v) { + if (next) + next[v >> 31] = t->elem; + return av_tree_find(t->child[(v >> 31) ^ 1], key, cmp, next); + } else { + if (next) { + av_tree_find(t->child[0], key, cmp, next); + av_tree_find(t->child[1], key, cmp, next); + } + return t->elem; + } + } + return NULL; +} + +void *av_tree_insert(AVTreeNode **tp, void *key, + int (*cmp)(const void *key, const void *b), AVTreeNode **next) +{ + AVTreeNode *t = *tp; + if (t) { + unsigned int v = cmp(t->elem, key); + void *ret; + if (!v) { + if (*next) + return t->elem; + else if (t->child[0] || t->child[1]) { + int i = !t->child[0]; + void *next_elem[2]; + av_tree_find(t->child[i], key, cmp, next_elem); + key = t->elem = next_elem[i]; + v = -i; + } else { + *next = t; + *tp = NULL; + return NULL; + } + } + ret = av_tree_insert(&t->child[v >> 31], key, cmp, next); + if (!ret) { + int i = (v >> 31) ^ !!*next; + AVTreeNode **child = &t->child[i]; + t->state += 2 * i - 1; + + if (!(t->state & 1)) { + if (t->state) { + /* The following code is equivalent to + * if ((*child)->state * 2 == -t->state) + * rotate(child, i ^ 1); + * rotate(tp, i); + * + * with rotate(): + * static void rotate(AVTreeNode **tp, int i) + * { + * AVTreeNode *t= *tp; + * + * *tp = t->child[i]; + * t->child[i] = t->child[i]->child[i ^ 1]; + * (*tp)->child[i ^ 1] = t; + * i = 4 * t->state + 2 * (*tp)->state + 12; + * t->state = ((0x614586 >> i) & 3) - 1; + * (*tp)->state = ((0x400EEA >> i) & 3) - 1 + + * ((*tp)->state >> 1); + * } + * but such a rotate function is both bigger and slower + */ + if ((*child)->state * 2 == -t->state) { + *tp = (*child)->child[i ^ 1]; + (*child)->child[i ^ 1] = (*tp)->child[i]; + (*tp)->child[i] = *child; + *child = (*tp)->child[i ^ 1]; + (*tp)->child[i ^ 1] = t; + + (*tp)->child[0]->state = -((*tp)->state > 0); + (*tp)->child[1]->state = (*tp)->state < 0; + (*tp)->state = 0; + } else { + *tp = *child; + *child = (*child)->child[i ^ 1]; + (*tp)->child[i ^ 1] = t; + if ((*tp)->state) + t->state = 0; + else + t->state >>= 1; + (*tp)->state = -t->state; + } + } + } + if (!(*tp)->state ^ !!*next) + return key; + } + return ret; + } else { + *tp = *next; + *next = NULL; + if (*tp) { + (*tp)->elem = key; + return NULL; + } else + return key; + } +} + +void av_tree_destroy(AVTreeNode *t) +{ + if (t) { + av_tree_destroy(t->child[0]); + av_tree_destroy(t->child[1]); + av_free(t); + } +} + +void av_tree_enumerate(AVTreeNode *t, void *opaque, + int (*cmp)(void *opaque, void *elem), + int (*enu)(void *opaque, void *elem)) +{ + if (t) { + int v = cmp ? cmp(opaque, t->elem) : 0; + if (v >= 0) + av_tree_enumerate(t->child[0], opaque, cmp, enu); + if (v == 0) + enu(opaque, t->elem); + if (v <= 0) + av_tree_enumerate(t->child[1], opaque, cmp, enu); + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tree.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tree.h new file mode 100644 index 0000000000..d5e0aebfbd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tree.h @@ -0,0 +1,138 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * A tree container. + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_TREE_H +#define AVUTIL_TREE_H + +#include "attributes.h" +#include "version.h" + +/** + * @addtogroup lavu_tree AVTree + * @ingroup lavu_data + * + * Low-complexity tree container + * + * Insertion, removal, finding equal, largest which is smaller than and + * smallest which is larger than, all have O(log n) worst-case complexity. + * @{ + */ + + +struct AVTreeNode; +extern const int av_tree_node_size; + +/** + * Allocate an AVTreeNode. + */ +struct AVTreeNode *av_tree_node_alloc(void); + +/** + * Find an element. + * @param root a pointer to the root node of the tree + * @param next If next is not NULL, then next[0] will contain the previous + * element and next[1] the next element. If either does not exist, + * then the corresponding entry in next is unchanged. + * @param cmp compare function used to compare elements in the tree, + * API identical to that of Standard C's qsort + * It is guaranteed that the first and only the first argument to cmp() + * will be the key parameter to av_tree_find(), thus it could if the + * user wants, be a different type (like an opaque context). + * @return An element with cmp(key, elem) == 0 or NULL if no such element + * exists in the tree. + */ +void *av_tree_find(const struct AVTreeNode *root, void *key, + int (*cmp)(const void *key, const void *b), void *next[2]); + +/** + * Insert or remove an element. + * + * If *next is NULL, then the supplied element will be removed if it exists. + * If *next is non-NULL, then the supplied element will be inserted, unless + * it already exists in the tree. + * + * @param rootp A pointer to a pointer to the root node of the tree; note that + * the root node can change during insertions, this is required + * to keep the tree balanced. + * @param key pointer to the element key to insert in the tree + * @param next Used to allocate and free AVTreeNodes. For insertion the user + * must set it to an allocated and zeroed object of at least + * av_tree_node_size bytes size. av_tree_insert() will set it to + * NULL if it has been consumed. + * For deleting elements *next is set to NULL by the user and + * av_tree_insert() will set it to the AVTreeNode which was + * used for the removed element. + * This allows the use of flat arrays, which have + * lower overhead compared to many malloced elements. + * You might want to define a function like: + * @code + * void *tree_insert(struct AVTreeNode **rootp, void *key, + * int (*cmp)(void *key, const void *b), + * AVTreeNode **next) + * { + * if (!*next) + * *next = av_mallocz(av_tree_node_size); + * return av_tree_insert(rootp, key, cmp, next); + * } + * void *tree_remove(struct AVTreeNode **rootp, void *key, + * int (*cmp)(void *key, const void *b, AVTreeNode **next)) + * { + * av_freep(next); + * return av_tree_insert(rootp, key, cmp, next); + * } + * @endcode + * @param cmp compare function used to compare elements in the tree, API identical + * to that of Standard C's qsort + * @return If no insertion happened, the found element; if an insertion or + * removal happened, then either key or NULL will be returned. + * Which one it is depends on the tree state and the implementation. You + * should make no assumptions that it's one or the other in the code. + */ +void *av_tree_insert(struct AVTreeNode **rootp, void *key, + int (*cmp)(const void *key, const void *b), + struct AVTreeNode **next); + +void av_tree_destroy(struct AVTreeNode *t); + +/** + * Apply enu(opaque, &elem) to all the elements in the tree in a given range. + * + * @param cmp a comparison function that returns < 0 for an element below the + * range, > 0 for an element above the range and == 0 for an + * element inside the range + * + * @note The cmp function should use the same ordering used to construct the + * tree. + */ +void av_tree_enumerate(struct AVTreeNode *t, void *opaque, + int (*cmp)(void *opaque, void *elem), + int (*enu)(void *opaque, void *elem)); + +/** + * @} + */ + +#endif /* AVUTIL_TREE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/twofish.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/twofish.c new file mode 100644 index 0000000000..d84fa4f363 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/twofish.c @@ -0,0 +1,331 @@ +/* + * An implementation of the TwoFish algorithm + * Copyright (c) 2015 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "twofish.h" +#include "common.h" +#include "intreadwrite.h" +#include "attributes.h" + +#define LR(x, n) ((x) << (n) | (x) >> (32 - (n))) +#define RR(x, n) ((x) >> (n) | (x) << (32 - (n))) + +typedef struct AVTWOFISH { + uint32_t K[40]; + uint32_t S[4]; + int ksize; + uint32_t MDS1[256]; + uint32_t MDS2[256]; + uint32_t MDS3[256]; + uint32_t MDS4[256]; +} AVTWOFISH; + +static const uint8_t MD1[256] = { + 0x00, 0x5b, 0xb6, 0xed, 0x05, 0x5e, 0xb3, 0xe8, 0x0a, 0x51, 0xbc, 0xe7, 0x0f, 0x54, 0xb9, 0xe2, + 0x14, 0x4f, 0xa2, 0xf9, 0x11, 0x4a, 0xa7, 0xfc, 0x1e, 0x45, 0xa8, 0xf3, 0x1b, 0x40, 0xad, 0xf6, + 0x28, 0x73, 0x9e, 0xc5, 0x2d, 0x76, 0x9b, 0xc0, 0x22, 0x79, 0x94, 0xcf, 0x27, 0x7c, 0x91, 0xca, + 0x3c, 0x67, 0x8a, 0xd1, 0x39, 0x62, 0x8f, 0xd4, 0x36, 0x6d, 0x80, 0xdb, 0x33, 0x68, 0x85, 0xde, + 0x50, 0x0b, 0xe6, 0xbd, 0x55, 0x0e, 0xe3, 0xb8, 0x5a, 0x01, 0xec, 0xb7, 0x5f, 0x04, 0xe9, 0xb2, + 0x44, 0x1f, 0xf2, 0xa9, 0x41, 0x1a, 0xf7, 0xac, 0x4e, 0x15, 0xf8, 0xa3, 0x4b, 0x10, 0xfd, 0xa6, + 0x78, 0x23, 0xce, 0x95, 0x7d, 0x26, 0xcb, 0x90, 0x72, 0x29, 0xc4, 0x9f, 0x77, 0x2c, 0xc1, 0x9a, + 0x6c, 0x37, 0xda, 0x81, 0x69, 0x32, 0xdf, 0x84, 0x66, 0x3d, 0xd0, 0x8b, 0x63, 0x38, 0xd5, 0x8e, + 0xa0, 0xfb, 0x16, 0x4d, 0xa5, 0xfe, 0x13, 0x48, 0xaa, 0xf1, 0x1c, 0x47, 0xaf, 0xf4, 0x19, 0x42, + 0xb4, 0xef, 0x02, 0x59, 0xb1, 0xea, 0x07, 0x5c, 0xbe, 0xe5, 0x08, 0x53, 0xbb, 0xe0, 0x0d, 0x56, + 0x88, 0xd3, 0x3e, 0x65, 0x8d, 0xd6, 0x3b, 0x60, 0x82, 0xd9, 0x34, 0x6f, 0x87, 0xdc, 0x31, 0x6a, + 0x9c, 0xc7, 0x2a, 0x71, 0x99, 0xc2, 0x2f, 0x74, 0x96, 0xcd, 0x20, 0x7b, 0x93, 0xc8, 0x25, 0x7e, + 0xf0, 0xab, 0x46, 0x1d, 0xf5, 0xae, 0x43, 0x18, 0xfa, 0xa1, 0x4c, 0x17, 0xff, 0xa4, 0x49, 0x12, + 0xe4, 0xbf, 0x52, 0x09, 0xe1, 0xba, 0x57, 0x0c, 0xee, 0xb5, 0x58, 0x03, 0xeb, 0xb0, 0x5d, 0x06, + 0xd8, 0x83, 0x6e, 0x35, 0xdd, 0x86, 0x6b, 0x30, 0xd2, 0x89, 0x64, 0x3f, 0xd7, 0x8c, 0x61, 0x3a, + 0xcc, 0x97, 0x7a, 0x21, 0xc9, 0x92, 0x7f, 0x24, 0xc6, 0x9d, 0x70, 0x2b, 0xc3, 0x98, 0x75, 0x2e +}; + +static const uint8_t MD2[256] = { + 0x00, 0xef, 0xb7, 0x58, 0x07, 0xe8, 0xb0, 0x5f, 0x0e, 0xe1, 0xb9, 0x56, 0x09, 0xe6, 0xbe, 0x51, + 0x1c, 0xf3, 0xab, 0x44, 0x1b, 0xf4, 0xac, 0x43, 0x12, 0xfd, 0xa5, 0x4a, 0x15, 0xfa, 0xa2, 0x4d, + 0x38, 0xd7, 0x8f, 0x60, 0x3f, 0xd0, 0x88, 0x67, 0x36, 0xd9, 0x81, 0x6e, 0x31, 0xde, 0x86, 0x69, + 0x24, 0xcb, 0x93, 0x7c, 0x23, 0xcc, 0x94, 0x7b, 0x2a, 0xc5, 0x9d, 0x72, 0x2d, 0xc2, 0x9a, 0x75, + 0x70, 0x9f, 0xc7, 0x28, 0x77, 0x98, 0xc0, 0x2f, 0x7e, 0x91, 0xc9, 0x26, 0x79, 0x96, 0xce, 0x21, + 0x6c, 0x83, 0xdb, 0x34, 0x6b, 0x84, 0xdc, 0x33, 0x62, 0x8d, 0xd5, 0x3a, 0x65, 0x8a, 0xd2, 0x3d, + 0x48, 0xa7, 0xff, 0x10, 0x4f, 0xa0, 0xf8, 0x17, 0x46, 0xa9, 0xf1, 0x1e, 0x41, 0xae, 0xf6, 0x19, + 0x54, 0xbb, 0xe3, 0x0c, 0x53, 0xbc, 0xe4, 0x0b, 0x5a, 0xb5, 0xed, 0x02, 0x5d, 0xb2, 0xea, 0x05, + 0xe0, 0x0f, 0x57, 0xb8, 0xe7, 0x08, 0x50, 0xbf, 0xee, 0x01, 0x59, 0xb6, 0xe9, 0x06, 0x5e, 0xb1, + 0xfc, 0x13, 0x4b, 0xa4, 0xfb, 0x14, 0x4c, 0xa3, 0xf2, 0x1d, 0x45, 0xaa, 0xf5, 0x1a, 0x42, 0xad, + 0xd8, 0x37, 0x6f, 0x80, 0xdf, 0x30, 0x68, 0x87, 0xd6, 0x39, 0x61, 0x8e, 0xd1, 0x3e, 0x66, 0x89, + 0xc4, 0x2b, 0x73, 0x9c, 0xc3, 0x2c, 0x74, 0x9b, 0xca, 0x25, 0x7d, 0x92, 0xcd, 0x22, 0x7a, 0x95, + 0x90, 0x7f, 0x27, 0xc8, 0x97, 0x78, 0x20, 0xcf, 0x9e, 0x71, 0x29, 0xc6, 0x99, 0x76, 0x2e, 0xc1, + 0x8c, 0x63, 0x3b, 0xd4, 0x8b, 0x64, 0x3c, 0xd3, 0x82, 0x6d, 0x35, 0xda, 0x85, 0x6a, 0x32, 0xdd, + 0xa8, 0x47, 0x1f, 0xf0, 0xaf, 0x40, 0x18, 0xf7, 0xa6, 0x49, 0x11, 0xfe, 0xa1, 0x4e, 0x16, 0xf9, + 0xb4, 0x5b, 0x03, 0xec, 0xb3, 0x5c, 0x04, 0xeb, 0xba, 0x55, 0x0d, 0xe2, 0xbd, 0x52, 0x0a, 0xe5 +}; + +static const uint8_t q0[256] = { + 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38, + 0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48, + 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82, + 0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61, + 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1, + 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7, + 0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71, + 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7, + 0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90, + 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef, + 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64, + 0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a, + 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d, + 0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, + 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4, + 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0 +}; + +static const uint8_t q1[256] = { + 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b, + 0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f, + 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5, + 0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51, + 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c, + 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8, + 0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2, + 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17, + 0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e, + 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9, + 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48, + 0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64, + 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69, + 0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc, + 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9, + 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91 +}; + +struct AVTWOFISH *av_twofish_alloc(void) +{ + return av_mallocz(sizeof(struct AVTWOFISH)); +} + +const int av_twofish_size = sizeof(AVTWOFISH); + +static uint8_t gfmul(uint8_t a, uint8_t b) +{ + uint8_t r = 0, t; + while (a && b) { + if (a & 1) + r = r ^ b; + t = b & 0x80; + b = b << 1; + if (t) + b = b ^ 0x4d; + a = a >> 1; + } + return r; +} + +static uint32_t tf_RS(uint32_t k0, uint32_t k1) +{ + uint8_t s[4], m[8]; + AV_WL32(m, k0); + AV_WL32(m + 4, k1); + s[0] = gfmul(0x01, m[0]) ^ gfmul(0xa4, m[1]) ^ gfmul(0x55, m[2]) ^ gfmul(0x87, m[3]) ^ gfmul(0x5a, m[4]) ^ gfmul(0x58, m[5]) ^ gfmul(0xdb, m[6]) ^ gfmul(0x9e, m[7]); + s[1] = gfmul(0xa4, m[0]) ^ gfmul(0x56, m[1]) ^ gfmul(0x82, m[2]) ^ gfmul(0xf3, m[3]) ^ gfmul(0x1e, m[4]) ^ gfmul(0xc6, m[5]) ^ gfmul(0x68, m[6]) ^ gfmul(0xe5, m[7]); + s[2] = gfmul(0x02, m[0]) ^ gfmul(0xa1, m[1]) ^ gfmul(0xfc, m[2]) ^ gfmul(0xc1, m[3]) ^ gfmul(0x47, m[4]) ^ gfmul(0xae, m[5]) ^ gfmul(0x3d, m[6]) ^ gfmul(0x19, m[7]); + s[3] = gfmul(0xa4, m[0]) ^ gfmul(0x55, m[1]) ^ gfmul(0x87, m[2]) ^ gfmul(0x5a, m[3]) ^ gfmul(0x58, m[4]) ^ gfmul(0xdb, m[5]) ^ gfmul(0x9e, m[6]) ^ gfmul(0x03, m[7]); + return AV_RL32(s); +} + +static void tf_h0(uint8_t y[4], uint32_t L[4], int k) +{ + uint8_t l[4]; + if (k == 4) { + AV_WL32(l, L[3]); + y[0] = q1[y[0]] ^ l[0]; + y[1] = q0[y[1]] ^ l[1]; + y[2] = q0[y[2]] ^ l[2]; + y[3] = q1[y[3]] ^ l[3]; + } + if (k >= 3) { + AV_WL32(l, L[2]); + y[0] = q1[y[0]] ^ l[0]; + y[1] = q1[y[1]] ^ l[1]; + y[2] = q0[y[2]] ^ l[2]; + y[3] = q0[y[3]] ^ l[3]; + } + AV_WL32(l, L[1]); + y[0] = q1[q0[q0[y[0]] ^ l[0]] ^ (L[0] & 0xff)]; + y[1] = q0[q0[q1[y[1]] ^ l[1]] ^ ((L[0] >> 8) & 0xff)]; + y[2] = q1[q1[q0[y[2]] ^ l[2]] ^ ((L[0] >> 16) & 0xff)]; + y[3] = q0[q1[q1[y[3]] ^ l[3]] ^ (L[0] >> 24)]; +} + +static uint32_t tf_h(uint32_t X, uint32_t L[4], int k) +{ + uint8_t y[4], l[4]; + AV_WL32(y, X); + tf_h0(y, L, k); + + l[0] = y[0] ^ MD2[y[1]] ^ MD1[y[2]] ^ MD1[y[3]]; + l[1] = MD1[y[0]] ^ MD2[y[1]] ^ MD2[y[2]] ^ y[3]; + l[2] = MD2[y[0]] ^ MD1[y[1]] ^ y[2] ^ MD2[y[3]]; + l[3] = MD2[y[0]] ^ y[1] ^ MD2[y[2]] ^ MD1[y[3]]; + + return AV_RL32(l); +} + +static uint32_t MDS_mul(AVTWOFISH *cs, uint32_t X) +{ + return cs->MDS1[(X) & 0xff] ^ cs->MDS2[((X) >> 8) & 0xff] ^ cs->MDS3[((X) >> 16) & 0xff] ^ cs->MDS4[(X) >> 24]; +} + +static void precomputeMDS(AVTWOFISH *cs) +{ + uint8_t y[4]; + int i; + for (i = 0; i < 256; i++) { + y[0] = y[1] = y[2] = y[3] = i; + tf_h0(y, cs->S, cs->ksize); + cs->MDS1[i] = ((uint32_t)y[0]) ^ ((uint32_t)MD1[y[0]] << 8) ^ ((uint32_t)MD2[y[0]] << 16) ^ ((uint32_t)MD2[y[0]] << 24); + cs->MDS2[i] = ((uint32_t)MD2[y[1]]) ^ ((uint32_t)MD2[y[1]] << 8) ^ ((uint32_t)MD1[y[1]] << 16) ^ ((uint32_t)y[1] << 24); + cs->MDS3[i] = ((uint32_t)MD1[y[2]]) ^ ((uint32_t)MD2[y[2]] << 8) ^ ((uint32_t)y[2] << 16) ^ ((uint32_t)MD2[y[2]] << 24); + cs->MDS4[i] = ((uint32_t)MD1[y[3]]) ^ ((uint32_t)y[3] << 8) ^ ((uint32_t)MD2[y[3]] << 16) ^ ((uint32_t)MD1[y[3]] << 24); + } +} + +static void twofish_encrypt(AVTWOFISH *cs, uint8_t *dst, const uint8_t *src) +{ + uint32_t P[4], t0, t1; + int i; + P[0] = AV_RL32(src) ^ cs->K[0]; + P[1] = AV_RL32(src + 4) ^ cs->K[1]; + P[2] = AV_RL32(src + 8) ^ cs->K[2]; + P[3] = AV_RL32(src + 12) ^ cs->K[3]; + for (i = 0; i < 16; i += 2) { + t0 = MDS_mul(cs, P[0]); + t1 = MDS_mul(cs, LR(P[1], 8)); + P[2] = RR(P[2] ^ (t0 + t1 + cs->K[2 * i + 8]), 1); + P[3] = LR(P[3], 1) ^ (t0 + 2 * t1 + cs->K[2 * i + 9]); + t0 = MDS_mul(cs, P[2]); + t1 = MDS_mul(cs, LR(P[3], 8)); + P[0] = RR(P[0] ^ (t0 + t1 + cs->K[2 * i + 10]), 1); + P[1] = LR(P[1], 1) ^ (t0 + 2 * t1 + cs->K[2 * i + 11]); + } + P[2] ^= cs->K[4]; + P[3] ^= cs->K[5]; + P[0] ^= cs->K[6]; + P[1] ^= cs->K[7]; + AV_WL32(dst, P[2]); + AV_WL32(dst + 4, P[3]); + AV_WL32(dst + 8, P[0]); + AV_WL32(dst + 12, P[1]); +} + +static void twofish_decrypt(AVTWOFISH *cs, uint8_t *dst, const uint8_t *src, uint8_t *iv) +{ + uint32_t P[4], t0, t1; + int i; + P[2] = AV_RL32(src) ^ cs->K[4]; + P[3] = AV_RL32(src + 4) ^ cs->K[5]; + P[0] = AV_RL32(src + 8) ^ cs->K[6]; + P[1] = AV_RL32(src + 12) ^ cs->K[7]; + for (i = 15; i >= 0; i -= 2) { + t0 = MDS_mul(cs, P[2]); + t1 = MDS_mul(cs, LR(P[3], 8)); + P[0] = LR(P[0], 1) ^ (t0 + t1 + cs->K[2 * i + 8]); + P[1] = RR(P[1] ^ (t0 + 2 * t1 + cs->K[2 * i + 9]), 1); + t0 = MDS_mul(cs, P[0]); + t1 = MDS_mul(cs, LR(P[1], 8)); + P[2] = LR(P[2], 1) ^ (t0 + t1 + cs->K[2 * i + 6]); + P[3] = RR(P[3] ^ (t0 + 2 * t1 + cs->K[2 * i + 7]), 1); + } + P[0] ^= cs->K[0]; + P[1] ^= cs->K[1]; + P[2] ^= cs->K[2]; + P[3] ^= cs->K[3]; + if (iv) { + P[0] ^= AV_RL32(iv); + P[1] ^= AV_RL32(iv + 4); + P[2] ^= AV_RL32(iv + 8); + P[3] ^= AV_RL32(iv + 12); + memcpy(iv, src, 16); + } + AV_WL32(dst, P[2]); + AV_WL32(dst + 4, P[3]); + AV_WL32(dst + 8, P[0]); + AV_WL32(dst + 12, P[1]); +} + +av_cold int av_twofish_init(AVTWOFISH *cs, const uint8_t *key, int key_bits) +{ + int i; + uint8_t keypad[32]; + uint32_t Key[8], Me[4], Mo[4], A, B; + const uint32_t rho = 0x01010101; + if (key_bits < 0) + return AVERROR(EINVAL); + if (key_bits <= 128) { + cs->ksize = 2; + } else if (key_bits <= 192) { + cs->ksize = 3; + } else { + cs->ksize = 4; + } + memset(keypad, 0, sizeof(keypad)); + if (key_bits <= 256) { + memcpy(keypad, key, key_bits >> 3); + } else { + memcpy(keypad, key, 32); + } + for (i = 0; i < 2 * cs->ksize ; i++) + Key[i] = AV_RL32(keypad + 4 * i); + for (i = 0; i < cs->ksize; i++) { + Me[i] = Key[2 * i]; + Mo[i] = Key[2 * i + 1]; + cs->S[cs->ksize - i - 1] = tf_RS(Me[i], Mo[i]); + } + precomputeMDS(cs); + for (i = 0; i < 20; i++) { + A = tf_h((2 * i) * rho, Me, cs->ksize); + B = tf_h((2 * i + 1) * rho, Mo, cs->ksize); + B = LR(B, 8); + cs->K[2 * i] = A + B; + cs->K[2 * i + 1] = LR((A + (2 * B)), 9); + } + if (cs->ksize << 6 != key_bits) { + return 1; + } else { + return 0; + } +} + +void av_twofish_crypt(AVTWOFISH *cs, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt) +{ + int i; + while (count--) { + if (decrypt) { + twofish_decrypt(cs, dst, src, iv); + } else { + if (iv) { + for (i = 0; i < 16; i++) + dst[i] = src[i] ^ iv[i]; + twofish_encrypt(cs, dst, dst); + memcpy(iv, dst, 16); + } else { + twofish_encrypt(cs, dst, src); + } + } + src = src + 16; + dst = dst + 16; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/twofish.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/twofish.h new file mode 100644 index 0000000000..813cfecdf8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/twofish.h @@ -0,0 +1,70 @@ +/* + * An implementation of the TwoFish algorithm + * Copyright (c) 2015 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TWOFISH_H +#define AVUTIL_TWOFISH_H + +#include + + +/** + * @file + * @brief Public header for libavutil TWOFISH algorithm + * @defgroup lavu_twofish TWOFISH + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_twofish_size; + +struct AVTWOFISH; + +/** + * Allocate an AVTWOFISH context + * To free the struct: av_free(ptr) + */ +struct AVTWOFISH *av_twofish_alloc(void); + +/** + * Initialize an AVTWOFISH context. + * + * @param ctx an AVTWOFISH context + * @param key a key of size ranging from 1 to 32 bytes used for encryption/decryption + * @param key_bits number of keybits: 128, 192, 256 If less than the required, padded with zeroes to nearest valid value; return value is 0 if key_bits is 128/192/256, -1 if less than 0, 1 otherwise + */ +int av_twofish_init(struct AVTWOFISH *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVTWOFISH context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 16 byte blocks + * @paran iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_twofish_crypt(struct AVTWOFISH *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t* iv, int decrypt); + +/** + * @} + */ +#endif /* AVUTIL_TWOFISH_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tx.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tx.c new file mode 100644 index 0000000000..93f6e489d3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tx.c @@ -0,0 +1,803 @@ +/* + * Copyright (c) 2019 Lynne + * Power of two FFT: + * Copyright (c) 2008 Loren Merritt + * Copyright (c) 2002 Fabrice Bellard + * Partly based on libdjbfft by D. J. Bernstein + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "tx.h" +#include "thread.h" +#include "mem.h" +#include "avassert.h" + +typedef float FFTSample; +typedef AVComplexFloat FFTComplex; + +struct AVTXContext { + int n; /* Nptwo part */ + int m; /* Ptwo part */ + + FFTComplex *exptab; /* MDCT exptab */ + FFTComplex *tmp; /* Temporary buffer needed for all compound transforms */ + int *pfatab; /* Input/Output mapping for compound transforms */ + int *revtab; /* Input mapping for power of two transforms */ +}; + +#define FFT_NAME(x) x + +#define COSTABLE(size) \ + static DECLARE_ALIGNED(32, FFTSample, FFT_NAME(ff_cos_##size))[size/2] + +static FFTSample * const FFT_NAME(ff_cos_tabs)[18]; + +COSTABLE(16); +COSTABLE(32); +COSTABLE(64); +COSTABLE(128); +COSTABLE(256); +COSTABLE(512); +COSTABLE(1024); +COSTABLE(2048); +COSTABLE(4096); +COSTABLE(8192); +COSTABLE(16384); +COSTABLE(32768); +COSTABLE(65536); +COSTABLE(131072); + +static av_cold void init_ff_cos_tabs(int index) +{ + int m = 1 << index; + double freq = 2*M_PI/m; + FFTSample *tab = FFT_NAME(ff_cos_tabs)[index]; + for(int i = 0; i <= m/4; i++) + tab[i] = cos(i*freq); + for(int i = 1; i < m/4; i++) + tab[m/2 - i] = tab[i]; +} + +typedef struct CosTabsInitOnce { + void (*func)(void); + AVOnce control; +} CosTabsInitOnce; + +#define INIT_FF_COS_TABS_FUNC(index, size) \ +static av_cold void init_ff_cos_tabs_ ## size (void) \ +{ \ + init_ff_cos_tabs(index); \ +} + +INIT_FF_COS_TABS_FUNC(4, 16) +INIT_FF_COS_TABS_FUNC(5, 32) +INIT_FF_COS_TABS_FUNC(6, 64) +INIT_FF_COS_TABS_FUNC(7, 128) +INIT_FF_COS_TABS_FUNC(8, 256) +INIT_FF_COS_TABS_FUNC(9, 512) +INIT_FF_COS_TABS_FUNC(10, 1024) +INIT_FF_COS_TABS_FUNC(11, 2048) +INIT_FF_COS_TABS_FUNC(12, 4096) +INIT_FF_COS_TABS_FUNC(13, 8192) +INIT_FF_COS_TABS_FUNC(14, 16384) +INIT_FF_COS_TABS_FUNC(15, 32768) +INIT_FF_COS_TABS_FUNC(16, 65536) +INIT_FF_COS_TABS_FUNC(17, 131072) + +static CosTabsInitOnce cos_tabs_init_once[] = { + { NULL }, + { NULL }, + { NULL }, + { NULL }, + { init_ff_cos_tabs_16, AV_ONCE_INIT }, + { init_ff_cos_tabs_32, AV_ONCE_INIT }, + { init_ff_cos_tabs_64, AV_ONCE_INIT }, + { init_ff_cos_tabs_128, AV_ONCE_INIT }, + { init_ff_cos_tabs_256, AV_ONCE_INIT }, + { init_ff_cos_tabs_512, AV_ONCE_INIT }, + { init_ff_cos_tabs_1024, AV_ONCE_INIT }, + { init_ff_cos_tabs_2048, AV_ONCE_INIT }, + { init_ff_cos_tabs_4096, AV_ONCE_INIT }, + { init_ff_cos_tabs_8192, AV_ONCE_INIT }, + { init_ff_cos_tabs_16384, AV_ONCE_INIT }, + { init_ff_cos_tabs_32768, AV_ONCE_INIT }, + { init_ff_cos_tabs_65536, AV_ONCE_INIT }, + { init_ff_cos_tabs_131072, AV_ONCE_INIT }, +}; + +static FFTSample * const FFT_NAME(ff_cos_tabs)[] = { + NULL, NULL, NULL, NULL, + FFT_NAME(ff_cos_16), + FFT_NAME(ff_cos_32), + FFT_NAME(ff_cos_64), + FFT_NAME(ff_cos_128), + FFT_NAME(ff_cos_256), + FFT_NAME(ff_cos_512), + FFT_NAME(ff_cos_1024), + FFT_NAME(ff_cos_2048), + FFT_NAME(ff_cos_4096), + FFT_NAME(ff_cos_8192), + FFT_NAME(ff_cos_16384), + FFT_NAME(ff_cos_32768), + FFT_NAME(ff_cos_65536), + FFT_NAME(ff_cos_131072), +}; + +static av_cold void ff_init_ff_cos_tabs(int index) +{ + ff_thread_once(&cos_tabs_init_once[index].control, + cos_tabs_init_once[index].func); +} + +static AVOnce tabs_53_once = AV_ONCE_INIT; +static DECLARE_ALIGNED(32, FFTComplex, FFT_NAME(ff_53_tabs))[4]; + +static av_cold void ff_init_53_tabs(void) +{ + ff_53_tabs[0] = (FFTComplex){ cos(2 * M_PI / 12), cos(2 * M_PI / 12) }; + ff_53_tabs[1] = (FFTComplex){ 0.5, 0.5 }; + ff_53_tabs[2] = (FFTComplex){ cos(2 * M_PI / 5), sin(2 * M_PI / 5) }; + ff_53_tabs[3] = (FFTComplex){ cos(2 * M_PI / 10), sin(2 * M_PI / 10) }; +} + +#define BF(x, y, a, b) do { \ + x = (a) - (b); \ + y = (a) + (b); \ + } while (0) + +#define CMUL(dre, dim, are, aim, bre, bim) do { \ + (dre) = (are) * (bre) - (aim) * (bim); \ + (dim) = (are) * (bim) + (aim) * (bre); \ + } while (0) + +#define CMUL3(c, a, b) CMUL((c).re, (c).im, (a).re, (a).im, (b).re, (b).im) + +static av_always_inline void fft3(FFTComplex *out, FFTComplex *in, + ptrdiff_t stride) +{ + FFTComplex tmp[2]; + + tmp[0].re = in[1].im - in[2].im; + tmp[0].im = in[1].re - in[2].re; + tmp[1].re = in[1].re + in[2].re; + tmp[1].im = in[1].im + in[2].im; + + out[0*stride].re = in[0].re + tmp[1].re; + out[0*stride].im = in[0].im + tmp[1].im; + + tmp[0].re *= ff_53_tabs[0].re; + tmp[0].im *= ff_53_tabs[0].im; + tmp[1].re *= ff_53_tabs[1].re; + tmp[1].im *= ff_53_tabs[1].re; + + out[1*stride].re = in[0].re - tmp[1].re + tmp[0].re; + out[1*stride].im = in[0].im - tmp[1].im - tmp[0].im; + out[2*stride].re = in[0].re - tmp[1].re - tmp[0].re; + out[2*stride].im = in[0].im - tmp[1].im + tmp[0].im; +} + +#define DECL_FFT5(NAME, D0, D1, D2, D3, D4) \ +static av_always_inline void NAME(FFTComplex *out, FFTComplex *in, \ + ptrdiff_t stride) \ +{ \ + FFTComplex z0[4], t[6]; \ + \ + t[0].re = in[1].re + in[4].re; \ + t[0].im = in[1].im + in[4].im; \ + t[1].im = in[1].re - in[4].re; \ + t[1].re = in[1].im - in[4].im; \ + t[2].re = in[2].re + in[3].re; \ + t[2].im = in[2].im + in[3].im; \ + t[3].im = in[2].re - in[3].re; \ + t[3].re = in[2].im - in[3].im; \ + \ + out[D0*stride].re = in[0].re + in[1].re + in[2].re + \ + in[3].re + in[4].re; \ + out[D0*stride].im = in[0].im + in[1].im + in[2].im + \ + in[3].im + in[4].im; \ + \ + t[4].re = ff_53_tabs[2].re * t[2].re - ff_53_tabs[3].re * t[0].re; \ + t[4].im = ff_53_tabs[2].re * t[2].im - ff_53_tabs[3].re * t[0].im; \ + t[0].re = ff_53_tabs[2].re * t[0].re - ff_53_tabs[3].re * t[2].re; \ + t[0].im = ff_53_tabs[2].re * t[0].im - ff_53_tabs[3].re * t[2].im; \ + t[5].re = ff_53_tabs[2].im * t[3].re - ff_53_tabs[3].im * t[1].re; \ + t[5].im = ff_53_tabs[2].im * t[3].im - ff_53_tabs[3].im * t[1].im; \ + t[1].re = ff_53_tabs[2].im * t[1].re + ff_53_tabs[3].im * t[3].re; \ + t[1].im = ff_53_tabs[2].im * t[1].im + ff_53_tabs[3].im * t[3].im; \ + \ + z0[0].re = t[0].re - t[1].re; \ + z0[0].im = t[0].im - t[1].im; \ + z0[1].re = t[4].re + t[5].re; \ + z0[1].im = t[4].im + t[5].im; \ + \ + z0[2].re = t[4].re - t[5].re; \ + z0[2].im = t[4].im - t[5].im; \ + z0[3].re = t[0].re + t[1].re; \ + z0[3].im = t[0].im + t[1].im; \ + \ + out[D1*stride].re = in[0].re + z0[3].re; \ + out[D1*stride].im = in[0].im + z0[0].im; \ + out[D2*stride].re = in[0].re + z0[2].re; \ + out[D2*stride].im = in[0].im + z0[1].im; \ + out[D3*stride].re = in[0].re + z0[1].re; \ + out[D3*stride].im = in[0].im + z0[2].im; \ + out[D4*stride].re = in[0].re + z0[0].re; \ + out[D4*stride].im = in[0].im + z0[3].im; \ +} + +DECL_FFT5(fft5, 0, 1, 2, 3, 4) +DECL_FFT5(fft5_m1, 0, 6, 12, 3, 9) +DECL_FFT5(fft5_m2, 10, 1, 7, 13, 4) +DECL_FFT5(fft5_m3, 5, 11, 2, 8, 14) + +static av_always_inline void fft15(FFTComplex *out, FFTComplex *in, + ptrdiff_t stride) +{ + FFTComplex tmp[15]; + + for (int i = 0; i < 5; i++) + fft3(tmp + i, in + i*3, 5); + + fft5_m1(out, tmp + 0, stride); + fft5_m2(out, tmp + 5, stride); + fft5_m3(out, tmp + 10, stride); +} + +#define BUTTERFLIES(a0,a1,a2,a3) {\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, a0.re, t5);\ + BF(a3.im, a1.im, a1.im, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, a1.re, t4);\ + BF(a2.im, a0.im, a0.im, t6);\ +} + +// force loading all the inputs before storing any. +// this is slightly slower for small data, but avoids store->load aliasing +// for addresses separated by large powers of 2. +#define BUTTERFLIES_BIG(a0,a1,a2,a3) {\ + FFTSample r0=a0.re, i0=a0.im, r1=a1.re, i1=a1.im;\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, r0, t5);\ + BF(a3.im, a1.im, i1, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, r1, t4);\ + BF(a2.im, a0.im, i0, t6);\ +} + +#define TRANSFORM(a0,a1,a2,a3,wre,wim) {\ + CMUL(t1, t2, a2.re, a2.im, wre, -wim);\ + CMUL(t5, t6, a3.re, a3.im, wre, wim);\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +#define TRANSFORM_ZERO(a0,a1,a2,a3) {\ + t1 = a2.re;\ + t2 = a2.im;\ + t5 = a3.re;\ + t6 = a3.im;\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +/* z[0...8n-1], w[1...2n-1] */ +#define PASS(name)\ +static void name(FFTComplex *z, const FFTSample *wre, unsigned int n)\ +{\ + FFTSample t1, t2, t3, t4, t5, t6;\ + int o1 = 2*n;\ + int o2 = 4*n;\ + int o3 = 6*n;\ + const FFTSample *wim = wre+o1;\ + n--;\ +\ + TRANSFORM_ZERO(z[0],z[o1],z[o2],z[o3]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + do {\ + z += 2;\ + wre += 2;\ + wim -= 2;\ + TRANSFORM(z[0],z[o1],z[o2],z[o3],wre[0],wim[0]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + } while(--n);\ +} + +PASS(pass) +#undef BUTTERFLIES +#define BUTTERFLIES BUTTERFLIES_BIG +PASS(pass_big) + +#define DECL_FFT(n,n2,n4)\ +static void fft##n(FFTComplex *z)\ +{\ + fft##n2(z);\ + fft##n4(z+n4*2);\ + fft##n4(z+n4*3);\ + pass(z,FFT_NAME(ff_cos_##n),n4/2);\ +} + +static void fft4(FFTComplex *z) +{ + FFTSample t1, t2, t3, t4, t5, t6, t7, t8; + + BF(t3, t1, z[0].re, z[1].re); + BF(t8, t6, z[3].re, z[2].re); + BF(z[2].re, z[0].re, t1, t6); + BF(t4, t2, z[0].im, z[1].im); + BF(t7, t5, z[2].im, z[3].im); + BF(z[3].im, z[1].im, t4, t8); + BF(z[3].re, z[1].re, t3, t7); + BF(z[2].im, z[0].im, t2, t5); +} + +static void fft8(FFTComplex *z) +{ + FFTSample t1, t2, t3, t4, t5, t6; + + fft4(z); + + BF(t1, z[5].re, z[4].re, -z[5].re); + BF(t2, z[5].im, z[4].im, -z[5].im); + BF(t5, z[7].re, z[6].re, -z[7].re); + BF(t6, z[7].im, z[6].im, -z[7].im); + + BUTTERFLIES(z[0],z[2],z[4],z[6]); + TRANSFORM(z[1],z[3],z[5],z[7],M_SQRT1_2,M_SQRT1_2); +} + +static void fft16(FFTComplex *z) +{ + FFTSample t1, t2, t3, t4, t5, t6; + FFTSample cos_16_1 = FFT_NAME(ff_cos_16)[1]; + FFTSample cos_16_3 = FFT_NAME(ff_cos_16)[3]; + + fft8(z); + fft4(z+8); + fft4(z+12); + + TRANSFORM_ZERO(z[0],z[4],z[8],z[12]); + TRANSFORM(z[2],z[6],z[10],z[14],M_SQRT1_2,M_SQRT1_2); + TRANSFORM(z[1],z[5],z[9],z[13],cos_16_1,cos_16_3); + TRANSFORM(z[3],z[7],z[11],z[15],cos_16_3,cos_16_1); +} + +DECL_FFT(32,16,8) +DECL_FFT(64,32,16) +DECL_FFT(128,64,32) +DECL_FFT(256,128,64) +DECL_FFT(512,256,128) +#define pass pass_big +DECL_FFT(1024,512,256) +DECL_FFT(2048,1024,512) +DECL_FFT(4096,2048,1024) +DECL_FFT(8192,4096,2048) +DECL_FFT(16384,8192,4096) +DECL_FFT(32768,16384,8192) +DECL_FFT(65536,32768,16384) +DECL_FFT(131072,65536,32768) + +static void (* const fft_dispatch[])(FFTComplex*) = { + fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024, + fft2048, fft4096, fft8192, fft16384, fft32768, fft65536, fft131072 +}; + +#define DECL_COMP_FFT(N) \ +static void compound_fft_##N##xM(AVTXContext *s, void *_out, \ + void *_in, ptrdiff_t stride) \ +{ \ + const int m = s->m, *in_map = s->pfatab, *out_map = in_map + N*m; \ + FFTComplex *in = _in; \ + FFTComplex *out = _out; \ + FFTComplex fft##N##in[N]; \ + void (*fftp)(FFTComplex *z) = fft_dispatch[av_log2(m) - 2]; \ + \ + for (int i = 0; i < m; i++) { \ + for (int j = 0; j < N; j++) \ + fft##N##in[j] = in[in_map[i*N + j]]; \ + fft##N(s->tmp + s->revtab[i], fft##N##in, m); \ + } \ + \ + for (int i = 0; i < N; i++) \ + fftp(s->tmp + m*i); \ + \ + for (int i = 0; i < N*m; i++) \ + out[i] = s->tmp[out_map[i]]; \ +} + +DECL_COMP_FFT(3) +DECL_COMP_FFT(5) +DECL_COMP_FFT(15) + +static void monolithic_fft(AVTXContext *s, void *_out, void *_in, + ptrdiff_t stride) +{ + FFTComplex *in = _in; + FFTComplex *out = _out; + int m = s->m, mb = av_log2(m) - 2; + for (int i = 0; i < m; i++) + out[s->revtab[i]] = in[i]; + fft_dispatch[mb](out); +} + +#define DECL_COMP_IMDCT(N) \ +static void compound_imdct_##N##xM(AVTXContext *s, void *_dst, void *_src, \ + ptrdiff_t stride) \ +{ \ + FFTComplex fft##N##in[N]; \ + FFTComplex *z = _dst, *exp = s->exptab; \ + const int m = s->m, len8 = N*m >> 1; \ + const int *in_map = s->pfatab, *out_map = in_map + N*m; \ + const float *src = _src, *in1, *in2; \ + void (*fftp)(FFTComplex *) = fft_dispatch[av_log2(m) - 2]; \ + \ + stride /= sizeof(*src); /* To convert it from bytes */ \ + in1 = src; \ + in2 = src + ((N*m*2) - 1) * stride; \ + \ + for (int i = 0; i < m; i++) { \ + for (int j = 0; j < N; j++) { \ + const int k = in_map[i*N + j]; \ + FFTComplex tmp = { in2[-k*stride], in1[k*stride] }; \ + CMUL3(fft##N##in[j], tmp, exp[k >> 1]); \ + } \ + fft##N(s->tmp + s->revtab[i], fft##N##in, m); \ + } \ + \ + for (int i = 0; i < N; i++) \ + fftp(s->tmp + m*i); \ + \ + for (int i = 0; i < len8; i++) { \ + const int i0 = len8 + i, i1 = len8 - i - 1; \ + const int s0 = out_map[i0], s1 = out_map[i1]; \ + FFTComplex src1 = { s->tmp[s1].im, s->tmp[s1].re }; \ + FFTComplex src0 = { s->tmp[s0].im, s->tmp[s0].re }; \ + \ + CMUL(z[i1].re, z[i0].im, src1.re, src1.im, exp[i1].im, exp[i1].re); \ + CMUL(z[i0].re, z[i1].im, src0.re, src0.im, exp[i0].im, exp[i0].re); \ + } \ +} + +DECL_COMP_IMDCT(3) +DECL_COMP_IMDCT(5) +DECL_COMP_IMDCT(15) + +#define DECL_COMP_MDCT(N) \ +static void compound_mdct_##N##xM(AVTXContext *s, void *_dst, void *_src, \ + ptrdiff_t stride) \ +{ \ + float *src = _src, *dst = _dst; \ + FFTComplex *exp = s->exptab, tmp, fft##N##in[N]; \ + const int m = s->m, len4 = N*m, len3 = len4 * 3, len8 = len4 >> 1; \ + const int *in_map = s->pfatab, *out_map = in_map + N*m; \ + void (*fftp)(FFTComplex *) = fft_dispatch[av_log2(m) - 2]; \ + \ + stride /= sizeof(*dst); \ + \ + for (int i = 0; i < m; i++) { /* Folding and pre-reindexing */ \ + for (int j = 0; j < N; j++) { \ + const int k = in_map[i*N + j]; \ + if (k < len4) { \ + tmp.re = -src[ len4 + k] + src[1*len4 - 1 - k]; \ + tmp.im = -src[ len3 + k] - src[1*len3 - 1 - k]; \ + } else { \ + tmp.re = -src[ len4 + k] - src[5*len4 - 1 - k]; \ + tmp.im = src[-len4 + k] - src[1*len3 - 1 - k]; \ + } \ + CMUL(fft##N##in[j].im, fft##N##in[j].re, tmp.re, tmp.im, \ + exp[k >> 1].re, exp[k >> 1].im); \ + } \ + fft##N(s->tmp + s->revtab[i], fft##N##in, m); \ + } \ + \ + for (int i = 0; i < N; i++) \ + fftp(s->tmp + m*i); \ + \ + for (int i = 0; i < len8; i++) { \ + const int i0 = len8 + i, i1 = len8 - i - 1; \ + const int s0 = out_map[i0], s1 = out_map[i1]; \ + FFTComplex src1 = { s->tmp[s1].re, s->tmp[s1].im }; \ + FFTComplex src0 = { s->tmp[s0].re, s->tmp[s0].im }; \ + \ + CMUL(dst[2*i1*stride + stride], dst[2*i0*stride], src0.re, src0.im, \ + exp[i0].im, exp[i0].re); \ + CMUL(dst[2*i0*stride + stride], dst[2*i1*stride], src1.re, src1.im, \ + exp[i1].im, exp[i1].re); \ + } \ +} + +DECL_COMP_MDCT(3) +DECL_COMP_MDCT(5) +DECL_COMP_MDCT(15) + +static void monolithic_imdct(AVTXContext *s, void *_dst, void *_src, + ptrdiff_t stride) +{ + FFTComplex *z = _dst, *exp = s->exptab; + const int m = s->m, len8 = m >> 1; + const float *src = _src, *in1, *in2; + void (*fftp)(FFTComplex *) = fft_dispatch[av_log2(m) - 2]; + + stride /= sizeof(*src); + in1 = src; + in2 = src + ((m*2) - 1) * stride; + + for (int i = 0; i < m; i++) { + FFTComplex tmp = { in2[-2*i*stride], in1[2*i*stride] }; + CMUL3(z[s->revtab[i]], tmp, exp[i]); + } + + fftp(z); + + for (int i = 0; i < len8; i++) { + const int i0 = len8 + i, i1 = len8 - i - 1; + FFTComplex src1 = { z[i1].im, z[i1].re }; + FFTComplex src0 = { z[i0].im, z[i0].re }; + + CMUL(z[i1].re, z[i0].im, src1.re, src1.im, exp[i1].im, exp[i1].re); + CMUL(z[i0].re, z[i1].im, src0.re, src0.im, exp[i0].im, exp[i0].re); + } +} + +static void monolithic_mdct(AVTXContext *s, void *_dst, void *_src, + ptrdiff_t stride) +{ + float *src = _src, *dst = _dst; + FFTComplex *exp = s->exptab, tmp, *z = _dst; + const int m = s->m, len4 = m, len3 = len4 * 3, len8 = len4 >> 1; + void (*fftp)(FFTComplex *) = fft_dispatch[av_log2(m) - 2]; + + stride /= sizeof(*dst); + + for (int i = 0; i < m; i++) { /* Folding and pre-reindexing */ + const int k = 2*i; + if (k < len4) { + tmp.re = -src[ len4 + k] + src[1*len4 - 1 - k]; + tmp.im = -src[ len3 + k] - src[1*len3 - 1 - k]; + } else { + tmp.re = -src[ len4 + k] - src[5*len4 - 1 - k]; + tmp.im = src[-len4 + k] - src[1*len3 - 1 - k]; + } + CMUL(z[s->revtab[i]].im, z[s->revtab[i]].re, tmp.re, tmp.im, + exp[i].re, exp[i].im); + } + + fftp(z); + + for (int i = 0; i < len8; i++) { + const int i0 = len8 + i, i1 = len8 - i - 1; + FFTComplex src1 = { z[i1].re, z[i1].im }; + FFTComplex src0 = { z[i0].re, z[i0].im }; + + CMUL(dst[2*i1*stride + stride], dst[2*i0*stride], src0.re, src0.im, + exp[i0].im, exp[i0].re); + CMUL(dst[2*i0*stride + stride], dst[2*i1*stride], src1.re, src1.im, + exp[i1].im, exp[i1].re); + } +} + +/* Calculates the modular multiplicative inverse, not fast, replace */ +static int mulinv(int n, int m) +{ + n = n % m; + for (int x = 1; x < m; x++) + if (((n * x) % m) == 1) + return x; + av_assert0(0); /* Never reached */ +} + +/* Guaranteed to work for any n, m where gcd(n, m) == 1 */ +static int gen_compound_mapping(AVTXContext *s, int n, int m, int inv, + enum AVTXType type) +{ + int *in_map, *out_map; + const int len = n*m; + const int m_inv = mulinv(m, n); + const int n_inv = mulinv(n, m); + const int mdct = type == AV_TX_FLOAT_MDCT; + + if (!(s->pfatab = av_malloc(2*len*sizeof(*s->pfatab)))) + return AVERROR(ENOMEM); + + in_map = s->pfatab; + out_map = s->pfatab + n*m; + + /* Ruritanian map for input, CRT map for output, can be swapped */ + for (int j = 0; j < m; j++) { + for (int i = 0; i < n; i++) { + /* Shifted by 1 to simplify forward MDCTs */ + in_map[j*n + i] = ((i*m + j*n) % len) << mdct; + out_map[(i*m*m_inv + j*n*n_inv) % len] = i*m + j; + } + } + + /* Change transform direction by reversing all ACs */ + if (inv) { + for (int i = 0; i < m; i++) { + int *in = &in_map[i*n + 1]; /* Skip the DC */ + for (int j = 0; j < ((n - 1) >> 1); j++) + FFSWAP(int, in[j], in[n - j - 2]); + } + } + + /* Our 15-point transform is also a compound one, so embed its input map */ + if (n == 15) { + for (int k = 0; k < m; k++) { + int tmp[15]; + memcpy(tmp, &in_map[k*15], 15*sizeof(*tmp)); + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 3; j++) + in_map[k*15 + i*3 + j] = tmp[(i*3 + j*5) % 15]; + } + } + } + + return 0; +} + +static int split_radix_permutation(int i, int n, int inverse) +{ + int m; + if (n <= 2) + return i & 1; + m = n >> 1; + if (!(i & m)) + return split_radix_permutation(i, m, inverse)*2; + m >>= 1; + if (inverse == !(i & m)) + return split_radix_permutation(i, m, inverse)*4 + 1; + else + return split_radix_permutation(i, m, inverse)*4 - 1; +} + +static int get_ptwo_revtab(AVTXContext *s, int m, int inv) +{ + if (!(s->revtab = av_malloc(m*sizeof(*s->revtab)))) + return AVERROR(ENOMEM); + + /* Default */ + for (int i = 0; i < m; i++) { + int k = -split_radix_permutation(i, m, inv) & (m - 1); + s->revtab[k] = i; + } + + return 0; +} + +static int gen_mdct_exptab(AVTXContext *s, int len4, double scale) +{ + const double theta = (scale < 0 ? len4 : 0) + 1.0/8.0; + + if (!(s->exptab = av_malloc_array(len4, sizeof(*s->exptab)))) + return AVERROR(ENOMEM); + + scale = sqrt(fabs(scale)); + for (int i = 0; i < len4; i++) { + const double alpha = M_PI_2 * (i + theta) / len4; + s->exptab[i].re = cos(alpha) * scale; + s->exptab[i].im = sin(alpha) * scale; + } + + return 0; +} + +av_cold void av_tx_uninit(AVTXContext **ctx) +{ + if (!(*ctx)) + return; + + av_free((*ctx)->pfatab); + av_free((*ctx)->exptab); + av_free((*ctx)->revtab); + av_free((*ctx)->tmp); + + av_freep(ctx); +} + +static int init_mdct_fft(AVTXContext *s, av_tx_fn *tx, enum AVTXType type, + int inv, int len, const void *scale, uint64_t flags) +{ + int err, n = 1, m = 1, max_ptwo = 1 << (FF_ARRAY_ELEMS(fft_dispatch) + 1); + + if (type == AV_TX_FLOAT_MDCT) + len >>= 1; + +#define CHECK_FACTOR(DST, FACTOR, SRC) \ + if (DST == 1 && !(SRC % FACTOR)) { \ + DST = FACTOR; \ + SRC /= FACTOR; \ + } + CHECK_FACTOR(n, 15, len) + CHECK_FACTOR(n, 5, len) + CHECK_FACTOR(n, 3, len) +#undef CHECK_NPTWO_FACTOR + + /* len must be a power of two now */ + if (!(len & (len - 1)) && len >= 4 && len <= max_ptwo) { + m = len; + len = 1; + } + + /* Filter out direct 3, 5 and 15 transforms, too niche */ + if (len > 1 || m == 1) { + av_log(NULL, AV_LOG_ERROR, "Unsupported transform size: n = %i, " + "m = %i, residual = %i!\n", n, m, len); + return AVERROR(EINVAL); + } else if (n > 1 && m > 1) { /* 2D transform case */ + if ((err = gen_compound_mapping(s, n, m, inv, type))) + return err; + if (!(s->tmp = av_malloc(n*m*sizeof(*s->tmp)))) + return AVERROR(ENOMEM); + *tx = n == 3 ? compound_fft_3xM : + n == 5 ? compound_fft_5xM : + compound_fft_15xM; + if (type == AV_TX_FLOAT_MDCT) + *tx = n == 3 ? inv ? compound_imdct_3xM : compound_mdct_3xM : + n == 5 ? inv ? compound_imdct_5xM : compound_mdct_5xM : + inv ? compound_imdct_15xM : compound_mdct_15xM; + } else { /* Direct transform case */ + *tx = monolithic_fft; + if (type == AV_TX_FLOAT_MDCT) + *tx = inv ? monolithic_imdct : monolithic_mdct; + } + + if (n != 1) + ff_thread_once(&tabs_53_once, ff_init_53_tabs); + if (m != 1) { + get_ptwo_revtab(s, m, inv); + for (int i = 4; i <= av_log2(m); i++) + ff_init_ff_cos_tabs(i); + } + + if (type == AV_TX_FLOAT_MDCT) + if ((err = gen_mdct_exptab(s, n*m, *((float *)scale)))) + return err; + + s->n = n; + s->m = m; + + return 0; +} + +av_cold int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, + int inv, int len, const void *scale, uint64_t flags) +{ + int err; + AVTXContext *s = av_mallocz(sizeof(*s)); + if (!s) + return AVERROR(ENOMEM); + + switch (type) { + case AV_TX_FLOAT_FFT: + case AV_TX_FLOAT_MDCT: + if ((err = init_mdct_fft(s, tx, type, inv, len, scale, flags))) + goto fail; + break; + default: + err = AVERROR(EINVAL); + goto fail; + } + + *ctx = s; + + return 0; + +fail: + av_tx_uninit(&s); + *tx = NULL; + return err; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tx.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tx.h new file mode 100644 index 0000000000..b1f2d96353 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/tx.h @@ -0,0 +1,81 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TX_H +#define AVUTIL_TX_H + +#include +#include + +typedef struct AVTXContext AVTXContext; + +typedef struct AVComplexFloat { + float re, im; +} AVComplexFloat; + +enum AVTXType { + /** + * Standard complex to complex FFT with sample data type AVComplexFloat. + * Scaling currently unsupported + */ + AV_TX_FLOAT_FFT = 0, + /** + * Standard MDCT with sample data type of float and a scale type of + * float. Length is the frame size, not the window size (which is 2x frame) + */ + AV_TX_FLOAT_MDCT = 1, +}; + +/** + * Function pointer to a function to perform the transform. + * + * @note Using a different context than the one allocated during av_tx_init() + * is not allowed. + * + * @param s the transform context + * @param out the output array + * @param in the input array + * @param stride the input or output stride (depending on transform direction) + * in bytes, currently implemented for all MDCT transforms + */ +typedef void (*av_tx_fn)(AVTXContext *s, void *out, void *in, ptrdiff_t stride); + +/** + * Initialize a transform context with the given configuration + * Currently power of two lengths from 4 to 131072 are supported, along with + * any length decomposable to a power of two and either 3, 5 or 15. + * + * @param ctx the context to allocate, will be NULL on error + * @param tx pointer to the transform function pointer to set + * @param type type the type of transform + * @param inv whether to do an inverse or a forward transform + * @param len the size of the transform in samples + * @param scale pointer to the value to scale the output if supported by type + * @param flags currently unused + * + * @return 0 on success, negative error code on failure + */ +int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, + int inv, int len, const void *scale, uint64_t flags); + +/** + * Frees a context and sets ctx to NULL, does nothing when ctx == NULL + */ +void av_tx_uninit(AVTXContext **ctx); + +#endif /* AVUTIL_TX_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/utils.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/utils.c new file mode 100644 index 0000000000..230081ea47 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/utils.c @@ -0,0 +1,160 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "avutil.h" +#include "avassert.h" +#include "samplefmt.h" +#include "internal.h" + +/** + * @file + * various utility functions + */ + +#include "libavutil/ffversion.h" +const char av_util_ffversion[] = "FFmpeg version " FFMPEG_VERSION; + +const char *av_version_info(void) +{ + return FFMPEG_VERSION; +} + +unsigned avutil_version(void) +{ + static int checks_done; + if (checks_done) + return LIBAVUTIL_VERSION_INT; + + av_assert0(AV_SAMPLE_FMT_DBLP == 9); + av_assert0(AVMEDIA_TYPE_ATTACHMENT == 4); + av_assert0(AV_PICTURE_TYPE_BI == 7); + av_assert0(LIBAVUTIL_VERSION_MICRO >= 100); + av_assert0(HAVE_MMX2 == HAVE_MMXEXT); + + av_assert0(((size_t)-1) > 0); // C guarantees this but if false on a platform we care about revert at least b284e1ffe343d6697fb950d1ee517bafda8a9844 + + if (av_sat_dadd32(1, 2) != 5) { + av_log(NULL, AV_LOG_FATAL, "Libavutil has been built with a broken binutils, please upgrade binutils and rebuild\n"); + abort(); + } + + if (llrint(1LL<<60) != 1LL<<60) { + av_log(NULL, AV_LOG_ERROR, "Libavutil has been linked to a broken llrint()\n"); + } + + checks_done = 1; + return LIBAVUTIL_VERSION_INT; +} + +const char *avutil_configuration(void) +{ + return FFMPEG_CONFIGURATION; +} + +const char *avutil_license(void) +{ +#define LICENSE_PREFIX "libavutil license: " + return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; +} + +const char *av_get_media_type_string(enum AVMediaType media_type) +{ + switch (media_type) { + case AVMEDIA_TYPE_VIDEO: return "video"; + case AVMEDIA_TYPE_AUDIO: return "audio"; + case AVMEDIA_TYPE_DATA: return "data"; + case AVMEDIA_TYPE_SUBTITLE: return "subtitle"; + case AVMEDIA_TYPE_ATTACHMENT: return "attachment"; + default: return NULL; + } +} + +char av_get_picture_type_char(enum AVPictureType pict_type) +{ + switch (pict_type) { + case AV_PICTURE_TYPE_I: return 'I'; + case AV_PICTURE_TYPE_P: return 'P'; + case AV_PICTURE_TYPE_B: return 'B'; + case AV_PICTURE_TYPE_S: return 'S'; + case AV_PICTURE_TYPE_SI: return 'i'; + case AV_PICTURE_TYPE_SP: return 'p'; + case AV_PICTURE_TYPE_BI: return 'b'; + default: return '?'; + } +} + +unsigned av_int_list_length_for_size(unsigned elsize, + const void *list, uint64_t term) +{ + unsigned i; + + if (!list) + return 0; +#define LIST_LENGTH(type) \ + { type t = term, *l = (type *)list; for (i = 0; l[i] != t; i++); } + switch (elsize) { + case 1: LIST_LENGTH(uint8_t); break; + case 2: LIST_LENGTH(uint16_t); break; + case 4: LIST_LENGTH(uint32_t); break; + case 8: LIST_LENGTH(uint64_t); break; + default: av_assert0(!"valid element size"); + } + return i; +} + +char *av_fourcc_make_string(char *buf, uint32_t fourcc) +{ + int i; + char *orig_buf = buf; + size_t buf_size = AV_FOURCC_MAX_STRING_SIZE; + + for (i = 0; i < 4; i++) { + const int c = fourcc & 0xff; + const int print_chr = (c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c && strchr(". -_", c)); + const int len = snprintf(buf, buf_size, print_chr ? "%c" : "[%d]", c); + if (len < 0) + break; + buf += len; + buf_size = buf_size > len ? buf_size - len : 0; + fourcc >>= 8; + } + + return orig_buf; +} + +AVRational av_get_time_base_q(void) +{ + return (AVRational){1, AV_TIME_BASE}; +} + +void av_assert0_fpu(void) { +#if HAVE_MMX_INLINE + uint16_t state[14]; + __asm__ volatile ( + "fstenv %0 \n\t" + : "+m" (state) + : + : "memory" + ); + av_assert0((state[4] & 3) == 3); +#endif +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/version.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/version.h new file mode 100644 index 0000000000..24ca8ab7db --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/version.h @@ -0,0 +1,139 @@ +/* + * copyright (c) 2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu + * Libavutil version macros + */ + +#ifndef AVUTIL_VERSION_H +#define AVUTIL_VERSION_H + +#include "macros.h" + +/** + * @addtogroup version_utils + * + * Useful to check and match library version in order to maintain + * backward compatibility. + * + * The FFmpeg libraries follow a versioning sheme very similar to + * Semantic Versioning (http://semver.org/) + * The difference is that the component called PATCH is called MICRO in FFmpeg + * and its value is reset to 100 instead of 0 to keep it above or equal to 100. + * Also we do not increase MICRO for every bugfix or change in git master. + * + * Prior to FFmpeg 3.2 point releases did not change any lib version number to + * avoid aliassing different git master checkouts. + * Starting with FFmpeg 3.2, the released library versions will occupy + * a separate MAJOR.MINOR that is not used on the master development branch. + * That is if we branch a release of master 55.10.123 we will bump to 55.11.100 + * for the release and master will continue at 55.12.100 after it. Each new + * point release will then bump the MICRO improving the usefulness of the lib + * versions. + * + * @{ + */ + +#define AV_VERSION_INT(a, b, c) ((a)<<16 | (b)<<8 | (c)) +#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c +#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c) + +/** + * Extract version components from the full ::AV_VERSION_INT int as returned + * by functions like ::avformat_version() and ::avcodec_version() + */ +#define AV_VERSION_MAJOR(a) ((a) >> 16) +#define AV_VERSION_MINOR(a) (((a) & 0x00FF00) >> 8) +#define AV_VERSION_MICRO(a) ((a) & 0xFF) + +/** + * @} + */ + +/** + * @defgroup lavu_ver Version and Build diagnostics + * + * Macros and function useful to check at compiletime and at runtime + * which version of libavutil is in use. + * + * @{ + */ + +#define LIBAVUTIL_VERSION_MAJOR 56 +#define LIBAVUTIL_VERSION_MINOR 31 +#define LIBAVUTIL_VERSION_MICRO 100 + +#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT + +#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) + +/** + * @defgroup lavu_depr_guards Deprecation Guards + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @note, when bumping the major version it is recommended to manually + * disable each FF_API_* in its own commit instead of disabling them all + * at once through the bump. This improves the git bisect-ability of the change. + * + * @{ + */ + +#ifndef FF_API_VAAPI +#define FF_API_VAAPI (LIBAVUTIL_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_FRAME_QP +#define FF_API_FRAME_QP (LIBAVUTIL_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_PLUS1_MINUS1 +#define FF_API_PLUS1_MINUS1 (LIBAVUTIL_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_ERROR_FRAME +#define FF_API_ERROR_FRAME (LIBAVUTIL_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_PKT_PTS +#define FF_API_PKT_PTS (LIBAVUTIL_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_CRYPTO_SIZE_T +#define FF_API_CRYPTO_SIZE_T (LIBAVUTIL_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_FRAME_GET_SET +#define FF_API_FRAME_GET_SET (LIBAVUTIL_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_PSEUDOPAL +#define FF_API_PSEUDOPAL (LIBAVUTIL_VERSION_MAJOR < 57) +#endif + + +/** + * @} + * @} + */ + +#endif /* AVUTIL_VERSION_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/asm.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/asm.h new file mode 100644 index 0000000000..9bff42d628 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/asm.h @@ -0,0 +1,154 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_ASM_H +#define AVUTIL_X86_ASM_H + +#include +#include "config.h" + +typedef struct xmm_reg { uint64_t a, b; } xmm_reg; +typedef struct ymm_reg { uint64_t a, b, c, d; } ymm_reg; + +#if ARCH_X86_64 +# define FF_OPSIZE "q" +# define FF_REG_a "rax" +# define FF_REG_b "rbx" +# define FF_REG_c "rcx" +# define FF_REG_d "rdx" +# define FF_REG_D "rdi" +# define FF_REG_S "rsi" +# define FF_PTR_SIZE "8" +typedef int64_t x86_reg; + +/* FF_REG_SP is defined in Solaris sys headers, so use FF_REG_sp */ +# define FF_REG_sp "rsp" +# define FF_REG_BP "rbp" +# define FF_REGBP rbp +# define FF_REGa rax +# define FF_REGb rbx +# define FF_REGc rcx +# define FF_REGd rdx +# define FF_REGSP rsp + +#elif ARCH_X86_32 + +# define FF_OPSIZE "l" +# define FF_REG_a "eax" +# define FF_REG_b "ebx" +# define FF_REG_c "ecx" +# define FF_REG_d "edx" +# define FF_REG_D "edi" +# define FF_REG_S "esi" +# define FF_PTR_SIZE "4" +typedef int32_t x86_reg; + +# define FF_REG_sp "esp" +# define FF_REG_BP "ebp" +# define FF_REGBP ebp +# define FF_REGa eax +# define FF_REGb ebx +# define FF_REGc ecx +# define FF_REGd edx +# define FF_REGSP esp +#else +typedef int x86_reg; +#endif + +#define HAVE_7REGS (ARCH_X86_64 || (HAVE_EBX_AVAILABLE && HAVE_EBP_AVAILABLE)) +#define HAVE_6REGS (ARCH_X86_64 || (HAVE_EBX_AVAILABLE || HAVE_EBP_AVAILABLE)) + +#if ARCH_X86_64 && defined(PIC) +# define BROKEN_RELOCATIONS 1 +#endif + +/* + * If gcc is not set to support sse (-msse) it will not accept xmm registers + * in the clobber list for inline asm. XMM_CLOBBERS takes a list of xmm + * registers to be marked as clobbered and evaluates to nothing if they are + * not supported, or to the list itself if they are supported. Since a clobber + * list may not be empty, XMM_CLOBBERS_ONLY should be used if the xmm + * registers are the only in the clobber list. + * For example a list with "eax" and "xmm0" as clobbers should become: + * : XMM_CLOBBERS("xmm0",) "eax" + * and a list with only "xmm0" should become: + * XMM_CLOBBERS_ONLY("xmm0") + */ +#if HAVE_XMM_CLOBBERS +# define XMM_CLOBBERS(...) __VA_ARGS__ +# define XMM_CLOBBERS_ONLY(...) : __VA_ARGS__ +#else +# define XMM_CLOBBERS(...) +# define XMM_CLOBBERS_ONLY(...) +#endif + +/* Use to export labels from asm. */ +#define LABEL_MANGLE(a) EXTERN_PREFIX #a + +// Use rip-relative addressing if compiling PIC code on x86-64. +#if ARCH_X86_64 && defined(PIC) +# define LOCAL_MANGLE(a) #a "(%%rip)" +#else +# define LOCAL_MANGLE(a) #a +#endif + +#if HAVE_INLINE_ASM_DIRECT_SYMBOL_REFS +# define MANGLE(a) EXTERN_PREFIX LOCAL_MANGLE(a) +# define NAMED_CONSTRAINTS_ADD(...) +# define NAMED_CONSTRAINTS(...) +# define NAMED_CONSTRAINTS_ARRAY_ADD(...) +# define NAMED_CONSTRAINTS_ARRAY(...) +#else + /* When direct symbol references are used in code passed to a compiler that does not support them + * then these references need to be converted to named asm constraints instead. + * Instead of returning a direct symbol MANGLE now returns a named constraint for that specific symbol. + * In order for this to work there must also be a corresponding entry in the asm-interface. To add this + * entry use the macro NAMED_CONSTRAINTS() and pass in a list of each symbol reference used in the + * corresponding block of code. (e.g. NAMED_CONSTRAINTS(var1,var2,var3) where var1 is the first symbol etc. ). + * If there are already existing constraints then use NAMED_CONSTRAINTS_ADD to add to the existing constraint list. + */ +# define MANGLE(a) "%["#a"]" + // Intel/MSVC does not correctly expand va-args so we need a rather ugly hack in order to get it to work +# define FE_0(P,X) P(X) +# define FE_1(P,X,X1) P(X), FE_0(P,X1) +# define FE_2(P,X,X1,X2) P(X), FE_1(P,X1,X2) +# define FE_3(P,X,X1,X2,X3) P(X), FE_2(P,X1,X2,X3) +# define FE_4(P,X,X1,X2,X3,X4) P(X), FE_3(P,X1,X2,X3,X4) +# define FE_5(P,X,X1,X2,X3,X4,X5) P(X), FE_4(P,X1,X2,X3,X4,X5) +# define FE_6(P,X,X1,X2,X3,X4,X5,X6) P(X), FE_5(P,X1,X2,X3,X4,X5,X6) +# define FE_7(P,X,X1,X2,X3,X4,X5,X6,X7) P(X), FE_6(P,X1,X2,X3,X4,X5,X6,X7) +# define FE_8(P,X,X1,X2,X3,X4,X5,X6,X7,X8) P(X), FE_7(P,X1,X2,X3,X4,X5,X6,X7,X8) +# define FE_9(P,X,X1,X2,X3,X4,X5,X6,X7,X8,X9) P(X), FE_8(P,X1,X2,X3,X4,X5,X6,X7,X8,X9) +# define GET_FE_IMPL(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,NAME,...) NAME +# define GET_FE(A) GET_FE_IMPL A +# define GET_FE_GLUE(x, y) x y +# define FOR_EACH_VA(P,...) GET_FE_GLUE(GET_FE((__VA_ARGS__,FE_9,FE_8,FE_7,FE_6,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)), (P,__VA_ARGS__)) +# define NAME_CONSTRAINT(x) [x] "m"(x) + // Parameters are a list of each symbol reference required +# define NAMED_CONSTRAINTS_ADD(...) , FOR_EACH_VA(NAME_CONSTRAINT,__VA_ARGS__) + // Same but without comma for when there are no previously defined constraints +# define NAMED_CONSTRAINTS(...) FOR_EACH_VA(NAME_CONSTRAINT,__VA_ARGS__) + // Same as above NAMED_CONSTRAINTS except used for passing arrays/pointers instead of normal variables +# define NAME_CONSTRAINT_ARRAY(x) [x] "m"(*x) +# define NAMED_CONSTRAINTS_ARRAY_ADD(...) , FOR_EACH_VA(NAME_CONSTRAINT_ARRAY,__VA_ARGS__) +# define NAMED_CONSTRAINTS_ARRAY(...) FOR_EACH_VA(NAME_CONSTRAINT_ARRAY,__VA_ARGS__) +#endif + +#endif /* AVUTIL_X86_ASM_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/bswap.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/bswap.h new file mode 100644 index 0000000000..ffa59e4c82 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/bswap.h @@ -0,0 +1,87 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * byte swapping routines + */ + +#ifndef AVUTIL_X86_BSWAP_H +#define AVUTIL_X86_BSWAP_H + +#include +#if defined(_MSC_VER) +#include +#endif +#include "config.h" +#include "libavutil/attributes.h" + +#if defined(_MSC_VER) + +#define av_bswap16 av_bswap16 +static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +{ + return _rotr16(x, 8); +} + +#define av_bswap32 av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return _byteswap_ulong(x); +} + +#if ARCH_X86_64 +#define av_bswap64 av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + return _byteswap_uint64(x); +} +#endif + + +#elif HAVE_INLINE_ASM + +#if AV_GCC_VERSION_AT_MOST(4,0) +#define av_bswap16 av_bswap16 +static av_always_inline av_const unsigned av_bswap16(unsigned x) +{ + __asm__("rorw $8, %w0" : "+r"(x)); + return x; +} +#endif /* AV_GCC_VERSION_AT_MOST(4,0) */ + +#if AV_GCC_VERSION_AT_MOST(4,4) || defined(__INTEL_COMPILER) +#define av_bswap32 av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + __asm__("bswap %0" : "+r" (x)); + return x; +} + +#if ARCH_X86_64 +#define av_bswap64 av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + __asm__("bswap %0": "=r" (x) : "0" (x)); + return x; +} +#endif +#endif /* AV_GCC_VERSION_AT_MOST(4,4) */ + +#endif /* HAVE_INLINE_ASM */ +#endif /* AVUTIL_X86_BSWAP_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpu.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpu.c new file mode 100644 index 0000000000..bcd41a50a2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpu.c @@ -0,0 +1,272 @@ +/* + * CPU detection code, extracted from mmx.h + * (c)1997-99 by H. Dietz and R. Fisher + * Converted to C and improved by Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" + +#if HAVE_X86ASM + +#define cpuid(index, eax, ebx, ecx, edx) \ + ff_cpu_cpuid(index, &eax, &ebx, &ecx, &edx) + +#define xgetbv(index, eax, edx) \ + ff_cpu_xgetbv(index, &eax, &edx) + +#elif HAVE_INLINE_ASM + +/* ebx saving is necessary for PIC. gcc seems unable to see it alone */ +#define cpuid(index, eax, ebx, ecx, edx) \ + __asm__ volatile ( \ + "mov %%"FF_REG_b", %%"FF_REG_S" \n\t" \ + "cpuid \n\t" \ + "xchg %%"FF_REG_b", %%"FF_REG_S \ + : "=a" (eax), "=S" (ebx), "=c" (ecx), "=d" (edx) \ + : "0" (index), "2"(0)) + +#define xgetbv(index, eax, edx) \ + __asm__ (".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c" (index)) + +#define get_eflags(x) \ + __asm__ volatile ("pushfl \n" \ + "pop %0 \n" \ + : "=r"(x)) + +#define set_eflags(x) \ + __asm__ volatile ("push %0 \n" \ + "popfl \n" \ + :: "r"(x)) + +#endif /* HAVE_INLINE_ASM */ + +#if ARCH_X86_64 + +#define cpuid_test() 1 + +#elif HAVE_X86ASM + +#define cpuid_test ff_cpu_cpuid_test + +#elif HAVE_INLINE_ASM + +static int cpuid_test(void) +{ + x86_reg a, c; + + /* Check if CPUID is supported by attempting to toggle the ID bit in + * the EFLAGS register. */ + get_eflags(a); + set_eflags(a ^ 0x200000); + get_eflags(c); + + return a != c; +} +#endif + +/* Function to test if multimedia instructions are supported... */ +int ff_get_cpu_flags_x86(void) +{ + int rval = 0; + +#ifdef cpuid + + int eax, ebx, ecx, edx; + int max_std_level, max_ext_level, std_caps = 0, ext_caps = 0; + int family = 0, model = 0; + union { int i[3]; char c[12]; } vendor; + int xcr0_lo = 0, xcr0_hi = 0; + + if (!cpuid_test()) + return 0; /* CPUID not supported */ + + cpuid(0, max_std_level, vendor.i[0], vendor.i[2], vendor.i[1]); + + if (max_std_level >= 1) { + cpuid(1, eax, ebx, ecx, std_caps); + family = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff); + model = ((eax >> 4) & 0xf) + ((eax >> 12) & 0xf0); + if (std_caps & (1 << 15)) + rval |= AV_CPU_FLAG_CMOV; + if (std_caps & (1 << 23)) + rval |= AV_CPU_FLAG_MMX; + if (std_caps & (1 << 25)) + rval |= AV_CPU_FLAG_MMXEXT; +#if HAVE_SSE + if (std_caps & (1 << 25)) + rval |= AV_CPU_FLAG_SSE; + if (std_caps & (1 << 26)) + rval |= AV_CPU_FLAG_SSE2; + if (ecx & 1) + rval |= AV_CPU_FLAG_SSE3; + if (ecx & 0x00000200 ) + rval |= AV_CPU_FLAG_SSSE3; + if (ecx & 0x00080000 ) + rval |= AV_CPU_FLAG_SSE4; + if (ecx & 0x00100000 ) + rval |= AV_CPU_FLAG_SSE42; + if (ecx & 0x02000000 ) + rval |= AV_CPU_FLAG_AESNI; +#if HAVE_AVX + /* Check OXSAVE and AVX bits */ + if ((ecx & 0x18000000) == 0x18000000) { + /* Check for OS support */ + xgetbv(0, xcr0_lo, xcr0_hi); + if ((xcr0_lo & 0x6) == 0x6) { + rval |= AV_CPU_FLAG_AVX; + if (ecx & 0x00001000) + rval |= AV_CPU_FLAG_FMA3; + } + } +#endif /* HAVE_AVX */ +#endif /* HAVE_SSE */ + } + if (max_std_level >= 7) { + cpuid(7, eax, ebx, ecx, edx); +#if HAVE_AVX2 + if ((rval & AV_CPU_FLAG_AVX) && (ebx & 0x00000020)) + rval |= AV_CPU_FLAG_AVX2; +#if HAVE_AVX512 /* F, CD, BW, DQ, VL */ + if ((xcr0_lo & 0xe0) == 0xe0) { /* OPMASK/ZMM state */ + if ((rval & AV_CPU_FLAG_AVX2) && (ebx & 0xd0030000) == 0xd0030000) + rval |= AV_CPU_FLAG_AVX512; + + } +#endif /* HAVE_AVX512 */ +#endif /* HAVE_AVX2 */ + /* BMI1/2 don't need OS support */ + if (ebx & 0x00000008) { + rval |= AV_CPU_FLAG_BMI1; + if (ebx & 0x00000100) + rval |= AV_CPU_FLAG_BMI2; + } + } + + cpuid(0x80000000, max_ext_level, ebx, ecx, edx); + + if (max_ext_level >= 0x80000001) { + cpuid(0x80000001, eax, ebx, ecx, ext_caps); + if (ext_caps & (1U << 31)) + rval |= AV_CPU_FLAG_3DNOW; + if (ext_caps & (1 << 30)) + rval |= AV_CPU_FLAG_3DNOWEXT; + if (ext_caps & (1 << 23)) + rval |= AV_CPU_FLAG_MMX; + if (ext_caps & (1 << 22)) + rval |= AV_CPU_FLAG_MMXEXT; + + if (!strncmp(vendor.c, "AuthenticAMD", 12)) { + /* Allow for selectively disabling SSE2 functions on AMD processors + with SSE2 support but not SSE4a. This includes Athlon64, some + Opteron, and some Sempron processors. MMX, SSE, or 3DNow! are faster + than SSE2 often enough to utilize this special-case flag. + AV_CPU_FLAG_SSE2 and AV_CPU_FLAG_SSE2SLOW are both set in this case + so that SSE2 is used unless explicitly disabled by checking + AV_CPU_FLAG_SSE2SLOW. */ + if (rval & AV_CPU_FLAG_SSE2 && !(ecx & 0x00000040)) + rval |= AV_CPU_FLAG_SSE2SLOW; + + /* Similar to the above but for AVX functions on AMD processors. + This is necessary only for functions using YMM registers on Bulldozer + and Jaguar based CPUs as they lack 256-bit execution units. SSE/AVX + functions using XMM registers are always faster on them. + AV_CPU_FLAG_AVX and AV_CPU_FLAG_AVXSLOW are both set so that AVX is + used unless explicitly disabled by checking AV_CPU_FLAG_AVXSLOW. */ + if ((family == 0x15 || family == 0x16) && (rval & AV_CPU_FLAG_AVX)) + rval |= AV_CPU_FLAG_AVXSLOW; + } + + /* XOP and FMA4 use the AVX instruction coding scheme, so they can't be + * used unless the OS has AVX support. */ + if (rval & AV_CPU_FLAG_AVX) { + if (ecx & 0x00000800) + rval |= AV_CPU_FLAG_XOP; + if (ecx & 0x00010000) + rval |= AV_CPU_FLAG_FMA4; + } + } + + if (!strncmp(vendor.c, "GenuineIntel", 12)) { + if (family == 6 && (model == 9 || model == 13 || model == 14)) { + /* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and + * 6/14 (core1 "yonah") theoretically support sse2, but it's + * usually slower than mmx, so let's just pretend they don't. + * AV_CPU_FLAG_SSE2 is disabled and AV_CPU_FLAG_SSE2SLOW is + * enabled so that SSE2 is not used unless explicitly enabled + * by checking AV_CPU_FLAG_SSE2SLOW. The same situation + * applies for AV_CPU_FLAG_SSE3 and AV_CPU_FLAG_SSE3SLOW. */ + if (rval & AV_CPU_FLAG_SSE2) + rval ^= AV_CPU_FLAG_SSE2SLOW | AV_CPU_FLAG_SSE2; + if (rval & AV_CPU_FLAG_SSE3) + rval ^= AV_CPU_FLAG_SSE3SLOW | AV_CPU_FLAG_SSE3; + } + /* The Atom processor has SSSE3 support, which is useful in many cases, + * but sometimes the SSSE3 version is slower than the SSE2 equivalent + * on the Atom, but is generally faster on other processors supporting + * SSSE3. This flag allows for selectively disabling certain SSSE3 + * functions on the Atom. */ + if (family == 6 && model == 28) + rval |= AV_CPU_FLAG_ATOM; + + /* Conroe has a slow shuffle unit. Check the model number to ensure not + * to include crippled low-end Penryns and Nehalems that lack SSE4. */ + if ((rval & AV_CPU_FLAG_SSSE3) && !(rval & AV_CPU_FLAG_SSE4) && + family == 6 && model < 23) + rval |= AV_CPU_FLAG_SSSE3SLOW; + } + +#endif /* cpuid */ + + return rval; +} + +size_t ff_get_cpu_max_align_x86(void) +{ + int flags = av_get_cpu_flags(); + + if (flags & AV_CPU_FLAG_AVX512) + return 64; + if (flags & (AV_CPU_FLAG_AVX2 | + AV_CPU_FLAG_AVX | + AV_CPU_FLAG_XOP | + AV_CPU_FLAG_FMA4 | + AV_CPU_FLAG_FMA3 | + AV_CPU_FLAG_AVXSLOW)) + return 32; + if (flags & (AV_CPU_FLAG_AESNI | + AV_CPU_FLAG_SSE42 | + AV_CPU_FLAG_SSE4 | + AV_CPU_FLAG_SSSE3 | + AV_CPU_FLAG_SSE3 | + AV_CPU_FLAG_SSE2 | + AV_CPU_FLAG_SSE | + AV_CPU_FLAG_ATOM | + AV_CPU_FLAG_SSSE3SLOW | + AV_CPU_FLAG_SSE3SLOW | + AV_CPU_FLAG_SSE2SLOW)) + return 16; + + return 8; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpu.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpu.h new file mode 100644 index 0000000000..937c697fa0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpu.h @@ -0,0 +1,113 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_CPU_H +#define AVUTIL_X86_CPU_H + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" + +#define AV_CPU_FLAG_AMD3DNOW AV_CPU_FLAG_3DNOW +#define AV_CPU_FLAG_AMD3DNOWEXT AV_CPU_FLAG_3DNOWEXT + +#define X86_AMD3DNOW(flags) CPUEXT(flags, AMD3DNOW) +#define X86_AMD3DNOWEXT(flags) CPUEXT(flags, AMD3DNOWEXT) +#define X86_MMX(flags) CPUEXT(flags, MMX) +#define X86_MMXEXT(flags) CPUEXT(flags, MMXEXT) +#define X86_SSE(flags) CPUEXT(flags, SSE) +#define X86_SSE2(flags) CPUEXT(flags, SSE2) +#define X86_SSE2_FAST(flags) CPUEXT_FAST(flags, SSE2) +#define X86_SSE2_SLOW(flags) CPUEXT_SLOW(flags, SSE2) +#define X86_SSE3(flags) CPUEXT(flags, SSE3) +#define X86_SSE3_FAST(flags) CPUEXT_FAST(flags, SSE3) +#define X86_SSE3_SLOW(flags) CPUEXT_SLOW(flags, SSE3) +#define X86_SSSE3(flags) CPUEXT(flags, SSSE3) +#define X86_SSSE3_FAST(flags) CPUEXT_FAST(flags, SSSE3) +#define X86_SSSE3_SLOW(flags) CPUEXT_SLOW(flags, SSSE3) +#define X86_SSE4(flags) CPUEXT(flags, SSE4) +#define X86_SSE42(flags) CPUEXT(flags, SSE42) +#define X86_AVX(flags) CPUEXT(flags, AVX) +#define X86_AVX_FAST(flags) CPUEXT_FAST(flags, AVX) +#define X86_AVX_SLOW(flags) CPUEXT_SLOW(flags, AVX) +#define X86_XOP(flags) CPUEXT(flags, XOP) +#define X86_FMA3(flags) CPUEXT(flags, FMA3) +#define X86_FMA4(flags) CPUEXT(flags, FMA4) +#define X86_AVX2(flags) CPUEXT(flags, AVX2) +#define X86_AESNI(flags) CPUEXT(flags, AESNI) +#define X86_AVX512(flags) CPUEXT(flags, AVX512) + +#define EXTERNAL_AMD3DNOW(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AMD3DNOW) +#define EXTERNAL_AMD3DNOWEXT(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AMD3DNOWEXT) +#define EXTERNAL_MMX(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, MMX) +#define EXTERNAL_MMXEXT(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, MMXEXT) +#define EXTERNAL_SSE(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE) +#define EXTERNAL_SSE2(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE2) +#define EXTERNAL_SSE2_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _EXTERNAL, SSE2) +#define EXTERNAL_SSE2_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _EXTERNAL, SSE2) +#define EXTERNAL_SSE3(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE3) +#define EXTERNAL_SSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _EXTERNAL, SSE3) +#define EXTERNAL_SSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _EXTERNAL, SSE3) +#define EXTERNAL_SSSE3(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSSE3) +#define EXTERNAL_SSSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _EXTERNAL, SSSE3) +#define EXTERNAL_SSSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _EXTERNAL, SSSE3) +#define EXTERNAL_SSE4(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE4) +#define EXTERNAL_SSE42(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE42) +#define EXTERNAL_AVX(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AVX) +#define EXTERNAL_AVX_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _EXTERNAL, AVX) +#define EXTERNAL_AVX_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _EXTERNAL, AVX) +#define EXTERNAL_XOP(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, XOP) +#define EXTERNAL_FMA3(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, FMA3) +#define EXTERNAL_FMA3_FAST(flags) CPUEXT_SUFFIX_FAST2(flags, _EXTERNAL, FMA3, AVX) +#define EXTERNAL_FMA3_SLOW(flags) CPUEXT_SUFFIX_SLOW2(flags, _EXTERNAL, FMA3, AVX) +#define EXTERNAL_FMA4(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, FMA4) +#define EXTERNAL_AVX2(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AVX2) +#define EXTERNAL_AVX2_FAST(flags) CPUEXT_SUFFIX_FAST2(flags, _EXTERNAL, AVX2, AVX) +#define EXTERNAL_AVX2_SLOW(flags) CPUEXT_SUFFIX_SLOW2(flags, _EXTERNAL, AVX2, AVX) +#define EXTERNAL_AESNI(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AESNI) +#define EXTERNAL_AVX512(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AVX512) + +#define INLINE_AMD3DNOW(flags) CPUEXT_SUFFIX(flags, _INLINE, AMD3DNOW) +#define INLINE_AMD3DNOWEXT(flags) CPUEXT_SUFFIX(flags, _INLINE, AMD3DNOWEXT) +#define INLINE_MMX(flags) CPUEXT_SUFFIX(flags, _INLINE, MMX) +#define INLINE_MMXEXT(flags) CPUEXT_SUFFIX(flags, _INLINE, MMXEXT) +#define INLINE_SSE(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE) +#define INLINE_SSE2(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE2) +#define INLINE_SSE2_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _INLINE, SSE2) +#define INLINE_SSE2_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _INLINE, SSE2) +#define INLINE_SSE3(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE3) +#define INLINE_SSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _INLINE, SSE3) +#define INLINE_SSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _INLINE, SSE3) +#define INLINE_SSSE3(flags) CPUEXT_SUFFIX(flags, _INLINE, SSSE3) +#define INLINE_SSSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _INLINE, SSSE3) +#define INLINE_SSSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _INLINE, SSSE3) +#define INLINE_SSE4(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE4) +#define INLINE_SSE42(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE42) +#define INLINE_AVX(flags) CPUEXT_SUFFIX(flags, _INLINE, AVX) +#define INLINE_AVX_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _INLINE, AVX) +#define INLINE_AVX_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _INLINE, AVX) +#define INLINE_XOP(flags) CPUEXT_SUFFIX(flags, _INLINE, XOP) +#define INLINE_FMA3(flags) CPUEXT_SUFFIX(flags, _INLINE, FMA3) +#define INLINE_FMA4(flags) CPUEXT_SUFFIX(flags, _INLINE, FMA4) +#define INLINE_AVX2(flags) CPUEXT_SUFFIX(flags, _INLINE, AVX2) +#define INLINE_AESNI(flags) CPUEXT_SUFFIX(flags, _INLINE, AESNI) + +void ff_cpu_cpuid(int index, int *eax, int *ebx, int *ecx, int *edx); +void ff_cpu_xgetbv(int op, int *eax, int *edx); +int ff_cpu_cpuid_test(void); + +#endif /* AVUTIL_X86_CPU_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/emms.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/emms.h new file mode 100644 index 0000000000..c21e34b451 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/emms.h @@ -0,0 +1,55 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_EMMS_H +#define AVUTIL_X86_EMMS_H + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" + +void avpriv_emms_asm(void); + +#if HAVE_MMX_INLINE +# define emms_c emms_c +/** + * Empty mmx state. + * this must be called between any dsp function and float/double code. + * for example sin(); dsp->idct_put(); emms_c(); cos() + * Note, *alloc() and *free() also use float code in some libc implementations + * thus this also applies to them or any function using them. + */ +static av_always_inline void emms_c(void) +{ +/* Some inlined functions may also use mmx instructions regardless of + * runtime cpuflags. With that in mind, we unconditionally empty the + * mmx state if the target cpu chosen at configure time supports it. + */ +#if !defined(__MMX__) + if(av_get_cpu_flags() & AV_CPU_FLAG_MMX) +#endif + __asm__ volatile ("emms" ::: "memory"); +} +#elif HAVE_MMX && HAVE_MM_EMPTY +# include +# define emms_c _mm_empty +#elif HAVE_MMX_EXTERNAL +# define emms_c avpriv_emms_asm +#endif /* HAVE_MMX_INLINE */ + +#endif /* AVUTIL_X86_EMMS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/fixed_dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/fixed_dsp_init.c new file mode 100644 index 0000000000..303a2eb922 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/fixed_dsp_init.c @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/fixed_dsp.h" +#include "cpu.h" + +void ff_butterflies_fixed_sse2(int *src0, int *src1, int len); + +av_cold void ff_fixed_dsp_init_x86(AVFixedDSPContext *fdsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE2(cpu_flags)) { + fdsp->butterflies_fixed = ff_butterflies_fixed_sse2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/float_dsp_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/float_dsp_init.c new file mode 100644 index 0000000000..8826e4e2c9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/float_dsp_init.c @@ -0,0 +1,121 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/float_dsp.h" +#include "cpu.h" +#include "asm.h" + +void ff_vector_fmul_sse(float *dst, const float *src0, const float *src1, + int len); +void ff_vector_fmul_avx(float *dst, const float *src0, const float *src1, + int len); + +void ff_vector_dmul_sse2(double *dst, const double *src0, const double *src1, + int len); +void ff_vector_dmul_avx(double *dst, const double *src0, const double *src1, + int len); + +void ff_vector_fmac_scalar_sse(float *dst, const float *src, float mul, + int len); +void ff_vector_fmac_scalar_avx(float *dst, const float *src, float mul, + int len); +void ff_vector_fmac_scalar_fma3(float *dst, const float *src, float mul, + int len); + +void ff_vector_fmul_scalar_sse(float *dst, const float *src, float mul, + int len); + +void ff_vector_dmac_scalar_sse2(double *dst, const double *src, double mul, + int len); +void ff_vector_dmac_scalar_avx(double *dst, const double *src, double mul, + int len); +void ff_vector_dmac_scalar_fma3(double *dst, const double *src, double mul, + int len); + +void ff_vector_dmul_scalar_sse2(double *dst, const double *src, + double mul, int len); +void ff_vector_dmul_scalar_avx(double *dst, const double *src, + double mul, int len); + +void ff_vector_fmul_window_3dnowext(float *dst, const float *src0, + const float *src1, const float *win, int len); +void ff_vector_fmul_window_sse(float *dst, const float *src0, + const float *src1, const float *win, int len); + +void ff_vector_fmul_add_sse(float *dst, const float *src0, const float *src1, + const float *src2, int len); +void ff_vector_fmul_add_avx(float *dst, const float *src0, const float *src1, + const float *src2, int len); +void ff_vector_fmul_add_fma3(float *dst, const float *src0, const float *src1, + const float *src2, int len); + +void ff_vector_fmul_reverse_sse(float *dst, const float *src0, + const float *src1, int len); +void ff_vector_fmul_reverse_avx(float *dst, const float *src0, + const float *src1, int len); +void ff_vector_fmul_reverse_avx2(float *dst, const float *src0, + const float *src1, int len); + +float ff_scalarproduct_float_sse(const float *v1, const float *v2, int order); + +void ff_butterflies_float_sse(float *av_restrict src0, float *av_restrict src1, int len); + +av_cold void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_AMD3DNOWEXT(cpu_flags)) { + fdsp->vector_fmul_window = ff_vector_fmul_window_3dnowext; + } + if (EXTERNAL_SSE(cpu_flags)) { + fdsp->vector_fmul = ff_vector_fmul_sse; + fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_sse; + fdsp->vector_fmul_scalar = ff_vector_fmul_scalar_sse; + fdsp->vector_fmul_window = ff_vector_fmul_window_sse; + fdsp->vector_fmul_add = ff_vector_fmul_add_sse; + fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_sse; + fdsp->scalarproduct_float = ff_scalarproduct_float_sse; + fdsp->butterflies_float = ff_butterflies_float_sse; + } + if (EXTERNAL_SSE2(cpu_flags)) { + fdsp->vector_dmul = ff_vector_dmul_sse2; + fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_sse2; + fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_sse2; + } + if (EXTERNAL_AVX_FAST(cpu_flags)) { + fdsp->vector_fmul = ff_vector_fmul_avx; + fdsp->vector_dmul = ff_vector_dmul_avx; + fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_avx; + fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_avx; + fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_avx; + fdsp->vector_fmul_add = ff_vector_fmul_add_avx; + fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_avx; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_avx2; + } + if (EXTERNAL_FMA3_FAST(cpu_flags)) { + fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_fma3; + fdsp->vector_fmul_add = ff_vector_fmul_add_fma3; + fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_fma3; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/imgutils_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/imgutils_init.c new file mode 100644 index 0000000000..4ea398205e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/imgutils_init.c @@ -0,0 +1,49 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavutil/cpu.h" +#include "libavutil/error.h" +#include "libavutil/imgutils.h" +#include "libavutil/imgutils_internal.h" +#include "libavutil/internal.h" + +#include "cpu.h" + +void ff_image_copy_plane_uc_from_sse4(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height); + +int ff_image_copy_plane_uc_from_x86(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height) +{ + int cpu_flags = av_get_cpu_flags(); + ptrdiff_t bw_aligned = FFALIGN(bytewidth, 64); + + if (EXTERNAL_SSE4(cpu_flags) && + bw_aligned <= dst_linesize && bw_aligned <= src_linesize) + ff_image_copy_plane_uc_from_sse4(dst, dst_linesize, src, src_linesize, + bw_aligned, height); + else + return AVERROR(ENOSYS); + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/intmath.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/intmath.h new file mode 100644 index 0000000000..40743fd13e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/intmath.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_INTMATH_H +#define AVUTIL_X86_INTMATH_H + +#include +#include +#if HAVE_FAST_CLZ +#if defined(_MSC_VER) +#include +#elif defined(__INTEL_COMPILER) +#include +#endif +#endif +#include "config.h" + +#if HAVE_FAST_CLZ +#if (defined(__INTEL_COMPILER) && (__INTEL_COMPILER>=1216)) || defined(_MSC_VER) +# if defined(__INTEL_COMPILER) +# define ff_log2(x) (_bit_scan_reverse((x)|1)) +# else +# define ff_log2 ff_log2_x86 +static av_always_inline av_const int ff_log2_x86(unsigned int v) +{ + unsigned long n; + _BitScanReverse(&n, v|1); + return n; +} +# endif +# define ff_log2_16bit av_log2 + +#if defined(__INTEL_COMPILER) || (defined(_MSC_VER) && (_MSC_VER >= 1700) && \ + (defined(__BMI__) || !defined(__clang__))) +# define ff_ctz(v) _tzcnt_u32(v) + +# if ARCH_X86_64 +# define ff_ctzll(v) _tzcnt_u64(v) +# else +# define ff_ctzll ff_ctzll_x86 +static av_always_inline av_const int ff_ctzll_x86(long long v) +{ + return ((uint32_t)v == 0) ? _tzcnt_u32((uint32_t)(v >> 32)) + 32 : _tzcnt_u32((uint32_t)v); +} +# endif +#endif /* _MSC_VER */ + +#endif /* __INTEL_COMPILER */ + +#endif /* HAVE_FAST_CLZ */ + +#if defined(__GNUC__) + +/* Our generic version of av_popcount is faster than GCC's built-in on + * CPUs that don't support the popcnt instruction. + */ +#if defined(__POPCNT__) + #define av_popcount __builtin_popcount +#if ARCH_X86_64 + #define av_popcount64 __builtin_popcountll +#endif + +#endif /* __POPCNT__ */ + +#if defined(__BMI2__) + +#if AV_GCC_VERSION_AT_LEAST(5,1) +#define av_mod_uintp2 __builtin_ia32_bzhi_si +#elif HAVE_INLINE_ASM +/* GCC releases before 5.1.0 have a broken bzhi builtin, so for those we + * implement it using inline assembly + */ +#define av_mod_uintp2 av_mod_uintp2_bmi2 +static av_always_inline av_const unsigned av_mod_uintp2_bmi2(unsigned a, unsigned p) +{ + if (av_builtin_constant_p(p)) + return a & ((1 << p) - 1); + else { + unsigned x; + __asm__ ("bzhi %2, %1, %0 \n\t" : "=r"(x) : "rm"(a), "r"(p)); + return x; + } +} +#endif /* AV_GCC_VERSION_AT_LEAST */ + +#endif /* __BMI2__ */ + +#if defined(__SSE2__) && !defined(__INTEL_COMPILER) + +#define av_clipd av_clipd_sse2 +static av_always_inline av_const double av_clipd_sse2(double a, double amin, double amax) +{ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + __asm__ ("minsd %2, %0 \n\t" + "maxsd %1, %0 \n\t" + : "+&x"(a) : "xm"(amin), "xm"(amax)); + return a; +} + +#endif /* __SSE2__ */ + +#if defined(__SSE__) && !defined(__INTEL_COMPILER) + +#define av_clipf av_clipf_sse +static av_always_inline av_const float av_clipf_sse(float a, float amin, float amax) +{ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + __asm__ ("minss %2, %0 \n\t" + "maxss %1, %0 \n\t" + : "+&x"(a) : "xm"(amin), "xm"(amax)); + return a; +} + +#endif /* __SSE__ */ + +#endif /* __GNUC__ */ + +#endif /* AVUTIL_X86_INTMATH_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/intreadwrite.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/intreadwrite.h new file mode 100644 index 0000000000..4061d19231 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/intreadwrite.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010 Alexander Strange + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_INTREADWRITE_H +#define AVUTIL_X86_INTREADWRITE_H + +#include +#include "config.h" +#include "libavutil/attributes.h" + +#if HAVE_MMX + +#if !HAVE_FAST_64BIT && defined(__MMX__) + +#define AV_COPY64 AV_COPY64 +static av_always_inline void AV_COPY64(void *d, const void *s) +{ + __asm__("movq %1, %%mm0 \n\t" + "movq %%mm0, %0 \n\t" + : "=m"(*(uint64_t*)d) + : "m" (*(const uint64_t*)s) + : "mm0"); +} + +#define AV_SWAP64 AV_SWAP64 +static av_always_inline void AV_SWAP64(void *a, void *b) +{ + __asm__("movq %1, %%mm0 \n\t" + "movq %0, %%mm1 \n\t" + "movq %%mm0, %0 \n\t" + "movq %%mm1, %1 \n\t" + : "+m"(*(uint64_t*)a), "+m"(*(uint64_t*)b) + ::"mm0", "mm1"); +} + +#define AV_ZERO64 AV_ZERO64 +static av_always_inline void AV_ZERO64(void *d) +{ + __asm__("pxor %%mm0, %%mm0 \n\t" + "movq %%mm0, %0 \n\t" + : "=m"(*(uint64_t*)d) + :: "mm0"); +} + +#endif /* !HAVE_FAST_64BIT && defined(__MMX__) */ + +#ifdef __SSE__ + +#define AV_COPY128 AV_COPY128 +static av_always_inline void AV_COPY128(void *d, const void *s) +{ + struct v {uint64_t v[2];}; + + __asm__("movaps %1, %%xmm0 \n\t" + "movaps %%xmm0, %0 \n\t" + : "=m"(*(struct v*)d) + : "m" (*(const struct v*)s) + : "xmm0"); +} + +#endif /* __SSE__ */ + +#ifdef __SSE2__ + +#define AV_ZERO128 AV_ZERO128 +static av_always_inline void AV_ZERO128(void *d) +{ + struct v {uint64_t v[2];}; + + __asm__("pxor %%xmm0, %%xmm0 \n\t" + "movdqa %%xmm0, %0 \n\t" + : "=m"(*(struct v*)d) + :: "xmm0"); +} + +#endif /* __SSE2__ */ + +#endif /* HAVE_MMX */ + +#endif /* AVUTIL_X86_INTREADWRITE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/lls_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/lls_init.c new file mode 100644 index 0000000000..1c5dca42dc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/lls_init.c @@ -0,0 +1,45 @@ +/* + * linear least squares model + * + * Copyright (c) 2013 Loren Merritt + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/lls.h" +#include "libavutil/x86/cpu.h" + +void ff_update_lls_sse2(LLSModel *m, const double *var); +void ff_update_lls_avx(LLSModel *m, const double *var); +void ff_update_lls_fma3(LLSModel *m, const double *var); +double ff_evaluate_lls_sse2(LLSModel *m, const double *var, int order); + +av_cold void ff_init_lls_x86(LLSModel *m) +{ + int cpu_flags = av_get_cpu_flags(); + if (EXTERNAL_SSE2(cpu_flags)) { + m->update_lls = ff_update_lls_sse2; + if (m->indep_count >= 4) + m->evaluate_lls = ff_evaluate_lls_sse2; + } + if (EXTERNAL_AVX_FAST(cpu_flags)) { + m->update_lls = ff_update_lls_avx; + } + if (EXTERNAL_FMA3_FAST(cpu_flags)) { + m->update_lls = ff_update_lls_fma3; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/pixelutils.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/pixelutils.h new file mode 100644 index 0000000000..876cf46053 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/pixelutils.h @@ -0,0 +1,26 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_PIXELUTILS_H +#define AVUTIL_X86_PIXELUTILS_H + +#include "libavutil/pixelutils.h" + +void ff_pixelutils_sad_init_x86(av_pixelutils_sad_fn *sad, int aligned); + +#endif /* AVUTIL_X86_PIXELUTILS_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/pixelutils_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/pixelutils_init.c new file mode 100644 index 0000000000..184a3a4a9f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/pixelutils_init.c @@ -0,0 +1,94 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "pixelutils.h" +#include "cpu.h" + +int ff_pixelutils_sad_8x8_mmx(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_8x8_mmxext(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +int ff_pixelutils_sad_16x16_mmxext(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_16x16_sse2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_a_16x16_sse2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_u_16x16_sse2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +int ff_pixelutils_sad_32x32_sse2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_a_32x32_sse2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_u_32x32_sse2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +int ff_pixelutils_sad_32x32_avx2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_a_32x32_avx2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_u_32x32_avx2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +void ff_pixelutils_sad_init_x86(av_pixelutils_sad_fn *sad, int aligned) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + sad[2] = ff_pixelutils_sad_8x8_mmx; + } + + // The best way to use SSE2 would be to do 2 SADs in parallel, + // but we'd have to modify the pixelutils API to return SIMD functions. + + // It's probably not faster to shuffle data around + // to get two lines of 8 pixels into a single 16byte register, + // so just use the MMX 8x8 version even when SSE2 is available. + if (EXTERNAL_MMXEXT(cpu_flags)) { + sad[2] = ff_pixelutils_sad_8x8_mmxext; + sad[3] = ff_pixelutils_sad_16x16_mmxext; + } + + if (EXTERNAL_SSE2(cpu_flags)) { + switch (aligned) { + case 0: sad[3] = ff_pixelutils_sad_16x16_sse2; break; // src1 unaligned, src2 unaligned + case 1: sad[3] = ff_pixelutils_sad_u_16x16_sse2; break; // src1 aligned, src2 unaligned + case 2: sad[3] = ff_pixelutils_sad_a_16x16_sse2; break; // src1 aligned, src2 aligned + } + } + + if (EXTERNAL_SSE2(cpu_flags)) { + switch (aligned) { + case 0: sad[4] = ff_pixelutils_sad_32x32_sse2; break; // src1 unaligned, src2 unaligned + case 1: sad[4] = ff_pixelutils_sad_u_32x32_sse2; break; // src1 aligned, src2 unaligned + case 2: sad[4] = ff_pixelutils_sad_a_32x32_sse2; break; // src1 aligned, src2 aligned + } + } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + switch (aligned) { + case 0: sad[4] = ff_pixelutils_sad_32x32_avx2; break; // src1 unaligned, src2 unaligned + case 1: sad[4] = ff_pixelutils_sad_u_32x32_avx2; break; // src1 aligned, src2 unaligned + case 2: sad[4] = ff_pixelutils_sad_a_32x32_avx2; break; // src1 aligned, src2 aligned + } + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/timer.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/timer.h new file mode 100644 index 0000000000..4d1e88def0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/timer.h @@ -0,0 +1,50 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_TIMER_H +#define AVUTIL_X86_TIMER_H + +#include + +#if HAVE_INLINE_ASM + +#define FF_TIMER_UNITS "decicycles" +#define AV_READ_TIME read_time + +static inline uint64_t read_time(void) +{ + uint32_t a, d; + __asm__ volatile( +#if ARCH_X86_64 || defined(__SSE2__) + "lfence \n\t" +#endif + "rdtsc \n\t" + : "=a" (a), "=d" (d)); + return ((uint64_t)d << 32) + a; +} + +#elif HAVE_RDTSC + +#include +#define AV_READ_TIME __rdtsc + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVUTIL_X86_TIMER_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/w64xmmtest.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/w64xmmtest.h new file mode 100644 index 0000000000..a4a05b0419 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/w64xmmtest.h @@ -0,0 +1,78 @@ +/* + * check XMM registers for clobbers on Win64 + * Copyright (c) 2008 Ramiro Polla + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_W64XMMTEST_H +#define AVUTIL_X86_W64XMMTEST_H + +#include +#include +#include +#include +#include + +#include "libavutil/bswap.h" + +#define storexmmregs(mem) \ + __asm__ volatile( \ + "movups %%xmm6 , 0x00(%0)\n\t" \ + "movups %%xmm7 , 0x10(%0)\n\t" \ + "movups %%xmm8 , 0x20(%0)\n\t" \ + "movups %%xmm9 , 0x30(%0)\n\t" \ + "movups %%xmm10, 0x40(%0)\n\t" \ + "movups %%xmm11, 0x50(%0)\n\t" \ + "movups %%xmm12, 0x60(%0)\n\t" \ + "movups %%xmm13, 0x70(%0)\n\t" \ + "movups %%xmm14, 0x80(%0)\n\t" \ + "movups %%xmm15, 0x90(%0)\n\t" \ + :: "r"(mem) : "memory") + +#define testxmmclobbers(func, ctx, ...) \ + uint64_t xmm[2][10][2]; \ + int ret; \ + storexmmregs(xmm[0]); \ + ret = __real_ ## func(ctx, __VA_ARGS__); \ + storexmmregs(xmm[1]); \ + if (memcmp(xmm[0], xmm[1], sizeof(xmm[0]))) { \ + int i; \ + av_log(ctx, AV_LOG_ERROR, \ + "XMM REGS CLOBBERED IN %s!\n", #func); \ + for (i = 0; i < 10; i ++) \ + if (xmm[0][i][0] != xmm[1][i][0] || \ + xmm[0][i][1] != xmm[1][i][1]) { \ + av_log(ctx, AV_LOG_ERROR, \ + "xmm%-2d = %016"PRIx64"%016"PRIx64"\n", \ + 6 + i, av_bswap64(xmm[0][i][0]), \ + av_bswap64(xmm[0][i][1])); \ + av_log(ctx, AV_LOG_ERROR, \ + " -> %016"PRIx64"%016"PRIx64"\n", \ + av_bswap64(xmm[1][i][0]), \ + av_bswap64(xmm[1][i][1])); \ + } \ + abort(); \ + } \ + return ret + +#define wrap(func) \ +int __real_ ## func; \ +int __wrap_ ## func; \ +int __wrap_ ## func + +#endif /* AVUTIL_X86_W64XMMTEST_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xga_font_data.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xga_font_data.c new file mode 100644 index 0000000000..3aed3142cf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xga_font_data.c @@ -0,0 +1,417 @@ +/* + * CGA/EGA/VGA ROM font data + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * CGA/EGA/VGA ROM font data + */ + +#include +#include "xga_font_data.h" + +const uint8_t avpriv_cga_font[2048] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, + 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c, + 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, + 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, + 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, + 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0, + 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99, + 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, + 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, + 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, + 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, + 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, + 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, + 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00, + 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00, + 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, + 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00, + 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, + 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, + 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00, + 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00, + 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00, + 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00, + 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, + 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, + 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, + 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00, + 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00, + 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00, + 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, + 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78, 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00, + 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, + 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38, + 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00, + 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00, + 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00, + 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18, + 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00, 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30, + 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, + 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00, 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00, + 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, + 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f, + 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00, 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0, + 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, + 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00, + 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00, + 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00, 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0, + 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, + 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00, + 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00, + 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, + 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, + 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, + 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const uint8_t avpriv_vga16_font[4096] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, + 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xga_font_data.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xga_font_data.h new file mode 100644 index 0000000000..69dc337120 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xga_font_data.h @@ -0,0 +1,35 @@ +/* + * CGA/EGA/VGA ROM font data + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * CGA/EGA/VGA ROM font data + */ + +#ifndef AVUTIL_XGA_FONT_DATA_H +#define AVUTIL_XGA_FONT_DATA_H + +#include +#include "internal.h" + +extern av_export_avutil const uint8_t avpriv_cga_font[2048]; +extern av_export_avutil const uint8_t avpriv_vga16_font[4096]; + +#endif /* AVUTIL_XGA_FONT_DATA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xtea.c b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xtea.c new file mode 100644 index 0000000000..f7892af9fb --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xtea.c @@ -0,0 +1,253 @@ +/* + * A 32-bit implementation of the XTEA algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * loosely based on the implementation of David Wheeler and Roger Needham + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief XTEA 32-bit implementation + * @author Samuel Pitoiset + * @ingroup lavu_xtea + */ + +#include "avutil.h" +#include "common.h" +#include "intreadwrite.h" +#include "mem.h" +#include "xtea.h" + +AVXTEA *av_xtea_alloc(void) +{ + return av_mallocz(sizeof(struct AVXTEA)); +} + +void av_xtea_init(AVXTEA *ctx, const uint8_t key[16]) +{ + int i; + + for (i = 0; i < 4; i++) + ctx->key[i] = AV_RB32(key + (i << 2)); +} + +void av_xtea_le_init(AVXTEA *ctx, const uint8_t key[16]) +{ + int i; + + for (i = 0; i < 4; i++) + ctx->key[i] = AV_RL32(key + (i << 2)); +} + +static void xtea_crypt_ecb(AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int decrypt, uint8_t *iv) +{ + uint32_t v0, v1; +#if !CONFIG_SMALL + uint32_t k0 = ctx->key[0]; + uint32_t k1 = ctx->key[1]; + uint32_t k2 = ctx->key[2]; + uint32_t k3 = ctx->key[3]; +#endif + + v0 = AV_RB32(src); + v1 = AV_RB32(src + 4); + + if (decrypt) { +#if CONFIG_SMALL + int i; + uint32_t delta = 0x9E3779B9U, sum = delta * 32; + + for (i = 0; i < 32; i++) { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + ctx->key[(sum >> 11) & 3]); + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + ctx->key[sum & 3]); + } +#else +#define DSTEP(SUM, K0, K1) \ + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (SUM + K0); \ + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (SUM - 0x9E3779B9U + K1) + + DSTEP(0xC6EF3720U, k2, k3); + DSTEP(0x28B7BD67U, k3, k2); + DSTEP(0x8A8043AEU, k0, k1); + DSTEP(0xEC48C9F5U, k1, k0); + DSTEP(0x4E11503CU, k2, k3); + DSTEP(0xAFD9D683U, k2, k2); + DSTEP(0x11A25CCAU, k3, k1); + DSTEP(0x736AE311U, k0, k0); + DSTEP(0xD5336958U, k1, k3); + DSTEP(0x36FBEF9FU, k1, k2); + DSTEP(0x98C475E6U, k2, k1); + DSTEP(0xFA8CFC2DU, k3, k0); + DSTEP(0x5C558274U, k0, k3); + DSTEP(0xBE1E08BBU, k1, k2); + DSTEP(0x1FE68F02U, k1, k1); + DSTEP(0x81AF1549U, k2, k0); + DSTEP(0xE3779B90U, k3, k3); + DSTEP(0x454021D7U, k0, k2); + DSTEP(0xA708A81EU, k1, k1); + DSTEP(0x08D12E65U, k1, k0); + DSTEP(0x6A99B4ACU, k2, k3); + DSTEP(0xCC623AF3U, k3, k2); + DSTEP(0x2E2AC13AU, k0, k1); + DSTEP(0x8FF34781U, k0, k0); + DSTEP(0xF1BBCDC8U, k1, k3); + DSTEP(0x5384540FU, k2, k2); + DSTEP(0xB54CDA56U, k3, k1); + DSTEP(0x1715609DU, k0, k0); + DSTEP(0x78DDE6E4U, k0, k3); + DSTEP(0xDAA66D2BU, k1, k2); + DSTEP(0x3C6EF372U, k2, k1); + DSTEP(0x9E3779B9U, k3, k0); +#endif + if (iv) { + v0 ^= AV_RB32(iv); + v1 ^= AV_RB32(iv + 4); + memcpy(iv, src, 8); + } + } else { +#if CONFIG_SMALL + int i; + uint32_t sum = 0, delta = 0x9E3779B9U; + + for (i = 0; i < 32; i++) { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + ctx->key[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + ctx->key[(sum >> 11) & 3]); + } +#else +#define ESTEP(SUM, K0, K1) \ + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (SUM + K0);\ + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (SUM + 0x9E3779B9U + K1) + ESTEP(0x00000000U, k0, k3); + ESTEP(0x9E3779B9U, k1, k2); + ESTEP(0x3C6EF372U, k2, k1); + ESTEP(0xDAA66D2BU, k3, k0); + ESTEP(0x78DDE6E4U, k0, k0); + ESTEP(0x1715609DU, k1, k3); + ESTEP(0xB54CDA56U, k2, k2); + ESTEP(0x5384540FU, k3, k1); + ESTEP(0xF1BBCDC8U, k0, k0); + ESTEP(0x8FF34781U, k1, k0); + ESTEP(0x2E2AC13AU, k2, k3); + ESTEP(0xCC623AF3U, k3, k2); + ESTEP(0x6A99B4ACU, k0, k1); + ESTEP(0x08D12E65U, k1, k1); + ESTEP(0xA708A81EU, k2, k0); + ESTEP(0x454021D7U, k3, k3); + ESTEP(0xE3779B90U, k0, k2); + ESTEP(0x81AF1549U, k1, k1); + ESTEP(0x1FE68F02U, k2, k1); + ESTEP(0xBE1E08BBU, k3, k0); + ESTEP(0x5C558274U, k0, k3); + ESTEP(0xFA8CFC2DU, k1, k2); + ESTEP(0x98C475E6U, k2, k1); + ESTEP(0x36FBEF9FU, k3, k1); + ESTEP(0xD5336958U, k0, k0); + ESTEP(0x736AE311U, k1, k3); + ESTEP(0x11A25CCAU, k2, k2); + ESTEP(0xAFD9D683U, k3, k2); + ESTEP(0x4E11503CU, k0, k1); + ESTEP(0xEC48C9F5U, k1, k0); + ESTEP(0x8A8043AEU, k2, k3); + ESTEP(0x28B7BD67U, k3, k2); +#endif + } + + AV_WB32(dst, v0); + AV_WB32(dst + 4, v1); +} + +static void xtea_le_crypt_ecb(AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int decrypt, uint8_t *iv) +{ + uint32_t v0, v1; + int i; + + v0 = AV_RL32(src); + v1 = AV_RL32(src + 4); + + if (decrypt) { + uint32_t delta = 0x9E3779B9, sum = delta * 32; + + for (i = 0; i < 32; i++) { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + ctx->key[(sum >> 11) & 3]); + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + ctx->key[sum & 3]); + } + if (iv) { + v0 ^= AV_RL32(iv); + v1 ^= AV_RL32(iv + 4); + memcpy(iv, src, 8); + } + } else { + uint32_t sum = 0, delta = 0x9E3779B9; + + for (i = 0; i < 32; i++) { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + ctx->key[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + ctx->key[(sum >> 11) & 3]); + } + } + + AV_WL32(dst, v0); + AV_WL32(dst + 4, v1); +} + +static void xtea_crypt(AVXTEA *ctx, uint8_t *dst, const uint8_t *src, int count, + uint8_t *iv, int decrypt, + void (*crypt)(AVXTEA *, uint8_t *, const uint8_t *, int, uint8_t *)) +{ + int i; + + if (decrypt) { + while (count--) { + crypt(ctx, dst, src, decrypt, iv); + + src += 8; + dst += 8; + } + } else { + while (count--) { + if (iv) { + for (i = 0; i < 8; i++) + dst[i] = src[i] ^ iv[i]; + crypt(ctx, dst, dst, decrypt, NULL); + memcpy(iv, dst, 8); + } else { + crypt(ctx, dst, src, decrypt, NULL); + } + src += 8; + dst += 8; + } + } +} + +void av_xtea_crypt(AVXTEA *ctx, uint8_t *dst, const uint8_t *src, int count, + uint8_t *iv, int decrypt) +{ + xtea_crypt(ctx, dst, src, count, iv, decrypt, xtea_crypt_ecb); +} + +void av_xtea_le_crypt(AVXTEA *ctx, uint8_t *dst, const uint8_t *src, int count, + uint8_t *iv, int decrypt) +{ + xtea_crypt(ctx, dst, src, count, iv, decrypt, xtea_le_crypt_ecb); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xtea.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xtea.h new file mode 100644 index 0000000000..735427c109 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/xtea.h @@ -0,0 +1,94 @@ +/* + * A 32-bit implementation of the XTEA algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_XTEA_H +#define AVUTIL_XTEA_H + +#include + +/** + * @file + * @brief Public header for libavutil XTEA algorithm + * @defgroup lavu_xtea XTEA + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVXTEA { + uint32_t key[16]; +} AVXTEA; + +/** + * Allocate an AVXTEA context. + */ +AVXTEA *av_xtea_alloc(void); + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption, + * interpreted as big endian 32 bit numbers + */ +void av_xtea_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption, + * interpreted as little endian 32 bit numbers + */ +void av_xtea_le_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, + * in big endian format. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, + * in little endian format. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_le_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_XTEA_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/Makefile new file mode 100644 index 0000000000..42666e4dd2 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/Makefile @@ -0,0 +1,23 @@ +NAME = swresample +DESC = FFmpeg audio resampling library +FFLIBS = avutil + +HEADERS = swresample.h \ + version.h \ + +OBJS = audioconvert.o \ + dither.o \ + options.o \ + rematrix.o \ + resample.o \ + resample_dsp.o \ + swresample.o \ + swresample_frame.o \ + +OBJS-$(CONFIG_LIBSOXR) += soxr_resample.o +OBJS-$(CONFIG_SHARED) += log2_tab.o + +# Windows resource file +SLIBOBJS-$(HAVE_GNU_WINDRES) += swresampleres.o + +TESTPROGS = swresample diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/audio_convert_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/audio_convert_init.c new file mode 100644 index 0000000000..60e24adb1c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/audio_convert_init.c @@ -0,0 +1,67 @@ +/* + * This file is part of libswresample. + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/aarch64/cpu.h" +#include "libavutil/samplefmt.h" +#include "libswresample/swresample_internal.h" +#include "libswresample/audioconvert.h" + +void swri_oldapi_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len); +void swri_oldapi_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src, int len, int channels); +void swri_oldapi_conv_fltp_to_s16_nch_neon(int16_t *dst, float *const *src, int len, int channels); + +static void conv_flt_to_s16_neon(uint8_t **dst, const uint8_t **src, int len){ + swri_oldapi_conv_flt_to_s16_neon((int16_t*)*dst, (const float*)*src, len); +} + +static void conv_fltp_to_s16_2ch_neon(uint8_t **dst, const uint8_t **src, int len){ + swri_oldapi_conv_fltp_to_s16_2ch_neon((int16_t*)*dst, (float *const*)src, len, 2); +} + +static void conv_fltp_to_s16_nch_neon(uint8_t **dst, const uint8_t **src, int len){ + int channels; + for(channels=3; channelssimd_f= NULL; + + if (have_neon(cpu_flags)) { + if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = conv_flt_to_s16_neon; + if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels == 2) + ac->simd_f = conv_fltp_to_s16_2ch_neon; + if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels > 2) + ac->simd_f = conv_fltp_to_s16_nch_neon; + if(ac->simd_f) + ac->in_simd_align_mask = ac->out_simd_align_mask = 15; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/resample_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/resample_init.c new file mode 100644 index 0000000000..d01ec18756 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/resample_init.c @@ -0,0 +1,120 @@ +/* + * Audio resampling + * + * Copyright (c) 2004-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/cpu.h" +#include "libavutil/avassert.h" + +#include "libavutil/aarch64/cpu.h" +#include "libswresample/resample.h" + +#define DECLARE_RESAMPLE_COMMON_TEMPLATE(TYPE, DELEM, FELEM, FELEM2, OUT) \ + \ +void ff_resample_common_apply_filter_x4_##TYPE##_neon(FELEM2 *acc, const DELEM *src, \ + const FELEM *filter, int length); \ + \ +void ff_resample_common_apply_filter_x8_##TYPE##_neon(FELEM2 *acc, const DELEM *src, \ + const FELEM *filter, int length); \ + \ +static int ff_resample_common_##TYPE##_neon(ResampleContext *c, void *dest, const void *source, \ + int n, int update_ctx) \ +{ \ + DELEM *dst = dest; \ + const DELEM *src = source; \ + int dst_index; \ + int index = c->index; \ + int frac = c->frac; \ + int sample_index = 0; \ + int x4_aligned_filter_length = c->filter_length & ~3; \ + int x8_aligned_filter_length = c->filter_length & ~7; \ + \ + while (index >= c->phase_count) { \ + sample_index++; \ + index -= c->phase_count; \ + } \ + \ + for (dst_index = 0; dst_index < n; dst_index++) { \ + FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index; \ + \ + FELEM2 val = 0; \ + int i = 0; \ + if (x8_aligned_filter_length >= 8) { \ + ff_resample_common_apply_filter_x8_##TYPE##_neon(&val, &src[sample_index], \ + filter, x8_aligned_filter_length); \ + i += x8_aligned_filter_length; \ + \ + } else if (x4_aligned_filter_length >= 4) { \ + ff_resample_common_apply_filter_x4_##TYPE##_neon(&val, &src[sample_index], \ + filter, x4_aligned_filter_length); \ + i += x4_aligned_filter_length; \ + } \ + for (; i < c->filter_length; i++) { \ + val += src[sample_index + i] * (FELEM2)filter[i]; \ + } \ + OUT(dst[dst_index], val); \ + \ + frac += c->dst_incr_mod; \ + index += c->dst_incr_div; \ + if (frac >= c->src_incr) { \ + frac -= c->src_incr; \ + index++; \ + } \ + \ + while (index >= c->phase_count) { \ + sample_index++; \ + index -= c->phase_count; \ + } \ + } \ + \ + if (update_ctx) { \ + c->frac = frac; \ + c->index = index; \ + } \ + \ + return sample_index; \ +} \ + +#define OUT(d, v) d = v +DECLARE_RESAMPLE_COMMON_TEMPLATE(float, float, float, float, OUT) +#undef OUT + +#define OUT(d, v) (v) = ((v) + (1<<(14)))>>15; (d) = av_clip_int16(v) +DECLARE_RESAMPLE_COMMON_TEMPLATE(s16, int16_t, int16_t, int32_t, OUT) +#undef OUT + +av_cold void swri_resample_dsp_aarch64_init(ResampleContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (!have_neon(cpu_flags)) + return; + + switch(c->format) { + case AV_SAMPLE_FMT_FLTP: + c->dsp.resample_common = ff_resample_common_float_neon; + break; + case AV_SAMPLE_FMT_S16P: + c->dsp.resample_common = ff_resample_common_s16_neon; + break; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/audio_convert_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/audio_convert_init.c new file mode 100644 index 0000000000..ec9e62ede7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/audio_convert_init.c @@ -0,0 +1,67 @@ +/* + * This file is part of libswresample. + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/arm/cpu.h" +#include "libavutil/samplefmt.h" +#include "libswresample/swresample_internal.h" +#include "libswresample/audioconvert.h" + +void swri_oldapi_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len); +void swri_oldapi_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src, int len, int channels); +void swri_oldapi_conv_fltp_to_s16_nch_neon(int16_t *dst, float *const *src, int len, int channels); + +static void conv_flt_to_s16_neon(uint8_t **dst, const uint8_t **src, int len){ + swri_oldapi_conv_flt_to_s16_neon((int16_t*)*dst, (const float*)*src, len); +} + +static void conv_fltp_to_s16_2ch_neon(uint8_t **dst, const uint8_t **src, int len){ + swri_oldapi_conv_fltp_to_s16_2ch_neon((int16_t*)*dst, (float *const*)src, len, 2); +} + +static void conv_fltp_to_s16_nch_neon(uint8_t **dst, const uint8_t **src, int len){ + int channels; + for(channels=3; channelssimd_f= NULL; + + if (have_neon(cpu_flags)) { + if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = conv_flt_to_s16_neon; + if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels == 2) + ac->simd_f = conv_fltp_to_s16_2ch_neon; + if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels > 2) + ac->simd_f = conv_fltp_to_s16_nch_neon; + if(ac->simd_f) + ac->in_simd_align_mask = ac->out_simd_align_mask = 15; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/resample_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/resample_init.c new file mode 100644 index 0000000000..09b9766ff3 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/resample_init.c @@ -0,0 +1,120 @@ +/* + * Audio resampling + * + * Copyright (c) 2004-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/cpu.h" +#include "libavutil/avassert.h" + +#include "libavutil/arm/cpu.h" +#include "libswresample/resample.h" + +#define DECLARE_RESAMPLE_COMMON_TEMPLATE(TYPE, DELEM, FELEM, FELEM2, OUT) \ + \ +void ff_resample_common_apply_filter_x4_##TYPE##_neon(FELEM2 *acc, const DELEM *src, \ + const FELEM *filter, int length); \ + \ +void ff_resample_common_apply_filter_x8_##TYPE##_neon(FELEM2 *acc, const DELEM *src, \ + const FELEM *filter, int length); \ + \ +static int ff_resample_common_##TYPE##_neon(ResampleContext *c, void *dest, const void *source, \ + int n, int update_ctx) \ +{ \ + DELEM *dst = dest; \ + const DELEM *src = source; \ + int dst_index; \ + int index = c->index; \ + int frac = c->frac; \ + int sample_index = 0; \ + int x4_aligned_filter_length = c->filter_length & ~3; \ + int x8_aligned_filter_length = c->filter_length & ~7; \ + \ + while (index >= c->phase_count) { \ + sample_index++; \ + index -= c->phase_count; \ + } \ + \ + for (dst_index = 0; dst_index < n; dst_index++) { \ + FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index; \ + \ + FELEM2 val = 0; \ + int i = 0; \ + if (x8_aligned_filter_length >= 8) { \ + ff_resample_common_apply_filter_x8_##TYPE##_neon(&val, &src[sample_index], \ + filter, x8_aligned_filter_length); \ + i += x8_aligned_filter_length; \ + \ + } else if (x4_aligned_filter_length >= 4) { \ + ff_resample_common_apply_filter_x4_##TYPE##_neon(&val, &src[sample_index], \ + filter, x4_aligned_filter_length); \ + i += x4_aligned_filter_length; \ + } \ + for (; i < c->filter_length; i++) { \ + val += src[sample_index + i] * (FELEM2)filter[i]; \ + } \ + OUT(dst[dst_index], val); \ + \ + frac += c->dst_incr_mod; \ + index += c->dst_incr_div; \ + if (frac >= c->src_incr) { \ + frac -= c->src_incr; \ + index++; \ + } \ + \ + while (index >= c->phase_count) { \ + sample_index++; \ + index -= c->phase_count; \ + } \ + } \ + \ + if (update_ctx) { \ + c->frac = frac; \ + c->index = index; \ + } \ + \ + return sample_index; \ +} \ + +#define OUT(d, v) d = v +DECLARE_RESAMPLE_COMMON_TEMPLATE(float, float, float, float, OUT) +#undef OUT + +#define OUT(d, v) (v) = ((v) + (1<<(14)))>>15; (d) = av_clip_int16(v) +DECLARE_RESAMPLE_COMMON_TEMPLATE(s16, int16_t, int16_t, int32_t, OUT) +#undef OUT + +av_cold void swri_resample_dsp_arm_init(ResampleContext *c) +{ + int cpu_flags = av_get_cpu_flags(); + + if (!have_neon(cpu_flags)) + return; + + switch(c->format) { + case AV_SAMPLE_FMT_FLTP: + c->dsp.resample_common = ff_resample_common_float_neon; + break; + case AV_SAMPLE_FMT_S16P: + c->dsp.resample_common = ff_resample_common_s16_neon; + break; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/audioconvert.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/audioconvert.c new file mode 100644 index 0000000000..96ce84ac44 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/audioconvert.c @@ -0,0 +1,247 @@ +/* + * audio conversion + * Copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio conversion + * @author Michael Niedermayer + */ + +#include "libavutil/avstring.h" +#include "libavutil/avassert.h" +#include "libavutil/libm.h" +#include "libavutil/samplefmt.h" +#include "audioconvert.h" + + +#define CONV_FUNC_NAME(dst_fmt, src_fmt) conv_ ## src_fmt ## _to_ ## dst_fmt + +//FIXME rounding ? +#define CONV_FUNC(ofmt, otype, ifmt, expr)\ +static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end)\ +{\ + uint8_t *end2 = end - 3*os;\ + while(po < end2){\ + *(otype*)po = expr; pi += is; po += os;\ + *(otype*)po = expr; pi += is; po += os;\ + *(otype*)po = expr; pi += is; po += os;\ + *(otype*)po = expr; pi += is; po += os;\ + }\ + while(po < end){\ + *(otype*)po = expr; pi += is; po += os;\ + }\ +} + +//FIXME put things below under ifdefs so we do not waste space for cases no codec will need +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_U8 , *(const uint8_t*)pi) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80U)<<8) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80U)<<24) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_U8 , (uint64_t)((*(const uint8_t*)pi - 0x80U))<<56) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0f/ (1<<7))) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7))) +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi<<16) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S16, (uint64_t)(*(const int16_t*)pi)<<48) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0f/ (1<<15))) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15))) +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi>>16) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S32, (uint64_t)(*(const int32_t*)pi)<<32) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0f/ (1U<<31))) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31))) +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S64, (*(const int64_t*)pi>>56) + 0x80) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S64, *(const int64_t*)pi>>48) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S64, *(const int64_t*)pi>>32) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S64, *(const int64_t*)pi) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S64, *(const int64_t*)pi*(1.0f/ (INT64_C(1)<<63))) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S64, *(const int64_t*)pi*(1.0 / (INT64_C(1)<<63))) +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8( lrintf(*(const float*)pi * (1<<7)) + 0x80)) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16( lrintf(*(const float*)pi * (1<<15)))) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31)))) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_FLT, llrintf(*(const float*)pi * (INT64_C(1)<<63))) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_FLT, *(const float*)pi) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_FLT, *(const float*)pi) +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8( lrint(*(const double*)pi * (1<<7)) + 0x80)) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16( lrint(*(const double*)pi * (1<<15)))) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31)))) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_DBL, llrint(*(const double*)pi * (INT64_C(1)<<63))) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi) + +#define FMT_PAIR_FUNC(out, in) [(out) + AV_SAMPLE_FMT_NB*(in)] = CONV_FUNC_NAME(out, in) + +static conv_func_type * const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB*AV_SAMPLE_FMT_NB] = { + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64), +}; + +static void cpy1(uint8_t **dst, const uint8_t **src, int len){ + memcpy(*dst, *src, len); +} +static void cpy2(uint8_t **dst, const uint8_t **src, int len){ + memcpy(*dst, *src, 2*len); +} +static void cpy4(uint8_t **dst, const uint8_t **src, int len){ + memcpy(*dst, *src, 4*len); +} +static void cpy8(uint8_t **dst, const uint8_t **src, int len){ + memcpy(*dst, *src, 8*len); +} + +AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels, const int *ch_map, + int flags) +{ + AudioConvert *ctx; + conv_func_type *f = fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt) + AV_SAMPLE_FMT_NB*av_get_packed_sample_fmt(in_fmt)]; + + if (!f) + return NULL; + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return NULL; + + if(channels == 1){ + in_fmt = av_get_planar_sample_fmt( in_fmt); + out_fmt = av_get_planar_sample_fmt(out_fmt); + } + + ctx->channels = channels; + ctx->conv_f = f; + ctx->ch_map = ch_map; + if (in_fmt == AV_SAMPLE_FMT_U8 || in_fmt == AV_SAMPLE_FMT_U8P) + memset(ctx->silence, 0x80, sizeof(ctx->silence)); + + if(out_fmt == in_fmt && !ch_map) { + switch(av_get_bytes_per_sample(in_fmt)){ + case 1:ctx->simd_f = cpy1; break; + case 2:ctx->simd_f = cpy2; break; + case 4:ctx->simd_f = cpy4; break; + case 8:ctx->simd_f = cpy8; break; + } + } + + if(HAVE_X86ASM && HAVE_MMX) swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels); + if(ARCH_ARM) swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels); + if(ARCH_AARCH64) swri_audio_convert_init_aarch64(ctx, out_fmt, in_fmt, channels); + + return ctx; +} + +void swri_audio_convert_free(AudioConvert **ctx) +{ + av_freep(ctx); +} + +int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len) +{ + int ch; + int off=0; + const int os= (out->planar ? 1 :out->ch_count) *out->bps; + unsigned misaligned = 0; + + av_assert0(ctx->channels == out->ch_count); + + if (ctx->in_simd_align_mask) { + int planes = in->planar ? in->ch_count : 1; + unsigned m = 0; + for (ch = 0; ch < planes; ch++) + m |= (intptr_t)in->ch[ch]; + misaligned |= m & ctx->in_simd_align_mask; + } + if (ctx->out_simd_align_mask) { + int planes = out->planar ? out->ch_count : 1; + unsigned m = 0; + for (ch = 0; ch < planes; ch++) + m |= (intptr_t)out->ch[ch]; + misaligned |= m & ctx->out_simd_align_mask; + } + + //FIXME optimize common cases + + if(ctx->simd_f && !ctx->ch_map && !misaligned){ + off = len&~15; + av_assert1(off>=0); + av_assert1(off<=len); + av_assert2(ctx->channels == SWR_CH_MAX || !in->ch[ctx->channels]); + if(off>0){ + if(out->planar == in->planar){ + int planes = out->planar ? out->ch_count : 1; + for(ch=0; chsimd_f(out->ch+ch, (const uint8_t **)in->ch+ch, off * (out->planar ? 1 :out->ch_count)); + } + }else{ + ctx->simd_f(out->ch, (const uint8_t **)in->ch, off); + } + } + if(off == len) + return 0; + } + + for(ch=0; chchannels; ch++){ + const int ich= ctx->ch_map ? ctx->ch_map[ch] : ch; + const int is= ich < 0 ? 0 : (in->planar ? 1 : in->ch_count) * in->bps; + const uint8_t *pi= ich < 0 ? ctx->silence : in->ch[ich]; + uint8_t *po= out->ch[ch]; + uint8_t *end= po + os*len; + if(!po) + continue; + ctx->conv_f(po+off*os, pi+off*is, is, os, end); + } + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/audioconvert.h b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/audioconvert.h new file mode 100644 index 0000000000..1ca30c2a65 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/audioconvert.h @@ -0,0 +1,78 @@ +/* + * audio conversion + * Copyright (c) 2006 Michael Niedermayer + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_AUDIOCONVERT_H +#define SWRESAMPLE_AUDIOCONVERT_H + +/** + * @file + * Audio format conversion routines + */ + + +#include "swresample_internal.h" +#include "libavutil/cpu.h" + + +typedef void (conv_func_type)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end); +typedef void (simd_func_type)(uint8_t **dst, const uint8_t **src, int len); + +typedef struct AudioConvert { + int channels; + int in_simd_align_mask; + int out_simd_align_mask; + conv_func_type *conv_f; + simd_func_type *simd_f; + const int *ch_map; + uint8_t silence[8]; ///< silence input sample +}AudioConvert; + +/** + * Create an audio sample format converter context + * @param out_fmt Output sample format + * @param in_fmt Input sample format + * @param channels Number of channels + * @param flags See AV_CPU_FLAG_xx + * @param ch_map list of the channels id to pick from the source stream, NULL + * if all channels must be selected + * @return NULL on error + */ +AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels, const int *ch_map, + int flags); + +/** + * Free audio sample format converter context. + * and set the pointer to NULL + */ +void swri_audio_convert_free(AudioConvert **ctx); + +/** + * Convert between audio sample formats + * @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel. + * @param[in] in array of input buffers for each channel + * @param len length of audio frame size (measured in samples) + */ +int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len); + +#endif /* SWRESAMPLE_AUDIOCONVERT_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/dither.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/dither.c new file mode 100644 index 0000000000..64068d35b6 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/dither.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2012-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "swresample_internal.h" + +#include "noise_shaping_data.c" + +int swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat noise_fmt) { + double scale = s->dither.noise_scale; +#define TMP_EXTRA 2 + double *tmp = av_malloc_array(len + TMP_EXTRA, sizeof(double)); + int i; + + if (!tmp) + return AVERROR(ENOMEM); + + for(i=0; idither.method){ + case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break; + default: + av_assert0(s->dither.method < SWR_DITHER_NB); + v = ((double)seed) / UINT_MAX; + seed = seed*1664525 + 1013904223; + v-= ((double)seed) / UINT_MAX; + break; + } + tmp[i] = v; + } + + for(i=0; idither.method){ + default: + av_assert0(s->dither.method < SWR_DITHER_NB); + v = tmp[i]; + break; + case SWR_DITHER_TRIANGULAR_HIGHPASS : + v = (- tmp[i] + 2*tmp[i+1] - tmp[i+2]) / sqrt(6); + break; + } + + v*= scale; + + switch(noise_fmt){ + case AV_SAMPLE_FMT_S16P: ((int16_t*)dst)[i] = v; break; + case AV_SAMPLE_FMT_S32P: ((int32_t*)dst)[i] = v; break; + case AV_SAMPLE_FMT_FLTP: ((float *)dst)[i] = v; break; + case AV_SAMPLE_FMT_DBLP: ((double *)dst)[i] = v; break; + default: av_assert0(0); + } + } + + av_free(tmp); + return 0; +} + +av_cold int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt) +{ + int i; + double scale = 0; + + if (s->dither.method > SWR_DITHER_TRIANGULAR_HIGHPASS && s->dither.method <= SWR_DITHER_NS) + return AVERROR(EINVAL); + + out_fmt = av_get_packed_sample_fmt(out_fmt); + in_fmt = av_get_packed_sample_fmt( in_fmt); + + if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){ + if(out_fmt == AV_SAMPLE_FMT_S32) scale = 1.0/(1LL<<31); + if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1LL<<15); + if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1LL<< 7); + } + if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S32 && (s->dither.output_sample_bits&31)) scale = 1; + if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S16) scale = 1<<16; + if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1<<24; + if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1<<8; + + scale *= s->dither.scale; + + if (out_fmt == AV_SAMPLE_FMT_S32 && s->dither.output_sample_bits) + scale *= 1<<(32-s->dither.output_sample_bits); + + if (scale == 0) { + s->dither.method = 0; + return 0; + } + + s->dither.ns_pos = 0; + s->dither.noise_scale= scale; + s->dither.ns_scale = scale; + s->dither.ns_scale_1 = scale ? 1/scale : 0; + memset(s->dither.ns_errors, 0, sizeof(s->dither.ns_errors)); + for (i=0; filters[i].coefs; i++) { + const filter_t *f = &filters[i]; + if (llabs(s->out_sample_rate - f->rate)*20 <= f->rate && f->name == s->dither.method) { + int j; + s->dither.ns_taps = f->len; + for (j=0; jlen; j++) + s->dither.ns_coeffs[j] = f->coefs[j]; + s->dither.ns_scale_1 *= 1 - exp(f->gain_cB * M_LN10 * 0.005) * 2 / (1<<(8*av_get_bytes_per_sample(out_fmt))); + break; + } + } + if (!filters[i].coefs && s->dither.method > SWR_DITHER_NS) { + av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n"); + s->dither.method = SWR_DITHER_TRIANGULAR_HIGHPASS; + } + + return 0; +} + +#define TEMPLATE_DITHER_S16 +#include "dither_template.c" +#undef TEMPLATE_DITHER_S16 + +#define TEMPLATE_DITHER_S32 +#include "dither_template.c" +#undef TEMPLATE_DITHER_S32 + +#define TEMPLATE_DITHER_FLT +#include "dither_template.c" +#undef TEMPLATE_DITHER_FLT + +#define TEMPLATE_DITHER_DBL +#include "dither_template.c" +#undef TEMPLATE_DITHER_DBL diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/dither_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/dither_template.c new file mode 100644 index 0000000000..1f535de3dc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/dither_template.c @@ -0,0 +1,84 @@ +/* + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if defined(TEMPLATE_DITHER_DBL) +# define RENAME(N) N ## _double +# define DELEM double +# define CLIP(v) while(0) + +#elif defined(TEMPLATE_DITHER_FLT) +# define RENAME(N) N ## _float +# define DELEM float +# define CLIP(v) while(0) + +#elif defined(TEMPLATE_DITHER_S32) +# define RENAME(N) N ## _int32 +# define DELEM int32_t +# define CLIP(v) v = FFMAX(FFMIN(v, INT32_MAX), INT32_MIN) + +#elif defined(TEMPLATE_DITHER_S16) +# define RENAME(N) N ## _int16 +# define DELEM int16_t +# define CLIP(v) v = FFMAX(FFMIN(v, INT16_MAX), INT16_MIN) + +#else +ERROR +#endif + +void RENAME(swri_noise_shaping)(SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count){ + int pos = s->dither.ns_pos; + int i, j, ch; + int taps = s->dither.ns_taps; + float S = s->dither.ns_scale; + float S_1 = s->dither.ns_scale_1; + + av_assert2((taps&3) != 2); + av_assert2((taps&3) != 3 || s->dither.ns_coeffs[taps] == 0); + + for (ch=0; chch_count; ch++) { + const float *noise = ((const float *)noises->ch[ch]) + s->dither.noise_pos; + const DELEM *src = (const DELEM*)srcs->ch[ch]; + DELEM *dst = (DELEM*)dsts->ch[ch]; + float *ns_errors = s->dither.ns_errors[ch]; + const float *ns_coeffs = s->dither.ns_coeffs; + pos = s->dither.ns_pos; + for (i=0; idither.ns_pos = pos; +} + +#undef RENAME +#undef DELEM +#undef CLIP diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/noise_shaping_data.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/noise_shaping_data.c new file mode 100644 index 0000000000..77e0f2eafc --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/noise_shaping_data.c @@ -0,0 +1,224 @@ +/* Effect: dither/noise-shape Copyright (c) 2008-9 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +typedef struct { + int rate; + enum {fir, iir} type; + size_t len; + int gain_cB; /* Chosen so clips are few if any, but not guaranteed none. */ + double const * coefs; + enum SwrDitherType name; +} filter_t; + +static double const lip44[] = {2.033, -2.165, 1.959, -1.590, .6149}; +static double const fwe44[] = { + 2.412, -3.370, 3.937, -4.174, 3.353, -2.205, 1.281, -.569, .0847}; +static double const mew44[] = { + 1.662, -1.263, .4827, -.2913, .1268, -.1124, .03252, -.01265, -.03524}; +static double const iew44[] = { + 2.847, -4.685, 6.214, -7.184, 6.639, -5.032, 3.263, -1.632, .4191}; +static double const ges44[] = { + 2.2061, -.4706, -.2534, -.6214, 1.0587, .0676, -.6054, -.2738}; +static double const ges48[] = { + 2.2374, -.7339, -.1251, -.6033, .903, .0116, -.5853, -.2571}; + +static double const shi48[] = { + 2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406, + -5.8483986854553222656, 3.7067542076110839844, -1.0495119094848632812, + -1.1830236911773681641, 2.1126792430877685547, -1.9094531536102294922, + 0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609, + 0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002, + -0.023473845794796943665, +}; +static double const shi44[] = { + 2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875, + -7.4572014808654785156, 6.7263274192810058594, -4.8481650352478027344, + 2.0412089824676513672, 0.7006359100341796875, -2.9537565708160400391, + 4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297, + -2.1179926395416259766, 0.879302978515625, -0.031759146600961685181, + -0.42382788658142089844, 0.47882103919982910156, -0.35490813851356506348, + 0.17496839165687561035, -0.060908168554306030273, +}; +static double const shi38[] = { + 1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219, + -2.6341717243194580078, 2.1440362930297851562, -1.8153258562088012695, + 1.0816224813461303711, -0.70302653312683105469, 0.15991993248462677002, + 0.041549518704414367676, -0.29416576027870178223, 0.2518316805362701416, + -0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203, + 0.016833892092108726501, +}; +static double const shi32[] = +{ /* dmaker 32000: bestmax=4.99659 (inverted) */ +0.82118552923202515, +-1.0063692331314087, +0.62341964244842529, +-1.0447187423706055, +0.64532512426376343, +-0.87615132331848145, +0.52219754457473755, +-0.67434263229370117, +0.44954317808151245, +-0.52557498216629028, +0.34567299485206604, +-0.39618203043937683, +0.26791760325431824, +-0.28936097025871277, +0.1883765310049057, +-0.19097308814525604, +0.10431359708309174, +-0.10633844882249832, +0.046832218766212463, +-0.039653312414884567, +}; +static double const shi22[] = +{ /* dmaker 22050: bestmax=5.77762 (inverted) */ +0.056581053882837296, +-0.56956905126571655, +-0.40727734565734863, +-0.33870288729667664, +-0.29810553789138794, +-0.19039161503314972, +-0.16510021686553955, +-0.13468159735202789, +-0.096633769571781158, +-0.081049129366874695, +-0.064953058958053589, +-0.054459091275930405, +-0.043378707021474838, +-0.03660014271736145, +-0.026256965473294258, +-0.018786206841468811, +-0.013387725688517094, +-0.0090983230620622635, +-0.0026585909072309732, +-0.00042083300650119781, +}; +static double const shi16[] = +{ /* dmaker 16000: bestmax=5.97128 (inverted) */ +-0.37251132726669312, +-0.81423574686050415, +-0.55010956525802612, +-0.47405767440795898, +-0.32624706625938416, +-0.3161766529083252, +-0.2286367267370224, +-0.22916607558727264, +-0.19565616548061371, +-0.18160104751586914, +-0.15423151850700378, +-0.14104481041431427, +-0.11844276636838913, +-0.097583092749118805, +-0.076493598520755768, +-0.068106919527053833, +-0.041881654411554337, +-0.036922425031661987, +-0.019364040344953537, +-0.014994367957115173, +}; +static double const shi11[] = +{ /* dmaker 11025: bestmax=5.9406 (inverted) */ +-0.9264228343963623, +-0.98695987462997437, +-0.631156325340271, +-0.51966935396194458, +-0.39738872647285461, +-0.35679301619529724, +-0.29720726609230042, +-0.26310476660728455, +-0.21719355881214142, +-0.18561814725399017, +-0.15404847264289856, +-0.12687471508979797, +-0.10339745879173279, +-0.083688631653785706, +-0.05875682458281517, +-0.046893671154975891, +-0.027950936928391457, +-0.020740609616041183, +-0.009366452693939209, +-0.0060260160826146603, +}; +static double const shi08[] = +{ /* dmaker 8000: bestmax=5.56234 (inverted) */ +-1.202863335609436, +-0.94103097915649414, +-0.67878556251525879, +-0.57650017738342285, +-0.50004476308822632, +-0.44349345564842224, +-0.37833768129348755, +-0.34028723835945129, +-0.29413089156150818, +-0.24994957447052002, +-0.21715600788593292, +-0.18792112171649933, +-0.15268312394618988, +-0.12135542929172516, +-0.099610626697540283, +-0.075273610651493073, +-0.048787496984004974, +-0.042586319148540497, +-0.028991291299462318, +-0.011869125068187714, +}; +static double const shl48[] = { + 2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469, + -1.8117271661758422852, -0.20124770700931549072, 1.4759907722473144531, + -1.7210904359817504883, 0.97746700048446655273, -0.13790138065814971924, + -0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559, + -0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035, + 0.068674825131893157959, +}; +static double const shl44[] = { + 2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109, + -2.7571926116943359375, 1.4978630542755126953, -0.3427594602108001709, + -0.71733748912811279297, 1.0737057924270629883, -1.0225815773010253906, + 0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996, + 0.10322438180446624756, -0.067442022264003753662, -0.00495197344571352005, + 0, +}; +static double const shh44[] = { + 3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375, + -11.824929237365722656, 12.767142295837402344, -11.917946815490722656, + 9.1739168167114257812, -5.3712320327758789062, 1.1393624544143676758, + 2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031, + -5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656, + 2.1909697055816650391, -1.1672389507293701172, 0.4903914332389831543, + -0.16519790887832641602, 0.023217858746647834778, +}; + +static const filter_t filters[] = { + {44100, fir, 5, 210, lip44, SWR_DITHER_NS_LIPSHITZ}, + {46000, fir, 9, 276, fwe44, SWR_DITHER_NS_F_WEIGHTED}, + {46000, fir, 9, 160, mew44, SWR_DITHER_NS_MODIFIED_E_WEIGHTED}, + {46000, fir, 9, 321, iew44, SWR_DITHER_NS_IMPROVED_E_WEIGHTED}, +// {48000, iir, 4, 220, ges48, SWR_DITHER_NS_GESEMANN}, +// {44100, iir, 4, 230, ges44, SWR_DITHER_NS_GESEMANN}, + {48000, fir, 16, 301, shi48, SWR_DITHER_NS_SHIBATA}, + {44100, fir, 20, 333, shi44, SWR_DITHER_NS_SHIBATA}, + {37800, fir, 16, 240, shi38, SWR_DITHER_NS_SHIBATA}, + {32000, fir, 20, 240/*TBD*/, shi32, SWR_DITHER_NS_SHIBATA}, + {22050, fir, 20, 240/*TBD*/, shi22, SWR_DITHER_NS_SHIBATA}, + {16000, fir, 20, 240/*TBD*/, shi16, SWR_DITHER_NS_SHIBATA}, + {11025, fir, 20, 240/*TBD*/, shi11, SWR_DITHER_NS_SHIBATA}, + { 8000, fir, 20, 240/*TBD*/, shi08, SWR_DITHER_NS_SHIBATA}, + {48000, fir, 16, 250, shl48, SWR_DITHER_NS_LOW_SHIBATA}, + {44100, fir, 15, 250, shl44, SWR_DITHER_NS_LOW_SHIBATA}, + {44100, fir, 20, 383, shh44, SWR_DITHER_NS_HIGH_SHIBATA}, + { 0, fir, 0, 0, NULL, SWR_DITHER_NONE}, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/options.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/options.c new file mode 100644 index 0000000000..00d4f7c1c9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/options.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "swresample_internal.h" + +#include + +#define C30DB M_SQRT2 +#define C15DB 1.189207115 +#define C__0DB 1.0 +#define C_15DB 0.840896415 +#define C_30DB M_SQRT1_2 +#define C_45DB 0.594603558 +#define C_60DB 0.5 + +#define OFFSET(x) offsetof(SwrContext,x) +#define PARAM AV_OPT_FLAG_AUDIO_PARAM + +static const AVOption options[]={ +{"ich" , "set input channel count" , OFFSET(user_in_ch_count ), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, +{"in_channel_count" , "set input channel count" , OFFSET(user_in_ch_count ), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, +{"och" , "set output channel count" , OFFSET(user_out_ch_count ), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, +{"out_channel_count" , "set output channel count" , OFFSET(user_out_ch_count ), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, +{"uch" , "set used channel count" , OFFSET(user_used_ch_count), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, +{"used_channel_count" , "set used channel count" , OFFSET(user_used_ch_count), AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_CH_MAX, PARAM}, +{"isr" , "set input sample rate" , OFFSET( in_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, +{"in_sample_rate" , "set input sample rate" , OFFSET( in_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, +{"osr" , "set output sample rate" , OFFSET(out_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, +{"out_sample_rate" , "set output sample rate" , OFFSET(out_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, +{"isf" , "set input sample format" , OFFSET( in_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"in_sample_fmt" , "set input sample format" , OFFSET( in_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"osf" , "set output sample format" , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"out_sample_fmt" , "set output sample format" , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"tsf" , "set internal sample format" , OFFSET(user_int_sample_fmt), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"internal_sample_fmt" , "set internal sample format" , OFFSET(user_int_sample_fmt), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"icl" , "set input channel layout" , OFFSET(user_in_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, INT64_MIN, INT64_MAX , PARAM, "channel_layout"}, +{"in_channel_layout" , "set input channel layout" , OFFSET(user_in_ch_layout ), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, INT64_MIN, INT64_MAX , PARAM, "channel_layout"}, +{"ocl" , "set output channel layout" , OFFSET(user_out_ch_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, INT64_MIN, INT64_MAX , PARAM, "channel_layout"}, +{"out_channel_layout" , "set output channel layout" , OFFSET(user_out_ch_layout), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=0 }, INT64_MIN, INT64_MAX , PARAM, "channel_layout"}, +{"clev" , "set center mix level" , OFFSET(clev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, +{"center_mix_level" , "set center mix level" , OFFSET(clev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, +{"slev" , "set surround mix level" , OFFSET(slev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, +{"surround_mix_level" , "set surround mix Level" , OFFSET(slev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, +{"lfe_mix_level" , "set LFE mix level" , OFFSET(lfe_mix_level ), AV_OPT_TYPE_FLOAT, {.dbl=0 }, -32 , 32 , PARAM}, +{"rmvol" , "set rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0 }, -1000 , 1000 , PARAM}, +{"rematrix_volume" , "set rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0 }, -1000 , 1000 , PARAM}, +{"rematrix_maxval" , "set rematrix maxval" , OFFSET(rematrix_maxval), AV_OPT_TYPE_FLOAT, {.dbl=0.0 }, 0 , 1000 , PARAM}, + +{"flags" , "set flags" , OFFSET(flags ), AV_OPT_TYPE_FLAGS, {.i64=0 }, 0 , UINT_MAX , PARAM, "flags"}, +{"swr_flags" , "set flags" , OFFSET(flags ), AV_OPT_TYPE_FLAGS, {.i64=0 }, 0 , UINT_MAX , PARAM, "flags"}, +{"res" , "force resampling" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_FLAG_RESAMPLE }, INT_MIN, INT_MAX , PARAM, "flags"}, + +{"dither_scale" , "set dither scale" , OFFSET(dither.scale ), AV_OPT_TYPE_FLOAT, {.dbl=1 }, 0 , INT_MAX , PARAM}, + +{"dither_method" , "set dither method" , OFFSET(user_dither_method),AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_DITHER_NB-1, PARAM, "dither_method"}, +{"rectangular" , "select rectangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_RECTANGULAR}, INT_MIN, INT_MAX , PARAM, "dither_method"}, +{"triangular" , "select triangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR }, INT_MIN, INT_MAX , PARAM, "dither_method"}, +{"triangular_hp" , "select triangular dither with high pass" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR_HIGHPASS }, INT_MIN, INT_MAX, PARAM, "dither_method"}, +{"lipshitz" , "select Lipshitz noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_LIPSHITZ}, INT_MIN, INT_MAX, PARAM, "dither_method"}, +{"shibata" , "select Shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"}, +{"low_shibata" , "select low Shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_LOW_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"}, +{"high_shibata" , "select high Shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_HIGH_SHIBATA }, INT_MIN, INT_MAX, PARAM, "dither_method"}, +{"f_weighted" , "select f-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_F_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"}, +{"modified_e_weighted" , "select modified-e-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_MODIFIED_E_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"}, +{"improved_e_weighted" , "select improved-e-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_IMPROVED_E_WEIGHTED }, INT_MIN, INT_MAX, PARAM, "dither_method"}, + +{"filter_size" , "set swr resampling filter size", OFFSET(filter_size) , AV_OPT_TYPE_INT , {.i64=32 }, 0 , INT_MAX , PARAM }, +{"phase_shift" , "set swr resampling phase shift", OFFSET(phase_shift) , AV_OPT_TYPE_INT , {.i64=10 }, 0 , 24 , PARAM }, +{"linear_interp" , "enable linear interpolation" , OFFSET(linear_interp) , AV_OPT_TYPE_BOOL , {.i64=1 }, 0 , 1 , PARAM }, +{"exact_rational" , "enable exact rational" , OFFSET(exact_rational) , AV_OPT_TYPE_BOOL , {.i64=1 }, 0 , 1 , PARAM }, +{"cutoff" , "set cutoff frequency ratio" , OFFSET(cutoff) , AV_OPT_TYPE_DOUBLE,{.dbl=0. }, 0 , 1 , PARAM }, + +/* duplicate option in order to work with avconv */ +{"resample_cutoff" , "set cutoff frequency ratio" , OFFSET(cutoff) , AV_OPT_TYPE_DOUBLE,{.dbl=0. }, 0 , 1 , PARAM }, + +{"resampler" , "set resampling Engine" , OFFSET(engine) , AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_ENGINE_NB-1, PARAM, "resampler"}, +{"swr" , "select SW Resampler" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_ENGINE_SWR }, INT_MIN, INT_MAX , PARAM, "resampler"}, +{"soxr" , "select SoX Resampler" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_ENGINE_SOXR }, INT_MIN, INT_MAX , PARAM, "resampler"}, +{"precision" , "set soxr resampling precision (in bits)" + , OFFSET(precision) , AV_OPT_TYPE_DOUBLE,{.dbl=20.0 }, 15.0 , 33.0 , PARAM }, +{"cheby" , "enable soxr Chebyshev passband & higher-precision irrational ratio approximation" + , OFFSET(cheby) , AV_OPT_TYPE_BOOL , {.i64=0 }, 0 , 1 , PARAM }, +{"min_comp" , "set minimum difference between timestamps and audio data (in seconds) below which no timestamp compensation of either kind is applied" + , OFFSET(min_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=FLT_MAX }, 0 , FLT_MAX , PARAM }, +{"min_hard_comp" , "set minimum difference between timestamps and audio data (in seconds) to trigger padding/trimming the data." + , OFFSET(min_hard_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0.1 }, 0 , INT_MAX , PARAM }, +{"comp_duration" , "set duration (in seconds) over which data is stretched/squeezed to make it match the timestamps." + , OFFSET(soft_compensation_duration),AV_OPT_TYPE_FLOAT ,{.dbl=1 }, 0 , INT_MAX , PARAM }, +{"max_soft_comp" , "set maximum factor by which data is stretched/squeezed to make it match the timestamps." + , OFFSET(max_soft_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0 }, INT_MIN, INT_MAX , PARAM }, +{"async" , "simplified 1 parameter audio timestamp matching, 0(disabled), 1(filling and trimming), >1(maximum stretch/squeeze in samples per second)" + , OFFSET(async) , AV_OPT_TYPE_FLOAT ,{.dbl=0 }, INT_MIN, INT_MAX , PARAM }, +{"first_pts" , "Assume the first pts should be this value (in samples)." + , OFFSET(firstpts_in_samples), AV_OPT_TYPE_INT64 ,{.i64=AV_NOPTS_VALUE }, INT64_MIN,INT64_MAX, PARAM }, + +{ "matrix_encoding" , "set matrixed stereo encoding" , OFFSET(matrix_encoding), AV_OPT_TYPE_INT ,{.i64 = AV_MATRIX_ENCODING_NONE}, AV_MATRIX_ENCODING_NONE, AV_MATRIX_ENCODING_NB-1, PARAM, "matrix_encoding" }, + { "none", "select none", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_NONE }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, + { "dolby", "select Dolby", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DOLBY }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, + { "dplii", "select Dolby Pro Logic II", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DPLII }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, + +{ "filter_type" , "select swr filter type" , OFFSET(filter_type) , AV_OPT_TYPE_INT , { .i64 = SWR_FILTER_TYPE_KAISER }, SWR_FILTER_TYPE_CUBIC, SWR_FILTER_TYPE_KAISER, PARAM, "filter_type" }, + { "cubic" , "select cubic" , 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_CUBIC }, INT_MIN, INT_MAX, PARAM, "filter_type" }, + { "blackman_nuttall", "select Blackman Nuttall windowed sinc", 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_BLACKMAN_NUTTALL }, INT_MIN, INT_MAX, PARAM, "filter_type" }, + { "kaiser" , "select Kaiser windowed sinc" , 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_KAISER }, INT_MIN, INT_MAX, PARAM, "filter_type" }, + +{ "kaiser_beta" , "set swr Kaiser window beta" , OFFSET(kaiser_beta) , AV_OPT_TYPE_DOUBLE , {.dbl=9 }, 2 , 16 , PARAM }, + +{ "output_sample_bits" , "set swr number of output sample bits", OFFSET(dither.output_sample_bits), AV_OPT_TYPE_INT , {.i64=0 }, 0 , 64 , PARAM }, +{0} +}; + +static const char* context_to_name(void* ptr) { + return "SWR"; +} + +static const AVClass av_class = { + .class_name = "SWResampler", + .item_name = context_to_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = OFFSET(log_level_offset), + .parent_log_context_offset = OFFSET(log_ctx), + .category = AV_CLASS_CATEGORY_SWRESAMPLER, +}; + +const AVClass *swr_get_class(void) +{ + return &av_class; +} + +av_cold struct SwrContext *swr_alloc(void){ + SwrContext *s= av_mallocz(sizeof(SwrContext)); + if(s){ + s->av_class= &av_class; + av_opt_set_defaults(s); + } + return s; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/rematrix.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/rematrix.c new file mode 100644 index 0000000000..6b5feaa07b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/rematrix.c @@ -0,0 +1,576 @@ +/* + * Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "swresample_internal.h" +#include "libavutil/avassert.h" +#include "libavutil/channel_layout.h" + +#define TEMPLATE_REMATRIX_FLT +#include "rematrix_template.c" +#undef TEMPLATE_REMATRIX_FLT + +#define TEMPLATE_REMATRIX_DBL +#include "rematrix_template.c" +#undef TEMPLATE_REMATRIX_DBL + +#define TEMPLATE_REMATRIX_S16 +#include "rematrix_template.c" +#define TEMPLATE_CLIP +#include "rematrix_template.c" +#undef TEMPLATE_CLIP +#undef TEMPLATE_REMATRIX_S16 + +#define TEMPLATE_REMATRIX_S32 +#include "rematrix_template.c" +#undef TEMPLATE_REMATRIX_S32 + +#define FRONT_LEFT 0 +#define FRONT_RIGHT 1 +#define FRONT_CENTER 2 +#define LOW_FREQUENCY 3 +#define BACK_LEFT 4 +#define BACK_RIGHT 5 +#define FRONT_LEFT_OF_CENTER 6 +#define FRONT_RIGHT_OF_CENTER 7 +#define BACK_CENTER 8 +#define SIDE_LEFT 9 +#define SIDE_RIGHT 10 +#define TOP_CENTER 11 +#define TOP_FRONT_LEFT 12 +#define TOP_FRONT_CENTER 13 +#define TOP_FRONT_RIGHT 14 +#define TOP_BACK_LEFT 15 +#define TOP_BACK_CENTER 16 +#define TOP_BACK_RIGHT 17 +#define NUM_NAMED_CHANNELS 18 + +int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride) +{ + int nb_in, nb_out, in, out; + + if (!s || s->in_convert) // s needs to be allocated but not initialized + return AVERROR(EINVAL); + memset(s->matrix, 0, sizeof(s->matrix)); + memset(s->matrix_flt, 0, sizeof(s->matrix_flt)); + nb_in = (s->user_in_ch_count > 0) ? s->user_in_ch_count : + av_get_channel_layout_nb_channels(s->user_in_ch_layout); + nb_out = (s->user_out_ch_count > 0) ? s->user_out_ch_count : + av_get_channel_layout_nb_channels(s->user_out_ch_layout); + for (out = 0; out < nb_out; out++) { + for (in = 0; in < nb_in; in++) + s->matrix_flt[out][in] = s->matrix[out][in] = matrix[in]; + matrix += stride; + } + s->rematrix_custom = 1; + return 0; +} + +static int even(int64_t layout){ + if(!layout) return 1; + if(layout&(layout-1)) return 1; + return 0; +} + +static int clean_layout(void *s, int64_t layout){ + if(layout && layout != AV_CH_FRONT_CENTER && !(layout&(layout-1))) { + char buf[128]; + av_get_channel_layout_string(buf, sizeof(buf), -1, layout); + av_log(s, AV_LOG_VERBOSE, "Treating %s as mono\n", buf); + return AV_CH_FRONT_CENTER; + } + + return layout; +} + +static int sane_layout(int64_t layout){ + if(!(layout & AV_CH_LAYOUT_SURROUND)) // at least 1 front speaker + return 0; + if(!even(layout & (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT))) // no asymetric front + return 0; + if(!even(layout & (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT))) // no asymetric side + return 0; + if(!even(layout & (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT))) + return 0; + if(!even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER))) + return 0; + if(av_get_channel_layout_nb_channels(layout) >= SWR_CH_MAX) + return 0; + + return 1; +} + +av_cold int swr_build_matrix(uint64_t in_ch_layout_param, uint64_t out_ch_layout_param, + double center_mix_level, double surround_mix_level, + double lfe_mix_level, double maxval, + double rematrix_volume, double *matrix_param, + int stride, enum AVMatrixEncoding matrix_encoding, void *log_context) +{ + int i, j, out_i; + double matrix[NUM_NAMED_CHANNELS][NUM_NAMED_CHANNELS]={{0}}; + int64_t unaccounted, in_ch_layout, out_ch_layout; + double maxcoef=0; + char buf[128]; + + in_ch_layout = clean_layout(log_context, in_ch_layout_param); + out_ch_layout = clean_layout(log_context, out_ch_layout_param); + + if( out_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX + && (in_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0 + ) + out_ch_layout = AV_CH_LAYOUT_STEREO; + + if( in_ch_layout == AV_CH_LAYOUT_STEREO_DOWNMIX + && (out_ch_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == 0 + ) + in_ch_layout = AV_CH_LAYOUT_STEREO; + + if(!sane_layout(in_ch_layout)){ + av_get_channel_layout_string(buf, sizeof(buf), -1, in_ch_layout_param); + av_log(log_context, AV_LOG_ERROR, "Input channel layout '%s' is not supported\n", buf); + return AVERROR(EINVAL); + } + + if(!sane_layout(out_ch_layout)){ + av_get_channel_layout_string(buf, sizeof(buf), -1, out_ch_layout_param); + av_log(log_context, AV_LOG_ERROR, "Output channel layout '%s' is not supported\n", buf); + return AVERROR(EINVAL); + } + + for(i=0; i maxval || rematrix_volume < 0){ + maxcoef /= maxval; + for(i=0; i 0){ + for(i=0; irematrix_maxval > 0) { + maxval = s->rematrix_maxval; + } else if ( av_get_packed_sample_fmt(s->out_sample_fmt) < AV_SAMPLE_FMT_FLT + || av_get_packed_sample_fmt(s->int_sample_fmt) < AV_SAMPLE_FMT_FLT) { + maxval = 1.0; + } else + maxval = INT_MAX; + + memset(s->matrix, 0, sizeof(s->matrix)); + ret = swr_build_matrix(s->in_ch_layout, s->out_ch_layout, + s->clev, s->slev, s->lfe_mix_level, + maxval, s->rematrix_volume, (double*)s->matrix, + s->matrix[1] - s->matrix[0], s->matrix_encoding, s); + + if (ret >= 0 && s->int_sample_fmt == AV_SAMPLE_FMT_FLTP) { + int i, j; + for (i = 0; i < FF_ARRAY_ELEMS(s->matrix[0]); i++) + for (j = 0; j < FF_ARRAY_ELEMS(s->matrix[0]); j++) + s->matrix_flt[i][j] = s->matrix[i][j]; + } + + return ret; +} + +av_cold int swri_rematrix_init(SwrContext *s){ + int i, j; + int nb_in = s->used_ch_count; + int nb_out = s->out.ch_count; + + s->mix_any_f = NULL; + + if (!s->rematrix_custom) { + int r = auto_matrix(s); + if (r) + return r; + } + if (s->midbuf.fmt == AV_SAMPLE_FMT_S16P){ + int maxsum = 0; + s->native_matrix = av_calloc(nb_in * nb_out, sizeof(int)); + s->native_one = av_mallocz(sizeof(int)); + if (!s->native_matrix || !s->native_one) + return AVERROR(ENOMEM); + for (i = 0; i < nb_out; i++) { + double rem = 0; + int sum = 0; + + for (j = 0; j < nb_in; j++) { + double target = s->matrix[i][j] * 32768 + rem; + ((int*)s->native_matrix)[i * nb_in + j] = lrintf(target); + rem += target - ((int*)s->native_matrix)[i * nb_in + j]; + sum += FFABS(((int*)s->native_matrix)[i * nb_in + j]); + } + maxsum = FFMAX(maxsum, sum); + } + *((int*)s->native_one) = 32768; + if (maxsum <= 32768) { + s->mix_1_1_f = (mix_1_1_func_type*)copy_s16; + s->mix_2_1_f = (mix_2_1_func_type*)sum2_s16; + s->mix_any_f = (mix_any_func_type*)get_mix_any_func_s16(s); + } else { + s->mix_1_1_f = (mix_1_1_func_type*)copy_clip_s16; + s->mix_2_1_f = (mix_2_1_func_type*)sum2_clip_s16; + s->mix_any_f = (mix_any_func_type*)get_mix_any_func_clip_s16(s); + } + }else if(s->midbuf.fmt == AV_SAMPLE_FMT_FLTP){ + s->native_matrix = av_calloc(nb_in * nb_out, sizeof(float)); + s->native_one = av_mallocz(sizeof(float)); + if (!s->native_matrix || !s->native_one) + return AVERROR(ENOMEM); + for (i = 0; i < nb_out; i++) + for (j = 0; j < nb_in; j++) + ((float*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j]; + *((float*)s->native_one) = 1.0; + s->mix_1_1_f = (mix_1_1_func_type*)copy_float; + s->mix_2_1_f = (mix_2_1_func_type*)sum2_float; + s->mix_any_f = (mix_any_func_type*)get_mix_any_func_float(s); + }else if(s->midbuf.fmt == AV_SAMPLE_FMT_DBLP){ + s->native_matrix = av_calloc(nb_in * nb_out, sizeof(double)); + s->native_one = av_mallocz(sizeof(double)); + if (!s->native_matrix || !s->native_one) + return AVERROR(ENOMEM); + for (i = 0; i < nb_out; i++) + for (j = 0; j < nb_in; j++) + ((double*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j]; + *((double*)s->native_one) = 1.0; + s->mix_1_1_f = (mix_1_1_func_type*)copy_double; + s->mix_2_1_f = (mix_2_1_func_type*)sum2_double; + s->mix_any_f = (mix_any_func_type*)get_mix_any_func_double(s); + }else if(s->midbuf.fmt == AV_SAMPLE_FMT_S32P){ + s->native_one = av_mallocz(sizeof(int)); + if (!s->native_one) + return AVERROR(ENOMEM); + s->native_matrix = av_calloc(nb_in * nb_out, sizeof(int)); + if (!s->native_matrix) { + av_freep(&s->native_one); + return AVERROR(ENOMEM); + } + for (i = 0; i < nb_out; i++) { + double rem = 0; + + for (j = 0; j < nb_in; j++) { + double target = s->matrix[i][j] * 32768 + rem; + ((int*)s->native_matrix)[i * nb_in + j] = lrintf(target); + rem += target - ((int*)s->native_matrix)[i * nb_in + j]; + } + } + *((int*)s->native_one) = 32768; + s->mix_1_1_f = (mix_1_1_func_type*)copy_s32; + s->mix_2_1_f = (mix_2_1_func_type*)sum2_s32; + s->mix_any_f = (mix_any_func_type*)get_mix_any_func_s32(s); + }else + av_assert0(0); + //FIXME quantize for integeres + for (i = 0; i < SWR_CH_MAX; i++) { + int ch_in=0; + for (j = 0; j < SWR_CH_MAX; j++) { + s->matrix32[i][j]= lrintf(s->matrix[i][j] * 32768); + if(s->matrix[i][j]) + s->matrix_ch[i][++ch_in]= j; + } + s->matrix_ch[i][0]= ch_in; + } + + if(HAVE_X86ASM && HAVE_MMX) + return swri_rematrix_init_x86(s); + + return 0; +} + +av_cold void swri_rematrix_free(SwrContext *s){ + av_freep(&s->native_matrix); + av_freep(&s->native_one); + av_freep(&s->native_simd_matrix); + av_freep(&s->native_simd_one); +} + +int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){ + int out_i, in_i, i, j; + int len1 = 0; + int off = 0; + + if(s->mix_any_f) { + s->mix_any_f(out->ch, (const uint8_t **)in->ch, s->native_matrix, len); + return 0; + } + + if(s->mix_2_1_simd || s->mix_1_1_simd){ + len1= len&~15; + off = len1 * out->bps; + } + + av_assert0(!s->out_ch_layout || out->ch_count == av_get_channel_layout_nb_channels(s->out_ch_layout)); + av_assert0(!s-> in_ch_layout || in ->ch_count == av_get_channel_layout_nb_channels(s-> in_ch_layout)); + + for(out_i=0; out_ich_count; out_i++){ + switch(s->matrix_ch[out_i][0]){ + case 0: + if(mustcopy) + memset(out->ch[out_i], 0, len * av_get_bytes_per_sample(s->int_sample_fmt)); + break; + case 1: + in_i= s->matrix_ch[out_i][1]; + if(s->matrix[out_i][in_i]!=1.0){ + if(s->mix_1_1_simd && len1) + s->mix_1_1_simd(out->ch[out_i] , in->ch[in_i] , s->native_simd_matrix, in->ch_count*out_i + in_i, len1); + if(len != len1) + s->mix_1_1_f (out->ch[out_i]+off, in->ch[in_i]+off, s->native_matrix, in->ch_count*out_i + in_i, len-len1); + }else if(mustcopy){ + memcpy(out->ch[out_i], in->ch[in_i], len*out->bps); + }else{ + out->ch[out_i]= in->ch[in_i]; + } + break; + case 2: { + int in_i1 = s->matrix_ch[out_i][1]; + int in_i2 = s->matrix_ch[out_i][2]; + if(s->mix_2_1_simd && len1) + s->mix_2_1_simd(out->ch[out_i] , in->ch[in_i1] , in->ch[in_i2] , s->native_simd_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1); + else + s->mix_2_1_f (out->ch[out_i] , in->ch[in_i1] , in->ch[in_i2] , s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1); + if(len != len1) + s->mix_2_1_f (out->ch[out_i]+off, in->ch[in_i1]+off, in->ch[in_i2]+off, s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len-len1); + break;} + default: + if(s->int_sample_fmt == AV_SAMPLE_FMT_FLTP){ + for(i=0; imatrix_ch[out_i][0]; j++){ + in_i= s->matrix_ch[out_i][1+j]; + v+= ((float*)in->ch[in_i])[i] * s->matrix_flt[out_i][in_i]; + } + ((float*)out->ch[out_i])[i]= v; + } + }else if(s->int_sample_fmt == AV_SAMPLE_FMT_DBLP){ + for(i=0; imatrix_ch[out_i][0]; j++){ + in_i= s->matrix_ch[out_i][1+j]; + v+= ((double*)in->ch[in_i])[i] * s->matrix[out_i][in_i]; + } + ((double*)out->ch[out_i])[i]= v; + } + }else{ + for(i=0; imatrix_ch[out_i][0]; j++){ + in_i= s->matrix_ch[out_i][1+j]; + v+= ((int16_t*)in->ch[in_i])[i] * s->matrix32[out_i][in_i]; + } + ((int16_t*)out->ch[out_i])[i]= (v + 16384)>>15; + } + } + } + } + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/rematrix_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/rematrix_template.c new file mode 100644 index 0000000000..add65e3155 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/rematrix_template.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if defined(TEMPLATE_REMATRIX_FLT) +# define R(x) x +# define SAMPLE float +# define COEFF float +# define INTER float +# define RENAME(x) x ## _float +#elif defined(TEMPLATE_REMATRIX_DBL) +# define R(x) x +# define SAMPLE double +# define COEFF double +# define INTER double +# define RENAME(x) x ## _double +#elif defined(TEMPLATE_REMATRIX_S16) +# define SAMPLE int16_t +# define COEFF int +# define INTER int +# ifdef TEMPLATE_CLIP +# define R(x) av_clip_int16(((x) + 16384)>>15) +# define RENAME(x) x ## _clip_s16 +# else +# define R(x) (((x) + 16384)>>15) +# define RENAME(x) x ## _s16 +# endif +#elif defined(TEMPLATE_REMATRIX_S32) +# define R(x) (((x) + 16384)>>15) +# define SAMPLE int32_t +# define COEFF int +# define INTER int64_t +# define RENAME(x) x ## _s32 +#endif + +typedef void (RENAME(mix_any_func_type))(SAMPLE **out, const SAMPLE **in1, COEFF *coeffp, integer len); + +static void RENAME(sum2)(SAMPLE *out, const SAMPLE *in1, const SAMPLE *in2, COEFF *coeffp, integer index1, integer index2, integer len){ + int i; + INTER coeff1 = coeffp[index1]; + INTER coeff2 = coeffp[index2]; + + for(i=0; iout_ch_layout == AV_CH_LAYOUT_STEREO && (s->in_ch_layout == AV_CH_LAYOUT_5POINT1 || s->in_ch_layout == AV_CH_LAYOUT_5POINT1_BACK) + && s->matrix[0][2] == s->matrix[1][2] && s->matrix[0][3] == s->matrix[1][3] + && !s->matrix[0][1] && !s->matrix[0][5] && !s->matrix[1][0] && !s->matrix[1][4] + ) + return RENAME(mix6to2); + + if( s->out_ch_layout == AV_CH_LAYOUT_STEREO && s->in_ch_layout == AV_CH_LAYOUT_7POINT1 + && s->matrix[0][2] == s->matrix[1][2] && s->matrix[0][3] == s->matrix[1][3] + && !s->matrix[0][1] && !s->matrix[0][5] && !s->matrix[1][0] && !s->matrix[1][4] + && !s->matrix[0][7] && !s->matrix[1][6] + ) + return RENAME(mix8to2); + + return NULL; +} + +#undef R +#undef SAMPLE +#undef COEFF +#undef INTER +#undef RENAME diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample.c new file mode 100644 index 0000000000..df49505bf9 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample.c @@ -0,0 +1,622 @@ +/* + * audio resampling + * Copyright (c) 2004-2012 Michael Niedermayer + * bessel function: Copyright (c) 2006 Xiaogang Zhang + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio resampling + * @author Michael Niedermayer + */ + +#include "libavutil/avassert.h" +#include "resample.h" + +static inline double eval_poly(const double *coeff, int size, double x) { + double sum = coeff[size-1]; + int i; + for (i = size-2; i >= 0; --i) { + sum *= x; + sum += coeff[i]; + } + return sum; +} + +/** + * 0th order modified bessel function of the first kind. + * Algorithm taken from the Boost project, source: + * https://searchcode.com/codesearch/view/14918379/ + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0 (see notice below). + * Boost Software License - Version 1.0 - August 17th, 2003 +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + */ + +static double bessel(double x) { +// Modified Bessel function of the first kind of order zero +// minimax rational approximations on intervals, see +// Blair and Edwards, Chalk River Report AECL-4928, 1974 + static const double p1[] = { + -2.2335582639474375249e+15, + -5.5050369673018427753e+14, + -3.2940087627407749166e+13, + -8.4925101247114157499e+11, + -1.1912746104985237192e+10, + -1.0313066708737980747e+08, + -5.9545626019847898221e+05, + -2.4125195876041896775e+03, + -7.0935347449210549190e+00, + -1.5453977791786851041e-02, + -2.5172644670688975051e-05, + -3.0517226450451067446e-08, + -2.6843448573468483278e-11, + -1.5982226675653184646e-14, + -5.2487866627945699800e-18, + }; + static const double q1[] = { + -2.2335582639474375245e+15, + 7.8858692566751002988e+12, + -1.2207067397808979846e+10, + 1.0377081058062166144e+07, + -4.8527560179962773045e+03, + 1.0, + }; + static const double p2[] = { + -2.2210262233306573296e-04, + 1.3067392038106924055e-02, + -4.4700805721174453923e-01, + 5.5674518371240761397e+00, + -2.3517945679239481621e+01, + 3.1611322818701131207e+01, + -9.6090021968656180000e+00, + }; + static const double q2[] = { + -5.5194330231005480228e-04, + 3.2547697594819615062e-02, + -1.1151759188741312645e+00, + 1.3982595353892851542e+01, + -6.0228002066743340583e+01, + 8.5539563258012929600e+01, + -3.1446690275135491500e+01, + 1.0, + }; + double y, r, factor; + if (x == 0) + return 1.0; + x = fabs(x); + if (x <= 15) { + y = x * x; + return eval_poly(p1, FF_ARRAY_ELEMS(p1), y) / eval_poly(q1, FF_ARRAY_ELEMS(q1), y); + } + else { + y = 1 / x - 1.0 / 15; + r = eval_poly(p2, FF_ARRAY_ELEMS(p2), y) / eval_poly(q2, FF_ARRAY_ELEMS(q2), y); + factor = exp(x) / sqrt(x); + return factor * r; + } +} + +/** + * builds a polyphase filterbank. + * @param factor resampling factor + * @param scale wanted sum of coefficients for each filter + * @param filter_type filter type + * @param kaiser_beta kaiser window beta + * @return 0 on success, negative on error + */ +static int build_filter(ResampleContext *c, void *filter, double factor, int tap_count, int alloc, int phase_count, int scale, + int filter_type, double kaiser_beta){ + int ph, i; + int ph_nb = phase_count % 2 ? phase_count : phase_count / 2 + 1; + double x, y, w, t, s; + double *tab = av_malloc_array(tap_count+1, sizeof(*tab)); + double *sin_lut = av_malloc_array(ph_nb, sizeof(*sin_lut)); + const int center= (tap_count-1)/2; + double norm = 0; + int ret = AVERROR(ENOMEM); + + if (!tab || !sin_lut) + goto fail; + + av_assert0(tap_count == 1 || tap_count % 2 == 0); + + /* if upsampling, only need to interpolate, no filter */ + if (factor > 1.0) + factor = 1.0; + + if (factor == 1.0) { + for (ph = 0; ph < ph_nb; ph++) + sin_lut[ph] = sin(M_PI * ph / phase_count) * (center & 1 ? 1 : -1); + } + for(ph = 0; ph < ph_nb; ph++) { + s = sin_lut[ph]; + for(i=0;iformat){ + case AV_SAMPLE_FMT_S16P: + for(i=0;ifilter_bank); + av_freep(cc); +} + +static ResampleContext *resample_init(ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, + double cutoff0, enum AVSampleFormat format, enum SwrFilterType filter_type, double kaiser_beta, + double precision, int cheby, int exact_rational) +{ + double cutoff = cutoff0? cutoff0 : 0.97; + double factor= FFMIN(out_rate * cutoff / in_rate, 1.0); + int phase_count= 1< 1) + filter_length = FFALIGN(filter_length, 2); + + if (exact_rational) { + int phase_count_exact, phase_count_exact_den; + + av_reduce(&phase_count_exact, &phase_count_exact_den, out_rate, in_rate, INT_MAX); + if (phase_count_exact <= phase_count) { + phase_count_compensation = phase_count_exact * (phase_count / phase_count_exact); + phase_count = phase_count_exact; + } + } + + if (!c || c->phase_count != phase_count || c->linear!=linear || c->factor != factor + || c->filter_length != filter_length || c->format != format + || c->filter_type != filter_type || c->kaiser_beta != kaiser_beta) { + resample_free(&c); + c = av_mallocz(sizeof(*c)); + if (!c) + return NULL; + + c->format= format; + + c->felem_size= av_get_bytes_per_sample(c->format); + + switch(c->format){ + case AV_SAMPLE_FMT_S16P: + c->filter_shift = 15; + break; + case AV_SAMPLE_FMT_S32P: + c->filter_shift = 30; + break; + case AV_SAMPLE_FMT_FLTP: + case AV_SAMPLE_FMT_DBLP: + c->filter_shift = 0; + break; + default: + av_log(NULL, AV_LOG_ERROR, "Unsupported sample format\n"); + av_assert0(0); + } + + if (filter_size/factor > INT32_MAX/256) { + av_log(NULL, AV_LOG_ERROR, "Filter length too large\n"); + goto error; + } + + c->phase_count = phase_count; + c->linear = linear; + c->factor = factor; + c->filter_length = filter_length; + c->filter_alloc = FFALIGN(c->filter_length, 8); + c->filter_bank = av_calloc(c->filter_alloc, (phase_count+1)*c->felem_size); + c->filter_type = filter_type; + c->kaiser_beta = kaiser_beta; + c->phase_count_compensation = phase_count_compensation; + if (!c->filter_bank) + goto error; + if (build_filter(c, (void*)c->filter_bank, factor, c->filter_length, c->filter_alloc, phase_count, 1<filter_shift, filter_type, kaiser_beta)) + goto error; + memcpy(c->filter_bank + (c->filter_alloc*phase_count+1)*c->felem_size, c->filter_bank, (c->filter_alloc-1)*c->felem_size); + memcpy(c->filter_bank + (c->filter_alloc*phase_count )*c->felem_size, c->filter_bank + (c->filter_alloc - 1)*c->felem_size, c->felem_size); + } + + c->compensation_distance= 0; + if(!av_reduce(&c->src_incr, &c->dst_incr, out_rate, in_rate * (int64_t)phase_count, INT32_MAX/2)) + goto error; + while (c->dst_incr < (1<<20) && c->src_incr < (1<<20)) { + c->dst_incr *= 2; + c->src_incr *= 2; + } + c->ideal_dst_incr = c->dst_incr; + c->dst_incr_div = c->dst_incr / c->src_incr; + c->dst_incr_mod = c->dst_incr % c->src_incr; + + c->index= -phase_count*((c->filter_length-1)/2); + c->frac= 0; + + swri_resample_dsp_init(c); + + return c; +error: + av_freep(&c->filter_bank); + av_free(c); + return NULL; +} + +static int rebuild_filter_bank_with_compensation(ResampleContext *c) +{ + uint8_t *new_filter_bank; + int new_src_incr, new_dst_incr; + int phase_count = c->phase_count_compensation; + int ret; + + if (phase_count == c->phase_count) + return 0; + + av_assert0(!c->frac && !c->dst_incr_mod); + + new_filter_bank = av_calloc(c->filter_alloc, (phase_count + 1) * c->felem_size); + if (!new_filter_bank) + return AVERROR(ENOMEM); + + ret = build_filter(c, new_filter_bank, c->factor, c->filter_length, c->filter_alloc, + phase_count, 1 << c->filter_shift, c->filter_type, c->kaiser_beta); + if (ret < 0) { + av_freep(&new_filter_bank); + return ret; + } + memcpy(new_filter_bank + (c->filter_alloc*phase_count+1)*c->felem_size, new_filter_bank, (c->filter_alloc-1)*c->felem_size); + memcpy(new_filter_bank + (c->filter_alloc*phase_count )*c->felem_size, new_filter_bank + (c->filter_alloc - 1)*c->felem_size, c->felem_size); + + if (!av_reduce(&new_src_incr, &new_dst_incr, c->src_incr, + c->dst_incr * (int64_t)(phase_count/c->phase_count), INT32_MAX/2)) + { + av_freep(&new_filter_bank); + return AVERROR(EINVAL); + } + + c->src_incr = new_src_incr; + c->dst_incr = new_dst_incr; + while (c->dst_incr < (1<<20) && c->src_incr < (1<<20)) { + c->dst_incr *= 2; + c->src_incr *= 2; + } + c->ideal_dst_incr = c->dst_incr; + c->dst_incr_div = c->dst_incr / c->src_incr; + c->dst_incr_mod = c->dst_incr % c->src_incr; + c->index *= phase_count / c->phase_count; + c->phase_count = phase_count; + av_freep(&c->filter_bank); + c->filter_bank = new_filter_bank; + return 0; +} + +static int set_compensation(ResampleContext *c, int sample_delta, int compensation_distance){ + int ret; + + if (compensation_distance && sample_delta) { + ret = rebuild_filter_bank_with_compensation(c); + if (ret < 0) + return ret; + } + + c->compensation_distance= compensation_distance; + if (compensation_distance) + c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance; + else + c->dst_incr = c->ideal_dst_incr; + + c->dst_incr_div = c->dst_incr / c->src_incr; + c->dst_incr_mod = c->dst_incr % c->src_incr; + + return 0; +} + +static int multiple_resample(ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed){ + int i; + int av_unused mm_flags = av_get_cpu_flags(); + int need_emms = c->format == AV_SAMPLE_FMT_S16P && ARCH_X86_32 && + (mm_flags & (AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_SSE2)) == AV_CPU_FLAG_MMX2; + int64_t max_src_size = (INT64_MAX/2 / c->phase_count) / c->src_incr; + + if (c->compensation_distance) + dst_size = FFMIN(dst_size, c->compensation_distance); + src_size = FFMIN(src_size, max_src_size); + + *consumed = 0; + + if (c->filter_length == 1 && c->phase_count == 1) { + int64_t index2= (1LL<<32)*c->frac/c->src_incr + (1LL<<32)*c->index; + int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr; + int new_size = (src_size * (int64_t)c->src_incr - c->frac + c->dst_incr - 1) / c->dst_incr; + + dst_size = FFMAX(FFMIN(dst_size, new_size), 0); + if (dst_size > 0) { + for (i = 0; i < dst->ch_count; i++) { + c->dsp.resample_one(dst->ch[i], src->ch[i], dst_size, index2, incr); + if (i+1 == dst->ch_count) { + c->index += dst_size * c->dst_incr_div; + c->index += (c->frac + dst_size * (int64_t)c->dst_incr_mod) / c->src_incr; + av_assert2(c->index >= 0); + *consumed = c->index; + c->frac = (c->frac + dst_size * (int64_t)c->dst_incr_mod) % c->src_incr; + c->index = 0; + } + } + } + } else { + int64_t end_index = (1LL + src_size - c->filter_length) * c->phase_count; + int64_t delta_frac = (end_index - c->index) * c->src_incr - c->frac; + int delta_n = (delta_frac + c->dst_incr - 1) / c->dst_incr; + int (*resample_func)(struct ResampleContext *c, void *dst, + const void *src, int n, int update_ctx); + + dst_size = FFMAX(FFMIN(dst_size, delta_n), 0); + if (dst_size > 0) { + /* resample_linear and resample_common should have same behavior + * when frac and dst_incr_mod are zero */ + resample_func = (c->linear && (c->frac || c->dst_incr_mod)) ? + c->dsp.resample_linear : c->dsp.resample_common; + for (i = 0; i < dst->ch_count; i++) + *consumed = resample_func(c, dst->ch[i], src->ch[i], dst_size, i+1 == dst->ch_count); + } + } + + if(need_emms) + emms_c(); + + if (c->compensation_distance) { + c->compensation_distance -= dst_size; + if (!c->compensation_distance) { + c->dst_incr = c->ideal_dst_incr; + c->dst_incr_div = c->dst_incr / c->src_incr; + c->dst_incr_mod = c->dst_incr % c->src_incr; + } + } + + return dst_size; +} + +static int64_t get_delay(struct SwrContext *s, int64_t base){ + ResampleContext *c = s->resample; + int64_t num = s->in_buffer_count - (c->filter_length-1)/2; + num *= c->phase_count; + num -= c->index; + num *= c->src_incr; + num -= c->frac; + return av_rescale(num, base, s->in_sample_rate*(int64_t)c->src_incr * c->phase_count); +} + +static int64_t get_out_samples(struct SwrContext *s, int in_samples) { + ResampleContext *c = s->resample; + // The + 2 are added to allow implementations to be slightly inaccurate, they should not be needed currently. + // They also make it easier to proof that changes and optimizations do not + // break the upper bound. + int64_t num = s->in_buffer_count + 2LL + in_samples; + num *= c->phase_count; + num -= c->index; + num = av_rescale_rnd(num, s->out_sample_rate, ((int64_t)s->in_sample_rate) * c->phase_count, AV_ROUND_UP) + 2; + + if (c->compensation_distance) { + if (num > INT_MAX) + return AVERROR(EINVAL); + + num = FFMAX(num, (num * c->ideal_dst_incr - 1) / c->dst_incr + 1); + } + return num; +} + +static int resample_flush(struct SwrContext *s) { + ResampleContext *c = s->resample; + AudioData *a= &s->in_buffer; + int i, j, ret; + int reflection = (FFMIN(s->in_buffer_count, c->filter_length) + 1) / 2; + + if((ret = swri_realloc_audio(a, s->in_buffer_index + s->in_buffer_count + reflection)) < 0) + return ret; + av_assert0(a->planar); + for(i=0; ich_count; i++){ + for(j=0; jch[i] + (s->in_buffer_index+s->in_buffer_count+j )*a->bps, + a->ch[i] + (s->in_buffer_index+s->in_buffer_count-j-1)*a->bps, a->bps); + } + } + s->in_buffer_count += reflection; + return 0; +} + +// in fact the whole handle multiple ridiculously small buffers might need more thinking... +static int invert_initial_buffer(ResampleContext *c, AudioData *dst, const AudioData *src, + int in_count, int *out_idx, int *out_sz) +{ + int n, ch, num = FFMIN(in_count + *out_sz, c->filter_length + 1), res; + + if (c->index >= 0) + return 0; + + if ((res = swri_realloc_audio(dst, c->filter_length * 2 + 1)) < 0) + return res; + + // copy + for (n = *out_sz; n < num; n++) { + for (ch = 0; ch < src->ch_count; ch++) { + memcpy(dst->ch[ch] + ((c->filter_length + n) * c->felem_size), + src->ch[ch] + ((n - *out_sz) * c->felem_size), c->felem_size); + } + } + + // if not enough data is in, return and wait for more + if (num < c->filter_length + 1) { + *out_sz = num; + *out_idx = c->filter_length; + return INT_MAX; + } + + // else invert + for (n = 1; n <= c->filter_length; n++) { + for (ch = 0; ch < src->ch_count; ch++) { + memcpy(dst->ch[ch] + ((c->filter_length - n) * c->felem_size), + dst->ch[ch] + ((c->filter_length + n) * c->felem_size), + c->felem_size); + } + } + + res = num - *out_sz; + *out_idx = c->filter_length; + while (c->index < 0) { + --*out_idx; + c->index += c->phase_count; + } + *out_sz = FFMAX(*out_sz + c->filter_length, + 1 + c->filter_length * 2) - *out_idx; + + return FFMAX(res, 0); +} + +struct Resampler const swri_resampler={ + resample_init, + resample_free, + multiple_resample, + resample_flush, + set_compensation, + get_delay, + invert_initial_buffer, + get_out_samples, +}; diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample.h b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample.h new file mode 100644 index 0000000000..1731dad3cf --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample.h @@ -0,0 +1,68 @@ +/* + * audio resampling + * Copyright (c) 2004-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_RESAMPLE_H +#define SWRESAMPLE_RESAMPLE_H + +#include "libavutil/log.h" +#include "libavutil/samplefmt.h" + +#include "swresample_internal.h" + +typedef struct ResampleContext { + const AVClass *av_class; + uint8_t *filter_bank; + int filter_length; + int filter_alloc; + int ideal_dst_incr; + int dst_incr; + int dst_incr_div; + int dst_incr_mod; + int index; + int frac; + int src_incr; + int compensation_distance; + int phase_count; + int linear; + enum SwrFilterType filter_type; + double kaiser_beta; + double factor; + enum AVSampleFormat format; + int felem_size; + int filter_shift; + int phase_count_compensation; /* desired phase_count when compensation is enabled */ + + struct { + void (*resample_one)(void *dst, const void *src, + int n, int64_t index, int64_t incr); + int (*resample_common)(struct ResampleContext *c, void *dst, + const void *src, int n, int update_ctx); + int (*resample_linear)(struct ResampleContext *c, void *dst, + const void *src, int n, int update_ctx); + } dsp; +} ResampleContext; + +void swri_resample_dsp_init(ResampleContext *c); +void swri_resample_dsp_x86_init(ResampleContext *c); +void swri_resample_dsp_arm_init(ResampleContext *c); +void swri_resample_dsp_aarch64_init(ResampleContext *c); + +#endif /* SWRESAMPLE_RESAMPLE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample_dsp.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample_dsp.c new file mode 100644 index 0000000000..b2424eb6f7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample_dsp.c @@ -0,0 +1,74 @@ +/* + * audio resampling + * Copyright (c) 2004-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio resampling + * @author Michael Niedermayer + */ + +#include "resample.h" + +#define TEMPLATE_RESAMPLE_S16 +#include "resample_template.c" +#undef TEMPLATE_RESAMPLE_S16 + +#define TEMPLATE_RESAMPLE_S32 +#include "resample_template.c" +#undef TEMPLATE_RESAMPLE_S32 + +#define TEMPLATE_RESAMPLE_FLT +#include "resample_template.c" +#undef TEMPLATE_RESAMPLE_FLT + +#define TEMPLATE_RESAMPLE_DBL +#include "resample_template.c" +#undef TEMPLATE_RESAMPLE_DBL + +void swri_resample_dsp_init(ResampleContext *c) +{ + switch(c->format){ + case AV_SAMPLE_FMT_S16P: + c->dsp.resample_one = resample_one_int16; + c->dsp.resample_common = resample_common_int16; + c->dsp.resample_linear = resample_linear_int16; + break; + case AV_SAMPLE_FMT_S32P: + c->dsp.resample_one = resample_one_int32; + c->dsp.resample_common = resample_common_int32; + c->dsp.resample_linear = resample_linear_int32; + break; + case AV_SAMPLE_FMT_FLTP: + c->dsp.resample_one = resample_one_float; + c->dsp.resample_common = resample_common_float; + c->dsp.resample_linear = resample_linear_float; + break; + case AV_SAMPLE_FMT_DBLP: + c->dsp.resample_one = resample_one_double; + c->dsp.resample_common = resample_common_double; + c->dsp.resample_linear = resample_linear_double; + break; + } + + if (ARCH_X86) swri_resample_dsp_x86_init(c); + else if (ARCH_ARM) swri_resample_dsp_arm_init(c); + else if (ARCH_AARCH64) swri_resample_dsp_aarch64_init(c); +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample_template.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample_template.c new file mode 100644 index 0000000000..4c227b9940 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/resample_template.c @@ -0,0 +1,212 @@ +/* + * audio resampling + * Copyright (c) 2004-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio resampling + * @author Michael Niedermayer + */ + +#if defined(TEMPLATE_RESAMPLE_DBL) + +# define RENAME(N) N ## _double +# define FILTER_SHIFT 0 +# define DELEM double +# define FELEM double +# define FELEM2 double +# define FOFFSET 0 +# define OUT(d, v) d = v + +#elif defined(TEMPLATE_RESAMPLE_FLT) + +# define RENAME(N) N ## _float +# define FILTER_SHIFT 0 +# define DELEM float +# define FELEM float +# define FELEM2 float +# define FOFFSET 0 +# define OUT(d, v) d = v + +#elif defined(TEMPLATE_RESAMPLE_S32) + +# define RENAME(N) N ## _int32 +# define FILTER_SHIFT 30 +# define DELEM int32_t +# define FELEM int32_t +# define FELEM2 int64_t +# define FELEM_MAX INT32_MAX +# define FELEM_MIN INT32_MIN +# define FOFFSET (1<<(FILTER_SHIFT-1)) +# define OUT(d, v) (d) = av_clipl_int32((v)>>FILTER_SHIFT) + +#elif defined(TEMPLATE_RESAMPLE_S16) + +# define RENAME(N) N ## _int16 +# define FILTER_SHIFT 15 +# define DELEM int16_t +# define FELEM int16_t +# define FELEM2 int32_t +# define FELEML int64_t +# define FELEM_MAX INT16_MAX +# define FELEM_MIN INT16_MIN +# define FOFFSET (1<<(FILTER_SHIFT-1)) +# define OUT(d, v) (d) = av_clip_int16((v)>>FILTER_SHIFT) + +#endif + +static void RENAME(resample_one)(void *dest, const void *source, + int dst_size, int64_t index2, int64_t incr) +{ + DELEM *dst = dest; + const DELEM *src = source; + int dst_index; + + for (dst_index = 0; dst_index < dst_size; dst_index++) { + dst[dst_index] = src[index2 >> 32]; + index2 += incr; + } +} + +static int RENAME(resample_common)(ResampleContext *c, + void *dest, const void *source, + int n, int update_ctx) +{ + DELEM *dst = dest; + const DELEM *src = source; + int dst_index; + int index= c->index; + int frac= c->frac; + int sample_index = 0; + + while (index >= c->phase_count) { + sample_index++; + index -= c->phase_count; + } + + for (dst_index = 0; dst_index < n; dst_index++) { + FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index; + + FELEM2 val = FOFFSET; + FELEM2 val2= 0; + int i; + for (i = 0; i + 1 < c->filter_length; i+=2) { + val += src[sample_index + i ] * (FELEM2)filter[i ]; + val2 += src[sample_index + i + 1] * (FELEM2)filter[i + 1]; + } + if (i < c->filter_length) + val += src[sample_index + i ] * (FELEM2)filter[i ]; +#ifdef FELEML + OUT(dst[dst_index], val + (FELEML)val2); +#else + OUT(dst[dst_index], val + val2); +#endif + + frac += c->dst_incr_mod; + index += c->dst_incr_div; + if (frac >= c->src_incr) { + frac -= c->src_incr; + index++; + } + + while (index >= c->phase_count) { + sample_index++; + index -= c->phase_count; + } + } + + if(update_ctx){ + c->frac= frac; + c->index= index; + } + + return sample_index; +} + +static int RENAME(resample_linear)(ResampleContext *c, + void *dest, const void *source, + int n, int update_ctx) +{ + DELEM *dst = dest; + const DELEM *src = source; + int dst_index; + int index= c->index; + int frac= c->frac; + int sample_index = 0; +#if FILTER_SHIFT == 0 + double inv_src_incr = 1.0 / c->src_incr; +#endif + + while (index >= c->phase_count) { + sample_index++; + index -= c->phase_count; + } + + for (dst_index = 0; dst_index < n; dst_index++) { + FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index; + FELEM2 val = FOFFSET, v2 = FOFFSET; + + int i; + for (i = 0; i < c->filter_length; i++) { + val += src[sample_index + i] * (FELEM2)filter[i]; + v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_alloc]; + } +#ifdef FELEML + val += (v2 - val) * (FELEML) frac / c->src_incr; +#else +# if FILTER_SHIFT == 0 + val += (v2 - val) * inv_src_incr * frac; +# else + val += (v2 - val) / c->src_incr * frac; +# endif +#endif + OUT(dst[dst_index], val); + + frac += c->dst_incr_mod; + index += c->dst_incr_div; + if (frac >= c->src_incr) { + frac -= c->src_incr; + index++; + } + + while (index >= c->phase_count) { + sample_index++; + index -= c->phase_count; + } + } + + if(update_ctx){ + c->frac= frac; + c->index= index; + } + + return sample_index; +} + +#undef RENAME +#undef FILTER_SHIFT +#undef DELEM +#undef FELEM +#undef FELEM2 +#undef FELEML +#undef FELEM_MAX +#undef FELEM_MIN +#undef OUT +#undef FOFFSET diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample.c new file mode 100644 index 0000000000..1ac5ef9a30 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample.c @@ -0,0 +1,949 @@ +/* + * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "swresample_internal.h" +#include "audioconvert.h" +#include "libavutil/avassert.h" +#include "libavutil/channel_layout.h" +#include "libavutil/internal.h" + +#include + +#define ALIGN 32 + +#include "libavutil/ffversion.h" +const char swr_ffversion[] = "FFmpeg version " FFMPEG_VERSION; + +unsigned swresample_version(void) +{ + av_assert0(LIBSWRESAMPLE_VERSION_MICRO >= 100); + return LIBSWRESAMPLE_VERSION_INT; +} + +const char *swresample_configuration(void) +{ + return FFMPEG_CONFIGURATION; +} + +const char *swresample_license(void) +{ +#define LICENSE_PREFIX "libswresample license: " + return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; +} + +int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map){ + if(!s || s->in_convert) // s needs to be allocated but not initialized + return AVERROR(EINVAL); + s->channel_map = channel_map; + return 0; +} + +struct SwrContext *swr_alloc_set_opts(struct SwrContext *s, + int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, + int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, + int log_offset, void *log_ctx){ + if(!s) s= swr_alloc(); + if(!s) return NULL; + + s->log_level_offset= log_offset; + s->log_ctx= log_ctx; + + if (av_opt_set_int(s, "ocl", out_ch_layout, 0) < 0) + goto fail; + + if (av_opt_set_int(s, "osf", out_sample_fmt, 0) < 0) + goto fail; + + if (av_opt_set_int(s, "osr", out_sample_rate, 0) < 0) + goto fail; + + if (av_opt_set_int(s, "icl", in_ch_layout, 0) < 0) + goto fail; + + if (av_opt_set_int(s, "isf", in_sample_fmt, 0) < 0) + goto fail; + + if (av_opt_set_int(s, "isr", in_sample_rate, 0) < 0) + goto fail; + + if (av_opt_set_int(s, "ich", av_get_channel_layout_nb_channels(s-> user_in_ch_layout), 0) < 0) + goto fail; + + if (av_opt_set_int(s, "och", av_get_channel_layout_nb_channels(s->user_out_ch_layout), 0) < 0) + goto fail; + + av_opt_set_int(s, "uch", 0, 0); + return s; +fail: + av_log(s, AV_LOG_ERROR, "Failed to set option\n"); + swr_free(&s); + return NULL; +} + +static void set_audiodata_fmt(AudioData *a, enum AVSampleFormat fmt){ + a->fmt = fmt; + a->bps = av_get_bytes_per_sample(fmt); + a->planar= av_sample_fmt_is_planar(fmt); + if (a->ch_count == 1) + a->planar = 1; +} + +static void free_temp(AudioData *a){ + av_free(a->data); + memset(a, 0, sizeof(*a)); +} + +static void clear_context(SwrContext *s){ + s->in_buffer_index= 0; + s->in_buffer_count= 0; + s->resample_in_constraint= 0; + memset(s->in.ch, 0, sizeof(s->in.ch)); + memset(s->out.ch, 0, sizeof(s->out.ch)); + free_temp(&s->postin); + free_temp(&s->midbuf); + free_temp(&s->preout); + free_temp(&s->in_buffer); + free_temp(&s->silence); + free_temp(&s->drop_temp); + free_temp(&s->dither.noise); + free_temp(&s->dither.temp); + swri_audio_convert_free(&s-> in_convert); + swri_audio_convert_free(&s->out_convert); + swri_audio_convert_free(&s->full_convert); + swri_rematrix_free(s); + + s->delayed_samples_fixup = 0; + s->flushed = 0; +} + +av_cold void swr_free(SwrContext **ss){ + SwrContext *s= *ss; + if(s){ + clear_context(s); + if (s->resampler) + s->resampler->free(&s->resample); + } + + av_freep(ss); +} + +av_cold void swr_close(SwrContext *s){ + clear_context(s); +} + +av_cold int swr_init(struct SwrContext *s){ + int ret; + char l1[1024], l2[1024]; + + clear_context(s); + + if(s-> in_sample_fmt >= AV_SAMPLE_FMT_NB){ + av_log(s, AV_LOG_ERROR, "Requested input sample format %d is invalid\n", s->in_sample_fmt); + return AVERROR(EINVAL); + } + if(s->out_sample_fmt >= AV_SAMPLE_FMT_NB){ + av_log(s, AV_LOG_ERROR, "Requested output sample format %d is invalid\n", s->out_sample_fmt); + return AVERROR(EINVAL); + } + + if(s-> in_sample_rate <= 0){ + av_log(s, AV_LOG_ERROR, "Requested input sample rate %d is invalid\n", s->in_sample_rate); + return AVERROR(EINVAL); + } + if(s->out_sample_rate <= 0){ + av_log(s, AV_LOG_ERROR, "Requested output sample rate %d is invalid\n", s->out_sample_rate); + return AVERROR(EINVAL); + } + s->out.ch_count = s-> user_out_ch_count; + s-> in.ch_count = s-> user_in_ch_count; + s->used_ch_count = s->user_used_ch_count; + + s-> in_ch_layout = s-> user_in_ch_layout; + s->out_ch_layout = s->user_out_ch_layout; + + s->int_sample_fmt= s->user_int_sample_fmt; + + s->dither.method = s->user_dither_method; + + if(av_get_channel_layout_nb_channels(s-> in_ch_layout) > SWR_CH_MAX) { + av_log(s, AV_LOG_WARNING, "Input channel layout 0x%"PRIx64" is invalid or unsupported.\n", s-> in_ch_layout); + s->in_ch_layout = 0; + } + + if(av_get_channel_layout_nb_channels(s->out_ch_layout) > SWR_CH_MAX) { + av_log(s, AV_LOG_WARNING, "Output channel layout 0x%"PRIx64" is invalid or unsupported.\n", s->out_ch_layout); + s->out_ch_layout = 0; + } + + switch(s->engine){ +#if CONFIG_LIBSOXR + case SWR_ENGINE_SOXR: s->resampler = &swri_soxr_resampler; break; +#endif + case SWR_ENGINE_SWR : s->resampler = &swri_resampler; break; + default: + av_log(s, AV_LOG_ERROR, "Requested resampling engine is unavailable\n"); + return AVERROR(EINVAL); + } + + if(!s->used_ch_count) + s->used_ch_count= s->in.ch_count; + + if(s->used_ch_count && s-> in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s-> in_ch_layout)){ + av_log(s, AV_LOG_WARNING, "Input channel layout has a different number of channels than the number of used channels, ignoring layout\n"); + s-> in_ch_layout= 0; + } + + if(!s-> in_ch_layout) + s-> in_ch_layout= av_get_default_channel_layout(s->used_ch_count); + if(!s->out_ch_layout) + s->out_ch_layout= av_get_default_channel_layout(s->out.ch_count); + + s->rematrix= s->out_ch_layout !=s->in_ch_layout || s->rematrix_volume!=1.0 || + s->rematrix_custom; + + if(s->int_sample_fmt == AV_SAMPLE_FMT_NONE){ + if( av_get_bytes_per_sample(s-> in_sample_fmt) <= 2 + && av_get_bytes_per_sample(s->out_sample_fmt) <= 2){ + s->int_sample_fmt= AV_SAMPLE_FMT_S16P; + }else if( av_get_bytes_per_sample(s-> in_sample_fmt) <= 2 + && !s->rematrix + && s->out_sample_rate==s->in_sample_rate + && !(s->flags & SWR_FLAG_RESAMPLE)){ + s->int_sample_fmt= AV_SAMPLE_FMT_S16P; + }else if( av_get_planar_sample_fmt(s-> in_sample_fmt) == AV_SAMPLE_FMT_S32P + && av_get_planar_sample_fmt(s->out_sample_fmt) == AV_SAMPLE_FMT_S32P + && !s->rematrix + && s->out_sample_rate == s->in_sample_rate + && !(s->flags & SWR_FLAG_RESAMPLE) + && s->engine != SWR_ENGINE_SOXR){ + s->int_sample_fmt= AV_SAMPLE_FMT_S32P; + }else if(av_get_bytes_per_sample(s->in_sample_fmt) <= 4){ + s->int_sample_fmt= AV_SAMPLE_FMT_FLTP; + }else{ + s->int_sample_fmt= AV_SAMPLE_FMT_DBLP; + } + } + av_log(s, AV_LOG_DEBUG, "Using %s internally between filters\n", av_get_sample_fmt_name(s->int_sample_fmt)); + + if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P + &&s->int_sample_fmt != AV_SAMPLE_FMT_S32P + &&s->int_sample_fmt != AV_SAMPLE_FMT_S64P + &&s->int_sample_fmt != AV_SAMPLE_FMT_FLTP + &&s->int_sample_fmt != AV_SAMPLE_FMT_DBLP){ + av_log(s, AV_LOG_ERROR, "Requested sample format %s is not supported internally, s16p/s32p/s64p/fltp/dblp are supported\n", av_get_sample_fmt_name(s->int_sample_fmt)); + return AVERROR(EINVAL); + } + + set_audiodata_fmt(&s-> in, s-> in_sample_fmt); + set_audiodata_fmt(&s->out, s->out_sample_fmt); + + if (s->firstpts_in_samples != AV_NOPTS_VALUE) { + if (!s->async && s->min_compensation >= FLT_MAX/2) + s->async = 1; + s->firstpts = + s->outpts = s->firstpts_in_samples * s->out_sample_rate; + } else + s->firstpts = AV_NOPTS_VALUE; + + if (s->async) { + if (s->min_compensation >= FLT_MAX/2) + s->min_compensation = 0.001; + if (s->async > 1.0001) { + s->max_soft_compensation = s->async / (double) s->in_sample_rate; + } + } + + if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){ + s->resample = s->resampler->init(s->resample, s->out_sample_rate, s->in_sample_rate, s->filter_size, s->phase_shift, s->linear_interp, s->cutoff, s->int_sample_fmt, s->filter_type, s->kaiser_beta, s->precision, s->cheby, s->exact_rational); + if (!s->resample) { + av_log(s, AV_LOG_ERROR, "Failed to initialize resampler\n"); + return AVERROR(ENOMEM); + } + }else + s->resampler->free(&s->resample); + if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P + && s->int_sample_fmt != AV_SAMPLE_FMT_S32P + && s->int_sample_fmt != AV_SAMPLE_FMT_FLTP + && s->int_sample_fmt != AV_SAMPLE_FMT_DBLP + && s->resample){ + av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16p/s32p/fltp/dblp\n"); + ret = AVERROR(EINVAL); + goto fail; + } + +#define RSC 1 //FIXME finetune + if(!s-> in.ch_count) + s-> in.ch_count= av_get_channel_layout_nb_channels(s-> in_ch_layout); + if(!s->used_ch_count) + s->used_ch_count= s->in.ch_count; + if(!s->out.ch_count) + s->out.ch_count= av_get_channel_layout_nb_channels(s->out_ch_layout); + + if(!s-> in.ch_count){ + av_assert0(!s->in_ch_layout); + av_log(s, AV_LOG_ERROR, "Input channel count and layout are unset\n"); + ret = AVERROR(EINVAL); + goto fail; + } + + av_get_channel_layout_string(l1, sizeof(l1), s-> in.ch_count, s-> in_ch_layout); + av_get_channel_layout_string(l2, sizeof(l2), s->out.ch_count, s->out_ch_layout); + if (s->out_ch_layout && s->out.ch_count != av_get_channel_layout_nb_channels(s->out_ch_layout)) { + av_log(s, AV_LOG_ERROR, "Output channel layout %s mismatches specified channel count %d\n", l2, s->out.ch_count); + ret = AVERROR(EINVAL); + goto fail; + } + if (s->in_ch_layout && s->used_ch_count != av_get_channel_layout_nb_channels(s->in_ch_layout)) { + av_log(s, AV_LOG_ERROR, "Input channel layout %s mismatches specified channel count %d\n", l1, s->used_ch_count); + ret = AVERROR(EINVAL); + goto fail; + } + + if ((!s->out_ch_layout || !s->in_ch_layout) && s->used_ch_count != s->out.ch_count && !s->rematrix_custom) { + av_log(s, AV_LOG_ERROR, "Rematrix is needed between %s and %s " + "but there is not enough information to do it\n", l1, l2); + ret = AVERROR(EINVAL); + goto fail; + } + +av_assert0(s->used_ch_count); +av_assert0(s->out.ch_count); + s->resample_first= RSC*s->out.ch_count/s->used_ch_count - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0; + + s->in_buffer= s->in; + s->silence = s->in; + s->drop_temp= s->out; + + if ((ret = swri_dither_init(s, s->out_sample_fmt, s->int_sample_fmt)) < 0) + goto fail; + + if(!s->resample && !s->rematrix && !s->channel_map && !s->dither.method){ + s->full_convert = swri_audio_convert_alloc(s->out_sample_fmt, + s-> in_sample_fmt, s-> in.ch_count, NULL, 0); + return 0; + } + + s->in_convert = swri_audio_convert_alloc(s->int_sample_fmt, + s-> in_sample_fmt, s->used_ch_count, s->channel_map, 0); + s->out_convert= swri_audio_convert_alloc(s->out_sample_fmt, + s->int_sample_fmt, s->out.ch_count, NULL, 0); + + if (!s->in_convert || !s->out_convert) { + ret = AVERROR(ENOMEM); + goto fail; + } + + s->postin= s->in; + s->preout= s->out; + s->midbuf= s->in; + + if(s->channel_map){ + s->postin.ch_count= + s->midbuf.ch_count= s->used_ch_count; + if(s->resample) + s->in_buffer.ch_count= s->used_ch_count; + } + if(!s->resample_first){ + s->midbuf.ch_count= s->out.ch_count; + if(s->resample) + s->in_buffer.ch_count = s->out.ch_count; + } + + set_audiodata_fmt(&s->postin, s->int_sample_fmt); + set_audiodata_fmt(&s->midbuf, s->int_sample_fmt); + set_audiodata_fmt(&s->preout, s->int_sample_fmt); + + if(s->resample){ + set_audiodata_fmt(&s->in_buffer, s->int_sample_fmt); + } + + av_assert0(!s->preout.count); + s->dither.noise = s->preout; + s->dither.temp = s->preout; + if (s->dither.method > SWR_DITHER_NS) { + s->dither.noise.bps = 4; + s->dither.noise.fmt = AV_SAMPLE_FMT_FLTP; + s->dither.noise_scale = 1; + } + + if(s->rematrix || s->dither.method) { + ret = swri_rematrix_init(s); + if (ret < 0) + goto fail; + } + + return 0; +fail: + swr_close(s); + return ret; + +} + +int swri_realloc_audio(AudioData *a, int count){ + int i, countb; + AudioData old; + + if(count < 0 || count > INT_MAX/2/a->bps/a->ch_count) + return AVERROR(EINVAL); + + if(a->count >= count) + return 0; + + count*=2; + + countb= FFALIGN(count*a->bps, ALIGN); + old= *a; + + av_assert0(a->bps); + av_assert0(a->ch_count); + + a->data= av_mallocz_array(countb, a->ch_count); + if(!a->data) + return AVERROR(ENOMEM); + for(i=0; ich_count; i++){ + a->ch[i]= a->data + i*(a->planar ? countb : a->bps); + if(a->count && a->planar) memcpy(a->ch[i], old.ch[i], a->count*a->bps); + } + if(a->count && !a->planar) memcpy(a->ch[0], old.ch[0], a->count*a->ch_count*a->bps); + av_freep(&old.data); + a->count= count; + + return 1; +} + +static void copy(AudioData *out, AudioData *in, + int count){ + av_assert0(out->planar == in->planar); + av_assert0(out->bps == in->bps); + av_assert0(out->ch_count == in->ch_count); + if(out->planar){ + int ch; + for(ch=0; chch_count; ch++) + memcpy(out->ch[ch], in->ch[ch], count*out->bps); + }else + memcpy(out->ch[0], in->ch[0], count*out->ch_count*out->bps); +} + +static void fill_audiodata(AudioData *out, uint8_t *in_arg [SWR_CH_MAX]){ + int i; + if(!in_arg){ + memset(out->ch, 0, sizeof(out->ch)); + }else if(out->planar){ + for(i=0; ich_count; i++) + out->ch[i]= in_arg[i]; + }else{ + for(i=0; ich_count; i++) + out->ch[i]= in_arg[0] + i*out->bps; + } +} + +static void reversefill_audiodata(AudioData *out, uint8_t *in_arg [SWR_CH_MAX]){ + int i; + if(out->planar){ + for(i=0; ich_count; i++) + in_arg[i]= out->ch[i]; + }else{ + in_arg[0]= out->ch[0]; + } +} + +/** + * + * out may be equal in. + */ +static void buf_set(AudioData *out, AudioData *in, int count){ + int ch; + if(in->planar){ + for(ch=0; chch_count; ch++) + out->ch[ch]= in->ch[ch] + count*out->bps; + }else{ + for(ch=out->ch_count-1; ch>=0; ch--) + out->ch[ch]= in->ch[0] + (ch + count*out->ch_count) * out->bps; + } +} + +/** + * + * @return number of samples output per channel + */ +static int resample(SwrContext *s, AudioData *out_param, int out_count, + const AudioData * in_param, int in_count){ + AudioData in, out, tmp; + int ret_sum=0; + int border=0; + int padless = ARCH_X86 && s->engine == SWR_ENGINE_SWR ? 7 : 0; + + av_assert1(s->in_buffer.ch_count == in_param->ch_count); + av_assert1(s->in_buffer.planar == in_param->planar); + av_assert1(s->in_buffer.fmt == in_param->fmt); + + tmp=out=*out_param; + in = *in_param; + + border = s->resampler->invert_initial_buffer(s->resample, &s->in_buffer, + &in, in_count, &s->in_buffer_index, &s->in_buffer_count); + if (border == INT_MAX) { + return 0; + } else if (border < 0) { + return border; + } else if (border) { + buf_set(&in, &in, border); + in_count -= border; + s->resample_in_constraint = 0; + } + + do{ + int ret, size, consumed; + if(!s->resample_in_constraint && s->in_buffer_count){ + buf_set(&tmp, &s->in_buffer, s->in_buffer_index); + ret= s->resampler->multiple_resample(s->resample, &out, out_count, &tmp, s->in_buffer_count, &consumed); + out_count -= ret; + ret_sum += ret; + buf_set(&out, &out, ret); + s->in_buffer_count -= consumed; + s->in_buffer_index += consumed; + + if(!in_count) + break; + if(s->in_buffer_count <= border){ + buf_set(&in, &in, -s->in_buffer_count); + in_count += s->in_buffer_count; + s->in_buffer_count=0; + s->in_buffer_index=0; + border = 0; + } + } + + if((s->flushed || in_count > padless) && !s->in_buffer_count){ + s->in_buffer_index=0; + ret= s->resampler->multiple_resample(s->resample, &out, out_count, &in, FFMAX(in_count-padless, 0), &consumed); + out_count -= ret; + ret_sum += ret; + buf_set(&out, &out, ret); + in_count -= consumed; + buf_set(&in, &in, consumed); + } + + //TODO is this check sane considering the advanced copy avoidance below + size= s->in_buffer_index + s->in_buffer_count + in_count; + if( size > s->in_buffer.count + && s->in_buffer_count + in_count <= s->in_buffer_index){ + buf_set(&tmp, &s->in_buffer, s->in_buffer_index); + copy(&s->in_buffer, &tmp, s->in_buffer_count); + s->in_buffer_index=0; + }else + if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0) + return ret; + + if(in_count){ + int count= in_count; + if(s->in_buffer_count && s->in_buffer_count+2 < count && out_count) count= s->in_buffer_count+2; + + buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count); + copy(&tmp, &in, /*in_*/count); + s->in_buffer_count += count; + in_count -= count; + border += count; + buf_set(&in, &in, count); + s->resample_in_constraint= 0; + if(s->in_buffer_count != count || in_count) + continue; + if (padless) { + padless = 0; + continue; + } + } + break; + }while(1); + + s->resample_in_constraint= !!out_count; + + return ret_sum; +} + +static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_count, + AudioData *in , int in_count){ + AudioData *postin, *midbuf, *preout; + int ret/*, in_max*/; + AudioData preout_tmp, midbuf_tmp; + + if(s->full_convert){ + av_assert0(!s->resample); + swri_audio_convert(s->full_convert, out, in, in_count); + return out_count; + } + +// in_max= out_count*(int64_t)s->in_sample_rate / s->out_sample_rate + resample_filter_taps; +// in_count= FFMIN(in_count, in_in + 2 - s->hist_buffer_count); + + if((ret=swri_realloc_audio(&s->postin, in_count))<0) + return ret; + if(s->resample_first){ + av_assert0(s->midbuf.ch_count == s->used_ch_count); + if((ret=swri_realloc_audio(&s->midbuf, out_count))<0) + return ret; + }else{ + av_assert0(s->midbuf.ch_count == s->out.ch_count); + if((ret=swri_realloc_audio(&s->midbuf, in_count))<0) + return ret; + } + if((ret=swri_realloc_audio(&s->preout, out_count))<0) + return ret; + + postin= &s->postin; + + midbuf_tmp= s->midbuf; + midbuf= &midbuf_tmp; + preout_tmp= s->preout; + preout= &preout_tmp; + + if(s->int_sample_fmt == s-> in_sample_fmt && s->in.planar && !s->channel_map) + postin= in; + + if(s->resample_first ? !s->resample : !s->rematrix) + midbuf= postin; + + if(s->resample_first ? !s->rematrix : !s->resample) + preout= midbuf; + + if(s->int_sample_fmt == s->out_sample_fmt && s->out.planar + && !(s->out_sample_fmt==AV_SAMPLE_FMT_S32P && (s->dither.output_sample_bits&31))){ + if(preout==in){ + out_count= FFMIN(out_count, in_count); //TODO check at the end if this is needed or redundant + av_assert0(s->in.planar); //we only support planar internally so it has to be, we support copying non planar though + copy(out, in, out_count); + return out_count; + } + else if(preout==postin) preout= midbuf= postin= out; + else if(preout==midbuf) preout= midbuf= out; + else preout= out; + } + + if(in != postin){ + swri_audio_convert(s->in_convert, postin, in, in_count); + } + + if(s->resample_first){ + if(postin != midbuf) + out_count= resample(s, midbuf, out_count, postin, in_count); + if(midbuf != preout) + swri_rematrix(s, preout, midbuf, out_count, preout==out); + }else{ + if(postin != midbuf) + swri_rematrix(s, midbuf, postin, in_count, midbuf==out); + if(midbuf != preout) + out_count= resample(s, preout, out_count, midbuf, in_count); + } + + if(preout != out && out_count){ + AudioData *conv_src = preout; + if(s->dither.method){ + int ch; + int dither_count= FFMAX(out_count, 1<<16); + + if (preout == in) { + conv_src = &s->dither.temp; + if((ret=swri_realloc_audio(&s->dither.temp, dither_count))<0) + return ret; + } + + if((ret=swri_realloc_audio(&s->dither.noise, dither_count))<0) + return ret; + if(ret) + for(ch=0; chdither.noise.ch_count; ch++) + if((ret=swri_get_dither(s, s->dither.noise.ch[ch], s->dither.noise.count, (12345678913579ULL*ch + 3141592) % 2718281828U, s->dither.noise.fmt))<0) + return ret; + av_assert0(s->dither.noise.ch_count == preout->ch_count); + + if(s->dither.noise_pos + out_count > s->dither.noise.count) + s->dither.noise_pos = 0; + + if (s->dither.method < SWR_DITHER_NS){ + if (s->mix_2_1_simd) { + int len1= out_count&~15; + int off = len1 * preout->bps; + + if(len1) + for(ch=0; chch_count; ch++) + s->mix_2_1_simd(conv_src->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos, s->native_simd_one, 0, 0, len1); + if(out_count != len1) + for(ch=0; chch_count; ch++) + s->mix_2_1_f(conv_src->ch[ch] + off, preout->ch[ch] + off, s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos + off, s->native_one, 0, 0, out_count - len1); + } else { + for(ch=0; chch_count; ch++) + s->mix_2_1_f(conv_src->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos, s->native_one, 0, 0, out_count); + } + } else { + switch(s->int_sample_fmt) { + case AV_SAMPLE_FMT_S16P :swri_noise_shaping_int16(s, conv_src, preout, &s->dither.noise, out_count); break; + case AV_SAMPLE_FMT_S32P :swri_noise_shaping_int32(s, conv_src, preout, &s->dither.noise, out_count); break; + case AV_SAMPLE_FMT_FLTP :swri_noise_shaping_float(s, conv_src, preout, &s->dither.noise, out_count); break; + case AV_SAMPLE_FMT_DBLP :swri_noise_shaping_double(s,conv_src, preout, &s->dither.noise, out_count); break; + } + } + s->dither.noise_pos += out_count; + } +//FIXME packed doesn't need more than 1 chan here! + swri_audio_convert(s->out_convert, out, conv_src, out_count); + } + return out_count; +} + +int swr_is_initialized(struct SwrContext *s) { + return !!s->in_buffer.ch_count; +} + +int attribute_align_arg swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_CH_MAX], int out_count, + const uint8_t *in_arg [SWR_CH_MAX], int in_count){ + AudioData * in= &s->in; + AudioData *out= &s->out; + int av_unused max_output; + + if (!swr_is_initialized(s)) { + av_log(s, AV_LOG_ERROR, "Context has not been initialized\n"); + return AVERROR(EINVAL); + } +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >1 + max_output = swr_get_out_samples(s, in_count); +#endif + + while(s->drop_output > 0){ + int ret; + uint8_t *tmp_arg[SWR_CH_MAX]; +#define MAX_DROP_STEP 16384 + if((ret=swri_realloc_audio(&s->drop_temp, FFMIN(s->drop_output, MAX_DROP_STEP)))<0) + return ret; + + reversefill_audiodata(&s->drop_temp, tmp_arg); + s->drop_output *= -1; //FIXME find a less hackish solution + ret = swr_convert(s, tmp_arg, FFMIN(-s->drop_output, MAX_DROP_STEP), in_arg, in_count); //FIXME optimize but this is as good as never called so maybe it doesn't matter + s->drop_output *= -1; + in_count = 0; + if(ret>0) { + s->drop_output -= ret; + if (!s->drop_output && !out_arg) + return 0; + continue; + } + + av_assert0(s->drop_output); + return 0; + } + + if(!in_arg){ + if(s->resample){ + if (!s->flushed) + s->resampler->flush(s); + s->resample_in_constraint = 0; + s->flushed = 1; + }else if(!s->in_buffer_count){ + return 0; + } + }else + fill_audiodata(in , (void*)in_arg); + + fill_audiodata(out, out_arg); + + if(s->resample){ + int ret = swr_convert_internal(s, out, out_count, in, in_count); + if(ret>0 && !s->drop_output) + s->outpts += ret * (int64_t)s->in_sample_rate; + + av_assert2(max_output < 0 || ret < 0 || ret <= max_output); + + return ret; + }else{ + AudioData tmp= *in; + int ret2=0; + int ret, size; + size = FFMIN(out_count, s->in_buffer_count); + if(size){ + buf_set(&tmp, &s->in_buffer, s->in_buffer_index); + ret= swr_convert_internal(s, out, size, &tmp, size); + if(ret<0) + return ret; + ret2= ret; + s->in_buffer_count -= ret; + s->in_buffer_index += ret; + buf_set(out, out, ret); + out_count -= ret; + if(!s->in_buffer_count) + s->in_buffer_index = 0; + } + + if(in_count){ + size= s->in_buffer_index + s->in_buffer_count + in_count - out_count; + + if(in_count > out_count) { //FIXME move after swr_convert_internal + if( size > s->in_buffer.count + && s->in_buffer_count + in_count - out_count <= s->in_buffer_index){ + buf_set(&tmp, &s->in_buffer, s->in_buffer_index); + copy(&s->in_buffer, &tmp, s->in_buffer_count); + s->in_buffer_index=0; + }else + if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0) + return ret; + } + + if(out_count){ + size = FFMIN(in_count, out_count); + ret= swr_convert_internal(s, out, size, in, size); + if(ret<0) + return ret; + buf_set(in, in, ret); + in_count -= ret; + ret2 += ret; + } + if(in_count){ + buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count); + copy(&tmp, in, in_count); + s->in_buffer_count += in_count; + } + } + if(ret2>0 && !s->drop_output) + s->outpts += ret2 * (int64_t)s->in_sample_rate; + av_assert2(max_output < 0 || ret2 < 0 || ret2 <= max_output); + return ret2; + } +} + +int swr_drop_output(struct SwrContext *s, int count){ + const uint8_t *tmp_arg[SWR_CH_MAX]; + s->drop_output += count; + + if(s->drop_output <= 0) + return 0; + + av_log(s, AV_LOG_VERBOSE, "discarding %d audio samples\n", count); + return swr_convert(s, NULL, s->drop_output, tmp_arg, 0); +} + +int swr_inject_silence(struct SwrContext *s, int count){ + int ret, i; + uint8_t *tmp_arg[SWR_CH_MAX]; + + if(count <= 0) + return 0; + +#define MAX_SILENCE_STEP 16384 + while (count > MAX_SILENCE_STEP) { + if ((ret = swr_inject_silence(s, MAX_SILENCE_STEP)) < 0) + return ret; + count -= MAX_SILENCE_STEP; + } + + if((ret=swri_realloc_audio(&s->silence, count))<0) + return ret; + + if(s->silence.planar) for(i=0; isilence.ch_count; i++) { + memset(s->silence.ch[i], s->silence.bps==1 ? 0x80 : 0, count*s->silence.bps); + } else + memset(s->silence.ch[0], s->silence.bps==1 ? 0x80 : 0, count*s->silence.bps*s->silence.ch_count); + + reversefill_audiodata(&s->silence, tmp_arg); + av_log(s, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", count); + ret = swr_convert(s, NULL, 0, (const uint8_t**)tmp_arg, count); + return ret; +} + +int64_t swr_get_delay(struct SwrContext *s, int64_t base){ + if (s->resampler && s->resample){ + return s->resampler->get_delay(s, base); + }else{ + return (s->in_buffer_count*base + (s->in_sample_rate>>1))/ s->in_sample_rate; + } +} + +int swr_get_out_samples(struct SwrContext *s, int in_samples) +{ + int64_t out_samples; + + if (in_samples < 0) + return AVERROR(EINVAL); + + if (s->resampler && s->resample) { + if (!s->resampler->get_out_samples) + return AVERROR(ENOSYS); + out_samples = s->resampler->get_out_samples(s, in_samples); + } else { + out_samples = s->in_buffer_count + in_samples; + av_assert0(s->out_sample_rate == s->in_sample_rate); + } + + if (out_samples > INT_MAX) + return AVERROR(EINVAL); + + return out_samples; +} + +int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance){ + int ret; + + if (!s || compensation_distance < 0) + return AVERROR(EINVAL); + if (!compensation_distance && sample_delta) + return AVERROR(EINVAL); + if (!s->resample) { + s->flags |= SWR_FLAG_RESAMPLE; + ret = swr_init(s); + if (ret < 0) + return ret; + } + if (!s->resampler->set_compensation){ + return AVERROR(EINVAL); + }else{ + return s->resampler->set_compensation(s->resample, sample_delta, compensation_distance); + } +} + +int64_t swr_next_pts(struct SwrContext *s, int64_t pts){ + if(pts == INT64_MIN) + return s->outpts; + + if (s->firstpts == AV_NOPTS_VALUE) + s->outpts = s->firstpts = pts; + + if(s->min_compensation >= FLT_MAX) { + return (s->outpts = pts - swr_get_delay(s, s->in_sample_rate * (int64_t)s->out_sample_rate)); + } else { + int64_t delta = pts - swr_get_delay(s, s->in_sample_rate * (int64_t)s->out_sample_rate) - s->outpts + s->drop_output*(int64_t)s->in_sample_rate; + double fdelta = delta /(double)(s->in_sample_rate * (int64_t)s->out_sample_rate); + + if(fabs(fdelta) > s->min_compensation) { + if(s->outpts == s->firstpts || fabs(fdelta) > s->min_hard_compensation){ + int ret; + if(delta > 0) ret = swr_inject_silence(s, delta / s->out_sample_rate); + else ret = swr_drop_output (s, -delta / s-> in_sample_rate); + if(ret<0){ + av_log(s, AV_LOG_ERROR, "Failed to compensate for timestamp delta of %f\n", fdelta); + } + } else if(s->soft_compensation_duration && s->max_soft_compensation) { + int duration = s->out_sample_rate * s->soft_compensation_duration; + double max_soft_compensation = s->max_soft_compensation / (s->max_soft_compensation < 0 ? -s->in_sample_rate : 1); + int comp = av_clipf(fdelta, -max_soft_compensation, max_soft_compensation) * duration ; + av_log(s, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", fdelta, comp, duration); + swr_set_compensation(s, comp, duration); + } + } + + return s->outpts; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample.h b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample.h new file mode 100644 index 0000000000..c7b84fbcac --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample.h @@ -0,0 +1,579 @@ +/* + * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_SWRESAMPLE_H +#define SWRESAMPLE_SWRESAMPLE_H + +/** + * @file + * @ingroup lswr + * libswresample public header + */ + +/** + * @defgroup lswr libswresample + * @{ + * + * Audio resampling, sample format conversion and mixing library. + * + * Interaction with lswr is done through SwrContext, which is + * allocated with swr_alloc() or swr_alloc_set_opts(). It is opaque, so all parameters + * must be set with the @ref avoptions API. + * + * The first thing you will need to do in order to use lswr is to allocate + * SwrContext. This can be done with swr_alloc() or swr_alloc_set_opts(). If you + * are using the former, you must set options through the @ref avoptions API. + * The latter function provides the same feature, but it allows you to set some + * common options in the same statement. + * + * For example the following code will setup conversion from planar float sample + * format to interleaved signed 16-bit integer, downsampling from 48kHz to + * 44.1kHz and downmixing from 5.1 channels to stereo (using the default mixing + * matrix). This is using the swr_alloc() function. + * @code + * SwrContext *swr = swr_alloc(); + * av_opt_set_channel_layout(swr, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0); + * av_opt_set_channel_layout(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); + * av_opt_set_int(swr, "in_sample_rate", 48000, 0); + * av_opt_set_int(swr, "out_sample_rate", 44100, 0); + * av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); + * av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); + * @endcode + * + * The same job can be done using swr_alloc_set_opts() as well: + * @code + * SwrContext *swr = swr_alloc_set_opts(NULL, // we're allocating a new context + * AV_CH_LAYOUT_STEREO, // out_ch_layout + * AV_SAMPLE_FMT_S16, // out_sample_fmt + * 44100, // out_sample_rate + * AV_CH_LAYOUT_5POINT1, // in_ch_layout + * AV_SAMPLE_FMT_FLTP, // in_sample_fmt + * 48000, // in_sample_rate + * 0, // log_offset + * NULL); // log_ctx + * @endcode + * + * Once all values have been set, it must be initialized with swr_init(). If + * you need to change the conversion parameters, you can change the parameters + * using @ref AVOptions, as described above in the first example; or by using + * swr_alloc_set_opts(), but with the first argument the allocated context. + * You must then call swr_init() again. + * + * The conversion itself is done by repeatedly calling swr_convert(). + * Note that the samples may get buffered in swr if you provide insufficient + * output space or if sample rate conversion is done, which requires "future" + * samples. Samples that do not require future input can be retrieved at any + * time by using swr_convert() (in_count can be set to 0). + * At the end of conversion the resampling buffer can be flushed by calling + * swr_convert() with NULL in and 0 in_count. + * + * The samples used in the conversion process can be managed with the libavutil + * @ref lavu_sampmanip "samples manipulation" API, including av_samples_alloc() + * function used in the following example. + * + * The delay between input and output, can at any time be found by using + * swr_get_delay(). + * + * The following code demonstrates the conversion loop assuming the parameters + * from above and caller-defined functions get_input() and handle_output(): + * @code + * uint8_t **input; + * int in_samples; + * + * while (get_input(&input, &in_samples)) { + * uint8_t *output; + * int out_samples = av_rescale_rnd(swr_get_delay(swr, 48000) + + * in_samples, 44100, 48000, AV_ROUND_UP); + * av_samples_alloc(&output, NULL, 2, out_samples, + * AV_SAMPLE_FMT_S16, 0); + * out_samples = swr_convert(swr, &output, out_samples, + * input, in_samples); + * handle_output(output, out_samples); + * av_freep(&output); + * } + * @endcode + * + * When the conversion is finished, the conversion + * context and everything associated with it must be freed with swr_free(). + * A swr_close() function is also available, but it exists mainly for + * compatibility with libavresample, and is not required to be called. + * + * There will be no memory leak if the data is not completely flushed before + * swr_free(). + */ + +#include +#include "libavutil/channel_layout.h" +#include "libavutil/frame.h" +#include "libavutil/samplefmt.h" + +#include "libswresample/version.h" + +/** + * @name Option constants + * These constants are used for the @ref avoptions interface for lswr. + * @{ + * + */ + +#define SWR_FLAG_RESAMPLE 1 ///< Force resampling even if equal sample rate +//TODO use int resample ? +//long term TODO can we enable this dynamically? + +/** Dithering algorithms */ +enum SwrDitherType { + SWR_DITHER_NONE = 0, + SWR_DITHER_RECTANGULAR, + SWR_DITHER_TRIANGULAR, + SWR_DITHER_TRIANGULAR_HIGHPASS, + + SWR_DITHER_NS = 64, ///< not part of API/ABI + SWR_DITHER_NS_LIPSHITZ, + SWR_DITHER_NS_F_WEIGHTED, + SWR_DITHER_NS_MODIFIED_E_WEIGHTED, + SWR_DITHER_NS_IMPROVED_E_WEIGHTED, + SWR_DITHER_NS_SHIBATA, + SWR_DITHER_NS_LOW_SHIBATA, + SWR_DITHER_NS_HIGH_SHIBATA, + SWR_DITHER_NB, ///< not part of API/ABI +}; + +/** Resampling Engines */ +enum SwrEngine { + SWR_ENGINE_SWR, /**< SW Resampler */ + SWR_ENGINE_SOXR, /**< SoX Resampler */ + SWR_ENGINE_NB, ///< not part of API/ABI +}; + +/** Resampling Filter Types */ +enum SwrFilterType { + SWR_FILTER_TYPE_CUBIC, /**< Cubic */ + SWR_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall windowed sinc */ + SWR_FILTER_TYPE_KAISER, /**< Kaiser windowed sinc */ +}; + +/** + * @} + */ + +/** + * The libswresample context. Unlike libavcodec and libavformat, this structure + * is opaque. This means that if you would like to set options, you must use + * the @ref avoptions API and cannot directly set values to members of the + * structure. + */ +typedef struct SwrContext SwrContext; + +/** + * Get the AVClass for SwrContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + * @return the AVClass of SwrContext + */ +const AVClass *swr_get_class(void); + +/** + * @name SwrContext constructor functions + * @{ + */ + +/** + * Allocate SwrContext. + * + * If you use this function you will need to set the parameters (manually or + * with swr_alloc_set_opts()) before calling swr_init(). + * + * @see swr_alloc_set_opts(), swr_init(), swr_free() + * @return NULL on error, allocated context otherwise + */ +struct SwrContext *swr_alloc(void); + +/** + * Initialize context after user parameters have been set. + * @note The context must be configured using the AVOption API. + * + * @see av_opt_set_int() + * @see av_opt_set_dict() + * + * @param[in,out] s Swr context to initialize + * @return AVERROR error code in case of failure. + */ +int swr_init(struct SwrContext *s); + +/** + * Check whether an swr context has been initialized or not. + * + * @param[in] s Swr context to check + * @see swr_init() + * @return positive if it has been initialized, 0 if not initialized + */ +int swr_is_initialized(struct SwrContext *s); + +/** + * Allocate SwrContext if needed and set/reset common parameters. + * + * This function does not require s to be allocated with swr_alloc(). On the + * other hand, swr_alloc() can use swr_alloc_set_opts() to set the parameters + * on the allocated context. + * + * @param s existing Swr context if available, or NULL if not + * @param out_ch_layout output channel layout (AV_CH_LAYOUT_*) + * @param out_sample_fmt output sample format (AV_SAMPLE_FMT_*). + * @param out_sample_rate output sample rate (frequency in Hz) + * @param in_ch_layout input channel layout (AV_CH_LAYOUT_*) + * @param in_sample_fmt input sample format (AV_SAMPLE_FMT_*). + * @param in_sample_rate input sample rate (frequency in Hz) + * @param log_offset logging level offset + * @param log_ctx parent logging context, can be NULL + * + * @see swr_init(), swr_free() + * @return NULL on error, allocated context otherwise + */ +struct SwrContext *swr_alloc_set_opts(struct SwrContext *s, + int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, + int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, + int log_offset, void *log_ctx); + +/** + * @} + * + * @name SwrContext destructor functions + * @{ + */ + +/** + * Free the given SwrContext and set the pointer to NULL. + * + * @param[in] s a pointer to a pointer to Swr context + */ +void swr_free(struct SwrContext **s); + +/** + * Closes the context so that swr_is_initialized() returns 0. + * + * The context can be brought back to life by running swr_init(), + * swr_init() can also be used without swr_close(). + * This function is mainly provided for simplifying the usecase + * where one tries to support libavresample and libswresample. + * + * @param[in,out] s Swr context to be closed + */ +void swr_close(struct SwrContext *s); + +/** + * @} + * + * @name Core conversion functions + * @{ + */ + +/** Convert audio. + * + * in and in_count can be set to 0 to flush the last few samples out at the + * end. + * + * If more input is provided than output space, then the input will be buffered. + * You can avoid this buffering by using swr_get_out_samples() to retrieve an + * upper bound on the required number of output samples for the given number of + * input samples. Conversion will run directly without copying whenever possible. + * + * @param s allocated Swr context, with parameters set + * @param out output buffers, only the first one need be set in case of packed audio + * @param out_count amount of space available for output in samples per channel + * @param in input buffers, only the first one need to be set in case of packed audio + * @param in_count number of input samples available in one channel + * + * @return number of samples output per channel, negative value on error + */ +int swr_convert(struct SwrContext *s, uint8_t **out, int out_count, + const uint8_t **in , int in_count); + +/** + * Convert the next timestamp from input to output + * timestamps are in 1/(in_sample_rate * out_sample_rate) units. + * + * @note There are 2 slightly differently behaving modes. + * @li When automatic timestamp compensation is not used, (min_compensation >= FLT_MAX) + * in this case timestamps will be passed through with delays compensated + * @li When automatic timestamp compensation is used, (min_compensation < FLT_MAX) + * in this case the output timestamps will match output sample numbers. + * See ffmpeg-resampler(1) for the two modes of compensation. + * + * @param s[in] initialized Swr context + * @param pts[in] timestamp for the next input sample, INT64_MIN if unknown + * @see swr_set_compensation(), swr_drop_output(), and swr_inject_silence() are + * function used internally for timestamp compensation. + * @return the output timestamp for the next output sample + */ +int64_t swr_next_pts(struct SwrContext *s, int64_t pts); + +/** + * @} + * + * @name Low-level option setting functions + * These functons provide a means to set low-level options that is not possible + * with the AVOption API. + * @{ + */ + +/** + * Activate resampling compensation ("soft" compensation). This function is + * internally called when needed in swr_next_pts(). + * + * @param[in,out] s allocated Swr context. If it is not initialized, + * or SWR_FLAG_RESAMPLE is not set, swr_init() is + * called with the flag set. + * @param[in] sample_delta delta in PTS per sample + * @param[in] compensation_distance number of samples to compensate for + * @return >= 0 on success, AVERROR error codes if: + * @li @c s is NULL, + * @li @c compensation_distance is less than 0, + * @li @c compensation_distance is 0 but sample_delta is not, + * @li compensation unsupported by resampler, or + * @li swr_init() fails when called. + */ +int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance); + +/** + * Set a customized input channel mapping. + * + * @param[in,out] s allocated Swr context, not yet initialized + * @param[in] channel_map customized input channel mapping (array of channel + * indexes, -1 for a muted channel) + * @return >= 0 on success, or AVERROR error code in case of failure. + */ +int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map); + +/** + * Generate a channel mixing matrix. + * + * This function is the one used internally by libswresample for building the + * default mixing matrix. It is made public just as a utility function for + * building custom matrices. + * + * @param in_layout input channel layout + * @param out_layout output channel layout + * @param center_mix_level mix level for the center channel + * @param surround_mix_level mix level for the surround channel(s) + * @param lfe_mix_level mix level for the low-frequency effects channel + * @param rematrix_maxval if 1.0, coefficients will be normalized to prevent + * overflow. if INT_MAX, coefficients will not be + * normalized. + * @param[out] matrix mixing coefficients; matrix[i + stride * o] is + * the weight of input channel i in output channel o. + * @param stride distance between adjacent input channels in the + * matrix array + * @param matrix_encoding matrixed stereo downmix mode (e.g. dplii) + * @param log_ctx parent logging context, can be NULL + * @return 0 on success, negative AVERROR code on failure + */ +int swr_build_matrix(uint64_t in_layout, uint64_t out_layout, + double center_mix_level, double surround_mix_level, + double lfe_mix_level, double rematrix_maxval, + double rematrix_volume, double *matrix, + int stride, enum AVMatrixEncoding matrix_encoding, + void *log_ctx); + +/** + * Set a customized remix matrix. + * + * @param s allocated Swr context, not yet initialized + * @param matrix remix coefficients; matrix[i + stride * o] is + * the weight of input channel i in output channel o + * @param stride offset between lines of the matrix + * @return >= 0 on success, or AVERROR error code in case of failure. + */ +int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride); + +/** + * @} + * + * @name Sample handling functions + * @{ + */ + +/** + * Drops the specified number of output samples. + * + * This function, along with swr_inject_silence(), is called by swr_next_pts() + * if needed for "hard" compensation. + * + * @param s allocated Swr context + * @param count number of samples to be dropped + * + * @return >= 0 on success, or a negative AVERROR code on failure + */ +int swr_drop_output(struct SwrContext *s, int count); + +/** + * Injects the specified number of silence samples. + * + * This function, along with swr_drop_output(), is called by swr_next_pts() + * if needed for "hard" compensation. + * + * @param s allocated Swr context + * @param count number of samples to be dropped + * + * @return >= 0 on success, or a negative AVERROR code on failure + */ +int swr_inject_silence(struct SwrContext *s, int count); + +/** + * Gets the delay the next input sample will experience relative to the next output sample. + * + * Swresample can buffer data if more input has been provided than available + * output space, also converting between sample rates needs a delay. + * This function returns the sum of all such delays. + * The exact delay is not necessarily an integer value in either input or + * output sample rate. Especially when downsampling by a large value, the + * output sample rate may be a poor choice to represent the delay, similarly + * for upsampling and the input sample rate. + * + * @param s swr context + * @param base timebase in which the returned delay will be: + * @li if it's set to 1 the returned delay is in seconds + * @li if it's set to 1000 the returned delay is in milliseconds + * @li if it's set to the input sample rate then the returned + * delay is in input samples + * @li if it's set to the output sample rate then the returned + * delay is in output samples + * @li if it's the least common multiple of in_sample_rate and + * out_sample_rate then an exact rounding-free delay will be + * returned + * @returns the delay in 1 / @c base units. + */ +int64_t swr_get_delay(struct SwrContext *s, int64_t base); + +/** + * Find an upper bound on the number of samples that the next swr_convert + * call will output, if called with in_samples of input samples. This + * depends on the internal state, and anything changing the internal state + * (like further swr_convert() calls) will may change the number of samples + * swr_get_out_samples() returns for the same number of input samples. + * + * @param in_samples number of input samples. + * @note any call to swr_inject_silence(), swr_convert(), swr_next_pts() + * or swr_set_compensation() invalidates this limit + * @note it is recommended to pass the correct available buffer size + * to all functions like swr_convert() even if swr_get_out_samples() + * indicates that less would be used. + * @returns an upper bound on the number of samples that the next swr_convert + * will output or a negative value to indicate an error + */ +int swr_get_out_samples(struct SwrContext *s, int in_samples); + +/** + * @} + * + * @name Configuration accessors + * @{ + */ + +/** + * Return the @ref LIBSWRESAMPLE_VERSION_INT constant. + * + * This is useful to check if the build-time libswresample has the same version + * as the run-time one. + * + * @returns the unsigned int-typed version + */ +unsigned swresample_version(void); + +/** + * Return the swr build-time configuration. + * + * @returns the build-time @c ./configure flags + */ +const char *swresample_configuration(void); + +/** + * Return the swr license. + * + * @returns the license of libswresample, determined at build-time + */ +const char *swresample_license(void); + +/** + * @} + * + * @name AVFrame based API + * @{ + */ + +/** + * Convert the samples in the input AVFrame and write them to the output AVFrame. + * + * Input and output AVFrames must have channel_layout, sample_rate and format set. + * + * If the output AVFrame does not have the data pointers allocated the nb_samples + * field will be set using av_frame_get_buffer() + * is called to allocate the frame. + * + * The output AVFrame can be NULL or have fewer allocated samples than required. + * In this case, any remaining samples not written to the output will be added + * to an internal FIFO buffer, to be returned at the next call to this function + * or to swr_convert(). + * + * If converting sample rate, there may be data remaining in the internal + * resampling delay buffer. swr_get_delay() tells the number of + * remaining samples. To get this data as output, call this function or + * swr_convert() with NULL input. + * + * If the SwrContext configuration does not match the output and + * input AVFrame settings the conversion does not take place and depending on + * which AVFrame is not matching AVERROR_OUTPUT_CHANGED, AVERROR_INPUT_CHANGED + * or the result of a bitwise-OR of them is returned. + * + * @see swr_delay() + * @see swr_convert() + * @see swr_get_delay() + * + * @param swr audio resample context + * @param output output AVFrame + * @param input input AVFrame + * @return 0 on success, AVERROR on failure or nonmatching + * configuration. + */ +int swr_convert_frame(SwrContext *swr, + AVFrame *output, const AVFrame *input); + +/** + * Configure or reconfigure the SwrContext using the information + * provided by the AVFrames. + * + * The original resampling context is reset even on failure. + * The function calls swr_close() internally if the context is open. + * + * @see swr_close(); + * + * @param swr audio resample context + * @param output output AVFrame + * @param input input AVFrame + * @return 0 on success, AVERROR on failure. + */ +int swr_config_frame(SwrContext *swr, const AVFrame *out, const AVFrame *in); + +/** + * @} + * @} + */ + +#endif /* SWRESAMPLE_SWRESAMPLE_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample_frame.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample_frame.c new file mode 100644 index 0000000000..2853266d6c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample_frame.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2014 Luca Barbato + * Copyright (c) 2014 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "swresample_internal.h" +#include "libavutil/frame.h" +#include "libavutil/opt.h" + +int swr_config_frame(SwrContext *s, const AVFrame *out, const AVFrame *in) +{ + swr_close(s); + + if (in) { + if (av_opt_set_int(s, "icl", in->channel_layout, 0) < 0) + goto fail; + if (av_opt_set_int(s, "isf", in->format, 0) < 0) + goto fail; + if (av_opt_set_int(s, "isr", in->sample_rate, 0) < 0) + goto fail; + } + + if (out) { + if (av_opt_set_int(s, "ocl", out->channel_layout, 0) < 0) + goto fail; + if (av_opt_set_int(s, "osf", out->format, 0) < 0) + goto fail; + if (av_opt_set_int(s, "osr", out->sample_rate, 0) < 0) + goto fail; + } + + return 0; +fail: + av_log(s, AV_LOG_ERROR, "Failed to set option\n"); + return AVERROR(EINVAL); +} + +static int config_changed(SwrContext *s, + const AVFrame *out, const AVFrame *in) +{ + int ret = 0; + + if (in) { + if (s->in_ch_layout != in->channel_layout || + s->in_sample_rate != in->sample_rate || + s->in_sample_fmt != in->format) { + ret |= AVERROR_INPUT_CHANGED; + } + } + + if (out) { + if (s->out_ch_layout != out->channel_layout || + s->out_sample_rate != out->sample_rate || + s->out_sample_fmt != out->format) { + ret |= AVERROR_OUTPUT_CHANGED; + } + } + + return ret; +} + +static inline int convert_frame(SwrContext *s, + AVFrame *out, const AVFrame *in) +{ + int ret; + uint8_t **out_data = NULL; + const uint8_t **in_data = NULL; + int out_nb_samples = 0, in_nb_samples = 0; + + if (out) { + out_data = out->extended_data; + out_nb_samples = out->nb_samples; + } + + if (in) { + in_data = (const uint8_t **)in->extended_data; + in_nb_samples = in->nb_samples; + } + + ret = swr_convert(s, out_data, out_nb_samples, in_data, in_nb_samples); + + if (ret < 0) { + if (out) + out->nb_samples = 0; + return ret; + } + + if (out) + out->nb_samples = ret; + + return 0; +} + +static inline int available_samples(AVFrame *out) +{ + int bytes_per_sample = av_get_bytes_per_sample(out->format); + int samples = out->linesize[0] / bytes_per_sample; + + if (av_sample_fmt_is_planar(out->format)) { + return samples; + } else { + int channels = av_get_channel_layout_nb_channels(out->channel_layout); + return samples / channels; + } +} + +int swr_convert_frame(SwrContext *s, + AVFrame *out, const AVFrame *in) +{ + int ret, setup = 0; + + if (!swr_is_initialized(s)) { + if ((ret = swr_config_frame(s, out, in)) < 0) + return ret; + if ((ret = swr_init(s)) < 0) + return ret; + setup = 1; + } else { + // return as is or reconfigure for input changes? + if ((ret = config_changed(s, out, in))) + return ret; + } + + if (out) { + if (!out->linesize[0]) { + out->nb_samples = swr_get_delay(s, s->out_sample_rate) + 3; + if (in) { + out->nb_samples += in->nb_samples*(int64_t)s->out_sample_rate / s->in_sample_rate; + } + if ((ret = av_frame_get_buffer(out, 0)) < 0) { + if (setup) + swr_close(s); + return ret; + } + } else { + if (!out->nb_samples) + out->nb_samples = available_samples(out); + } + } + + return convert_frame(s, out, in); +} + diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample_internal.h b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample_internal.h new file mode 100644 index 0000000000..f2ea5a226d --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresample_internal.h @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_SWRESAMPLE_INTERNAL_H +#define SWRESAMPLE_SWRESAMPLE_INTERNAL_H + +#include "swresample.h" +#include "libavutil/channel_layout.h" +#include "config.h" + +#define SWR_CH_MAX 64 + +#define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */ + +#define NS_TAPS 20 + +#if ARCH_X86_64 +typedef int64_t integer; +#else +typedef int integer; +#endif + +typedef void (mix_1_1_func_type)(void *out, const void *in, void *coeffp, integer index, integer len); +typedef void (mix_2_1_func_type)(void *out, const void *in1, const void *in2, void *coeffp, integer index1, integer index2, integer len); + +typedef void (mix_any_func_type)(uint8_t **out, const uint8_t **in1, void *coeffp, integer len); + +typedef struct AudioData{ + uint8_t *ch[SWR_CH_MAX]; ///< samples buffer per channel + uint8_t *data; ///< samples buffer + int ch_count; ///< number of channels + int bps; ///< bytes per sample + int count; ///< number of samples + int planar; ///< 1 if planar audio, 0 otherwise + enum AVSampleFormat fmt; ///< sample format +} AudioData; + +struct DitherContext { + int method; + int noise_pos; + float scale; + float noise_scale; ///< Noise scale + int ns_taps; ///< Noise shaping dither taps + float ns_scale; ///< Noise shaping dither scale + float ns_scale_1; ///< Noise shaping dither scale^-1 + int ns_pos; ///< Noise shaping dither position + float ns_coeffs[NS_TAPS]; ///< Noise shaping filter coefficients + float ns_errors[SWR_CH_MAX][2*NS_TAPS]; + AudioData noise; ///< noise used for dithering + AudioData temp; ///< temporary storage when writing into the input buffer isn't possible + int output_sample_bits; ///< the number of used output bits, needed to scale dither correctly +}; + +typedef struct ResampleContext * (* resample_init_func)(struct ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, + double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, double kaiser_beta, double precision, int cheby, int exact_rational); +typedef void (* resample_free_func)(struct ResampleContext **c); +typedef int (* multiple_resample_func)(struct ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed); +typedef int (* resample_flush_func)(struct SwrContext *c); +typedef int (* set_compensation_func)(struct ResampleContext *c, int sample_delta, int compensation_distance); +typedef int64_t (* get_delay_func)(struct SwrContext *s, int64_t base); +typedef int (* invert_initial_buffer_func)(struct ResampleContext *c, AudioData *dst, const AudioData *src, int src_size, int *dst_idx, int *dst_count); +typedef int64_t (* get_out_samples_func)(struct SwrContext *s, int in_samples); + +struct Resampler { + resample_init_func init; + resample_free_func free; + multiple_resample_func multiple_resample; + resample_flush_func flush; + set_compensation_func set_compensation; + get_delay_func get_delay; + invert_initial_buffer_func invert_initial_buffer; + get_out_samples_func get_out_samples; +}; + +extern struct Resampler const swri_resampler; +extern struct Resampler const swri_soxr_resampler; + +struct SwrContext { + const AVClass *av_class; ///< AVClass used for AVOption and av_log() + int log_level_offset; ///< logging level offset + void *log_ctx; ///< parent logging context + enum AVSampleFormat in_sample_fmt; ///< input sample format + enum AVSampleFormat int_sample_fmt; ///< internal sample format (AV_SAMPLE_FMT_FLTP or AV_SAMPLE_FMT_S16P) + enum AVSampleFormat out_sample_fmt; ///< output sample format + int64_t in_ch_layout; ///< input channel layout + int64_t out_ch_layout; ///< output channel layout + int in_sample_rate; ///< input sample rate + int out_sample_rate; ///< output sample rate + int flags; ///< miscellaneous flags such as SWR_FLAG_RESAMPLE + float slev; ///< surround mixing level + float clev; ///< center mixing level + float lfe_mix_level; ///< LFE mixing level + float rematrix_volume; ///< rematrixing volume coefficient + float rematrix_maxval; ///< maximum value for rematrixing output + int matrix_encoding; /**< matrixed stereo encoding */ + const int *channel_map; ///< channel index (or -1 if muted channel) map + int used_ch_count; ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count) + int engine; + + int user_in_ch_count; ///< User set input channel count + int user_out_ch_count; ///< User set output channel count + int user_used_ch_count; ///< User set used channel count + int64_t user_in_ch_layout; ///< User set input channel layout + int64_t user_out_ch_layout; ///< User set output channel layout + enum AVSampleFormat user_int_sample_fmt; ///< User set internal sample format + int user_dither_method; ///< User set dither method + + struct DitherContext dither; + + int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */ + int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */ + int linear_interp; /**< if 1 then the resampling FIR filter will be linearly interpolated */ + int exact_rational; /**< if 1 then enable non power of 2 phase_count */ + double cutoff; /**< resampling cutoff frequency (swr: 6dB point; soxr: 0dB point). 1.0 corresponds to half the output sample rate */ + int filter_type; /**< swr resampling filter type */ + double kaiser_beta; /**< swr beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */ + double precision; /**< soxr resampling precision (in bits) */ + int cheby; /**< soxr: if 1 then passband rolloff will be none (Chebyshev) & irrational ratio approximation precision will be higher */ + + float min_compensation; ///< swr minimum below which no compensation will happen + float min_hard_compensation; ///< swr minimum below which no silence inject / sample drop will happen + float soft_compensation_duration; ///< swr duration over which soft compensation is applied + float max_soft_compensation; ///< swr maximum soft compensation in seconds over soft_compensation_duration + float async; ///< swr simple 1 parameter async, similar to ffmpegs -async + int64_t firstpts_in_samples; ///< swr first pts in samples + + int resample_first; ///< 1 if resampling must come first, 0 if rematrixing + int rematrix; ///< flag to indicate if rematrixing is needed (basically if input and output layouts mismatch) + int rematrix_custom; ///< flag to indicate that a custom matrix has been defined + + AudioData in; ///< input audio data + AudioData postin; ///< post-input audio data: used for rematrix/resample + AudioData midbuf; ///< intermediate audio data (postin/preout) + AudioData preout; ///< pre-output audio data: used for rematrix/resample + AudioData out; ///< converted output audio data + AudioData in_buffer; ///< cached audio data (convert and resample purpose) + AudioData silence; ///< temporary with silence + AudioData drop_temp; ///< temporary used to discard output + int in_buffer_index; ///< cached buffer position + int in_buffer_count; ///< cached buffer length + int resample_in_constraint; ///< 1 if the input end was reach before the output end, 0 otherwise + int flushed; ///< 1 if data is to be flushed and no further input is expected + int64_t outpts; ///< output PTS + int64_t firstpts; ///< first PTS + int drop_output; ///< number of output samples to drop + double delayed_samples_fixup; ///< soxr 0.1.1: needed to fixup delayed_samples after flush has been called. + + struct AudioConvert *in_convert; ///< input conversion context + struct AudioConvert *out_convert; ///< output conversion context + struct AudioConvert *full_convert; ///< full conversion context (single conversion for input and output) + struct ResampleContext *resample; ///< resampling context + struct Resampler const *resampler; ///< resampler virtual function table + + double matrix[SWR_CH_MAX][SWR_CH_MAX]; ///< floating point rematrixing coefficients + float matrix_flt[SWR_CH_MAX][SWR_CH_MAX]; ///< single precision floating point rematrixing coefficients + uint8_t *native_matrix; + uint8_t *native_one; + uint8_t *native_simd_one; + uint8_t *native_simd_matrix; + int32_t matrix32[SWR_CH_MAX][SWR_CH_MAX]; ///< 17.15 fixed point rematrixing coefficients + uint8_t matrix_ch[SWR_CH_MAX][SWR_CH_MAX+1]; ///< Lists of input channels per output channel that have non zero rematrixing coefficients + mix_1_1_func_type *mix_1_1_f; + mix_1_1_func_type *mix_1_1_simd; + + mix_2_1_func_type *mix_2_1_f; + mix_2_1_func_type *mix_2_1_simd; + + mix_any_func_type *mix_any_f; + + /* TODO: callbacks for ASM optimizations */ +}; + +av_warn_unused_result +int swri_realloc_audio(AudioData *a, int count); + +void swri_noise_shaping_int16 (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); +void swri_noise_shaping_int32 (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); +void swri_noise_shaping_float (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); +void swri_noise_shaping_double(SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); + +av_warn_unused_result +int swri_rematrix_init(SwrContext *s); +void swri_rematrix_free(SwrContext *s); +int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); +int swri_rematrix_init_x86(struct SwrContext *s); + +av_warn_unused_result +int swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat noise_fmt); +av_warn_unused_result +int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt); + +void swri_audio_convert_init_aarch64(struct AudioConvert *ac, + enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels); +void swri_audio_convert_init_arm(struct AudioConvert *ac, + enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels); +void swri_audio_convert_init_x86(struct AudioConvert *ac, + enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels); + +#endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresampleres.rc b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresampleres.rc new file mode 100644 index 0000000000..1320f78b9a --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/swresampleres.rc @@ -0,0 +1,55 @@ +/* + * Windows resource file for libswresample + * + * Copyright (C) 2012 James Almer + * Copyright (C) 2013 Tiancheng "Timothy" Gu + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "libswresample/version.h" +#include "libavutil/ffversion.h" +#include "config.h" + +1 VERSIONINFO +FILEVERSION LIBSWRESAMPLE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MINOR, LIBSWRESAMPLE_VERSION_MICRO, 0 +PRODUCTVERSION LIBSWRESAMPLE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MINOR, LIBSWRESAMPLE_VERSION_MICRO, 0 +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_DLL +{ + BLOCK "StringFileInfo" + { + BLOCK "040904B0" + { + VALUE "CompanyName", "FFmpeg Project" + VALUE "FileDescription", "FFmpeg audio resampling library" + VALUE "FileVersion", AV_STRINGIFY(LIBSWRESAMPLE_VERSION) + VALUE "InternalName", "libswresample" + VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project" + VALUE "OriginalFilename", "swresample" BUILDSUF "-" AV_STRINGIFY(LIBSWRESAMPLE_VERSION_MAJOR) SLIBSUF + VALUE "ProductName", "FFmpeg" + VALUE "ProductVersion", FFMPEG_VERSION + } + } + + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 0x04B0 + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/version.h b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/version.h new file mode 100644 index 0000000000..a0b361bc1f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/version.h @@ -0,0 +1,45 @@ +/* + * Version macros. + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_VERSION_H +#define SWRESAMPLE_VERSION_H + +/** + * @file + * Libswresample version macros + */ + +#include "libavutil/avutil.h" + +#define LIBSWRESAMPLE_VERSION_MAJOR 3 +#define LIBSWRESAMPLE_VERSION_MINOR 5 +#define LIBSWRESAMPLE_VERSION_MICRO 100 + +#define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ + LIBSWRESAMPLE_VERSION_MINOR, \ + LIBSWRESAMPLE_VERSION_MICRO) +#define LIBSWRESAMPLE_VERSION AV_VERSION(LIBSWRESAMPLE_VERSION_MAJOR, \ + LIBSWRESAMPLE_VERSION_MINOR, \ + LIBSWRESAMPLE_VERSION_MICRO) +#define LIBSWRESAMPLE_BUILD LIBSWRESAMPLE_VERSION_INT + +#define LIBSWRESAMPLE_IDENT "SwR" AV_STRINGIFY(LIBSWRESAMPLE_VERSION) + +#endif /* SWRESAMPLE_VERSION_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/audio_convert_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/audio_convert_init.c new file mode 100644 index 0000000000..bb89cf604b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/audio_convert_init.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2012 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/x86/cpu.h" +#include "libswresample/swresample_internal.h" +#include "libswresample/audioconvert.h" + +#define PROTO(pre, in, out, cap) void ff ## pre ## in## _to_ ##out## _a_ ##cap(uint8_t **dst, const uint8_t **src, int len); +#define PROTO2(pre, out, cap) PROTO(pre, int16, out, cap) PROTO(pre, int32, out, cap) PROTO(pre, float, out, cap) +#define PROTO3(pre, cap) PROTO2(pre, int16, cap) PROTO2(pre, int32, cap) PROTO2(pre, float, cap) +#define PROTO4(pre) PROTO3(pre, mmx) PROTO3(pre, sse) PROTO3(pre, sse2) PROTO3(pre, ssse3) PROTO3(pre, sse4) PROTO3(pre, avx) PROTO3(pre, avx2) +PROTO4(_) +PROTO4(_pack_2ch_) +PROTO4(_pack_6ch_) +PROTO4(_pack_8ch_) +PROTO4(_unpack_2ch_) +PROTO4(_unpack_6ch_) + +av_cold void swri_audio_convert_init_x86(struct AudioConvert *ac, + enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels){ + int mm_flags = av_get_cpu_flags(); + + ac->simd_f= NULL; + +//FIXME add memcpy case + +#define MULTI_CAPS_FUNC(flag, cap) \ + if (EXTERNAL_##flag(mm_flags)) {\ + if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S16 || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16P)\ + ac->simd_f = ff_int16_to_int32_a_ ## cap;\ + if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S32P)\ + ac->simd_f = ff_int32_to_int16_a_ ## cap;\ + } + +MULTI_CAPS_FUNC(MMX, mmx) +MULTI_CAPS_FUNC(SSE2, sse2) + + if(EXTERNAL_MMX(mm_flags)) { + if(channels == 6) { + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_6ch_float_to_float_a_mmx; + } + } + if(EXTERNAL_SSE(mm_flags)) { + if(channels == 6) { + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_6ch_float_to_float_a_sse; + + if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S32) + ac->simd_f = ff_unpack_6ch_float_to_float_a_sse; + } + } + if(EXTERNAL_SSE2(mm_flags)) { + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_int32_to_float_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S16 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S16P) + ac->simd_f = ff_int16_to_float_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = ff_float_to_int32_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = ff_float_to_int16_a_sse2; + + if(channels == 2) { + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_2ch_int32_to_int32_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_S16P) + ac->simd_f = ff_pack_2ch_int16_to_int16_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S16P) + ac->simd_f = ff_pack_2ch_int16_to_int32_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_2ch_int32_to_int16_a_sse2; + + if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S32) + ac->simd_f = ff_unpack_2ch_int32_to_int32_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S16) + ac->simd_f = ff_unpack_2ch_int16_to_int16_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16) + ac->simd_f = ff_unpack_2ch_int16_to_int32_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S32) + ac->simd_f = ff_unpack_2ch_int32_to_int16_a_sse2; + + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_2ch_int32_to_float_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = ff_pack_2ch_float_to_int32_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S16P) + ac->simd_f = ff_pack_2ch_int16_to_float_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = ff_pack_2ch_float_to_int16_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32) + ac->simd_f = ff_unpack_2ch_int32_to_float_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLT) + ac->simd_f = ff_unpack_2ch_float_to_int32_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S16) + ac->simd_f = ff_unpack_2ch_int16_to_float_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLT) + ac->simd_f = ff_unpack_2ch_float_to_int16_a_sse2; + } + if(channels == 6) { + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_6ch_int32_to_float_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = ff_pack_6ch_float_to_int32_a_sse2; + + if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32) + ac->simd_f = ff_unpack_6ch_int32_to_float_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLT) + ac->simd_f = ff_unpack_6ch_float_to_int32_a_sse2; + } + if(channels == 8) { + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_8ch_float_to_float_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_8ch_int32_to_float_a_sse2; + if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = ff_pack_8ch_float_to_int32_a_sse2; + } + } + if(EXTERNAL_SSSE3(mm_flags)) { + if(channels == 2) { + if( out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S16) + ac->simd_f = ff_unpack_2ch_int16_to_int16_a_ssse3; + if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16) + ac->simd_f = ff_unpack_2ch_int16_to_int32_a_ssse3; + if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S16) + ac->simd_f = ff_unpack_2ch_int16_to_float_a_ssse3; + } + } + if(EXTERNAL_AVX_FAST(mm_flags)) { + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_int32_to_float_a_avx; + } + if(EXTERNAL_AVX(mm_flags)) { + if(channels == 6) { + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_6ch_float_to_float_a_avx; + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_6ch_int32_to_float_a_avx; + if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = ff_pack_6ch_float_to_int32_a_avx; + + if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S32) + ac->simd_f = ff_unpack_6ch_float_to_float_a_avx; + if( out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32) + ac->simd_f = ff_unpack_6ch_int32_to_float_a_avx; + if( out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLT) + ac->simd_f = ff_unpack_6ch_float_to_int32_a_avx; + } + if(channels == 8) { + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_8ch_float_to_float_a_avx; + if( out_fmt == AV_SAMPLE_FMT_FLT && in_fmt == AV_SAMPLE_FMT_S32P) + ac->simd_f = ff_pack_8ch_int32_to_float_a_avx; + if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = ff_pack_8ch_float_to_int32_a_avx; + } + } + if(EXTERNAL_AVX2_FAST(mm_flags)) { + if( out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLTP) + ac->simd_f = ff_float_to_int32_a_avx2; + } +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/rematrix_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/rematrix_init.c new file mode 100644 index 0000000000..d6616f83be --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/rematrix_init.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/x86/cpu.h" +#include "libswresample/swresample_internal.h" + +#define D(type, simd) \ +mix_1_1_func_type ff_mix_1_1_a_## type ## _ ## simd;\ +mix_2_1_func_type ff_mix_2_1_a_## type ## _ ## simd; + +D(float, sse) +D(float, avx) +D(int16, mmx) +D(int16, sse2) + +av_cold int swri_rematrix_init_x86(struct SwrContext *s){ +#if HAVE_X86ASM + int mm_flags = av_get_cpu_flags(); + int nb_in = s->used_ch_count; + int nb_out = s->out.ch_count; + int num = nb_in * nb_out; + int i,j; + + s->mix_1_1_simd = NULL; + s->mix_2_1_simd = NULL; + + if (s->midbuf.fmt == AV_SAMPLE_FMT_S16P){ + if(EXTERNAL_MMX(mm_flags)) { + s->mix_1_1_simd = ff_mix_1_1_a_int16_mmx; + s->mix_2_1_simd = ff_mix_2_1_a_int16_mmx; + } + if(EXTERNAL_SSE2(mm_flags)) { + s->mix_1_1_simd = ff_mix_1_1_a_int16_sse2; + s->mix_2_1_simd = ff_mix_2_1_a_int16_sse2; + } + s->native_simd_matrix = av_mallocz_array(num, 2 * sizeof(int16_t)); + s->native_simd_one = av_mallocz(2 * sizeof(int16_t)); + if (!s->native_simd_matrix || !s->native_simd_one) + return AVERROR(ENOMEM); + + for(i=0; inative_matrix)[i * nb_in + j])); + sh = FFMAX(av_log2(sh) - 14, 0); + for(j=0; jnative_simd_matrix)[2*(i * nb_in + j)+1] = 15 - sh; + ((int16_t*)s->native_simd_matrix)[2*(i * nb_in + j)] = + ((((int*)s->native_matrix)[i * nb_in + j]) + (1<>1)) >> sh; + } + } + ((int16_t*)s->native_simd_one)[1] = 14; + ((int16_t*)s->native_simd_one)[0] = 16384; + } else if(s->midbuf.fmt == AV_SAMPLE_FMT_FLTP){ + if(EXTERNAL_SSE(mm_flags)) { + s->mix_1_1_simd = ff_mix_1_1_a_float_sse; + s->mix_2_1_simd = ff_mix_2_1_a_float_sse; + } + if(EXTERNAL_AVX_FAST(mm_flags)) { + s->mix_1_1_simd = ff_mix_1_1_a_float_avx; + s->mix_2_1_simd = ff_mix_2_1_a_float_avx; + } + s->native_simd_matrix = av_mallocz_array(num, sizeof(float)); + s->native_simd_one = av_mallocz(sizeof(float)); + if (!s->native_simd_matrix || !s->native_simd_one) + return AVERROR(ENOMEM); + memcpy(s->native_simd_matrix, s->native_matrix, num * sizeof(float)); + memcpy(s->native_simd_one, s->native_one, sizeof(float)); + } +#endif + + return 0; +} diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/resample_init.c b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/resample_init.c new file mode 100644 index 0000000000..c6b2a36060 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/resample_init.c @@ -0,0 +1,100 @@ +/* + * audio resampling + * Copyright (c) 2004-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio resampling + * @author Michael Niedermayer + */ + +#include "libavutil/x86/cpu.h" +#include "libswresample/resample.h" + +#define RESAMPLE_FUNCS(type, opt) \ +int ff_resample_common_##type##_##opt(ResampleContext *c, void *dst, \ + const void *src, int sz, int upd); \ +int ff_resample_linear_##type##_##opt(ResampleContext *c, void *dst, \ + const void *src, int sz, int upd) + +RESAMPLE_FUNCS(int16, mmxext); +RESAMPLE_FUNCS(int16, sse2); +RESAMPLE_FUNCS(int16, xop); +RESAMPLE_FUNCS(float, sse); +RESAMPLE_FUNCS(float, avx); +RESAMPLE_FUNCS(float, fma3); +RESAMPLE_FUNCS(float, fma4); +RESAMPLE_FUNCS(double, sse2); +RESAMPLE_FUNCS(double, avx); +RESAMPLE_FUNCS(double, fma3); + +av_cold void swri_resample_dsp_x86_init(ResampleContext *c) +{ + int av_unused mm_flags = av_get_cpu_flags(); + + switch(c->format){ + case AV_SAMPLE_FMT_S16P: + if (ARCH_X86_32 && EXTERNAL_MMXEXT(mm_flags)) { + c->dsp.resample_linear = ff_resample_linear_int16_mmxext; + c->dsp.resample_common = ff_resample_common_int16_mmxext; + } + if (EXTERNAL_SSE2(mm_flags)) { + c->dsp.resample_linear = ff_resample_linear_int16_sse2; + c->dsp.resample_common = ff_resample_common_int16_sse2; + } + if (EXTERNAL_XOP(mm_flags)) { + c->dsp.resample_linear = ff_resample_linear_int16_xop; + c->dsp.resample_common = ff_resample_common_int16_xop; + } + break; + case AV_SAMPLE_FMT_FLTP: + if (EXTERNAL_SSE(mm_flags)) { + c->dsp.resample_linear = ff_resample_linear_float_sse; + c->dsp.resample_common = ff_resample_common_float_sse; + } + if (EXTERNAL_AVX_FAST(mm_flags)) { + c->dsp.resample_linear = ff_resample_linear_float_avx; + c->dsp.resample_common = ff_resample_common_float_avx; + } + if (EXTERNAL_FMA3_FAST(mm_flags)) { + c->dsp.resample_linear = ff_resample_linear_float_fma3; + c->dsp.resample_common = ff_resample_common_float_fma3; + } + if (EXTERNAL_FMA4(mm_flags)) { + c->dsp.resample_linear = ff_resample_linear_float_fma4; + c->dsp.resample_common = ff_resample_common_float_fma4; + } + break; + case AV_SAMPLE_FMT_DBLP: + if (EXTERNAL_SSE2(mm_flags)) { + c->dsp.resample_linear = ff_resample_linear_double_sse2; + c->dsp.resample_common = ff_resample_common_double_sse2; + } + if (EXTERNAL_AVX_FAST(mm_flags)) { + c->dsp.resample_linear = ff_resample_linear_double_avx; + c->dsp.resample_common = ff_resample_common_double_avx; + } + if (EXTERNAL_FMA3_FAST(mm_flags)) { + c->dsp.resample_linear = ff_resample_linear_double_fma3; + c->dsp.resample_common = ff_resample_common_double_fma3; + } + break; + } +} diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index 786c8aef82..29834e44f5 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -400,7 +400,6 @@ fi # libopus, for WebRTC to transcode AAC with Opus. ##################################################################################### if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then - # cross build not specified, if exists flag, need to rebuild for no-arm platform. if [[ -f ${SRS_OBJS}/opus/lib/libopus.a ]]; then echo "The opus-1.3.1 is ok."; else @@ -417,6 +416,70 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then if [ ! -f ${SRS_OBJS}/opus/lib/libopus.a ]; then echo "Build opus-1.3.1 failed."; exit -1; fi fi +##################################################################################### +# ffmpeg-fix, for WebRTC to transcode AAC with Opus. +##################################################################################### +if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then + if [[ -f ${SRS_OBJS}/ffmpeg/lib/libavcodec.a ]]; then + echo "The ffmpeg-4.2-fit is ok."; + else + echo "Building ffmpeg-4.2-fit."; + ( + rm -rf ${SRS_OBJS}/ffmpeg-4.2-fit && cd ${SRS_OBJS} && ABS_OBJS=`pwd` && + ln -sf ../3rdparty/ffmpeg-4.2-fit && cd ffmpeg-4.2-fit && + PKG_CONFIG_PATH=$ABS_OBJS/opus/lib/pkgconfig ./configure \ + --prefix=`pwd`/_release \ + --pkg-config-flags="--static" \ + --extra-libs=-lpthread \ + --extra-libs=-lm \ + --disable-programs \ + --disable-doc \ + --disable-htmlpages \ + --disable-manpages \ + --disable-podpages \ + --disable-txtpages \ + --disable-avdevice \ + --disable-avformat \ + --disable-swscale \ + --disable-postproc \ + --disable-avfilter \ + --disable-network \ + --disable-dct \ + --disable-dwt \ + --disable-error-resilience \ + --disable-lsp \ + --disable-lzo \ + --disable-faan \ + --disable-pixelutils \ + --disable-hwaccels \ + --disable-devices \ + --disable-audiotoolbox \ + --disable-videotoolbox \ + --disable-appkit \ + --disable-coreimage \ + --disable-avfoundation \ + --disable-securetransport \ + --disable-iconv \ + --disable-lzma \ + --disable-sdl2 \ + --disable-everything \ + --enable-decoder=aac \ + --enable-decoder=aac_fixed \ + --enable-decoder=aac_latm \ + --enable-decoder=libopus \ + --enable-encoder=aac \ + --enable-encoder=opus \ + --enable-encoder=libopus \ + --enable-libopus && + make ${SRS_JOBS} && make install + cd .. && rm -rf ffmpeg && ln -sf ffmpeg-4.2-fit/_release ffmpeg + ) + fi + # check status + ret=$?; if [[ $ret -ne 0 ]]; then echo "Build ffmpeg-4.2-fit failed, ret=$ret"; exit $ret; fi + if [ ! -f ${SRS_OBJS}/ffmpeg/lib/libavcodec.a ]; then echo "Build ffmpeg-4.2-fit failed."; exit -1; fi +fi + ##################################################################################### # live transcoding, ffmpeg-4.1, x264-core157, lame-3.99.5, libaacplus-2.0.2. ##################################################################################### From 734e8487410e2e22e2a88bbb912f341aba4ac5c8 Mon Sep 17 00:00:00 2001 From: xiaozhihong Date: Sun, 22 Mar 2020 16:54:31 +0800 Subject: [PATCH 67/69] Update RtcSession peer address when changed. --- trunk/src/app/srs_app_listener.cpp | 26 ++++++++++++-------------- trunk/src/app/srs_app_listener.hpp | 9 ++++++--- trunk/src/app/srs_app_rtc_conn.cpp | 22 +++++++++++++++++++--- trunk/src/app/srs_app_rtc_conn.hpp | 5 ++++- 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/trunk/src/app/srs_app_listener.cpp b/trunk/src/app/srs_app_listener.cpp index 667dd50365..00a9d75608 100755 --- a/trunk/src/app/srs_app_listener.cpp +++ b/trunk/src/app/srs_app_listener.cpp @@ -237,23 +237,21 @@ SrsUdpMuxSocket::~SrsUdpMuxSocket() srs_freepa(buf); } -SrsUdpMuxSocket::SrsUdpMuxSocket(const SrsUdpMuxSocket& rhs) +SrsUdpMuxSocket* SrsUdpMuxSocket::copy_sendonly() { - operator=(rhs); -} + SrsUdpMuxSocket* sendonly = new SrsUdpMuxSocket(lfd); -SrsUdpMuxSocket& SrsUdpMuxSocket::operator=(const SrsUdpMuxSocket& rhs) -{ - buf = NULL; - nb_buf = 0; - nread = 0; - lfd = rhs.lfd; - from = rhs.from; - fromlen = rhs.fromlen; - peer_ip = rhs.peer_ip; - peer_port = rhs.peer_port; + // Don't copy buffer + srs_freepa(sendonly->buf); + sendonly->nb_buf = 0; + sendonly->nread = 0; + sendonly->lfd = lfd; + sendonly->from = from; + sendonly->fromlen = fromlen; + sendonly->peer_ip = peer_ip; + sendonly->peer_port = peer_port; - return *this; + return sendonly; } int SrsUdpMuxSocket::recvfrom(srs_utime_t timeout) diff --git a/trunk/src/app/srs_app_listener.hpp b/trunk/src/app/srs_app_listener.hpp index 1a73b6fafb..75aea4c529 100644 --- a/trunk/src/app/srs_app_listener.hpp +++ b/trunk/src/app/srs_app_listener.hpp @@ -143,9 +143,6 @@ class SrsUdpMuxSocket SrsUdpMuxSocket(srs_netfd_t fd); virtual ~SrsUdpMuxSocket(); - SrsUdpMuxSocket(const SrsUdpMuxSocket& rhs); - SrsUdpMuxSocket& operator=(const SrsUdpMuxSocket& rhs); - int recvfrom(srs_utime_t timeout); srs_error_t sendto(void* data, int size, srs_utime_t timeout); @@ -154,6 +151,12 @@ class SrsUdpMuxSocket std::string get_peer_ip() const { return peer_ip; } int get_peer_port() const { return peer_port; } std::string get_peer_id(); +public: + SrsUdpMuxSocket* copy_sendonly(); +private: + // Don't allow copy, user copy_sendonly instead + SrsUdpMuxSocket(const SrsUdpMuxSocket& rhs); + SrsUdpMuxSocket& operator=(const SrsUdpMuxSocket& rhs); }; class SrsUdpMuxListener : public ISrsCoroutineHandler diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 77de89bd69..da08a5cf37 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -605,18 +605,19 @@ srs_error_t SrsDtlsSession::unprotect_rtcp(char* out_buf, const char* in_buf, in } SrsRtcSenderThread::SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid) - : ukt(NULL) + : sendonly_ukt(NULL) { _parent_cid = parent_cid; trd = new SrsDummyCoroutine(); rtc_session = s; - ukt = *u; + sendonly_ukt = u->copy_sendonly(); } SrsRtcSenderThread::~SrsRtcSenderThread() { srs_freep(trd); + srs_freep(sendonly_ukt); } int SrsRtcSenderThread::cid() @@ -695,10 +696,19 @@ srs_error_t SrsRtcSenderThread::cycle() continue; } - send_and_free_messages(msgs.msgs, msg_count, &ukt); + send_and_free_messages(msgs.msgs, msg_count, sendonly_ukt); } } +void SrsRtcSenderThread::update_sendonly_socket(SrsUdpMuxSocket* ukt) +{ + srs_trace("session %s address changed, update %s -> %s", + rtc_session->id().c_str(), sendonly_ukt->get_peer_id().c_str(), ukt->get_peer_id().c_str()); + + srs_freep(sendonly_ukt); + sendonly_ukt = ukt->copy_sendonly(); +} + void SrsRtcSenderThread::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* udp_mux_skt) { srs_error_t err = srs_success; @@ -776,6 +786,12 @@ srs_error_t SrsRtcSession::on_stun(SrsUdpMuxSocket* udp_mux_skt, SrsStunPacket* last_stun_time = srs_get_system_time(); + if (strd && strd->sendonly_ukt) { + if (strd->sendonly_ukt->get_peer_id() != udp_mux_skt->get_peer_id()) { + strd->update_sendonly_socket(udp_mux_skt); + } + } + return err; } diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 029c8d4ab0..aaf0cbe622 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -165,7 +165,8 @@ class SrsRtcSenderThread : public ISrsCoroutineHandler int _parent_cid; private: SrsRtcSession* rtc_session; - SrsUdpMuxSocket ukt; +public: + SrsUdpMuxSocket* sendonly_ukt; public: SrsRtcSenderThread(SrsRtcSession* s, SrsUdpMuxSocket* u, int parent_cid); virtual ~SrsRtcSenderThread(); @@ -177,6 +178,8 @@ class SrsRtcSenderThread : public ISrsCoroutineHandler virtual void stop_loop(); public: virtual srs_error_t cycle(); +public: + void update_sendonly_socket(SrsUdpMuxSocket* ukt); private: void send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, SrsUdpMuxSocket* udp_mux_skt); }; From 37c84eccc02181c3466b52ad634b5f1a3a16ae0a Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 22 Mar 2020 17:14:07 +0800 Subject: [PATCH 68/69] For #1659, #307, add x86 asm for ffmpeg for rtc --- trunk/3rdparty/ffmpeg-4.2-fit/.gitignore | 3 +- .../libavcodec/aarch64/Makefile | 60 + .../ffmpeg-4.2-fit/libavcodec/x86/Makefile | 199 ++ .../libavcodec/x86/aacencdsp.asm | 86 + .../libavcodec/x86/aacpsdsp.asm | 487 +++++ .../libavcodec/x86/celt_pvq_search.asm | 385 ++++ .../ffmpeg-4.2-fit/libavcodec/x86/fft.asm | 1085 +++++++++++ .../ffmpeg-4.2-fit/libavcodec/x86/mdct15.asm | 221 +++ .../ffmpeg-4.2-fit/libavcodec/x86/sbrdsp.asm | 548 ++++++ .../ffmpeg-4.2-fit/libavutil/aarch64/Makefile | 4 + .../ffmpeg-4.2-fit/libavutil/arm/Makefile | 8 + .../ffmpeg-4.2-fit/libavutil/ffversion.h | 5 - .../ffmpeg-4.2-fit/libavutil/x86/Makefile | 18 + .../ffmpeg-4.2-fit/libavutil/x86/cpuid.asm | 91 + .../libavutil/x86/fixed_dsp.asm | 48 + .../libavutil/x86/float_dsp.asm | 484 +++++ .../ffmpeg-4.2-fit/libavutil/x86/imgutils.asm | 53 + .../ffmpeg-4.2-fit/libavutil/x86/lls.asm | 290 +++ .../ffmpeg-4.2-fit/libavutil/x86/x86inc.asm | 1701 +++++++++++++++++ .../ffmpeg-4.2-fit/libavutil/x86/x86util.asm | 1028 ++++++++++ .../libswresample/aarch64/Makefile | 7 + .../ffmpeg-4.2-fit/libswresample/arm/Makefile | 8 + .../ffmpeg-4.2-fit/libswresample/x86/Makefile | 9 + .../libswresample/x86/audio_convert.asm | 739 +++++++ .../libswresample/x86/rematrix.asm | 250 +++ .../libswresample/x86/resample.asm | 619 ++++++ trunk/auto/depends.sh | 50 +- trunk/configure | 5 +- 28 files changed, 8441 insertions(+), 50 deletions(-) create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacencdsp.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacpsdsp.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/celt_pvq_search.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mdct15.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbrdsp.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/Makefile delete mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffversion.h create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpuid.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/fixed_dsp.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/float_dsp.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/imgutils.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/lls.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/x86inc.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/x86util.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/Makefile create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/audio_convert.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/rematrix.asm create mode 100644 trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/resample.asm diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/.gitignore b/trunk/3rdparty/ffmpeg-4.2-fit/.gitignore index c348b5e28b..9ce1b69cd0 100644 --- a/trunk/3rdparty/ffmpeg-4.2-fit/.gitignore +++ b/trunk/3rdparty/ffmpeg-4.2-fit/.gitignore @@ -14,4 +14,5 @@ ffbuild/.config libavutil/lib.version libavcodec/libavcodec.version libavutil/libavutil.version -libswresample/libswresample.version \ No newline at end of file +libswresample/libswresample.version +libavutil/ffversion.h \ No newline at end of file diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/Makefile new file mode 100644 index 0000000000..00f93bf59f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/aarch64/Makefile @@ -0,0 +1,60 @@ +# subsystems +OBJS-$(CONFIG_FFT) += aarch64/fft_init_aarch64.o +OBJS-$(CONFIG_FMTCONVERT) += aarch64/fmtconvert_init.o +OBJS-$(CONFIG_H264CHROMA) += aarch64/h264chroma_init_aarch64.o +OBJS-$(CONFIG_H264DSP) += aarch64/h264dsp_init_aarch64.o +OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_init.o +OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_init_aarch64.o +OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_init_aarch64.o +OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_init.o +OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o +OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp_init.o +OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_init_aarch64.o + +# decoders/encoders +OBJS-$(CONFIG_AAC_DECODER) += aarch64/aacpsdsp_init_aarch64.o \ + aarch64/sbrdsp_init_aarch64.o +OBJS-$(CONFIG_DCA_DECODER) += aarch64/synth_filter_init.o +OBJS-$(CONFIG_OPUS_DECODER) += aarch64/opusdsp_init.o +OBJS-$(CONFIG_RV40_DECODER) += aarch64/rv40dsp_init_aarch64.o +OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_init_aarch64.o +OBJS-$(CONFIG_VORBIS_DECODER) += aarch64/vorbisdsp_init.o +OBJS-$(CONFIG_VP9_DECODER) += aarch64/vp9dsp_init_10bpp_aarch64.o \ + aarch64/vp9dsp_init_12bpp_aarch64.o \ + aarch64/vp9dsp_init_aarch64.o + +# ARMv8 optimizations + +# subsystems +ARMV8-OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp.o + +# NEON optimizations + +# subsystems +NEON-OBJS-$(CONFIG_AAC_DECODER) += aarch64/sbrdsp_neon.o +NEON-OBJS-$(CONFIG_FFT) += aarch64/fft_neon.o +NEON-OBJS-$(CONFIG_FMTCONVERT) += aarch64/fmtconvert_neon.o +NEON-OBJS-$(CONFIG_H264CHROMA) += aarch64/h264cmc_neon.o +NEON-OBJS-$(CONFIG_H264DSP) += aarch64/h264dsp_neon.o \ + aarch64/h264idct_neon.o +NEON-OBJS-$(CONFIG_H264PRED) += aarch64/h264pred_neon.o +NEON-OBJS-$(CONFIG_H264QPEL) += aarch64/h264qpel_neon.o \ + aarch64/hpeldsp_neon.o +NEON-OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_neon.o +NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o \ + aarch64/simple_idct_neon.o +NEON-OBJS-$(CONFIG_MDCT) += aarch64/mdct_neon.o +NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o +NEON-OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_neon.o + +# decoders/encoders +NEON-OBJS-$(CONFIG_AAC_DECODER) += aarch64/aacpsdsp_neon.o +NEON-OBJS-$(CONFIG_DCA_DECODER) += aarch64/synth_filter_neon.o +NEON-OBJS-$(CONFIG_OPUS_DECODER) += aarch64/opusdsp_neon.o +NEON-OBJS-$(CONFIG_VORBIS_DECODER) += aarch64/vorbisdsp_neon.o +NEON-OBJS-$(CONFIG_VP9_DECODER) += aarch64/vp9itxfm_16bpp_neon.o \ + aarch64/vp9itxfm_neon.o \ + aarch64/vp9lpf_16bpp_neon.o \ + aarch64/vp9lpf_neon.o \ + aarch64/vp9mc_16bpp_neon.o \ + aarch64/vp9mc_neon.o diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/Makefile new file mode 100644 index 0000000000..194135dafb --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/Makefile @@ -0,0 +1,199 @@ +OBJS += x86/constants.o \ + +# subsystems +OBJS-$(CONFIG_AC3DSP) += x86/ac3dsp_init.o +OBJS-$(CONFIG_AUDIODSP) += x86/audiodsp_init.o +OBJS-$(CONFIG_BLOCKDSP) += x86/blockdsp_init.o +OBJS-$(CONFIG_BSWAPDSP) += x86/bswapdsp_init.o +OBJS-$(CONFIG_DCT) += x86/dct_init.o +OBJS-$(CONFIG_DIRAC_DECODER) += x86/diracdsp_init.o \ + x86/dirac_dwt_init.o +OBJS-$(CONFIG_FDCTDSP) += x86/fdctdsp_init.o +OBJS-$(CONFIG_FFT) += x86/fft_init.o +OBJS-$(CONFIG_FLACDSP) += x86/flacdsp_init.o +OBJS-$(CONFIG_FMTCONVERT) += x86/fmtconvert_init.o +OBJS-$(CONFIG_H263DSP) += x86/h263dsp_init.o +OBJS-$(CONFIG_H264CHROMA) += x86/h264chroma_init.o +OBJS-$(CONFIG_H264DSP) += x86/h264dsp_init.o +OBJS-$(CONFIG_H264PRED) += x86/h264_intrapred_init.o +OBJS-$(CONFIG_H264QPEL) += x86/h264_qpel.o +OBJS-$(CONFIG_HPELDSP) += x86/hpeldsp_init.o +OBJS-$(CONFIG_LLAUDDSP) += x86/lossless_audiodsp_init.o +OBJS-$(CONFIG_LLVIDDSP) += x86/lossless_videodsp_init.o +OBJS-$(CONFIG_LLVIDENCDSP) += x86/lossless_videoencdsp_init.o +OBJS-$(CONFIG_HUFFYUVDSP) += x86/huffyuvdsp_init.o +OBJS-$(CONFIG_HUFFYUVENCDSP) += x86/huffyuvencdsp_init.o +OBJS-$(CONFIG_IDCTDSP) += x86/idctdsp_init.o +OBJS-$(CONFIG_LPC) += x86/lpc.o +OBJS-$(CONFIG_MDCT15) += x86/mdct15_init.o +OBJS-$(CONFIG_ME_CMP) += x86/me_cmp_init.o +OBJS-$(CONFIG_MPEGAUDIODSP) += x86/mpegaudiodsp.o +OBJS-$(CONFIG_MPEGVIDEO) += x86/mpegvideo.o \ + x86/mpegvideodsp.o +OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoenc.o \ + x86/mpegvideoencdsp_init.o +OBJS-$(CONFIG_PIXBLOCKDSP) += x86/pixblockdsp_init.o +OBJS-$(CONFIG_QPELDSP) += x86/qpeldsp_init.o +OBJS-$(CONFIG_RV34DSP) += x86/rv34dsp_init.o +OBJS-$(CONFIG_VC1DSP) += x86/vc1dsp_init.o +OBJS-$(CONFIG_VIDEODSP) += x86/videodsp_init.o +OBJS-$(CONFIG_VP3DSP) += x86/vp3dsp_init.o +OBJS-$(CONFIG_VP8DSP) += x86/vp8dsp_init.o +OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o + +# decoders/encoders +OBJS-$(CONFIG_AAC_DECODER) += x86/aacpsdsp_init.o \ + x86/sbrdsp_init.o +OBJS-$(CONFIG_AAC_ENCODER) += x86/aacencdsp_init.o +OBJS-$(CONFIG_ADPCM_G722_DECODER) += x86/g722dsp_init.o +OBJS-$(CONFIG_ADPCM_G722_ENCODER) += x86/g722dsp_init.o +OBJS-$(CONFIG_ALAC_DECODER) += x86/alacdsp_init.o +OBJS-$(CONFIG_APNG_DECODER) += x86/pngdsp_init.o +OBJS-$(CONFIG_CAVS_DECODER) += x86/cavsdsp.o +OBJS-$(CONFIG_DCA_DECODER) += x86/dcadsp_init.o x86/synth_filter_init.o +OBJS-$(CONFIG_DNXHD_ENCODER) += x86/dnxhdenc_init.o +OBJS-$(CONFIG_EXR_DECODER) += x86/exrdsp_init.o +OBJS-$(CONFIG_OPUS_DECODER) += x86/opusdsp_init.o +OBJS-$(CONFIG_OPUS_ENCODER) += x86/celt_pvq_init.o +OBJS-$(CONFIG_HEVC_DECODER) += x86/hevcdsp_init.o +OBJS-$(CONFIG_JPEG2000_DECODER) += x86/jpeg2000dsp_init.o +OBJS-$(CONFIG_LSCR_DECODER) += x86/pngdsp_init.o +OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp_init.o +OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct_init.o +OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp_init.o +OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp_init.o +OBJS-$(CONFIG_PRORES_LGPL_DECODER) += x86/proresdsp_init.o +OBJS-$(CONFIG_RV40_DECODER) += x86/rv40dsp_init.o +OBJS-$(CONFIG_SBC_ENCODER) += x86/sbcdsp_init.o +OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc_init.o +OBJS-$(CONFIG_TAK_DECODER) += x86/takdsp_init.o +OBJS-$(CONFIG_TRUEHD_DECODER) += x86/mlpdsp_init.o +OBJS-$(CONFIG_TTA_DECODER) += x86/ttadsp_init.o +OBJS-$(CONFIG_TTA_ENCODER) += x86/ttaencdsp_init.o +OBJS-$(CONFIG_UTVIDEO_DECODER) += x86/utvideodsp_init.o +OBJS-$(CONFIG_V210_DECODER) += x86/v210-init.o +OBJS-$(CONFIG_V210_ENCODER) += x86/v210enc_init.o +OBJS-$(CONFIG_VORBIS_DECODER) += x86/vorbisdsp_init.o +OBJS-$(CONFIG_VP3_DECODER) += x86/hpeldsp_vp3_init.o +OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp_init.o +OBJS-$(CONFIG_VP9_DECODER) += x86/vp9dsp_init.o \ + x86/vp9dsp_init_10bpp.o \ + x86/vp9dsp_init_12bpp.o \ + x86/vp9dsp_init_16bpp.o +OBJS-$(CONFIG_WEBP_DECODER) += x86/vp8dsp_init.o + + +# GCC inline assembly optimizations +# subsystems +MMX-OBJS-$(CONFIG_FDCTDSP) += x86/fdct.o +MMX-OBJS-$(CONFIG_VC1DSP) += x86/vc1dsp_mmx.o + +# decoders/encoders +MMX-OBJS-$(CONFIG_SNOW_DECODER) += x86/snowdsp.o +MMX-OBJS-$(CONFIG_SNOW_ENCODER) += x86/snowdsp.o + +# subsystems +X86ASM-OBJS-$(CONFIG_AC3DSP) += x86/ac3dsp.o \ + x86/ac3dsp_downmix.o +X86ASM-OBJS-$(CONFIG_AUDIODSP) += x86/audiodsp.o +X86ASM-OBJS-$(CONFIG_BLOCKDSP) += x86/blockdsp.o +X86ASM-OBJS-$(CONFIG_BSWAPDSP) += x86/bswapdsp.o +X86ASM-OBJS-$(CONFIG_DCT) += x86/dct32.o +X86ASM-OBJS-$(CONFIG_FFT) += x86/fft.o +X86ASM-OBJS-$(CONFIG_FMTCONVERT) += x86/fmtconvert.o +X86ASM-OBJS-$(CONFIG_H263DSP) += x86/h263_loopfilter.o +X86ASM-OBJS-$(CONFIG_H264CHROMA) += x86/h264_chromamc.o \ + x86/h264_chromamc_10bit.o +X86ASM-OBJS-$(CONFIG_H264DSP) += x86/h264_deblock.o \ + x86/h264_deblock_10bit.o \ + x86/h264_idct.o \ + x86/h264_idct_10bit.o \ + x86/h264_weight.o \ + x86/h264_weight_10bit.o +X86ASM-OBJS-$(CONFIG_H264PRED) += x86/h264_intrapred.o \ + x86/h264_intrapred_10bit.o +X86ASM-OBJS-$(CONFIG_H264QPEL) += x86/h264_qpel_8bit.o \ + x86/h264_qpel_10bit.o \ + x86/fpel.o \ + x86/qpel.o +X86ASM-OBJS-$(CONFIG_HPELDSP) += x86/fpel.o \ + x86/hpeldsp.o +X86ASM-OBJS-$(CONFIG_HUFFYUVDSP) += x86/huffyuvdsp.o +X86ASM-OBJS-$(CONFIG_HUFFYUVENCDSP) += x86/huffyuvencdsp.o +X86ASM-OBJS-$(CONFIG_IDCTDSP) += x86/idctdsp.o +X86ASM-OBJS-$(CONFIG_LLAUDDSP) += x86/lossless_audiodsp.o +X86ASM-OBJS-$(CONFIG_LLVIDDSP) += x86/lossless_videodsp.o +X86ASM-OBJS-$(CONFIG_LLVIDENCDSP) += x86/lossless_videoencdsp.o +X86ASM-OBJS-$(CONFIG_MDCT15) += x86/mdct15.o +X86ASM-OBJS-$(CONFIG_ME_CMP) += x86/me_cmp.o +X86ASM-OBJS-$(CONFIG_MPEGAUDIODSP) += x86/imdct36.o +X86ASM-OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoencdsp.o +X86ASM-OBJS-$(CONFIG_OPUS_DECODER) += x86/opusdsp.o +X86ASM-OBJS-$(CONFIG_OPUS_ENCODER) += x86/celt_pvq_search.o +X86ASM-OBJS-$(CONFIG_PIXBLOCKDSP) += x86/pixblockdsp.o +X86ASM-OBJS-$(CONFIG_QPELDSP) += x86/qpeldsp.o \ + x86/fpel.o \ + x86/qpel.o +X86ASM-OBJS-$(CONFIG_RV34DSP) += x86/rv34dsp.o +X86ASM-OBJS-$(CONFIG_VC1DSP) += x86/vc1dsp_loopfilter.o \ + x86/vc1dsp_mc.o +X86ASM-OBJS-$(CONFIG_IDCTDSP) += x86/simple_idct10.o \ + x86/simple_idct.o +X86ASM-OBJS-$(CONFIG_VIDEODSP) += x86/videodsp.o +X86ASM-OBJS-$(CONFIG_VP3DSP) += x86/vp3dsp.o +X86ASM-OBJS-$(CONFIG_VP8DSP) += x86/vp8dsp.o \ + x86/vp8dsp_loopfilter.o + +# decoders/encoders +X86ASM-OBJS-$(CONFIG_AAC_DECODER) += x86/aacpsdsp.o \ + x86/sbrdsp.o +X86ASM-OBJS-$(CONFIG_AAC_ENCODER) += x86/aacencdsp.o +X86ASM-OBJS-$(CONFIG_ADPCM_G722_DECODER) += x86/g722dsp.o +X86ASM-OBJS-$(CONFIG_ADPCM_G722_ENCODER) += x86/g722dsp.o +X86ASM-OBJS-$(CONFIG_ALAC_DECODER) += x86/alacdsp.o +X86ASM-OBJS-$(CONFIG_APNG_DECODER) += x86/pngdsp.o +X86ASM-OBJS-$(CONFIG_CAVS_DECODER) += x86/cavsidct.o +X86ASM-OBJS-$(CONFIG_DCA_DECODER) += x86/dcadsp.o x86/synth_filter.o +X86ASM-OBJS-$(CONFIG_DIRAC_DECODER) += x86/diracdsp.o \ + x86/dirac_dwt.o +X86ASM-OBJS-$(CONFIG_DNXHD_ENCODER) += x86/dnxhdenc.o +X86ASM-OBJS-$(CONFIG_EXR_DECODER) += x86/exrdsp.o +X86ASM-OBJS-$(CONFIG_FLAC_DECODER) += x86/flacdsp.o +ifdef CONFIG_GPL +X86ASM-OBJS-$(CONFIG_FLAC_ENCODER) += x86/flac_dsp_gpl.o +endif +X86ASM-OBJS-$(CONFIG_HEVC_DECODER) += x86/hevc_add_res.o \ + x86/hevc_deblock.o \ + x86/hevc_idct.o \ + x86/hevc_mc.o \ + x86/hevc_sao.o \ + x86/hevc_sao_10bit.o +X86ASM-OBJS-$(CONFIG_JPEG2000_DECODER) += x86/jpeg2000dsp.o +X86ASM-OBJS-$(CONFIG_LSCR_DECODER) += x86/pngdsp.o +X86ASM-OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp.o +X86ASM-OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct.o +X86ASM-OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp.o +X86ASM-OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp.o +X86ASM-OBJS-$(CONFIG_PRORES_LGPL_DECODER) += x86/proresdsp.o +X86ASM-OBJS-$(CONFIG_RV40_DECODER) += x86/rv40dsp.o +X86ASM-OBJS-$(CONFIG_SBC_ENCODER) += x86/sbcdsp.o +X86ASM-OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc.o +X86ASM-OBJS-$(CONFIG_TAK_DECODER) += x86/takdsp.o +X86ASM-OBJS-$(CONFIG_TRUEHD_DECODER) += x86/mlpdsp.o +X86ASM-OBJS-$(CONFIG_TTA_DECODER) += x86/ttadsp.o +X86ASM-OBJS-$(CONFIG_TTA_ENCODER) += x86/ttaencdsp.o +X86ASM-OBJS-$(CONFIG_UTVIDEO_DECODER) += x86/utvideodsp.o +X86ASM-OBJS-$(CONFIG_V210_ENCODER) += x86/v210enc.o +X86ASM-OBJS-$(CONFIG_V210_DECODER) += x86/v210.o +X86ASM-OBJS-$(CONFIG_VORBIS_DECODER) += x86/vorbisdsp.o +X86ASM-OBJS-$(CONFIG_VP3_DECODER) += x86/hpeldsp_vp3.o +X86ASM-OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp.o +X86ASM-OBJS-$(CONFIG_VP9_DECODER) += x86/vp9intrapred.o \ + x86/vp9intrapred_16bpp.o \ + x86/vp9itxfm.o \ + x86/vp9itxfm_16bpp.o \ + x86/vp9lpf.o \ + x86/vp9lpf_16bpp.o \ + x86/vp9mc.o \ + x86/vp9mc_16bpp.o +X86ASM-OBJS-$(CONFIG_WEBP_DECODER) += x86/vp8dsp.o diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacencdsp.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacencdsp.asm new file mode 100644 index 0000000000..97af571ec8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacencdsp.asm @@ -0,0 +1,86 @@ +;****************************************************************************** +;* SIMD optimized AAC encoder DSP functions +;* +;* Copyright (C) 2016 Rostislav Pehlivanov +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA + +float_abs_mask: times 4 dd 0x7fffffff + +SECTION .text + +;******************************************************************* +;void ff_abs_pow34(float *out, const float *in, const int size); +;******************************************************************* +INIT_XMM sse +cglobal abs_pow34, 3, 3, 3, out, in, size + mova m2, [float_abs_mask] + shl sizeq, 2 + add inq, sizeq + add outq, sizeq + neg sizeq +.loop: + andps m0, m2, [inq+sizeq] + sqrtps m1, m0 + mulps m0, m1 + sqrtps m0, m0 + mova [outq+sizeq], m0 + add sizeq, mmsize + jl .loop + RET + +;******************************************************************* +;void ff_aac_quantize_bands(int *out, const float *in, const float *scaled, +; int size, int is_signed, int maxval, const float Q34, +; const float rounding) +;******************************************************************* +INIT_XMM sse2 +cglobal aac_quantize_bands, 5, 5, 6, out, in, scaled, size, is_signed, maxval, Q34, rounding +%if UNIX64 == 0 + movss m0, Q34m + movss m1, roundingm + cvtsi2ss m3, dword maxvalm +%else + cvtsi2ss m3, maxvald +%endif + shufps m0, m0, 0 + shufps m1, m1, 0 + shufps m3, m3, 0 + shl is_signedd, 31 + movd m4, is_signedd + shufps m4, m4, 0 + shl sized, 2 + add inq, sizeq + add outq, sizeq + add scaledq, sizeq + neg sizeq +.loop: + mulps m2, m0, [scaledq+sizeq] + addps m2, m1 + minps m2, m3 + andps m5, m4, [inq+sizeq] + orps m2, m5 + cvttps2dq m2, m2 + mova [outq+sizeq], m2 + add sizeq, mmsize + jl .loop + RET diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacpsdsp.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacpsdsp.asm new file mode 100644 index 0000000000..4acd087c85 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/aacpsdsp.asm @@ -0,0 +1,487 @@ +;****************************************************************************** +;* SIMD optimized MPEG-4 Parametric Stereo decoding functions +;* +;* Copyright (C) 2015 James Almer +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA + +ps_p1m1p1m1: dd 0, 0x80000000, 0, 0x80000000 + +SECTION .text + +;************************************************************************* +;void ff_ps_add_squares_(float *dst, const float (*src)[2], int n); +;************************************************************************* +%macro PS_ADD_SQUARES 1 +cglobal ps_add_squares, 3, 3, %1, dst, src, n + shl nd, 3 + add srcq, nq + neg nq + +align 16 +.loop: + movaps m0, [srcq+nq] + movaps m1, [srcq+nq+mmsize] + mulps m0, m0 + mulps m1, m1 + HADDPS m0, m1, m2 + addps m0, [dstq] + movaps [dstq], m0 + add dstq, mmsize + add nq, mmsize*2 + jl .loop + REP_RET +%endmacro + +INIT_XMM sse +PS_ADD_SQUARES 2 +INIT_XMM sse3 +PS_ADD_SQUARES 3 + +;******************************************************************* +;void ff_ps_mul_pair_single_sse(float (*dst)[2], float (*src0)[2], +; float *src1, int n); +;******************************************************************* +INIT_XMM sse +cglobal ps_mul_pair_single, 4, 4, 4, dst, src1, src2, n + shl nd, 3 + add src1q, nq + add dstq, nq + neg nq + +align 16 +.loop: + movu m0, [src1q+nq] + movu m1, [src1q+nq+mmsize] + mova m2, [src2q] + mova m3, m2 + unpcklps m2, m2 + unpckhps m3, m3 + mulps m0, m2 + mulps m1, m3 + mova [dstq+nq], m0 + mova [dstq+nq+mmsize], m1 + add src2q, mmsize + add nq, mmsize*2 + jl .loop + REP_RET + +;*********************************************************************** +;void ff_ps_stereo_interpolate_sse3(float (*l)[2], float (*r)[2], +; float h[2][4], float h_step[2][4], +; int len); +;*********************************************************************** +INIT_XMM sse3 +cglobal ps_stereo_interpolate, 5, 5, 6, l, r, h, h_step, n + movaps m0, [hq] + movaps m1, [h_stepq] + unpcklps m4, m0, m0 + unpckhps m0, m0 + unpcklps m5, m1, m1 + unpckhps m1, m1 + shl nd, 3 + add lq, nq + add rq, nq + neg nq + +align 16 +.loop: + addps m4, m5 + addps m0, m1 + movddup m2, [lq+nq] + movddup m3, [rq+nq] + mulps m2, m4 + mulps m3, m0 + addps m2, m3 + movsd [lq+nq], m2 + movhps [rq+nq], m2 + add nq, 8 + jl .loop + REP_RET + +;*************************************************************************** +;void ps_stereo_interpolate_ipdopd_sse3(float (*l)[2], float (*r)[2], +; float h[2][4], float h_step[2][4], +; int len); +;*************************************************************************** +INIT_XMM sse3 +cglobal ps_stereo_interpolate_ipdopd, 5, 5, 10, l, r, h, h_step, n + movaps m0, [hq] + movaps m1, [hq+mmsize] +%if ARCH_X86_64 + movaps m8, [h_stepq] + movaps m9, [h_stepq+mmsize] + %define H_STEP0 m8 + %define H_STEP1 m9 +%else + %define H_STEP0 [h_stepq] + %define H_STEP1 [h_stepq+mmsize] +%endif + shl nd, 3 + add lq, nq + add rq, nq + neg nq + +align 16 +.loop: + addps m0, H_STEP0 + addps m1, H_STEP1 + movddup m2, [lq+nq] + movddup m3, [rq+nq] + shufps m4, m2, m2, q2301 + shufps m5, m3, m3, q2301 + unpcklps m6, m0, m0 + unpckhps m7, m0, m0 + mulps m2, m6 + mulps m3, m7 + unpcklps m6, m1, m1 + unpckhps m7, m1, m1 + mulps m4, m6 + mulps m5, m7 + addps m2, m3 + addsubps m2, m4 + addsubps m2, m5 + movsd [lq+nq], m2 + movhps [rq+nq], m2 + add nq, 8 + jl .loop + REP_RET + +;********************************************************** +;void ps_hybrid_analysis_ileave_sse(float out[2][38][64], +; float (*in)[32][2], +; int i, int len) +;********************************************************** +INIT_XMM sse +cglobal ps_hybrid_analysis_ileave, 3, 7, 5, out, in, i, len, in0, in1, tmp + movsxdifnidn iq, id + mov lend, 32 << 3 + lea inq, [inq+iq*4] + mov tmpd, id + shl tmpd, 8 + add outq, tmpq + mov tmpd, 64 + sub tmpd, id + mov id, tmpd + + test id, 1 + jne .loop4 + test id, 2 + jne .loop8 + +align 16 +.loop16: + mov in0q, inq + mov in1q, 38*64*4 + add in1q, in0q + mov tmpd, lend + +.inner_loop16: + movaps m0, [in0q] + movaps m1, [in1q] + movaps m2, [in0q+lenq] + movaps m3, [in1q+lenq] + TRANSPOSE4x4PS 0, 1, 2, 3, 4 + movaps [outq], m0 + movaps [outq+lenq], m1 + movaps [outq+lenq*2], m2 + movaps [outq+3*32*2*4], m3 + lea in0q, [in0q+lenq*2] + lea in1q, [in1q+lenq*2] + add outq, mmsize + sub tmpd, mmsize + jg .inner_loop16 + add inq, 16 + add outq, 3*32*2*4 + sub id, 4 + jg .loop16 + RET + +align 16 +.loop8: + mov in0q, inq + mov in1q, 38*64*4 + add in1q, in0q + mov tmpd, lend + +.inner_loop8: + movlps m0, [in0q] + movlps m1, [in1q] + movhps m0, [in0q+lenq] + movhps m1, [in1q+lenq] + SBUTTERFLYPS 0, 1, 2 + SBUTTERFLYPD 0, 1, 2 + movaps [outq], m0 + movaps [outq+lenq], m1 + lea in0q, [in0q+lenq*2] + lea in1q, [in1q+lenq*2] + add outq, mmsize + sub tmpd, mmsize + jg .inner_loop8 + add inq, 8 + add outq, lenq + sub id, 2 + jg .loop16 + RET + +align 16 +.loop4: + mov in0q, inq + mov in1q, 38*64*4 + add in1q, in0q + mov tmpd, lend + +.inner_loop4: + movss m0, [in0q] + movss m1, [in1q] + movss m2, [in0q+lenq] + movss m3, [in1q+lenq] + movlhps m0, m1 + movlhps m2, m3 + shufps m0, m2, q2020 + movaps [outq], m0 + lea in0q, [in0q+lenq*2] + lea in1q, [in1q+lenq*2] + add outq, mmsize + sub tmpd, mmsize + jg .inner_loop4 + add inq, 4 + sub id, 1 + test id, 2 + jne .loop8 + cmp id, 4 + jge .loop16 + RET + +;*********************************************************** +;void ps_hybrid_synthesis_deint_sse4(float out[2][38][64], +; float (*in)[32][2], +; int i, int len) +;*********************************************************** +%macro HYBRID_SYNTHESIS_DEINT 0 +cglobal ps_hybrid_synthesis_deint, 3, 7, 5, out, in, i, len, out0, out1, tmp +%if cpuflag(sse4) +%define MOVH movsd +%else +%define MOVH movlps +%endif + movsxdifnidn iq, id + mov lend, 32 << 3 + lea outq, [outq+iq*4] + mov tmpd, id + shl tmpd, 8 + add inq, tmpq + mov tmpd, 64 + sub tmpd, id + mov id, tmpd + + test id, 1 + jne .loop4 + test id, 2 + jne .loop8 + +align 16 +.loop16: + mov out0q, outq + mov out1q, 38*64*4 + add out1q, out0q + mov tmpd, lend + +.inner_loop16: + movaps m0, [inq] + movaps m1, [inq+lenq] + movaps m2, [inq+lenq*2] + movaps m3, [inq+3*32*2*4] + TRANSPOSE4x4PS 0, 1, 2, 3, 4 + movaps [out0q], m0 + movaps [out1q], m1 + movaps [out0q+lenq], m2 + movaps [out1q+lenq], m3 + lea out0q, [out0q+lenq*2] + lea out1q, [out1q+lenq*2] + add inq, mmsize + sub tmpd, mmsize + jg .inner_loop16 + add outq, 16 + add inq, 3*32*2*4 + sub id, 4 + jg .loop16 + RET + +align 16 +.loop8: + mov out0q, outq + mov out1q, 38*64*4 + add out1q, out0q + mov tmpd, lend + +.inner_loop8: + movaps m0, [inq] + movaps m1, [inq+lenq] + SBUTTERFLYPS 0, 1, 2 + SBUTTERFLYPD 0, 1, 2 + MOVH [out0q], m0 + MOVH [out1q], m1 + movhps [out0q+lenq], m0 + movhps [out1q+lenq], m1 + lea out0q, [out0q+lenq*2] + lea out1q, [out1q+lenq*2] + add inq, mmsize + sub tmpd, mmsize + jg .inner_loop8 + add outq, 8 + add inq, lenq + sub id, 2 + jg .loop16 + RET + +align 16 +.loop4: + mov out0q, outq + mov out1q, 38*64*4 + add out1q, out0q + mov tmpd, lend + +.inner_loop4: + movaps m0, [inq] + movss [out0q], m0 +%if cpuflag(sse4) + extractps [out1q], m0, 1 + extractps [out0q+lenq], m0, 2 + extractps [out1q+lenq], m0, 3 +%else + movhlps m1, m0 + movss [out0q+lenq], m1 + shufps m0, m0, 0xb1 + movss [out1q], m0 + movhlps m1, m0 + movss [out1q+lenq], m1 +%endif + lea out0q, [out0q+lenq*2] + lea out1q, [out1q+lenq*2] + add inq, mmsize + sub tmpd, mmsize + jg .inner_loop4 + add outq, 4 + sub id, 1 + test id, 2 + jne .loop8 + cmp id, 4 + jge .loop16 + RET +%endmacro + +INIT_XMM sse +HYBRID_SYNTHESIS_DEINT +INIT_XMM sse4 +HYBRID_SYNTHESIS_DEINT + +;******************************************************************* +;void ff_ps_hybrid_analysis_(float (*out)[2], float (*in)[2], +; const float (*filter)[8][2], +; ptrdiff_t stride, int n); +;******************************************************************* +%macro PS_HYBRID_ANALYSIS_LOOP 3 + movu %1, [inq+mmsize*%3] + movu m1, [inq+mmsize*(5-%3)+8] +%if cpuflag(sse3) + pshufd %2, %1, q2301 + pshufd m4, m1, q0123 + pshufd m1, m1, q1032 + pshufd m2, [filterq+nq+mmsize*%3], q2301 + addsubps %2, m4 + addsubps %1, m1 +%else + mova m2, [filterq+nq+mmsize*%3] + mova %2, %1 + mova m4, m1 + shufps %2, %2, q2301 + shufps m4, m4, q0123 + shufps m1, m1, q1032 + shufps m2, m2, q2301 + xorps m4, m7 + xorps m1, m7 + subps %2, m4 + subps %1, m1 +%endif + mulps %2, m2 + mulps %1, m2 +%if %3 + addps m3, %2 + addps m0, %1 +%endif +%endmacro + +%macro PS_HYBRID_ANALYSIS 0 +cglobal ps_hybrid_analysis, 5, 5, 8, out, in, filter, stride, n +%if cpuflag(sse3) +%define MOVH movsd +%else +%define MOVH movlps +%endif + shl strideq, 3 + shl nd, 6 + add filterq, nq + neg nq + mova m7, [ps_p1m1p1m1] + +align 16 +.loop: + PS_HYBRID_ANALYSIS_LOOP m0, m3, 0 + PS_HYBRID_ANALYSIS_LOOP m5, m6, 1 + PS_HYBRID_ANALYSIS_LOOP m5, m6, 2 + +%if cpuflag(sse3) + pshufd m3, m3, q2301 + xorps m0, m7 + hsubps m3, m0 + pshufd m1, m3, q0020 + pshufd m3, m3, q0031 + addps m1, m3 + movsd m2, [inq+6*8] +%else + mova m1, m3 + mova m2, m0 + shufps m1, m1, q2301 + shufps m2, m2, q2301 + subps m1, m3 + addps m2, m0 + unpcklps m3, m1, m2 + unpckhps m1, m2 + addps m1, m3 + movu m2, [inq+6*8] ; faster than movlps and no risk of overread +%endif + movss m3, [filterq+nq+8*6] + SPLATD m3 + mulps m2, m3 + addps m1, m2 + MOVH [outq], m1 + add outq, strideq + add nq, 64 + jl .loop + REP_RET +%endmacro + +INIT_XMM sse +PS_HYBRID_ANALYSIS +INIT_XMM sse3 +PS_HYBRID_ANALYSIS diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/celt_pvq_search.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/celt_pvq_search.asm new file mode 100644 index 0000000000..5c1e6d6174 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/celt_pvq_search.asm @@ -0,0 +1,385 @@ +;****************************************************************************** +;* SIMD optimized Opus encoder DSP function +;* +;* Copyright (C) 2017 Ivan Kalvachev +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "config.asm" +%include "libavutil/x86/x86util.asm" + +%ifdef __NASM_VER__ +%use "smartalign" +ALIGNMODE p6 +%endif + +SECTION_RODATA 64 + +const_float_abs_mask: times 8 dd 0x7fffffff +const_align_abs_edge: times 8 dd 0 + +const_float_0_5: times 8 dd 0.5 +const_float_1: times 8 dd 1.0 +const_float_sign_mask: times 8 dd 0x80000000 + +const_int32_offsets: + %rep 8 + dd $-const_int32_offsets + %endrep +SECTION .text + +; +; Setup High Register to be used +; for holding memory constants +; +; %1 - the register to be used, assmues it is >= mm8 +; %2 - name of the constant. +; +; Subsequent opcodes are going to use the constant in the form +; "addps m0, mm_const_name" and it would be turned into: +; "addps m0, [const_name]" on 32 bit arch or +; "addps m0, m8" on 64 bit arch +%macro SET_HI_REG_MM_CONSTANT 3 ; movop, reg, const_name +%if num_mmregs > 8 + %define mm_%3 %2 + %{1} %2, [%3] ; movaps m8, [const_name] +%else + %define mm_%3 [%3] +%endif +%endmacro + +; +; Set Position Independent Code +; Base address of a constant +; %1 - the register to be used, if PIC is set +; %2 - name of the constant. +; +; Subsequent opcode are going to use the base address in the form +; "movaps m0, [pic_base_constant_name+r4]" and it would be turned into +; "movaps m0, [r5 + r4]" if PIC is enabled +; "movaps m0, [constant_name + r4]" if texrel are used +%macro SET_PIC_BASE 3; reg, const_label +%ifdef PIC + %{1} %2, [%3] ; lea r5, [rip+const] + %define pic_base_%3 %2 +%else + %define pic_base_%3 %3 +%endif +%endmacro + +%macro PULSES_SEARCH 1 +; m6 Syy_norm +; m7 Sxy_norm + addps m6, mm_const_float_0_5 ; Syy_norm += 1.0/2 + pxor m1, m1 ; max_idx + xorps m3, m3 ; p_max + xor r4d, r4d +align 16 +%%distortion_search: + movd xm2, dword r4d ; movd zero extends +%ifidn %1,add + movaps m4, [tmpY + r4] ; y[i] + movaps m5, [tmpX + r4] ; X[i] + + %if USE_APPROXIMATION == 1 + xorps m0, m0 + cmpps m0, m0, m5, 4 ; m0 = (X[i] != 0.0) + %endif + + addps m4, m6 ; m4 = Syy_new = y[i] + Syy_norm + addps m5, m7 ; m5 = Sxy_new = X[i] + Sxy_norm + + %if USE_APPROXIMATION == 1 + andps m5, m0 ; if(X[i] == 0) Sxy_new = 0; Prevent aproximation error from setting pulses in array padding. + %endif + +%else + movaps m5, [tmpY + r4] ; m5 = y[i] + + xorps m0, m0 ; m0 = 0; + cmpps m0, m0, m5, 1 ; m0 = (0 p_max) + maxps m3, m5 ; m3=max(p_max,p) + ; maxps here is faster than blendvps, despite blend having lower latency. + + pand m2, m0 ; This version seems faster than sse41 pblendvb + pmaxsw m1, m2 ; SSE2 signed word, so it would work for N < 32768/4 + + add r4d, mmsize + cmp r4d, Nd + jb %%distortion_search + + por m1, mm_const_int32_offsets ; max_idx offsets per individual lane (skipped in the inner loop) + movdqa m4, m1 ; needed for the aligned y[max_idx]+=1; processing + +%if mmsize >= 32 +; Merge parallel maximums round 8 (4 vs 4) + + vextractf128 xm5, ym3, 1 ; xmm5 = ymm3[1x128] = ymm3[255..128b] + cmpps xm0, xm3, xm5, 1 ; m0 = (m3 < m5) = ( p[0x128] < p[1x128] ) + + vextracti128 xm2, ym1, 1 ; xmm2 = ymm1[1x128] = ymm1[255..128b] + BLENDVPS xm3, xm5, xm0 ; max_idx = m0 ? max_idx[1x128] : max_idx[0x128] + PBLENDVB xm1, xm2, xm0 ; p = m0 ? p[1x128] : p[0x128] +%endif + +; Merge parallel maximums round 4 (2 vs 2) + ; m3=p[3210] + movhlps xm5, xm3 ; m5=p[xx32] + cmpps xm0, xm3, xm5, 1 ; m0 = (m3 < m5) = ( p[1,0] < p[3,2] ) + + pshufd xm2, xm1, q3232 + BLENDVPS xm3, xm5, xm0 ; max_idx = m0 ? max_idx[3,2] : max_idx[1,0] + PBLENDVB xm1, xm2, xm0 ; p = m0 ? p[3,2] : p[1,0] + +; Merge parallel maximums final round (1 vs 1) + shufps xm0, xm3, xm3, q1111 ; m0 = m3[1] = p[1] + cmpss xm0, xm3, 5 ; m0 = !(m0 >= m3) = !( p[1] >= p[0] ) + + pshufd xm2, xm1, q1111 + PBLENDVB xm1, xm2, xm0 + + movd dword r4d, xm1 ; zero extends to the rest of r4q + + VBROADCASTSS m3, [tmpX + r4] + %{1}ps m7, m3 ; Sxy += X[max_idx] + + VBROADCASTSS m5, [tmpY + r4] + %{1}ps m6, m5 ; Syy += Y[max_idx] + + ; We have to update a single element in Y[i] + ; However writing 4 bytes and then doing 16 byte load in the inner loop + ; could cause a stall due to breaking write forwarding. + VPBROADCASTD m1, xm1 + pcmpeqd m1, m1, m4 ; exactly 1 element matches max_idx and this finds it + + and r4d, ~(mmsize-1) ; align address down, so the value pointed by max_idx is inside a mmsize load + movaps m5, [tmpY + r4] ; m5 = Y[y3...ym...y0] + andps m1, mm_const_float_1 ; m1 = [ 0...1.0...0] + %{1}ps m5, m1 ; m5 = Y[y3...ym...y0] +/- [0...1.0...0] + movaps [tmpY + r4], m5 ; Y[max_idx] +-= 1.0; +%endmacro + +; +; We need one more register for +; PIC relative addressing. Use this +; to count it in cglobal +; +%ifdef PIC + %define num_pic_regs 1 +%else + %define num_pic_regs 0 +%endif + +; +; Pyramid Vector Quantization Search implementation +; +; float * inX - Unaligned (SIMD) access, it will be overread, +; but extra data is masked away. +; int32 * outY - Should be aligned and padded buffer. +; It is used as temp buffer. +; uint32 K - Number of pulses to have after quantizations. +; uint32 N - Number of vector elements. Must be 0 < N < 256 +; +%macro PVQ_FAST_SEARCH 1 +cglobal pvq_search%1, 4, 5+num_pic_regs, 11, 256*4, inX, outY, K, N +%define tmpX rsp +%define tmpY outYq + + movaps m0, [const_float_abs_mask] + shl Nd, 2 ; N *= sizeof(float); also 32 bit operation zeroes the high 32 bits in 64 bit mode. + mov r4d, Nd + + neg r4d + and r4d, mmsize-1 + + SET_PIC_BASE lea, r5, const_align_abs_edge ; rip+const + movups m2, [pic_base_const_align_abs_edge + r4 - mmsize] + + add Nd, r4d ; N = align(N, mmsize) + + lea r4d, [Nd - mmsize] ; N is rounded up (aligned up) to mmsize, so r4 can't become negative here, unless N=0. + movups m1, [inXq + r4] + andps m1, m2 + movaps [tmpX + r4], m1 ; Sx = abs( X[N-1] ) + +align 16 +%%loop_abs_sum: + sub r4d, mmsize + jc %%end_loop_abs_sum + + movups m2, [inXq + r4] + andps m2, m0 + + movaps [tmpX + r4], m2 ; tmpX[i]=abs(X[i]) + addps m1, m2 ; Sx += abs(X[i]) + jmp %%loop_abs_sum + +align 16 +%%end_loop_abs_sum: + + HSUMPS m1, m2 ; m1 = Sx + + xorps m0, m0 + comiss xm0, xm1 ; + jz %%zero_input ; if (Sx==0) goto zero_input + + cvtsi2ss xm0, dword Kd ; m0 = K +%if USE_APPROXIMATION == 1 + rcpss xm1, xm1 ; m1 = approx(1/Sx) + mulss xm0, xm1 ; m0 = K*(1/Sx) +%else + divss xm0, xm1 ; b = K/Sx + ; b = K/max_x +%endif + + VBROADCASTSS m0, xm0 + + lea r4d, [Nd - mmsize] + pxor m5, m5 ; Sy ( Sum of abs( y[i]) ) + xorps m6, m6 ; Syy ( Sum of y[i]*y[i] ) + xorps m7, m7 ; Sxy ( Sum of X[i]*y[i] ) +align 16 +%%loop_guess: + movaps m1, [tmpX + r4] ; m1 = X[i] + mulps m2, m0, m1 ; m2 = res*X[i] + cvtps2dq m2, m2 ; yt = (int)lrintf( res*X[i] ) + paddd m5, m2 ; Sy += yt + cvtdq2ps m2, m2 ; yt = (float)yt + mulps m1, m2 ; m1 = X[i]*yt + movaps [tmpY + r4], m2 ; y[i] = m2 + addps m7, m1 ; Sxy += m1; + mulps m2, m2 ; m2 = yt*yt + addps m6, m2 ; Syy += m2 + + sub r4d, mmsize + jnc %%loop_guess + + HSUMPS m6, m1 ; Syy_norm + HADDD m5, m4 ; pulses + + movd dword r4d, xm5 ; zero extends to the rest of r4q + + sub Kd, r4d ; K -= pulses , also 32 bit operation zeroes high 32 bit in 64 bit mode. + jz %%finish ; K - pulses == 0 + + SET_HI_REG_MM_CONSTANT movaps, m8, const_float_0_5 + SET_HI_REG_MM_CONSTANT movaps, m9, const_float_1 + SET_HI_REG_MM_CONSTANT movdqa, m10, const_int32_offsets + ; Use Syy/2 in distortion parameter calculations. + ; Saves pre and post-caclulation to correct Y[] values. + ; Same precision, since float mantisa is normalized. + ; The SQRT approximation does differ. + HSUMPS m7, m0 ; Sxy_norm + mulps m6, mm_const_float_0_5 + + jc %%remove_pulses_loop ; K - pulses < 0 + +align 16 ; K - pulses > 0 +%%add_pulses_loop: + + PULSES_SEARCH add ; m6 Syy_norm ; m7 Sxy_norm + + sub Kd, 1 + jnz %%add_pulses_loop + + addps m6, m6 ; Syy*=2 + + jmp %%finish + +align 16 +%%remove_pulses_loop: + + PULSES_SEARCH sub ; m6 Syy_norm ; m7 Sxy_norm + + add Kd, 1 + jnz %%remove_pulses_loop + + addps m6, m6 ; Syy*=2 + +align 16 +%%finish: + lea r4d, [Nd - mmsize] + movaps m2, [const_float_sign_mask] + +align 16 +%%restore_sign_loop: + movaps m0, [tmpY + r4] ; m0 = Y[i] + movups m1, [inXq + r4] ; m1 = X[i] + andps m1, m2 ; m1 = sign(X[i]) + orps m0, m1 ; m0 = Y[i]*sign + cvtps2dq m3, m0 ; m3 = (int)m0 + movaps [outYq + r4], m3 + + sub r4d, mmsize + jnc %%restore_sign_loop +%%return: + +%if ARCH_X86_64 == 0 ; sbrdsp + movss r0m, xm6 ; return (float)Syy_norm + fld dword r0m +%else + movaps m0, m6 ; return (float)Syy_norm +%endif + + RET + +align 16 +%%zero_input: + lea r4d, [Nd - mmsize] + xorps m0, m0 +%%zero_loop: + movaps [outYq + r4], m0 + sub r4d, mmsize + jnc %%zero_loop + + movaps m6, [const_float_1] + jmp %%return +%endmacro + +; if 1, use a float op that give half precision but execute for around 3 cycles. +; On Skylake & Ryzen the division is much faster (around 11c/3), +; that makes the full precision code about 2% slower. +; Opus also does use rsqrt approximation in their intrinsics code. +%define USE_APPROXIMATION 1 + +INIT_XMM sse2 +PVQ_FAST_SEARCH _approx + +INIT_XMM sse4 +PVQ_FAST_SEARCH _approx + +%define USE_APPROXIMATION 0 + +INIT_XMM avx +PVQ_FAST_SEARCH _exact diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft.asm new file mode 100644 index 0000000000..a671e8f48e --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/fft.asm @@ -0,0 +1,1085 @@ +;****************************************************************************** +;* FFT transform with SSE/3DNow optimizations +;* Copyright (c) 2008 Loren Merritt +;* Copyright (c) 2011 Vitor Sessak +;* +;* This algorithm (though not any of the implementation details) is +;* based on libdjbfft by D. J. Bernstein. +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +; These functions are not individually interchangeable with the C versions. +; While C takes arrays of FFTComplex, SSE/3DNow leave intermediate results +; in blocks as conventient to the vector size. +; i.e. {4x real, 4x imaginary, 4x real, ...} (or 2x respectively) + +%include "libavutil/x86/x86util.asm" + +%if ARCH_X86_64 +%define pointer resq +%else +%define pointer resd +%endif + +struc FFTContext + .nbits: resd 1 + .reverse: resd 1 + .revtab: pointer 1 + .tmpbuf: pointer 1 + .mdctsize: resd 1 + .mdctbits: resd 1 + .tcos: pointer 1 + .tsin: pointer 1 + .fftperm: pointer 1 + .fftcalc: pointer 1 + .imdctcalc:pointer 1 + .imdcthalf:pointer 1 +endstruc + +SECTION_RODATA 32 + +%define M_SQRT1_2 0.70710678118654752440 +%define M_COS_PI_1_8 0.923879532511287 +%define M_COS_PI_3_8 0.38268343236509 + +ps_cos16_1: dd 1.0, M_COS_PI_1_8, M_SQRT1_2, M_COS_PI_3_8, 1.0, M_COS_PI_1_8, M_SQRT1_2, M_COS_PI_3_8 +ps_cos16_2: dd 0, M_COS_PI_3_8, M_SQRT1_2, M_COS_PI_1_8, 0, -M_COS_PI_3_8, -M_SQRT1_2, -M_COS_PI_1_8 + +ps_root2: times 8 dd M_SQRT1_2 +ps_root2mppm: dd -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2 +ps_p1p1m1p1: dd 0, 0, 1<<31, 0, 0, 0, 1<<31, 0 + +perm1: dd 0x00, 0x02, 0x03, 0x01, 0x03, 0x00, 0x02, 0x01 +perm2: dd 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x02, 0x03 +ps_p1p1m1p1root2: dd 1.0, 1.0, -1.0, 1.0, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2, M_SQRT1_2 +ps_m1m1p1m1p1m1m1m1: dd 1<<31, 1<<31, 0, 1<<31, 0, 1<<31, 1<<31, 1<<31 +ps_m1p1: dd 1<<31, 0 + +cextern ps_neg + +%assign i 16 +%rep 14 +cextern cos_ %+ i +%assign i i<<1 +%endrep + +%if ARCH_X86_64 + %define pointer dq +%else + %define pointer dd +%endif + +%macro IF0 1+ +%endmacro +%macro IF1 1+ + %1 +%endmacro + +SECTION .text + +%macro T2_3DNOW 4 ; z0, z1, mem0, mem1 + mova %1, %3 + mova %2, %1 + pfadd %1, %4 + pfsub %2, %4 +%endmacro + +%macro T4_3DNOW 6 ; z0, z1, z2, z3, tmp0, tmp1 + mova %5, %3 + pfsub %3, %4 + pfadd %5, %4 ; {t6,t5} + pxor %3, [ps_m1p1] ; {t8,t7} + mova %6, %1 + movd [r0+12], %3 + punpckhdq %3, [r0+8] + pfadd %1, %5 ; {r0,i0} + pfsub %6, %5 ; {r2,i2} + mova %4, %2 + pfadd %2, %3 ; {r1,i1} + pfsub %4, %3 ; {r3,i3} + SWAP %3, %6 +%endmacro + +; in: %1 = {r0,i0,r2,i2,r4,i4,r6,i6} +; %2 = {r1,i1,r3,i3,r5,i5,r7,i7} +; %3, %4, %5 tmp +; out: %1 = {r0,r1,r2,r3,i0,i1,i2,i3} +; %2 = {r4,r5,r6,r7,i4,i5,i6,i7} +%macro T8_AVX 5 + vsubps %5, %1, %2 ; v = %1 - %2 + vaddps %3, %1, %2 ; w = %1 + %2 + vmulps %2, %5, [ps_p1p1m1p1root2] ; v *= vals1 + vpermilps %2, %2, [perm1] + vblendps %1, %2, %3, 0x33 ; q = {w1,w2,v4,v2,w5,w6,v7,v6} + vshufps %5, %3, %2, 0x4e ; r = {w3,w4,v1,v3,w7,w8,v8,v5} + vsubps %4, %5, %1 ; s = r - q + vaddps %1, %5, %1 ; u = r + q + vpermilps %1, %1, [perm2] ; k = {u1,u2,u3,u4,u6,u5,u7,u8} + vshufps %5, %4, %1, 0xbb + vshufps %3, %4, %1, 0xee + vperm2f128 %3, %3, %5, 0x13 + vxorps %4, %4, [ps_m1m1p1m1p1m1m1m1] ; s *= {1,1,-1,-1,1,-1,-1,-1} + vshufps %2, %1, %4, 0xdd + vshufps %1, %1, %4, 0x88 + vperm2f128 %4, %2, %1, 0x02 ; v = {k1,k3,s1,s3,k2,k4,s2,s4} + vperm2f128 %1, %1, %2, 0x13 ; w = {k6,k8,s6,s8,k5,k7,s5,s7} + vsubps %5, %1, %3 + vblendps %1, %5, %1, 0x55 ; w -= {0,s7,0,k7,0,s8,0,k8} + vsubps %2, %4, %1 ; %2 = v - w + vaddps %1, %4, %1 ; %1 = v + w +%endmacro + +; In SSE mode do one fft4 transforms +; in: %1={r0,i0,r2,i2} %2={r1,i1,r3,i3} +; out: %1={r0,r1,r2,r3} %2={i0,i1,i2,i3} +; +; In AVX mode do two fft4 transforms +; in: %1={r0,i0,r2,i2,r4,i4,r6,i6} %2={r1,i1,r3,i3,r5,i5,r7,i7} +; out: %1={r0,r1,r2,r3,r4,r5,r6,r7} %2={i0,i1,i2,i3,i4,i5,i6,i7} +%macro T4_SSE 3 + subps %3, %1, %2 ; {t3,t4,-t8,t7} + addps %1, %1, %2 ; {t1,t2,t6,t5} + xorps %3, %3, [ps_p1p1m1p1] + shufps %2, %1, %3, 0xbe ; {t6,t5,t7,t8} + shufps %1, %1, %3, 0x44 ; {t1,t2,t3,t4} + subps %3, %1, %2 ; {r2,i2,r3,i3} + addps %1, %1, %2 ; {r0,i0,r1,i1} + shufps %2, %1, %3, 0xdd ; {i0,i1,i2,i3} + shufps %1, %1, %3, 0x88 ; {r0,r1,r2,r3} +%endmacro + +; In SSE mode do one FFT8 +; in: %1={r0,r1,r2,r3} %2={i0,i1,i2,i3} %3={r4,i4,r6,i6} %4={r5,i5,r7,i7} +; out: %1={r0,r1,r2,r3} %2={i0,i1,i2,i3} %1={r4,r5,r6,r7} %2={i4,i5,i6,i7} +; +; In AVX mode do two FFT8 +; in: %1={r0,i0,r2,i2,r8, i8, r10,i10} %2={r1,i1,r3,i3,r9, i9, r11,i11} +; %3={r4,i4,r6,i6,r12,i12,r14,i14} %4={r5,i5,r7,i7,r13,i13,r15,i15} +; out: %1={r0,r1,r2,r3,r8, r9, r10,r11} %2={i0,i1,i2,i3,i8, i9, i10,i11} +; %3={r4,r5,r6,r7,r12,r13,r14,r15} %4={i4,i5,i6,i7,i12,i13,i14,i15} +%macro T8_SSE 6 + addps %6, %3, %4 ; {t1,t2,t3,t4} + subps %3, %3, %4 ; {r5,i5,r7,i7} + shufps %4, %3, %3, 0xb1 ; {i5,r5,i7,r7} + mulps %3, %3, [ps_root2mppm] ; {-r5,i5,r7,-i7} + mulps %4, %4, [ps_root2] + addps %3, %3, %4 ; {t8,t7,ta,t9} + shufps %4, %6, %3, 0x9c ; {t1,t4,t7,ta} + shufps %6, %6, %3, 0x36 ; {t3,t2,t9,t8} + subps %3, %6, %4 ; {t6,t5,tc,tb} + addps %6, %6, %4 ; {t1,t2,t9,ta} + shufps %5, %6, %3, 0x8d ; {t2,ta,t6,tc} + shufps %6, %6, %3, 0xd8 ; {t1,t9,t5,tb} + subps %3, %1, %6 ; {r4,r5,r6,r7} + addps %1, %1, %6 ; {r0,r1,r2,r3} + subps %4, %2, %5 ; {i4,i5,i6,i7} + addps %2, %2, %5 ; {i0,i1,i2,i3} +%endmacro + +%macro INTERL 5 +%if cpuflag(avx) + vunpckhps %3, %2, %1 + vunpcklps %2, %2, %1 + vextractf128 %4(%5), %2, 0 + vextractf128 %4 %+ H(%5), %3, 0 + vextractf128 %4(%5 + 1), %2, 1 + vextractf128 %4 %+ H(%5 + 1), %3, 1 +%elif cpuflag(sse) || cpuflag(3dnow) + mova %3, %2 + unpcklps %2, %1 + unpckhps %3, %1 + mova %4(%5), %2 + mova %4(%5+1), %3 +%endif +%endmacro + +; scheduled for cpu-bound sizes +%macro PASS_SMALL 3 ; (to load m4-m7), wre, wim +IF%1 mova m4, Z(4) +IF%1 mova m5, Z(5) + mova m0, %2 ; wre + mova m1, %3 ; wim + mulps m2, m4, m0 ; r2*wre +IF%1 mova m6, Z2(6) + mulps m3, m5, m1 ; i2*wim +IF%1 mova m7, Z2(7) + mulps m4, m4, m1 ; r2*wim + mulps m5, m5, m0 ; i2*wre + addps m2, m2, m3 ; r2*wre + i2*wim + mulps m3, m1, m7 ; i3*wim + subps m5, m5, m4 ; i2*wre - r2*wim + mulps m1, m1, m6 ; r3*wim + mulps m4, m0, m6 ; r3*wre + mulps m0, m0, m7 ; i3*wre + subps m4, m4, m3 ; r3*wre - i3*wim + mova m3, Z(0) + addps m0, m0, m1 ; i3*wre + r3*wim + subps m1, m4, m2 ; t3 + addps m4, m4, m2 ; t5 + subps m3, m3, m4 ; r2 + addps m4, m4, Z(0) ; r0 + mova m6, Z(2) + mova Z(4), m3 + mova Z(0), m4 + subps m3, m5, m0 ; t4 + subps m4, m6, m3 ; r3 + addps m3, m3, m6 ; r1 + mova Z2(6), m4 + mova Z(2), m3 + mova m2, Z(3) + addps m3, m5, m0 ; t6 + subps m2, m2, m1 ; i3 + mova m7, Z(1) + addps m1, m1, Z(3) ; i1 + mova Z2(7), m2 + mova Z(3), m1 + subps m4, m7, m3 ; i2 + addps m3, m3, m7 ; i0 + mova Z(5), m4 + mova Z(1), m3 +%endmacro + +; scheduled to avoid store->load aliasing +%macro PASS_BIG 1 ; (!interleave) + mova m4, Z(4) ; r2 + mova m5, Z(5) ; i2 + mova m0, [wq] ; wre + mova m1, [wq+o1q] ; wim + mulps m2, m4, m0 ; r2*wre + mova m6, Z2(6) ; r3 + mulps m3, m5, m1 ; i2*wim + mova m7, Z2(7) ; i3 + mulps m4, m4, m1 ; r2*wim + mulps m5, m5, m0 ; i2*wre + addps m2, m2, m3 ; r2*wre + i2*wim + mulps m3, m1, m7 ; i3*wim + mulps m1, m1, m6 ; r3*wim + subps m5, m5, m4 ; i2*wre - r2*wim + mulps m4, m0, m6 ; r3*wre + mulps m0, m0, m7 ; i3*wre + subps m4, m4, m3 ; r3*wre - i3*wim + mova m3, Z(0) + addps m0, m0, m1 ; i3*wre + r3*wim + subps m1, m4, m2 ; t3 + addps m4, m4, m2 ; t5 + subps m3, m3, m4 ; r2 + addps m4, m4, Z(0) ; r0 + mova m6, Z(2) + mova Z(4), m3 + mova Z(0), m4 + subps m3, m5, m0 ; t4 + subps m4, m6, m3 ; r3 + addps m3, m3, m6 ; r1 +IF%1 mova Z2(6), m4 +IF%1 mova Z(2), m3 + mova m2, Z(3) + addps m5, m5, m0 ; t6 + subps m2, m2, m1 ; i3 + mova m7, Z(1) + addps m1, m1, Z(3) ; i1 +IF%1 mova Z2(7), m2 +IF%1 mova Z(3), m1 + subps m6, m7, m5 ; i2 + addps m5, m5, m7 ; i0 +IF%1 mova Z(5), m6 +IF%1 mova Z(1), m5 +%if %1==0 + INTERL m1, m3, m7, Z, 2 + INTERL m2, m4, m0, Z2, 6 + + mova m1, Z(0) + mova m2, Z(4) + + INTERL m5, m1, m3, Z, 0 + INTERL m6, m2, m7, Z, 4 +%endif +%endmacro + +%macro PUNPCK 3 + mova %3, %1 + punpckldq %1, %2 + punpckhdq %3, %2 +%endmacro + +%define Z(x) [r0+mmsize*x] +%define Z2(x) [r0+mmsize*x] +%define ZH(x) [r0+mmsize*x+mmsize/2] + +INIT_YMM avx + +%if HAVE_AVX_EXTERNAL +align 16 +fft8_avx: + mova m0, Z(0) + mova m1, Z(1) + T8_AVX m0, m1, m2, m3, m4 + mova Z(0), m0 + mova Z(1), m1 + ret + + +align 16 +fft16_avx: + mova m2, Z(2) + mova m3, Z(3) + T4_SSE m2, m3, m7 + + mova m0, Z(0) + mova m1, Z(1) + T8_AVX m0, m1, m4, m5, m7 + + mova m4, [ps_cos16_1] + mova m5, [ps_cos16_2] + vmulps m6, m2, m4 + vmulps m7, m3, m5 + vaddps m7, m7, m6 + vmulps m2, m2, m5 + vmulps m3, m3, m4 + vsubps m3, m3, m2 + vblendps m2, m7, m3, 0xf0 + vperm2f128 m3, m7, m3, 0x21 + vaddps m4, m2, m3 + vsubps m2, m3, m2 + vperm2f128 m2, m2, m2, 0x01 + vsubps m3, m1, m2 + vaddps m1, m1, m2 + vsubps m5, m0, m4 + vaddps m0, m0, m4 + vextractf128 Z(0), m0, 0 + vextractf128 ZH(0), m1, 0 + vextractf128 Z(1), m0, 1 + vextractf128 ZH(1), m1, 1 + vextractf128 Z(2), m5, 0 + vextractf128 ZH(2), m3, 0 + vextractf128 Z(3), m5, 1 + vextractf128 ZH(3), m3, 1 + ret + +align 16 +fft32_avx: + call fft16_avx + + mova m0, Z(4) + mova m1, Z(5) + + T4_SSE m0, m1, m4 + + mova m2, Z(6) + mova m3, Z(7) + + T8_SSE m0, m1, m2, m3, m4, m6 + ; m0={r0,r1,r2,r3,r8, r9, r10,r11} m1={i0,i1,i2,i3,i8, i9, i10,i11} + ; m2={r4,r5,r6,r7,r12,r13,r14,r15} m3={i4,i5,i6,i7,i12,i13,i14,i15} + + vperm2f128 m4, m0, m2, 0x20 + vperm2f128 m5, m1, m3, 0x20 + vperm2f128 m6, m0, m2, 0x31 + vperm2f128 m7, m1, m3, 0x31 + + PASS_SMALL 0, [cos_32], [cos_32+32] + + ret + +fft32_interleave_avx: + call fft32_avx + mov r2d, 32 +.deint_loop: + mova m2, Z(0) + mova m3, Z(1) + vunpcklps m0, m2, m3 + vunpckhps m1, m2, m3 + vextractf128 Z(0), m0, 0 + vextractf128 ZH(0), m1, 0 + vextractf128 Z(1), m0, 1 + vextractf128 ZH(1), m1, 1 + add r0, mmsize*2 + sub r2d, mmsize/4 + jg .deint_loop + ret + +%endif + +INIT_XMM sse + +align 16 +fft4_avx: +fft4_sse: + mova m0, Z(0) + mova m1, Z(1) + T4_SSE m0, m1, m2 + mova Z(0), m0 + mova Z(1), m1 + ret + +align 16 +fft8_sse: + mova m0, Z(0) + mova m1, Z(1) + T4_SSE m0, m1, m2 + mova m2, Z(2) + mova m3, Z(3) + T8_SSE m0, m1, m2, m3, m4, m5 + mova Z(0), m0 + mova Z(1), m1 + mova Z(2), m2 + mova Z(3), m3 + ret + +align 16 +fft16_sse: + mova m0, Z(0) + mova m1, Z(1) + T4_SSE m0, m1, m2 + mova m2, Z(2) + mova m3, Z(3) + T8_SSE m0, m1, m2, m3, m4, m5 + mova m4, Z(4) + mova m5, Z(5) + mova Z(0), m0 + mova Z(1), m1 + mova Z(2), m2 + mova Z(3), m3 + T4_SSE m4, m5, m6 + mova m6, Z2(6) + mova m7, Z2(7) + T4_SSE m6, m7, m0 + PASS_SMALL 0, [cos_16], [cos_16+16] + ret + + +%macro FFT48_3DNOW 0 +align 16 +fft4 %+ SUFFIX: + T2_3DNOW m0, m1, Z(0), Z(1) + mova m2, Z(2) + mova m3, Z(3) + T4_3DNOW m0, m1, m2, m3, m4, m5 + PUNPCK m0, m1, m4 + PUNPCK m2, m3, m5 + mova Z(0), m0 + mova Z(1), m4 + mova Z(2), m2 + mova Z(3), m5 + ret + +align 16 +fft8 %+ SUFFIX: + T2_3DNOW m0, m1, Z(0), Z(1) + mova m2, Z(2) + mova m3, Z(3) + T4_3DNOW m0, m1, m2, m3, m4, m5 + mova Z(0), m0 + mova Z(2), m2 + T2_3DNOW m4, m5, Z(4), Z(5) + T2_3DNOW m6, m7, Z2(6), Z2(7) + PSWAPD m0, m5 + PSWAPD m2, m7 + pxor m0, [ps_m1p1] + pxor m2, [ps_m1p1] + pfsub m5, m0 + pfadd m7, m2 + pfmul m5, [ps_root2] + pfmul m7, [ps_root2] + T4_3DNOW m1, m3, m5, m7, m0, m2 + mova Z(5), m5 + mova Z2(7), m7 + mova m0, Z(0) + mova m2, Z(2) + T4_3DNOW m0, m2, m4, m6, m5, m7 + PUNPCK m0, m1, m5 + PUNPCK m2, m3, m7 + mova Z(0), m0 + mova Z(1), m5 + mova Z(2), m2 + mova Z(3), m7 + PUNPCK m4, Z(5), m5 + PUNPCK m6, Z2(7), m7 + mova Z(4), m4 + mova Z(5), m5 + mova Z2(6), m6 + mova Z2(7), m7 + ret +%endmacro + +%if ARCH_X86_32 +INIT_MMX 3dnowext +FFT48_3DNOW + +INIT_MMX 3dnow +FFT48_3DNOW +%endif + +%define Z(x) [zcq + o1q*(x&6) + mmsize*(x&1)] +%define Z2(x) [zcq + o3q + mmsize*(x&1)] +%define ZH(x) [zcq + o1q*(x&6) + mmsize*(x&1) + mmsize/2] +%define Z2H(x) [zcq + o3q + mmsize*(x&1) + mmsize/2] + +%macro DECL_PASS 2+ ; name, payload +align 16 +%1: +DEFINE_ARGS zc, w, n, o1, o3 + lea o3q, [nq*3] + lea o1q, [nq*8] + shl o3q, 4 +.loop: + %2 + add zcq, mmsize*2 + add wq, mmsize + sub nd, mmsize/8 + jg .loop + rep ret +%endmacro + +%macro FFT_DISPATCH 2; clobbers 5 GPRs, 8 XMMs + lea r2, [dispatch_tab%1] + mov r2, [r2 + (%2q-2)*gprsize] +%ifdef PIC + lea r3, [$$] + add r2, r3 +%endif + call r2 +%endmacro ; FFT_DISPATCH + +INIT_YMM avx + +%if HAVE_AVX_EXTERNAL +DECL_PASS pass_avx, PASS_BIG 1 +DECL_PASS pass_interleave_avx, PASS_BIG 0 + +cglobal fft_calc, 2,5,8 + mov r3d, [r0 + FFTContext.nbits] + mov r0, r1 + mov r1, r3 + FFT_DISPATCH _interleave %+ SUFFIX, r1 + REP_RET + +%endif + +INIT_XMM sse + +DECL_PASS pass_sse, PASS_BIG 1 +DECL_PASS pass_interleave_sse, PASS_BIG 0 + +%macro FFT_CALC_FUNC 0 +cglobal fft_calc, 2,5,8 + mov r3d, [r0 + FFTContext.nbits] + PUSH r1 + PUSH r3 + mov r0, r1 + mov r1, r3 + FFT_DISPATCH _interleave %+ SUFFIX, r1 + POP rcx + POP r4 + cmp rcx, 3+(mmsize/16) + jg .end + mov r2, -1 + add rcx, 3 + shl r2, cl + sub r4, r2 +.loop: +%if mmsize == 8 + PSWAPD m0, [r4 + r2 + 4] + mova [r4 + r2 + 4], m0 +%else + movaps xmm0, [r4 + r2] + movaps xmm1, xmm0 + unpcklps xmm0, [r4 + r2 + 16] + unpckhps xmm1, [r4 + r2 + 16] + movaps [r4 + r2], xmm0 + movaps [r4 + r2 + 16], xmm1 +%endif + add r2, mmsize*2 + jl .loop +.end: +%if cpuflag(3dnow) + femms + RET +%else + REP_RET +%endif +%endmacro + +%if ARCH_X86_32 +INIT_MMX 3dnow +FFT_CALC_FUNC +INIT_MMX 3dnowext +FFT_CALC_FUNC +%endif +INIT_XMM sse +FFT_CALC_FUNC + +cglobal fft_permute, 2,7,1 + mov r4, [r0 + FFTContext.revtab] + mov r5, [r0 + FFTContext.tmpbuf] + mov ecx, [r0 + FFTContext.nbits] + mov r2, 1 + shl r2, cl + xor r0, r0 +%if ARCH_X86_32 + mov r1, r1m +%endif +.loop: + movaps xmm0, [r1 + 8*r0] + movzx r6, word [r4 + 2*r0] + movzx r3, word [r4 + 2*r0 + 2] + movlps [r5 + 8*r6], xmm0 + movhps [r5 + 8*r3], xmm0 + add r0, 2 + cmp r0, r2 + jl .loop + shl r2, 3 + add r1, r2 + add r5, r2 + neg r2 +; nbits >= 2 (FFT4) and sizeof(FFTComplex)=8 => at least 32B +.loopcopy: + movaps xmm0, [r5 + r2] + movaps xmm1, [r5 + r2 + 16] + movaps [r1 + r2], xmm0 + movaps [r1 + r2 + 16], xmm1 + add r2, 32 + jl .loopcopy + REP_RET + +%macro IMDCT_CALC_FUNC 0 +cglobal imdct_calc, 3,5,3 + mov r3d, [r0 + FFTContext.mdctsize] + mov r4, [r0 + FFTContext.imdcthalf] + add r1, r3 + PUSH r3 + PUSH r1 +%if ARCH_X86_32 + push r2 + push r1 + push r0 +%else + sub rsp, 8+32*WIN64 ; allocate win64 shadow space +%endif + call r4 +%if ARCH_X86_32 + add esp, 12 +%else + add rsp, 8+32*WIN64 +%endif + POP r1 + POP r3 + lea r0, [r1 + 2*r3] + mov r2, r3 + sub r3, mmsize + neg r2 + mova m2, [ps_neg] +.loop: +%if mmsize == 8 + PSWAPD m0, [r1 + r3] + PSWAPD m1, [r0 + r2] + pxor m0, m2 +%else + mova m0, [r1 + r3] + mova m1, [r0 + r2] + shufps m0, m0, 0x1b + shufps m1, m1, 0x1b + xorps m0, m2 +%endif + mova [r0 + r3], m1 + mova [r1 + r2], m0 + sub r3, mmsize + add r2, mmsize + jl .loop +%if cpuflag(3dnow) + femms + RET +%else + REP_RET +%endif +%endmacro + +%if ARCH_X86_32 +INIT_MMX 3dnow +IMDCT_CALC_FUNC +INIT_MMX 3dnowext +IMDCT_CALC_FUNC +%endif + +INIT_XMM sse +IMDCT_CALC_FUNC + +%if ARCH_X86_32 +INIT_MMX 3dnow +%define mulps pfmul +%define addps pfadd +%define subps pfsub +%define unpcklps punpckldq +%define unpckhps punpckhdq +DECL_PASS pass_3dnow, PASS_SMALL 1, [wq], [wq+o1q] +DECL_PASS pass_interleave_3dnow, PASS_BIG 0 +%define pass_3dnowext pass_3dnow +%define pass_interleave_3dnowext pass_interleave_3dnow +%endif + +%ifdef PIC +%define SECTION_REL - $$ +%else +%define SECTION_REL +%endif + +%macro DECL_FFT 1-2 ; nbits, suffix +%ifidn %0, 1 +%xdefine fullsuffix SUFFIX +%else +%xdefine fullsuffix %2 %+ SUFFIX +%endif +%xdefine list_of_fft fft4 %+ SUFFIX SECTION_REL, fft8 %+ SUFFIX SECTION_REL +%if %1>=5 +%xdefine list_of_fft list_of_fft, fft16 %+ SUFFIX SECTION_REL +%endif +%if %1>=6 +%xdefine list_of_fft list_of_fft, fft32 %+ fullsuffix SECTION_REL +%endif + +%assign n 1<<%1 +%rep 18-%1 +%assign n2 n/2 +%assign n4 n/4 +%xdefine list_of_fft list_of_fft, fft %+ n %+ fullsuffix SECTION_REL + +align 16 +fft %+ n %+ fullsuffix: + call fft %+ n2 %+ SUFFIX + add r0, n*4 - (n&(-2<<%1)) + call fft %+ n4 %+ SUFFIX + add r0, n*2 - (n2&(-2<<%1)) + call fft %+ n4 %+ SUFFIX + sub r0, n*6 + (n2&(-2<<%1)) + lea r1, [cos_ %+ n] + mov r2d, n4/2 + jmp pass %+ fullsuffix + +%assign n n*2 +%endrep +%undef n + +align 8 +dispatch_tab %+ fullsuffix: pointer list_of_fft +%endmacro ; DECL_FFT + +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +DECL_FFT 6 +DECL_FFT 6, _interleave +%endif +INIT_XMM sse +DECL_FFT 5 +DECL_FFT 5, _interleave +%if ARCH_X86_32 +INIT_MMX 3dnow +DECL_FFT 4 +DECL_FFT 4, _interleave +INIT_MMX 3dnowext +DECL_FFT 4 +DECL_FFT 4, _interleave +%endif + +INIT_XMM sse +%undef mulps +%undef addps +%undef subps +%undef unpcklps +%undef unpckhps + +%macro PREROTATER 5 ;-2*k, 2*k, input+n4, tcos+n8, tsin+n8 +%if mmsize == 8 ; j*2+2-n4, n4-2-j*2, input+n4, tcos+n8, tsin+n8 + PSWAPD m0, [%3+%2*4] + movq m2, [%3+%1*4-8] + movq m3, m0 + punpckldq m0, m2 + punpckhdq m2, m3 + movd m1, [%4+%1*2-4] ; tcos[j] + movd m3, [%4+%2*2] ; tcos[n4-j-1] + punpckldq m1, [%5+%1*2-4] ; tsin[j] + punpckldq m3, [%5+%2*2] ; tsin[n4-j-1] + + mova m4, m0 + PSWAPD m5, m1 + pfmul m0, m1 + pfmul m4, m5 + mova m6, m2 + PSWAPD m5, m3 + pfmul m2, m3 + pfmul m6, m5 +%if cpuflag(3dnowext) + pfpnacc m0, m4 + pfpnacc m2, m6 +%else + SBUTTERFLY dq, 0, 4, 1 + SBUTTERFLY dq, 2, 6, 3 + pxor m4, m7 + pxor m6, m7 + pfadd m0, m4 + pfadd m2, m6 +%endif +%else + movaps xmm0, [%3+%2*4] + movaps xmm1, [%3+%1*4-0x10] + movaps xmm2, xmm0 + shufps xmm0, xmm1, 0x88 + shufps xmm1, xmm2, 0x77 + movlps xmm4, [%4+%2*2] + movlps xmm5, [%5+%2*2+0x0] + movhps xmm4, [%4+%1*2-0x8] + movhps xmm5, [%5+%1*2-0x8] + movaps xmm2, xmm0 + movaps xmm3, xmm1 + mulps xmm0, xmm5 + mulps xmm1, xmm4 + mulps xmm2, xmm4 + mulps xmm3, xmm5 + subps xmm1, xmm0 + addps xmm2, xmm3 + movaps xmm0, xmm1 + unpcklps xmm1, xmm2 + unpckhps xmm0, xmm2 +%endif +%endmacro + +%macro CMUL 6 ;j, xmm0, xmm1, 3, 4, 5 +%if cpuflag(sse) + mulps m6, %3, [%5+%1] + mulps m7, %2, [%5+%1] + mulps %2, %2, [%6+%1] + mulps %3, %3, [%6+%1] + subps %2, %2, m6 + addps %3, %3, m7 +%elif cpuflag(3dnow) + mova m6, [%1+%2*2] + mova %3, [%1+%2*2+8] + mova %4, m6 + mova m7, %3 + pfmul m6, [%5+%2] + pfmul %3, [%6+%2] + pfmul %4, [%6+%2] + pfmul m7, [%5+%2] + pfsub %3, m6 + pfadd %4, m7 +%endif +%endmacro + +%macro POSROTATESHUF 5 ;j, k, z+n8, tcos+n8, tsin+n8 +.post: +%if cpuflag(avx) + vmovaps ymm1, [%3+%1*2] + vmovaps ymm0, [%3+%1*2+0x20] + vmovaps ymm3, [%3+%2*2] + vmovaps ymm2, [%3+%2*2+0x20] + + CMUL %1, ymm0, ymm1, %3, %4, %5 + CMUL %2, ymm2, ymm3, %3, %4, %5 + vshufps ymm1, ymm1, ymm1, 0x1b + vshufps ymm3, ymm3, ymm3, 0x1b + vperm2f128 ymm1, ymm1, ymm1, 0x01 + vperm2f128 ymm3, ymm3, ymm3, 0x01 + vunpcklps ymm6, ymm2, ymm1 + vunpckhps ymm4, ymm2, ymm1 + vunpcklps ymm7, ymm0, ymm3 + vunpckhps ymm5, ymm0, ymm3 + + vextractf128 [%3+%1*2], ymm7, 0 + vextractf128 [%3+%1*2+0x10], ymm5, 0 + vextractf128 [%3+%1*2+0x20], ymm7, 1 + vextractf128 [%3+%1*2+0x30], ymm5, 1 + + vextractf128 [%3+%2*2], ymm6, 0 + vextractf128 [%3+%2*2+0x10], ymm4, 0 + vextractf128 [%3+%2*2+0x20], ymm6, 1 + vextractf128 [%3+%2*2+0x30], ymm4, 1 + sub %2, 0x20 + add %1, 0x20 + jl .post +%elif cpuflag(sse) + movaps xmm1, [%3+%1*2] + movaps xmm0, [%3+%1*2+0x10] + CMUL %1, xmm0, xmm1, %3, %4, %5 + movaps xmm5, [%3+%2*2] + movaps xmm4, [%3+%2*2+0x10] + CMUL %2, xmm4, xmm5, %3, %4, %5 + shufps xmm1, xmm1, 0x1b + shufps xmm5, xmm5, 0x1b + movaps xmm6, xmm4 + unpckhps xmm4, xmm1 + unpcklps xmm6, xmm1 + movaps xmm2, xmm0 + unpcklps xmm0, xmm5 + unpckhps xmm2, xmm5 + movaps [%3+%2*2], xmm6 + movaps [%3+%2*2+0x10], xmm4 + movaps [%3+%1*2], xmm0 + movaps [%3+%1*2+0x10], xmm2 + sub %2, 0x10 + add %1, 0x10 + jl .post +%elif cpuflag(3dnow) + CMUL %3, %1, m0, m1, %4, %5 + CMUL %3, %2, m2, m3, %4, %5 + movd [%3+%1*2+ 0], m0 + movd [%3+%2*2+12], m1 + movd [%3+%2*2+ 0], m2 + movd [%3+%1*2+12], m3 + psrlq m0, 32 + psrlq m1, 32 + psrlq m2, 32 + psrlq m3, 32 + movd [%3+%1*2+ 8], m0 + movd [%3+%2*2+ 4], m1 + movd [%3+%2*2+ 8], m2 + movd [%3+%1*2+ 4], m3 + sub %2, 8 + add %1, 8 + jl .post +%endif +%endmacro + +%macro DECL_IMDCT 0 +cglobal imdct_half, 3,12,8; FFTContext *s, FFTSample *output, const FFTSample *input +%if ARCH_X86_64 +%define rrevtab r7 +%define rtcos r8 +%define rtsin r9 +%else +%define rrevtab r6 +%define rtsin r6 +%define rtcos r5 +%endif + mov r3d, [r0+FFTContext.mdctsize] + add r2, r3 + shr r3, 1 + mov rtcos, [r0+FFTContext.tcos] + mov rtsin, [r0+FFTContext.tsin] + add rtcos, r3 + add rtsin, r3 +%if ARCH_X86_64 == 0 + push rtcos + push rtsin +%endif + shr r3, 1 + mov rrevtab, [r0+FFTContext.revtab] + add rrevtab, r3 +%if ARCH_X86_64 == 0 + push rrevtab +%endif + +%if mmsize == 8 + sub r3, 2 +%else + sub r3, 4 +%endif +%if ARCH_X86_64 || mmsize == 8 + xor r4, r4 + sub r4, r3 +%endif +%if notcpuflag(3dnowext) && mmsize == 8 + movd m7, [ps_neg] +%endif +.pre: +%if ARCH_X86_64 == 0 +;unspill +%if mmsize != 8 + xor r4, r4 + sub r4, r3 +%endif + mov rtcos, [esp+8] + mov rtsin, [esp+4] +%endif + + PREROTATER r4, r3, r2, rtcos, rtsin +%if mmsize == 8 + mov r6, [esp] ; rrevtab = ptr+n8 + movzx r5, word [rrevtab+r4-2] ; rrevtab[j] + movzx r6, word [rrevtab+r3] ; rrevtab[n4-j-1] + mova [r1+r5*8], m0 + mova [r1+r6*8], m2 + add r4, 2 + sub r3, 2 +%else +%if ARCH_X86_64 + movzx r5, word [rrevtab+r4-4] + movzx r6, word [rrevtab+r4-2] + movzx r10, word [rrevtab+r3] + movzx r11, word [rrevtab+r3+2] + movlps [r1+r5 *8], xmm0 + movhps [r1+r6 *8], xmm0 + movlps [r1+r10*8], xmm1 + movhps [r1+r11*8], xmm1 + add r4, 4 +%else + mov r6, [esp] + movzx r5, word [r6+r4-4] + movzx r4, word [r6+r4-2] + movlps [r1+r5*8], xmm0 + movhps [r1+r4*8], xmm0 + movzx r5, word [r6+r3] + movzx r4, word [r6+r3+2] + movlps [r1+r5*8], xmm1 + movhps [r1+r4*8], xmm1 +%endif + sub r3, 4 +%endif + jns .pre + + mov r5, r0 + mov r6, r1 + mov r0, r1 + mov r1d, [r5+FFTContext.nbits] + + FFT_DISPATCH SUFFIX, r1 + + mov r0d, [r5+FFTContext.mdctsize] + add r6, r0 + shr r0, 1 +%if ARCH_X86_64 == 0 +%define rtcos r2 +%define rtsin r3 + mov rtcos, [esp+8] + mov rtsin, [esp+4] +%endif + neg r0 + mov r1, -mmsize + sub r1, r0 + POSROTATESHUF r0, r1, r6, rtcos, rtsin +%if ARCH_X86_64 == 0 + add esp, 12 +%endif +%if mmsize == 8 + femms +%endif + RET +%endmacro + +DECL_IMDCT + +%if ARCH_X86_32 +INIT_MMX 3dnow +DECL_IMDCT + +INIT_MMX 3dnowext +DECL_IMDCT +%endif + +INIT_YMM avx + +%if HAVE_AVX_EXTERNAL +DECL_IMDCT +%endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mdct15.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mdct15.asm new file mode 100644 index 0000000000..2a2cdbd21b --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/mdct15.asm @@ -0,0 +1,221 @@ +;****************************************************************************** +;* SIMD optimized non-power-of-two MDCT functions +;* +;* Copyright (C) 2017 Rostislav Pehlivanov +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA 32 + +perm_neg: dd 2, 5, 3, 4, 6, 1, 7, 0 +perm_pos: dd 0, 7, 1, 6, 4, 3, 5, 2 +sign_adjust_r: times 4 dd 0x80000000, 0x00000000 + +sign_adjust_5: dd 0x00000000, 0x80000000, 0x80000000, 0x00000000 + +SECTION .text + +%if ARCH_X86_64 + +;***************************************************************************************** +;void ff_fft15_avx(FFTComplex *out, FFTComplex *in, FFTComplex *exptab, ptrdiff_t stride); +;***************************************************************************************** +%macro FFT5 3 ; %1 - in_offset, %2 - dst1 (64bit used), %3 - dst2 + VBROADCASTSD m0, [inq + %1] ; in[ 0].re, in[ 0].im, in[ 0].re, in[ 0].im + movsd xm1, [inq + 1*16 + 8 + %1] ; in[ 3].re, in[ 3].im, 0, 0 + movsd xm4, [inq + 6*16 + 0 + %1] ; in[12].re, in[12].im, 0, 0 + movhps xm1, [inq + 3*16 + 0 + %1] ; in[ 3].re, in[ 3].im, in[ 6].re, in[ 6].im + movhps xm4, [inq + 4*16 + 8 + %1] ; in[12].re, in[12].im, in[ 9].re, in[ 9].im + + subps xm2, xm1, xm4 ; t[2].im, t[2].re, t[3].im, t[3].re + addps xm1, xm4 ; t[0].re, t[0].im, t[1].re, t[1].im + + movhlps %2, xm1 ; t[0].re, t[1].re, t[0].im, t[1].im + addps %2, xm1 + addps %2, xm0 ; DC[0].re, DC[0].im, junk... + movlhps %2, %2 ; DC[0].re, DC[0].im, DC[0].re, DC[0].im + + shufps xm3, xm1, xm2, q0110 ; t[0].re, t[0].im, t[2].re, t[2].im + shufps xm1, xm2, q2332 ; t[1].re, t[1].im, t[3].re, t[3].im + + mulps xm%3, xm1, xm5 + mulps xm4, xm3, xm6 + mulps xm1, xm6 + + xorps xm1, xm7 + mulps xm3, xm5 + addsubps xm3, xm1 ; t[0].re, t[0].im, t[2].re, t[2].im + subps xm%3, xm4 ; t[4].re, t[4].im, t[5].re, t[5].im + + movhlps xm2, xm%3, xm3 ; t[2].re, t[2].im, t[5].re, t[5].im + movlhps xm3, xm%3 ; t[0].re, t[0].im, t[4].re, t[4].im + + xorps xm2, xm7 + addps xm%3, xm2, xm3 + subps xm3, xm2 + + shufps xm3, xm3, q1032 + vinsertf128 m%3, m%3, xm3, 1 ; All ACs (tmp[1] through to tmp[4]) + addps m%3, m%3, m0 ; Finally offset with DCs +%endmacro + +%macro BUTTERFLIES_DC 1 ; %1 - exptab_offset + mulps xm0, xm9, [exptabq + %1 + 16*0] + mulps xm1, xm10, [exptabq + %1 + 16*1] + + haddps xm0, xm1 + movhlps xm1, xm0 ; t[0].re, t[1].re, t[0].im, t[1].im + + addps xm0, xm1 + addps xm0, xm8 + + movsd [outq], xm0 +%endmacro + +%macro BUTTERFLIES_AC 1 ; %1 - exptab_offset + mulps m0, m12, [exptabq + 64*0 + 0*mmsize + %1] + mulps m1, m12, [exptabq + 64*0 + 1*mmsize + %1] + mulps m2, m13, [exptabq + 64*1 + 0*mmsize + %1] + mulps m3, m13, [exptabq + 64*1 + 1*mmsize + %1] + + addps m0, m0, m2 + addps m1, m1, m3 + addps m0, m0, m11 + + shufps m1, m1, m1, q2301 + addps m0, m0, m1 + + vextractf128 xm1, m0, 1 + + movlps [outq + strideq*1], xm0 + movhps [outq + strideq*2], xm0 + movlps [outq + stride3q], xm1 + movhps [outq + strideq*4], xm1 +%endmacro + +INIT_YMM avx +cglobal fft15, 4, 5, 14, out, in, exptab, stride, stride5 + shl strideq, 3 + + movaps xm5, [exptabq + 480 + 16*0] + movaps xm6, [exptabq + 480 + 16*1] + movaps xm7, [sign_adjust_5] + + FFT5 0, xm8, 11 + FFT5 8, xm9, 12 + FFT5 16, xm10, 13 + +%define stride3q inq + lea stride3q, [strideq + strideq*2] + lea stride5q, [strideq + strideq*4] + + BUTTERFLIES_DC (8*6 + 4*0)*2*4 + BUTTERFLIES_AC (8*0 + 0*0)*2*4 + + add outq, stride5q + BUTTERFLIES_DC (8*6 + 4*1)*2*4 + BUTTERFLIES_AC (8*2 + 0*0)*2*4 + + add outq, stride5q + BUTTERFLIES_DC (8*6 + 4*2)*2*4 + BUTTERFLIES_AC (8*4 + 0*0)*2*4 + + RET + +%endif ; ARCH_X86_64 + +;******************************************************************************************************* +;void ff_mdct15_postreindex(FFTComplex *out, FFTComplex *in, FFTComplex *exp, int *lut, ptrdiff_t len8); +;******************************************************************************************************* +%macro LUT_LOAD_4D 3 + mov r4d, [lutq + %3q*4 + 0] + movsd xmm%1, [inq + r4q*8] + mov r4d, [lutq + %3q*4 + 4] + movhps xmm%1, [inq + r4q*8] +%if cpuflag(avx2) + mov r4d, [lutq + %3q*4 + 8] + movsd %2, [inq + r4q*8] + mov r4d, [lutq + %3q*4 + 12] + movhps %2, [inq + r4q*8] + vinsertf128 %1, %1, %2, 1 +%endif +%endmacro + +%macro POSTROTATE_FN 1 +cglobal mdct15_postreindex, 5, 7, 8 + cpuflag(avx2)*2, out, in, exp, lut, len8, offset_p, offset_n + + xor offset_nq, offset_nq + lea offset_pq, [len8q*2 - %1] + + movaps m7, [sign_adjust_r] + +%if cpuflag(avx2) + movaps m8, [perm_pos] + movaps m9, [perm_neg] +%endif + +.loop: + movups m0, [expq + offset_pq*8] ; exp[p0].re, exp[p0].im, exp[p1].re, exp[p1].im, exp[p2].re, exp[p2].im, exp[p3].re, exp[p3].im + movups m1, [expq + offset_nq*8] ; exp[n3].re, exp[n3].im, exp[n2].re, exp[n2].im, exp[n1].re, exp[n1].im, exp[n0].re, exp[n0].im + + LUT_LOAD_4D m3, xm4, offset_p ; in[p0].re, in[p0].im, in[p1].re, in[p1].im, in[p2].re, in[p2].im, in[p3].re, in[p3].im + LUT_LOAD_4D m4, xm5, offset_n ; in[n3].re, in[n3].im, in[n2].re, in[n2].im, in[n1].re, in[n1].im, in[n0].re, in[n0].im + + mulps m5, m3, m0 ; in[p].reim * exp[p].reim + mulps m6, m4, m1 ; in[n].reim * exp[n].reim + + xorps m5, m7 ; in[p].re *= -1, in[p].im *= 1 + xorps m6, m7 ; in[n].re *= -1, in[n].im *= 1 + + shufps m3, m3, m3, q2301 ; in[p].imre + shufps m4, m4, m4, q2301 ; in[n].imre + + mulps m3, m0 ; in[p].imre * exp[p].reim + mulps m4, m1 ; in[n].imre * exp[n].reim + + haddps m3, m6 ; out[n0].im, out[n1].im, out[n3].re, out[n2].re, out[n2].im, out[n3].im, out[n1].re, out[n0].re + haddps m5, m4 ; out[p0].re, out[p1].re, out[p3].im, out[p2].im, out[p2].re, out[p3].re, out[p1].im, out[p0].im + +%if cpuflag(avx2) + vpermps m3, m9, m3 ; out[n3].im, out[n3].re, out[n2].im, out[n2].re, out[n1].im, out[n1].re, out[n0].im, out[n0].re + vpermps m5, m8, m5 ; out[p0].re, out[p0].im, out[p1].re, out[p1].im, out[p2].re, out[p2].im, out[p3].re, out[p3].im +%else + shufps m3, m3, m3, q0312 + shufps m5, m5, m5, q2130 +%endif + + movups [outq + offset_nq*8], m3 + movups [outq + offset_pq*8], m5 + + sub offset_pq, %1 + add offset_nq, %1 + cmp offset_nq, offset_pq + jle .loop + + REP_RET +%endmacro + +INIT_XMM sse3 +POSTROTATE_FN 2 + +%if ARCH_X86_64 && HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +POSTROTATE_FN 4 +%endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbrdsp.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbrdsp.asm new file mode 100644 index 0000000000..62bbe512ec --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavcodec/x86/sbrdsp.asm @@ -0,0 +1,548 @@ +;****************************************************************************** +;* AAC Spectral Band Replication decoding functions +;* Copyright (C) 2012 Christophe Gisquet +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA +; mask equivalent for multiply by -1.0 1.0 +ps_mask times 2 dd 1<<31, 0 +ps_mask2 times 2 dd 0, 1<<31 +ps_mask3 dd 0, 0, 0, 1<<31 +ps_noise0 times 2 dd 1.0, 0.0, +ps_noise2 times 2 dd -1.0, 0.0 +ps_noise13 dd 0.0, 1.0, 0.0, -1.0 + dd 0.0, -1.0, 0.0, 1.0 + dd 0.0, 1.0, 0.0, -1.0 +cextern sbr_noise_table +cextern ps_neg + +SECTION .text + +INIT_XMM sse +cglobal sbr_sum_square, 2, 3, 6 + mov r2d, r1d + xorps m0, m0 + xorps m1, m1 + sar r2, 3 + jz .prepare +.loop: + movu m2, [r0 + 0] + movu m3, [r0 + 16] + movu m4, [r0 + 32] + movu m5, [r0 + 48] + mulps m2, m2 + mulps m3, m3 + mulps m4, m4 + mulps m5, m5 + addps m0, m2 + addps m1, m3 + addps m0, m4 + addps m1, m5 + add r0, 64 + dec r2 + jnz .loop +.prepare: + and r1, 7 + sar r1, 1 + jz .end +; len is a multiple of 2, thus there are at least 4 elements to process +.endloop: + movu m2, [r0] + add r0, 16 + mulps m2, m2 + dec r1 + addps m0, m2 + jnz .endloop +.end: + addps m0, m1 + movhlps m2, m0 + addps m0, m2 + movss m1, m0 + shufps m0, m0, 1 + addss m0, m1 +%if ARCH_X86_64 == 0 + movss r0m, m0 + fld dword r0m +%endif + RET + +%define STEP 40*4*2 +cglobal sbr_hf_g_filt, 5, 6, 5 + lea r1, [r1 + 8*r4] ; offset by ixh elements into X_high + mov r5, r3 + and r3, 0xFC + lea r2, [r2 + r3*4] + lea r0, [r0 + r3*8] + neg r3 + jz .loop1 +.loop4: + movlps m0, [r2 + 4*r3 + 0] + movlps m1, [r2 + 4*r3 + 8] + movlps m2, [r1 + 0*STEP] + movlps m3, [r1 + 2*STEP] + movhps m2, [r1 + 1*STEP] + movhps m3, [r1 + 3*STEP] + unpcklps m0, m0 + unpcklps m1, m1 + mulps m0, m2 + mulps m1, m3 + movu [r0 + 8*r3 + 0], m0 + movu [r0 + 8*r3 + 16], m1 + add r1, 4*STEP + add r3, 4 + jnz .loop4 + and r5, 3 ; number of single element loops + jz .end +.loop1: ; element 0 and 1 can be computed at the same time + movss m0, [r2] + movlps m2, [r1] + unpcklps m0, m0 + mulps m2, m0 + movlps [r0], m2 + add r0, 8 + add r2, 4 + add r1, STEP + dec r5 + jnz .loop1 +.end: + RET + +; void ff_sbr_hf_gen_sse(float (*X_high)[2], const float (*X_low)[2], +; const float alpha0[2], const float alpha1[2], +; float bw, int start, int end) +; +cglobal sbr_hf_gen, 4,4,8, X_high, X_low, alpha0, alpha1, BW, S, E + ; load alpha factors +%define bw m0 +%if ARCH_X86_64 == 0 || WIN64 + movss bw, BWm +%endif + movlps m2, [alpha1q] + movlps m1, [alpha0q] + shufps bw, bw, 0 + mulps m2, bw ; (a1[0] a1[1])*bw + mulps m1, bw ; (a0[0] a0[1])*bw = (a2 a3) + mulps m2, bw ; (a1[0] a1[1])*bw*bw = (a0 a1) + mova m3, m1 + mova m4, m2 + + ; Set pointers +%if ARCH_X86_64 == 0 || WIN64 + ; start and end 6th and 7th args on stack + mov r2d, Sm + mov r3d, Em + DEFINE_ARGS X_high, X_low, start, end +%else +; BW does not actually occupy a register, so shift by 1 + DEFINE_ARGS X_high, X_low, alpha0, alpha1, start, end + movsxd startq, startd + movsxd endq, endd +%endif + sub startq, endq ; neg num of loops + lea X_highq, [X_highq + endq*2*4] + lea X_lowq, [X_lowq + endq*2*4 - 2*2*4] + shl startq, 3 ; offset from num loops + + mova m0, [X_lowq + startq] + shufps m3, m3, q1111 + shufps m4, m4, q1111 + xorps m3, [ps_mask] + shufps m1, m1, q0000 + shufps m2, m2, q0000 + xorps m4, [ps_mask] +.loop2: + movu m7, [X_lowq + startq + 8] ; BbCc + mova m6, m0 + mova m5, m7 + shufps m0, m0, q2301 ; aAbB + shufps m7, m7, q2301 ; bBcC + mulps m0, m4 + mulps m7, m3 + mulps m6, m2 + mulps m5, m1 + addps m7, m0 + mova m0, [X_lowq + startq + 16] ; CcDd + addps m7, m0 + addps m6, m5 + addps m7, m6 + mova [X_highq + startq], m7 + add startq, 16 + jnz .loop2 + RET + +cglobal sbr_sum64x5, 1,2,4,z + lea r1q, [zq+ 256] +.loop: + mova m0, [zq+ 0] + mova m2, [zq+ 16] + mova m1, [zq+ 256] + mova m3, [zq+ 272] + addps m0, [zq+ 512] + addps m2, [zq+ 528] + addps m1, [zq+ 768] + addps m3, [zq+ 784] + addps m0, [zq+1024] + addps m2, [zq+1040] + addps m0, m1 + addps m2, m3 + mova [zq], m0 + mova [zq+16], m2 + add zq, 32 + cmp zq, r1q + jne .loop + REP_RET + +INIT_XMM sse +cglobal sbr_qmf_post_shuffle, 2,3,4,W,z + lea r2q, [zq + (64-4)*4] + mova m3, [ps_neg] +.loop: + mova m1, [zq] + xorps m0, m3, [r2q] + shufps m0, m0, m0, q0123 + unpcklps m2, m0, m1 + unpckhps m0, m0, m1 + mova [Wq + 0], m2 + mova [Wq + 16], m0 + add Wq, 32 + sub r2q, 16 + add zq, 16 + cmp zq, r2q + jl .loop + REP_RET + +INIT_XMM sse +cglobal sbr_neg_odd_64, 1,2,4,z + lea r1q, [zq+256] +.loop: + mova m0, [zq+ 0] + mova m1, [zq+16] + mova m2, [zq+32] + mova m3, [zq+48] + xorps m0, [ps_mask2] + xorps m1, [ps_mask2] + xorps m2, [ps_mask2] + xorps m3, [ps_mask2] + mova [zq+ 0], m0 + mova [zq+16], m1 + mova [zq+32], m2 + mova [zq+48], m3 + add zq, 64 + cmp zq, r1q + jne .loop + REP_RET + +; void ff_sbr_qmf_deint_bfly_sse2(float *v, const float *src0, const float *src1) +%macro SBR_QMF_DEINT_BFLY 0 +cglobal sbr_qmf_deint_bfly, 3,5,8, v,src0,src1,vrev,c + mov cq, 64*4-2*mmsize + lea vrevq, [vq + 64*4] +.loop: + mova m0, [src0q+cq] + mova m1, [src1q] + mova m4, [src0q+cq+mmsize] + mova m5, [src1q+mmsize] +%if cpuflag(sse2) + pshufd m2, m0, q0123 + pshufd m3, m1, q0123 + pshufd m6, m4, q0123 + pshufd m7, m5, q0123 +%else + shufps m2, m0, m0, q0123 + shufps m3, m1, m1, q0123 + shufps m6, m4, m4, q0123 + shufps m7, m5, m5, q0123 +%endif + addps m5, m2 + subps m0, m7 + addps m1, m6 + subps m4, m3 + mova [vrevq], m1 + mova [vrevq+mmsize], m5 + mova [vq+cq], m0 + mova [vq+cq+mmsize], m4 + add src1q, 2*mmsize + add vrevq, 2*mmsize + sub cq, 2*mmsize + jge .loop + REP_RET +%endmacro + +INIT_XMM sse +SBR_QMF_DEINT_BFLY + +INIT_XMM sse2 +SBR_QMF_DEINT_BFLY + +INIT_XMM sse2 +cglobal sbr_qmf_pre_shuffle, 1,4,6,z +%define OFFSET (32*4-2*mmsize) + mov r3q, OFFSET + lea r1q, [zq + (32+1)*4] + lea r2q, [zq + 64*4] + mova m5, [ps_neg] +.loop: + movu m0, [r1q] + movu m2, [r1q + mmsize] + movu m1, [zq + r3q + 4 + mmsize] + movu m3, [zq + r3q + 4] + + pxor m2, m5 + pxor m0, m5 + pshufd m2, m2, q0123 + pshufd m0, m0, q0123 + SBUTTERFLY dq, 2, 3, 4 + SBUTTERFLY dq, 0, 1, 4 + mova [r2q + 2*r3q + 0*mmsize], m2 + mova [r2q + 2*r3q + 1*mmsize], m3 + mova [r2q + 2*r3q + 2*mmsize], m0 + mova [r2q + 2*r3q + 3*mmsize], m1 + add r1q, 2*mmsize + sub r3q, 2*mmsize + jge .loop + movq m2, [zq] + movq [r2q], m2 + REP_RET + +%ifdef PIC +%define NREGS 1 +%if UNIX64 +%define NOISE_TABLE r6q ; r5q is m_max +%else +%define NOISE_TABLE r5q +%endif +%else +%define NREGS 0 +%define NOISE_TABLE sbr_noise_table +%endif + +%macro LOAD_NST 1 +%ifdef PIC + lea NOISE_TABLE, [%1] + mova m0, [kxq + NOISE_TABLE] +%else + mova m0, [kxq + %1] +%endif +%endmacro + +INIT_XMM sse2 +; sbr_hf_apply_noise_0(float (*Y)[2], const float *s_m, +; const float *q_filt, int noise, +; int kx, int m_max) +cglobal sbr_hf_apply_noise_0, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max + mova m0, [ps_noise0] + jmp apply_noise_main + +; sbr_hf_apply_noise_1(float (*Y)[2], const float *s_m, +; const float *q_filt, int noise, +; int kx, int m_max) +cglobal sbr_hf_apply_noise_1, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max + and kxq, 1 + shl kxq, 4 + LOAD_NST ps_noise13 + jmp apply_noise_main + +; sbr_hf_apply_noise_2(float (*Y)[2], const float *s_m, +; const float *q_filt, int noise, +; int kx, int m_max) +cglobal sbr_hf_apply_noise_2, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max + mova m0, [ps_noise2] + jmp apply_noise_main + +; sbr_hf_apply_noise_3(float (*Y)[2], const float *s_m, +; const float *q_filt, int noise, +; int kx, int m_max) +cglobal sbr_hf_apply_noise_3, 5,5+NREGS+UNIX64,8, Y,s_m,q_filt,noise,kx,m_max + and kxq, 1 + shl kxq, 4 + LOAD_NST ps_noise13+16 + +apply_noise_main: +%if ARCH_X86_64 == 0 || WIN64 + mov kxd, m_maxm + DEFINE_ARGS Y, s_m, q_filt, noise, count +%else + DEFINE_ARGS Y, s_m, q_filt, noise, kx, count +%endif + movsxdifnidn noiseq, noised + dec noiseq + shl countd, 2 +%ifdef PIC + lea NOISE_TABLE, [sbr_noise_table] +%endif + lea Yq, [Yq + 2*countq] + add s_mq, countq + add q_filtq, countq + shl noiseq, 3 + pxor m5, m5 + neg countq +.loop: + mova m1, [q_filtq + countq] + movu m3, [noiseq + NOISE_TABLE + 1*mmsize] + movu m4, [noiseq + NOISE_TABLE + 2*mmsize] + add noiseq, 2*mmsize + and noiseq, 0x1ff<<3 + punpckhdq m2, m1, m1 + punpckldq m1, m1 + mulps m1, m3 ; m2 = q_filt[m] * ff_sbr_noise_table[noise] + mulps m2, m4 ; m2 = q_filt[m] * ff_sbr_noise_table[noise] + mova m3, [s_mq + countq] + ; TODO: replace by a vpermd in AVX2 + punpckhdq m4, m3, m3 + punpckldq m3, m3 + pcmpeqd m6, m3, m5 ; m6 == 0 + pcmpeqd m7, m4, m5 ; m7 == 0 + mulps m3, m0 ; s_m[m] * phi_sign + mulps m4, m0 ; s_m[m] * phi_sign + pand m1, m6 + pand m2, m7 + movu m6, [Yq + 2*countq] + movu m7, [Yq + 2*countq + mmsize] + addps m3, m1 + addps m4, m2 + addps m6, m3 + addps m7, m4 + movu [Yq + 2*countq], m6 + movu [Yq + 2*countq + mmsize], m7 + add countq, mmsize + jl .loop + RET + +INIT_XMM sse +cglobal sbr_qmf_deint_neg, 2,4,4,v,src,vrev,c +%define COUNT 32*4 +%define OFFSET 32*4 + mov cq, -COUNT + lea vrevq, [vq + OFFSET + COUNT] + add vq, OFFSET-mmsize + add srcq, 2*COUNT + mova m3, [ps_neg] +.loop: + mova m0, [srcq + 2*cq + 0*mmsize] + mova m1, [srcq + 2*cq + 1*mmsize] + shufps m2, m0, m1, q2020 + shufps m1, m0, q1313 + xorps m2, m3 + mova [vq], m1 + mova [vrevq + cq], m2 + sub vq, mmsize + add cq, mmsize + jl .loop + REP_RET + +%macro SBR_AUTOCORRELATE 0 +cglobal sbr_autocorrelate, 2,3,8,32, x, phi, cnt + mov cntq, 37*8 + add xq, cntq + neg cntq + +%if cpuflag(sse3) +%define MOVH movsd + movddup m5, [xq+cntq] +%else +%define MOVH movlps + movlps m5, [xq+cntq] + movlhps m5, m5 +%endif + MOVH m7, [xq+cntq+8 ] + MOVH m1, [xq+cntq+16] + shufps m7, m7, q0110 + shufps m1, m1, q0110 + mulps m3, m5, m7 ; x[0][0] * x[1][0], x[0][1] * x[1][1], x[0][0] * x[1][1], x[0][1] * x[1][0] + mulps m4, m5, m5 ; x[0][0] * x[0][0], x[0][1] * x[0][1]; + mulps m5, m1 ; real_sum2 = x[0][0] * x[2][0], x[0][1] * x[2][1]; imag_sum2 = x[0][0] * x[2][1], x[0][1] * x[2][0] + movaps [rsp ], m3 + movaps [rsp+16], m4 + add cntq, 8 + + MOVH m2, [xq+cntq+16] + movlhps m7, m7 + shufps m2, m2, q0110 + mulps m6, m7, m1 ; real_sum1 = x[1][0] * x[2][0], x[1][1] * x[2][1]; imag_sum1 += x[1][0] * x[2][1], x[1][1] * x[2][0] + mulps m4, m7, m2 + mulps m7, m7 ; real_sum0 = x[1][0] * x[1][0], x[1][1] * x[1][1]; + addps m5, m4 ; real_sum2 += x[1][0] * x[3][0], x[1][1] * x[3][1]; imag_sum2 += x[1][0] * x[3][1], x[1][1] * x[3][0] + +align 16 +.loop: + add cntq, 8 + MOVH m0, [xq+cntq+16] + movlhps m1, m1 + shufps m0, m0, q0110 + mulps m3, m1, m2 + mulps m4, m1, m0 + mulps m1, m1 + addps m6, m3 ; real_sum1 += x[i][0] * x[i + 1][0], x[i][1] * x[i + 1][1]; imag_sum1 += x[i][0] * x[i + 1][1], x[i][1] * x[i + 1][0]; + addps m5, m4 ; real_sum2 += x[i][0] * x[i + 2][0], x[i][1] * x[i + 2][1]; imag_sum2 += x[i][0] * x[i + 2][1], x[i][1] * x[i + 2][0]; + addps m7, m1 ; real_sum0 += x[i][0] * x[i][0], x[i][1] * x[i][1]; + add cntq, 8 + MOVH m1, [xq+cntq+16] + movlhps m2, m2 + shufps m1, m1, q0110 + mulps m3, m2, m0 + mulps m4, m2, m1 + mulps m2, m2 + addps m6, m3 ; real_sum1 += x[i][0] * x[i + 1][0], x[i][1] * x[i + 1][1]; imag_sum1 += x[i][0] * x[i + 1][1], x[i][1] * x[i + 1][0]; + addps m5, m4 ; real_sum2 += x[i][0] * x[i + 2][0], x[i][1] * x[i + 2][1]; imag_sum2 += x[i][0] * x[i + 2][1], x[i][1] * x[i + 2][0]; + addps m7, m2 ; real_sum0 += x[i][0] * x[i][0], x[i][1] * x[i][1]; + add cntq, 8 + MOVH m2, [xq+cntq+16] + movlhps m0, m0 + shufps m2, m2, q0110 + mulps m3, m0, m1 + mulps m4, m0, m2 + mulps m0, m0 + addps m6, m3 ; real_sum1 += x[i][0] * x[i + 1][0], x[i][1] * x[i + 1][1]; imag_sum1 += x[i][0] * x[i + 1][1], x[i][1] * x[i + 1][0]; + addps m5, m4 ; real_sum2 += x[i][0] * x[i + 2][0], x[i][1] * x[i + 2][1]; imag_sum2 += x[i][0] * x[i + 2][1], x[i][1] * x[i + 2][0]; + addps m7, m0 ; real_sum0 += x[i][0] * x[i][0], x[i][1] * x[i][1]; + jl .loop + + movlhps m1, m1 + mulps m2, m1 + mulps m1, m1 + addps m2, m6 ; real_sum1 + x[38][0] * x[39][0], x[38][1] * x[39][1]; imag_sum1 + x[38][0] * x[39][1], x[38][1] * x[39][0]; + addps m1, m7 ; real_sum0 + x[38][0] * x[38][0], x[38][1] * x[38][1]; + addps m6, [rsp ] ; real_sum1 + x[ 0][0] * x[ 1][0], x[ 0][1] * x[ 1][1]; imag_sum1 + x[ 0][0] * x[ 1][1], x[ 0][1] * x[ 1][0]; + addps m7, [rsp+16] ; real_sum0 + x[ 0][0] * x[ 0][0], x[ 0][1] * x[ 0][1]; + + xorps m2, [ps_mask3] + xorps m5, [ps_mask3] + xorps m6, [ps_mask3] + HADDPS m2, m5, m3 + HADDPS m7, m6, m4 +%if cpuflag(sse3) + movshdup m0, m1 +%else + movss m0, m1 + shufps m1, m1, q0001 +%endif + addss m1, m0 + movaps [phiq ], m2 + movhps [phiq+0x18], m7 + movss [phiq+0x28], m7 + movss [phiq+0x10], m1 + RET +%endmacro + +INIT_XMM sse +SBR_AUTOCORRELATE +INIT_XMM sse3 +SBR_AUTOCORRELATE diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/Makefile new file mode 100644 index 0000000000..5613813ba8 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/aarch64/Makefile @@ -0,0 +1,4 @@ +OBJS += aarch64/cpu.o \ + aarch64/float_dsp_init.o \ + +NEON-OBJS += aarch64/float_dsp_neon.o diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/Makefile new file mode 100644 index 0000000000..5da44b0542 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/arm/Makefile @@ -0,0 +1,8 @@ +OBJS += arm/cpu.o \ + arm/float_dsp_init_arm.o \ + +VFP-OBJS += arm/float_dsp_init_vfp.o \ + arm/float_dsp_vfp.o \ + +NEON-OBJS += arm/float_dsp_init_neon.o \ + arm/float_dsp_neon.o \ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffversion.h b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffversion.h deleted file mode 100644 index 723c7d4244..0000000000 --- a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/ffversion.h +++ /dev/null @@ -1,5 +0,0 @@ -/* Automatically generated by version.sh, do not manually edit! */ -#ifndef AVUTIL_FFVERSION_H -#define AVUTIL_FFVERSION_H -#define FFMPEG_VERSION "" -#endif /* AVUTIL_FFVERSION_H */ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/Makefile new file mode 100644 index 0000000000..5f5242b5bd --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/Makefile @@ -0,0 +1,18 @@ +OBJS += x86/cpu.o \ + x86/fixed_dsp_init.o \ + x86/float_dsp_init.o \ + x86/imgutils_init.o \ + x86/lls_init.o \ + +OBJS-$(CONFIG_PIXELUTILS) += x86/pixelutils_init.o \ + +EMMS_OBJS_$(HAVE_MMX_INLINE)_$(HAVE_MMX_EXTERNAL)_$(HAVE_MM_EMPTY) = x86/emms.o + +X86ASM-OBJS += x86/cpuid.o \ + $(EMMS_OBJS__yes_) \ + x86/fixed_dsp.o \ + x86/float_dsp.o \ + x86/imgutils.o \ + x86/lls.o \ + +X86ASM-OBJS-$(CONFIG_PIXELUTILS) += x86/pixelutils.o \ diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpuid.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpuid.asm new file mode 100644 index 0000000000..c3f7866ec7 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/cpuid.asm @@ -0,0 +1,91 @@ +;***************************************************************************** +;* Copyright (C) 2005-2010 x264 project +;* +;* Authors: Loren Merritt +;* Fiona Glaser +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "x86util.asm" + +SECTION .text + +;----------------------------------------------------------------------------- +; void ff_cpu_cpuid(int index, int *eax, int *ebx, int *ecx, int *edx) +;----------------------------------------------------------------------------- +cglobal cpu_cpuid, 5,7 + push rbx + push r4 + push r3 + push r2 + push r1 + mov eax, r0d + xor ecx, ecx + cpuid + pop r4 + mov [r4], eax + pop r4 + mov [r4], ebx + pop r4 + mov [r4], ecx + pop r4 + mov [r4], edx + pop rbx + RET + +;----------------------------------------------------------------------------- +; void ff_cpu_xgetbv(int op, int *eax, int *edx) +;----------------------------------------------------------------------------- +cglobal cpu_xgetbv, 3,7 + push r2 + push r1 + mov ecx, r0d + xgetbv + pop r4 + mov [r4], eax + pop r4 + mov [r4], edx + RET + +%if ARCH_X86_64 == 0 +;----------------------------------------------------------------------------- +; int ff_cpu_cpuid_test(void) +; return 0 if unsupported +;----------------------------------------------------------------------------- +cglobal cpu_cpuid_test + pushfd + push ebx + push ebp + push esi + push edi + pushfd + pop eax + mov ebx, eax + xor eax, 0x200000 + push eax + popfd + pushfd + pop eax + xor eax, ebx + pop edi + pop esi + pop ebp + pop ebx + popfd + ret +%endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/fixed_dsp.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/fixed_dsp.asm new file mode 100644 index 0000000000..979dd5c334 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/fixed_dsp.asm @@ -0,0 +1,48 @@ +;***************************************************************************** +;* x86-optimized Float DSP functions +;* +;* Copyright 2016 James Almer +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "x86util.asm" + +SECTION .text + +;----------------------------------------------------------------------------- +; void ff_butterflies_fixed(float *src0, float *src1, int len); +;----------------------------------------------------------------------------- +INIT_XMM sse2 +cglobal butterflies_fixed, 3,3,3, src0, src1, len + shl lend, 2 + add src0q, lenq + add src1q, lenq + neg lenq + +align 16 +.loop: + mova m0, [src0q + lenq] + mova m1, [src1q + lenq] + mova m2, m0 + paddd m0, m1 + psubd m2, m1 + mova [src0q + lenq], m0 + mova [src1q + lenq], m2 + add lenq, mmsize + jl .loop + RET diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/float_dsp.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/float_dsp.asm new file mode 100644 index 0000000000..517fd63638 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/float_dsp.asm @@ -0,0 +1,484 @@ +;***************************************************************************** +;* x86-optimized Float DSP functions +;* +;* Copyright 2006 Loren Merritt +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "x86util.asm" + +SECTION_RODATA 32 +pd_reverse: dd 7, 6, 5, 4, 3, 2, 1, 0 + +SECTION .text + +;----------------------------------------------------------------------------- +; void vector_fmul(float *dst, const float *src0, const float *src1, int len) +;----------------------------------------------------------------------------- +%macro VECTOR_FMUL 0 +cglobal vector_fmul, 4,4,2, dst, src0, src1, len + lea lenq, [lend*4 - 64] +ALIGN 16 +.loop: +%assign a 0 +%rep 32/mmsize + mova m0, [src0q + lenq + (a+0)*mmsize] + mova m1, [src0q + lenq + (a+1)*mmsize] + mulps m0, m0, [src1q + lenq + (a+0)*mmsize] + mulps m1, m1, [src1q + lenq + (a+1)*mmsize] + mova [dstq + lenq + (a+0)*mmsize], m0 + mova [dstq + lenq + (a+1)*mmsize], m1 +%assign a a+2 +%endrep + + sub lenq, 64 + jge .loop + REP_RET +%endmacro + +INIT_XMM sse +VECTOR_FMUL +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +VECTOR_FMUL +%endif + +;----------------------------------------------------------------------------- +; void vector_dmul(double *dst, const double *src0, const double *src1, int len) +;----------------------------------------------------------------------------- +%macro VECTOR_DMUL 0 +cglobal vector_dmul, 4,4,4, dst, src0, src1, len + lea lend, [lenq*8 - mmsize*4] +ALIGN 16 +.loop: + movaps m0, [src0q + lenq + 0*mmsize] + movaps m1, [src0q + lenq + 1*mmsize] + movaps m2, [src0q + lenq + 2*mmsize] + movaps m3, [src0q + lenq + 3*mmsize] + mulpd m0, m0, [src1q + lenq + 0*mmsize] + mulpd m1, m1, [src1q + lenq + 1*mmsize] + mulpd m2, m2, [src1q + lenq + 2*mmsize] + mulpd m3, m3, [src1q + lenq + 3*mmsize] + movaps [dstq + lenq + 0*mmsize], m0 + movaps [dstq + lenq + 1*mmsize], m1 + movaps [dstq + lenq + 2*mmsize], m2 + movaps [dstq + lenq + 3*mmsize], m3 + + sub lenq, mmsize*4 + jge .loop + RET +%endmacro + +INIT_XMM sse2 +VECTOR_DMUL +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +VECTOR_DMUL +%endif + +;------------------------------------------------------------------------------ +; void ff_vector_fmac_scalar(float *dst, const float *src, float mul, int len) +;------------------------------------------------------------------------------ + +%macro VECTOR_FMAC_SCALAR 0 +%if UNIX64 +cglobal vector_fmac_scalar, 3,3,5, dst, src, len +%else +cglobal vector_fmac_scalar, 4,4,5, dst, src, mul, len +%endif +%if ARCH_X86_32 + VBROADCASTSS m0, mulm +%else +%if WIN64 + SWAP 0, 2 +%endif + shufps xm0, xm0, 0 +%if cpuflag(avx) + vinsertf128 m0, m0, xm0, 1 +%endif +%endif + lea lenq, [lend*4-64] +.loop: +%if cpuflag(fma3) + mova m1, [dstq+lenq] + mova m2, [dstq+lenq+1*mmsize] + fmaddps m1, m0, [srcq+lenq], m1 + fmaddps m2, m0, [srcq+lenq+1*mmsize], m2 +%else ; cpuflag + mulps m1, m0, [srcq+lenq] + mulps m2, m0, [srcq+lenq+1*mmsize] +%if mmsize < 32 + mulps m3, m0, [srcq+lenq+2*mmsize] + mulps m4, m0, [srcq+lenq+3*mmsize] +%endif ; mmsize + addps m1, m1, [dstq+lenq] + addps m2, m2, [dstq+lenq+1*mmsize] +%if mmsize < 32 + addps m3, m3, [dstq+lenq+2*mmsize] + addps m4, m4, [dstq+lenq+3*mmsize] +%endif ; mmsize +%endif ; cpuflag + mova [dstq+lenq], m1 + mova [dstq+lenq+1*mmsize], m2 +%if mmsize < 32 + mova [dstq+lenq+2*mmsize], m3 + mova [dstq+lenq+3*mmsize], m4 +%endif ; mmsize + sub lenq, 64 + jge .loop + REP_RET +%endmacro + +INIT_XMM sse +VECTOR_FMAC_SCALAR +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +VECTOR_FMAC_SCALAR +%endif +%if HAVE_FMA3_EXTERNAL +INIT_YMM fma3 +VECTOR_FMAC_SCALAR +%endif + +;------------------------------------------------------------------------------ +; void ff_vector_fmul_scalar(float *dst, const float *src, float mul, int len) +;------------------------------------------------------------------------------ + +%macro VECTOR_FMUL_SCALAR 0 +%if UNIX64 +cglobal vector_fmul_scalar, 3,3,2, dst, src, len +%else +cglobal vector_fmul_scalar, 4,4,3, dst, src, mul, len +%endif +%if ARCH_X86_32 + movss m0, mulm +%elif WIN64 + SWAP 0, 2 +%endif + shufps m0, m0, 0 + lea lenq, [lend*4-mmsize] +.loop: + mova m1, [srcq+lenq] + mulps m1, m0 + mova [dstq+lenq], m1 + sub lenq, mmsize + jge .loop + REP_RET +%endmacro + +INIT_XMM sse +VECTOR_FMUL_SCALAR + +;------------------------------------------------------------------------------ +; void ff_vector_dmac_scalar(double *dst, const double *src, double mul, +; int len) +;------------------------------------------------------------------------------ + +%macro VECTOR_DMAC_SCALAR 0 +%if ARCH_X86_32 +cglobal vector_dmac_scalar, 2,4,5, dst, src, mul, len, lenaddr + mov lenq, lenaddrm + VBROADCASTSD m0, mulm +%else +%if UNIX64 +cglobal vector_dmac_scalar, 3,3,5, dst, src, len +%else +cglobal vector_dmac_scalar, 4,4,5, dst, src, mul, len + SWAP 0, 2 +%endif + movlhps xm0, xm0 +%if cpuflag(avx) + vinsertf128 m0, m0, xm0, 1 +%endif +%endif + lea lenq, [lend*8-mmsize*4] +.loop: +%if cpuflag(fma3) + movaps m1, [dstq+lenq] + movaps m2, [dstq+lenq+1*mmsize] + movaps m3, [dstq+lenq+2*mmsize] + movaps m4, [dstq+lenq+3*mmsize] + fmaddpd m1, m0, [srcq+lenq], m1 + fmaddpd m2, m0, [srcq+lenq+1*mmsize], m2 + fmaddpd m3, m0, [srcq+lenq+2*mmsize], m3 + fmaddpd m4, m0, [srcq+lenq+3*mmsize], m4 +%else ; cpuflag + mulpd m1, m0, [srcq+lenq] + mulpd m2, m0, [srcq+lenq+1*mmsize] + mulpd m3, m0, [srcq+lenq+2*mmsize] + mulpd m4, m0, [srcq+lenq+3*mmsize] + addpd m1, m1, [dstq+lenq] + addpd m2, m2, [dstq+lenq+1*mmsize] + addpd m3, m3, [dstq+lenq+2*mmsize] + addpd m4, m4, [dstq+lenq+3*mmsize] +%endif ; cpuflag + movaps [dstq+lenq], m1 + movaps [dstq+lenq+1*mmsize], m2 + movaps [dstq+lenq+2*mmsize], m3 + movaps [dstq+lenq+3*mmsize], m4 + sub lenq, mmsize*4 + jge .loop + REP_RET +%endmacro + +INIT_XMM sse2 +VECTOR_DMAC_SCALAR +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +VECTOR_DMAC_SCALAR +%endif +%if HAVE_FMA3_EXTERNAL +INIT_YMM fma3 +VECTOR_DMAC_SCALAR +%endif + +;------------------------------------------------------------------------------ +; void ff_vector_dmul_scalar(double *dst, const double *src, double mul, +; int len) +;------------------------------------------------------------------------------ + +%macro VECTOR_DMUL_SCALAR 0 +%if ARCH_X86_32 +cglobal vector_dmul_scalar, 3,4,3, dst, src, mul, len, lenaddr + mov lenq, lenaddrm +%elif UNIX64 +cglobal vector_dmul_scalar, 3,3,3, dst, src, len +%else +cglobal vector_dmul_scalar, 4,4,3, dst, src, mul, len +%endif +%if ARCH_X86_32 + VBROADCASTSD m0, mulm +%else +%if WIN64 + SWAP 0, 2 +%endif + movlhps xm0, xm0 +%if cpuflag(avx) + vinsertf128 ym0, ym0, xm0, 1 +%endif +%endif + lea lenq, [lend*8-2*mmsize] +.loop: + mulpd m1, m0, [srcq+lenq ] + mulpd m2, m0, [srcq+lenq+mmsize] + movaps [dstq+lenq ], m1 + movaps [dstq+lenq+mmsize], m2 + sub lenq, 2*mmsize + jge .loop + REP_RET +%endmacro + +INIT_XMM sse2 +VECTOR_DMUL_SCALAR +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +VECTOR_DMUL_SCALAR +%endif + +;----------------------------------------------------------------------------- +; vector_fmul_window(float *dst, const float *src0, +; const float *src1, const float *win, int len); +;----------------------------------------------------------------------------- +%macro VECTOR_FMUL_WINDOW 0 +cglobal vector_fmul_window, 5, 6, 6, dst, src0, src1, win, len, len1 + shl lend, 2 + lea len1q, [lenq - mmsize] + add src0q, lenq + add dstq, lenq + add winq, lenq + neg lenq +.loop: + mova m0, [winq + lenq] + mova m4, [src0q + lenq] +%if cpuflag(sse) + mova m1, [winq + len1q] + mova m5, [src1q + len1q] + shufps m1, m1, 0x1b + shufps m5, m5, 0x1b + mova m2, m0 + mova m3, m1 + mulps m2, m4 + mulps m3, m5 + mulps m1, m4 + mulps m0, m5 + addps m2, m3 + subps m1, m0 + shufps m2, m2, 0x1b +%else + pswapd m1, [winq + len1q] + pswapd m5, [src1q + len1q] + mova m2, m0 + mova m3, m1 + pfmul m2, m4 + pfmul m3, m5 + pfmul m1, m4 + pfmul m0, m5 + pfadd m2, m3 + pfsub m1, m0 + pswapd m2, m2 +%endif + mova [dstq + lenq], m1 + mova [dstq + len1q], m2 + sub len1q, mmsize + add lenq, mmsize + jl .loop +%if mmsize == 8 + femms +%endif + REP_RET +%endmacro + +INIT_MMX 3dnowext +VECTOR_FMUL_WINDOW +INIT_XMM sse +VECTOR_FMUL_WINDOW + +;----------------------------------------------------------------------------- +; vector_fmul_add(float *dst, const float *src0, const float *src1, +; const float *src2, int len) +;----------------------------------------------------------------------------- +%macro VECTOR_FMUL_ADD 0 +cglobal vector_fmul_add, 5,5,4, dst, src0, src1, src2, len + lea lenq, [lend*4 - 2*mmsize] +ALIGN 16 +.loop: + mova m0, [src0q + lenq] + mova m1, [src0q + lenq + mmsize] +%if cpuflag(fma3) + mova m2, [src2q + lenq] + mova m3, [src2q + lenq + mmsize] + fmaddps m0, m0, [src1q + lenq], m2 + fmaddps m1, m1, [src1q + lenq + mmsize], m3 +%else + mulps m0, m0, [src1q + lenq] + mulps m1, m1, [src1q + lenq + mmsize] + addps m0, m0, [src2q + lenq] + addps m1, m1, [src2q + lenq + mmsize] +%endif + mova [dstq + lenq], m0 + mova [dstq + lenq + mmsize], m1 + + sub lenq, 2*mmsize + jge .loop + REP_RET +%endmacro + +INIT_XMM sse +VECTOR_FMUL_ADD +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +VECTOR_FMUL_ADD +%endif +%if HAVE_FMA3_EXTERNAL +INIT_YMM fma3 +VECTOR_FMUL_ADD +%endif + +;----------------------------------------------------------------------------- +; void vector_fmul_reverse(float *dst, const float *src0, const float *src1, +; int len) +;----------------------------------------------------------------------------- +%macro VECTOR_FMUL_REVERSE 0 +cglobal vector_fmul_reverse, 4,4,2, dst, src0, src1, len +%if cpuflag(avx2) + movaps m2, [pd_reverse] +%endif + lea lenq, [lend*4 - 2*mmsize] +ALIGN 16 +.loop: +%if cpuflag(avx2) + vpermps m0, m2, [src1q] + vpermps m1, m2, [src1q+mmsize] +%elif cpuflag(avx) + vmovaps xmm0, [src1q + 16] + vinsertf128 m0, m0, [src1q], 1 + vshufps m0, m0, m0, q0123 + vmovaps xmm1, [src1q + mmsize + 16] + vinsertf128 m1, m1, [src1q + mmsize], 1 + vshufps m1, m1, m1, q0123 +%else + mova m0, [src1q] + mova m1, [src1q + mmsize] + shufps m0, m0, q0123 + shufps m1, m1, q0123 +%endif + mulps m0, m0, [src0q + lenq + mmsize] + mulps m1, m1, [src0q + lenq] + movaps [dstq + lenq + mmsize], m0 + movaps [dstq + lenq], m1 + add src1q, 2*mmsize + sub lenq, 2*mmsize + jge .loop + REP_RET +%endmacro + +INIT_XMM sse +VECTOR_FMUL_REVERSE +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +VECTOR_FMUL_REVERSE +%endif +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +VECTOR_FMUL_REVERSE +%endif + +; float scalarproduct_float_sse(const float *v1, const float *v2, int len) +INIT_XMM sse +cglobal scalarproduct_float, 3,3,2, v1, v2, offset + shl offsetd, 2 + add v1q, offsetq + add v2q, offsetq + neg offsetq + xorps xmm0, xmm0 +.loop: + movaps xmm1, [v1q+offsetq] + mulps xmm1, [v2q+offsetq] + addps xmm0, xmm1 + add offsetq, 16 + js .loop + movhlps xmm1, xmm0 + addps xmm0, xmm1 + movss xmm1, xmm0 + shufps xmm0, xmm0, 1 + addss xmm0, xmm1 +%if ARCH_X86_64 == 0 + movss r0m, xmm0 + fld dword r0m +%endif + RET + +;----------------------------------------------------------------------------- +; void ff_butterflies_float(float *src0, float *src1, int len); +;----------------------------------------------------------------------------- +INIT_XMM sse +cglobal butterflies_float, 3,3,3, src0, src1, len + shl lend, 2 + add src0q, lenq + add src1q, lenq + neg lenq +.loop: + mova m0, [src0q + lenq] + mova m1, [src1q + lenq] + subps m2, m0, m1 + addps m0, m0, m1 + mova [src1q + lenq], m2 + mova [src0q + lenq], m0 + add lenq, mmsize + jl .loop + REP_RET diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/imgutils.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/imgutils.asm new file mode 100644 index 0000000000..3cca56cdca --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/imgutils.asm @@ -0,0 +1,53 @@ +;***************************************************************************** +;* Copyright 2016 Anton Khirnov +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION .text + +INIT_XMM sse4 +cglobal image_copy_plane_uc_from, 6, 7, 4, dst, dst_linesize, src, src_linesize, bw, height, rowpos + add dstq, bwq + add srcq, bwq + neg bwq + +.row_start: + mov rowposq, bwq + +.loop: + movntdqa m0, [srcq + rowposq + 0 * mmsize] + movntdqa m1, [srcq + rowposq + 1 * mmsize] + movntdqa m2, [srcq + rowposq + 2 * mmsize] + movntdqa m3, [srcq + rowposq + 3 * mmsize] + + mova [dstq + rowposq + 0 * mmsize], m0 + mova [dstq + rowposq + 1 * mmsize], m1 + mova [dstq + rowposq + 2 * mmsize], m2 + mova [dstq + rowposq + 3 * mmsize], m3 + + add rowposq, 4 * mmsize + jnz .loop + + add srcq, src_linesizeq + add dstq, dst_linesizeq + dec heightd + jnz .row_start + + RET diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/lls.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/lls.asm new file mode 100644 index 0000000000..317fba6fca --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/lls.asm @@ -0,0 +1,290 @@ +;****************************************************************************** +;* linear least squares model +;* +;* Copyright (c) 2013 Loren Merritt +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "x86util.asm" + +SECTION .text + +%define MAX_VARS 32 +%define MAX_VARS_ALIGN (MAX_VARS+4) +%define COVAR_STRIDE MAX_VARS_ALIGN*8 +%define COVAR(x,y) [covarq + (x)*8 + (y)*COVAR_STRIDE] + +struc LLSModel + .covariance: resq MAX_VARS_ALIGN*MAX_VARS_ALIGN + .coeff: resq MAX_VARS*MAX_VARS + .variance: resq MAX_VARS + .indep_count: resd 1 +endstruc + +%macro ADDPD_MEM 2 +%if cpuflag(avx) + vaddpd %2, %2, %1 +%else + addpd %2, %1 +%endif + mova %1, %2 +%endmacro + +INIT_XMM sse2 +%define movdqa movaps +cglobal update_lls, 2,5,8, ctx, var, i, j, covar2 + %define covarq ctxq + mov id, [ctxq + LLSModel.indep_count] + lea varq, [varq + iq*8] + neg iq + mov covar2q, covarq +.loopi: + ; Compute all 3 pairwise products of a 2x2 block that lies on the diagonal + mova m1, [varq + iq*8] + mova m3, [varq + iq*8 + 16] + pshufd m4, m1, q1010 + pshufd m5, m1, q3232 + pshufd m6, m3, q1010 + pshufd m7, m3, q3232 + mulpd m0, m1, m4 + mulpd m1, m1, m5 + lea covarq, [covar2q + 16] + ADDPD_MEM COVAR(-2,0), m0 + ADDPD_MEM COVAR(-2,1), m1 + lea jq, [iq + 2] + cmp jd, -2 + jg .skip4x4 +.loop4x4: + ; Compute all 16 pairwise products of a 4x4 block + mulpd m0, m4, m3 + mulpd m1, m5, m3 + mulpd m2, m6, m3 + mulpd m3, m3, m7 + ADDPD_MEM COVAR(0,0), m0 + ADDPD_MEM COVAR(0,1), m1 + ADDPD_MEM COVAR(0,2), m2 + ADDPD_MEM COVAR(0,3), m3 + mova m3, [varq + jq*8 + 16] + mulpd m0, m4, m3 + mulpd m1, m5, m3 + mulpd m2, m6, m3 + mulpd m3, m3, m7 + ADDPD_MEM COVAR(2,0), m0 + ADDPD_MEM COVAR(2,1), m1 + ADDPD_MEM COVAR(2,2), m2 + ADDPD_MEM COVAR(2,3), m3 + mova m3, [varq + jq*8 + 32] + add covarq, 32 + add jq, 4 + cmp jd, -2 + jle .loop4x4 +.skip4x4: + test jd, jd + jg .skip2x4 + mulpd m4, m3 + mulpd m5, m3 + mulpd m6, m3 + mulpd m7, m3 + ADDPD_MEM COVAR(0,0), m4 + ADDPD_MEM COVAR(0,1), m5 + ADDPD_MEM COVAR(0,2), m6 + ADDPD_MEM COVAR(0,3), m7 +.skip2x4: + add iq, 4 + add covar2q, 4*COVAR_STRIDE+32 + cmp id, -2 + jle .loopi + test id, id + jg .ret + mov jq, iq + %define covarq covar2q +.loop2x1: + movsd m0, [varq + iq*8] + movlhps m0, m0 + mulpd m0, [varq + jq*8] + ADDPD_MEM COVAR(0,0), m0 + inc iq + add covarq, COVAR_STRIDE + test id, id + jle .loop2x1 +.ret: + REP_RET + +%macro UPDATE_LLS 0 +cglobal update_lls, 3,6,8, ctx, var, count, i, j, count2 + %define covarq ctxq + mov countd, [ctxq + LLSModel.indep_count] + lea count2d, [countq-2] + xor id, id +.loopi: + ; Compute all 10 pairwise products of a 4x4 block that lies on the diagonal + mova ymm1, [varq + iq*8] + vbroadcastsd ymm4, [varq + iq*8] + vbroadcastsd ymm5, [varq + iq*8 + 8] + vbroadcastsd ymm6, [varq + iq*8 + 16] + vbroadcastsd ymm7, [varq + iq*8 + 24] + vextractf128 xmm3, ymm1, 1 +%if cpuflag(fma3) + mova ymm0, COVAR(iq ,0) + mova xmm2, COVAR(iq+2,2) + fmaddpd ymm0, ymm1, ymm4, ymm0 + fmaddpd xmm2, xmm3, xmm6, xmm2 + fmaddpd ymm1, ymm5, ymm1, COVAR(iq ,1) + fmaddpd xmm3, xmm7, xmm3, COVAR(iq+2,3) + mova COVAR(iq ,0), ymm0 + mova COVAR(iq ,1), ymm1 + mova COVAR(iq+2,2), xmm2 + mova COVAR(iq+2,3), xmm3 +%else + vmulpd ymm0, ymm1, ymm4 + vmulpd ymm1, ymm1, ymm5 + vmulpd xmm2, xmm3, xmm6 + vmulpd xmm3, xmm3, xmm7 + ADDPD_MEM COVAR(iq ,0), ymm0 + ADDPD_MEM COVAR(iq ,1), ymm1 + ADDPD_MEM COVAR(iq+2,2), xmm2 + ADDPD_MEM COVAR(iq+2,3), xmm3 +%endif ; cpuflag(fma3) + lea jd, [iq + 4] + cmp jd, count2d + jg .skip4x4 +.loop4x4: + ; Compute all 16 pairwise products of a 4x4 block + mova ymm3, [varq + jq*8] +%if cpuflag(fma3) + mova ymm0, COVAR(jq, 0) + mova ymm1, COVAR(jq, 1) + mova ymm2, COVAR(jq, 2) + fmaddpd ymm0, ymm3, ymm4, ymm0 + fmaddpd ymm1, ymm3, ymm5, ymm1 + fmaddpd ymm2, ymm3, ymm6, ymm2 + fmaddpd ymm3, ymm7, ymm3, COVAR(jq,3) + mova COVAR(jq, 0), ymm0 + mova COVAR(jq, 1), ymm1 + mova COVAR(jq, 2), ymm2 + mova COVAR(jq, 3), ymm3 +%else + vmulpd ymm0, ymm3, ymm4 + vmulpd ymm1, ymm3, ymm5 + vmulpd ymm2, ymm3, ymm6 + vmulpd ymm3, ymm3, ymm7 + ADDPD_MEM COVAR(jq,0), ymm0 + ADDPD_MEM COVAR(jq,1), ymm1 + ADDPD_MEM COVAR(jq,2), ymm2 + ADDPD_MEM COVAR(jq,3), ymm3 +%endif ; cpuflag(fma3) + add jd, 4 + cmp jd, count2d + jle .loop4x4 +.skip4x4: + cmp jd, countd + jg .skip2x4 + mova xmm3, [varq + jq*8] +%if cpuflag(fma3) + mova xmm0, COVAR(jq, 0) + mova xmm1, COVAR(jq, 1) + mova xmm2, COVAR(jq, 2) + fmaddpd xmm0, xmm3, xmm4, xmm0 + fmaddpd xmm1, xmm3, xmm5, xmm1 + fmaddpd xmm2, xmm3, xmm6, xmm2 + fmaddpd xmm3, xmm7, xmm3, COVAR(jq,3) + mova COVAR(jq, 0), xmm0 + mova COVAR(jq, 1), xmm1 + mova COVAR(jq, 2), xmm2 + mova COVAR(jq, 3), xmm3 +%else + vmulpd xmm0, xmm3, xmm4 + vmulpd xmm1, xmm3, xmm5 + vmulpd xmm2, xmm3, xmm6 + vmulpd xmm3, xmm3, xmm7 + ADDPD_MEM COVAR(jq,0), xmm0 + ADDPD_MEM COVAR(jq,1), xmm1 + ADDPD_MEM COVAR(jq,2), xmm2 + ADDPD_MEM COVAR(jq,3), xmm3 +%endif ; cpuflag(fma3) +.skip2x4: + add id, 4 + add covarq, 4*COVAR_STRIDE + cmp id, count2d + jle .loopi + cmp id, countd + jg .ret + mov jd, id +.loop2x1: + vmovddup xmm0, [varq + iq*8] +%if cpuflag(fma3) + mova xmm1, [varq + jq*8] + fmaddpd xmm0, xmm1, xmm0, COVAR(jq,0) + mova COVAR(jq,0), xmm0 +%else + vmulpd xmm0, [varq + jq*8] + ADDPD_MEM COVAR(jq,0), xmm0 +%endif ; cpuflag(fma3) + inc id + add covarq, COVAR_STRIDE + cmp id, countd + jle .loop2x1 +.ret: + REP_RET +%endmacro ; UPDATE_LLS + +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +UPDATE_LLS +%endif +%if HAVE_FMA3_EXTERNAL +INIT_YMM fma3 +UPDATE_LLS +%endif + +INIT_XMM sse2 +cglobal evaluate_lls, 3,4,2, ctx, var, order, i + ; This function is often called on the same buffer as update_lls, but with + ; an offset. They can't both be aligned. + ; Load halves rather than movu to avoid store-forwarding stalls, since the + ; input was initialized immediately prior to this function using scalar math. + %define coefsq ctxq + mov id, orderd + imul orderd, MAX_VARS + lea coefsq, [ctxq + LLSModel.coeff + orderq*8] + movsd m0, [varq] + movhpd m0, [varq + 8] + mulpd m0, [coefsq] + lea coefsq, [coefsq + iq*8] + lea varq, [varq + iq*8] + neg iq + add iq, 2 +.loop: + movsd m1, [varq + iq*8] + movhpd m1, [varq + iq*8 + 8] + mulpd m1, [coefsq + iq*8] + addpd m0, m1 + add iq, 2 + jl .loop + jg .skip1 + movsd m1, [varq + iq*8] + mulsd m1, [coefsq + iq*8] + addpd m0, m1 +.skip1: + movhlps m1, m0 + addsd m0, m1 +%if ARCH_X86_32 + movsd r0m, m0 + fld qword r0m +%endif + RET diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/x86inc.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/x86inc.asm new file mode 100644 index 0000000000..5044ee86f0 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/x86inc.asm @@ -0,0 +1,1701 @@ +;***************************************************************************** +;* x86inc.asm: x264asm abstraction layer +;***************************************************************************** +;* Copyright (C) 2005-2018 x264 project +;* +;* Authors: Loren Merritt +;* Henrik Gramner +;* Anton Mitrofanov +;* Fiona Glaser +;* +;* 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 is a header file for the x264ASM assembly language, which uses +; NASM/YASM syntax combined with a large number of macros to provide easy +; abstraction between different calling conventions (x86_32, win64, linux64). +; It also has various other useful features to simplify writing the kind of +; DSP functions that are most often used in x264. + +; Unlike the rest of x264, this file is available under an ISC license, as it +; has significant usefulness outside of x264 and we want it to be available +; to the largest audience possible. Of course, if you modify it for your own +; purposes to add a new feature, we strongly encourage contributing a patch +; as this feature might be useful for others as well. Send patches or ideas +; to x264-devel@videolan.org . + +%ifndef private_prefix + %define private_prefix x264 +%endif + +%ifndef public_prefix + %define public_prefix private_prefix +%endif + +%if HAVE_ALIGNED_STACK + %define STACK_ALIGNMENT 16 +%endif +%ifndef STACK_ALIGNMENT + %if ARCH_X86_64 + %define STACK_ALIGNMENT 16 + %else + %define STACK_ALIGNMENT 4 + %endif +%endif + +%define WIN64 0 +%define UNIX64 0 +%if ARCH_X86_64 + %ifidn __OUTPUT_FORMAT__,win32 + %define WIN64 1 + %elifidn __OUTPUT_FORMAT__,win64 + %define WIN64 1 + %elifidn __OUTPUT_FORMAT__,x64 + %define WIN64 1 + %else + %define UNIX64 1 + %endif +%endif + +%define FORMAT_ELF 0 +%ifidn __OUTPUT_FORMAT__,elf + %define FORMAT_ELF 1 +%elifidn __OUTPUT_FORMAT__,elf32 + %define FORMAT_ELF 1 +%elifidn __OUTPUT_FORMAT__,elf64 + %define FORMAT_ELF 1 +%endif + +%ifdef PREFIX + %define mangle(x) _ %+ x +%else + %define mangle(x) x +%endif + +; aout does not support align= +; NOTE: This section is out of sync with x264, in order to +; keep supporting OS/2. +%macro SECTION_RODATA 0-1 16 + %ifidn __OUTPUT_FORMAT__,aout + SECTION .text + %elifidn __OUTPUT_FORMAT__,coff + SECTION .text + %elifidn __OUTPUT_FORMAT__,win32 + SECTION .rdata align=%1 + %elif WIN64 + SECTION .rdata align=%1 + %else + SECTION .rodata align=%1 + %endif +%endmacro + +%if WIN64 + %define PIC +%elif ARCH_X86_64 == 0 +; x86_32 doesn't require PIC. +; Some distros prefer shared objects to be PIC, but nothing breaks if +; the code contains a few textrels, so we'll skip that complexity. + %undef PIC +%endif +%ifdef PIC + default rel +%endif + +%macro CPUNOP 1 + %if HAVE_CPUNOP + CPU %1 + %endif +%endmacro + +; Macros to eliminate most code duplication between x86_32 and x86_64: +; Currently this works only for leaf functions which load all their arguments +; into registers at the start, and make no other use of the stack. Luckily that +; covers most of x264's asm. + +; PROLOGUE: +; %1 = number of arguments. loads them from stack if needed. +; %2 = number of registers used. pushes callee-saved regs if needed. +; %3 = number of xmm registers used. pushes callee-saved xmm regs if needed. +; %4 = (optional) stack size to be allocated. The stack will be aligned before +; allocating the specified stack size. If the required stack alignment is +; larger than the known stack alignment the stack will be manually aligned +; and an extra register will be allocated to hold the original stack +; pointer (to not invalidate r0m etc.). To prevent the use of an extra +; register as stack pointer, request a negative stack size. +; %4+/%5+ = list of names to define to registers +; PROLOGUE can also be invoked by adding the same options to cglobal + +; e.g. +; cglobal foo, 2,3,7,0x40, dst, src, tmp +; declares a function (foo) that automatically loads two arguments (dst and +; src) into registers, uses one additional register (tmp) plus 7 vector +; registers (m0-m6) and allocates 0x40 bytes of stack space. + +; TODO Some functions can use some args directly from the stack. If they're the +; last args then you can just not declare them, but if they're in the middle +; we need more flexible macro. + +; RET: +; Pops anything that was pushed by PROLOGUE, and returns. + +; REP_RET: +; Use this instead of RET if it's a branch target. + +; registers: +; rN and rNq are the native-size register holding function argument N +; rNd, rNw, rNb are dword, word, and byte size +; rNh is the high 8 bits of the word size +; rNm is the original location of arg N (a register or on the stack), dword +; rNmp is native size + +%macro DECLARE_REG 2-3 + %define r%1q %2 + %define r%1d %2d + %define r%1w %2w + %define r%1b %2b + %define r%1h %2h + %define %2q %2 + %if %0 == 2 + %define r%1m %2d + %define r%1mp %2 + %elif ARCH_X86_64 ; memory + %define r%1m [rstk + stack_offset + %3] + %define r%1mp qword r %+ %1 %+ m + %else + %define r%1m [rstk + stack_offset + %3] + %define r%1mp dword r %+ %1 %+ m + %endif + %define r%1 %2 +%endmacro + +%macro DECLARE_REG_SIZE 3 + %define r%1q r%1 + %define e%1q r%1 + %define r%1d e%1 + %define e%1d e%1 + %define r%1w %1 + %define e%1w %1 + %define r%1h %3 + %define e%1h %3 + %define r%1b %2 + %define e%1b %2 + %if ARCH_X86_64 == 0 + %define r%1 e%1 + %endif +%endmacro + +DECLARE_REG_SIZE ax, al, ah +DECLARE_REG_SIZE bx, bl, bh +DECLARE_REG_SIZE cx, cl, ch +DECLARE_REG_SIZE dx, dl, dh +DECLARE_REG_SIZE si, sil, null +DECLARE_REG_SIZE di, dil, null +DECLARE_REG_SIZE bp, bpl, null + +; t# defines for when per-arch register allocation is more complex than just function arguments + +%macro DECLARE_REG_TMP 1-* + %assign %%i 0 + %rep %0 + CAT_XDEFINE t, %%i, r%1 + %assign %%i %%i+1 + %rotate 1 + %endrep +%endmacro + +%macro DECLARE_REG_TMP_SIZE 0-* + %rep %0 + %define t%1q t%1 %+ q + %define t%1d t%1 %+ d + %define t%1w t%1 %+ w + %define t%1h t%1 %+ h + %define t%1b t%1 %+ b + %rotate 1 + %endrep +%endmacro + +DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 + +%if ARCH_X86_64 + %define gprsize 8 +%else + %define gprsize 4 +%endif + +%macro PUSH 1 + push %1 + %ifidn rstk, rsp + %assign stack_offset stack_offset+gprsize + %endif +%endmacro + +%macro POP 1 + pop %1 + %ifidn rstk, rsp + %assign stack_offset stack_offset-gprsize + %endif +%endmacro + +%macro PUSH_IF_USED 1-* + %rep %0 + %if %1 < regs_used + PUSH r%1 + %endif + %rotate 1 + %endrep +%endmacro + +%macro POP_IF_USED 1-* + %rep %0 + %if %1 < regs_used + pop r%1 + %endif + %rotate 1 + %endrep +%endmacro + +%macro LOAD_IF_USED 1-* + %rep %0 + %if %1 < num_args + mov r%1, r %+ %1 %+ mp + %endif + %rotate 1 + %endrep +%endmacro + +%macro SUB 2 + sub %1, %2 + %ifidn %1, rstk + %assign stack_offset stack_offset+(%2) + %endif +%endmacro + +%macro ADD 2 + add %1, %2 + %ifidn %1, rstk + %assign stack_offset stack_offset-(%2) + %endif +%endmacro + +%macro movifnidn 2 + %ifnidn %1, %2 + mov %1, %2 + %endif +%endmacro + +%macro movsxdifnidn 2 + %ifnidn %1, %2 + movsxd %1, %2 + %endif +%endmacro + +%macro ASSERT 1 + %if (%1) == 0 + %error assertion ``%1'' failed + %endif +%endmacro + +%macro DEFINE_ARGS 0-* + %ifdef n_arg_names + %assign %%i 0 + %rep n_arg_names + CAT_UNDEF arg_name %+ %%i, q + CAT_UNDEF arg_name %+ %%i, d + CAT_UNDEF arg_name %+ %%i, w + CAT_UNDEF arg_name %+ %%i, h + CAT_UNDEF arg_name %+ %%i, b + CAT_UNDEF arg_name %+ %%i, m + CAT_UNDEF arg_name %+ %%i, mp + CAT_UNDEF arg_name, %%i + %assign %%i %%i+1 + %endrep + %endif + + %xdefine %%stack_offset stack_offset + %undef stack_offset ; so that the current value of stack_offset doesn't get baked in by xdefine + %assign %%i 0 + %rep %0 + %xdefine %1q r %+ %%i %+ q + %xdefine %1d r %+ %%i %+ d + %xdefine %1w r %+ %%i %+ w + %xdefine %1h r %+ %%i %+ h + %xdefine %1b r %+ %%i %+ b + %xdefine %1m r %+ %%i %+ m + %xdefine %1mp r %+ %%i %+ mp + CAT_XDEFINE arg_name, %%i, %1 + %assign %%i %%i+1 + %rotate 1 + %endrep + %xdefine stack_offset %%stack_offset + %assign n_arg_names %0 +%endmacro + +%define required_stack_alignment ((mmsize + 15) & ~15) +%define vzeroupper_required (mmsize > 16 && (ARCH_X86_64 == 0 || xmm_regs_used > 16 || notcpuflag(avx512))) +%define high_mm_regs (16*cpuflag(avx512)) + +%macro ALLOC_STACK 1-2 0 ; stack_size, n_xmm_regs (for win64 only) + %ifnum %1 + %if %1 != 0 + %assign %%pad 0 + %assign stack_size %1 + %if stack_size < 0 + %assign stack_size -stack_size + %endif + %if WIN64 + %assign %%pad %%pad + 32 ; shadow space + %if mmsize != 8 + %assign xmm_regs_used %2 + %if xmm_regs_used > 8 + %assign %%pad %%pad + (xmm_regs_used-8)*16 ; callee-saved xmm registers + %endif + %endif + %endif + %if required_stack_alignment <= STACK_ALIGNMENT + ; maintain the current stack alignment + %assign stack_size_padded stack_size + %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1)) + SUB rsp, stack_size_padded + %else + %assign %%reg_num (regs_used - 1) + %xdefine rstk r %+ %%reg_num + ; align stack, and save original stack location directly above + ; it, i.e. in [rsp+stack_size_padded], so we can restore the + ; stack in a single instruction (i.e. mov rsp, rstk or mov + ; rsp, [rsp+stack_size_padded]) + %if %1 < 0 ; need to store rsp on stack + %xdefine rstkm [rsp + stack_size + %%pad] + %assign %%pad %%pad + gprsize + %else ; can keep rsp in rstk during whole function + %xdefine rstkm rstk + %endif + %assign stack_size_padded stack_size + ((%%pad + required_stack_alignment-1) & ~(required_stack_alignment-1)) + mov rstk, rsp + and rsp, ~(required_stack_alignment-1) + sub rsp, stack_size_padded + movifnidn rstkm, rstk + %endif + WIN64_PUSH_XMM + %endif + %endif +%endmacro + +%macro SETUP_STACK_POINTER 1 + %ifnum %1 + %if %1 != 0 && required_stack_alignment > STACK_ALIGNMENT + %if %1 > 0 + ; Reserve an additional register for storing the original stack pointer, but avoid using + ; eax/rax for this purpose since it can potentially get overwritten as a return value. + %assign regs_used (regs_used + 1) + %if ARCH_X86_64 && regs_used == 7 + %assign regs_used 8 + %elif ARCH_X86_64 == 0 && regs_used == 1 + %assign regs_used 2 + %endif + %endif + %if ARCH_X86_64 && regs_used < 5 + UNIX64 * 3 + ; Ensure that we don't clobber any registers containing arguments. For UNIX64 we also preserve r6 (rax) + ; since it's used as a hidden argument in vararg functions to specify the number of vector registers used. + %assign regs_used 5 + UNIX64 * 3 + %endif + %endif + %endif +%endmacro + +%macro DEFINE_ARGS_INTERNAL 3+ + %ifnum %2 + DEFINE_ARGS %3 + %elif %1 == 4 + DEFINE_ARGS %2 + %elif %1 > 4 + DEFINE_ARGS %2, %3 + %endif +%endmacro + +%if WIN64 ; Windows x64 ;================================================= + +DECLARE_REG 0, rcx +DECLARE_REG 1, rdx +DECLARE_REG 2, R8 +DECLARE_REG 3, R9 +DECLARE_REG 4, R10, 40 +DECLARE_REG 5, R11, 48 +DECLARE_REG 6, rax, 56 +DECLARE_REG 7, rdi, 64 +DECLARE_REG 8, rsi, 72 +DECLARE_REG 9, rbx, 80 +DECLARE_REG 10, rbp, 88 +DECLARE_REG 11, R14, 96 +DECLARE_REG 12, R15, 104 +DECLARE_REG 13, R12, 112 +DECLARE_REG 14, R13, 120 + +%macro PROLOGUE 2-5+ 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names... + %assign num_args %1 + %assign regs_used %2 + ASSERT regs_used >= num_args + SETUP_STACK_POINTER %4 + ASSERT regs_used <= 15 + PUSH_IF_USED 7, 8, 9, 10, 11, 12, 13, 14 + ALLOC_STACK %4, %3 + %if mmsize != 8 && stack_size == 0 + WIN64_SPILL_XMM %3 + %endif + LOAD_IF_USED 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 + DEFINE_ARGS_INTERNAL %0, %4, %5 +%endmacro + +%macro WIN64_PUSH_XMM 0 + ; Use the shadow space to store XMM6 and XMM7, the rest needs stack space allocated. + %if xmm_regs_used > 6 + high_mm_regs + movaps [rstk + stack_offset + 8], xmm6 + %endif + %if xmm_regs_used > 7 + high_mm_regs + movaps [rstk + stack_offset + 24], xmm7 + %endif + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 + %assign %%i 8 + %rep %%xmm_regs_on_stack + movaps [rsp + (%%i-8)*16 + stack_size + 32], xmm %+ %%i + %assign %%i %%i+1 + %endrep + %endif +%endmacro + +%macro WIN64_SPILL_XMM 1 + %assign xmm_regs_used %1 + ASSERT xmm_regs_used <= 16 + high_mm_regs + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 + ; Allocate stack space for callee-saved xmm registers plus shadow space and align the stack. + %assign %%pad %%xmm_regs_on_stack*16 + 32 + %assign stack_size_padded %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1)) + SUB rsp, stack_size_padded + %endif + WIN64_PUSH_XMM +%endmacro + +%macro WIN64_RESTORE_XMM_INTERNAL 0 + %assign %%pad_size 0 + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 + %assign %%i xmm_regs_used - high_mm_regs + %rep %%xmm_regs_on_stack + %assign %%i %%i-1 + movaps xmm %+ %%i, [rsp + (%%i-8)*16 + stack_size + 32] + %endrep + %endif + %if stack_size_padded > 0 + %if stack_size > 0 && required_stack_alignment > STACK_ALIGNMENT + mov rsp, rstkm + %else + add rsp, stack_size_padded + %assign %%pad_size stack_size_padded + %endif + %endif + %if xmm_regs_used > 7 + high_mm_regs + movaps xmm7, [rsp + stack_offset - %%pad_size + 24] + %endif + %if xmm_regs_used > 6 + high_mm_regs + movaps xmm6, [rsp + stack_offset - %%pad_size + 8] + %endif +%endmacro + +%macro WIN64_RESTORE_XMM 0 + WIN64_RESTORE_XMM_INTERNAL + %assign stack_offset (stack_offset-stack_size_padded) + %assign stack_size_padded 0 + %assign xmm_regs_used 0 +%endmacro + +%define has_epilogue regs_used > 7 || stack_size > 0 || vzeroupper_required || xmm_regs_used > 6+high_mm_regs + +%macro RET 0 + WIN64_RESTORE_XMM_INTERNAL + POP_IF_USED 14, 13, 12, 11, 10, 9, 8, 7 + %if vzeroupper_required + vzeroupper + %endif + AUTO_REP_RET +%endmacro + +%elif ARCH_X86_64 ; *nix x64 ;============================================= + +DECLARE_REG 0, rdi +DECLARE_REG 1, rsi +DECLARE_REG 2, rdx +DECLARE_REG 3, rcx +DECLARE_REG 4, R8 +DECLARE_REG 5, R9 +DECLARE_REG 6, rax, 8 +DECLARE_REG 7, R10, 16 +DECLARE_REG 8, R11, 24 +DECLARE_REG 9, rbx, 32 +DECLARE_REG 10, rbp, 40 +DECLARE_REG 11, R14, 48 +DECLARE_REG 12, R15, 56 +DECLARE_REG 13, R12, 64 +DECLARE_REG 14, R13, 72 + +%macro PROLOGUE 2-5+ 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names... + %assign num_args %1 + %assign regs_used %2 + %assign xmm_regs_used %3 + ASSERT regs_used >= num_args + SETUP_STACK_POINTER %4 + ASSERT regs_used <= 15 + PUSH_IF_USED 9, 10, 11, 12, 13, 14 + ALLOC_STACK %4 + LOAD_IF_USED 6, 7, 8, 9, 10, 11, 12, 13, 14 + DEFINE_ARGS_INTERNAL %0, %4, %5 +%endmacro + +%define has_epilogue regs_used > 9 || stack_size > 0 || vzeroupper_required + +%macro RET 0 + %if stack_size_padded > 0 + %if required_stack_alignment > STACK_ALIGNMENT + mov rsp, rstkm + %else + add rsp, stack_size_padded + %endif + %endif + POP_IF_USED 14, 13, 12, 11, 10, 9 + %if vzeroupper_required + vzeroupper + %endif + AUTO_REP_RET +%endmacro + +%else ; X86_32 ;============================================================== + +DECLARE_REG 0, eax, 4 +DECLARE_REG 1, ecx, 8 +DECLARE_REG 2, edx, 12 +DECLARE_REG 3, ebx, 16 +DECLARE_REG 4, esi, 20 +DECLARE_REG 5, edi, 24 +DECLARE_REG 6, ebp, 28 +%define rsp esp + +%macro DECLARE_ARG 1-* + %rep %0 + %define r%1m [rstk + stack_offset + 4*%1 + 4] + %define r%1mp dword r%1m + %rotate 1 + %endrep +%endmacro + +DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 + +%macro PROLOGUE 2-5+ ; #args, #regs, #xmm_regs, [stack_size,] arg_names... + %assign num_args %1 + %assign regs_used %2 + ASSERT regs_used >= num_args + %if num_args > 7 + %assign num_args 7 + %endif + %if regs_used > 7 + %assign regs_used 7 + %endif + SETUP_STACK_POINTER %4 + ASSERT regs_used <= 7 + PUSH_IF_USED 3, 4, 5, 6 + ALLOC_STACK %4 + LOAD_IF_USED 0, 1, 2, 3, 4, 5, 6 + DEFINE_ARGS_INTERNAL %0, %4, %5 +%endmacro + +%define has_epilogue regs_used > 3 || stack_size > 0 || vzeroupper_required + +%macro RET 0 + %if stack_size_padded > 0 + %if required_stack_alignment > STACK_ALIGNMENT + mov rsp, rstkm + %else + add rsp, stack_size_padded + %endif + %endif + POP_IF_USED 6, 5, 4, 3 + %if vzeroupper_required + vzeroupper + %endif + AUTO_REP_RET +%endmacro + +%endif ;====================================================================== + +%if WIN64 == 0 + %macro WIN64_SPILL_XMM 1 + %endmacro + %macro WIN64_RESTORE_XMM 0 + %endmacro + %macro WIN64_PUSH_XMM 0 + %endmacro +%endif + +; On AMD cpus <=K10, an ordinary ret is slow if it immediately follows either +; a branch or a branch target. So switch to a 2-byte form of ret in that case. +; We can automatically detect "follows a branch", but not a branch target. +; (SSSE3 is a sufficient condition to know that your cpu doesn't have this problem.) +%macro REP_RET 0 + %if has_epilogue || cpuflag(ssse3) + RET + %else + rep ret + %endif + annotate_function_size +%endmacro + +%define last_branch_adr $$ +%macro AUTO_REP_RET 0 + %if notcpuflag(ssse3) + times ((last_branch_adr-$)>>31)+1 rep ; times 1 iff $ == last_branch_adr. + %endif + ret + annotate_function_size +%endmacro + +%macro BRANCH_INSTR 0-* + %rep %0 + %macro %1 1-2 %1 + %2 %1 + %if notcpuflag(ssse3) + %%branch_instr equ $ + %xdefine last_branch_adr %%branch_instr + %endif + %endmacro + %rotate 1 + %endrep +%endmacro + +BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, jna, jnae, jb, jbe, jnb, jnbe, jc, jnc, js, jns, jo, jno, jp, jnp + +%macro TAIL_CALL 2 ; callee, is_nonadjacent + %if has_epilogue + call %1 + RET + %elif %2 + jmp %1 + %endif + annotate_function_size +%endmacro + +;============================================================================= +; arch-independent part +;============================================================================= + +%assign function_align 16 + +; Begin a function. +; Applies any symbol mangling needed for C linkage, and sets up a define such that +; subsequent uses of the function name automatically refer to the mangled version. +; Appends cpuflags to the function name if cpuflags has been specified. +; The "" empty default parameter is a workaround for nasm, which fails if SUFFIX +; is empty and we call cglobal_internal with just %1 %+ SUFFIX (without %2). +%macro cglobal 1-2+ "" ; name, [PROLOGUE args] + cglobal_internal 1, %1 %+ SUFFIX, %2 +%endmacro +%macro cvisible 1-2+ "" ; name, [PROLOGUE args] + cglobal_internal 0, %1 %+ SUFFIX, %2 +%endmacro +%macro cglobal_internal 2-3+ + annotate_function_size + %if %1 + %xdefine %%FUNCTION_PREFIX private_prefix + %xdefine %%VISIBILITY hidden + %else + %xdefine %%FUNCTION_PREFIX public_prefix + %xdefine %%VISIBILITY + %endif + %ifndef cglobaled_%2 + %xdefine %2 mangle(%%FUNCTION_PREFIX %+ _ %+ %2) + %xdefine %2.skip_prologue %2 %+ .skip_prologue + CAT_XDEFINE cglobaled_, %2, 1 + %endif + %xdefine current_function %2 + %xdefine current_function_section __SECT__ + %if FORMAT_ELF + global %2:function %%VISIBILITY + %else + global %2 + %endif + align function_align + %2: + RESET_MM_PERMUTATION ; needed for x86-64, also makes disassembly somewhat nicer + %xdefine rstk rsp ; copy of the original stack pointer, used when greater alignment than the known stack alignment is required + %assign stack_offset 0 ; stack pointer offset relative to the return address + %assign stack_size 0 ; amount of stack space that can be freely used inside a function + %assign stack_size_padded 0 ; total amount of allocated stack space, including space for callee-saved xmm registers on WIN64 and alignment padding + %assign xmm_regs_used 0 ; number of XMM registers requested, used for dealing with callee-saved registers on WIN64 and vzeroupper + %ifnidn %3, "" + PROLOGUE %3 + %endif +%endmacro + +; Create a global symbol from a local label with the correct name mangling and type +%macro cglobal_label 1 + %if FORMAT_ELF + global current_function %+ %1:function hidden + %else + global current_function %+ %1 + %endif + %1: +%endmacro + +%macro cextern 1 + %xdefine %1 mangle(private_prefix %+ _ %+ %1) + CAT_XDEFINE cglobaled_, %1, 1 + extern %1 +%endmacro + +; like cextern, but without the prefix +%macro cextern_naked 1 + %ifdef PREFIX + %xdefine %1 mangle(%1) + %endif + CAT_XDEFINE cglobaled_, %1, 1 + extern %1 +%endmacro + +%macro const 1-2+ + %xdefine %1 mangle(private_prefix %+ _ %+ %1) + %if FORMAT_ELF + global %1:data hidden + %else + global %1 + %endif + %1: %2 +%endmacro + +; This is needed for ELF, otherwise the GNU linker assumes the stack is executable by default. +%if FORMAT_ELF + [SECTION .note.GNU-stack noalloc noexec nowrite progbits] +%endif + +; Tell debuggers how large the function was. +; This may be invoked multiple times per function; we rely on later instances overriding earlier ones. +; This is invoked by RET and similar macros, and also cglobal does it for the previous function, +; but if the last function in a source file doesn't use any of the standard macros for its epilogue, +; then its size might be unspecified. +%macro annotate_function_size 0 + %ifdef __YASM_VER__ + %ifdef current_function + %if FORMAT_ELF + current_function_section + %%ecf equ $ + size current_function %%ecf - current_function + __SECT__ + %endif + %endif + %endif +%endmacro + +; cpuflags + +%assign cpuflags_mmx (1<<0) +%assign cpuflags_mmx2 (1<<1) | cpuflags_mmx +%assign cpuflags_3dnow (1<<2) | cpuflags_mmx +%assign cpuflags_3dnowext (1<<3) | cpuflags_3dnow +%assign cpuflags_sse (1<<4) | cpuflags_mmx2 +%assign cpuflags_sse2 (1<<5) | cpuflags_sse +%assign cpuflags_sse2slow (1<<6) | cpuflags_sse2 +%assign cpuflags_lzcnt (1<<7) | cpuflags_sse2 +%assign cpuflags_sse3 (1<<8) | cpuflags_sse2 +%assign cpuflags_ssse3 (1<<9) | cpuflags_sse3 +%assign cpuflags_sse4 (1<<10)| cpuflags_ssse3 +%assign cpuflags_sse42 (1<<11)| cpuflags_sse4 +%assign cpuflags_aesni (1<<12)| cpuflags_sse42 +%assign cpuflags_avx (1<<13)| cpuflags_sse42 +%assign cpuflags_xop (1<<14)| cpuflags_avx +%assign cpuflags_fma4 (1<<15)| cpuflags_avx +%assign cpuflags_fma3 (1<<16)| cpuflags_avx +%assign cpuflags_bmi1 (1<<17)| cpuflags_avx|cpuflags_lzcnt +%assign cpuflags_bmi2 (1<<18)| cpuflags_bmi1 +%assign cpuflags_avx2 (1<<19)| cpuflags_fma3|cpuflags_bmi2 +%assign cpuflags_avx512 (1<<20)| cpuflags_avx2 ; F, CD, BW, DQ, VL + +%assign cpuflags_cache32 (1<<21) +%assign cpuflags_cache64 (1<<22) +%assign cpuflags_aligned (1<<23) ; not a cpu feature, but a function variant +%assign cpuflags_atom (1<<24) + +; Returns a boolean value expressing whether or not the specified cpuflag is enabled. +%define cpuflag(x) (((((cpuflags & (cpuflags_ %+ x)) ^ (cpuflags_ %+ x)) - 1) >> 31) & 1) +%define notcpuflag(x) (cpuflag(x) ^ 1) + +; Takes an arbitrary number of cpuflags from the above list. +; All subsequent functions (up to the next INIT_CPUFLAGS) is built for the specified cpu. +; You shouldn't need to invoke this macro directly, it's a subroutine for INIT_MMX &co. +%macro INIT_CPUFLAGS 0-* + %xdefine SUFFIX + %undef cpuname + %assign cpuflags 0 + + %if %0 >= 1 + %rep %0 + %ifdef cpuname + %xdefine cpuname cpuname %+ _%1 + %else + %xdefine cpuname %1 + %endif + %assign cpuflags cpuflags | cpuflags_%1 + %rotate 1 + %endrep + %xdefine SUFFIX _ %+ cpuname + + %if cpuflag(avx) + %assign avx_enabled 1 + %endif + %if (mmsize == 16 && notcpuflag(sse2)) || (mmsize == 32 && notcpuflag(avx2)) + %define mova movaps + %define movu movups + %define movnta movntps + %endif + %if cpuflag(aligned) + %define movu mova + %elif cpuflag(sse3) && notcpuflag(ssse3) + %define movu lddqu + %endif + %endif + + %if ARCH_X86_64 || cpuflag(sse2) + CPUNOP amdnop + %else + CPUNOP basicnop + %endif +%endmacro + +; Merge mmx, sse*, and avx* +; m# is a simd register of the currently selected size +; xm# is the corresponding xmm register if mmsize >= 16, otherwise the same as m# +; ym# is the corresponding ymm register if mmsize >= 32, otherwise the same as m# +; zm# is the corresponding zmm register if mmsize >= 64, otherwise the same as m# +; (All 4 remain in sync through SWAP.) + +%macro CAT_XDEFINE 3 + %xdefine %1%2 %3 +%endmacro + +%macro CAT_UNDEF 2 + %undef %1%2 +%endmacro + +%macro DEFINE_MMREGS 1 ; mmtype + %assign %%prev_mmregs 0 + %ifdef num_mmregs + %assign %%prev_mmregs num_mmregs + %endif + + %assign num_mmregs 8 + %if ARCH_X86_64 && mmsize >= 16 + %assign num_mmregs 16 + %if cpuflag(avx512) || mmsize == 64 + %assign num_mmregs 32 + %endif + %endif + + %assign %%i 0 + %rep num_mmregs + CAT_XDEFINE m, %%i, %1 %+ %%i + CAT_XDEFINE nn%1, %%i, %%i + %assign %%i %%i+1 + %endrep + %if %%prev_mmregs > num_mmregs + %rep %%prev_mmregs - num_mmregs + CAT_UNDEF m, %%i + CAT_UNDEF nn %+ mmtype, %%i + %assign %%i %%i+1 + %endrep + %endif + %xdefine mmtype %1 +%endmacro + +; Prefer registers 16-31 over 0-15 to avoid having to use vzeroupper +%macro AVX512_MM_PERMUTATION 0-1 0 ; start_reg + %if ARCH_X86_64 && cpuflag(avx512) + %assign %%i %1 + %rep 16-%1 + %assign %%i_high %%i+16 + SWAP %%i, %%i_high + %assign %%i %%i+1 + %endrep + %endif +%endmacro + +%macro INIT_MMX 0-1+ + %assign avx_enabled 0 + %define RESET_MM_PERMUTATION INIT_MMX %1 + %define mmsize 8 + %define mova movq + %define movu movq + %define movh movd + %define movnta movntq + INIT_CPUFLAGS %1 + DEFINE_MMREGS mm +%endmacro + +%macro INIT_XMM 0-1+ + %assign avx_enabled 0 + %define RESET_MM_PERMUTATION INIT_XMM %1 + %define mmsize 16 + %define mova movdqa + %define movu movdqu + %define movh movq + %define movnta movntdq + INIT_CPUFLAGS %1 + DEFINE_MMREGS xmm + %if WIN64 + AVX512_MM_PERMUTATION 6 ; Swap callee-saved registers with volatile registers + %endif +%endmacro + +%macro INIT_YMM 0-1+ + %assign avx_enabled 1 + %define RESET_MM_PERMUTATION INIT_YMM %1 + %define mmsize 32 + %define mova movdqa + %define movu movdqu + %undef movh + %define movnta movntdq + INIT_CPUFLAGS %1 + DEFINE_MMREGS ymm + AVX512_MM_PERMUTATION +%endmacro + +%macro INIT_ZMM 0-1+ + %assign avx_enabled 1 + %define RESET_MM_PERMUTATION INIT_ZMM %1 + %define mmsize 64 + %define mova movdqa + %define movu movdqu + %undef movh + %define movnta movntdq + INIT_CPUFLAGS %1 + DEFINE_MMREGS zmm + AVX512_MM_PERMUTATION +%endmacro + +INIT_XMM + +%macro DECLARE_MMCAST 1 + %define mmmm%1 mm%1 + %define mmxmm%1 mm%1 + %define mmymm%1 mm%1 + %define mmzmm%1 mm%1 + %define xmmmm%1 mm%1 + %define xmmxmm%1 xmm%1 + %define xmmymm%1 xmm%1 + %define xmmzmm%1 xmm%1 + %define ymmmm%1 mm%1 + %define ymmxmm%1 xmm%1 + %define ymmymm%1 ymm%1 + %define ymmzmm%1 ymm%1 + %define zmmmm%1 mm%1 + %define zmmxmm%1 xmm%1 + %define zmmymm%1 ymm%1 + %define zmmzmm%1 zmm%1 + %define xm%1 xmm %+ m%1 + %define ym%1 ymm %+ m%1 + %define zm%1 zmm %+ m%1 +%endmacro + +%assign i 0 +%rep 32 + DECLARE_MMCAST i + %assign i i+1 +%endrep + +; I often want to use macros that permute their arguments. e.g. there's no +; efficient way to implement butterfly or transpose or dct without swapping some +; arguments. +; +; I would like to not have to manually keep track of the permutations: +; If I insert a permutation in the middle of a function, it should automatically +; change everything that follows. For more complex macros I may also have multiple +; implementations, e.g. the SSE2 and SSSE3 versions may have different permutations. +; +; Hence these macros. Insert a PERMUTE or some SWAPs at the end of a macro that +; permutes its arguments. It's equivalent to exchanging the contents of the +; registers, except that this way you exchange the register names instead, so it +; doesn't cost any cycles. + +%macro PERMUTE 2-* ; takes a list of pairs to swap + %rep %0/2 + %xdefine %%tmp%2 m%2 + %rotate 2 + %endrep + %rep %0/2 + %xdefine m%1 %%tmp%2 + CAT_XDEFINE nn, m%1, %1 + %rotate 2 + %endrep +%endmacro + +%macro SWAP 2+ ; swaps a single chain (sometimes more concise than pairs) + %ifnum %1 ; SWAP 0, 1, ... + SWAP_INTERNAL_NUM %1, %2 + %else ; SWAP m0, m1, ... + SWAP_INTERNAL_NAME %1, %2 + %endif +%endmacro + +%macro SWAP_INTERNAL_NUM 2-* + %rep %0-1 + %xdefine %%tmp m%1 + %xdefine m%1 m%2 + %xdefine m%2 %%tmp + CAT_XDEFINE nn, m%1, %1 + CAT_XDEFINE nn, m%2, %2 + %rotate 1 + %endrep +%endmacro + +%macro SWAP_INTERNAL_NAME 2-* + %xdefine %%args nn %+ %1 + %rep %0-1 + %xdefine %%args %%args, nn %+ %2 + %rotate 1 + %endrep + SWAP_INTERNAL_NUM %%args +%endmacro + +; If SAVE_MM_PERMUTATION is placed at the end of a function, then any later +; calls to that function will automatically load the permutation, so values can +; be returned in mmregs. +%macro SAVE_MM_PERMUTATION 0-1 + %if %0 + %xdefine %%f %1_m + %else + %xdefine %%f current_function %+ _m + %endif + %assign %%i 0 + %rep num_mmregs + CAT_XDEFINE %%f, %%i, m %+ %%i + %assign %%i %%i+1 + %endrep +%endmacro + +%macro LOAD_MM_PERMUTATION 1 ; name to load from + %ifdef %1_m0 + %assign %%i 0 + %rep num_mmregs + CAT_XDEFINE m, %%i, %1_m %+ %%i + CAT_XDEFINE nn, m %+ %%i, %%i + %assign %%i %%i+1 + %endrep + %endif +%endmacro + +; Append cpuflags to the callee's name iff the appended name is known and the plain name isn't +%macro call 1 + %ifid %1 + call_internal %1 %+ SUFFIX, %1 + %else + call %1 + %endif +%endmacro +%macro call_internal 2 + %xdefine %%i %2 + %ifndef cglobaled_%2 + %ifdef cglobaled_%1 + %xdefine %%i %1 + %endif + %endif + call %%i + LOAD_MM_PERMUTATION %%i +%endmacro + +; Substitutions that reduce instruction size but are functionally equivalent +%macro add 2 + %ifnum %2 + %if %2==128 + sub %1, -128 + %else + add %1, %2 + %endif + %else + add %1, %2 + %endif +%endmacro + +%macro sub 2 + %ifnum %2 + %if %2==128 + add %1, -128 + %else + sub %1, %2 + %endif + %else + sub %1, %2 + %endif +%endmacro + +;============================================================================= +; AVX abstraction layer +;============================================================================= + +%assign i 0 +%rep 32 + %if i < 8 + CAT_XDEFINE sizeofmm, i, 8 + CAT_XDEFINE regnumofmm, i, i + %endif + CAT_XDEFINE sizeofxmm, i, 16 + CAT_XDEFINE sizeofymm, i, 32 + CAT_XDEFINE sizeofzmm, i, 64 + CAT_XDEFINE regnumofxmm, i, i + CAT_XDEFINE regnumofymm, i, i + CAT_XDEFINE regnumofzmm, i, i + %assign i i+1 +%endrep +%undef i + +%macro CHECK_AVX_INSTR_EMU 3-* + %xdefine %%opcode %1 + %xdefine %%dst %2 + %rep %0-2 + %ifidn %%dst, %3 + %error non-avx emulation of ``%%opcode'' is not supported + %endif + %rotate 1 + %endrep +%endmacro + +;%1 == instruction +;%2 == minimal instruction set +;%3 == 1 if float, 0 if int +;%4 == 1 if 4-operand emulation, 0 if 3-operand emulation, 255 otherwise (no emulation) +;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not +;%6+: operands +%macro RUN_AVX_INSTR 6-9+ + %ifnum sizeof%7 + %assign __sizeofreg sizeof%7 + %elifnum sizeof%6 + %assign __sizeofreg sizeof%6 + %else + %assign __sizeofreg mmsize + %endif + %assign __emulate_avx 0 + %if avx_enabled && __sizeofreg >= 16 + %xdefine __instr v%1 + %else + %xdefine __instr %1 + %if %0 >= 8+%4 + %assign __emulate_avx 1 + %endif + %endif + %ifnidn %2, fnord + %ifdef cpuname + %if notcpuflag(%2) + %error use of ``%1'' %2 instruction in cpuname function: current_function + %elif cpuflags_%2 < cpuflags_sse && notcpuflag(sse2) && __sizeofreg > 8 + %error use of ``%1'' sse2 instruction in cpuname function: current_function + %endif + %endif + %endif + + %if __emulate_avx + %xdefine __src1 %7 + %xdefine __src2 %8 + %if %5 && %4 == 0 + %ifnidn %6, %7 + %ifidn %6, %8 + %xdefine __src1 %8 + %xdefine __src2 %7 + %elifnnum sizeof%8 + ; 3-operand AVX instructions with a memory arg can only have it in src2, + ; whereas SSE emulation prefers to have it in src1 (i.e. the mov). + ; So, if the instruction is commutative with a memory arg, swap them. + %xdefine __src1 %8 + %xdefine __src2 %7 + %endif + %endif + %endif + %ifnidn %6, __src1 + %if %0 >= 9 + CHECK_AVX_INSTR_EMU {%1 %6, %7, %8, %9}, %6, __src2, %9 + %else + CHECK_AVX_INSTR_EMU {%1 %6, %7, %8}, %6, __src2 + %endif + %if __sizeofreg == 8 + MOVQ %6, __src1 + %elif %3 + MOVAPS %6, __src1 + %else + MOVDQA %6, __src1 + %endif + %endif + %if %0 >= 9 + %1 %6, __src2, %9 + %else + %1 %6, __src2 + %endif + %elif %0 >= 9 + __instr %6, %7, %8, %9 + %elif %0 == 8 + __instr %6, %7, %8 + %elif %0 == 7 + __instr %6, %7 + %else + __instr %6 + %endif +%endmacro + +;%1 == instruction +;%2 == minimal instruction set +;%3 == 1 if float, 0 if int +;%4 == 1 if 4-operand emulation, 0 if 3-operand emulation, 255 otherwise (no emulation) +;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not +%macro AVX_INSTR 1-5 fnord, 0, 255, 0 + %macro %1 1-10 fnord, fnord, fnord, fnord, %1, %2, %3, %4, %5 + %ifidn %2, fnord + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1 + %elifidn %3, fnord + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2 + %elifidn %4, fnord + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3 + %elifidn %5, fnord + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4 + %else + RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4, %5 + %endif + %endmacro +%endmacro + +; Instructions with both VEX/EVEX and legacy encodings +; Non-destructive instructions are written without parameters +AVX_INSTR addpd, sse2, 1, 0, 1 +AVX_INSTR addps, sse, 1, 0, 1 +AVX_INSTR addsd, sse2, 1, 0, 0 +AVX_INSTR addss, sse, 1, 0, 0 +AVX_INSTR addsubpd, sse3, 1, 0, 0 +AVX_INSTR addsubps, sse3, 1, 0, 0 +AVX_INSTR aesdec, aesni, 0, 0, 0 +AVX_INSTR aesdeclast, aesni, 0, 0, 0 +AVX_INSTR aesenc, aesni, 0, 0, 0 +AVX_INSTR aesenclast, aesni, 0, 0, 0 +AVX_INSTR aesimc, aesni +AVX_INSTR aeskeygenassist, aesni +AVX_INSTR andnpd, sse2, 1, 0, 0 +AVX_INSTR andnps, sse, 1, 0, 0 +AVX_INSTR andpd, sse2, 1, 0, 1 +AVX_INSTR andps, sse, 1, 0, 1 +AVX_INSTR blendpd, sse4, 1, 1, 0 +AVX_INSTR blendps, sse4, 1, 1, 0 +AVX_INSTR blendvpd, sse4 ; can't be emulated +AVX_INSTR blendvps, sse4 ; can't be emulated +AVX_INSTR cmpeqpd, sse2, 1, 0, 1 +AVX_INSTR cmpeqps, sse, 1, 0, 1 +AVX_INSTR cmpeqsd, sse2, 1, 0, 0 +AVX_INSTR cmpeqss, sse, 1, 0, 0 +AVX_INSTR cmplepd, sse2, 1, 0, 0 +AVX_INSTR cmpleps, sse, 1, 0, 0 +AVX_INSTR cmplesd, sse2, 1, 0, 0 +AVX_INSTR cmpless, sse, 1, 0, 0 +AVX_INSTR cmpltpd, sse2, 1, 0, 0 +AVX_INSTR cmpltps, sse, 1, 0, 0 +AVX_INSTR cmpltsd, sse2, 1, 0, 0 +AVX_INSTR cmpltss, sse, 1, 0, 0 +AVX_INSTR cmpneqpd, sse2, 1, 0, 1 +AVX_INSTR cmpneqps, sse, 1, 0, 1 +AVX_INSTR cmpneqsd, sse2, 1, 0, 0 +AVX_INSTR cmpneqss, sse, 1, 0, 0 +AVX_INSTR cmpnlepd, sse2, 1, 0, 0 +AVX_INSTR cmpnleps, sse, 1, 0, 0 +AVX_INSTR cmpnlesd, sse2, 1, 0, 0 +AVX_INSTR cmpnless, sse, 1, 0, 0 +AVX_INSTR cmpnltpd, sse2, 1, 0, 0 +AVX_INSTR cmpnltps, sse, 1, 0, 0 +AVX_INSTR cmpnltsd, sse2, 1, 0, 0 +AVX_INSTR cmpnltss, sse, 1, 0, 0 +AVX_INSTR cmpordpd, sse2 1, 0, 1 +AVX_INSTR cmpordps, sse 1, 0, 1 +AVX_INSTR cmpordsd, sse2 1, 0, 0 +AVX_INSTR cmpordss, sse 1, 0, 0 +AVX_INSTR cmppd, sse2, 1, 1, 0 +AVX_INSTR cmpps, sse, 1, 1, 0 +AVX_INSTR cmpsd, sse2, 1, 1, 0 +AVX_INSTR cmpss, sse, 1, 1, 0 +AVX_INSTR cmpunordpd, sse2, 1, 0, 1 +AVX_INSTR cmpunordps, sse, 1, 0, 1 +AVX_INSTR cmpunordsd, sse2, 1, 0, 0 +AVX_INSTR cmpunordss, sse, 1, 0, 0 +AVX_INSTR comisd, sse2 +AVX_INSTR comiss, sse +AVX_INSTR cvtdq2pd, sse2 +AVX_INSTR cvtdq2ps, sse2 +AVX_INSTR cvtpd2dq, sse2 +AVX_INSTR cvtpd2ps, sse2 +AVX_INSTR cvtps2dq, sse2 +AVX_INSTR cvtps2pd, sse2 +AVX_INSTR cvtsd2si, sse2 +AVX_INSTR cvtsd2ss, sse2, 1, 0, 0 +AVX_INSTR cvtsi2sd, sse2, 1, 0, 0 +AVX_INSTR cvtsi2ss, sse, 1, 0, 0 +AVX_INSTR cvtss2sd, sse2, 1, 0, 0 +AVX_INSTR cvtss2si, sse +AVX_INSTR cvttpd2dq, sse2 +AVX_INSTR cvttps2dq, sse2 +AVX_INSTR cvttsd2si, sse2 +AVX_INSTR cvttss2si, sse +AVX_INSTR divpd, sse2, 1, 0, 0 +AVX_INSTR divps, sse, 1, 0, 0 +AVX_INSTR divsd, sse2, 1, 0, 0 +AVX_INSTR divss, sse, 1, 0, 0 +AVX_INSTR dppd, sse4, 1, 1, 0 +AVX_INSTR dpps, sse4, 1, 1, 0 +AVX_INSTR extractps, sse4 +AVX_INSTR haddpd, sse3, 1, 0, 0 +AVX_INSTR haddps, sse3, 1, 0, 0 +AVX_INSTR hsubpd, sse3, 1, 0, 0 +AVX_INSTR hsubps, sse3, 1, 0, 0 +AVX_INSTR insertps, sse4, 1, 1, 0 +AVX_INSTR lddqu, sse3 +AVX_INSTR ldmxcsr, sse +AVX_INSTR maskmovdqu, sse2 +AVX_INSTR maxpd, sse2, 1, 0, 1 +AVX_INSTR maxps, sse, 1, 0, 1 +AVX_INSTR maxsd, sse2, 1, 0, 0 +AVX_INSTR maxss, sse, 1, 0, 0 +AVX_INSTR minpd, sse2, 1, 0, 1 +AVX_INSTR minps, sse, 1, 0, 1 +AVX_INSTR minsd, sse2, 1, 0, 0 +AVX_INSTR minss, sse, 1, 0, 0 +AVX_INSTR movapd, sse2 +AVX_INSTR movaps, sse +AVX_INSTR movd, mmx +AVX_INSTR movddup, sse3 +AVX_INSTR movdqa, sse2 +AVX_INSTR movdqu, sse2 +AVX_INSTR movhlps, sse, 1, 0, 0 +AVX_INSTR movhpd, sse2, 1, 0, 0 +AVX_INSTR movhps, sse, 1, 0, 0 +AVX_INSTR movlhps, sse, 1, 0, 0 +AVX_INSTR movlpd, sse2, 1, 0, 0 +AVX_INSTR movlps, sse, 1, 0, 0 +AVX_INSTR movmskpd, sse2 +AVX_INSTR movmskps, sse +AVX_INSTR movntdq, sse2 +AVX_INSTR movntdqa, sse4 +AVX_INSTR movntpd, sse2 +AVX_INSTR movntps, sse +AVX_INSTR movq, mmx +AVX_INSTR movsd, sse2, 1, 0, 0 +AVX_INSTR movshdup, sse3 +AVX_INSTR movsldup, sse3 +AVX_INSTR movss, sse, 1, 0, 0 +AVX_INSTR movupd, sse2 +AVX_INSTR movups, sse +AVX_INSTR mpsadbw, sse4, 0, 1, 0 +AVX_INSTR mulpd, sse2, 1, 0, 1 +AVX_INSTR mulps, sse, 1, 0, 1 +AVX_INSTR mulsd, sse2, 1, 0, 0 +AVX_INSTR mulss, sse, 1, 0, 0 +AVX_INSTR orpd, sse2, 1, 0, 1 +AVX_INSTR orps, sse, 1, 0, 1 +AVX_INSTR pabsb, ssse3 +AVX_INSTR pabsd, ssse3 +AVX_INSTR pabsw, ssse3 +AVX_INSTR packsswb, mmx, 0, 0, 0 +AVX_INSTR packssdw, mmx, 0, 0, 0 +AVX_INSTR packuswb, mmx, 0, 0, 0 +AVX_INSTR packusdw, sse4, 0, 0, 0 +AVX_INSTR paddb, mmx, 0, 0, 1 +AVX_INSTR paddw, mmx, 0, 0, 1 +AVX_INSTR paddd, mmx, 0, 0, 1 +AVX_INSTR paddq, sse2, 0, 0, 1 +AVX_INSTR paddsb, mmx, 0, 0, 1 +AVX_INSTR paddsw, mmx, 0, 0, 1 +AVX_INSTR paddusb, mmx, 0, 0, 1 +AVX_INSTR paddusw, mmx, 0, 0, 1 +AVX_INSTR palignr, ssse3, 0, 1, 0 +AVX_INSTR pand, mmx, 0, 0, 1 +AVX_INSTR pandn, mmx, 0, 0, 0 +AVX_INSTR pavgb, mmx2, 0, 0, 1 +AVX_INSTR pavgw, mmx2, 0, 0, 1 +AVX_INSTR pblendvb, sse4 ; can't be emulated +AVX_INSTR pblendw, sse4, 0, 1, 0 +AVX_INSTR pclmulqdq, fnord, 0, 1, 0 +AVX_INSTR pclmulhqhqdq, fnord, 0, 0, 0 +AVX_INSTR pclmulhqlqdq, fnord, 0, 0, 0 +AVX_INSTR pclmullqhqdq, fnord, 0, 0, 0 +AVX_INSTR pclmullqlqdq, fnord, 0, 0, 0 +AVX_INSTR pcmpestri, sse42 +AVX_INSTR pcmpestrm, sse42 +AVX_INSTR pcmpistri, sse42 +AVX_INSTR pcmpistrm, sse42 +AVX_INSTR pcmpeqb, mmx, 0, 0, 1 +AVX_INSTR pcmpeqw, mmx, 0, 0, 1 +AVX_INSTR pcmpeqd, mmx, 0, 0, 1 +AVX_INSTR pcmpeqq, sse4, 0, 0, 1 +AVX_INSTR pcmpgtb, mmx, 0, 0, 0 +AVX_INSTR pcmpgtw, mmx, 0, 0, 0 +AVX_INSTR pcmpgtd, mmx, 0, 0, 0 +AVX_INSTR pcmpgtq, sse42, 0, 0, 0 +AVX_INSTR pextrb, sse4 +AVX_INSTR pextrd, sse4 +AVX_INSTR pextrq, sse4 +AVX_INSTR pextrw, mmx2 +AVX_INSTR phaddw, ssse3, 0, 0, 0 +AVX_INSTR phaddd, ssse3, 0, 0, 0 +AVX_INSTR phaddsw, ssse3, 0, 0, 0 +AVX_INSTR phminposuw, sse4 +AVX_INSTR phsubw, ssse3, 0, 0, 0 +AVX_INSTR phsubd, ssse3, 0, 0, 0 +AVX_INSTR phsubsw, ssse3, 0, 0, 0 +AVX_INSTR pinsrb, sse4, 0, 1, 0 +AVX_INSTR pinsrd, sse4, 0, 1, 0 +AVX_INSTR pinsrq, sse4, 0, 1, 0 +AVX_INSTR pinsrw, mmx2, 0, 1, 0 +AVX_INSTR pmaddwd, mmx, 0, 0, 1 +AVX_INSTR pmaddubsw, ssse3, 0, 0, 0 +AVX_INSTR pmaxsb, sse4, 0, 0, 1 +AVX_INSTR pmaxsw, mmx2, 0, 0, 1 +AVX_INSTR pmaxsd, sse4, 0, 0, 1 +AVX_INSTR pmaxub, mmx2, 0, 0, 1 +AVX_INSTR pmaxuw, sse4, 0, 0, 1 +AVX_INSTR pmaxud, sse4, 0, 0, 1 +AVX_INSTR pminsb, sse4, 0, 0, 1 +AVX_INSTR pminsw, mmx2, 0, 0, 1 +AVX_INSTR pminsd, sse4, 0, 0, 1 +AVX_INSTR pminub, mmx2, 0, 0, 1 +AVX_INSTR pminuw, sse4, 0, 0, 1 +AVX_INSTR pminud, sse4, 0, 0, 1 +AVX_INSTR pmovmskb, mmx2 +AVX_INSTR pmovsxbw, sse4 +AVX_INSTR pmovsxbd, sse4 +AVX_INSTR pmovsxbq, sse4 +AVX_INSTR pmovsxwd, sse4 +AVX_INSTR pmovsxwq, sse4 +AVX_INSTR pmovsxdq, sse4 +AVX_INSTR pmovzxbw, sse4 +AVX_INSTR pmovzxbd, sse4 +AVX_INSTR pmovzxbq, sse4 +AVX_INSTR pmovzxwd, sse4 +AVX_INSTR pmovzxwq, sse4 +AVX_INSTR pmovzxdq, sse4 +AVX_INSTR pmuldq, sse4, 0, 0, 1 +AVX_INSTR pmulhrsw, ssse3, 0, 0, 1 +AVX_INSTR pmulhuw, mmx2, 0, 0, 1 +AVX_INSTR pmulhw, mmx, 0, 0, 1 +AVX_INSTR pmullw, mmx, 0, 0, 1 +AVX_INSTR pmulld, sse4, 0, 0, 1 +AVX_INSTR pmuludq, sse2, 0, 0, 1 +AVX_INSTR por, mmx, 0, 0, 1 +AVX_INSTR psadbw, mmx2, 0, 0, 1 +AVX_INSTR pshufb, ssse3, 0, 0, 0 +AVX_INSTR pshufd, sse2 +AVX_INSTR pshufhw, sse2 +AVX_INSTR pshuflw, sse2 +AVX_INSTR psignb, ssse3, 0, 0, 0 +AVX_INSTR psignw, ssse3, 0, 0, 0 +AVX_INSTR psignd, ssse3, 0, 0, 0 +AVX_INSTR psllw, mmx, 0, 0, 0 +AVX_INSTR pslld, mmx, 0, 0, 0 +AVX_INSTR psllq, mmx, 0, 0, 0 +AVX_INSTR pslldq, sse2, 0, 0, 0 +AVX_INSTR psraw, mmx, 0, 0, 0 +AVX_INSTR psrad, mmx, 0, 0, 0 +AVX_INSTR psrlw, mmx, 0, 0, 0 +AVX_INSTR psrld, mmx, 0, 0, 0 +AVX_INSTR psrlq, mmx, 0, 0, 0 +AVX_INSTR psrldq, sse2, 0, 0, 0 +AVX_INSTR psubb, mmx, 0, 0, 0 +AVX_INSTR psubw, mmx, 0, 0, 0 +AVX_INSTR psubd, mmx, 0, 0, 0 +AVX_INSTR psubq, sse2, 0, 0, 0 +AVX_INSTR psubsb, mmx, 0, 0, 0 +AVX_INSTR psubsw, mmx, 0, 0, 0 +AVX_INSTR psubusb, mmx, 0, 0, 0 +AVX_INSTR psubusw, mmx, 0, 0, 0 +AVX_INSTR ptest, sse4 +AVX_INSTR punpckhbw, mmx, 0, 0, 0 +AVX_INSTR punpckhwd, mmx, 0, 0, 0 +AVX_INSTR punpckhdq, mmx, 0, 0, 0 +AVX_INSTR punpckhqdq, sse2, 0, 0, 0 +AVX_INSTR punpcklbw, mmx, 0, 0, 0 +AVX_INSTR punpcklwd, mmx, 0, 0, 0 +AVX_INSTR punpckldq, mmx, 0, 0, 0 +AVX_INSTR punpcklqdq, sse2, 0, 0, 0 +AVX_INSTR pxor, mmx, 0, 0, 1 +AVX_INSTR rcpps, sse +AVX_INSTR rcpss, sse, 1, 0, 0 +AVX_INSTR roundpd, sse4 +AVX_INSTR roundps, sse4 +AVX_INSTR roundsd, sse4, 1, 1, 0 +AVX_INSTR roundss, sse4, 1, 1, 0 +AVX_INSTR rsqrtps, sse +AVX_INSTR rsqrtss, sse, 1, 0, 0 +AVX_INSTR shufpd, sse2, 1, 1, 0 +AVX_INSTR shufps, sse, 1, 1, 0 +AVX_INSTR sqrtpd, sse2 +AVX_INSTR sqrtps, sse +AVX_INSTR sqrtsd, sse2, 1, 0, 0 +AVX_INSTR sqrtss, sse, 1, 0, 0 +AVX_INSTR stmxcsr, sse +AVX_INSTR subpd, sse2, 1, 0, 0 +AVX_INSTR subps, sse, 1, 0, 0 +AVX_INSTR subsd, sse2, 1, 0, 0 +AVX_INSTR subss, sse, 1, 0, 0 +AVX_INSTR ucomisd, sse2 +AVX_INSTR ucomiss, sse +AVX_INSTR unpckhpd, sse2, 1, 0, 0 +AVX_INSTR unpckhps, sse, 1, 0, 0 +AVX_INSTR unpcklpd, sse2, 1, 0, 0 +AVX_INSTR unpcklps, sse, 1, 0, 0 +AVX_INSTR xorpd, sse2, 1, 0, 1 +AVX_INSTR xorps, sse, 1, 0, 1 + +; 3DNow instructions, for sharing code between AVX, SSE and 3DN +AVX_INSTR pfadd, 3dnow, 1, 0, 1 +AVX_INSTR pfsub, 3dnow, 1, 0, 0 +AVX_INSTR pfmul, 3dnow, 1, 0, 1 + +; base-4 constants for shuffles +%assign i 0 +%rep 256 + %assign j ((i>>6)&3)*1000 + ((i>>4)&3)*100 + ((i>>2)&3)*10 + (i&3) + %if j < 10 + CAT_XDEFINE q000, j, i + %elif j < 100 + CAT_XDEFINE q00, j, i + %elif j < 1000 + CAT_XDEFINE q0, j, i + %else + CAT_XDEFINE q, j, i + %endif + %assign i i+1 +%endrep +%undef i +%undef j + +%macro FMA_INSTR 3 + %macro %1 4-7 %1, %2, %3 + %if cpuflag(xop) + v%5 %1, %2, %3, %4 + %elifnidn %1, %4 + %6 %1, %2, %3 + %7 %1, %4 + %else + %error non-xop emulation of ``%5 %1, %2, %3, %4'' is not supported + %endif + %endmacro +%endmacro + +FMA_INSTR pmacsww, pmullw, paddw +FMA_INSTR pmacsdd, pmulld, paddd ; sse4 emulation +FMA_INSTR pmacsdql, pmuldq, paddq ; sse4 emulation +FMA_INSTR pmadcswd, pmaddwd, paddd + +; tzcnt is equivalent to "rep bsf" and is backwards-compatible with bsf. +; This lets us use tzcnt without bumping the yasm version requirement yet. +%define tzcnt rep bsf + +; Macros for consolidating FMA3 and FMA4 using 4-operand (dst, src1, src2, src3) syntax. +; FMA3 is only possible if dst is the same as one of the src registers. +; Either src2 or src3 can be a memory operand. +%macro FMA4_INSTR 2-* + %push fma4_instr + %xdefine %$prefix %1 + %rep %0 - 1 + %macro %$prefix%2 4-6 %$prefix, %2 + %if notcpuflag(fma3) && notcpuflag(fma4) + %error use of ``%5%6'' fma instruction in cpuname function: current_function + %elif cpuflag(fma4) + v%5%6 %1, %2, %3, %4 + %elifidn %1, %2 + ; If %3 or %4 is a memory operand it needs to be encoded as the last operand. + %ifnum sizeof%3 + v%{5}213%6 %2, %3, %4 + %else + v%{5}132%6 %2, %4, %3 + %endif + %elifidn %1, %3 + v%{5}213%6 %3, %2, %4 + %elifidn %1, %4 + v%{5}231%6 %4, %2, %3 + %else + %error fma3 emulation of ``%5%6 %1, %2, %3, %4'' is not supported + %endif + %endmacro + %rotate 1 + %endrep + %pop +%endmacro + +FMA4_INSTR fmadd, pd, ps, sd, ss +FMA4_INSTR fmaddsub, pd, ps +FMA4_INSTR fmsub, pd, ps, sd, ss +FMA4_INSTR fmsubadd, pd, ps +FMA4_INSTR fnmadd, pd, ps, sd, ss +FMA4_INSTR fnmsub, pd, ps, sd, ss + +; Macros for converting VEX instructions to equivalent EVEX ones. +%macro EVEX_INSTR 2-3 0 ; vex, evex, prefer_evex + %macro %1 2-7 fnord, fnord, %1, %2, %3 + %ifidn %3, fnord + %define %%args %1, %2 + %elifidn %4, fnord + %define %%args %1, %2, %3 + %else + %define %%args %1, %2, %3, %4 + %endif + %assign %%evex_required cpuflag(avx512) & %7 + %ifnum regnumof%1 + %if regnumof%1 >= 16 || sizeof%1 > 32 + %assign %%evex_required 1 + %endif + %endif + %ifnum regnumof%2 + %if regnumof%2 >= 16 || sizeof%2 > 32 + %assign %%evex_required 1 + %endif + %endif + %if %%evex_required + %6 %%args + %else + %5 %%args ; Prefer VEX over EVEX due to shorter instruction length + %endif + %endmacro +%endmacro + +EVEX_INSTR vbroadcastf128, vbroadcastf32x4 +EVEX_INSTR vbroadcasti128, vbroadcasti32x4 +EVEX_INSTR vextractf128, vextractf32x4 +EVEX_INSTR vextracti128, vextracti32x4 +EVEX_INSTR vinsertf128, vinsertf32x4 +EVEX_INSTR vinserti128, vinserti32x4 +EVEX_INSTR vmovdqa, vmovdqa32 +EVEX_INSTR vmovdqu, vmovdqu32 +EVEX_INSTR vpand, vpandd +EVEX_INSTR vpandn, vpandnd +EVEX_INSTR vpor, vpord +EVEX_INSTR vpxor, vpxord +EVEX_INSTR vrcpps, vrcp14ps, 1 ; EVEX versions have higher precision +EVEX_INSTR vrcpss, vrcp14ss, 1 +EVEX_INSTR vrsqrtps, vrsqrt14ps, 1 +EVEX_INSTR vrsqrtss, vrsqrt14ss, 1 + +; workaround: vpbroadcastq is broken in x86_32 due to a yasm bug (fixed in 1.3.0) +%ifdef __YASM_VER__ + %if __YASM_VERSION_ID__ < 0x01030000 && ARCH_X86_64 == 0 + %macro vpbroadcastq 2 + %if sizeof%1 == 16 + movddup %1, %2 + %else + vbroadcastsd %1, %2 + %endif + %endmacro + %endif +%endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/x86util.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/x86util.asm new file mode 100644 index 0000000000..d7cd996842 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libavutil/x86/x86util.asm @@ -0,0 +1,1028 @@ +;***************************************************************************** +;* x86util.asm +;***************************************************************************** +;* Copyright (C) 2008-2010 x264 project +;* +;* Authors: Loren Merritt +;* Holger Lubitz +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%define private_prefix ff +%define public_prefix avpriv +%define cpuflags_mmxext cpuflags_mmx2 + +%include "libavutil/x86/x86inc.asm" + +; expands to [base],...,[base+7*stride] +%define PASS8ROWS(base, base3, stride, stride3) \ + [base], [base + stride], [base + 2*stride], [base3], \ + [base3 + stride], [base3 + 2*stride], [base3 + stride3], [base3 + stride*4] + +; Interleave low src0 with low src1 and store in src0, +; interleave high src0 with high src1 and store in src1. +; %1 - types +; %2 - index of the register with src0 +; %3 - index of the register with src1 +; %4 - index of the register for intermediate results +; example for %1 - wd: input: src0: x0 x1 x2 x3 z0 z1 z2 z3 +; src1: y0 y1 y2 y3 q0 q1 q2 q3 +; output: src0: x0 y0 x1 y1 x2 y2 x3 y3 +; src1: z0 q0 z1 q1 z2 q2 z3 q3 +%macro SBUTTERFLY 4 +%ifidn %1, dqqq + vperm2i128 m%4, m%2, m%3, q0301 + vinserti128 m%2, m%2, xm%3, 1 +%elif avx_enabled == 0 + mova m%4, m%2 + punpckl%1 m%2, m%3 + punpckh%1 m%4, m%3 +%else + punpckh%1 m%4, m%2, m%3 + punpckl%1 m%2, m%3 +%endif + SWAP %3, %4 +%endmacro + +%macro SBUTTERFLY2 4 + punpckl%1 m%4, m%2, m%3 + punpckh%1 m%2, m%2, m%3 + SWAP %2, %4, %3 +%endmacro + +%macro SBUTTERFLYPS 3 + unpcklps m%3, m%1, m%2 + unpckhps m%1, m%1, m%2 + SWAP %1, %3, %2 +%endmacro + +%macro SBUTTERFLYPD 3 + movlhps m%3, m%1, m%2 + movhlps m%2, m%2, m%1 + SWAP %1, %3 +%endmacro + +%macro TRANSPOSE4x4B 5 + SBUTTERFLY bw, %1, %2, %5 + SBUTTERFLY bw, %3, %4, %5 + SBUTTERFLY wd, %1, %3, %5 + SBUTTERFLY wd, %2, %4, %5 + SWAP %2, %3 +%endmacro + +%macro TRANSPOSE4x4W 5 + SBUTTERFLY wd, %1, %2, %5 + SBUTTERFLY wd, %3, %4, %5 + SBUTTERFLY dq, %1, %3, %5 + SBUTTERFLY dq, %2, %4, %5 + SWAP %2, %3 +%endmacro + +%macro TRANSPOSE2x4x4B 5 + SBUTTERFLY bw, %1, %2, %5 + SBUTTERFLY bw, %3, %4, %5 + SBUTTERFLY wd, %1, %3, %5 + SBUTTERFLY wd, %2, %4, %5 + SBUTTERFLY dq, %1, %2, %5 + SBUTTERFLY dq, %3, %4, %5 +%endmacro + +%macro TRANSPOSE2x4x4W 5 + SBUTTERFLY wd, %1, %2, %5 + SBUTTERFLY wd, %3, %4, %5 + SBUTTERFLY dq, %1, %3, %5 + SBUTTERFLY dq, %2, %4, %5 + SBUTTERFLY qdq, %1, %2, %5 + SBUTTERFLY qdq, %3, %4, %5 +%endmacro + +%macro TRANSPOSE4x4D 5 + SBUTTERFLY dq, %1, %2, %5 + SBUTTERFLY dq, %3, %4, %5 + SBUTTERFLY qdq, %1, %3, %5 + SBUTTERFLY qdq, %2, %4, %5 + SWAP %2, %3 +%endmacro + +; identical behavior to TRANSPOSE4x4D, but using SSE1 float ops +%macro TRANSPOSE4x4PS 5 + SBUTTERFLYPS %1, %2, %5 + SBUTTERFLYPS %3, %4, %5 + SBUTTERFLYPD %1, %3, %5 + SBUTTERFLYPD %2, %4, %5 + SWAP %2, %3 +%endmacro + +%macro TRANSPOSE8x4D 9-11 +%if ARCH_X86_64 + SBUTTERFLY dq, %1, %2, %9 + SBUTTERFLY dq, %3, %4, %9 + SBUTTERFLY dq, %5, %6, %9 + SBUTTERFLY dq, %7, %8, %9 + SBUTTERFLY qdq, %1, %3, %9 + SBUTTERFLY qdq, %2, %4, %9 + SBUTTERFLY qdq, %5, %7, %9 + SBUTTERFLY qdq, %6, %8, %9 + SWAP %2, %5 + SWAP %4, %7 +%else +; in: m0..m7 +; out: m0..m7, unless %11 in which case m2 is in %9 +; spills into %9 and %10 + movdqa %9, m%7 + SBUTTERFLY dq, %1, %2, %7 + movdqa %10, m%2 + movdqa m%7, %9 + SBUTTERFLY dq, %3, %4, %2 + SBUTTERFLY dq, %5, %6, %2 + SBUTTERFLY dq, %7, %8, %2 + SBUTTERFLY qdq, %1, %3, %2 + movdqa %9, m%3 + movdqa m%2, %10 + SBUTTERFLY qdq, %2, %4, %3 + SBUTTERFLY qdq, %5, %7, %3 + SBUTTERFLY qdq, %6, %8, %3 + SWAP %2, %5 + SWAP %4, %7 +%if %0<11 + movdqa m%3, %9 +%endif +%endif +%endmacro + +%macro TRANSPOSE8x8W 9-11 +%if ARCH_X86_64 + SBUTTERFLY wd, %1, %2, %9 + SBUTTERFLY wd, %3, %4, %9 + SBUTTERFLY wd, %5, %6, %9 + SBUTTERFLY wd, %7, %8, %9 + SBUTTERFLY dq, %1, %3, %9 + SBUTTERFLY dq, %2, %4, %9 + SBUTTERFLY dq, %5, %7, %9 + SBUTTERFLY dq, %6, %8, %9 + SBUTTERFLY qdq, %1, %5, %9 + SBUTTERFLY qdq, %2, %6, %9 + SBUTTERFLY qdq, %3, %7, %9 + SBUTTERFLY qdq, %4, %8, %9 + SWAP %2, %5 + SWAP %4, %7 +%else +; in: m0..m7, unless %11 in which case m6 is in %9 +; out: m0..m7, unless %11 in which case m4 is in %10 +; spills into %9 and %10 +%if %0<11 + movdqa %9, m%7 +%endif + SBUTTERFLY wd, %1, %2, %7 + movdqa %10, m%2 + movdqa m%7, %9 + SBUTTERFLY wd, %3, %4, %2 + SBUTTERFLY wd, %5, %6, %2 + SBUTTERFLY wd, %7, %8, %2 + SBUTTERFLY dq, %1, %3, %2 + movdqa %9, m%3 + movdqa m%2, %10 + SBUTTERFLY dq, %2, %4, %3 + SBUTTERFLY dq, %5, %7, %3 + SBUTTERFLY dq, %6, %8, %3 + SBUTTERFLY qdq, %1, %5, %3 + SBUTTERFLY qdq, %2, %6, %3 + movdqa %10, m%2 + movdqa m%3, %9 + SBUTTERFLY qdq, %3, %7, %2 + SBUTTERFLY qdq, %4, %8, %2 + SWAP %2, %5 + SWAP %4, %7 +%if %0<11 + movdqa m%5, %10 +%endif +%endif +%endmacro + +%macro TRANSPOSE16x16W 18-19 +; in: m0..m15, unless %19 in which case m6 is in %17 +; out: m0..m15, unless %19 in which case m4 is in %18 +; spills into %17 and %18 +%if %0 < 19 + mova %17, m%7 +%endif + + SBUTTERFLY dqqq, %1, %9, %7 + SBUTTERFLY dqqq, %2, %10, %7 + SBUTTERFLY dqqq, %3, %11, %7 + SBUTTERFLY dqqq, %4, %12, %7 + SBUTTERFLY dqqq, %5, %13, %7 + SBUTTERFLY dqqq, %6, %14, %7 + mova %18, m%14 + mova m%7, %17 + SBUTTERFLY dqqq, %7, %15, %14 + SBUTTERFLY dqqq, %8, %16, %14 + + SBUTTERFLY wd, %1, %2, %14 + SBUTTERFLY wd, %3, %4, %14 + SBUTTERFLY wd, %5, %6, %14 + SBUTTERFLY wd, %7, %8, %14 + SBUTTERFLY wd, %9, %10, %14 + SBUTTERFLY wd, %11, %12, %14 + mova %17, m%12 + mova m%14, %18 + SBUTTERFLY wd, %13, %14, %12 + SBUTTERFLY wd, %15, %16, %12 + + SBUTTERFLY dq, %1, %3, %12 + SBUTTERFLY dq, %2, %4, %12 + SBUTTERFLY dq, %5, %7, %12 + SBUTTERFLY dq, %6, %8, %12 + SBUTTERFLY dq, %9, %11, %12 + mova %18, m%11 + mova m%12, %17 + SBUTTERFLY dq, %10, %12, %11 + SBUTTERFLY dq, %13, %15, %11 + SBUTTERFLY dq, %14, %16, %11 + + SBUTTERFLY qdq, %1, %5, %11 + SBUTTERFLY qdq, %2, %6, %11 + SBUTTERFLY qdq, %3, %7, %11 + SBUTTERFLY qdq, %4, %8, %11 + + SWAP %2, %5 + SWAP %4, %7 + + SBUTTERFLY qdq, %9, %13, %11 + SBUTTERFLY qdq, %10, %14, %11 + mova m%11, %18 + mova %18, m%5 + SBUTTERFLY qdq, %11, %15, %5 + SBUTTERFLY qdq, %12, %16, %5 + +%if %0 < 19 + mova m%5, %18 +%endif + + SWAP %10, %13 + SWAP %12, %15 +%endmacro + +%macro TRANSPOSE_8X8B 8 + %if mmsize == 8 + %error "This macro does not support mmsize == 8" + %endif + punpcklbw m%1, m%2 + punpcklbw m%3, m%4 + punpcklbw m%5, m%6 + punpcklbw m%7, m%8 + TRANSPOSE4x4W %1, %3, %5, %7, %2 + MOVHL m%2, m%1 + MOVHL m%4, m%3 + MOVHL m%6, m%5 + MOVHL m%8, m%7 +%endmacro + +; PABSW macro assumes %1 != %2, while ABS1/2 macros work in-place +%macro PABSW 2 +%if cpuflag(ssse3) + pabsw %1, %2 +%elif cpuflag(mmxext) + pxor %1, %1 + psubw %1, %2 + pmaxsw %1, %2 +%else + pxor %1, %1 + pcmpgtw %1, %2 + pxor %2, %1 + psubw %2, %1 + SWAP %1, %2 +%endif +%endmacro + +%macro PSIGNW 2 +%if cpuflag(ssse3) + psignw %1, %2 +%else + pxor %1, %2 + psubw %1, %2 +%endif +%endmacro + +%macro ABS1 2 +%if cpuflag(ssse3) + pabsw %1, %1 +%elif cpuflag(mmxext) ; a, tmp + pxor %2, %2 + psubw %2, %1 + pmaxsw %1, %2 +%else ; a, tmp + pxor %2, %2 + pcmpgtw %2, %1 + pxor %1, %2 + psubw %1, %2 +%endif +%endmacro + +%macro ABS2 4 +%if cpuflag(ssse3) + pabsw %1, %1 + pabsw %2, %2 +%elif cpuflag(mmxext) ; a, b, tmp0, tmp1 + pxor %3, %3 + pxor %4, %4 + psubw %3, %1 + psubw %4, %2 + pmaxsw %1, %3 + pmaxsw %2, %4 +%else ; a, b, tmp0, tmp1 + pxor %3, %3 + pxor %4, %4 + pcmpgtw %3, %1 + pcmpgtw %4, %2 + pxor %1, %3 + pxor %2, %4 + psubw %1, %3 + psubw %2, %4 +%endif +%endmacro + +%macro ABSB 2 ; source mmreg, temp mmreg (unused for SSSE3) +%if cpuflag(ssse3) + pabsb %1, %1 +%else + pxor %2, %2 + psubb %2, %1 + pminub %1, %2 +%endif +%endmacro + +%macro ABSB2 4 ; src1, src2, tmp1, tmp2 (tmp1/2 unused for SSSE3) +%if cpuflag(ssse3) + pabsb %1, %1 + pabsb %2, %2 +%else + pxor %3, %3 + pxor %4, %4 + psubb %3, %1 + psubb %4, %2 + pminub %1, %3 + pminub %2, %4 +%endif +%endmacro + +%macro ABSD2 4 + pxor %3, %3 + pxor %4, %4 + pcmpgtd %3, %1 + pcmpgtd %4, %2 + pxor %1, %3 + pxor %2, %4 + psubd %1, %3 + psubd %2, %4 +%endmacro + +%macro ABS4 6 + ABS2 %1, %2, %5, %6 + ABS2 %3, %4, %5, %6 +%endmacro + +%macro SPLATB_LOAD 3 +%if cpuflag(ssse3) + movd %1, [%2-3] + pshufb %1, %3 +%else + movd %1, [%2-3] ;to avoid crossing a cacheline + punpcklbw %1, %1 + SPLATW %1, %1, 3 +%endif +%endmacro + +%macro SPLATB_REG 3 +%if cpuflag(ssse3) + movd %1, %2d + pshufb %1, %3 +%else + movd %1, %2d + punpcklbw %1, %1 + SPLATW %1, %1, 0 +%endif +%endmacro + +%macro HADDD 2 ; sum junk +%if sizeof%1 == 32 +%define %2 xmm%2 + vextracti128 %2, %1, 1 +%define %1 xmm%1 + paddd %1, %2 +%endif +%if mmsize >= 16 +%if cpuflag(xop) && sizeof%1 == 16 + vphadddq %1, %1 +%endif + movhlps %2, %1 + paddd %1, %2 +%endif +%if notcpuflag(xop) || sizeof%1 != 16 +%if cpuflag(mmxext) + PSHUFLW %2, %1, q0032 +%else ; mmx + mova %2, %1 + psrlq %2, 32 +%endif + paddd %1, %2 +%endif +%undef %1 +%undef %2 +%endmacro + +%macro HADDW 2 ; reg, tmp +%if cpuflag(xop) && sizeof%1 == 16 + vphaddwq %1, %1 + movhlps %2, %1 + paddd %1, %2 +%else + pmaddwd %1, [pw_1] + HADDD %1, %2 +%endif +%endmacro + +%macro HADDPS 3 ; dst, src, tmp +%if cpuflag(sse3) + haddps %1, %1, %2 +%else + movaps %3, %1 + shufps %1, %2, q2020 + shufps %3, %2, q3131 + addps %1, %3 +%endif +%endmacro + +%macro PALIGNR 4-5 +%if cpuflag(ssse3) +%if %0==5 + palignr %1, %2, %3, %4 +%else + palignr %1, %2, %3 +%endif +%else ; [dst,] src1, src2, imm, tmp + %define %%dst %1 +%if %0==5 +%ifnidn %1, %2 + mova %%dst, %2 +%endif + %rotate 1 +%endif +%ifnidn %4, %2 + mova %4, %2 +%endif +%if mmsize==8 + psllq %%dst, (8-%3)*8 + psrlq %4, %3*8 +%else + pslldq %%dst, 16-%3 + psrldq %4, %3 +%endif + por %%dst, %4 +%endif +%endmacro + +%macro PAVGB 2-4 +%if cpuflag(mmxext) + pavgb %1, %2 +%elif cpuflag(3dnow) + pavgusb %1, %2 +%elif cpuflag(mmx) + movu %3, %2 + por %3, %1 + pxor %1, %2 + pand %1, %4 + psrlq %1, 1 + psubb %3, %1 + SWAP %1, %3 +%endif +%endmacro + +%macro PSHUFLW 1+ + %if mmsize == 8 + pshufw %1 + %else + pshuflw %1 + %endif +%endmacro + +%macro PSWAPD 2 +%if cpuflag(mmxext) + pshufw %1, %2, q1032 +%elif cpuflag(3dnowext) + pswapd %1, %2 +%elif cpuflag(3dnow) + movq %1, %2 + psrlq %1, 32 + punpckldq %1, %2 +%endif +%endmacro + +%macro DEINTB 5 ; mask, reg1, mask, reg2, optional src to fill masks from +%ifnum %5 + pand m%3, m%5, m%4 ; src .. y6 .. y4 + pand m%1, m%5, m%2 ; dst .. y6 .. y4 +%else + mova m%1, %5 + pand m%3, m%1, m%4 ; src .. y6 .. y4 + pand m%1, m%1, m%2 ; dst .. y6 .. y4 +%endif + psrlw m%2, 8 ; dst .. y7 .. y5 + psrlw m%4, 8 ; src .. y7 .. y5 +%endmacro + +%macro SUMSUB_BA 3-4 +%if %0==3 + padd%1 m%2, m%3 + padd%1 m%3, m%3 + psub%1 m%3, m%2 +%else +%if avx_enabled == 0 + mova m%4, m%2 + padd%1 m%2, m%3 + psub%1 m%3, m%4 +%else + padd%1 m%4, m%2, m%3 + psub%1 m%3, m%2 + SWAP %2, %4 +%endif +%endif +%endmacro + +%macro SUMSUB_BADC 5-6 +%if %0==6 + SUMSUB_BA %1, %2, %3, %6 + SUMSUB_BA %1, %4, %5, %6 +%else + padd%1 m%2, m%3 + padd%1 m%4, m%5 + padd%1 m%3, m%3 + padd%1 m%5, m%5 + psub%1 m%3, m%2 + psub%1 m%5, m%4 +%endif +%endmacro + +%macro SUMSUB2_AB 4 +%ifnum %3 + psub%1 m%4, m%2, m%3 + psub%1 m%4, m%3 + padd%1 m%2, m%2 + padd%1 m%2, m%3 +%else + mova m%4, m%2 + padd%1 m%2, m%2 + padd%1 m%2, %3 + psub%1 m%4, %3 + psub%1 m%4, %3 +%endif +%endmacro + +%macro SUMSUB2_BA 4 +%if avx_enabled == 0 + mova m%4, m%2 + padd%1 m%2, m%3 + padd%1 m%2, m%3 + psub%1 m%3, m%4 + psub%1 m%3, m%4 +%else + padd%1 m%4, m%2, m%3 + padd%1 m%4, m%3 + psub%1 m%3, m%2 + psub%1 m%3, m%2 + SWAP %2, %4 +%endif +%endmacro + +%macro SUMSUBD2_AB 5 +%ifnum %4 + psra%1 m%5, m%2, 1 ; %3: %3>>1 + psra%1 m%4, m%3, 1 ; %2: %2>>1 + padd%1 m%4, m%2 ; %3: %3>>1+%2 + psub%1 m%5, m%3 ; %2: %2>>1-%3 + SWAP %2, %5 + SWAP %3, %4 +%else + mova %5, m%2 + mova %4, m%3 + psra%1 m%3, 1 ; %3: %3>>1 + psra%1 m%2, 1 ; %2: %2>>1 + padd%1 m%3, %5 ; %3: %3>>1+%2 + psub%1 m%2, %4 ; %2: %2>>1-%3 +%endif +%endmacro + +%macro DCT4_1D 5 +%ifnum %5 + SUMSUB_BADC w, %4, %1, %3, %2, %5 + SUMSUB_BA w, %3, %4, %5 + SUMSUB2_AB w, %1, %2, %5 + SWAP %1, %3, %4, %5, %2 +%else + SUMSUB_BADC w, %4, %1, %3, %2 + SUMSUB_BA w, %3, %4 + mova [%5], m%2 + SUMSUB2_AB w, %1, [%5], %2 + SWAP %1, %3, %4, %2 +%endif +%endmacro + +%macro IDCT4_1D 6-7 +%ifnum %6 + SUMSUBD2_AB %1, %3, %5, %7, %6 + ; %3: %3>>1-%5 %5: %3+%5>>1 + SUMSUB_BA %1, %4, %2, %7 + ; %4: %2+%4 %2: %2-%4 + SUMSUB_BADC %1, %5, %4, %3, %2, %7 + ; %5: %2+%4 + (%3+%5>>1) + ; %4: %2+%4 - (%3+%5>>1) + ; %3: %2-%4 + (%3>>1-%5) + ; %2: %2-%4 - (%3>>1-%5) +%else +%ifidn %1, w + SUMSUBD2_AB %1, %3, %5, [%6], [%6+16] +%else + SUMSUBD2_AB %1, %3, %5, [%6], [%6+32] +%endif + SUMSUB_BA %1, %4, %2 + SUMSUB_BADC %1, %5, %4, %3, %2 +%endif + SWAP %2, %5, %4 + ; %2: %2+%4 + (%3+%5>>1) row0 + ; %3: %2-%4 + (%3>>1-%5) row1 + ; %4: %2-%4 - (%3>>1-%5) row2 + ; %5: %2+%4 - (%3+%5>>1) row3 +%endmacro + + +%macro LOAD_DIFF 5 +%ifidn %3, none + movh %1, %4 + movh %2, %5 + punpcklbw %1, %2 + punpcklbw %2, %2 + psubw %1, %2 +%else + movh %1, %4 + punpcklbw %1, %3 + movh %2, %5 + punpcklbw %2, %3 + psubw %1, %2 +%endif +%endmacro + +%macro STORE_DCT 6 + movq [%5+%6+ 0], m%1 + movq [%5+%6+ 8], m%2 + movq [%5+%6+16], m%3 + movq [%5+%6+24], m%4 + movhps [%5+%6+32], m%1 + movhps [%5+%6+40], m%2 + movhps [%5+%6+48], m%3 + movhps [%5+%6+56], m%4 +%endmacro + +%macro LOAD_DIFF_8x4P 7-10 r0,r2,0 ; 4x dest, 2x temp, 2x pointer, increment? + LOAD_DIFF m%1, m%5, m%7, [%8], [%9] + LOAD_DIFF m%2, m%6, m%7, [%8+r1], [%9+r3] + LOAD_DIFF m%3, m%5, m%7, [%8+2*r1], [%9+2*r3] + LOAD_DIFF m%4, m%6, m%7, [%8+r4], [%9+r5] +%if %10 + lea %8, [%8+4*r1] + lea %9, [%9+4*r3] +%endif +%endmacro + +%macro DIFFx2 6-7 + movh %3, %5 + punpcklbw %3, %4 + psraw %1, 6 + paddsw %1, %3 + movh %3, %6 + punpcklbw %3, %4 + psraw %2, 6 + paddsw %2, %3 + packuswb %2, %1 +%endmacro + +%macro STORE_DIFF 4 + movh %2, %4 + punpcklbw %2, %3 + psraw %1, 6 + paddsw %1, %2 + packuswb %1, %1 + movh %4, %1 +%endmacro + +%macro STORE_DIFFx2 8 ; add1, add2, reg1, reg2, zero, shift, source, stride + movh %3, [%7] + movh %4, [%7+%8] + psraw %1, %6 + psraw %2, %6 + punpcklbw %3, %5 + punpcklbw %4, %5 + paddw %3, %1 + paddw %4, %2 + packuswb %3, %5 + packuswb %4, %5 + movh [%7], %3 + movh [%7+%8], %4 +%endmacro + +%macro PMINUB 3 ; dst, src, ignored +%if cpuflag(mmxext) + pminub %1, %2 +%else ; dst, src, tmp + mova %3, %1 + psubusb %3, %2 + psubb %1, %3 +%endif +%endmacro + +%macro SPLATW 2-3 0 +%if cpuflag(avx2) && %3 == 0 + vpbroadcastw %1, %2 +%elif mmsize == 16 + pshuflw %1, %2, (%3)*0x55 + punpcklqdq %1, %1 +%elif cpuflag(mmxext) + pshufw %1, %2, (%3)*0x55 +%else + %ifnidn %1, %2 + mova %1, %2 + %endif + %if %3 & 2 + punpckhwd %1, %1 + %else + punpcklwd %1, %1 + %endif + %if %3 & 1 + punpckhwd %1, %1 + %else + punpcklwd %1, %1 + %endif +%endif +%endmacro + +%macro SPLATD 1 +%if mmsize == 8 + punpckldq %1, %1 +%elif cpuflag(sse2) + pshufd %1, %1, 0 +%elif cpuflag(sse) + shufps %1, %1, 0 +%endif +%endmacro + +%macro CLIPUB 3 ;(dst, min, max) + pmaxub %1, %2 + pminub %1, %3 +%endmacro + +%macro CLIPW 3 ;(dst, min, max) + pmaxsw %1, %2 + pminsw %1, %3 +%endmacro + +%macro PMINSD 3 ; dst, src, tmp/unused +%if cpuflag(sse4) + pminsd %1, %2 +%elif cpuflag(sse2) + cvtdq2ps %1, %1 + minps %1, %2 + cvtps2dq %1, %1 +%else + mova %3, %2 + pcmpgtd %3, %1 + pxor %1, %2 + pand %1, %3 + pxor %1, %2 +%endif +%endmacro + +%macro PMAXSD 3 ; dst, src, tmp/unused +%if cpuflag(sse4) + pmaxsd %1, %2 +%else + mova %3, %1 + pcmpgtd %3, %2 + pand %1, %3 + pandn %3, %2 + por %1, %3 +%endif +%endmacro + +%macro CLIPD 3-4 +%if cpuflag(sse4); src/dst, min, max, unused + pminsd %1, %3 + pmaxsd %1, %2 +%elif cpuflag(sse2) ; src/dst, min (float), max (float), unused + cvtdq2ps %1, %1 + minps %1, %3 + maxps %1, %2 + cvtps2dq %1, %1 +%else ; src/dst, min, max, tmp + PMINSD %1, %3, %4 + PMAXSD %1, %2, %4 +%endif +%endmacro + +%macro VBROADCASTSS 2 ; dst xmm/ymm, src m32/xmm +%if cpuflag(avx2) + vbroadcastss %1, %2 +%elif cpuflag(avx) + %ifnum sizeof%2 ; avx1 register + shufps xmm%1, xmm%2, xmm%2, q0000 + %if sizeof%1 >= 32 ; mmsize>=32 + vinsertf128 %1, %1, xmm%1, 1 + %endif + %else ; avx1 memory + vbroadcastss %1, %2 + %endif +%else + %ifnum sizeof%2 ; sse register + shufps %1, %2, %2, q0000 + %else ; sse memory + movss %1, %2 + shufps %1, %1, 0 + %endif +%endif +%endmacro + +%macro VBROADCASTSD 2 ; dst xmm/ymm, src m64 +%if cpuflag(avx) && mmsize == 32 + vbroadcastsd %1, %2 +%elif cpuflag(sse3) + movddup %1, %2 +%else ; sse2 + movsd %1, %2 + movlhps %1, %1 +%endif +%endmacro + +%macro VPBROADCASTD 2 ; dst xmm/ymm, src m32/xmm +%if cpuflag(avx2) + vpbroadcastd %1, %2 +%elif cpuflag(avx) && sizeof%1 >= 32 + %error vpbroadcastd not possible with ymm on avx1. try vbroadcastss +%else + %ifnum sizeof%2 ; sse2 register + pshufd %1, %2, q0000 + %else ; sse memory + movd %1, %2 + pshufd %1, %1, 0 + %endif +%endif +%endmacro + +%macro VBROADCASTI128 2 ; dst xmm/ymm, src : 128bits val +%if mmsize > 16 + vbroadcasti128 %1, %2 +%else + mova %1, %2 +%endif +%endmacro + +%macro SHUFFLE_MASK_W 8 + %rep 8 + %if %1>=0x80 + db %1, %1 + %else + db %1*2 + db %1*2+1 + %endif + %rotate 1 + %endrep +%endmacro + +%macro PMOVSXWD 2; dst, src +%if cpuflag(sse4) + pmovsxwd %1, %2 +%else + %ifnidn %1, %2 + mova %1, %2 + %endif + punpcklwd %1, %1 + psrad %1, 16 +%endif +%endmacro + +; Wrapper for non-FMA version of fmaddps +%macro FMULADD_PS 5 + %if cpuflag(fma3) || cpuflag(fma4) + fmaddps %1, %2, %3, %4 + %elifidn %1, %4 + mulps %5, %2, %3 + addps %1, %4, %5 + %else + mulps %1, %2, %3 + addps %1, %4 + %endif +%endmacro + +%macro LSHIFT 2 +%if mmsize > 8 + pslldq %1, %2 +%else + psllq %1, 8*(%2) +%endif +%endmacro + +%macro RSHIFT 2 +%if mmsize > 8 + psrldq %1, %2 +%else + psrlq %1, 8*(%2) +%endif +%endmacro + +%macro MOVHL 2 ; dst, src +%ifidn %1, %2 + punpckhqdq %1, %2 +%elif cpuflag(avx) + punpckhqdq %1, %2, %2 +%elif cpuflag(sse4) + pshufd %1, %2, q3232 ; pshufd is slow on some older CPUs, so only use it on more modern ones +%else + movhlps %1, %2 ; may cause an int/float domain transition and has a dependency on dst +%endif +%endmacro + +; Horizontal Sum of Packed Single precision floats +; The resulting sum is in all elements. +%macro HSUMPS 2 ; dst/src, tmp +%if cpuflag(avx) + %if sizeof%1>=32 ; avx + vperm2f128 %2, %1, %1, (0)*16+(1) + addps %1, %2 + %endif + shufps %2, %1, %1, q1032 + addps %1, %2 + shufps %2, %1, %1, q0321 + addps %1, %2 +%else ; this form is a bit faster than the short avx-like emulation. + movaps %2, %1 + shufps %1, %1, q1032 + addps %1, %2 + movaps %2, %1 + shufps %1, %1, q0321 + addps %1, %2 + ; all %1 members should be equal for as long as float a+b==b+a +%endif +%endmacro + +; Emulate blendvps if not available +; +; src_b is destroyed when using emulation with logical operands +; SSE41 blendv instruction is hard coded to use xmm0 as mask +%macro BLENDVPS 3 ; dst/src_a, src_b, mask +%if cpuflag(avx) + blendvps %1, %1, %2, %3 +%elif cpuflag(sse4) + %ifnidn %3,xmm0 + %error sse41 blendvps uses xmm0 as default 3d operand, you used %3 + %endif + blendvps %1, %2, %3 +%else + xorps %2, %1 + andps %2, %3 + xorps %1, %2 +%endif +%endmacro + +; Emulate pblendvb if not available +; +; src_b is destroyed when using emulation with logical operands +; SSE41 blendv instruction is hard coded to use xmm0 as mask +%macro PBLENDVB 3 ; dst/src_a, src_b, mask +%if cpuflag(avx) + %if cpuflag(avx) && notcpuflag(avx2) && sizeof%1 >= 32 + %error pblendb not possible with ymm on avx1, try blendvps. + %endif + pblendvb %1, %1, %2, %3 +%elif cpuflag(sse4) + %ifnidn %3,xmm0 + %error sse41 pblendvd uses xmm0 as default 3d operand, you used %3 + %endif + pblendvb %1, %2, %3 +%else + pxor %2, %1 + pand %2, %3 + pxor %1, %2 +%endif +%endmacro diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/Makefile new file mode 100644 index 0000000000..5c34f8d949 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/aarch64/Makefile @@ -0,0 +1,7 @@ +OBJS += aarch64/audio_convert_init.o \ + aarch64/resample_init.o + +OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o + +NEON-OBJS += aarch64/audio_convert_neon.o \ + aarch64/resample.o diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/Makefile new file mode 100644 index 0000000000..53ab4626f4 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/arm/Makefile @@ -0,0 +1,8 @@ +OBJS += arm/audio_convert_init.o \ + arm/resample_init.o + + +OBJS-$(CONFIG_NEON_CLOBBER_TEST) += arm/neontest.o + +NEON-OBJS += arm/audio_convert_neon.o \ + arm/resample.o diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/Makefile b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/Makefile new file mode 100644 index 0000000000..fa0641f03f --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/Makefile @@ -0,0 +1,9 @@ +X86ASM-OBJS += x86/audio_convert.o\ + x86/rematrix.o\ + x86/resample.o\ + +OBJS += x86/audio_convert_init.o\ + x86/rematrix_init.o\ + x86/resample_init.o\ + +OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/audio_convert.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/audio_convert.asm new file mode 100644 index 0000000000..d441636d3c --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/audio_convert.asm @@ -0,0 +1,739 @@ +;****************************************************************************** +;* Copyright (c) 2012 Michael Niedermayer +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA 32 +flt2pm31: times 8 dd 4.6566129e-10 +flt2p31 : times 8 dd 2147483648.0 +flt2p15 : times 8 dd 32768.0 + +word_unpack_shuf : db 0, 1, 4, 5, 8, 9,12,13, 2, 3, 6, 7,10,11,14,15 + +SECTION .text + + +;to, from, a/u, log2_outsize, log_intsize, const +%macro PACK_2CH 5-7 +cglobal pack_2ch_%2_to_%1_%3, 3, 4, 6, dst, src, len, src2 + mov src2q , [srcq+gprsize] + mov srcq , [srcq] + mov dstq , [dstq] +%ifidn %3, a + test dstq, mmsize-1 + jne pack_2ch_%2_to_%1_u_int %+ SUFFIX + test srcq, mmsize-1 + jne pack_2ch_%2_to_%1_u_int %+ SUFFIX + test src2q, mmsize-1 + jne pack_2ch_%2_to_%1_u_int %+ SUFFIX +%else +pack_2ch_%2_to_%1_u_int %+ SUFFIX: +%endif + lea srcq , [srcq + (1<<%5)*lenq] + lea src2q, [src2q + (1<<%5)*lenq] + lea dstq , [dstq + (2<<%4)*lenq] + neg lenq + %7 m0,m1,m2,m3,m4,m5 +.next: +%if %4 >= %5 + mov%3 m0, [ srcq +(1<<%5)*lenq] + mova m1, m0 + mov%3 m2, [ src2q+(1<<%5)*lenq] +%if %5 == 1 + punpcklwd m0, m2 + punpckhwd m1, m2 +%else + punpckldq m0, m2 + punpckhdq m1, m2 +%endif + %6 m0,m1,m2,m3,m4,m5 +%else + mov%3 m0, [ srcq +(1<<%5)*lenq] + mov%3 m1, [mmsize + srcq +(1<<%5)*lenq] + mov%3 m2, [ src2q+(1<<%5)*lenq] + mov%3 m3, [mmsize + src2q+(1<<%5)*lenq] + %6 m0,m1,m2,m3,m4,m5 + mova m2, m0 + punpcklwd m0, m1 + punpckhwd m2, m1 + SWAP 1,2 +%endif + mov%3 [ dstq+(2<<%4)*lenq], m0 + mov%3 [ mmsize + dstq+(2<<%4)*lenq], m1 +%if %4 > %5 + mov%3 [2*mmsize + dstq+(2<<%4)*lenq], m2 + mov%3 [3*mmsize + dstq+(2<<%4)*lenq], m3 + add lenq, 4*mmsize/(2<<%4) +%else + add lenq, 2*mmsize/(2<<%4) +%endif + jl .next + REP_RET +%endmacro + +%macro UNPACK_2CH 5-7 +cglobal unpack_2ch_%2_to_%1_%3, 3, 4, 7, dst, src, len, dst2 + mov dst2q , [dstq+gprsize] + mov srcq , [srcq] + mov dstq , [dstq] +%ifidn %3, a + test dstq, mmsize-1 + jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX + test srcq, mmsize-1 + jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX + test dst2q, mmsize-1 + jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX +%else +unpack_2ch_%2_to_%1_u_int %+ SUFFIX: +%endif + lea srcq , [srcq + (2<<%5)*lenq] + lea dstq , [dstq + (1<<%4)*lenq] + lea dst2q, [dst2q + (1<<%4)*lenq] + neg lenq + %7 m0,m1,m2,m3,m4,m5 + mova m6, [word_unpack_shuf] +.next: + mov%3 m0, [ srcq +(2<<%5)*lenq] + mov%3 m2, [ mmsize + srcq +(2<<%5)*lenq] +%if %5 == 1 +%ifidn SUFFIX, _ssse3 + pshufb m0, m6 + mova m1, m0 + pshufb m2, m6 + punpcklqdq m0,m2 + punpckhqdq m1,m2 +%else + mova m1, m0 + punpcklwd m0,m2 + punpckhwd m1,m2 + + mova m2, m0 + punpcklwd m0,m1 + punpckhwd m2,m1 + + mova m1, m0 + punpcklwd m0,m2 + punpckhwd m1,m2 +%endif +%else + mova m1, m0 + shufps m0, m2, 10001000b + shufps m1, m2, 11011101b +%endif +%if %4 < %5 + mov%3 m2, [2*mmsize + srcq +(2<<%5)*lenq] + mova m3, m2 + mov%3 m4, [3*mmsize + srcq +(2<<%5)*lenq] + shufps m2, m4, 10001000b + shufps m3, m4, 11011101b + SWAP 1,2 +%endif + %6 m0,m1,m2,m3,m4,m5 + mov%3 [ dstq+(1<<%4)*lenq], m0 +%if %4 > %5 + mov%3 [ dst2q+(1<<%4)*lenq], m2 + mov%3 [ mmsize + dstq+(1<<%4)*lenq], m1 + mov%3 [ mmsize + dst2q+(1<<%4)*lenq], m3 + add lenq, 2*mmsize/(1<<%4) +%else + mov%3 [ dst2q+(1<<%4)*lenq], m1 + add lenq, mmsize/(1<<%4) +%endif + jl .next + REP_RET +%endmacro + +%macro CONV 5-7 +cglobal %2_to_%1_%3, 3, 3, 6, dst, src, len + mov srcq , [srcq] + mov dstq , [dstq] +%ifidn %3, a + test dstq, mmsize-1 + jne %2_to_%1_u_int %+ SUFFIX + test srcq, mmsize-1 + jne %2_to_%1_u_int %+ SUFFIX +%else +%2_to_%1_u_int %+ SUFFIX: +%endif + lea srcq , [srcq + (1<<%5)*lenq] + lea dstq , [dstq + (1<<%4)*lenq] + neg lenq + %7 m0,m1,m2,m3,m4,m5 +.next: + mov%3 m0, [ srcq +(1<<%5)*lenq] + mov%3 m1, [ mmsize + srcq +(1<<%5)*lenq] +%if %4 < %5 + mov%3 m2, [2*mmsize + srcq +(1<<%5)*lenq] + mov%3 m3, [3*mmsize + srcq +(1<<%5)*lenq] +%endif + %6 m0,m1,m2,m3,m4,m5 + mov%3 [ dstq+(1<<%4)*lenq], m0 + mov%3 [ mmsize + dstq+(1<<%4)*lenq], m1 +%if %4 > %5 + mov%3 [2*mmsize + dstq+(1<<%4)*lenq], m2 + mov%3 [3*mmsize + dstq+(1<<%4)*lenq], m3 + add lenq, 4*mmsize/(1<<%4) +%else + add lenq, 2*mmsize/(1<<%4) +%endif + jl .next +%if mmsize == 8 + emms + RET +%else + REP_RET +%endif +%endmacro + +%macro PACK_6CH 8 +cglobal pack_6ch_%2_to_%1_%3, 2, 8, %6, dst, src, src1, src2, src3, src4, src5, len +%if ARCH_X86_64 + mov lend, r2d +%else + %define lend dword r2m +%endif + mov src1q, [srcq+1*gprsize] + mov src2q, [srcq+2*gprsize] + mov src3q, [srcq+3*gprsize] + mov src4q, [srcq+4*gprsize] + mov src5q, [srcq+5*gprsize] + mov srcq, [srcq] + mov dstq, [dstq] +%ifidn %3, a + test dstq, mmsize-1 + jne pack_6ch_%2_to_%1_u_int %+ SUFFIX + test srcq, mmsize-1 + jne pack_6ch_%2_to_%1_u_int %+ SUFFIX + test src1q, mmsize-1 + jne pack_6ch_%2_to_%1_u_int %+ SUFFIX + test src2q, mmsize-1 + jne pack_6ch_%2_to_%1_u_int %+ SUFFIX + test src3q, mmsize-1 + jne pack_6ch_%2_to_%1_u_int %+ SUFFIX + test src4q, mmsize-1 + jne pack_6ch_%2_to_%1_u_int %+ SUFFIX + test src5q, mmsize-1 + jne pack_6ch_%2_to_%1_u_int %+ SUFFIX +%else +pack_6ch_%2_to_%1_u_int %+ SUFFIX: +%endif + sub src1q, srcq + sub src2q, srcq + sub src3q, srcq + sub src4q, srcq + sub src5q, srcq + %8 x,x,x,x,m7,x +.loop: + mov%3 m0, [srcq ] + mov%3 m1, [srcq+src1q] + mov%3 m2, [srcq+src2q] + mov%3 m3, [srcq+src3q] + mov%3 m4, [srcq+src4q] + mov%3 m5, [srcq+src5q] +%if cpuflag(sse) + SBUTTERFLYPS 0, 1, 6 + SBUTTERFLYPS 2, 3, 6 + SBUTTERFLYPS 4, 5, 6 + +%if cpuflag(avx) + blendps m6, m4, m0, 1100b +%else + movaps m6, m4 + shufps m4, m0, q3210 + SWAP 4,6 +%endif + movlhps m0, m2 + movhlps m4, m2 +%if cpuflag(avx) + blendps m2, m5, m1, 1100b +%else + movaps m2, m5 + shufps m5, m1, q3210 + SWAP 2,5 +%endif + movlhps m1, m3 + movhlps m5, m3 + + %7 m0,m6,x,x,m7,m3 + %7 m4,m1,x,x,m7,m3 + %7 m2,m5,x,x,m7,m3 + + mov %+ %3 %+ ps [dstq ], m0 + mov %+ %3 %+ ps [dstq+16], m6 + mov %+ %3 %+ ps [dstq+32], m4 + mov %+ %3 %+ ps [dstq+48], m1 + mov %+ %3 %+ ps [dstq+64], m2 + mov %+ %3 %+ ps [dstq+80], m5 +%else ; mmx + SBUTTERFLY dq, 0, 1, 6 + SBUTTERFLY dq, 2, 3, 6 + SBUTTERFLY dq, 4, 5, 6 + + movq [dstq ], m0 + movq [dstq+ 8], m2 + movq [dstq+16], m4 + movq [dstq+24], m1 + movq [dstq+32], m3 + movq [dstq+40], m5 +%endif + add srcq, mmsize + add dstq, mmsize*6 + sub lend, mmsize/4 + jg .loop +%if mmsize == 8 + emms + RET +%else + REP_RET +%endif +%endmacro + +%macro UNPACK_6CH 8 +cglobal unpack_6ch_%2_to_%1_%3, 2, 8, %6, dst, src, dst1, dst2, dst3, dst4, dst5, len +%if ARCH_X86_64 + mov lend, r2d +%else + %define lend dword r2m +%endif + mov dst1q, [dstq+1*gprsize] + mov dst2q, [dstq+2*gprsize] + mov dst3q, [dstq+3*gprsize] + mov dst4q, [dstq+4*gprsize] + mov dst5q, [dstq+5*gprsize] + mov dstq, [dstq] + mov srcq, [srcq] +%ifidn %3, a + test dstq, mmsize-1 + jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX + test srcq, mmsize-1 + jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX + test dst1q, mmsize-1 + jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX + test dst2q, mmsize-1 + jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX + test dst3q, mmsize-1 + jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX + test dst4q, mmsize-1 + jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX + test dst5q, mmsize-1 + jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX +%else +unpack_6ch_%2_to_%1_u_int %+ SUFFIX: +%endif + sub dst1q, dstq + sub dst2q, dstq + sub dst3q, dstq + sub dst4q, dstq + sub dst5q, dstq + %8 x,x,x,x,m7,x +.loop: + mov%3 m0, [srcq ] + mov%3 m1, [srcq+16] + mov%3 m2, [srcq+32] + mov%3 m3, [srcq+48] + mov%3 m4, [srcq+64] + mov%3 m5, [srcq+80] + + SBUTTERFLYPS 0, 3, 6 + SBUTTERFLYPS 1, 4, 6 + SBUTTERFLYPS 2, 5, 6 + SBUTTERFLYPS 0, 4, 6 + SBUTTERFLYPS 3, 2, 6 + SBUTTERFLYPS 1, 5, 6 + SWAP 1, 4 + SWAP 2, 3 + + %7 m0,m1,x,x,m7,m6 + %7 m2,m3,x,x,m7,m6 + %7 m4,m5,x,x,m7,m6 + + mov %+ %3 %+ ps [dstq ], m0 + mov %+ %3 %+ ps [dstq+dst1q], m1 + mov %+ %3 %+ ps [dstq+dst2q], m2 + mov %+ %3 %+ ps [dstq+dst3q], m3 + mov %+ %3 %+ ps [dstq+dst4q], m4 + mov %+ %3 %+ ps [dstq+dst5q], m5 + + add srcq, mmsize*6 + add dstq, mmsize + sub lend, mmsize/4 + jg .loop + REP_RET +%endmacro + +%define PACK_8CH_GPRS (10 * ARCH_X86_64) + ((6 + HAVE_ALIGNED_STACK) * ARCH_X86_32) + +%macro PACK_8CH 8 +cglobal pack_8ch_%2_to_%1_%3, 2, PACK_8CH_GPRS, %6, ARCH_X86_32*48, dst, src, len, src1, src2, src3, src4, src5, src6, src7 + mov dstq, [dstq] +%if ARCH_X86_32 + DEFINE_ARGS dst, src, src2, src3, src4, src5, src6 + %define lend dword r2m + %define src1q r0q + %define src1m dword [rsp+32] +%if HAVE_ALIGNED_STACK == 0 + DEFINE_ARGS dst, src, src2, src3, src5, src6 + %define src4q r0q + %define src4m dword [rsp+36] +%endif + %define src7q r0q + %define src7m dword [rsp+40] + mov dstm, dstq +%endif + mov src7q, [srcq+7*gprsize] + mov src6q, [srcq+6*gprsize] +%if ARCH_X86_32 + mov src7m, src7q +%endif + mov src5q, [srcq+5*gprsize] + mov src4q, [srcq+4*gprsize] + mov src3q, [srcq+3*gprsize] +%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0 + mov src4m, src4q +%endif + mov src2q, [srcq+2*gprsize] + mov src1q, [srcq+1*gprsize] + mov srcq, [srcq] +%ifidn %3, a +%if ARCH_X86_32 + test dstmp, mmsize-1 +%else + test dstq, mmsize-1 +%endif + jne pack_8ch_%2_to_%1_u_int %+ SUFFIX + test srcq, mmsize-1 + jne pack_8ch_%2_to_%1_u_int %+ SUFFIX + test src1q, mmsize-1 + jne pack_8ch_%2_to_%1_u_int %+ SUFFIX + test src2q, mmsize-1 + jne pack_8ch_%2_to_%1_u_int %+ SUFFIX + test src3q, mmsize-1 + jne pack_8ch_%2_to_%1_u_int %+ SUFFIX +%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0 + test src4m, mmsize-1 +%else + test src4q, mmsize-1 +%endif + jne pack_8ch_%2_to_%1_u_int %+ SUFFIX + test src5q, mmsize-1 + jne pack_8ch_%2_to_%1_u_int %+ SUFFIX + test src6q, mmsize-1 + jne pack_8ch_%2_to_%1_u_int %+ SUFFIX +%if ARCH_X86_32 + test src7m, mmsize-1 +%else + test src7q, mmsize-1 +%endif + jne pack_8ch_%2_to_%1_u_int %+ SUFFIX +%else +pack_8ch_%2_to_%1_u_int %+ SUFFIX: +%endif + sub src1q, srcq + sub src2q, srcq + sub src3q, srcq +%if ARCH_X86_64 || HAVE_ALIGNED_STACK + sub src4q, srcq +%else + sub src4m, srcq +%endif + sub src5q, srcq + sub src6q, srcq +%if ARCH_X86_64 + sub src7q, srcq +%else + mov src1m, src1q + sub src7m, srcq +%endif + +%if ARCH_X86_64 + %8 x,x,x,x,m9,x +%elifidn %1, int32 + %define m9 [flt2p31] +%else + %define m9 [flt2pm31] +%endif + +.loop: + mov%3 m0, [srcq ] + mov%3 m1, [srcq+src1q] + mov%3 m2, [srcq+src2q] +%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0 + mov src4q, src4m +%endif + mov%3 m3, [srcq+src3q] + mov%3 m4, [srcq+src4q] + mov%3 m5, [srcq+src5q] +%if ARCH_X86_32 + mov src7q, src7m +%endif + mov%3 m6, [srcq+src6q] + mov%3 m7, [srcq+src7q] + +%if ARCH_X86_64 + TRANSPOSE8x4D 0, 1, 2, 3, 4, 5, 6, 7, 8 + + %7 m0,m1,x,x,m9,m8 + %7 m2,m3,x,x,m9,m8 + %7 m4,m5,x,x,m9,m8 + %7 m6,m7,x,x,m9,m8 + + mov%3 [dstq], m0 +%else + mov dstq, dstm + + TRANSPOSE8x4D 0, 1, 2, 3, 4, 5, 6, 7, [rsp], [rsp+16], 1 + + %7 m0,m1,x,x,m9,m2 + mova m2, [rsp] + mov%3 [dstq], m0 + %7 m2,m3,x,x,m9,m0 + %7 m4,m5,x,x,m9,m0 + %7 m6,m7,x,x,m9,m0 + +%endif + + mov%3 [dstq+16], m1 + mov%3 [dstq+32], m2 + mov%3 [dstq+48], m3 + mov%3 [dstq+64], m4 + mov%3 [dstq+80], m5 + mov%3 [dstq+96], m6 + mov%3 [dstq+112], m7 + + add srcq, mmsize + add dstq, mmsize*8 +%if ARCH_X86_32 + mov dstm, dstq + mov src1q, src1m +%endif + sub lend, mmsize/4 + jg .loop + REP_RET +%endmacro + +%macro INT16_TO_INT32_N 6 + pxor m2, m2 + pxor m3, m3 + punpcklwd m2, m1 + punpckhwd m3, m1 + SWAP 4,0 + pxor m0, m0 + pxor m1, m1 + punpcklwd m0, m4 + punpckhwd m1, m4 +%endmacro + +%macro INT32_TO_INT16_N 6 + psrad m0, 16 + psrad m1, 16 + psrad m2, 16 + psrad m3, 16 + packssdw m0, m1 + packssdw m2, m3 + SWAP 1,2 +%endmacro + +%macro INT32_TO_FLOAT_INIT 6 + mova %5, [flt2pm31] +%endmacro +%macro INT32_TO_FLOAT_N 6 + cvtdq2ps %1, %1 + cvtdq2ps %2, %2 + mulps %1, %1, %5 + mulps %2, %2, %5 +%endmacro + +%macro FLOAT_TO_INT32_INIT 6 + mova %5, [flt2p31] +%endmacro +%macro FLOAT_TO_INT32_N 6 + mulps %1, %5 + mulps %2, %5 + cvtps2dq %6, %1 + cmpps %1, %1, %5, 5 + paddd %1, %6 + cvtps2dq %6, %2 + cmpps %2, %2, %5, 5 + paddd %2, %6 +%endmacro + +%macro INT16_TO_FLOAT_INIT 6 + mova m5, [flt2pm31] +%endmacro +%macro INT16_TO_FLOAT_N 6 + INT16_TO_INT32_N %1,%2,%3,%4,%5,%6 + cvtdq2ps m0, m0 + cvtdq2ps m1, m1 + cvtdq2ps m2, m2 + cvtdq2ps m3, m3 + mulps m0, m0, m5 + mulps m1, m1, m5 + mulps m2, m2, m5 + mulps m3, m3, m5 +%endmacro + +%macro FLOAT_TO_INT16_INIT 6 + mova m5, [flt2p15] +%endmacro +%macro FLOAT_TO_INT16_N 6 + mulps m0, m5 + mulps m1, m5 + mulps m2, m5 + mulps m3, m5 + cvtps2dq m0, m0 + cvtps2dq m1, m1 + packssdw m0, m1 + cvtps2dq m1, m2 + cvtps2dq m3, m3 + packssdw m1, m3 +%endmacro + +%macro NOP_N 0-6 +%endmacro + +INIT_MMX mmx +CONV int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N +CONV int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N +CONV int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N +CONV int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N + +PACK_6CH float, float, u, 2, 2, 0, NOP_N, NOP_N +PACK_6CH float, float, a, 2, 2, 0, NOP_N, NOP_N + +INIT_XMM sse +PACK_6CH float, float, u, 2, 2, 7, NOP_N, NOP_N +PACK_6CH float, float, a, 2, 2, 7, NOP_N, NOP_N + +UNPACK_6CH float, float, u, 2, 2, 7, NOP_N, NOP_N +UNPACK_6CH float, float, a, 2, 2, 7, NOP_N, NOP_N + +INIT_XMM sse2 +CONV int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N +CONV int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N +CONV int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N +CONV int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N + +PACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N +PACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N +PACK_2CH int32, int32, u, 2, 2, NOP_N, NOP_N +PACK_2CH int32, int32, a, 2, 2, NOP_N, NOP_N +PACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N +PACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N +PACK_2CH int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N +PACK_2CH int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N + +UNPACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N +UNPACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N +UNPACK_2CH int32, int32, u, 2, 2, NOP_N, NOP_N +UNPACK_2CH int32, int32, a, 2, 2, NOP_N, NOP_N +UNPACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N +UNPACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N +UNPACK_2CH int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N +UNPACK_2CH int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N + +CONV float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +CONV float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +CONV int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +CONV int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +CONV float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT +CONV float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT +CONV int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT +CONV int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT + +PACK_2CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +PACK_2CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +PACK_2CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +PACK_2CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +PACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT +PACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT +PACK_2CH int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT +PACK_2CH int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT + +UNPACK_2CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +UNPACK_2CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +UNPACK_2CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +UNPACK_2CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +UNPACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT +UNPACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT +UNPACK_2CH int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT +UNPACK_2CH int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT + +PACK_6CH float, int32, u, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +PACK_6CH float, int32, a, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +PACK_6CH int32, float, u, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +PACK_6CH int32, float, a, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT + +UNPACK_6CH float, int32, u, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +UNPACK_6CH float, int32, a, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +UNPACK_6CH int32, float, u, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +UNPACK_6CH int32, float, a, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT + +PACK_8CH float, float, u, 2, 2, 9, NOP_N, NOP_N +PACK_8CH float, float, a, 2, 2, 9, NOP_N, NOP_N + +PACK_8CH float, int32, u, 2, 2, 10, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +PACK_8CH float, int32, a, 2, 2, 10, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +PACK_8CH int32, float, u, 2, 2, 10, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +PACK_8CH int32, float, a, 2, 2, 10, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT + +INIT_XMM ssse3 +UNPACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N +UNPACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N +UNPACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N +UNPACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N +UNPACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT +UNPACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT + +%if HAVE_AVX_EXTERNAL +INIT_XMM avx +PACK_6CH float, float, u, 2, 2, 8, NOP_N, NOP_N +PACK_6CH float, float, a, 2, 2, 8, NOP_N, NOP_N + +UNPACK_6CH float, float, u, 2, 2, 8, NOP_N, NOP_N +UNPACK_6CH float, float, a, 2, 2, 8, NOP_N, NOP_N + +PACK_6CH float, int32, u, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +PACK_6CH float, int32, a, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +PACK_6CH int32, float, u, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +PACK_6CH int32, float, a, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT + +UNPACK_6CH float, int32, u, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +UNPACK_6CH float, int32, a, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +UNPACK_6CH int32, float, u, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +UNPACK_6CH int32, float, a, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT + +PACK_8CH float, float, u, 2, 2, 9, NOP_N, NOP_N +PACK_8CH float, float, a, 2, 2, 9, NOP_N, NOP_N + +PACK_8CH float, int32, u, 2, 2, 10, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +PACK_8CH float, int32, a, 2, 2, 10, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +PACK_8CH int32, float, u, 2, 2, 10, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +PACK_8CH int32, float, a, 2, 2, 10, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT + +INIT_YMM avx +CONV float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +CONV float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT +%endif + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +CONV int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +CONV int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT +%endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/rematrix.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/rematrix.asm new file mode 100644 index 0000000000..7984b9a729 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/rematrix.asm @@ -0,0 +1,250 @@ +;****************************************************************************** +;* Copyright (c) 2012 Michael Niedermayer +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + + +SECTION_RODATA 32 +dw1: times 8 dd 1 +w1 : times 16 dw 1 + +SECTION .text + +%macro MIX2_FLT 1 +cglobal mix_2_1_%1_float, 7, 7, 6, out, in1, in2, coeffp, index1, index2, len +%ifidn %1, a + test in1q, mmsize-1 + jne mix_2_1_float_u_int %+ SUFFIX + test in2q, mmsize-1 + jne mix_2_1_float_u_int %+ SUFFIX + test outq, mmsize-1 + jne mix_2_1_float_u_int %+ SUFFIX +%else +mix_2_1_float_u_int %+ SUFFIX: +%endif + VBROADCASTSS m4, [coeffpq + 4*index1q] + VBROADCASTSS m5, [coeffpq + 4*index2q] + shl lend , 2 + add in1q , lenq + add in2q , lenq + add outq , lenq + neg lenq +.next: +%ifidn %1, a + mulps m0, m4, [in1q + lenq ] + mulps m1, m5, [in2q + lenq ] + mulps m2, m4, [in1q + lenq + mmsize] + mulps m3, m5, [in2q + lenq + mmsize] +%else + movu m0, [in1q + lenq ] + movu m1, [in2q + lenq ] + movu m2, [in1q + lenq + mmsize] + movu m3, [in2q + lenq + mmsize] + mulps m0, m0, m4 + mulps m1, m1, m5 + mulps m2, m2, m4 + mulps m3, m3, m5 +%endif + addps m0, m0, m1 + addps m2, m2, m3 + mov%1 [outq + lenq ], m0 + mov%1 [outq + lenq + mmsize], m2 + add lenq, mmsize*2 + jl .next + REP_RET +%endmacro + +%macro MIX1_FLT 1 +cglobal mix_1_1_%1_float, 5, 5, 3, out, in, coeffp, index, len +%ifidn %1, a + test inq, mmsize-1 + jne mix_1_1_float_u_int %+ SUFFIX + test outq, mmsize-1 + jne mix_1_1_float_u_int %+ SUFFIX +%else +mix_1_1_float_u_int %+ SUFFIX: +%endif + VBROADCASTSS m2, [coeffpq + 4*indexq] + shl lenq , 2 + add inq , lenq + add outq , lenq + neg lenq +.next: +%ifidn %1, a + mulps m0, m2, [inq + lenq ] + mulps m1, m2, [inq + lenq + mmsize] +%else + movu m0, [inq + lenq ] + movu m1, [inq + lenq + mmsize] + mulps m0, m0, m2 + mulps m1, m1, m2 +%endif + mov%1 [outq + lenq ], m0 + mov%1 [outq + lenq + mmsize], m1 + add lenq, mmsize*2 + jl .next + REP_RET +%endmacro + +%macro MIX1_INT16 1 +cglobal mix_1_1_%1_int16, 5, 5, 6, out, in, coeffp, index, len +%ifidn %1, a + test inq, mmsize-1 + jne mix_1_1_int16_u_int %+ SUFFIX + test outq, mmsize-1 + jne mix_1_1_int16_u_int %+ SUFFIX +%else +mix_1_1_int16_u_int %+ SUFFIX: +%endif + movd m4, [coeffpq + 4*indexq] + SPLATW m5, m4 + psllq m4, 32 + psrlq m4, 48 + mova m0, [w1] + psllw m0, m4 + psrlw m0, 1 + punpcklwd m5, m0 + add lenq , lenq + add inq , lenq + add outq , lenq + neg lenq +.next: + mov%1 m0, [inq + lenq ] + mov%1 m2, [inq + lenq + mmsize] + mova m1, m0 + mova m3, m2 + punpcklwd m0, [w1] + punpckhwd m1, [w1] + punpcklwd m2, [w1] + punpckhwd m3, [w1] + pmaddwd m0, m5 + pmaddwd m1, m5 + pmaddwd m2, m5 + pmaddwd m3, m5 + psrad m0, m4 + psrad m1, m4 + psrad m2, m4 + psrad m3, m4 + packssdw m0, m1 + packssdw m2, m3 + mov%1 [outq + lenq ], m0 + mov%1 [outq + lenq + mmsize], m2 + add lenq, mmsize*2 + jl .next +%if mmsize == 8 + emms + RET +%else + REP_RET +%endif +%endmacro + +%macro MIX2_INT16 1 +cglobal mix_2_1_%1_int16, 7, 7, 8, out, in1, in2, coeffp, index1, index2, len +%ifidn %1, a + test in1q, mmsize-1 + jne mix_2_1_int16_u_int %+ SUFFIX + test in2q, mmsize-1 + jne mix_2_1_int16_u_int %+ SUFFIX + test outq, mmsize-1 + jne mix_2_1_int16_u_int %+ SUFFIX +%else +mix_2_1_int16_u_int %+ SUFFIX: +%endif + movd m4, [coeffpq + 4*index1q] + movd m6, [coeffpq + 4*index2q] + SPLATW m5, m4 + SPLATW m6, m6 + psllq m4, 32 + psrlq m4, 48 + mova m7, [dw1] + pslld m7, m4 + psrld m7, 1 + punpcklwd m5, m6 + add lend , lend + add in1q , lenq + add in2q , lenq + add outq , lenq + neg lenq +.next: + mov%1 m0, [in1q + lenq ] + mov%1 m2, [in2q + lenq ] + mova m1, m0 + punpcklwd m0, m2 + punpckhwd m1, m2 + + mov%1 m2, [in1q + lenq + mmsize] + mov%1 m6, [in2q + lenq + mmsize] + mova m3, m2 + punpcklwd m2, m6 + punpckhwd m3, m6 + + pmaddwd m0, m5 + pmaddwd m1, m5 + pmaddwd m2, m5 + pmaddwd m3, m5 + paddd m0, m7 + paddd m1, m7 + paddd m2, m7 + paddd m3, m7 + psrad m0, m4 + psrad m1, m4 + psrad m2, m4 + psrad m3, m4 + packssdw m0, m1 + packssdw m2, m3 + mov%1 [outq + lenq ], m0 + mov%1 [outq + lenq + mmsize], m2 + add lenq, mmsize*2 + jl .next +%if mmsize == 8 + emms + RET +%else + REP_RET +%endif +%endmacro + + +INIT_MMX mmx +MIX1_INT16 u +MIX1_INT16 a +MIX2_INT16 u +MIX2_INT16 a + +INIT_XMM sse +MIX2_FLT u +MIX2_FLT a +MIX1_FLT u +MIX1_FLT a + +INIT_XMM sse2 +MIX1_INT16 u +MIX1_INT16 a +MIX2_INT16 u +MIX2_INT16 a + +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +MIX2_FLT u +MIX2_FLT a +MIX1_FLT u +MIX1_FLT a +%endif diff --git a/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/resample.asm b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/resample.asm new file mode 100644 index 0000000000..7107cf9d42 --- /dev/null +++ b/trunk/3rdparty/ffmpeg-4.2-fit/libswresample/x86/resample.asm @@ -0,0 +1,619 @@ +;****************************************************************************** +;* Copyright (c) 2012 Michael Niedermayer +;* Copyright (c) 2014 James Almer gmail.com> +;* Copyright (c) 2014 Ronald S. Bultje +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +%if ARCH_X86_64 +%define pointer resq +%else +%define pointer resd +%endif + +struc ResampleContext + .av_class: pointer 1 + .filter_bank: pointer 1 + .filter_length: resd 1 + .filter_alloc: resd 1 + .ideal_dst_incr: resd 1 + .dst_incr: resd 1 + .dst_incr_div: resd 1 + .dst_incr_mod: resd 1 + .index: resd 1 + .frac: resd 1 + .src_incr: resd 1 + .compensation_distance: resd 1 + .phase_count: resd 1 + + ; there's a few more here but we only care about the first few +endstruc + +SECTION_RODATA + +pf_1: dd 1.0 +pdbl_1: dq 1.0 +pd_0x4000: dd 0x4000 + +SECTION .text + +; FIXME remove unneeded variables (index_incr, phase_mask) +%macro RESAMPLE_FNS 3-5 ; format [float or int16], bps, log2_bps, float op suffix [s or d], 1.0 constant +; int resample_common_$format(ResampleContext *ctx, $format *dst, +; const $format *src, int size, int update_ctx) +%if ARCH_X86_64 ; unix64 and win64 +cglobal resample_common_%1, 0, 15, 2, ctx, dst, src, phase_count, index, frac, \ + dst_incr_mod, size, min_filter_count_x4, \ + min_filter_len_x4, dst_incr_div, src_incr, \ + phase_mask, dst_end, filter_bank + + ; use red-zone for variable storage +%define ctx_stackq [rsp-0x8] +%define src_stackq [rsp-0x10] +%if WIN64 +%define update_context_stackd r4m +%else ; unix64 +%define update_context_stackd [rsp-0x14] +%endif + + ; load as many variables in registers as possible; for the rest, store + ; on stack so that we have 'ctx' available as one extra register + mov sized, r3d +%if UNIX64 + mov update_context_stackd, r4d +%endif + mov indexd, [ctxq+ResampleContext.index] + mov fracd, [ctxq+ResampleContext.frac] + mov dst_incr_modd, [ctxq+ResampleContext.dst_incr_mod] + mov filter_bankq, [ctxq+ResampleContext.filter_bank] + mov src_incrd, [ctxq+ResampleContext.src_incr] + mov ctx_stackq, ctxq + mov min_filter_len_x4d, [ctxq+ResampleContext.filter_length] + mov dst_incr_divd, [ctxq+ResampleContext.dst_incr_div] + shl min_filter_len_x4d, %3 + lea dst_endq, [dstq+sizeq*%2] + +%if UNIX64 + mov ecx, [ctxq+ResampleContext.phase_count] + mov edi, [ctxq+ResampleContext.filter_alloc] + + DEFINE_ARGS filter_alloc, dst, src, phase_count, index, frac, dst_incr_mod, \ + filter, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \ + src_incr, phase_mask, dst_end, filter_bank +%elif WIN64 + mov R9d, [ctxq+ResampleContext.filter_alloc] + mov ecx, [ctxq+ResampleContext.phase_count] + + DEFINE_ARGS phase_count, dst, src, filter_alloc, index, frac, dst_incr_mod, \ + filter, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \ + src_incr, phase_mask, dst_end, filter_bank +%endif + + neg min_filter_len_x4q + sub filter_bankq, min_filter_len_x4q + sub srcq, min_filter_len_x4q + mov src_stackq, srcq +%else ; x86-32 +cglobal resample_common_%1, 1, 7, 2, ctx, phase_count, dst, frac, \ + index, min_filter_length_x4, filter_bank + + ; push temp variables to stack +%define ctx_stackq r0mp +%define src_stackq r2mp +%define update_context_stackd r4m + + mov dstq, r1mp + mov r3, r3mp + lea r3, [dstq+r3*%2] + PUSH dword [ctxq+ResampleContext.dst_incr_div] + PUSH dword [ctxq+ResampleContext.dst_incr_mod] + PUSH dword [ctxq+ResampleContext.filter_alloc] + PUSH r3 + PUSH dword [ctxq+ResampleContext.phase_count] ; unneeded replacement for phase_mask + PUSH dword [ctxq+ResampleContext.src_incr] + mov min_filter_length_x4d, [ctxq+ResampleContext.filter_length] + mov indexd, [ctxq+ResampleContext.index] + shl min_filter_length_x4d, %3 + mov fracd, [ctxq+ResampleContext.frac] + neg min_filter_length_x4q + mov filter_bankq, [ctxq+ResampleContext.filter_bank] + sub r2mp, min_filter_length_x4q + sub filter_bankq, min_filter_length_x4q + PUSH min_filter_length_x4q + PUSH filter_bankq + mov phase_countd, [ctxq+ResampleContext.phase_count] + + DEFINE_ARGS src, phase_count, dst, frac, index, min_filter_count_x4, filter + +%define filter_bankq dword [rsp+0x0] +%define min_filter_length_x4q dword [rsp+0x4] +%define src_incrd dword [rsp+0x8] +%define phase_maskd dword [rsp+0xc] +%define dst_endq dword [rsp+0x10] +%define filter_allocd dword [rsp+0x14] +%define dst_incr_modd dword [rsp+0x18] +%define dst_incr_divd dword [rsp+0x1c] + + mov srcq, r2mp +%endif + +.loop: + mov filterd, filter_allocd + imul filterd, indexd +%if ARCH_X86_64 + mov min_filter_count_x4q, min_filter_len_x4q + lea filterq, [filter_bankq+filterq*%2] +%else ; x86-32 + mov min_filter_count_x4q, filter_bankq + lea filterq, [min_filter_count_x4q+filterq*%2] + mov min_filter_count_x4q, min_filter_length_x4q +%endif +%ifidn %1, int16 + movd m0, [pd_0x4000] +%else ; float/double + xorps m0, m0, m0 +%endif + + align 16 +.inner_loop: + movu m1, [srcq+min_filter_count_x4q*1] +%ifidn %1, int16 +%if cpuflag(xop) + vpmadcswd m0, m1, [filterq+min_filter_count_x4q*1], m0 +%else + pmaddwd m1, [filterq+min_filter_count_x4q*1] + paddd m0, m1 +%endif +%else ; float/double +%if cpuflag(fma4) || cpuflag(fma3) + fmaddp%4 m0, m1, [filterq+min_filter_count_x4q*1], m0 +%else + mulp%4 m1, m1, [filterq+min_filter_count_x4q*1] + addp%4 m0, m0, m1 +%endif ; cpuflag +%endif + add min_filter_count_x4q, mmsize + js .inner_loop + +%ifidn %1, int16 + HADDD m0, m1 + psrad m0, 15 + add fracd, dst_incr_modd + packssdw m0, m0 + add indexd, dst_incr_divd + movd [dstq], m0 +%else ; float/double + ; horizontal sum & store +%if mmsize == 32 + vextractf128 xm1, m0, 0x1 + addp%4 xm0, xm1 +%endif + movhlps xm1, xm0 +%ifidn %1, float + addps xm0, xm1 + shufps xm1, xm0, xm0, q0001 +%endif + add fracd, dst_incr_modd + addp%4 xm0, xm1 + add indexd, dst_incr_divd + movs%4 [dstq], xm0 +%endif + cmp fracd, src_incrd + jl .skip + sub fracd, src_incrd + inc indexd + +%if UNIX64 + DEFINE_ARGS filter_alloc, dst, src, phase_count, index, frac, dst_incr_mod, \ + index_incr, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \ + src_incr, phase_mask, dst_end, filter_bank +%elif WIN64 + DEFINE_ARGS phase_count, dst, src, filter_alloc, index, frac, dst_incr_mod, \ + index_incr, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \ + src_incr, phase_mask, dst_end, filter_bank +%else ; x86-32 + DEFINE_ARGS src, phase_count, dst, frac, index, index_incr +%endif + +.skip: + add dstq, %2 + cmp indexd, phase_countd + jb .index_skip +.index_while: + sub indexd, phase_countd + lea srcq, [srcq+%2] + cmp indexd, phase_countd + jnb .index_while +.index_skip: + cmp dstq, dst_endq + jne .loop + +%if ARCH_X86_64 + DEFINE_ARGS ctx, dst, src, phase_count, index, frac +%else ; x86-32 + DEFINE_ARGS src, ctx, update_context, frac, index +%endif + + cmp dword update_context_stackd, 0 + jz .skip_store + ; strictly speaking, the function should always return the consumed + ; number of bytes; however, we only use the value if update_context + ; is true, so let's just leave it uninitialized otherwise + mov ctxq, ctx_stackq + movifnidn rax, srcq + mov [ctxq+ResampleContext.frac ], fracd + sub rax, src_stackq + mov [ctxq+ResampleContext.index], indexd + shr rax, %3 + +.skip_store: +%if ARCH_X86_32 + ADD rsp, 0x20 +%endif + RET + +; int resample_linear_$format(ResampleContext *ctx, float *dst, +; const float *src, int size, int update_ctx) +%if ARCH_X86_64 ; unix64 and win64 +%if UNIX64 +cglobal resample_linear_%1, 0, 15, 5, ctx, dst, phase_mask, phase_count, index, frac, \ + size, dst_incr_mod, min_filter_count_x4, \ + min_filter_len_x4, dst_incr_div, src_incr, \ + src, dst_end, filter_bank + + mov srcq, r2mp +%else ; win64 +cglobal resample_linear_%1, 0, 15, 5, ctx, phase_mask, src, phase_count, index, frac, \ + size, dst_incr_mod, min_filter_count_x4, \ + min_filter_len_x4, dst_incr_div, src_incr, \ + dst, dst_end, filter_bank + + mov dstq, r1mp +%endif + + ; use red-zone for variable storage +%define ctx_stackq [rsp-0x8] +%define src_stackq [rsp-0x10] +%define phase_mask_stackd [rsp-0x14] +%if WIN64 +%define update_context_stackd r4m +%else ; unix64 +%define update_context_stackd [rsp-0x18] +%endif + + ; load as many variables in registers as possible; for the rest, store + ; on stack so that we have 'ctx' available as one extra register + mov sized, r3d +%if UNIX64 + mov update_context_stackd, r4d +%endif + mov indexd, [ctxq+ResampleContext.index] + mov fracd, [ctxq+ResampleContext.frac] + mov dst_incr_modd, [ctxq+ResampleContext.dst_incr_mod] + mov filter_bankq, [ctxq+ResampleContext.filter_bank] + mov src_incrd, [ctxq+ResampleContext.src_incr] + mov ctx_stackq, ctxq + mov min_filter_len_x4d, [ctxq+ResampleContext.filter_length] +%ifidn %1, int16 + movd m4, [pd_0x4000] +%else ; float/double + cvtsi2s%4 xm0, src_incrd + movs%4 xm4, [%5] + divs%4 xm4, xm0 +%endif + mov dst_incr_divd, [ctxq+ResampleContext.dst_incr_div] + shl min_filter_len_x4d, %3 + lea dst_endq, [dstq+sizeq*%2] + +%if UNIX64 + mov ecx, [ctxq+ResampleContext.phase_count] + mov edi, [ctxq+ResampleContext.filter_alloc] + + DEFINE_ARGS filter_alloc, dst, filter2, phase_count, index, frac, filter1, \ + dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \ + dst_incr_div, src_incr, src, dst_end, filter_bank +%elif WIN64 + mov R9d, [ctxq+ResampleContext.filter_alloc] + mov ecx, [ctxq+ResampleContext.phase_count] + + DEFINE_ARGS phase_count, filter2, src, filter_alloc, index, frac, filter1, \ + dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \ + dst_incr_div, src_incr, dst, dst_end, filter_bank +%endif + + neg min_filter_len_x4q + sub filter_bankq, min_filter_len_x4q + sub srcq, min_filter_len_x4q + mov src_stackq, srcq +%else ; x86-32 +cglobal resample_linear_%1, 1, 7, 5, ctx, min_filter_length_x4, filter2, \ + frac, index, dst, filter_bank + + ; push temp variables to stack +%define ctx_stackq r0mp +%define src_stackq r2mp +%define update_context_stackd r4m + + mov dstq, r1mp + mov r3, r3mp + lea r3, [dstq+r3*%2] + PUSH dword [ctxq+ResampleContext.dst_incr_div] + PUSH r3 + mov r3, dword [ctxq+ResampleContext.filter_alloc] + PUSH dword [ctxq+ResampleContext.dst_incr_mod] + PUSH r3 + shl r3, %3 + PUSH r3 + mov r3, dword [ctxq+ResampleContext.src_incr] + PUSH dword [ctxq+ResampleContext.phase_count] ; unneeded replacement of phase_mask + PUSH r3d +%ifidn %1, int16 + movd m4, [pd_0x4000] +%else ; float/double + cvtsi2s%4 xm0, r3d + movs%4 xm4, [%5] + divs%4 xm4, xm0 +%endif + mov min_filter_length_x4d, [ctxq+ResampleContext.filter_length] + mov indexd, [ctxq+ResampleContext.index] + shl min_filter_length_x4d, %3 + mov fracd, [ctxq+ResampleContext.frac] + neg min_filter_length_x4q + mov filter_bankq, [ctxq+ResampleContext.filter_bank] + sub r2mp, min_filter_length_x4q + sub filter_bankq, min_filter_length_x4q + PUSH min_filter_length_x4q + PUSH filter_bankq + PUSH dword [ctxq+ResampleContext.phase_count] + + DEFINE_ARGS filter1, min_filter_count_x4, filter2, frac, index, dst, src + +%define phase_count_stackd dword [rsp+0x0] +%define filter_bankq dword [rsp+0x4] +%define min_filter_length_x4q dword [rsp+0x8] +%define src_incrd dword [rsp+0xc] +%define phase_mask_stackd dword [rsp+0x10] +%define filter_alloc_x4q dword [rsp+0x14] +%define filter_allocd dword [rsp+0x18] +%define dst_incr_modd dword [rsp+0x1c] +%define dst_endq dword [rsp+0x20] +%define dst_incr_divd dword [rsp+0x24] + + mov srcq, r2mp +%endif + +.loop: + mov filter1d, filter_allocd + imul filter1d, indexd +%if ARCH_X86_64 + mov min_filter_count_x4q, min_filter_len_x4q + lea filter1q, [filter_bankq+filter1q*%2] + lea filter2q, [filter1q+filter_allocq*%2] +%else ; x86-32 + mov min_filter_count_x4q, filter_bankq + lea filter1q, [min_filter_count_x4q+filter1q*%2] + mov min_filter_count_x4q, min_filter_length_x4q + mov filter2q, filter1q + add filter2q, filter_alloc_x4q +%endif +%ifidn %1, int16 + mova m0, m4 + mova m2, m4 +%else ; float/double + xorps m0, m0, m0 + xorps m2, m2, m2 +%endif + + align 16 +.inner_loop: + movu m1, [srcq+min_filter_count_x4q*1] +%ifidn %1, int16 +%if cpuflag(xop) + vpmadcswd m2, m1, [filter2q+min_filter_count_x4q*1], m2 + vpmadcswd m0, m1, [filter1q+min_filter_count_x4q*1], m0 +%else + pmaddwd m3, m1, [filter2q+min_filter_count_x4q*1] + pmaddwd m1, [filter1q+min_filter_count_x4q*1] + paddd m2, m3 + paddd m0, m1 +%endif ; cpuflag +%else ; float/double +%if cpuflag(fma4) || cpuflag(fma3) + fmaddp%4 m2, m1, [filter2q+min_filter_count_x4q*1], m2 + fmaddp%4 m0, m1, [filter1q+min_filter_count_x4q*1], m0 +%else + mulp%4 m3, m1, [filter2q+min_filter_count_x4q*1] + mulp%4 m1, m1, [filter1q+min_filter_count_x4q*1] + addp%4 m2, m2, m3 + addp%4 m0, m0, m1 +%endif ; cpuflag +%endif + add min_filter_count_x4q, mmsize + js .inner_loop + +%ifidn %1, int16 +%if mmsize == 16 +%if cpuflag(xop) + vphadddq m2, m2 + vphadddq m0, m0 +%endif + pshufd m3, m2, q0032 + pshufd m1, m0, q0032 + paddd m2, m3 + paddd m0, m1 +%endif +%if notcpuflag(xop) + PSHUFLW m3, m2, q0032 + PSHUFLW m1, m0, q0032 + paddd m2, m3 + paddd m0, m1 +%endif + psubd m2, m0 + ; This is probably a really bad idea on atom and other machines with a + ; long transfer latency between GPRs and XMMs (atom). However, it does + ; make the clip a lot simpler... + movd eax, m2 + add indexd, dst_incr_divd + imul fracd + idiv src_incrd + movd m1, eax + add fracd, dst_incr_modd + paddd m0, m1 + psrad m0, 15 + packssdw m0, m0 + movd [dstq], m0 + + ; note that for imul/idiv, I need to move filter to edx/eax for each: + ; - 32bit: eax=r0[filter1], edx=r2[filter2] + ; - win64: eax=r6[filter1], edx=r1[todo] + ; - unix64: eax=r6[filter1], edx=r2[todo] +%else ; float/double + ; val += (v2 - val) * (FELEML) frac / c->src_incr; +%if mmsize == 32 + vextractf128 xm1, m0, 0x1 + vextractf128 xm3, m2, 0x1 + addp%4 xm0, xm1 + addp%4 xm2, xm3 +%endif + cvtsi2s%4 xm1, fracd + subp%4 xm2, xm0 + mulp%4 xm1, xm4 + shufp%4 xm1, xm1, q0000 +%if cpuflag(fma4) || cpuflag(fma3) + fmaddp%4 xm0, xm2, xm1, xm0 +%else + mulp%4 xm2, xm1 + addp%4 xm0, xm2 +%endif ; cpuflag + + ; horizontal sum & store + movhlps xm1, xm0 +%ifidn %1, float + addps xm0, xm1 + shufps xm1, xm0, xm0, q0001 +%endif + add fracd, dst_incr_modd + addp%4 xm0, xm1 + add indexd, dst_incr_divd + movs%4 [dstq], xm0 +%endif + cmp fracd, src_incrd + jl .skip + sub fracd, src_incrd + inc indexd + +%if UNIX64 + DEFINE_ARGS filter_alloc, dst, filter2, phase_count, index, frac, index_incr, \ + dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \ + dst_incr_div, src_incr, src, dst_end, filter_bank +%elif WIN64 + DEFINE_ARGS phase_count, filter2, src, filter_alloc, index, frac, index_incr, \ + dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \ + dst_incr_div, src_incr, dst, dst_end, filter_bank +%else ; x86-32 + DEFINE_ARGS filter1, phase_count, index_incr, frac, index, dst, src +%endif + +.skip: +%if ARCH_X86_32 + mov phase_countd, phase_count_stackd +%endif + add dstq, %2 + cmp indexd, phase_countd + jb .index_skip +.index_while: + sub indexd, phase_countd + lea srcq, [srcq+%2] + cmp indexd, phase_countd + jnb .index_while +.index_skip: + cmp dstq, dst_endq + jne .loop + +%if UNIX64 + DEFINE_ARGS ctx, dst, filter2, phase_count, index, frac, index_incr, \ + dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \ + dst_incr_div, src_incr, src, dst_end, filter_bank +%elif WIN64 + DEFINE_ARGS ctx, filter2, src, phase_count, index, frac, index_incr, \ + dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \ + dst_incr_div, src_incr, dst, dst_end, filter_bank +%else ; x86-32 + DEFINE_ARGS filter1, ctx, update_context, frac, index, dst, src +%endif + + cmp dword update_context_stackd, 0 + jz .skip_store + ; strictly speaking, the function should always return the consumed + ; number of bytes; however, we only use the value if update_context + ; is true, so let's just leave it uninitialized otherwise + mov ctxq, ctx_stackq + movifnidn rax, srcq + mov [ctxq+ResampleContext.frac ], fracd + sub rax, src_stackq + mov [ctxq+ResampleContext.index], indexd + shr rax, %3 + +.skip_store: +%if ARCH_X86_32 + ADD rsp, 0x28 +%endif + RET +%endmacro + +INIT_XMM sse +RESAMPLE_FNS float, 4, 2, s, pf_1 + +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +RESAMPLE_FNS float, 4, 2, s, pf_1 +%endif +%if HAVE_FMA3_EXTERNAL +INIT_YMM fma3 +RESAMPLE_FNS float, 4, 2, s, pf_1 +%endif +%if HAVE_FMA4_EXTERNAL +INIT_XMM fma4 +RESAMPLE_FNS float, 4, 2, s, pf_1 +%endif + +%if ARCH_X86_32 +INIT_MMX mmxext +RESAMPLE_FNS int16, 2, 1 +%endif + +INIT_XMM sse2 +RESAMPLE_FNS int16, 2, 1 +%if HAVE_XOP_EXTERNAL +INIT_XMM xop +RESAMPLE_FNS int16, 2, 1 +%endif + +INIT_XMM sse2 +RESAMPLE_FNS double, 8, 3, d, pdbl_1 + +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +RESAMPLE_FNS double, 8, 3, d, pdbl_1 +%endif +%if HAVE_FMA3_EXTERNAL +INIT_YMM fma3 +RESAMPLE_FNS double, 8, 3, d, pdbl_1 +%endif diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index 29834e44f5..e66a257ca2 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -429,48 +429,14 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then ln -sf ../3rdparty/ffmpeg-4.2-fit && cd ffmpeg-4.2-fit && PKG_CONFIG_PATH=$ABS_OBJS/opus/lib/pkgconfig ./configure \ --prefix=`pwd`/_release \ - --pkg-config-flags="--static" \ - --extra-libs=-lpthread \ - --extra-libs=-lm \ - --disable-programs \ - --disable-doc \ - --disable-htmlpages \ - --disable-manpages \ - --disable-podpages \ - --disable-txtpages \ - --disable-avdevice \ - --disable-avformat \ - --disable-swscale \ - --disable-postproc \ - --disable-avfilter \ - --disable-network \ - --disable-dct \ - --disable-dwt \ - --disable-error-resilience \ - --disable-lsp \ - --disable-lzo \ - --disable-faan \ - --disable-pixelutils \ - --disable-hwaccels \ - --disable-devices \ - --disable-audiotoolbox \ - --disable-videotoolbox \ - --disable-appkit \ - --disable-coreimage \ - --disable-avfoundation \ - --disable-securetransport \ - --disable-iconv \ - --disable-lzma \ - --disable-sdl2 \ - --disable-everything \ - --enable-decoder=aac \ - --enable-decoder=aac_fixed \ - --enable-decoder=aac_latm \ - --enable-decoder=libopus \ - --enable-encoder=aac \ - --enable-encoder=opus \ - --enable-encoder=libopus \ - --enable-libopus && + --pkg-config-flags="--static" --extra-libs=-lpthread --extra-libs=-lm \ + --disable-programs --disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages \ + --disable-avdevice --disable-avformat --disable-swscale --disable-postproc --disable-avfilter --disable-network \ + --disable-dct --disable-dwt --disable-error-resilience --disable-lsp --disable-lzo --disable-faan --disable-pixelutils \ + --disable-hwaccels --disable-devices --disable-audiotoolbox --disable-videotoolbox --disable-appkit --disable-coreimage \ + --disable-avfoundation --disable-securetransport --disable-iconv --disable-lzma --disable-sdl2 --disable-everything \ + --enable-decoder=aac --enable-decoder=aac_fixed --enable-decoder=aac_latm --enable-decoder=libopus --enable-encoder=aac \ + --enable-encoder=opus --enable-encoder=libopus --enable-libopus && make ${SRS_JOBS} && make install cd .. && rm -rf ffmpeg && ln -sf ffmpeg-4.2-fit/_release ffmpeg ) diff --git a/trunk/configure b/trunk/configure index 4e710d1838..f7efe2d58e 100755 --- a/trunk/configure +++ b/trunk/configure @@ -151,7 +151,8 @@ if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-lst"; fi # srtp LibSrtpRoot="${SRS_OBJS_DIR}/srtp2/include"; LibSrtpFile="${SRS_OBJS_DIR}/srtp2/lib/libsrtp2.a" # ffmpeg -LibFfmpegRoot="${SRS_OBJS_DIR}/ffmpeg/include"; LibFfmpegFile="${SRS_OBJS_DIR}/ffmpeg/lib/libavcodec.a ${SRS_OBJS_DIR}/ffmpeg/lib/libswresample.a ${SRS_OBJS_DIR}/ffmpeg/lib/libavutil.a ${SRS_OBJS_DIR}/ffmpeg/lib/libopus.a -lpthread" +LibFfmpegRoot="${SRS_OBJS_DIR}/ffmpeg/include"; LibFfmpegFile="${SRS_OBJS_DIR}/ffmpeg/lib/libavcodec.a ${SRS_OBJS_DIR}/ffmpeg/lib/libswresample.a ${SRS_OBJS_DIR}/ffmpeg/lib/libavutil.a -lpthread" +LibFfmpegRoot="${LibFfmpegRoot} ${SRS_OBJS_DIR}/opus/include"; LibFfmpegFile="${LibFfmpegFile} ${SRS_OBJS_DIR}/opus/lib/libopus.a" # openssl-1.1.0e, for the RTMP complex handshake. LibSSLRoot="";LibSSLfile="" if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == NO ]]; then @@ -173,7 +174,7 @@ fi # the link options, always use static link SrsLinkOptions="-ldl"; if [[ $SRS_SRT == YES ]]; then - SrsLinkOptions="${SrsLinkOptions} -pthread"; + SrsLinkOptions="${SrsLinkOptions} -lpthread"; fi if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == YES ]]; then SrsLinkOptions="${SrsLinkOptions} -lssl -lcrypto"; From 602a478e1bb55f6b1d9421afb62b7aa4e112fef1 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 22 Mar 2020 18:17:05 +0800 Subject: [PATCH 69/69] For #1659, #307, add switch to disable rtc --- .circleci/config.yml | 2 +- trunk/auto/auto_headers.sh | 6 +++ trunk/auto/depends.sh | 4 +- trunk/auto/options.sh | 12 +++-- trunk/configure | 76 ++++++++++++++++++++++------- trunk/src/app/srs_app_http_api.cpp | 4 ++ trunk/src/app/srs_app_http_api.hpp | 2 + trunk/src/app/srs_app_source.cpp | 28 +++++++++-- trunk/src/app/srs_app_source.hpp | 8 +++ trunk/src/kernel/srs_kernel_flv.cpp | 10 +++- trunk/src/kernel/srs_kernel_flv.hpp | 5 ++ trunk/src/main/srs_main_server.cpp | 4 ++ 12 files changed, 133 insertions(+), 28 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9fa2e06e3a..cd14797ecc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ jobs: - image: ossrs/srs:dev steps: - checkout - - run: cd trunk && ./configure && make + - run: cd trunk && ./configure --without-rtc && make && ./configure && make test: docker: - image: ossrs/srs:dev diff --git a/trunk/auto/auto_headers.sh b/trunk/auto/auto_headers.sh index b4c04545cd..71e9d48182 100755 --- a/trunk/auto/auto_headers.sh +++ b/trunk/auto/auto_headers.sh @@ -73,6 +73,12 @@ else srs_undefine_macro "SRS_AUTO_SRT" $SRS_AUTO_HEADERS_H fi +if [ $SRS_RTC = YES ]; then + srs_define_macro "SRS_AUTO_RTC" $SRS_AUTO_HEADERS_H +else + srs_undefine_macro "SRS_AUTO_RTC" $SRS_AUTO_HEADERS_H +fi + if [ $SRS_MEM_WATCH = YES ]; then srs_define_macro "SRS_AUTO_MEM_WATCH" $SRS_AUTO_HEADERS_H else diff --git a/trunk/auto/depends.sh b/trunk/auto/depends.sh index e66a257ca2..81e6f1f4b2 100755 --- a/trunk/auto/depends.sh +++ b/trunk/auto/depends.sh @@ -399,7 +399,7 @@ fi ##################################################################################### # libopus, for WebRTC to transcode AAC with Opus. ##################################################################################### -if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then +if [[ $SRS_EXPORT_LIBRTMP_PROJECT == NO && $SRS_RTC == YES ]]; then if [[ -f ${SRS_OBJS}/opus/lib/libopus.a ]]; then echo "The opus-1.3.1 is ok."; else @@ -419,7 +419,7 @@ fi ##################################################################################### # ffmpeg-fix, for WebRTC to transcode AAC with Opus. ##################################################################################### -if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then +if [[ $SRS_EXPORT_LIBRTMP_PROJECT == NO && $SRS_RTC == YES ]]; then if [[ -f ${SRS_OBJS}/ffmpeg/lib/libavcodec.a ]]; then echo "The ffmpeg-4.2-fit is ok."; else diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh index ad89f882d1..3f142b4a87 100755 --- a/trunk/auto/options.sh +++ b/trunk/auto/options.sh @@ -17,6 +17,7 @@ help=no # feature options SRS_HDS=NO SRS_SRT=NO +SRS_RTC=YES SRS_NGINX=NO SRS_FFMPEG_TOOL=NO SRS_LIBRTMP=NO @@ -130,7 +131,8 @@ Features: --with-librtmp Enable srs-librtmp, library for client. --with-research Build the research tools. --with-utest Build the utest for SRS. - --with-srt Build the srt for SRS. + --with-srt Build the SRT support for SRS. + --with-rtc Build the WebRTC support for SRS. --without-ssl Disable rtmp complex handshake. --without-hds Disable hds, the adobe http dynamic streaming. @@ -139,7 +141,8 @@ Features: --without-librtmp Disable srs-librtmp, library for client. --without-research Do not build the research tools. --without-utest Do not build the utest for SRS. - --without-srt Do not build the srt for SRS. + --without-srt Do not build the SRT support for SRS. + --without-rtc Do not build the WebRTC support for SRS. --prefix= The absolute installation path for srs. Default: $SRS_PREFIX --static Whether add '-static' to link options. @@ -225,6 +228,7 @@ function parse_user_option() { --with-research) SRS_RESEARCH=YES ;; --with-utest) SRS_UTEST=YES ;; --with-srt) SRS_SRT=YES ;; + --with-rtc) SRS_RTC=YES ;; --with-gperf) SRS_GPERF=YES ;; --with-gmc) SRS_GPERF_MC=YES ;; --with-gmd) SRS_GPERF_MD=YES ;; @@ -240,7 +244,8 @@ function parse_user_option() { --without-librtmp) SRS_LIBRTMP=NO ;; --without-research) SRS_RESEARCH=NO ;; --without-utest) SRS_UTEST=NO ;; - --without-srt) SRS_SRT=NO ;; + --without-srt) SRS_SRT=NO ;; + --without-rtc) SRS_RTC=NO ;; --without-gperf) SRS_GPERF=NO ;; --without-gmc) SRS_GPERF_MC=NO ;; --without-gmd) SRS_GPERF_MD=NO ;; @@ -539,6 +544,7 @@ function regenerate_options() { if [ $SRS_RESEARCH = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-research"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-research"; fi if [ $SRS_UTEST = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-utest"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-utest"; fi if [ $SRS_SRT = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-srt"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-srt"; fi + if [ $SRS_RTC = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-rtc"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-rtc"; fi if [ $SRS_GPERF = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gperf"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gperf"; fi if [ $SRS_GPERF_MC = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gmc"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gmc"; fi if [ $SRS_GPERF_MD = YES ]; then SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --with-gmd"; else SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --without-gmd"; fi diff --git a/trunk/configure b/trunk/configure index f7efe2d58e..30757bdc33 100755 --- a/trunk/configure +++ b/trunk/configure @@ -149,10 +149,14 @@ END LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a" if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-lst"; fi # srtp -LibSrtpRoot="${SRS_OBJS_DIR}/srtp2/include"; LibSrtpFile="${SRS_OBJS_DIR}/srtp2/lib/libsrtp2.a" -# ffmpeg -LibFfmpegRoot="${SRS_OBJS_DIR}/ffmpeg/include"; LibFfmpegFile="${SRS_OBJS_DIR}/ffmpeg/lib/libavcodec.a ${SRS_OBJS_DIR}/ffmpeg/lib/libswresample.a ${SRS_OBJS_DIR}/ffmpeg/lib/libavutil.a -lpthread" -LibFfmpegRoot="${LibFfmpegRoot} ${SRS_OBJS_DIR}/opus/include"; LibFfmpegFile="${LibFfmpegFile} ${SRS_OBJS_DIR}/opus/lib/libopus.a" +if [[ $SRS_RTC == YES ]]; then + LibSrtpRoot="${SRS_OBJS_DIR}/srtp2/include"; LibSrtpFile="${SRS_OBJS_DIR}/srtp2/lib/libsrtp2.a" +fi +# FFMPEG for WebRTC transcoding, such as aac to opus. +if [[ $SRS_RTC == YES ]]; then + LibFfmpegRoot="${SRS_OBJS_DIR}/ffmpeg/include"; LibFfmpegFile="${SRS_OBJS_DIR}/ffmpeg/lib/libavcodec.a ${SRS_OBJS_DIR}/ffmpeg/lib/libswresample.a ${SRS_OBJS_DIR}/ffmpeg/lib/libavutil.a" + LibFfmpegRoot="${LibFfmpegRoot} ${SRS_OBJS_DIR}/opus/include"; LibFfmpegFile="${LibFfmpegFile} ${SRS_OBJS_DIR}/opus/lib/libopus.a" +fi # openssl-1.1.0e, for the RTMP complex handshake. LibSSLRoot="";LibSSLfile="" if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == NO ]]; then @@ -173,7 +177,7 @@ if [[ $SRS_SRT == YES ]]; then fi # the link options, always use static link SrsLinkOptions="-ldl"; -if [[ $SRS_SRT == YES ]]; then +if [[ $SRS_SRT == YES || $SRS_RTC == YES ]]; then SrsLinkOptions="${SrsLinkOptions} -lpthread"; fi if [[ $SRS_SSL == YES && $SRS_USE_SYS_SSL == YES ]]; then @@ -206,9 +210,12 @@ MODULE_ID="KERNEL" MODULE_DEPENDS=("CORE") ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_kernel_error" "srs_kernel_log" "srs_kernel_buffer" - "srs_kernel_utility" "srs_kernel_flv" "srs_kernel_rtp" "srs_kernel_codec" "srs_kernel_io" + "srs_kernel_utility" "srs_kernel_flv" "srs_kernel_codec" "srs_kernel_io" "srs_kernel_consts" "srs_kernel_aac" "srs_kernel_mp3" "srs_kernel_ts" "srs_kernel_stream" "srs_kernel_balance" "srs_kernel_mp4" "srs_kernel_file") +if [[ $SRS_RTC == YES ]]; then + MODULE_FILES+=("srs_kernel_rtp") +fi KERNEL_INCS="src/kernel"; MODULE_DIR=${KERNEL_INCS} . auto/modules.sh KERNEL_OBJS="${MODULE_OBJS[@]}" # @@ -219,7 +226,10 @@ ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_protocol_amf0" "srs_protocol_io" "srs_rtmp_stack" "srs_rtmp_handshake" "srs_protocol_utility" "srs_rtmp_msg_array" "srs_protocol_stream" "srs_raw_avc" "srs_rtsp_stack" "srs_http_stack" "srs_protocol_kbps" "srs_protocol_json" - "srs_stun_stack" "srs_protocol_format") + "srs_protocol_format") +if [[ $SRS_RTC == YES ]]; then + MODULE_FILES+=("srs_stun_stack") +fi PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh PROTOCOL_OBJS="${MODULE_OBJS[@]}" # @@ -238,7 +248,10 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVICE" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL") - ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + if [[ $SRS_RTC == YES ]]; then + ModuleLibIncs+=("${LibFfmpegRoot[*]}" ${LibSrtpRoot}) + fi MODULE_FILES=("srs_service_log" "srs_service_st" "srs_service_http_client" "srs_service_http_conn" "srs_service_rtmp_conn" "srs_service_utility" "srs_service_conn") @@ -251,7 +264,10 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) + if [[ $SRS_RTC == YES ]]; then + ModuleLibIncs+=("${LibFfmpegRoot[*]}" ${LibSrtpRoot}) + fi MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -259,10 +275,13 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" - "srs_app_mpegts_udp" "srs_app_rtc" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" + "srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" - "srs_app_coworkers" "srs_app_hybrid" "srs_app_audio_recode") + "srs_app_coworkers" "srs_app_hybrid") + if [[ $SRS_RTC == YES ]]; then + MODULE_FILES+=("srs_app_rtc" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_audio_recode") + fi DEFINES="" # add each modules for app for SRS_MODULE in ${SRS_MODULES[*]}; do @@ -289,7 +308,10 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then if [[ $SRS_SRT == YES ]]; then MODULE_DEPENDS+=("SRT") fi - ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + if [[ $SRS_RTC == YES ]]; then + ModuleLibIncs+=("${LibFfmpegRoot[*]}" ${LibSrtpRoot}) + fi if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi @@ -302,7 +324,10 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="MAIN" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + if [[ $SRS_RTC == YES ]]; then + ModuleLibIncs+=("${LibFfmpegRoot[*]}" ${LibSrtpRoot}) + fi MODULE_FILES=() DEFINES="" # add each modules for main @@ -329,13 +354,19 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then done # # all depends libraries - ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibFfmpegFile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) + if [[ $SRS_RTC == YES ]]; then + ModuleLibFiles+=("${LibFfmpegFile[*]}" ${LibSrtpFile}) + fi if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi # all depends objects MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${APP_OBJS[@]} ${SERVER_OBJS[@]}" - ModuleLibIncs=(${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) + if [[ $SRS_RTC == YES ]]; then + ModuleLibIncs+=("${LibFfmpegRoot[*]}" ${LibSrtpRoot}) + fi if [[ $SRS_SRT == YES ]]; then MODULE_OBJS="${MODULE_OBJS} ${SRT_OBJS[@]}" fi @@ -346,7 +377,10 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then # # For modules, without the app module. MODULE_OBJS="${CORE_OBJS[@]} ${KERNEL_OBJS[@]} ${PROTOCOL_OBJS[@]} ${SERVICE_OBJS[@]} ${MAIN_OBJS[@]}" - ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibFfmpegFile} ${LibSSLfile} ${LibGperfFile}) + ModuleLibFiles=(${LibSTfile} ${LibSSLfile} ${LibGperfFile}) + if [[ $SRS_RTC == YES ]]; then + ModuleLibFiles+=("${LibFfmpegFile[*]}" ${LibSrtpFile}) + fi # for SRS_MODULE in ${SRS_MODULES[*]}; do . $SRS_MODULE/config @@ -366,11 +400,17 @@ if [ $SRS_UTEST = YES ]; then MODULE_FILES=("srs_utest" "srs_utest_amf0" "srs_utest_protocol" "srs_utest_kernel" "srs_utest_core" "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app") - ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSrtpRoot} ${LibFfmpegRoot} ${LibSSLRoot}) + ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSTRoot} ${LibSSLRoot}) + if [[ $SRS_RTC == YES ]]; then + ModuleLibIncs+=("${LibFfmpegRoot[*]}" ${LibSrtpRoot}) + fi if [[ $SRS_SRT == YES ]]; then ModuleLibIncs+=("${LibSRTRoot[*]}") fi - ModuleLibFiles=(${LibSTfile} ${LibSrtpFile} ${LibFfmpegFile} ${LibSSLfile}) + ModuleLibFiles=(${LibSTfile} ${LibSSLfile}) + if [[ $SRS_RTC == YES ]]; then + ModuleLibFiles+=("${LibFfmpegFile[*]}" ${LibSrtpFile}) + fi if [[ $SRS_SRT == YES ]]; then ModuleLibFiles+=("${LibSRTfile[*]}") fi diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 2ea98230a5..ab755df2f2 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -46,7 +46,9 @@ using namespace std; #include #include #include +#ifdef SRS_AUTO_RTC #include +#endif srs_error_t srs_api_response_jsonp(ISrsHttpResponseWriter* w, string callback, string data) { @@ -781,6 +783,7 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessa return srs_api_response(w, r, obj->dumps()); } +#ifdef SRS_AUTO_RTC SrsGoApiSdp::SrsGoApiSdp(SrsRtcServer* rtc_svr) { rtc_server = rtc_svr; @@ -907,6 +910,7 @@ srs_error_t SrsGoApiSdp::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessag return err; } +#endif SrsGoApiClients::SrsGoApiClients() { diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 7b55eaf526..4caee1de8c 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -166,6 +166,7 @@ class SrsGoApiStreams : public ISrsHttpHandler virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r); }; +#ifdef SRS_AUTO_RTC class SrsGoApiSdp : public ISrsHttpHandler { private: @@ -178,6 +179,7 @@ class SrsGoApiSdp : public ISrsHttpHandler private: virtual srs_error_t do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r, SrsJsonObject* res); }; +#endif class SrsGoApiClients : public ISrsHttpHandler { diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 3ba15a6213..94d24e250c 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -33,7 +33,6 @@ using namespace std; #include #include #include -#include #include #include #include @@ -51,6 +50,9 @@ using namespace std; #include #include #include +#ifdef SRS_AUTO_RTC +#include +#endif #define CONST_MAX_JITTER_MS 250 #define CONST_MAX_JITTER_MS_NEG -250 @@ -816,6 +818,7 @@ SrsSharedPtrMessage* SrsMixQueue::pop() return msg; } +#ifdef SRS_AUTO_RTC SrsRtpPacketQueue::SrsRtpPacketQueue() { } @@ -864,6 +867,7 @@ SrsRtpSharedPacket* SrsRtpPacketQueue::find(const uint16_t& sequence) return pkt; } +#endif SrsOriginHub::SrsOriginHub() { @@ -875,7 +879,9 @@ SrsOriginHub::SrsOriginHub() dash = new SrsDash(); dvr = new SrsDvr(); encoder = new SrsEncoder(); +#ifdef SRS_AUTO_RTC rtc = new SrsRtc(); +#endif #ifdef SRS_AUTO_HDS hds = new SrsHds(); #endif @@ -919,10 +925,12 @@ srs_error_t SrsOriginHub::initialize(SrsSource* s, SrsRequest* r) if ((err = format->initialize()) != srs_success) { return srs_error_wrap(err, "format initialize"); } - + +#ifdef SRS_AUTO_RTC if ((err = rtc->initialize(this, req)) != srs_success) { return srs_error_wrap(err, "rtc initialize"); } +#endif if ((err = hls->initialize(this, req)) != srs_success) { return srs_error_wrap(err, "hls initialize"); @@ -1022,11 +1030,13 @@ srs_error_t SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio) srs_flv_srates[c->sound_rate]); } +#ifdef SRS_AUTO_RTC if ((err = rtc->on_audio(msg, format)) != srs_success) { srs_warn("rtc: ignore audio error %s", srs_error_desc(err).c_str()); srs_error_reset(err); rtc->on_unpublish(); } +#endif if ((err = hls->on_audio(msg, format)) != srs_success) { // apply the error strategy for hls. @@ -1121,6 +1131,7 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se return err; } +#ifdef SRS_AUTO_RTC // Parse RTMP message to RTP packets, in FU-A if too large. if ((err = rtc->on_video(msg, format)) != srs_success) { // TODO: We should support more strategies. @@ -1132,6 +1143,7 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se // TODO: FIXME: Refactor to move to rtp? // Save the RTP packets for find_rtp_packet() to rtx or restore it. source->rtp_queue->push(msg->rtp_packets); +#endif if ((err = hls->on_video(msg, format)) != srs_success) { // TODO: We should support more strategies. @@ -1200,10 +1212,12 @@ srs_error_t SrsOriginHub::on_publish() if ((err = encoder->on_publish(req)) != srs_success) { return srs_error_wrap(err, "encoder publish"); } - + +#ifdef SRS_AUTO_RTC if ((err = rtc->on_publish()) != srs_success) { return srs_error_wrap(err, "rtc publish"); } +#endif if ((err = hls->on_publish()) != srs_success) { return srs_error_wrap(err, "hls publish"); @@ -1242,7 +1256,9 @@ void SrsOriginHub::on_unpublish() destroy_forwarders(); encoder->on_unpublish(); +#ifdef SRS_AUTO_RTC rtc->on_unpublish(); +#endif hls->on_unpublish(); dash->on_unpublish(); dvr->on_unpublish(); @@ -1904,7 +1920,9 @@ SrsSource::SrsSource() jitter_algorithm = SrsRtmpJitterAlgorithmOFF; mix_correct = false; mix_queue = new SrsMixQueue(); +#ifdef SRS_AUTO_RTC rtp_queue = new SrsRtpPacketQueue(); +#endif _can_publish = true; _pre_source_id = _source_id = -1; @@ -1934,7 +1952,9 @@ SrsSource::~SrsSource() srs_freep(hub); srs_freep(meta); srs_freep(mix_queue); +#ifdef SRS_AUTO_RTC srs_freep(rtp_queue); +#endif srs_freep(play_edge); srs_freep(publish_edge); @@ -2692,7 +2712,9 @@ string SrsSource::get_curr_origin() return play_edge->get_curr_origin(); } +#ifdef SRS_AUTO_RTC SrsRtpSharedPacket* SrsSource::find_rtp_packet(const uint16_t& seq) { return rtp_queue->find(seq); } +#endif diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 01005d96ba..ac04f5a051 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -325,6 +325,7 @@ class SrsMixQueue virtual SrsSharedPtrMessage* pop(); }; +#ifdef SRS_AUTO_RTC // To find the RTP packet for RTX or restore. class SrsRtpPacketQueue { @@ -347,6 +348,7 @@ class SrsRtpPacketQueue void insert(const uint16_t& sequence, SrsRtpSharedPacket* pkt); SrsRtpSharedPacket* find(const uint16_t& sequence); }; +#endif // The hub for origin is a collection of utilities for origin only, // For example, DVR, HLS, Forward and Transcode are only available for origin, @@ -360,8 +362,10 @@ class SrsOriginHub : public ISrsReloadHandler private: // The format, codec information. SrsRtmpFormat* format; +#ifdef SRS_AUTO_RTC // rtc handler SrsRtc* rtc; +#endif // hls handler. SrsHls* hls; // The DASH encoder. @@ -534,8 +538,10 @@ class SrsSource : public ISrsReloadHandler bool mix_correct; // The mix queue to implements the mix correct algorithm. SrsMixQueue* mix_queue; +#ifdef SRS_AUTO_RTC // rtp packet queue SrsRtpPacketQueue* rtp_queue; +#endif // For play, whether enabled atc. // The atc(use absolute time and donot adjust time), // directly use msg time and donot adjust if atc is true, @@ -625,8 +631,10 @@ class SrsSource : public ISrsReloadHandler public: virtual std::string get_curr_origin(); public: +#ifdef SRS_AUTO_RTC // Find rtp packet by sequence SrsRtpSharedPacket* find_rtp_packet(const uint16_t& seq); +#endif }; #endif diff --git a/trunk/src/kernel/srs_kernel_flv.cpp b/trunk/src/kernel/srs_kernel_flv.cpp index be4e808e2c..f24dc2047e 100644 --- a/trunk/src/kernel/srs_kernel_flv.cpp +++ b/trunk/src/kernel/srs_kernel_flv.cpp @@ -36,11 +36,13 @@ using namespace std; #include #include #include -#include #include #include #include #include +#ifdef SRS_AUTO_RTC +#include +#endif SrsMessageHeader::SrsMessageHeader() { @@ -230,9 +232,11 @@ SrsSharedPtrMessage::~SrsSharedPtrMessage() } } +#ifdef SRS_AUTO_RTC for (int i = 0; i < (int)rtp_packets.size(); ++i) { srs_freep(rtp_packets[i]); } +#endif } srs_error_t SrsSharedPtrMessage::create(SrsCommonMessage* msg) @@ -351,17 +355,21 @@ SrsSharedPtrMessage* SrsSharedPtrMessage::copy() copy->payload = ptr->payload; copy->size = ptr->size; +#ifdef SRS_AUTO_RTC for (int i = 0; i < (int)rtp_packets.size(); ++i) { copy->rtp_packets.push_back(rtp_packets[i]->copy()); } +#endif return copy; } +#ifdef SRS_AUTO_RTC void SrsSharedPtrMessage::set_rtp_packets(const std::vector& pkts) { rtp_packets = pkts; } +#endif SrsFlvTransmuxer::SrsFlvTransmuxer() { diff --git a/trunk/src/kernel/srs_kernel_flv.hpp b/trunk/src/kernel/srs_kernel_flv.hpp index ec4545d968..23fa0baf08 100644 --- a/trunk/src/kernel/srs_kernel_flv.hpp +++ b/trunk/src/kernel/srs_kernel_flv.hpp @@ -288,7 +288,10 @@ class SrsSharedPtrMessage // video/audio packet use raw bytes, no video/audio packet. char* payload; +#ifdef SRS_AUTO_RTC std::vector rtp_packets; +#endif + private: class SrsSharedPtrPayload { @@ -344,7 +347,9 @@ class SrsSharedPtrMessage // @remark, assert object is created. virtual SrsSharedPtrMessage* copy(); public: +#ifdef SRS_AUTO_RTC virtual void set_rtp_packets(const std::vector& pkts); +#endif }; // Transmux RTMP packets to FLV stream. diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 1bec4c0ad3..d8415e76ff 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -50,7 +50,9 @@ using namespace std; #include #include #include +#ifdef SRS_AUTO_RTC #include +#endif #ifdef SRS_AUTO_SRT #include @@ -449,7 +451,9 @@ srs_error_t run_hybrid_server() _srs_hybrid->register_server(new SrtServerAdapter()); #endif +#ifdef SRS_AUTO_RTC _srs_hybrid->register_server(new RtcServerAdapter()); +#endif // Do some system initialize. if ((err = _srs_hybrid->initialize()) != srs_success) {

    w-3|QaTl-(@bee_o&5nfia5I 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